Skip to content

Commit

Permalink
builder: Add a set_rdev() convenience
Browse files Browse the repository at this point in the history
Commonly one may be building tar archives from the filesystem
in a custom way, or operating on a translation of a non-tar
format which uses rdev, not split major/minor.

Today one needs to replicate the nontrivial bit manipulations
to split the device; but since we have that code anyways in
our own "build from filesystem" code, let's just add it as a public
API.

Signed-off-by: Colin Walters <[email protected]>
  • Loading branch information
cgwalters committed Sep 13, 2024
1 parent 97d5033 commit c8b7972
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
6 changes: 1 addition & 5 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())?;
Expand Down
11 changes: 11 additions & 0 deletions src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions tests/header/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit c8b7972

Please sign in to comment.