zip/extra_fields/ntfs.rs
1use std::io::Read;
2
3use crate::{
4 result::{ZipError, ZipResult},
5 unstable::LittleEndianReadExt,
6};
7
8/// The NTFS extra field as described in [PKWARE's APPNOTE.TXT v6.3.9].
9///
10/// This field stores [Windows file times], which are 64-bit unsigned integer
11/// values that represents the number of 100-nanosecond intervals that have
12/// elapsed since "1601-01-01 00:00:00 UTC".
13///
14/// [PKWARE's APPNOTE.TXT v6.3.9]: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
15/// [Windows file times]: https://docs.microsoft.com/en-us/windows/win32/sysinfo/file-times
16#[derive(Clone, Debug, PartialEq)]
17pub struct Ntfs {
18 mtime: u64,
19 atime: u64,
20 ctime: u64,
21}
22
23impl Ntfs {
24 /// Creates a NTFS extra field struct by reading the required bytes from the
25 /// reader.
26 ///
27 /// This method assumes that the length has already been read, therefore it
28 /// must be passed as an argument.
29 ///
30 /// # Errors
31 ///
32 /// Fails if the NTFS extra field doesn't have the correct length or a read fails
33 ///
34 pub fn try_from_reader<R>(reader: &mut R, len: u16) -> ZipResult<Self>
35 where
36 R: Read,
37 {
38 if len != 32 {
39 return Err(ZipError::UnsupportedArchive(
40 "NTFS extra field has an unsupported length",
41 ));
42 }
43
44 // Read reserved for future use.
45 let _ = reader.read_u32_le()?;
46
47 let tag = reader.read_u16_le()?;
48 if tag != 0x0001 {
49 return Err(ZipError::UnsupportedArchive(
50 "NTFS extra field has an unsupported attribute tag",
51 ));
52 }
53 let size = reader.read_u16_le()?;
54 if size != 24 {
55 return Err(ZipError::UnsupportedArchive(
56 "NTFS extra field has an unsupported attribute size",
57 ));
58 }
59
60 let mtime = reader.read_u64_le()?;
61 let atime = reader.read_u64_le()?;
62 let ctime = reader.read_u64_le()?;
63 Ok(Self {
64 mtime,
65 atime,
66 ctime,
67 })
68 }
69
70 /// Returns the file last modification time as a file time.
71 #[must_use]
72 pub fn mtime(&self) -> u64 {
73 self.mtime
74 }
75
76 /// Returns the file last modification time as a file time.
77 #[cfg(feature = "nt-time")]
78 #[must_use]
79 pub fn modified_file_time(&self) -> nt_time::FileTime {
80 nt_time::FileTime::new(self.mtime)
81 }
82
83 /// Returns the file last access time as a file time.
84 #[must_use]
85 pub fn atime(&self) -> u64 {
86 self.atime
87 }
88
89 /// Returns the file last access time as a file time.
90 #[cfg(feature = "nt-time")]
91 #[must_use]
92 pub fn accessed_file_time(&self) -> nt_time::FileTime {
93 nt_time::FileTime::new(self.atime)
94 }
95
96 /// Returns the file creation time as a file time.
97 #[must_use]
98 pub fn ctime(&self) -> u64 {
99 self.ctime
100 }
101
102 /// Returns the file creation time as a file time.
103 #[cfg(feature = "nt-time")]
104 #[must_use]
105 pub fn created_file_time(&self) -> nt_time::FileTime {
106 nt_time::FileTime::new(self.ctime)
107 }
108}