diff --git a/cubestore/src/lib.rs b/cubestore/src/lib.rs index ca3bea1..7f26b88 100644 --- a/cubestore/src/lib.rs +++ b/cubestore/src/lib.rs @@ -618,19 +618,17 @@ impl CubeStore { /// "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 { - 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 = self .backend .keys() @@ -638,7 +636,7 @@ impl CubeStore { .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);