]> git.proxmox.com Git - proxmox-backup.git/commitdiff
src/tools/xattrs.rs: impl libc wrapper functions to get/set xattrs and fcaps
authorChristian Ebner <c.ebner@proxmox.com>
Wed, 15 May 2019 13:27:34 +0000 (15:27 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 16 May 2019 09:14:21 +0000 (11:14 +0200)
Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
src/tools.rs
src/tools/xattr.rs [new file with mode: 0644]

index e8e03304d75dd367ffd532cadce9a8e5fda375fa..ee3c80138b84902e53af9c7147c25175896e64b0 100644 (file)
@@ -36,6 +36,7 @@ pub mod procfs;
 pub mod read;
 pub mod write;
 pub mod acl;
+pub mod xattr;
 
 mod process_locker;
 pub use process_locker::*;
diff --git a/src/tools/xattr.rs b/src/tools/xattr.rs
new file mode 100644 (file)
index 0000000..21af1b5
--- /dev/null
@@ -0,0 +1,93 @@
+//! Wrapper functions for the libc xattr calls
+
+extern crate libc;
+
+use std::os::unix::io::RawFd;
+use nix::errno::Errno;
+use crate::pxar::{CaFormatXAttr, CaFormatFCaps};
+
+pub fn flistxattr(fd: RawFd) -> Result<Vec<u8>, nix::errno::Errno> {
+    // Initial buffer size for the attribute list, if content does not fit
+    // it gets dynamically increased until big enough.
+    let mut size = 256;
+    let mut buffer = vec![0u8; size];
+    let mut bytes = unsafe {
+        libc::flistxattr(fd, buffer.as_mut_ptr() as *mut i8, buffer.len())
+    };
+    while bytes < 0 {
+        let err = Errno::last();
+        match err {
+            Errno::ERANGE => {
+                // Buffer was not big enough to fit the list, retry with double the size
+                if size * 2 < size { return Err(Errno::ENOMEM); }
+                size *= 2;
+            },
+            _ => return Err(err),
+        }
+        // Retry to read the list with new buffer
+        buffer.resize(size, 0);
+        bytes = unsafe {
+            libc::flistxattr(fd, buffer.as_mut_ptr() as *mut i8, buffer.len())
+        };
+    }
+    buffer.resize(bytes as usize, 0);
+
+    Ok(buffer)
+}
+
+pub fn fgetxattr(fd: RawFd, name: &[u8]) -> Result<Vec<u8>, nix::errno::Errno> {
+    let mut size = 256;
+    let mut buffer = vec![0u8; size];
+    let mut bytes = unsafe {
+        libc::fgetxattr(fd, name.as_ptr() as *const i8, buffer.as_mut_ptr() as *mut core::ffi::c_void, buffer.len())
+    };
+    while bytes < 0 {
+        let err = Errno::last();
+        match err {
+            Errno::ERANGE => {
+                // Buffer was not big enough to fit the value, retry with double the size
+                if size * 2 < size { return Err(Errno::ENOMEM); }
+                size *= 2;
+            },
+            _ => return Err(err),
+        }
+        buffer.resize(size, 0);
+        bytes = unsafe {
+            libc::fgetxattr(fd, name.as_ptr() as *const i8, buffer.as_mut_ptr() as *mut core::ffi::c_void, buffer.len())
+        };
+    }
+    buffer.resize(bytes as usize, 0);
+
+    Ok(buffer)
+}
+
+pub fn fsetxattr(fd: RawFd, xattr: CaFormatXAttr) -> Result<(), nix::errno::Errno> {
+    let mut name = xattr.name.clone();
+    name.push('\0' as u8);
+    let flags = 0 as libc::c_int;
+    let result = unsafe {
+        libc::fsetxattr(fd, name.as_ptr() as *const libc::c_char, xattr.value.as_ptr() as *const libc::c_void, xattr.value.len(), flags)
+    };
+    if result < 0 {
+        let err = Errno::last();
+        return Err(err);
+    }
+
+    Ok(())
+}
+
+pub fn fsetxattr_fcaps(fd: RawFd, fcaps: CaFormatFCaps) -> Result<(), nix::errno::Errno> {
+    // TODO casync checks and removes capabilities if they are set
+    let name = b"security.capability\0";
+    let flags = 0 as libc::c_int;
+    let result = unsafe {
+        libc::fsetxattr(fd, name.as_ptr() as *const libc::c_char, fcaps.data.as_ptr() as *const libc::c_void, fcaps.data.len(), flags)
+    };
+    if result < 0 {
+        let err = Errno::last();
+        return Err(err);
+    }
+
+    Ok(())
+}
+