Skip to main content

zub/types/
metadata.rs

1use serde::{Deserialize, Serialize};
2
3/// extended attribute (name + value)
4#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
5pub struct Xattr {
6    pub name: String,
7    pub value: Vec<u8>,
8}
9
10impl Xattr {
11    pub fn new(name: impl Into<String>, value: impl Into<Vec<u8>>) -> Self {
12        Self {
13            name: name.into(),
14            value: value.into(),
15        }
16    }
17}
18
19/// a data region in a sparse file
20/// holes are implicit (gaps between regions)
21#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
22pub struct SparseRegion {
23    /// offset where this data region starts in the logical file
24    pub offset: u64,
25    /// length of this data region
26    pub length: u64,
27}
28
29impl SparseRegion {
30    pub fn new(offset: u64, length: u64) -> Self {
31        Self { offset, length }
32    }
33
34    /// end offset of this region (exclusive)
35    pub fn end(&self) -> u64 {
36        self.offset + self.length
37    }
38}
39
40/// diff entry change kind
41#[derive(Clone, Debug, PartialEq, Eq)]
42pub enum ChangeKind {
43    Added,
44    Modified,
45    Deleted,
46    MetadataOnly,
47}
48
49impl std::fmt::Display for ChangeKind {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        match self {
52            ChangeKind::Added => write!(f, "A"),
53            ChangeKind::Modified => write!(f, "M"),
54            ChangeKind::Deleted => write!(f, "D"),
55            ChangeKind::MetadataOnly => write!(f, "m"),
56        }
57    }
58}
59
60/// entry in a diff result
61#[derive(Clone, Debug, PartialEq, Eq)]
62pub struct DiffEntry {
63    pub path: String,
64    pub kind: ChangeKind,
65}
66
67impl std::fmt::Display for DiffEntry {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        write!(f, "{} {}", self.kind, self.path)
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_xattr_creation() {
79        let x = Xattr::new("security.selinux", vec![1, 2, 3]);
80        assert_eq!(x.name, "security.selinux");
81        assert_eq!(x.value, vec![1, 2, 3]);
82    }
83
84    #[test]
85    fn test_sparse_region() {
86        let r = SparseRegion::new(100, 50);
87        assert_eq!(r.offset, 100);
88        assert_eq!(r.length, 50);
89        assert_eq!(r.end(), 150);
90    }
91
92    #[test]
93    fn test_change_kind_display() {
94        assert_eq!(format!("{}", ChangeKind::Added), "A");
95        assert_eq!(format!("{}", ChangeKind::Modified), "M");
96        assert_eq!(format!("{}", ChangeKind::Deleted), "D");
97        assert_eq!(format!("{}", ChangeKind::MetadataOnly), "m");
98    }
99}