#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct CreatorSystem(u8);
impl CreatorSystem {
pub const FAT: Self = Self(0);
pub const UNIX: Self = Self(3);
pub const NTFS: Self = Self(10);
pub const MVS: Self = Self(11);
pub const VFAT: Self = Self(14);
pub const MACOS: Self = Self(19);
#[inline]
pub const fn new(id: u8) -> Self {
Self(id)
}
#[inline]
pub const fn as_u8(self) -> u8 {
self.0
}
#[inline]
pub const fn name(self) -> Option<&'static str> {
match self.0 {
0 => Some("FAT"),
3 => Some("UNIX"),
10 => Some("NTFS"),
11 => Some("MVS"),
14 => Some("VFAT"),
19 => Some("MACOS"),
_ => None,
}
}
}
impl core::fmt::Debug for CreatorSystem {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.name() {
Some(name) => write!(f, "CreatorSystem::{name}"),
None => write!(f, "CreatorSystem({})", self.0),
}
}
}
impl core::fmt::Display for CreatorSystem {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{} ({})", self.0, self.name().unwrap_or("UNKNOWN"))
}
}
impl From<u8> for CreatorSystem {
fn from(id: u8) -> Self {
Self(id)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VersionMadeBy(u16);
impl VersionMadeBy {
#[inline]
pub(crate) const fn new(system: CreatorSystem, zip_version: u8) -> Self {
Self(((system.as_u8() as u16) << 8) | zip_version as u16)
}
#[inline]
pub const fn from_raw(value: u16) -> Self {
Self(value)
}
#[inline]
pub const fn creator_system(self) -> CreatorSystem {
CreatorSystem((self.0 >> 8) as u8)
}
#[inline]
pub const fn zip_version(self) -> u8 {
self.0 as u8
}
#[inline]
pub const fn as_u16(self) -> u16 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EntryMode(u32);
impl EntryMode {
#[must_use]
pub(crate) const fn new(value: u32) -> Self {
Self(value)
}
#[must_use]
pub const fn value(&self) -> u32 {
self.0
}
#[must_use]
pub const fn is_symlink(&self) -> bool {
self.0 & S_IFMT == S_IFLNK
}
#[must_use]
pub const fn permissions(&self) -> u32 {
self.0 & 0o777
}
}
const S_IFMT: u32 = 0o170000; const S_IFSOCK: u32 = 0o140000; const S_IFLNK: u32 = 0o120000; const S_IFREG: u32 = 0o100000; const S_IFBLK: u32 = 0o060000; const S_IFDIR: u32 = 0o040000; const S_IFCHR: u32 = 0o020000; const S_IFIFO: u32 = 0o010000; const S_ISUID: u32 = 0o004000; const S_ISGID: u32 = 0o002000; const S_ISVTX: u32 = 0o001000;
pub(crate) const MSDOS_DIR: u32 = 0x10;
const MSDOS_READONLY: u32 = 0x01;
pub(crate) fn unix_mode_to_file_mode(m: u32) -> u32 {
let mut mode = m & 0o777;
match m & S_IFMT {
S_IFBLK => mode |= S_IFBLK,
S_IFCHR => mode |= S_IFCHR,
S_IFDIR => mode |= S_IFDIR,
S_IFIFO => mode |= S_IFIFO,
S_IFLNK => mode |= S_IFLNK,
S_IFSOCK => mode |= S_IFSOCK,
_ => mode |= S_IFREG, }
if m & S_ISGID != 0 {
mode |= S_ISGID;
}
if m & S_ISUID != 0 {
mode |= S_ISUID;
}
if m & S_ISVTX != 0 {
mode |= S_ISVTX;
}
mode
}
pub(crate) fn msdos_mode_to_file_mode(m: u32) -> u32 {
if m & MSDOS_DIR != 0 {
S_IFDIR | 0o777
} else if m & MSDOS_READONLY != 0 {
S_IFREG | 0o444
} else {
S_IFREG | 0o666
}
}
#[cfg(test)]
mod tests {
use super::*;
extern crate alloc;
use alloc::format;
#[test]
fn creator_system_known_names() {
assert_eq!(CreatorSystem::FAT.name(), Some("FAT"));
assert_eq!(CreatorSystem::UNIX.name(), Some("UNIX"));
assert_eq!(CreatorSystem::NTFS.name(), Some("NTFS"));
assert_eq!(CreatorSystem::MVS.name(), Some("MVS"));
assert_eq!(CreatorSystem::VFAT.name(), Some("VFAT"));
assert_eq!(CreatorSystem::MACOS.name(), Some("MACOS"));
assert_eq!(CreatorSystem::new(7).name(), None);
assert_eq!(CreatorSystem::NTFS.as_u8(), 10);
assert_eq!(CreatorSystem::MVS.as_u8(), 11);
}
#[test]
fn creator_system_raw_roundtrip() {
for id in [0u8, 3, 10, 11, 14, 19, 7, 255] {
assert_eq!(CreatorSystem::new(id).as_u8(), id);
assert_eq!(CreatorSystem::from(id), CreatorSystem::new(id));
}
}
#[test]
fn creator_system_debug_and_display() {
assert_eq!(format!("{:?}", CreatorSystem::UNIX), "CreatorSystem::UNIX");
assert_eq!(format!("{:?}", CreatorSystem::new(7)), "CreatorSystem(7)");
assert_eq!(format!("{}", CreatorSystem::UNIX), "3 (UNIX)");
assert_eq!(format!("{}", CreatorSystem::new(7)), "7 (UNKNOWN)");
}
#[test]
fn version_made_by_decomposition() {
let v = VersionMadeBy::from_raw(0x031e);
assert_eq!(v.creator_system(), CreatorSystem::UNIX);
assert_eq!(v.zip_version(), 30);
assert_eq!(v.as_u16(), 0x031e);
}
#[test]
fn version_made_by_new_matches_raw() {
let v = VersionMadeBy::new(CreatorSystem::MACOS, 20);
assert_eq!(v.as_u16(), (19 << 8) | 20);
assert_eq!(v.creator_system(), CreatorSystem::MACOS);
assert_eq!(v.zip_version(), 20);
}
}