fs_query: replace Avl_tree by Dictonary

This allows checking for duplicate directory entries. This occurs when
there are overlayed file systems.

Fixes #5334
This commit is contained in:
Johannes Schlatow 2024-08-28 17:00:44 +02:00 committed by Christian Helmuth
parent 30e57b9f24
commit 0a178dc625
3 changed files with 43 additions and 55 deletions

View File

@ -16,9 +16,7 @@
/* Genode includes */
#include <os/vfs.h>
/* local includes */
#include <sorted_for_each.h>
#include <util/dictionary.h>
namespace Genode {
@ -31,43 +29,35 @@ template <typename FN>
static void Genode::for_each_subdir_name(Allocator &alloc, Directory const &dir,
FN const &fn)
{
using Dirname = Directory::Entry::Name;
using Name = Directory::Entry::Name;
struct Name : Interface, private Dirname
struct Dirname : Dictionary<Dirname, Name>::Element
{
using Dirname::string;
Name(Dirname const &name) : Dirname(name) { }
bool higher(Name const &other) const
{
return (strcmp(other.string(), string()) > 0);
}
Dirname(Dictionary<Dirname, Name> & dict, Name const & name)
: Dictionary<Dirname, Name>::Element(dict, name)
{ }
};
/* obtain list of sub directory names */
Registry<Registered<Name>> names { };
/* obtain dictionary of sub directory names */
Dictionary<Dirname, Name> names { };
dir.for_each_entry([&] (Directory::Entry const &entry) {
if (entry.dir())
new (alloc) Registered<Name>(names, entry.name()); });
new (alloc) Dirname(names, entry.name()); });
auto destroy_names = [&] ()
{
names.for_each([&] (Registered<Name> &name) {
destroy(alloc, &name); });
};
auto destroy_element = [&] (Dirname &element) {
destroy(alloc, &element); };
/* iterate over sorted list */
/* iterate over dictionary */
try {
sorted_for_each(alloc, names, [&] (Name const &name) {
fn(name.string()); });
names.for_each([&] (Dirname const &element) {
fn(element.name.string()); });
}
catch (...) {
destroy_names();
while (names.with_any_element(destroy_element)) { }
throw;
}
destroy_names();
while (names.with_any_element(destroy_element)) { }
}
#endif /* _FOR_EACH_SUBDIR_NAME_H_ */

View File

@ -21,6 +21,7 @@
#include <os/vfs.h>
/* local includes */
#include <sorted_for_each.h>
#include <for_each_subdir_name.h>
namespace Fs_query {
@ -39,10 +40,9 @@ struct Fs_query::Watched_file
/**
* Support for 'sorted_for_each'
*/
bool higher(Watched_file const &other) const
{
return (strcmp(other._name.string(), _name.string()) > 0);
}
using Name = File_content::Path;
Name const &name() const { return _name; }
Node_rwx const _rwx;

View File

@ -16,6 +16,7 @@
#include <base/registry.h>
#include <base/allocator.h>
#include <util/dictionary.h>
namespace Genode {
template <typename T, typename FN>
@ -26,55 +27,52 @@ namespace Genode {
/**
* Execute 'fn' for each registry element
*
* The type T must be equipped with a method that defines the sort criterion:
* The type T must be equipped with a method name() and a type Name:
*
* bool higher(T const &other) const
* const & Name name() 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.
* 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 &registry,
FN const &fn)
{
struct Sorted_item : Avl_node<Sorted_item>
using Name = T::Name;
struct SortedItem : Dictionary<SortedItem, Name>::Element
{
T const &element;
Sorted_item(T const &element) : element(element) { }
bool higher(Sorted_item const *item) const
{
return item ? element.higher(item->element) : false;
}
SortedItem(Dictionary<SortedItem, Name> & dict, Name const & name, T const & element)
: Dictionary<SortedItem, Name>::Element(dict, name),
element(element)
{ }
};
/* build temporary AVL tree of sorted elements */
Avl_tree<Sorted_item> sorted { };
/* build temporary Dictionary of sorted and unique elements */
using Dict = Dictionary<SortedItem, Name>;
Dict sorted { };
registry.for_each([&] (T const &element) {
sorted.insert(new (alloc) Sorted_item(element)); });
/* skip duplicates */
if (sorted.exists(element.name())) return;
auto destroy_sorted = [&] ()
{
while (Sorted_item *item = sorted.first()) {
sorted.remove(item);
destroy(alloc, item);
}
};
new (alloc) SortedItem(sorted, element.name(), element);
});
auto destroy_element = [&] (SortedItem &item) {
destroy(alloc, &item); };
/* iterate over sorted elements, 'fn' may throw */
try {
sorted.for_each([&] (Sorted_item const &item) {
sorted.for_each([&] (SortedItem const &item) {
fn(item.element); });
}
catch (...) {
destroy_sorted();
while (sorted.with_any_element(destroy_element)) { }
throw;
}
destroy_sorted();
while (sorted.with_any_element(destroy_element)) { }
}
#endif /* _SORTED_FOR_EACH_H_ */