1use std::fmt;
2
3use nom::IResult;
4use nom::number::streaming::be_u32;
5use nom::number::streaming::be_u64;
6use nom::number::streaming::le_u32;
7use nom::number::streaming::le_u64;
8
9use serde::ser::Serialize;
10use serde::ser::Serializer;
11use serde::ser::SerializeStruct;
12
13#[cfg(test)]
14mod arbitrary;
15
16bitflags::bitflags! {
17 #[derive(Default)]
18 pub struct FileAttrFlags: u32 {
19 const Size = 0x00000001;
20 const UidGid = 0x00000002;
21 const Permissions = 0x00000004;
22 const ACModTime = 0x00000008;
23 const Extended = 0x80000000;
24 }
25}
26
27impl<I: nom_derive::InputSlice> nom_derive::Parse<I> for FileAttrFlags {
28 fn parse_be(i: I) -> IResult<I, Self> {
29 let (i, flags) = be_u32(i)?;
30 let this = Self::from_bits_truncate(flags);
31 Ok((i, this))
32 }
33
34 fn parse_le(i: I) -> IResult<I, Self> {
35 let (i, flags) = le_u32(i)?;
36 let this = Self::from_bits_truncate(flags);
37 Ok((i, this))
38 }
39
40 fn parse(i: I) -> IResult<I, Self> {
41 Self::parse_be(i)
42 }
43}
44
45#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
46#[repr(transparent)]
47pub struct Permissions(u32);
48impl fmt::Display for Permissions {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
50 write!(f, "{}{}{}{}{}{}{}{}{}{}", self.dir(), self.owner_r(), self.owner_w(), self.owner_x(), self.group_r(), self.group_w(), self.group_x(), self.other_r(), self.other_w(), self.other_x())
51 }
52}
53
54impl Permissions {
55 fn dir(self) -> char {
56 match self.0 & 0o40000 {
57 0 => '-',
58 _ => 'd'
59 }
60 } fn owner_r(self) -> char {
63 match self.0 & 0o400 {
64 0 => '-',
65 _ => 'r'
66 }
67 } fn owner_w(self) -> char {
70 match self.0 & 0o200 {
71 0 => '-',
72 _ => 'w'
73 }
74 } fn owner_x(self) -> char {
77 match self.0 & 0o100 {
78 0 => '-',
79 _ => 'x'
80 }
81 } fn group_r(self) -> char {
84 match self.0 & 0o040 {
85 0 => '-',
86 _ => 'r'
87 }
88 } fn group_w(self) -> char {
91 match self.0 & 0o020 {
92 0 => '-',
93 _ => 'w'
94 }
95 } fn group_x(self) -> char {
98 match self.0 & 0o010 {
99 0 => '-',
100 _ => 'x'
101 }
102 } fn other_r(self) -> char {
105 match self.0 & 0o004 {
106 0 => '-',
107 _ => 'r'
108 }
109 } fn other_w(self) -> char {
112 match self.0 & 0o002 {
113 0 => '-',
114 _ => 'w'
115 }
116 } fn other_x(self) -> char {
119 match self.0 & 0o001 {
120 0 => '-',
121 _ => 'x'
122 }
123 } }
125
126impl From<u32> for Permissions {
127 fn from(raw: u32) -> Self {
128 Self(raw)
129 }
130}
131
132#[derive(Clone, Debug, Default, Eq, PartialEq)]
133pub struct FileAttributes {
134 pub flags: FileAttrFlags,
135 pub size: Option<u64>,
136 pub uid: Option<u32>,
137 pub gid: Option<u32>,
138 pub permissions: Option<Permissions>,
139 pub atime: Option<u32>,
140 pub mtime: Option<u32>,
141 }
143
144fn format_month(ts: &time::OffsetDateTime) -> &'static str {
145 match ts.month() {
146 time::Month::January => "Jan",
147 time::Month::February => "Feb",
148 time::Month::March => "Mar",
149 time::Month::April => "Apr",
150 time::Month::May => "May",
151 time::Month::June => "Jun",
152 time::Month::July => "Jul",
153 time::Month::August => "Aug",
154 time::Month::September => "Sep",
155 time::Month::October => "Oct",
156 time::Month::November => "Nov",
157 time::Month::December => "Dec"
158 }
159}
160
161impl fmt::Display for FileAttributes {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
163 match self.permissions {
164 Some(v) => write!(f, "{} ", v)?,
165 None => write!(f, " ")?
166 };
168 write!(f, " 1 ")?;
170 match self.uid {
172 Some(v) => write!(f, "{: <8} ", v)?,
173 None => write!(f, " ")?
174 };
176 match self.gid {
177 Some(v) => write!(f, "{: <8} ", v)?,
178 None => write!(f, " ")?
179 };
181 match self.size {
182 Some(v) => write!(f, "{: >8} ", v)?,
183 None => write!(f, " ")?
184 };
186 match self.mtime {
187 Some(v) => {
188 let time = time::OffsetDateTime::from_unix_timestamp(v.into()).unwrap();
190 write!(f, "{} {: >2} {:0>2}:{:0>2} ", format_month(&time), time.day(), time.hour(), time.minute())?
191 },
192 None => write!(f, " ")?
193 };
195 Ok(())
196 }
197}
198
199impl Serialize for FileAttributes {
200 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
201 let mut field_count = 1;
202 if(self.flags.contains(FileAttrFlags::Size)) {
203 field_count += 1;
204 }
205 if(self.flags.contains(FileAttrFlags::UidGid)) {
206 field_count += 2;
207 }
208 if(self.flags.contains(FileAttrFlags::Permissions)) {
209 field_count += 1;
210 }
211 if(self.flags.contains(FileAttrFlags::ACModTime)) {
212 field_count += 2;
213 }
214 let mut state = serializer.serialize_struct("FileAttributes", field_count)?;
216 state.serialize_field("flags", &self.flags.bits())?;
217 if(self.flags.contains(FileAttrFlags::Size)) {
218 state.serialize_field("size", &self.size.unwrap_or(0))?;
219 }
220 if(self.flags.contains(FileAttrFlags::UidGid)) {
221 state.serialize_field("uid", &self.uid.unwrap_or(0))?;
222 state.serialize_field("gid", &self.gid.unwrap_or(0))?;
223 }
224 if(self.flags.contains(FileAttrFlags::Permissions)) {
225 state.serialize_field("permissions", &self.permissions.unwrap_or_default())?;
226 }
227 if(self.flags.contains(FileAttrFlags::ACModTime)) {
228 state.serialize_field("atime", &self.atime.unwrap_or(0))?;
229 state.serialize_field("mtime", &self.mtime.unwrap_or(0))?;
230 }
231 state.end()
232 } }
234
235impl<I: nom_derive::InputSlice> nom_derive::Parse<I> for FileAttributes {
236 fn parse_be(i: I) -> IResult<I, Self> {
237 let (mut i, flags) = FileAttrFlags::parse(i)?;
238 let mut attrs = Self{
239 flags,
240 ..Default::default()
241 };
242 if(attrs.flags.contains(FileAttrFlags::Size)) {
243 let (i_inner, size) = be_u64(i)?;
244 i = i_inner;
245 attrs.size = Some(size);
246 }
247 if(attrs.flags.contains(FileAttrFlags::UidGid)) {
248 let (i_inner, uid) = be_u32(i)?;
249 let (i_inner, gid) = be_u32(i_inner)?;
250 i = i_inner;
251 attrs.uid = Some(uid);
252 attrs.gid = Some(gid);
253 }
254 if(attrs.flags.contains(FileAttrFlags::Permissions)) {
255 let (i_inner, permissions) = be_u32(i)?;
256 i = i_inner;
257 attrs.permissions = Some(permissions.into());
258 }
259 if(attrs.flags.contains(FileAttrFlags::ACModTime)) {
260 let (i_inner, atime) = be_u32(i)?;
261 let (i_inner, mtime) = be_u32(i_inner)?;
262 i = i_inner;
263 attrs.atime = Some(atime);
264 attrs.mtime = Some(mtime);
265 }
266 Ok((i, attrs))
267 } fn parse_le(i: I) -> IResult<I, Self> {
270 let mut attrs = FileAttributes::default();
271 let (mut i, flags) = FileAttrFlags::parse(i)?;
272 attrs.flags = flags;
273 if(attrs.flags.contains(FileAttrFlags::Size)) {
274 let (i_inner, size) = le_u64(i)?;
275 i = i_inner;
276 attrs.size = Some(size);
277 }
278 if(attrs.flags.contains(FileAttrFlags::UidGid)) {
279 let (i_inner, uid) = le_u32(i)?;
280 let (i_inner, gid) = le_u32(i_inner)?;
281 i = i_inner;
282 attrs.uid = Some(uid);
283 attrs.gid = Some(gid);
284 }
285 if(attrs.flags.contains(FileAttrFlags::Permissions)) {
286 let (i_inner, permissions) = le_u32(i)?;
287 i = i_inner;
288 attrs.permissions = Some(permissions.into());
289 }
290 if(attrs.flags.contains(FileAttrFlags::ACModTime)) {
291 let (i_inner, atime) = le_u32(i)?;
292 let (i_inner, mtime) = le_u32(i_inner)?;
293 i = i_inner;
294 attrs.atime = Some(atime);
295 attrs.mtime = Some(mtime);
296 }
297 Ok((i, attrs))
298 } fn parse(i: I) -> IResult<I, Self> {
301 Self::parse_be(i)
302 }
303}
304
305impl FileAttributes {
306 pub fn new() -> Self {
307 Self{
308 flags: FileAttrFlags::from_bits_truncate(0),
309 ..Default::default()
310 }
311 } pub fn set_size(&mut self, size: u64) {
314 self.flags.set(FileAttrFlags::Size, true);
315 self.size = Some(size);
316 } pub fn get_uid_gid(&self) -> Option<(u32, u32)> {
319 match self.flags.contains(FileAttrFlags::UidGid) {
320 true => Some((self.uid.unwrap(), self.gid.unwrap())),
321 false => None
322 }
323 } pub fn set_uid_gid(&mut self, uid: u32, gid: u32) {
326 self.flags.set(FileAttrFlags::UidGid, true);
327 self.uid = Some(uid);
328 self.gid = Some(gid);
329 } pub fn get_permissions(&self) -> Option<u32> {
332 self.permissions.map(|p| p.0)
333 } pub fn set_permissions(&mut self, permissions: Permissions) {
336 self.flags.set(FileAttrFlags::Permissions, true);
337 self.permissions = Some(permissions);
338 } pub fn get_atime_mtime(&self) -> Option<(u32, u32)> {
341 match self.flags.contains(FileAttrFlags::ACModTime) {
342 true => Some((self.atime.unwrap(), self.mtime.unwrap())),
343 false => None
344 }
345 } pub fn set_atime_mtime(&mut self, atime: u32, mtime: u32) {
348 self.flags.set(FileAttrFlags::ACModTime, true);
349 self.atime = Some(atime);
350 self.mtime = Some(mtime);
351 } pub fn binsize(&self) -> u32 {
354 let mut size = 4;
355 if(self.flags.contains(FileAttrFlags::Size)) {
356 size += 8;
357 }
358 if(self.flags.contains(FileAttrFlags::UidGid)) {
359 size += 8;
360 }
361 if(self.flags.contains(FileAttrFlags::Permissions)) {
362 size += 4;
363 }
364 if(self.flags.contains(FileAttrFlags::ACModTime)) {
365 size += 8;
366 }
367 size
368 } }
370
371impl From<&super::Metadata> for FileAttributes {
372 fn from(metadata: &super::Metadata) -> Self {
373 let mut this = Self::new();
374 this.set_size(metadata.size);
375 this.set_uid_gid(metadata.uid, metadata.gid);
376 this.set_permissions({
377 let mut permissions = metadata.permissions;
378 if(metadata.is_dir) {
379 permissions |= 0o40000;
380 }
381 permissions.into()
382 });
383 this.set_atime_mtime(metadata.atime.unix_timestamp() as u32, metadata.mtime.unix_timestamp() as u32);
384 this
385 }
386}
387
388impl From<super::Metadata> for FileAttributes {
389 fn from(metadata: super::Metadata) -> Self {
390 Self::from(&metadata)
391 }
392}
393