repo: Add an API to read and parse directory metadata
The fact that the uid/gid/mode are big endian bit me when I was trying to parse this "by hand" in ostree-rs-ext. Let's add a footgun-free API for this. (And yeah, we should probably do the same for the other variant types)
This commit is contained in:
parent
f01c847a68
commit
d1731d0ea8
|
|
@ -19,3 +19,30 @@ pub type TreeVariantType = (Vec<(String, Vec<u8>)>, Vec<(String, Vec<u8>, Vec<u8
|
||||||
|
|
||||||
/// The type of a directory metadata object: `(uuua(ayay))`
|
/// The type of a directory metadata object: `(uuua(ayay))`
|
||||||
pub type DirmetaVariantType = (u32, u32, u32, Vec<(Vec<u8>, Vec<u8>)>);
|
pub type DirmetaVariantType = (u32, u32, u32, Vec<(Vec<u8>, Vec<u8>)>);
|
||||||
|
|
||||||
|
/// 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<u8>, Vec<u8>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirMetaParsed {
|
||||||
|
/// Parse a directory metadata variant; must be of type `(uuua(ayay))`.
|
||||||
|
pub fn from_variant(
|
||||||
|
v: &glib::Variant,
|
||||||
|
) -> Result<DirMetaParsed, glib::variant::VariantTypeMismatchError> {
|
||||||
|
let (uid, gid, mode, xattrs) = v.try_get::<crate::DirmetaVariantType>()?;
|
||||||
|
Ok(DirMetaParsed {
|
||||||
|
uid: u32::from_be(uid),
|
||||||
|
gid: u32::from_be(gid),
|
||||||
|
mode: u32::from_be(mode),
|
||||||
|
xattrs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<crate::DirMetaParsed, glib::Error> {
|
||||||
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ fn should_commit_content_to_repo_and_list_refs_again() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_traverse_commit() {
|
fn repo_traverse_and_read() {
|
||||||
let test_repo = TestRepo::new();
|
let test_repo = TestRepo::new();
|
||||||
let checksum = test_repo.test_commit("test");
|
let checksum = test_repo.test_commit("test");
|
||||||
|
|
||||||
|
|
@ -58,6 +58,13 @@ fn should_traverse_commit() {
|
||||||
),
|
),
|
||||||
objects
|
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]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue