diff --git a/rust-bindings/rust/src/core.rs b/rust-bindings/rust/src/core.rs index 616e1123..5e294b1b 100644 --- a/rust-bindings/rust/src/core.rs +++ b/rust-bindings/rust/src/core.rs @@ -19,3 +19,30 @@ pub type TreeVariantType = (Vec<(String, Vec)>, Vec<(String, Vec, Vec, Vec)>); + +/// Parsed representation of directory metadata. +pub struct DirMetaParsed { + /// The user ID. + pub uid: u32, + /// The group ID. + pub gid: u32, + /// The Unix mode, including file type flag. + pub mode: u32, + /// Extended attributes. + pub xattrs: Vec<(Vec, Vec)>, +} + +impl DirMetaParsed { + /// Parse a directory metadata variant; must be of type `(uuua(ayay))`. + pub fn from_variant( + v: &glib::Variant, + ) -> Result { + let (uid, gid, mode, xattrs) = v.try_get::()?; + Ok(DirMetaParsed { + uid: u32::from_be(uid), + gid: u32::from_be(gid), + mode: u32::from_be(mode), + xattrs, + }) + } +} diff --git a/rust-bindings/rust/src/repo.rs b/rust-bindings/rust/src/repo.rs index 5329b893..68895692 100644 --- a/rust-bindings/rust/src/repo.rs +++ b/rust-bindings/rust/src/repo.rs @@ -441,4 +441,13 @@ impl Repo { ); })) } + + /// Load and parse directory metadata. + /// In particular, uid/gid/mode are stored in big-endian format; this function + /// converts them to host native endianness. + pub fn read_dirmeta(&self, checksum: &str) -> Result { + let v = self.load_variant(crate::ObjectType::DirMeta, checksum)?; + // Safety: We know the variant type will match since we just passed it above + Ok(crate::DirMetaParsed::from_variant(&v).unwrap()) + } } diff --git a/rust-bindings/rust/tests/repo/mod.rs b/rust-bindings/rust/tests/repo/mod.rs index f56e390e..007a0d83 100644 --- a/rust-bindings/rust/tests/repo/mod.rs +++ b/rust-bindings/rust/tests/repo/mod.rs @@ -27,7 +27,7 @@ fn should_commit_content_to_repo_and_list_refs_again() { } #[test] -fn should_traverse_commit() { +fn repo_traverse_and_read() { let test_repo = TestRepo::new(); let checksum = test_repo.test_commit("test"); @@ -58,6 +58,13 @@ fn should_traverse_commit() { ), objects ); + + let dirmeta = test_repo + .repo + .read_dirmeta("ad49a0f4e3bc165361b6d17e8a865d479b373ee67d89ac6f0ce871f27da1be6d") + .unwrap(); + // Right now, the uid/gid are actually that of the test runner + assert_eq!(dirmeta.mode, 0o40750); } #[test]