box_format/
record.rs

1use crate::{compression::Compression, path::BoxPath, AttrMap};
2
3use crate::file::{BoxMetadata, Inode};
4use std::num::NonZeroU64;
5
6#[derive(Debug, Clone)]
7pub enum Record {
8    File(FileRecord),
9    Directory(DirectoryRecord),
10    Link(LinkRecord),
11}
12
13impl Record {
14    #[inline(always)]
15    pub fn as_file(&self) -> Option<&FileRecord> {
16        match self {
17            Record::File(file) => Some(file),
18            _ => None,
19        }
20    }
21
22    #[inline(always)]
23    pub fn as_file_mut(&mut self) -> Option<&mut FileRecord> {
24        match self {
25            Record::File(file) => Some(file),
26            _ => None,
27        }
28    }
29
30    #[inline(always)]
31    pub fn as_directory(&self) -> Option<&DirectoryRecord> {
32        match self {
33            Record::Directory(dir) => Some(dir),
34            _ => None,
35        }
36    }
37
38    #[inline(always)]
39    pub fn as_directory_mut(&mut self) -> Option<&mut DirectoryRecord> {
40        match self {
41            Record::Directory(dir) => Some(dir),
42            _ => None,
43        }
44    }
45
46    #[inline(always)]
47    pub fn as_link(&self) -> Option<&LinkRecord> {
48        match self {
49            Record::Link(link) => Some(link),
50            _ => None,
51        }
52    }
53
54    #[inline(always)]
55    pub fn as_link_mut(&mut self) -> Option<&mut LinkRecord> {
56        match self {
57            Record::Link(link) => Some(link),
58            _ => None,
59        }
60    }
61
62    #[inline(always)]
63    pub fn name(&self) -> &str {
64        match self {
65            Record::File(file) => &*file.name,
66            Record::Directory(dir) => &*dir.name,
67            Record::Link(link) => &*link.name,
68        }
69    }
70
71    #[inline(always)]
72    pub fn attr<S: AsRef<str>>(&self, metadata: &BoxMetadata, key: S) -> Option<&[u8]> {
73        let key = metadata.attr_key(key.as_ref())?;
74        self.attrs().get(&key).map(|x| &**x)
75    }
76
77    #[inline(always)]
78    pub(crate) fn attrs(&self) -> &AttrMap {
79        match self {
80            Record::Directory(dir) => &dir.attrs,
81            Record::File(file) => &file.attrs,
82            Record::Link(link) => &link.attrs,
83        }
84    }
85
86    #[inline(always)]
87    pub(crate) fn attrs_mut(&mut self) -> &mut AttrMap {
88        match self {
89            Record::Directory(dir) => &mut dir.attrs,
90            Record::File(file) => &mut file.attrs,
91            Record::Link(link) => &mut link.attrs,
92        }
93    }
94}
95
96#[derive(Debug, Clone)]
97pub struct LinkRecord {
98    pub name: String,
99
100    /// The target path of the symbolic link, which is the place the link points to. A path is always relative (no leading separator),
101    /// always delimited by a `UNIT SEPARATOR U+001F` (`"\x1f"`), and may not contain
102    /// any `.` or `..` path chunks.
103    pub target: BoxPath,
104
105    /// Optional attributes for the given paths, such as Windows or Unix ACLs, last accessed time, etc.
106    pub attrs: AttrMap,
107}
108
109impl LinkRecord {
110    #[inline(always)]
111    pub fn attr<S: AsRef<str>>(&self, metadata: &BoxMetadata, key: S) -> Option<&[u8]> {
112        let key = metadata.attr_key(key.as_ref())?;
113        self.attrs.get(&key).map(|x| &**x)
114    }
115
116    #[inline(always)]
117    pub fn upcast(self) -> Record {
118        Record::Link(self)
119    }
120}
121
122#[derive(Debug, Clone)]
123pub struct DirectoryRecord {
124    /// The name of the directory
125    pub name: String, // TODO: BoxName
126
127    /// List of inodes
128    pub inodes: Vec<Inode>,
129
130    /// Optional attributes for the given paths, such as Windows or Unix ACLs, last accessed time, etc.
131    pub attrs: AttrMap,
132}
133
134impl DirectoryRecord {
135    pub fn new(name: String) -> DirectoryRecord {
136        DirectoryRecord {
137            name,
138            inodes: vec![],
139            attrs: AttrMap::new(),
140        }
141    }
142
143    #[inline(always)]
144    pub fn attr<S: AsRef<str>>(&self, metadata: &BoxMetadata, key: S) -> Option<&[u8]> {
145        let key = metadata.attr_key(key.as_ref())?;
146        self.attrs.get(&key).map(|x| &**x)
147    }
148
149    #[inline(always)]
150    pub fn upcast(self) -> Record {
151        Record::Directory(self)
152    }
153}
154
155#[derive(Debug, Clone)]
156pub struct FileRecord {
157    /// a bytestring representing the type of compression being used, always 8 bytes.
158    pub compression: Compression,
159
160    /// The exact length of the data as written, ignoring any padding.
161    pub length: u64,
162
163    /// A hint for the size of the content when decompressed. Do not trust in absolute terms.
164    pub decompressed_length: u64,
165
166    /// The position of the data in the file
167    pub data: NonZeroU64,
168
169    /// The name of the file
170    pub name: String, // TODO: add BoxName
171
172    /// Optional attributes for the given paths, such as Windows or Unix ACLs, last accessed time, etc.
173    pub attrs: AttrMap,
174}
175
176impl FileRecord {
177    #[inline(always)]
178    pub fn compression(&self) -> Compression {
179        self.compression
180    }
181
182    #[inline(always)]
183    pub fn attr<S: AsRef<str>>(&self, metadata: &BoxMetadata, key: S) -> Option<&[u8]> {
184        let key = metadata.attr_key(key.as_ref())?;
185        self.attrs.get(&key).map(|x| &**x)
186    }
187
188    #[inline(always)]
189    pub fn upcast(self) -> Record {
190        Record::File(self)
191    }
192}