nwin 11 лет назад
Родитель
Сommit
1ab1f3f320
3 измененных файлов с 128 добавлено и 9 удалено
  1. 7 4
      src/xattr/mod.rs
  2. 3 5
      src/xattr/xattr_darwin.rs
  3. 118 0
      src/xattr/xattr_linux.rs

+ 7 - 4
src/xattr/mod.rs

@@ -3,8 +3,11 @@
 mod xattr_darwin;
 #[cfg(target_os = "macos")]
 pub use self::xattr_darwin::*;
-#[cfg(not(target_os = "macos"))]
+#[cfg(target_os = "linux")]
+mod xattr_linux;
+#[cfg(target_os = "linux")]
+pub use self::xattr_linux::*;
+#[cfg(not(any(target_os = "macos", target_os = "linux")))]
 mod xattr_other;
-#[cfg(not(target_os = "macos"))]
-pub use self::xattr_other::*;
-
+#[cfg(not(any(target_os = "macos", target_os = "linux")))]
+pub use self::xattr_other::*;

+ 3 - 5
src/xattr/xattr_darwin.rs

@@ -45,11 +45,9 @@ impl Attribute {
             c_flags |= flag as c_int
         }
         let c_path = try!(CString::new(path.as_vec()));
-        let bufsize = unsafe { listxattr(
-            c_path.as_ptr(),
-            ptr::null_mut(),
-            0, c_flags
-        )} as isize;
+        let bufsize = unsafe { 
+            listxattr(c_path.as_ptr(), ptr::null_mut(), 0, c_flags)
+        };
         if bufsize > 0 {
             let mut buf = vec![0u8; bufsize as usize];
             let err = unsafe { listxattr(

+ 118 - 0
src/xattr/xattr_linux.rs

@@ -0,0 +1,118 @@
+//! Extended attribute support for darwin
+extern crate libc;
+
+use std::ffi::CString;
+use std::ptr;
+use std::old_io as io;
+use self::libc::{size_t, ssize_t, c_char, c_void};
+
+extern "C" {
+    fn listxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t;
+    fn llistxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t;
+    fn getxattr(path: *const c_char, name: *const c_char, 
+                value: *mut c_void, size: size_t
+    ) -> ssize_t;
+    fn lgetxattr(path: *const c_char, name: *const c_char, 
+                value: *mut c_void, size: size_t
+    ) -> ssize_t;
+}
+
+/// Attributes which can be passed to `Attribute::list_with_flags`
+#[derive(Copy)]
+pub enum FollowSymlinks {
+    Yes,
+    No
+}
+
+/// Extended attribute
+#[derive(Debug, Clone)]
+pub struct Attribute {
+    name: String,
+    size: usize,
+}
+
+impl Attribute {
+    /// Lists the extended attribute of `path`.
+    /// Does follow symlinks by default.
+    pub fn list(path: &Path, do_follow: FollowSymlinks) -> io::IoResult<Vec<Attribute>> {
+        let (listxattr, getxattr) = match do_follow {
+            FollowSymlinks::Yes => (listxattr, getxattr),
+            FollowSymlinks::No => (llistxattr, lgetxattr),
+        };
+        let c_path = try!(CString::new(path.as_vec()));
+        let bufsize = unsafe {
+            listxattr(c_path.as_ptr(), ptr::null_mut(), 0)
+        };
+        if bufsize > 0 {
+            let mut buf = vec![0u8; bufsize as usize];
+            let err = unsafe { listxattr(
+                c_path.as_ptr(),
+                buf.as_mut_ptr() as *mut c_char,
+                bufsize as size_t
+            )};
+            if err > 0 {
+                // End indicies of the attribute names
+                // the buffer contains 0-terminates c-strings
+                let idx = buf.iter().enumerate().filter_map(|(i, v)|
+                    if *v == 0 { Some(i) } else { None }
+                );
+                let mut names = Vec::new();
+                let mut start = 0;
+                for end in idx {
+                    let size = unsafe {
+                        getxattr(
+                            c_path.as_ptr(),
+                            buf[start..end+1].as_ptr() as *const c_char,
+                            ptr::null_mut(), 0
+                        )
+                    };
+                    if size > 0 {
+                        names.push(Attribute { 
+                            name: String::from_utf8_lossy(&buf[start..end]).into_owned(),
+                            size: size as usize
+                        });
+                    }
+                    start = end + 1;
+                }
+                Ok(names)
+            } else {
+                Err(io::IoError {
+                    kind: io::OtherIoError,
+                    desc: "could not read extended attributes",
+                    detail: None
+                })
+            }
+        } else {
+            Err(io::IoError {
+                kind: io::OtherIoError,
+                desc: "could not read extended attributes",
+                detail: None
+            })
+        }
+    }
+    
+    /// Getter for name
+    pub fn name(&self) -> &str {
+        &self.name
+    }
+
+    /// Getter for size
+    pub fn size(&self) -> usize {
+        self.size
+    }
+}
+
+/// Lists the extended attributes.
+/// Follows symlinks like `stat`
+pub fn list(path: &Path) -> io::IoResult<Vec<Attribute>> {
+    Attribute::list(path, FollowSymlinks::Yes)
+}
+/// Lists the extended attributes.
+/// Does not follow symlinks like `lstat`
+pub fn llist(path: &Path) -> io::IoResult<Vec<Attribute>> {
+    Attribute::list(path, FollowSymlinks::No)
+}
+
+/// Returns true if the extended attribute feature is implemented on this platform.
+#[inline(always)]
+pub fn feature_implemented() -> bool { true }