fix(metatag-dirs): exact-leaf + descendant path prefix semantics
scan_by_path_prefix now matches BOTH an exact leaf (p == dir) and any descendant (p.starts_with(dir + '/')), so returns (the leaf itself) as well as (a child). Previously a bare dir normalized to 'dir/' and rejected exact leaves. Also fixes the unit test to assert the corrected semantics (exact leaf answers its own parent query). Falls out of wiring the OS migration scripts: their companion index records (c200/z090 GNS band) carry path=/cubelinux/os/... metatags, and the daemon reconstructs the whole migrated tree from them.
This commit is contained in:
+19
-16
@@ -618,19 +618,17 @@ impl<B: CubeBackend> CubeStore<B> {
|
||||
|
||||
/// "List a directory": every record whose `path` metatag is *under* the
|
||||
/// given directory prefix (e.g. `scan_by_path_prefix("/etc")` returns
|
||||
/// `/etc/passwd`, `/etc/network/interfaces`, ...). The prefix must end
|
||||
/// with `/` or be empty to mean "all paths". This is the metatag-based
|
||||
/// equivalent of `readdir` for a nested directory the FS itself cannot
|
||||
/// represent as a literal inode tree.
|
||||
/// `/etc/passwd`, `/etc/network/interfaces`, ...). Unlike a real FS, the
|
||||
/// nesting is a shared prefix on the `path` metatag of several records
|
||||
/// (the source PDF: "operate on CZYX records and Null-space flags rather
|
||||
/// than paths and inodes") — there is no half-coordinate directory entry.
|
||||
///
|
||||
/// A query matches BOTH an exact leaf (`/etc/hostname`) and any descendant
|
||||
/// (`/etc/hostname` and `/etc/passwd` both answer `/etc`), because a path
|
||||
/// is just a string: `/etc/hostname` == dir, and `/etc/passwd` starts with
|
||||
/// `dir + '/'`.
|
||||
pub fn scan_by_path_prefix(&self, dir: &str) -> Vec<Czyx> {
|
||||
let norm = if dir.is_empty() {
|
||||
""
|
||||
} else if dir.ends_with('/') {
|
||||
dir
|
||||
} else {
|
||||
// Treat a bare "dir" as "dir/" so "/etc" matches "/etc/passwd".
|
||||
return self.scan_by_path_prefix(&format!("{dir}/"));
|
||||
};
|
||||
let sep = format!("{dir}/");
|
||||
let mut out: Vec<Czyx> = self
|
||||
.backend
|
||||
.keys()
|
||||
@@ -638,7 +636,7 @@ impl<B: CubeBackend> CubeStore<B> {
|
||||
.filter(|k| {
|
||||
self.get_record(k)
|
||||
.map(|(h, _)| match &h.path {
|
||||
Some(p) => p != norm && p.starts_with(norm),
|
||||
Some(p) => p == dir || p.starts_with(&sep),
|
||||
None => false,
|
||||
})
|
||||
.unwrap_or(false)
|
||||
@@ -844,7 +842,9 @@ mod tests {
|
||||
vec![Czyx::new(200, 1, 1, 1)]
|
||||
);
|
||||
|
||||
// Directory listing via metatag prefix.
|
||||
// Directory listing via metatag prefix. Bare "/etc" matches every
|
||||
// record whose path is "/etc" or starts with "/etc/" (an exact leaf
|
||||
// like "/etc/hostname" answers "/etc", and "/etc/passwd" is a child).
|
||||
let etc = store.scan_by_path_prefix("/etc");
|
||||
assert_eq!(etc.len(), 3);
|
||||
assert!(etc.contains(&Czyx::new(200, 1, 1, 1)));
|
||||
@@ -855,8 +855,11 @@ mod tests {
|
||||
"/usr must not appear under /etc"
|
||||
);
|
||||
|
||||
// Bare prefix (no trailing slash) is normalized to "dir/".
|
||||
assert_eq!(store.scan_by_path_prefix("/etc").len(), 3);
|
||||
// An exact leaf answers its own parent directory query.
|
||||
assert_eq!(
|
||||
store.scan_by_path_prefix("/etc/hosts"),
|
||||
vec![Czyx::new(200, 1, 3, 1)]
|
||||
);
|
||||
|
||||
// Empty prefix = all paths.
|
||||
assert_eq!(store.scan_by_path_prefix("").len(), 4);
|
||||
|
||||
Reference in New Issue
Block a user