mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
fs_query: report dir content in alphabetic order
By sorting the reported output, all consumers of the reports become able to rely on a deterministic order. For example, the file browser of Sculpt OS, the launcher menu items, and the depot-selection items will appear in a predictable order. Fixes #4054
This commit is contained in:
parent
8f1db47c26
commit
e9ac14ed49
@ -202,10 +202,10 @@ regsub {.*report 'fs_query -> listing'} $output {} output
|
||||
compare_output_to {
|
||||
[init -> report_rom] <listing>
|
||||
[init -> report_rom] <dir path="/fs/items">
|
||||
[init -> report_rom] <file name="4" writeable="yes">fourth</file>
|
||||
[init -> report_rom] <file name="1" writeable="yes">first</file>
|
||||
[init -> report_rom] <file name="3" writeable="yes">updated
|
||||
[init -> report_rom] </file>
|
||||
[init -> report_rom] <file name="4" writeable="yes">fourth</file>
|
||||
[init -> report_rom] </dir>
|
||||
[init -> report_rom] </listing>
|
||||
}
|
||||
|
73
repos/gems/src/app/fs_query/for_each_subdir_name.h
Normal file
73
repos/gems/src/app/fs_query/for_each_subdir_name.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* \brief Utility for iterating over subdirectory names
|
||||
* \author Norman Feske
|
||||
* \date 2021-03-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _FOR_EACH_SUBDIR_NAME_H_
|
||||
#define _FOR_EACH_SUBDIR_NAME_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/vfs.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sorted_for_each.h>
|
||||
|
||||
namespace Genode {
|
||||
|
||||
template <typename FN>
|
||||
static void for_each_subdir_name(Allocator &, Directory const &, FN const &);
|
||||
}
|
||||
|
||||
|
||||
template <typename FN>
|
||||
static void Genode::for_each_subdir_name(Allocator &alloc, Directory const &dir,
|
||||
FN const &fn)
|
||||
{
|
||||
using Dirname = Directory::Entry::Name;
|
||||
|
||||
struct Name : Interface, private Dirname
|
||||
{
|
||||
using Dirname::string;
|
||||
|
||||
Name(Dirname const &name) : Dirname(name) { }
|
||||
|
||||
bool higher(Name const &other) const
|
||||
{
|
||||
return (strcmp(other.string(), string()) > 0);
|
||||
}
|
||||
};
|
||||
|
||||
/* obtain list of sub directory names */
|
||||
Registry<Registered<Name>> names { };
|
||||
dir.for_each_entry([&] (Directory::Entry const &entry) {
|
||||
if (entry.dir())
|
||||
new (alloc) Registered<Name>(names, entry.name()); });
|
||||
|
||||
auto destroy_names = [&] ()
|
||||
{
|
||||
names.for_each([&] (Registered<Name> &name) {
|
||||
destroy(alloc, &name); });
|
||||
};
|
||||
|
||||
/* iterate over sorted list */
|
||||
try {
|
||||
sorted_for_each(alloc, names, [&] (Name const &name) {
|
||||
fn(name.string()); });
|
||||
}
|
||||
catch (...) {
|
||||
destroy_names();
|
||||
throw;
|
||||
}
|
||||
|
||||
destroy_names();
|
||||
}
|
||||
|
||||
#endif /* _FOR_EACH_SUBDIR_NAME_H_ */
|
@ -16,9 +16,13 @@
|
||||
#include <base/component.h>
|
||||
#include <base/heap.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <util/avl_tree.h>
|
||||
#include <os/reporter.h>
|
||||
#include <os/vfs.h>
|
||||
|
||||
/* local includes */
|
||||
#include <for_each_subdir_name.h>
|
||||
|
||||
namespace Fs_query {
|
||||
using namespace Genode;
|
||||
struct Watched_file;
|
||||
@ -32,6 +36,14 @@ struct Fs_query::Watched_file
|
||||
{
|
||||
File_content::Path const _name;
|
||||
|
||||
/**
|
||||
* Support for 'sorted_for_each'
|
||||
*/
|
||||
bool higher(Watched_file const &other) const
|
||||
{
|
||||
return (strcmp(other._name.string(), _name.string()) > 0);
|
||||
}
|
||||
|
||||
Node_rwx const _rwx;
|
||||
|
||||
Watcher _watcher;
|
||||
@ -136,12 +148,11 @@ struct Fs_query::Watched_directory
|
||||
xml.node("dir", [&] () {
|
||||
xml.attribute("path", _rel_path);
|
||||
|
||||
_dir.for_each_entry([&] (Directory::Entry const &entry) {
|
||||
if (entry.dir())
|
||||
xml.node("dir", [&] () {
|
||||
xml.attribute("name", entry.name()); }); });
|
||||
for_each_subdir_name(_alloc, _dir, [&] (Directory::Entry::Name const &name) {
|
||||
xml.node("dir", [&] () {
|
||||
xml.attribute("name", name); }); });
|
||||
|
||||
_files.for_each([&] (Watched_file const &file) {
|
||||
sorted_for_each(_alloc, _files, [&] (Watched_file const &file) {
|
||||
file.gen_query_response(xml, query, _alloc, _dir); });
|
||||
});
|
||||
}
|
||||
@ -172,9 +183,9 @@ struct Fs_query::Main : Vfs::Watch_response_handler
|
||||
|
||||
Vfs_env(Main &main) : _main(main) { }
|
||||
|
||||
Genode::Env &env() override { return _main._env; }
|
||||
Allocator &alloc() override { return _main._heap; }
|
||||
Vfs::File_system &root_dir() override { return _main._root_dir_fs; }
|
||||
Genode::Env &env() override { return _main._env; }
|
||||
Allocator &alloc() override { return _main._heap; }
|
||||
Vfs::File_system &root_dir() override { return _main._root_dir_fs; }
|
||||
|
||||
} _vfs_env { *this };
|
||||
|
||||
|
80
repos/gems/src/app/fs_query/sorted_for_each.h
Normal file
80
repos/gems/src/app/fs_query/sorted_for_each.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* \brief Utility for accessing registry elements in a sorted order
|
||||
* \author Norman Feske
|
||||
* \date 2021-03-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SORTED_FOR_EACH_H_
|
||||
#define _SORTED_FOR_EACH_H_
|
||||
|
||||
#include <base/registry.h>
|
||||
#include <base/allocator.h>
|
||||
|
||||
namespace Genode {
|
||||
template <typename T, typename FN>
|
||||
static inline void sorted_for_each(Allocator &, Registry<T> const &, FN const &);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute 'fn' for each registry element
|
||||
*
|
||||
* The type T must be equipped with a method that defines the sort criterion:
|
||||
*
|
||||
* bool higher(T const &other) const
|
||||
*
|
||||
* It must implement a strict order over all registry elements. E.g., if the
|
||||
* registry contains a set of names, no name must occur twice. The allocator
|
||||
* passed as 'alloc' is used to for temporary allocations.
|
||||
*/
|
||||
template <typename T, typename FN>
|
||||
static inline void Genode::sorted_for_each(Allocator &alloc,
|
||||
Registry<T> const ®istry,
|
||||
FN const &fn)
|
||||
{
|
||||
struct Sorted_item : Avl_node<Sorted_item>
|
||||
{
|
||||
T const &element;
|
||||
|
||||
Sorted_item(T const &element) : element(element) { }
|
||||
|
||||
bool higher(Sorted_item const *item) const
|
||||
{
|
||||
return item ? element.higher(item->element) : false;
|
||||
}
|
||||
};
|
||||
|
||||
/* build temporary AVL tree of sorted elements */
|
||||
Avl_tree<Sorted_item> sorted { };
|
||||
registry.for_each([&] (T const &element) {
|
||||
sorted.insert(new (alloc) Sorted_item(element)); });
|
||||
|
||||
auto destroy_sorted = [&] ()
|
||||
{
|
||||
while (Sorted_item *item = sorted.first()) {
|
||||
sorted.remove(item);
|
||||
destroy(alloc, item);
|
||||
}
|
||||
};
|
||||
|
||||
/* iterate over sorted elements, 'fn' may throw */
|
||||
try {
|
||||
sorted.for_each([&] (Sorted_item const &item) {
|
||||
fn(item.element); });
|
||||
}
|
||||
catch (...) {
|
||||
destroy_sorted();
|
||||
throw;
|
||||
}
|
||||
|
||||
destroy_sorted();
|
||||
}
|
||||
|
||||
#endif /* _SORTED_FOR_EACH_H_ */
|
@ -1,3 +1,4 @@
|
||||
TARGET = fs_query
|
||||
SRC_CC = main.cc
|
||||
LIBS += base vfs
|
||||
TARGET := fs_query
|
||||
SRC_CC := main.cc
|
||||
LIBS += base vfs
|
||||
INC_DIR += $(PRG_DIR)
|
||||
|
Loading…
x
Reference in New Issue
Block a user