]> git.proxmox.com Git - proxmox-backup.git/blame - src/pxar/format_definition.rs
Cargo.toml: pathpatterns, pxar, proxmox-fuse
[proxmox-backup.git] / src / pxar / format_definition.rs
CommitLineData
8968258b 1//! *pxar* binary format definition
4fa71e05
DM
2//!
3//! Please note the all values are stored in little endian ordering.
4//!
5//! The Archive contains a list of items. Each item starts with a
5e50c606 6//! `PxarHeader`, followed by the item data.
de2016d5 7use std::cmp::Ordering;
b62b6cad 8
4ea22b68 9use endian_trait::Endian;
f7d4e4b5 10use anyhow::{bail, Error};
0866748d
DM
11use siphasher::sip::SipHasher24;
12
834a2f95 13
5e50c606 14/// Header types identifying items stored in the archive
4ea22b68
CE
15pub const PXAR_ENTRY: u64 = 0x1396fabcea5bbb51;
16pub const PXAR_FILENAME: u64 = 0x6dbb6ebcb3161f0b;
17pub const PXAR_SYMLINK: u64 = 0x664a6fb6830e0d6c;
18pub const PXAR_DEVICE: u64 = 0xac3dace369dfe643;
19pub const PXAR_XATTR: u64 = 0xb8157091f80bc486;
20pub const PXAR_ACL_USER: u64 = 0x297dc88b2ef12faf;
21pub const PXAR_ACL_GROUP: u64 = 0x36f2acb56cb3dd0b;
22pub const PXAR_ACL_GROUP_OBJ: u64 = 0x23047110441f38f3;
23pub const PXAR_ACL_DEFAULT: u64 = 0xfe3eeda6823c8cd0;
24pub const PXAR_ACL_DEFAULT_USER: u64 = 0xbdf03df9bd010a91;
25pub const PXAR_ACL_DEFAULT_GROUP: u64 = 0xa0cb1168782d1f51;
26pub const PXAR_FCAPS: u64 = 0xf7267db0afed0629;
27pub const PXAR_QUOTA_PROJID: u64 = 0x161baf2d8772a72b;
5e50c606
CE
28
29/// Marks item as hardlink
30/// compute_goodbye_hash(b"__PROXMOX_FORMAT_HARDLINK__");
4ea22b68 31pub const PXAR_FORMAT_HARDLINK: u64 = 0x2c5e06f634f65b86;
add5861e 32/// Marks the beginning of the payload (actual content) of regular files
4ea22b68 33pub const PXAR_PAYLOAD: u64 = 0x8b9e1d93d6dcffc9;
5e50c606 34/// Marks item as entry of goodbye table
4ea22b68 35pub const PXAR_GOODBYE: u64 = 0xdfd35c5e8327c403;
5e50c606
CE
36/// The end marker used in the GOODBYE object
37pub const PXAR_GOODBYE_TAIL_MARKER: u64 = 0x57446fa533702943;
4f6892eb 38
4ea22b68 39#[derive(Debug, Endian)]
b62b6cad 40#[repr(C)]
5e50c606 41pub struct PxarHeader {
5e50c606 42 /// The item type (see `PXAR_` constants).
3192ae96 43 pub htype: u64,
f92e8266
CE
44 /// The size of the item, including the size of `PxarHeader`.
45 pub size: u64,
b62b6cad
DM
46}
47
8c1dfa6c 48#[derive(Endian)]
b62b6cad 49#[repr(C)]
5e50c606 50pub struct PxarEntry {
3192ae96
DM
51 pub mode: u64,
52 pub flags: u64,
ead7546a
CE
53 pub uid: u32,
54 pub gid: u32,
3192ae96 55 pub mtime: u64,
b62b6cad
DM
56}
57
a7e37131
DM
58#[derive(Endian)]
59#[repr(C)]
5e50c606 60pub struct PxarDevice {
a7e37131
DM
61 pub major: u64,
62 pub minor: u64,
63}
64
b6ebfb8d 65#[derive(Endian)]
b62b6cad 66#[repr(C)]
5e50c606 67pub struct PxarGoodbyeItem {
f92e8266
CE
68 /// SipHash24 of the directory item name. The last GOODBYE item
69 /// uses the special hash value `PXAR_GOODBYE_TAIL_MARKER`.
70 pub hash: u64,
4fa71e05
DM
71 /// The offset from the start of the GOODBYE object to the start
72 /// of the matching directory item (point to a FILENAME). The last
73 /// GOODBYE item points to the start of the matching ENTRY
4b864ad4 74 /// object.
3192ae96 75 pub offset: u64,
4fa71e05
DM
76 /// The overall size of the directory item. The last GOODBYE item
77 /// repeats the size of the GOODBYE item.
3192ae96 78 pub size: u64,
b62b6cad
DM
79}
80
0866748d
DM
81/// Helper function to extract file names from binary archive.
82pub fn read_os_string(buffer: &[u8]) -> std::ffi::OsString {
b62b6cad
DM
83 let len = buffer.len();
84
85 use std::os::unix::ffi::OsStrExt;
86
4ea22b68
CE
87 let name = if len > 0 && buffer[len - 1] == 0 {
88 std::ffi::OsStr::from_bytes(&buffer[0..len - 1])
b62b6cad
DM
89 } else {
90 std::ffi::OsStr::from_bytes(&buffer)
91 };
92
93 name.into()
94}
0866748d 95
de2016d5
CE
96#[derive(Debug, Eq)]
97#[repr(C)]
5e50c606 98pub struct PxarXAttr {
de2016d5
CE
99 pub name: Vec<u8>,
100 pub value: Vec<u8>,
101}
102
5e50c606
CE
103impl Ord for PxarXAttr {
104 fn cmp(&self, other: &PxarXAttr) -> Ordering {
de2016d5
CE
105 self.name.cmp(&other.name)
106 }
107}
108
5e50c606
CE
109impl PartialOrd for PxarXAttr {
110 fn partial_cmp(&self, other: &PxarXAttr) -> Option<Ordering> {
de2016d5
CE
111 Some(self.cmp(other))
112 }
113}
114
5e50c606
CE
115impl PartialEq for PxarXAttr {
116 fn eq(&self, other: &PxarXAttr) -> bool {
de2016d5
CE
117 self.name == other.name
118 }
119}
120
121#[derive(Debug)]
122#[repr(C)]
5e50c606 123pub struct PxarFCaps {
de2016d5
CE
124 pub data: Vec<u8>,
125}
126
7cfaade7
CE
127#[derive(Debug, Endian, Eq)]
128#[repr(C)]
5e50c606 129pub struct PxarACLUser {
7cfaade7
CE
130 pub uid: u64,
131 pub permissions: u64,
132 //pub name: Vec<u64>, not impl for now
133}
134
135// TODO if also name is impl, sort by uid, then by name and last by permissions
5e50c606
CE
136impl Ord for PxarACLUser {
137 fn cmp(&self, other: &PxarACLUser) -> Ordering {
7cfaade7
CE
138 match self.uid.cmp(&other.uid) {
139 // uids are equal, entries ordered by permissions
140 Ordering::Equal => self.permissions.cmp(&other.permissions),
141 // uids are different, entries ordered by uid
142 uid_order => uid_order,
143 }
144 }
145}
146
5e50c606
CE
147impl PartialOrd for PxarACLUser {
148 fn partial_cmp(&self, other: &PxarACLUser) -> Option<Ordering> {
7cfaade7
CE
149 Some(self.cmp(other))
150 }
151}
152
5e50c606
CE
153impl PartialEq for PxarACLUser {
154 fn eq(&self, other: &PxarACLUser) -> bool {
7cfaade7
CE
155 self.uid == other.uid && self.permissions == other.permissions
156 }
157}
158
159#[derive(Debug, Endian, Eq)]
160#[repr(C)]
5e50c606 161pub struct PxarACLGroup {
7cfaade7
CE
162 pub gid: u64,
163 pub permissions: u64,
164 //pub name: Vec<u64>, not impl for now
165}
166
167// TODO if also name is impl, sort by gid, then by name and last by permissions
5e50c606
CE
168impl Ord for PxarACLGroup {
169 fn cmp(&self, other: &PxarACLGroup) -> Ordering {
7cfaade7
CE
170 match self.gid.cmp(&other.gid) {
171 // gids are equal, entries are ordered by permissions
172 Ordering::Equal => self.permissions.cmp(&other.permissions),
173 // gids are different, entries ordered by gid
174 gid_ordering => gid_ordering,
175 }
176 }
177}
178
5e50c606
CE
179impl PartialOrd for PxarACLGroup {
180 fn partial_cmp(&self, other: &PxarACLGroup) -> Option<Ordering> {
7cfaade7
CE
181 Some(self.cmp(other))
182 }
183}
184
5e50c606
CE
185impl PartialEq for PxarACLGroup {
186 fn eq(&self, other: &PxarACLGroup) -> bool {
7cfaade7
CE
187 self.gid == other.gid && self.permissions == other.permissions
188 }
189}
190
191#[derive(Debug, Endian)]
192#[repr(C)]
5e50c606 193pub struct PxarACLGroupObj {
7cfaade7
CE
194 pub permissions: u64,
195}
196
197#[derive(Debug, Endian)]
198#[repr(C)]
5e50c606 199pub struct PxarACLDefault {
7cfaade7
CE
200 pub user_obj_permissions: u64,
201 pub group_obj_permissions: u64,
202 pub other_permissions: u64,
203 pub mask_permissions: u64,
204}
205
4ea22b68 206pub(crate) struct PxarACL {
5e50c606
CE
207 pub users: Vec<PxarACLUser>,
208 pub groups: Vec<PxarACLGroup>,
209 pub group_obj: Option<PxarACLGroupObj>,
210 pub default: Option<PxarACLDefault>,
7cfaade7
CE
211}
212
5e50c606
CE
213pub const PXAR_ACL_PERMISSION_READ: u64 = 4;
214pub const PXAR_ACL_PERMISSION_WRITE: u64 = 2;
215pub const PXAR_ACL_PERMISSION_EXECUTE: u64 = 1;
7cfaade7 216
7312ab9e
CE
217#[derive(Debug, Endian)]
218#[repr(C)]
5e50c606 219pub struct PxarQuotaProjID {
7312ab9e
CE
220 pub projid: u64,
221}
222
27e6e180 223#[derive(Debug, Default)]
e60cfbcd 224pub struct PxarAttributes {
5e50c606
CE
225 pub xattrs: Vec<PxarXAttr>,
226 pub fcaps: Option<PxarFCaps>,
227 pub quota_projid: Option<PxarQuotaProjID>,
228 pub acl_user: Vec<PxarACLUser>,
229 pub acl_group: Vec<PxarACLGroup>,
230 pub acl_group_obj: Option<PxarACLGroupObj>,
231 pub acl_default: Option<PxarACLDefault>,
232 pub acl_default_user: Vec<PxarACLUser>,
233 pub acl_default_group: Vec<PxarACLGroup>,
e60cfbcd
CE
234}
235
0866748d
DM
236/// Create SipHash values for goodby tables.
237//pub fn compute_goodbye_hash(name: &std::ffi::CStr) -> u64 {
238pub fn compute_goodbye_hash(name: &[u8]) -> u64 {
0866748d
DM
239 use std::hash::Hasher;
240 let mut hasher = SipHasher24::new_with_keys(0x8574442b0f1d84b3, 0x2736ed30d1c22ec1);
241 hasher.write(name);
242 hasher.finish()
243}
b6ebfb8d 244
5e50c606 245pub fn check_ca_header<T>(head: &PxarHeader, htype: u64) -> Result<(), Error> {
b6ebfb8d 246 if head.htype != htype {
4ea22b68
CE
247 bail!(
248 "got wrong header type ({:016x} != {:016x})",
249 head.htype,
250 htype
251 );
b6ebfb8d 252 }
5e50c606 253 if head.size != (std::mem::size_of::<T>() + std::mem::size_of::<PxarHeader>()) as u64 {
b6ebfb8d
DM
254 bail!("got wrong header size for type {:016x}", htype);
255 }
256
257 Ok(())
258}
6fc053ed
CE
259
260/// The format requires to build sorted directory lookup tables in
261/// memory, so we restrict the number of allowed entries to limit
262/// maximum memory usage.
263pub const ENCODER_MAX_ENTRIES: usize = 1024 * 1024;