src/pxar/encoder.rs: impl support to store ACLs in pxar achives
Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
This commit is contained in:
parent
7cfaade7c8
commit
6a19448004
|
@ -8,6 +8,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use super::format_definition::*;
|
use super::format_definition::*;
|
||||||
use super::binary_search_tree::*;
|
use super::binary_search_tree::*;
|
||||||
|
use crate::tools::acl;
|
||||||
use crate::tools::xattr;
|
use crate::tools::xattr;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
@ -270,6 +271,110 @@ impl <'a, W: Write> Encoder<'a, W> {
|
||||||
Ok((xattrs, fcaps))
|
Ok((xattrs, fcaps))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_acl(&self, fd: RawFd, stat: &FileStat, acl_type: acl::ACLType) -> Result<PxarACL, Error> {
|
||||||
|
let ret = PxarACL {
|
||||||
|
users: Vec::new(),
|
||||||
|
groups: Vec::new(),
|
||||||
|
group_obj: None,
|
||||||
|
default: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.has_features(CA_FORMAT_WITH_ACL) {
|
||||||
|
return Ok(ret);
|
||||||
|
}
|
||||||
|
if (stat.st_mode & libc::S_IFMT) == libc::S_IFLNK {
|
||||||
|
return Ok(ret);
|
||||||
|
}
|
||||||
|
if acl_type == acl::ACL_TYPE_DEFAULT && (stat.st_mode & libc::S_IFMT) != libc::S_IFDIR {
|
||||||
|
bail!("ACL_TYPE_DEFAULT only defined for directories.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// In order to be able to get ACLs with type ACL_TYPE_DEFAULT, we have
|
||||||
|
// to create a path for acl_get_file(). acl_get_fd() only allows to get
|
||||||
|
// ACL_TYPE_ACCESS attributes.
|
||||||
|
let proc_path = Path::new("/proc/self/fd/").join(fd.to_string());
|
||||||
|
let acl = acl::ACL::get_file(&proc_path, acl_type)
|
||||||
|
.map_err(|err| format_err!("error while reading ACL - {}", err))?;
|
||||||
|
|
||||||
|
self.process_acl(acl, acl_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_acl(&self, acl: acl::ACL, acl_type: acl::ACLType) -> Result<PxarACL, Error> {
|
||||||
|
let mut acl_user = Vec::new();
|
||||||
|
let mut acl_group = Vec::new();
|
||||||
|
let mut acl_group_obj = None;
|
||||||
|
let mut acl_default = None;
|
||||||
|
let mut user_obj_permissions = None;
|
||||||
|
let mut group_obj_permissions = None;
|
||||||
|
let mut other_permissions = None;
|
||||||
|
let mut mask_permissions = None;
|
||||||
|
|
||||||
|
for entry in &mut acl.entries() {
|
||||||
|
let tag = entry.get_tag_type()?;
|
||||||
|
let permissions = entry.get_permissions()?;
|
||||||
|
match tag {
|
||||||
|
acl::ACL_USER_OBJ => user_obj_permissions = Some(permissions),
|
||||||
|
acl::ACL_GROUP_OBJ => group_obj_permissions = Some(permissions),
|
||||||
|
acl::ACL_OTHER => other_permissions = Some(permissions),
|
||||||
|
acl::ACL_MASK => mask_permissions = Some(permissions),
|
||||||
|
acl::ACL_USER => {
|
||||||
|
acl_user.push(CaFormatACLUser {
|
||||||
|
uid: entry.get_qualifier()?,
|
||||||
|
permissions: permissions,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
acl::ACL_GROUP => {
|
||||||
|
acl_group.push(CaFormatACLGroup {
|
||||||
|
gid: entry.get_qualifier()?,
|
||||||
|
permissions: permissions,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_ => bail!("Unexpected ACL tag encountered!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acl_user.sort();
|
||||||
|
acl_group.sort();
|
||||||
|
|
||||||
|
match acl_type {
|
||||||
|
acl::ACL_TYPE_ACCESS => {
|
||||||
|
// The mask permissions are mapped to the stat group permissions
|
||||||
|
// in case that the ACL group permissions were set.
|
||||||
|
// Only in that case we need to store the group permissions,
|
||||||
|
// in the other cases they are identical to the stat group permissions.
|
||||||
|
if let (Some(gop), Some(_)) = (group_obj_permissions, mask_permissions) {
|
||||||
|
acl_group_obj = Some(CaFormatACLGroupObj {
|
||||||
|
permissions: gop,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
acl::ACL_TYPE_DEFAULT => {
|
||||||
|
if user_obj_permissions != None ||
|
||||||
|
group_obj_permissions != None ||
|
||||||
|
other_permissions != None ||
|
||||||
|
mask_permissions != None
|
||||||
|
{
|
||||||
|
acl_default = Some(CaFormatACLDefault {
|
||||||
|
// The value is set to UINT64_MAX as placeholder if one
|
||||||
|
// of the permissions is not set
|
||||||
|
user_obj_permissions: user_obj_permissions.unwrap_or(std::u64::MAX),
|
||||||
|
group_obj_permissions: group_obj_permissions.unwrap_or(std::u64::MAX),
|
||||||
|
other_permissions: other_permissions.unwrap_or(std::u64::MAX),
|
||||||
|
mask_permissions: mask_permissions.unwrap_or(std::u64::MAX),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => bail!("Unexpected ACL type encountered"),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(PxarACL {
|
||||||
|
users: acl_user,
|
||||||
|
groups: acl_group,
|
||||||
|
group_obj: acl_group_obj,
|
||||||
|
default: acl_default,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn write_entry(&mut self, entry: CaFormatEntry) -> Result<(), Error> {
|
fn write_entry(&mut self, entry: CaFormatEntry) -> Result<(), Error> {
|
||||||
|
|
||||||
self.write_header(CA_FORMAT_ENTRY, std::mem::size_of::<CaFormatEntry>() as u64)?;
|
self.write_header(CA_FORMAT_ENTRY, std::mem::size_of::<CaFormatEntry>() as u64)?;
|
||||||
|
@ -298,6 +403,48 @@ impl <'a, W: Write> Encoder<'a, W> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_acl_user(&mut self, acl_user: CaFormatACLUser) -> Result<(), Error> {
|
||||||
|
self.write_header(CA_FORMAT_ACL_USER, std::mem::size_of::<CaFormatACLUser>() as u64)?;
|
||||||
|
self.write_item(acl_user)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_acl_group(&mut self, acl_group: CaFormatACLGroup) -> Result<(), Error> {
|
||||||
|
self.write_header(CA_FORMAT_ACL_GROUP, std::mem::size_of::<CaFormatACLGroup>() as u64)?;
|
||||||
|
self.write_item(acl_group)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_acl_group_obj(&mut self, acl_group_obj: CaFormatACLGroupObj) -> Result<(), Error> {
|
||||||
|
self.write_header(CA_FORMAT_ACL_GROUP_OBJ, std::mem::size_of::<CaFormatACLGroupObj>() as u64)?;
|
||||||
|
self.write_item(acl_group_obj)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_acl_default(&mut self, acl_default: CaFormatACLDefault) -> Result<(), Error> {
|
||||||
|
self.write_header(CA_FORMAT_ACL_DEFAULT, std::mem::size_of::<CaFormatACLDefault>() as u64)?;
|
||||||
|
self.write_item(acl_default)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_acl_default_user(&mut self, acl_default_user: CaFormatACLUser) -> Result<(), Error> {
|
||||||
|
self.write_header(CA_FORMAT_ACL_DEFAULT_USER, std::mem::size_of::<CaFormatACLUser>() as u64)?;
|
||||||
|
self.write_item(acl_default_user)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_acl_default_group(&mut self, acl_default_group: CaFormatACLGroup) -> Result<(), Error> {
|
||||||
|
self.write_header(CA_FORMAT_ACL_DEFAULT_GROUP, std::mem::size_of::<CaFormatACLGroup>() as u64)?;
|
||||||
|
self.write_item(acl_default_group)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn write_goodbye_table(&mut self, goodbye_offset: usize, goodbye_items: &mut [CaFormatGoodbyeItem]) -> Result<(), Error> {
|
fn write_goodbye_table(&mut self, goodbye_offset: usize, goodbye_items: &mut [CaFormatGoodbyeItem]) -> Result<(), Error> {
|
||||||
|
|
||||||
goodbye_items.sort_unstable_by(|a, b| a.hash.cmp(&b.hash));
|
goodbye_items.sort_unstable_by(|a, b| a.hash.cmp(&b.hash));
|
||||||
|
@ -352,6 +499,8 @@ impl <'a, W: Write> Encoder<'a, W> {
|
||||||
self.read_chattr(rawfd, &mut dir_entry)?;
|
self.read_chattr(rawfd, &mut dir_entry)?;
|
||||||
self.read_fat_attr(rawfd, magic, &mut dir_entry)?;
|
self.read_fat_attr(rawfd, magic, &mut dir_entry)?;
|
||||||
let (xattrs, fcaps) = self.read_xattrs(rawfd, &dir_stat)?;
|
let (xattrs, fcaps) = self.read_xattrs(rawfd, &dir_stat)?;
|
||||||
|
let acl_access = self.read_acl(rawfd, &dir_stat, acl::ACL_TYPE_ACCESS)?;
|
||||||
|
let acl_default = self.read_acl(rawfd, &dir_stat, acl::ACL_TYPE_DEFAULT)?;
|
||||||
|
|
||||||
self.write_entry(dir_entry)?;
|
self.write_entry(dir_entry)?;
|
||||||
for xattr in xattrs {
|
for xattr in xattrs {
|
||||||
|
@ -359,6 +508,26 @@ impl <'a, W: Write> Encoder<'a, W> {
|
||||||
}
|
}
|
||||||
self.write_fcaps(fcaps)?;
|
self.write_fcaps(fcaps)?;
|
||||||
|
|
||||||
|
for user in acl_access.users {
|
||||||
|
self.write_acl_user(user)?;
|
||||||
|
}
|
||||||
|
for group in acl_access.groups {
|
||||||
|
self.write_acl_group(group)?;
|
||||||
|
}
|
||||||
|
if let Some(group_obj) = acl_access.group_obj {
|
||||||
|
self.write_acl_group_obj(group_obj)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for default_user in acl_default.users {
|
||||||
|
self.write_acl_default_user(default_user)?;
|
||||||
|
}
|
||||||
|
for default_group in acl_default.groups {
|
||||||
|
self.write_acl_default_group(default_group)?;
|
||||||
|
}
|
||||||
|
if let Some(default) = acl_default.default {
|
||||||
|
self.write_acl_default(default)?;
|
||||||
|
}
|
||||||
|
|
||||||
let mut dir_count = 0;
|
let mut dir_count = 0;
|
||||||
|
|
||||||
let include_children;
|
let include_children;
|
||||||
|
@ -544,12 +713,22 @@ impl <'a, W: Write> Encoder<'a, W> {
|
||||||
self.read_chattr(filefd, &mut entry)?;
|
self.read_chattr(filefd, &mut entry)?;
|
||||||
self.read_fat_attr(filefd, magic, &mut entry)?;
|
self.read_fat_attr(filefd, magic, &mut entry)?;
|
||||||
let (xattrs, fcaps) = self.read_xattrs(filefd, &stat)?;
|
let (xattrs, fcaps) = self.read_xattrs(filefd, &stat)?;
|
||||||
|
let acl_access = self.read_acl(filefd, &stat, acl::ACL_TYPE_ACCESS)?;
|
||||||
|
|
||||||
self.write_entry(entry)?;
|
self.write_entry(entry)?;
|
||||||
for xattr in xattrs {
|
for xattr in xattrs {
|
||||||
self.write_xattr(xattr)?;
|
self.write_xattr(xattr)?;
|
||||||
}
|
}
|
||||||
self.write_fcaps(fcaps)?;
|
self.write_fcaps(fcaps)?;
|
||||||
|
for user in acl_access.users {
|
||||||
|
self.write_acl_user(user)?;
|
||||||
|
}
|
||||||
|
for group in acl_access.groups {
|
||||||
|
self.write_acl_group(group)?;
|
||||||
|
}
|
||||||
|
if let Some(group_obj) = acl_access.group_obj {
|
||||||
|
self.write_acl_group_obj(group_obj)?;
|
||||||
|
}
|
||||||
|
|
||||||
let include_payload;
|
let include_payload;
|
||||||
if is_virtual_file_system(magic) {
|
if is_virtual_file_system(magic) {
|
||||||
|
|
Loading…
Reference in New Issue