Skip to main content

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}