catar: encode/decode devices
This commit is contained in:
parent
1bdb3130f7
commit
a7e3713122
|
@ -120,7 +120,7 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
bail!("filename entry not nul terminated.");
|
bail!("filename entry not nul terminated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if buffer.iter().find(|b| (**b == b'/') || (**b == b'\\')).is_some() {
|
if buffer.iter().find(|b| (**b == b'/')).is_some() {
|
||||||
bail!("found invalid filename with slashes.");
|
bail!("found invalid filename with slashes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,9 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
|
|
||||||
let mode = Mode::from_bits_truncate((entry.mode as u32) & 0o7777);
|
let mode = Mode::from_bits_truncate((entry.mode as u32) & 0o7777);
|
||||||
|
|
||||||
nix::sys::stat::fchmodat(Some(dirfd), filename, mode, nix::sys::stat::FchmodatFlags::NoFollowSymlink)?;
|
// NOTE: we want :FchmodatFlags::NoFollowSymlink, but fchmodat does not support that
|
||||||
|
// on linux (see man fchmodat). Fortunately, we can simply avoid calling this on symlinks.
|
||||||
|
nix::sys::stat::fchmodat(Some(dirfd), filename, mode, nix::sys::stat::FchmodatFlags::FollowSymlink)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -229,6 +231,17 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn restore_device_at(&mut self, entry: &CaFormatEntry, dirfd: RawFd, filename: &OsStr, device: &CaFormatDevice) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let rdev = nix::sys::stat::makedev(device.major, device.minor);
|
||||||
|
let res = filename.with_nix_path(|cstr| unsafe {
|
||||||
|
libc::mknodat(dirfd, cstr.as_ptr(), 0o0600, rdev)
|
||||||
|
})?;
|
||||||
|
Errno::result(res)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn restore_sequential<F: Fn(&Path) -> Result<(), Error>>(
|
pub fn restore_sequential<F: Fn(&Path) -> Result<(), Error>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &mut PathBuf, // user for error reporting
|
path: &mut PathBuf, // user for error reporting
|
||||||
|
@ -306,6 +319,26 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ifmt == libc::S_IFBLK) || (ifmt == libc::S_IFCHR) {
|
||||||
|
|
||||||
|
let head: CaFormatHeader = self.read_item()?;
|
||||||
|
match head.htype {
|
||||||
|
CA_FORMAT_DEVICE => {
|
||||||
|
let device: CaFormatDevice = self.read_item()?;
|
||||||
|
self.restore_device_at(&entry, parent_fd, filename, &device)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
bail!("got unknown header type inside device entry {:016x}", head.htype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.restore_mode_at(&entry, parent_fd, filename)?;
|
||||||
|
self.restore_ugid_at(&entry, parent_fd, filename)?;
|
||||||
|
self.restore_mtime_at(&entry, parent_fd, filename)?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if ifmt == libc::S_IFREG {
|
if ifmt == libc::S_IFREG {
|
||||||
|
|
||||||
let mut read_buffer: [u8; 64*1024] = unsafe { std::mem::uninitialized() };
|
let mut read_buffer: [u8; 64*1024] = unsafe { std::mem::uninitialized() };
|
||||||
|
@ -490,14 +523,18 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
|
|
||||||
let mode = item.entry.mode as u32;
|
let mode = item.entry.mode as u32;
|
||||||
|
|
||||||
|
let ifmt = mode & libc::S_IFMT;
|
||||||
|
|
||||||
let osstr: &OsStr = prefix.as_ref();
|
let osstr: &OsStr = prefix.as_ref();
|
||||||
output.write(osstr.as_bytes())?;
|
output.write(osstr.as_bytes())?;
|
||||||
output.write(b"\n")?;
|
output.write(b"\n")?;
|
||||||
|
|
||||||
if (mode & libc::S_IFMT) == libc::S_IFDIR {
|
if ifmt == libc::S_IFDIR {
|
||||||
self.print_filenames(output, prefix, item)?;
|
self.print_filenames(output, prefix, item)?;
|
||||||
} else if (mode & libc::S_IFMT) == libc::S_IFREG {
|
} else if ifmt == libc::S_IFREG {
|
||||||
} else if (mode & libc::S_IFMT) == libc::S_IFLNK {
|
} else if ifmt == libc::S_IFLNK {
|
||||||
|
} else if ifmt == libc::S_IFBLK {
|
||||||
|
} else if ifmt == libc::S_IFCHR {
|
||||||
} else {
|
} else {
|
||||||
bail!("unknown item mode/type for {:?}", prefix);
|
bail!("unknown item mode/type for {:?}", prefix);
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,7 +280,9 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
|
||||||
|
|
||||||
self.write_filename(&filename)?;
|
self.write_filename(&filename)?;
|
||||||
|
|
||||||
if (stat.st_mode & libc::S_IFMT) == libc::S_IFDIR {
|
let ifmt = stat.st_mode & libc::S_IFMT;
|
||||||
|
|
||||||
|
if ifmt == libc::S_IFDIR {
|
||||||
|
|
||||||
match nix::dir::Dir::openat(rawfd, filename.as_ref(), OFlag::O_NOFOLLOW, Mode::empty()) {
|
match nix::dir::Dir::openat(rawfd, filename.as_ref(), OFlag::O_NOFOLLOW, Mode::empty()) {
|
||||||
Ok(mut dir) => self.encode_dir(&mut dir, &stat)?,
|
Ok(mut dir) => self.encode_dir(&mut dir, &stat)?,
|
||||||
|
@ -288,7 +290,7 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
|
||||||
Err(err) => bail!("open dir {:?} failed - {}", self.current_path, err),
|
Err(err) => bail!("open dir {:?} failed - {}", self.current_path, err),
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (stat.st_mode & libc::S_IFMT) == libc::S_IFREG {
|
} else if ifmt == libc::S_IFREG {
|
||||||
match nix::fcntl::openat(rawfd, filename.as_ref(), OFlag::O_NOFOLLOW, Mode::empty()) {
|
match nix::fcntl::openat(rawfd, filename.as_ref(), OFlag::O_NOFOLLOW, Mode::empty()) {
|
||||||
Ok(filefd) => {
|
Ok(filefd) => {
|
||||||
let res = self.encode_file(filefd, &stat);
|
let res = self.encode_file(filefd, &stat);
|
||||||
|
@ -298,7 +300,7 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
|
||||||
Err(nix::Error::Sys(Errno::ENOENT)) => self.report_vanished_file(&self.current_path)?,
|
Err(nix::Error::Sys(Errno::ENOENT)) => self.report_vanished_file(&self.current_path)?,
|
||||||
Err(err) => bail!("open file {:?} failed - {}", self.current_path, err),
|
Err(err) => bail!("open file {:?} failed - {}", self.current_path, err),
|
||||||
}
|
}
|
||||||
} else if (stat.st_mode & libc::S_IFMT) == libc::S_IFLNK {
|
} else if ifmt == libc::S_IFLNK {
|
||||||
let mut buffer = [0u8; libc::PATH_MAX as usize];
|
let mut buffer = [0u8; libc::PATH_MAX as usize];
|
||||||
|
|
||||||
let res = filename.with_nix_path(|cstr| {
|
let res = filename.with_nix_path(|cstr| {
|
||||||
|
@ -313,6 +315,8 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
|
||||||
Err(nix::Error::Sys(Errno::ENOENT)) => self.report_vanished_file(&self.current_path)?,
|
Err(nix::Error::Sys(Errno::ENOENT)) => self.report_vanished_file(&self.current_path)?,
|
||||||
Err(err) => bail!("readlink {:?} failed - {}", self.current_path, err),
|
Err(err) => bail!("readlink {:?} failed - {}", self.current_path, err),
|
||||||
}
|
}
|
||||||
|
} else if (ifmt == libc::S_IFBLK) || (ifmt == libc::S_IFCHR) {
|
||||||
|
self.encode_device(&stat)?;
|
||||||
} else {
|
} else {
|
||||||
bail!("unsupported file type (mode {:o} {:?})", stat.st_mode, self.current_path);
|
bail!("unsupported file type (mode {:o} {:?})", stat.st_mode, self.current_path);
|
||||||
}
|
}
|
||||||
|
@ -390,6 +394,23 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_device(&mut self, stat: &FileStat) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let mut entry = self.create_entry(&stat)?;
|
||||||
|
|
||||||
|
self.write_entry(entry)?;
|
||||||
|
|
||||||
|
let major = unsafe { libc::major(stat.st_rdev) } as u64;
|
||||||
|
let minor = unsafe { libc::minor(stat.st_rdev) } as u64;
|
||||||
|
|
||||||
|
println!("encode_device: {:?} {} {} {}", self.current_path, stat.st_rdev, major, minor);
|
||||||
|
|
||||||
|
self.write_header(CA_FORMAT_DEVICE, std::mem::size_of::<CaFormatDevice>() as u64)?;
|
||||||
|
self.write_item(CaFormatDevice { major, minor })?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn encode_symlink(&mut self, target: &[u8], stat: &FileStat) -> Result<(), Error> {
|
fn encode_symlink(&mut self, target: &[u8], stat: &FileStat) -> Result<(), Error> {
|
||||||
|
|
||||||
//println!("encode_symlink: {:?} -> {:?}", self.current_path, target);
|
//println!("encode_symlink: {:?} -> {:?}", self.current_path, target);
|
||||||
|
|
|
@ -13,6 +13,8 @@ use siphasher::sip::SipHasher24;
|
||||||
pub const CA_FORMAT_ENTRY: u64 = 0x1396fabcea5bbb51;
|
pub const CA_FORMAT_ENTRY: u64 = 0x1396fabcea5bbb51;
|
||||||
pub const CA_FORMAT_FILENAME: u64 = 0x6dbb6ebcb3161f0b;
|
pub const CA_FORMAT_FILENAME: u64 = 0x6dbb6ebcb3161f0b;
|
||||||
pub const CA_FORMAT_SYMLINK: u64 = 0x664a6fb6830e0d6c;
|
pub const CA_FORMAT_SYMLINK: u64 = 0x664a6fb6830e0d6c;
|
||||||
|
pub const CA_FORMAT_DEVICE: u64 = 0xac3dace369dfe643;
|
||||||
|
|
||||||
pub const CA_FORMAT_PAYLOAD: u64 = 0x8b9e1d93d6dcffc9;
|
pub const CA_FORMAT_PAYLOAD: u64 = 0x8b9e1d93d6dcffc9;
|
||||||
|
|
||||||
pub const CA_FORMAT_GOODBYE: u64 = 0xdfd35c5e8327c403;
|
pub const CA_FORMAT_GOODBYE: u64 = 0xdfd35c5e8327c403;
|
||||||
|
@ -95,6 +97,13 @@ pub struct CaFormatEntry {
|
||||||
pub mtime: u64,
|
pub mtime: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Endian)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CaFormatDevice {
|
||||||
|
pub major: u64,
|
||||||
|
pub minor: u64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Endian)]
|
#[derive(Endian)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct CaFormatGoodbyeItem {
|
pub struct CaFormatGoodbyeItem {
|
||||||
|
|
Loading…
Reference in New Issue