zip/extra_fields/
ntfs.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use std::io::Read;

use crate::{
    result::{ZipError, ZipResult},
    unstable::LittleEndianReadExt,
};

/// The NTFS extra field as described in [PKWARE's APPNOTE.TXT v6.3.9].
///
/// This field stores [Windows file times], which are 64-bit unsigned integer
/// values that represents the number of 100-nanosecond intervals that have
/// elapsed since "1601-01-01 00:00:00 UTC".
///
/// [PKWARE's APPNOTE.TXT v6.3.9]: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
/// [Windows file times]: https://docs.microsoft.com/en-us/windows/win32/sysinfo/file-times
#[derive(Clone, Debug)]
pub struct Ntfs {
    mtime: u64,
    atime: u64,
    ctime: u64,
}

impl Ntfs {
    /// Creates a NTFS extra field struct by reading the required bytes from the
    /// reader.
    ///
    /// This method assumes that the length has already been read, therefore it
    /// must be passed as an argument.
    pub fn try_from_reader<R>(reader: &mut R, len: u16) -> ZipResult<Self>
    where
        R: Read,
    {
        if len != 32 {
            return Err(ZipError::UnsupportedArchive(
                "NTFS extra field has an unsupported length",
            ));
        }

        // Read reserved for future use.
        let _ = reader.read_u32_le()?;

        let tag = reader.read_u16_le()?;
        if tag != 0x0001 {
            return Err(ZipError::UnsupportedArchive(
                "NTFS extra field has an unsupported attribute tag",
            ));
        }
        let size = reader.read_u16_le()?;
        if size != 24 {
            return Err(ZipError::UnsupportedArchive(
                "NTFS extra field has an unsupported attribute size",
            ));
        }

        let mtime = reader.read_u64_le()?;
        let atime = reader.read_u64_le()?;
        let ctime = reader.read_u64_le()?;
        Ok(Self {
            mtime,
            atime,
            ctime,
        })
    }

    /// Returns the file last modification time as a file time.
    pub fn mtime(&self) -> u64 {
        self.mtime
    }

    /// Returns the file last modification time as a file time.
    #[cfg(feature = "nt-time")]
    pub fn modified_file_time(&self) -> nt_time::FileTime {
        nt_time::FileTime::new(self.mtime)
    }

    /// Returns the file last access time as a file time.
    pub fn atime(&self) -> u64 {
        self.atime
    }

    /// Returns the file last access time as a file time.
    #[cfg(feature = "nt-time")]
    pub fn accessed_file_time(&self) -> nt_time::FileTime {
        nt_time::FileTime::new(self.atime)
    }

    /// Returns the file creation time as a file time.
    pub fn ctime(&self) -> u64 {
        self.ctime
    }

    /// Returns the file creation time as a file time.
    #[cfg(feature = "nt-time")]
    pub fn created_file_time(&self) -> nt_time::FileTime {
        nt_time::FileTime::new(self.ctime)
    }
}