compression/
aa_entry_stream.rs1use 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
26#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
27pub struct EntryAttributes {
28 pub bits: u32,
29 pub uid: u32,
30 pub gid: u32,
31 pub flags: u32,
32 pub mode: u32,
33 pub backup_time: Timespec,
34 pub creation_time: Timespec,
35 pub modification_time: Timespec,
36}
37
38impl EntryAttributes {
39 pub const UID_BIT: u32 = 1 << 0;
40 pub const GID_BIT: u32 = 1 << 1;
41 pub const FLAGS_BIT: u32 = 1 << 2;
42 pub const MODE_BIT: u32 = 1 << 3;
43 pub const BACKUP_TIME_BIT: u32 = 1 << 4;
44 pub const CREATION_TIME_BIT: u32 = 1 << 5;
45 pub const MODIFICATION_TIME_BIT: u32 = 1 << 6;
46
47 pub const fn has_uid(self) -> bool {
48 self.bits & Self::UID_BIT != 0
49 }
50
51 pub const fn has_gid(self) -> bool {
52 self.bits & Self::GID_BIT != 0
53 }
54
55 pub const fn has_flags(self) -> bool {
56 self.bits & Self::FLAGS_BIT != 0
57 }
58
59 pub const fn has_mode(self) -> bool {
60 self.bits & Self::MODE_BIT != 0
61 }
62}
63
64#[derive(Debug)]
65pub struct PathList {
66 handle: NonNull<c_void>,
67}
68
69impl PathList {
70 pub const END_NODE: u64 = u64::MAX;
71
72 pub fn from_directory_contents(
73 dir: &str,
74 path: Option<&str>,
75 flags: ArchiveFlags,
76 n_threads: i32,
77 ) -> Result<Self> {
78 let dir = util::cstring("dir", dir)?;
79 let path_cstring = path.map(|value| util::cstring("path", value)).transpose()?;
80 let handle = unsafe {
81 ffi::aa_entry_stream::compression_rs_aa_path_list_create_with_directory_contents(
82 dir.as_ptr(),
83 path_cstring.as_ref().map_or(null(), |value| value.as_ptr()),
84 flags.bits(),
85 n_threads,
86 )
87 };
88 Ok(Self {
89 handle: util::nonnull_handle(handle, "AAPathListCreateWithDirectoryContents")?,
90 })
91 }
92
93 pub fn from_path(dir: &str, path: &str) -> Result<Self> {
94 let dir = util::cstring("dir", dir)?;
95 let path = util::cstring("path", path)?;
96 let handle = unsafe {
97 ffi::aa_entry_stream::compression_rs_aa_path_list_create_with_path(
98 dir.as_ptr(),
99 path.as_ptr(),
100 )
101 };
102 Ok(Self {
103 handle: util::nonnull_handle(handle, "AAPathListCreateWithPath")?,
104 })
105 }
106
107 pub(crate) fn as_ptr(&self) -> *mut c_void {
108 self.handle.as_ptr()
109 }
110
111 pub fn first_node(&self) -> Option<u64> {
112 let node =
113 unsafe { ffi::aa_entry_stream::compression_rs_aa_path_list_node_first(self.as_ptr()) };
114 (node != Self::END_NODE).then_some(node)
115 }
116
117 pub fn next_node(&self, node: u64) -> Option<u64> {
118 let next = unsafe {
119 ffi::aa_entry_stream::compression_rs_aa_path_list_node_next(self.as_ptr(), node)
120 };
121 (next != Self::END_NODE).then_some(next)
122 }
123
124 pub fn node_path(&self, node: u64) -> Result<String> {
125 let mut length = 0_usize;
126 let status = unsafe {
127 ffi::aa_entry_stream::compression_rs_aa_path_list_node_get_path(
128 self.as_ptr(),
129 node,
130 0,
131 std::ptr::null_mut(),
132 &mut length,
133 )
134 };
135 util::status_result("AAPathListNodeGetPath", status)?;
136
137 let mut buffer = vec![0_i8; length.saturating_add(1)];
138 let status = unsafe {
139 ffi::aa_entry_stream::compression_rs_aa_path_list_node_get_path(
140 self.as_ptr(),
141 node,
142 buffer.len(),
143 buffer.as_mut_ptr(),
144 &mut length,
145 )
146 };
147 util::status_result("AAPathListNodeGetPath", status)?;
148
149 let value = unsafe { CStr::from_ptr(buffer.as_ptr()) }
150 .to_str()
151 .map_err(|_| CompressionError::Utf8Error {
152 operation: "AAPathListNodeGetPath",
153 })?;
154 Ok(value.to_string())
155 }
156
157 pub fn paths(&self) -> Result<Vec<String>> {
158 let mut paths = Vec::new();
159 let mut node = self.first_node();
160 while let Some(current) = node {
161 paths.push(self.node_path(current)?);
162 node = self.next_node(current);
163 }
164 Ok(paths)
165 }
166}
167
168impl Drop for PathList {
169 fn drop(&mut self) {
170 unsafe { ffi::aa_entry_stream::compression_rs_aa_path_list_release(self.as_ptr()) };
171 }
172}