Skip to main content

compression/
aa_entry_stream.rs

1use crate::{
2    aa_byte_stream::ArchiveFlags, aa_header::Timespec, ffi, util, CompressionError, Result,
3};
4use std::ffi::{c_void, CStr};
5use std::ptr::{null, NonNull};
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
8#[repr(u32)]
9pub enum EntryMessage {
10    SearchPruneDir = 10,
11    SearchExclude = 11,
12    SearchFail = 12,
13    ExtractBegin = 20,
14    ExtractEnd = 21,
15    ExtractFail = 22,
16    ExtractAttributes = 23,
17    ExtractXat = 24,
18    ExtractAcl = 25,
19    EncodeScanning = 30,
20    EncodeWriting = 31,
21    ConvertExclude = 40,
22    ProcessExclude = 50,
23    DecodeReading = 60,
24}
25
26impl EntryMessage {
27    pub(crate) const fn from_raw(raw: u32) -> Option<Self> {
28        match raw {
29            x if x == Self::SearchPruneDir as u32 => Some(Self::SearchPruneDir),
30            x if x == Self::SearchExclude as u32 => Some(Self::SearchExclude),
31            x if x == Self::SearchFail as u32 => Some(Self::SearchFail),
32            x if x == Self::ExtractBegin as u32 => Some(Self::ExtractBegin),
33            x if x == Self::ExtractEnd as u32 => Some(Self::ExtractEnd),
34            x if x == Self::ExtractFail as u32 => Some(Self::ExtractFail),
35            x if x == Self::ExtractAttributes as u32 => Some(Self::ExtractAttributes),
36            x if x == Self::ExtractXat as u32 => Some(Self::ExtractXat),
37            x if x == Self::ExtractAcl as u32 => Some(Self::ExtractAcl),
38            x if x == Self::EncodeScanning as u32 => Some(Self::EncodeScanning),
39            x if x == Self::EncodeWriting as u32 => Some(Self::EncodeWriting),
40            x if x == Self::ConvertExclude as u32 => Some(Self::ConvertExclude),
41            x if x == Self::ProcessExclude as u32 => Some(Self::ProcessExclude),
42            x if x == Self::DecodeReading as u32 => Some(Self::DecodeReading),
43            _ => None,
44        }
45    }
46}
47
48#[repr(C)]
49#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
50pub struct EntryAttributes {
51    pub bits: u32,
52    pub uid: u32,
53    pub gid: u32,
54    pub flags: u32,
55    pub mode: u32,
56    pub backup_time: Timespec,
57    pub creation_time: Timespec,
58    pub modification_time: Timespec,
59}
60
61impl EntryAttributes {
62    pub const UID_BIT: u32 = 1 << 0;
63    pub const GID_BIT: u32 = 1 << 1;
64    pub const FLAGS_BIT: u32 = 1 << 2;
65    pub const MODE_BIT: u32 = 1 << 3;
66    pub const BACKUP_TIME_BIT: u32 = 1 << 4;
67    pub const CREATION_TIME_BIT: u32 = 1 << 5;
68    pub const MODIFICATION_TIME_BIT: u32 = 1 << 6;
69
70    pub const fn has_uid(self) -> bool {
71        self.bits & Self::UID_BIT != 0
72    }
73
74    pub const fn has_gid(self) -> bool {
75        self.bits & Self::GID_BIT != 0
76    }
77
78    pub const fn has_flags(self) -> bool {
79        self.bits & Self::FLAGS_BIT != 0
80    }
81
82    pub const fn has_mode(self) -> bool {
83        self.bits & Self::MODE_BIT != 0
84    }
85}
86
87#[derive(Debug)]
88pub struct PathList {
89    handle: NonNull<c_void>,
90}
91
92impl PathList {
93    pub const END_NODE: u64 = u64::MAX;
94
95    pub fn from_directory_contents(
96        dir: &str,
97        path: Option<&str>,
98        flags: ArchiveFlags,
99        n_threads: i32,
100    ) -> Result<Self> {
101        let dir = util::cstring("dir", dir)?;
102        let path_cstring = path.map(|value| util::cstring("path", value)).transpose()?;
103        let handle = unsafe {
104            ffi::aa_entry_stream::compression_rs_aa_path_list_create_with_directory_contents(
105                dir.as_ptr(),
106                path_cstring.as_ref().map_or(null(), |value| value.as_ptr()),
107                flags.bits(),
108                n_threads,
109            )
110        };
111        Ok(Self {
112            handle: util::nonnull_handle(handle, "AAPathListCreateWithDirectoryContents")?,
113        })
114    }
115
116    pub fn from_path(dir: &str, path: &str) -> Result<Self> {
117        let dir = util::cstring("dir", dir)?;
118        let path = util::cstring("path", path)?;
119        let handle = unsafe {
120            ffi::aa_entry_stream::compression_rs_aa_path_list_create_with_path(
121                dir.as_ptr(),
122                path.as_ptr(),
123            )
124        };
125        Ok(Self {
126            handle: util::nonnull_handle(handle, "AAPathListCreateWithPath")?,
127        })
128    }
129
130    pub(crate) fn as_ptr(&self) -> *mut c_void {
131        self.handle.as_ptr()
132    }
133
134    pub fn first_node(&self) -> Option<u64> {
135        let node =
136            unsafe { ffi::aa_entry_stream::compression_rs_aa_path_list_node_first(self.as_ptr()) };
137        (node != Self::END_NODE).then_some(node)
138    }
139
140    pub fn next_node(&self, node: u64) -> Option<u64> {
141        let next = unsafe {
142            ffi::aa_entry_stream::compression_rs_aa_path_list_node_next(self.as_ptr(), node)
143        };
144        (next != Self::END_NODE).then_some(next)
145    }
146
147    pub fn node_path(&self, node: u64) -> Result<String> {
148        let mut length = 0_usize;
149        let status = unsafe {
150            ffi::aa_entry_stream::compression_rs_aa_path_list_node_get_path(
151                self.as_ptr(),
152                node,
153                0,
154                std::ptr::null_mut(),
155                &mut length,
156            )
157        };
158        util::status_result("AAPathListNodeGetPath", status)?;
159
160        let mut buffer = vec![0_i8; length.saturating_add(1)];
161        let status = unsafe {
162            ffi::aa_entry_stream::compression_rs_aa_path_list_node_get_path(
163                self.as_ptr(),
164                node,
165                buffer.len(),
166                buffer.as_mut_ptr(),
167                &mut length,
168            )
169        };
170        util::status_result("AAPathListNodeGetPath", status)?;
171
172        let value = unsafe { CStr::from_ptr(buffer.as_ptr()) }
173            .to_str()
174            .map_err(|_| CompressionError::Utf8Error {
175                operation: "AAPathListNodeGetPath",
176            })?;
177        Ok(value.to_string())
178    }
179
180    pub fn paths(&self) -> Result<Vec<String>> {
181        let mut paths = Vec::new();
182        let mut node = self.first_node();
183        while let Some(current) = node {
184            paths.push(self.node_path(current)?);
185            node = self.next_node(current);
186        }
187        Ok(paths)
188    }
189}
190
191impl Drop for PathList {
192    fn drop(&mut self) {
193        unsafe { ffi::aa_entry_stream::compression_rs_aa_path_list_release(self.as_ptr()) };
194    }
195}