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)