]> git.proxmox.com Git - pxar.git/blobdiff - src/format.rs
hardlinks also contain the offset
[pxar.git] / src / format.rs
index 62fb51a8ddecd9b4cf9bc3986712ecce113d3c5a..eec3676f0d53b6f2687a6e757a7f09ee917be661 100644 (file)
@@ -6,7 +6,7 @@
 //! item data.
 
 use std::cmp::Ordering;
-use std::ffi::OsStr;
+use std::ffi::{CStr, OsStr};
 use std::io;
 use std::mem::size_of;
 use std::os::unix::ffi::OsStrExt;
@@ -164,10 +164,30 @@ impl Entry {
     pub fn mtime_as_duration(&self) -> std::time::Duration {
         std::time::Duration::from_nanos(self.mtime)
     }
+
+    /// Get the file type portion of the mode bitfield.
+    pub fn get_file_bits(&self) -> u64 {
+        self.mode & mode::IFMT
+    }
+
+    /// Get the permission portion of the mode bitfield.
+    pub fn get_permission_bits(&self) -> u64 {
+        self.mode & !mode::IFMT
+    }
 }
 
 /// Convenience methods.
 impl Entry {
+    /// Get the file type (`mode & mode::IFMT`).
+    pub fn file_type(&self) -> u64 {
+        self.mode & mode::IFMT
+    }
+
+    /// Get the file mode bits (`mode & !mode::IFMT`).
+    pub fn file_mode(&self) -> u64 {
+        self.mode & !mode::IFMT
+    }
+
     /// Check whether this is a directory.
     pub fn is_dir(&self) -> bool {
         (self.mode & mode::IFMT) == mode::IFDIR
@@ -184,10 +204,32 @@ impl Entry {
         fmt == mode::IFCHR || fmt == mode::IFBLK
     }
 
+    /// Check whether this is a block device node.
+    pub fn is_blockdev(&self) -> bool {
+        let fmt = self.mode & mode::IFMT;
+        fmt == mode::IFBLK
+    }
+
+    /// Check whether this is a character device node.
+    pub fn is_chardev(&self) -> bool {
+        let fmt = self.mode & mode::IFMT;
+        fmt == mode::IFCHR
+    }
+
     /// Check whether this is a regular file.
     pub fn is_regular_file(&self) -> bool {
         (self.mode & mode::IFMT) == mode::IFREG
     }
+
+    /// Check whether this is a named pipe (FIFO).
+    pub fn is_fifo(&self) -> bool {
+        (self.mode & mode::IFMT) == mode::IFIFO
+    }
+
+    /// Check whether this is a named socket.
+    pub fn is_socket(&self) -> bool {
+        (self.mode & mode::IFMT) == mode::IFSOCK
+    }
 }
 
 impl From<&std::fs::Metadata> for Entry {
@@ -248,6 +290,7 @@ impl AsRef<OsStr> for Symlink {
 
 #[derive(Clone, Debug)]
 pub struct Hardlink {
+    pub offset: u64,
     pub data: Vec<u8>,
 }
 
@@ -290,8 +333,8 @@ impl XAttr {
         }
     }
 
-    pub fn name(&self) -> &[u8] {
-        &self.data[..self.name_len]
+    pub fn name(&self) -> &CStr {
+        unsafe { CStr::from_bytes_with_nul_unchecked(&self.data[..self.name_len + 1]) }
     }
 
     pub fn value(&self) -> &[u8] {
@@ -324,13 +367,46 @@ pub struct Device {
     pub minor: u64,
 }
 
+#[cfg(target_os = "linux")]
+impl Device {
+    /// Get a `dev_t` value for this device.
+    #[rustfmt::skip]
+    pub fn to_dev_t(&self) -> u64 {
+        // see bits/sysmacros.h
+        ((self.major & 0x0000_0fff) << 8) |
+        ((self.major & 0xffff_f000) << 32) |
+         (self.minor & 0x0000_00ff) |
+        ((self.minor & 0xffff_ff00) << 12)
+    }
+
+    /// Get a `Device` from a `dev_t` value.
+    #[rustfmt::skip]
+    pub fn from_dev_t(dev: u64) -> Self {
+        // see to_dev_t
+        Self {
+            major: (dev >>  8) & 0x0000_0fff |
+                   (dev >> 32) & 0xffff_f000,
+            minor:  dev        & 0x0000_00ff |
+                   (dev >> 12) & 0xffff_ff00,
+        }
+    }
+}
+
+#[cfg(all(test, target_os = "linux"))]
+#[test]
+fn test_linux_devices() {
+    let c_dev = unsafe { ::libc::makedev(0xabcd_1234, 0xdcba_5678) };
+    let dev = Device::from_dev_t(c_dev);
+    assert_eq!(dev.to_dev_t(), c_dev);
+}
+
 #[derive(Clone, Debug)]
 #[repr(C)]
 pub struct FCaps {
     pub data: Vec<u8>,
 }
 
-#[derive(Clone, Debug, Endian)]
+#[derive(Clone, Copy, Debug, Endian)]
 #[repr(C)]
 pub struct QuotaProjectId {
     pub projid: u64,