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))`
|
||||
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]
|
||||
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]
|
||||
|
|
|
|||
Loading…
Reference in New Issue