diff --git a/src/builder.rs b/src/builder.rs index 9b799329..0e919546 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -535,11 +535,7 @@ fn append_special( prepare_header_path(dst, &mut header, path)?; header.set_entry_type(entry_type); - let dev_id = stat.rdev(); - let dev_major = ((dev_id >> 32) & 0xffff_f000) | ((dev_id >> 8) & 0x0000_0fff); - let dev_minor = ((dev_id >> 12) & 0xffff_ff00) | ((dev_id) & 0x0000_00ff); - header.set_device_major(dev_major as u32)?; - header.set_device_minor(dev_minor as u32)?; + header.set_rdev(stat.rdev())?; header.set_cksum(); dst.write_all(header.as_bytes())?; diff --git a/src/header.rs b/src/header.rs index 36fb52ae..0fce3211 100644 --- a/src/header.rs +++ b/src/header.rs @@ -645,6 +645,17 @@ impl Header { } } + /// Encodes the device number into the major and minor fields of this header. + /// + /// This function will return an error if this header format cannot encode a + /// a device number. + pub fn set_rdev(&mut self, rdev: libc::dev_t) -> io::Result<()> { + let dev_major = ((rdev >> 32) & 0xffff_f000) | ((rdev >> 8) & 0x0000_0fff); + self.set_device_major(dev_major as u32)?; + let dev_minor = ((rdev >> 12) & 0xffff_ff00) | ((rdev) & 0x0000_00ff); + self.set_device_minor(dev_minor as u32) + } + /// Returns the device minor number, if present. /// /// This field may not be present in all archives, and it may not be diff --git a/tests/header/mod.rs b/tests/header/mod.rs index 9008cb55..3bdaacb4 100644 --- a/tests/header/mod.rs +++ b/tests/header/mod.rs @@ -100,6 +100,18 @@ fn dev_major_minor() { assert_eq!(t!(h.device_major()), Some(1)); assert_eq!(t!(h.device_minor()), Some(2)); + // Verify this is idempotent + let onetwo_rdev = libc::makedev(1, 2); + t!(h.set_rdev(onetwo_rdev)); + assert_eq!(t!(h.device_major()), Some(1)); + assert_eq!(t!(h.device_minor()), Some(2)); + + // And verify that changing the device works + let nvme_rdev = libc::makedev(0x88, 0x6); + t!(h.set_rdev(nvme_rdev)); + assert_eq!(t!(h.device_major()), Some(0x88)); + assert_eq!(t!(h.device_minor()), Some(0x6)); + h = Header::new_ustar(); t!(h.set_device_major(1)); t!(h.set_device_minor(2));