xattr_darwin.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. //! Extended attribute support for darwin
  2. extern crate libc;
  3. use std::ffi::CString;
  4. use std::ptr;
  5. use std::mem;
  6. use std::old_io as io;
  7. use self::libc::{c_int, size_t, ssize_t, c_char, c_void, uint32_t};
  8. /// Don't follow symbolic links
  9. const XATTR_NOFOLLOW: c_int = 0x0001;
  10. /// Expose HFS Compression extended attributes
  11. const XATTR_SHOWCOMPRESSION: c_int = 0x0020;
  12. extern "C" {
  13. fn listxattr(path: *const c_char, namebuf: *mut c_char,
  14. size: size_t, options: c_int) -> ssize_t;
  15. fn getxattr(path: *const c_char, name: *const c_char,
  16. value: *mut c_void, size: size_t, position: uint32_t,
  17. options: c_int) -> ssize_t;
  18. }
  19. /// Attributes which can be passed to `Attribute::list_with_flags`
  20. #[derive(Copy)]
  21. pub enum ListFlags {
  22. /// Don't follow symbolic links
  23. NoFollow = XATTR_NOFOLLOW as isize,
  24. /// Expose HFS Compression extended attributes
  25. ShowCompression = XATTR_SHOWCOMPRESSION as isize
  26. }
  27. /// Extended attribute
  28. #[derive(Debug, Clone)]
  29. pub struct Attribute {
  30. name: String,
  31. size: usize,
  32. }
  33. impl Attribute {
  34. /// Lists the extended attribute of `path`.
  35. /// Does follow symlinks by default.
  36. pub fn list(path: &Path, flags: &[ListFlags]) -> io::IoResult<Vec<Attribute>> {
  37. let mut c_flags: c_int = 0;
  38. for &flag in flags.iter() {
  39. c_flags |= flag as c_int
  40. }
  41. let c_path = try!(CString::new(path.as_vec()));
  42. let bufsize = unsafe {
  43. listxattr(c_path.as_ptr(), ptr::null_mut(), 0, c_flags)
  44. };
  45. if bufsize > 0 {
  46. let mut buf = vec![0u8; bufsize as usize];
  47. let err = unsafe { listxattr(
  48. c_path.as_ptr(),
  49. buf.as_mut_ptr() as *mut c_char,
  50. bufsize as size_t, c_flags
  51. )};
  52. if err > 0 {
  53. // End indicies of the attribute names
  54. // the buffer contains 0-terminates c-strings
  55. let idx = buf.iter().enumerate().filter_map(|(i, v)|
  56. if *v == 0 { Some(i) } else { None }
  57. );
  58. let mut names = Vec::new();
  59. let mut start = 0;
  60. for end in idx {
  61. let c_end = end + 1; // end of the c-string (including 0)
  62. let size = unsafe {
  63. getxattr(
  64. c_path.as_ptr(),
  65. buf[start..c_end].as_ptr() as *const c_char,
  66. ptr::null_mut(), 0, 0, c_flags
  67. )
  68. };
  69. if size > 0 {
  70. names.push(Attribute {
  71. name: unsafe {
  72. // buf is guaranteed to contain valid utf8 strings
  73. // see man listxattr
  74. mem::transmute::<&[u8], &str>(&buf[start..end]).to_string()
  75. },
  76. size: size as usize
  77. });
  78. }
  79. start = c_end;
  80. }
  81. Ok(names)
  82. } else {
  83. Err(io::IoError {
  84. kind: io::OtherIoError,
  85. desc: "could not read extended attributes",
  86. detail: None
  87. })
  88. }
  89. } else {
  90. Err(io::IoError {
  91. kind: io::OtherIoError,
  92. desc: "could not read extended attributes",
  93. detail: None
  94. })
  95. }
  96. }
  97. /// Getter for name
  98. pub fn name(&self) -> &str {
  99. &self.name
  100. }
  101. /// Getter for size
  102. pub fn size(&self) -> usize {
  103. self.size
  104. }
  105. }
  106. /// Lists the extended attributes.
  107. /// Follows symlinks like `stat`
  108. pub fn list(path: &Path) -> io::IoResult<Vec<Attribute>> {
  109. Attribute::list(path, &[])
  110. }
  111. /// Lists the extended attributes.
  112. /// Does not follow symlinks like `lstat`
  113. pub fn llist(path: &Path) -> io::IoResult<Vec<Attribute>> {
  114. Attribute::list(path, &[ListFlags::NoFollow])
  115. }
  116. /// Returns true if the extended attribute feature is implemented on this platform.
  117. #[inline(always)]
  118. pub fn feature_implemented() -> bool { true }