Skip to main content

async_deflate_zip/writer/
entry_options.rs

1use std::path::Path;
2use std::time::SystemTime;
3
4#[cfg(unix)]
5use std::os::unix::fs::{MetadataExt, PermissionsExt};
6
7use tokio::fs;
8
9/// Per-entry options for appending to a ZIP archive.
10///
11/// Passed to [`ZipWriter::append_file`](crate::writer::ZipWriter::append_file),
12/// [`ZipWriter::append_directory`](crate::writer::ZipWriter::append_directory),
13/// and [`ZipWriter::append_symlink`](crate::writer::ZipWriter::append_symlink)
14/// to control metadata such as
15/// modification time, Unix permissions, UID/GID, and file comment.
16///
17/// Use the convenience constructors for common cases:
18/// - [`file`](EntryOptions::file) — 0644 + current time
19/// - [`directory`](EntryOptions::directory) — 0755 + current time
20/// - [`symlink`](EntryOptions::symlink) — 0777 + current time
21/// - [`from_path`](EntryOptions::from_path) — read metadata from a real file
22///
23/// For full control, construct the struct directly:
24///
25/// ```rust,no_run
26/// use async_deflate_zip::EntryOptions;
27/// use std::time::SystemTime;
28///
29/// let opts = EntryOptions {
30///     mtime: SystemTime::UNIX_EPOCH,
31///     permissions: Some(0o755),
32///     uid_gid: Some((1000, 1000)),
33///     comment: Some("my file".to_string()),
34/// };
35/// ```
36pub struct EntryOptions {
37    /// Last modification time. Stored in MS-DOS format in the fixed CD fields
38    /// and as a Unix timestamp in the extended timestamp extra field (0x5455).
39    pub mtime: SystemTime,
40    /// Unix permission bits (e.g. `0o644`, `0o755`). The file type bit
41    /// (`S_IFREG`/`S_IFDIR`/`S_IFLNK`) is added automatically by the writer.
42    /// When `None`, no Unix permissions are written.
43    pub permissions: Option<u32>,
44    /// Unix user and group IDs. Stored in the 0x7875 (Ux) extra field.
45    pub uid_gid: Option<(u32, u32)>,
46    /// Per-entry comment stored in the Central Directory.
47    /// Maximum length is 65535 bytes. Comments longer than this will
48    /// cause `finalize` to return [`ZipError::FieldTooLong`](crate::error::ZipError::FieldTooLong).
49    pub comment: Option<String>,
50}
51
52impl Default for EntryOptions {
53    fn default() -> Self {
54        Self {
55            mtime: SystemTime::now(),
56            permissions: None,
57            uid_gid: None,
58            comment: None,
59        }
60    }
61}
62
63impl EntryOptions {
64    /// Read metadata (mtime, permissions, uid/gid) from a real filesystem path.
65    ///
66    /// The file's content is **not** read — only `symlink_metadata` is queried
67    /// so this works on symlinks, directories, and regular files alike.
68    ///
69    /// On Unix, permission bits are extracted from the file's mode and
70    /// UID/GID from the file's owner. On non-Unix platforms, permissions
71    /// default to `None` and UID/GID to `None`.
72    pub async fn from_path<T: AsRef<Path>>(path: T) -> std::io::Result<Self> {
73        let meta = fs::symlink_metadata(&path).await?;
74        Ok(Self {
75            mtime: meta.modified().unwrap_or_else(|_| SystemTime::now()),
76            #[cfg(unix)]
77            permissions: Some(meta.permissions().mode() & 0o7777),
78            #[cfg(not(unix))]
79            permissions: None,
80            uid_gid: {
81                #[cfg(unix)]
82                {
83                    Some((meta.uid(), meta.gid()))
84                }
85                #[cfg(not(unix))]
86                {
87                    None
88                }
89            },
90            comment: None,
91        })
92    }
93
94    /// Convenience options for a regular file: permissions `0o644`,
95    /// modification time set to now.
96    pub fn file() -> Self {
97        Self {
98            mtime: SystemTime::now(),
99            permissions: Some(0o644),
100            ..Default::default()
101        }
102    }
103
104    /// Convenience options for a directory: permissions `0o755`,
105    /// modification time set to now.
106    pub fn directory() -> Self {
107        Self {
108            mtime: SystemTime::now(),
109            permissions: Some(0o755),
110            ..Default::default()
111        }
112    }
113
114    /// Convenience options for a symbolic link: permissions `0o777`,
115    /// modification time set to now.
116    pub fn symlink() -> Self {
117        Self {
118            mtime: SystemTime::now(),
119            permissions: Some(0o777),
120            ..Default::default()
121        }
122    }
123}