1use std::io::Read;
23use crate::{
4 result::{ZipError, ZipResult},
5 unstable::LittleEndianReadExt,
6};
78/// 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)]
17pub struct Ntfs {
18 mtime: u64,
19 atime: u64,
20 ctime: u64,
21}
2223impl 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.
29pub fn try_from_reader<R>(reader: &mut R, len: u16) -> ZipResult<Self>
30where
31R: Read,
32 {
33if len != 32 {
34return Err(ZipError::UnsupportedArchive(
35"NTFS extra field has an unsupported length",
36 ));
37 }
3839// Read reserved for future use.
40let _ = reader.read_u32_le()?;
4142let tag = reader.read_u16_le()?;
43if tag != 0x0001 {
44return Err(ZipError::UnsupportedArchive(
45"NTFS extra field has an unsupported attribute tag",
46 ));
47 }
48let size = reader.read_u16_le()?;
49if size != 24 {
50return Err(ZipError::UnsupportedArchive(
51"NTFS extra field has an unsupported attribute size",
52 ));
53 }
5455let mtime = reader.read_u64_le()?;
56let atime = reader.read_u64_le()?;
57let ctime = reader.read_u64_le()?;
58Ok(Self {
59 mtime,
60 atime,
61 ctime,
62 })
63 }
6465/// Returns the file last modification time as a file time.
66pub fn mtime(&self) -> u64 {
67self.mtime
68 }
6970/// Returns the file last modification time as a file time.
71#[cfg(feature = "nt-time")]
72pub fn modified_file_time(&self) -> nt_time::FileTime {
73 nt_time::FileTime::new(self.mtime)
74 }
7576/// Returns the file last access time as a file time.
77pub fn atime(&self) -> u64 {
78self.atime
79 }
8081/// Returns the file last access time as a file time.
82#[cfg(feature = "nt-time")]
83pub fn accessed_file_time(&self) -> nt_time::FileTime {
84 nt_time::FileTime::new(self.atime)
85 }
8687/// Returns the file creation time as a file time.
88pub fn ctime(&self) -> u64 {
89self.ctime
90 }
9192/// Returns the file creation time as a file time.
93#[cfg(feature = "nt-time")]
94pub fn created_file_time(&self) -> nt_time::FileTime {
95 nt_time::FileTime::new(self.ctime)
96 }
97}