diff --git a/repos/gems/run/fs_query.run b/repos/gems/run/fs_query.run index e0f8336938..791e3cbc48 100644 --- a/repos/gems/run/fs_query.run +++ b/repos/gems/run/fs_query.run @@ -202,10 +202,10 @@ regsub {.*report 'fs_query -> listing'} $output {} output compare_output_to { [init -> report_rom] [init -> report_rom] -[init -> report_rom] fourth [init -> report_rom] first [init -> report_rom] updated [init -> report_rom] +[init -> report_rom] fourth [init -> report_rom] [init -> report_rom] } diff --git a/repos/gems/src/app/fs_query/for_each_subdir_name.h b/repos/gems/src/app/fs_query/for_each_subdir_name.h new file mode 100644 index 0000000000..3a300f33bd --- /dev/null +++ b/repos/gems/src/app/fs_query/for_each_subdir_name.h @@ -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 + +/* local includes */ +#include + +namespace Genode { + + template + static void for_each_subdir_name(Allocator &, Directory const &, FN const &); +} + + +template +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> names { }; + dir.for_each_entry([&] (Directory::Entry const &entry) { + if (entry.dir()) + new (alloc) Registered(names, entry.name()); }); + + auto destroy_names = [&] () + { + names.for_each([&] (Registered &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_ */ diff --git a/repos/gems/src/app/fs_query/main.cc b/repos/gems/src/app/fs_query/main.cc index 598e31264e..a3e204d711 100644 --- a/repos/gems/src/app/fs_query/main.cc +++ b/repos/gems/src/app/fs_query/main.cc @@ -16,9 +16,13 @@ #include #include #include +#include #include #include +/* local includes */ +#include + 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 }; diff --git a/repos/gems/src/app/fs_query/sorted_for_each.h b/repos/gems/src/app/fs_query/sorted_for_each.h new file mode 100644 index 0000000000..a4f4c5dd05 --- /dev/null +++ b/repos/gems/src/app/fs_query/sorted_for_each.h @@ -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 +#include + +namespace Genode { + template + static inline void sorted_for_each(Allocator &, Registry 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 +static inline void Genode::sorted_for_each(Allocator &alloc, + Registry const ®istry, + FN const &fn) +{ + struct Sorted_item : Avl_node + { + 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 { }; + 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_ */ diff --git a/repos/gems/src/app/fs_query/target.mk b/repos/gems/src/app/fs_query/target.mk index 73cde1a240..d747c2f0e3 100644 --- a/repos/gems/src/app/fs_query/target.mk +++ b/repos/gems/src/app/fs_query/target.mk @@ -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)