From b303057a193445c7da6a72cf0eb37d157bfd5ccc Mon Sep 17 00:00:00 2001 From: Christian Ebner Date: Fri, 17 May 2019 14:23:34 +0200 Subject: [PATCH] src/pxar/encoder.rs: impl functionality to encode xattrs/fcaps in pxar Signed-off-by: Christian Ebner --- src/pxar/encoder.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/pxar/encoder.rs b/src/pxar/encoder.rs index ae87ff5a..f4551e47 100644 --- a/src/pxar/encoder.rs +++ b/src/pxar/encoder.rs @@ -8,6 +8,7 @@ use std::collections::HashMap; use super::format_definition::*; use super::binary_search_tree::*; +use crate::tools::xattr; use std::io::Write; use std::os::unix::io::AsRawFd; @@ -213,6 +214,50 @@ impl <'a, W: Write> Encoder<'a, W> { Ok(()) } + fn read_xattrs(&self, fd: RawFd, stat: &FileStat, entry: &CaFormatEntry) -> Result<(Vec, Option), Error> { + let mut xattrs = Vec::new(); + let mut fcaps = None; + + let flags = CA_FORMAT_WITH_XATTRS | CA_FORMAT_WITH_FCAPS; + if (entry.feature_flags & flags) == 0 { return Ok((xattrs, fcaps)); } + // Should never be called on symlinks, just in case check anyway + if (stat.st_mode & libc::S_IFMT) == libc::S_IFLNK { return Ok((xattrs, fcaps)); } + + let xattr_names = match xattr::flistxattr(fd) { + Ok(names) => names, + Err(Errno::EOPNOTSUPP) => return Ok((xattrs, fcaps)), + Err(Errno::EBADF) => return Ok((xattrs, fcaps)), + Err(err) => bail!("read_xattrs failed for {:?} - {}", self.full_path(), err), + }; + + for name in xattr_names.split(|c| *c == '\0' as u8) { + // Only extract the relevant extended attributes + if !xattr::name_store(&name) { continue; } + + let value = match xattr::fgetxattr(fd, name) { + Ok(value) => value, + // Vanished between flistattr and getxattr, this is ok, silently ignore + Err(Errno::ENODATA) => continue, + Err(err) => bail!("read_xattrs failed for {:?} - {}", self.full_path(), err), + }; + + if xattr::security_capability(&name) { + // fcaps are stored in own format within the archive + fcaps = Some(CaFormatFCaps { + data: value, + }); + } else { + xattrs.push(CaFormatXAttr { + name: name.to_vec(), + value: value, + }); + } + } + xattrs.sort(); + + Ok((xattrs, fcaps)) + } + fn write_entry(&mut self, entry: CaFormatEntry) -> Result<(), Error> { self.write_header(CA_FORMAT_ENTRY, std::mem::size_of::() as u64)?; @@ -221,6 +266,26 @@ impl <'a, W: Write> Encoder<'a, W> { Ok(()) } + fn write_xattr(&mut self, xattr: CaFormatXAttr) -> Result<(), Error> { + let size = xattr.name.len() + xattr.value.len() + 1; // +1 for '\0' separating name and value + self.write_header(CA_FORMAT_XATTR, size as u64)?; + self.write(xattr.name.as_slice())?; + self.write(&[0])?; + self.write(xattr.value.as_slice())?; + + Ok(()) + } + + fn write_fcaps(&mut self, fcaps: Option) -> Result<(), Error> { + if let Some(fcaps) = fcaps { + let size = fcaps.data.len(); + self.write_header(CA_FORMAT_FCAPS, size as u64)?; + self.write(fcaps.data.as_slice())?; + } + + Ok(()) + } + 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)); @@ -274,8 +339,11 @@ impl <'a, W: Write> Encoder<'a, W> { self.read_chattr(rawfd, &mut dir_entry)?; self.read_fat_attr(rawfd, magic, &mut dir_entry)?; + let (xattrs, fcaps) = self.read_xattrs(rawfd, &dir_stat, &dir_entry)?; self.write_entry(dir_entry)?; + for xattr in xattrs { self.write_xattr(xattr)?; } + self.write_fcaps(fcaps)?; let mut dir_count = 0; @@ -461,8 +529,11 @@ impl <'a, W: Write> Encoder<'a, W> { self.read_chattr(filefd, &mut entry)?; self.read_fat_attr(filefd, magic, &mut entry)?; + let (xattrs, fcaps) = self.read_xattrs(filefd, &stat, &entry)?; self.write_entry(entry)?; + for xattr in xattrs { self.write_xattr(xattr)?; } + self.write_fcaps(fcaps)?; let include_payload; if is_virtual_file_system(magic) {