mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 02:01:38 +00:00
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:
parent
30e57b9f24
commit
0a178dc625
@ -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_ */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ®istry,
|
||||
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_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user