catar/decoder.rs: restore mode, uid, gid and mtime
This commit is contained in:
parent
25f60394d2
commit
23f68e53b4
|
@ -154,6 +154,80 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn restore_attributes(&mut self, entry: &CaFormatEntry) -> Result<CaFormatHeader, Error> {
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let head: CaFormatHeader = self.read_item()?;
|
||||||
|
match head.htype {
|
||||||
|
_ => return Ok(head),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_mode(&mut self, entry: &CaFormatEntry, fd: RawFd) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let mode = Mode::from_bits_truncate((entry.mode as u32) & 0o7777);
|
||||||
|
|
||||||
|
nix::sys::stat::fchmod(fd, mode)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_mode_at(&mut self, entry: &CaFormatEntry, dirfd: RawFd, filename: &OsStr) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let mode = Mode::from_bits_truncate((entry.mode as u32) & 0o7777);
|
||||||
|
|
||||||
|
nix::sys::stat::fchmodat(Some(dirfd), filename, mode, nix::sys::stat::FchmodatFlags::NoFollowSymlink)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_ugid(&mut self, entry: &CaFormatEntry, fd: RawFd) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let uid = entry.uid as u32;
|
||||||
|
let gid = entry.gid as u32;
|
||||||
|
|
||||||
|
let res = unsafe { libc::fchown(fd, uid, gid) };
|
||||||
|
Errno::result(res)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_ugid_at(&mut self, entry: &CaFormatEntry, dirfd: RawFd, filename: &OsStr) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let uid = entry.uid as u32;
|
||||||
|
let gid = entry.gid as u32;
|
||||||
|
|
||||||
|
let res = filename.with_nix_path(|cstr| unsafe {
|
||||||
|
libc::fchownat(dirfd, cstr.as_ptr(), uid, gid, libc::AT_SYMLINK_NOFOLLOW)
|
||||||
|
})?;
|
||||||
|
Errno::result(res)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_mtime(&mut self, entry: &CaFormatEntry, fd: RawFd) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let times = nsec_to_update_timespec(entry.mtime);
|
||||||
|
|
||||||
|
let res = unsafe { libc::futimens(fd, ×[0]) };
|
||||||
|
Errno::result(res)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_mtime_at(&mut self, entry: &CaFormatEntry, dirfd: RawFd, filename: &OsStr) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let times = nsec_to_update_timespec(entry.mtime);
|
||||||
|
|
||||||
|
let res = filename.with_nix_path(|cstr| unsafe {
|
||||||
|
libc::utimensat(dirfd, cstr.as_ptr(), ×[0], libc::AT_SYMLINK_NOFOLLOW)
|
||||||
|
})?;
|
||||||
|
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
|
||||||
|
@ -179,34 +253,37 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
Err(err) => bail!("unable to open directory {:?} - {}", path, err),
|
Err(err) => bail!("unable to open directory {:?} - {}", path, err),
|
||||||
};
|
};
|
||||||
|
|
||||||
//fixme: restore permission, acls, xattr, ...
|
let mut head = self.restore_attributes(&entry)?;
|
||||||
|
|
||||||
loop {
|
while head.htype == CA_FORMAT_FILENAME {
|
||||||
let head: CaFormatHeader = self.read_item()?;
|
let name = self.read_filename(head.size)?;
|
||||||
match head.htype {
|
path.push(&name);
|
||||||
CA_FORMAT_FILENAME => {
|
println!("NAME: {:?}", path);
|
||||||
let name = self.read_filename(head.size)?;
|
self.restore_sequential(path, &name, &dir, callback)?;
|
||||||
path.push(&name);
|
path.pop();
|
||||||
println!("NAME: {:?}", path);
|
|
||||||
self.restore_sequential(path, &name, &dir, callback)?;
|
head = self.read_item()?;
|
||||||
path.pop();
|
|
||||||
}
|
|
||||||
CA_FORMAT_GOODBYE => {
|
|
||||||
println!("Skip Goodbye");
|
|
||||||
if head.size < HEADER_SIZE { bail!("detected short goodbye table"); }
|
|
||||||
self.reader.seek(SeekFrom::Current((head.size - HEADER_SIZE) as i64))?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
bail!("got unknown header type inside directory entry {:016x}", head.htype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if head.htype != CA_FORMAT_GOODBYE {
|
||||||
|
bail!("got unknown header type inside directory entry {:016x}", head.htype);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Skip Goodbye");
|
||||||
|
if head.size < HEADER_SIZE { bail!("detected short goodbye table"); }
|
||||||
|
self.reader.seek(SeekFrom::Current((head.size - HEADER_SIZE) as i64))?;
|
||||||
|
|
||||||
|
self.restore_mode(&entry, dir.as_raw_fd())?;
|
||||||
|
self.restore_mtime(&entry, dir.as_raw_fd())?;
|
||||||
|
self.restore_ugid(&entry, dir.as_raw_fd())?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ifmt == libc::S_IFLNK {
|
if ifmt == libc::S_IFLNK {
|
||||||
// fixme: create symlink
|
// fixme: create symlink
|
||||||
//fixme: restore permission, acls, xattr, ...
|
//fixme: restore permission, acls, xattr, ...
|
||||||
|
|
||||||
let head: CaFormatHeader = self.read_item()?;
|
let head: CaFormatHeader = self.read_item()?;
|
||||||
match head.htype {
|
match head.htype {
|
||||||
CA_FORMAT_SYMLINK => {
|
CA_FORMAT_SYMLINK => {
|
||||||
|
@ -223,6 +300,11 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
bail!("got unknown header type inside symlink entry {:016x}", head.htype);
|
bail!("got unknown header type inside symlink entry {:016x}", head.htype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// self.restore_mode_at(&entry, parent_fd, filename)?; //not supported on symlinks
|
||||||
|
self.restore_ugid_at(&entry, parent_fd, filename)?;
|
||||||
|
self.restore_mtime_at(&entry, parent_fd, filename)?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,34 +320,32 @@ impl <'a, R: Read + Seek> CaTarDecoder<'a, R> {
|
||||||
Err(err) => bail!("open file {:?} failed - {}", path, err),
|
Err(err) => bail!("open file {:?} failed - {}", path, err),
|
||||||
};
|
};
|
||||||
|
|
||||||
//fixme: restore permission, acls, xattr, ...
|
let mut head = self.restore_attributes(&entry)?;
|
||||||
|
|
||||||
let head: CaFormatHeader = self.read_item()?;
|
if head.htype != CA_FORMAT_PAYLOAD {
|
||||||
match head.htype {
|
bail!("got unknown header type for file entry {:016x}", head.htype);
|
||||||
CA_FORMAT_PAYLOAD => {
|
|
||||||
if head.size < HEADER_SIZE {
|
|
||||||
bail!("detected short payload");
|
|
||||||
}
|
|
||||||
let need = (head.size - HEADER_SIZE) as usize;
|
|
||||||
//self.reader.seek(SeekFrom::Current(need as i64))?;
|
|
||||||
|
|
||||||
// fixme:: create file
|
|
||||||
|
|
||||||
let mut done = 0;
|
|
||||||
while (done < need) {
|
|
||||||
let todo = need - done;
|
|
||||||
let n = if todo > read_buffer.len() { read_buffer.len() } else { todo };
|
|
||||||
let data = &mut read_buffer[..n];
|
|
||||||
self.reader.read_exact(data)?;
|
|
||||||
file.write_all(data)?;
|
|
||||||
done += n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
bail!("got unknown header type for file entry {:016x}", head.htype);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if head.size < HEADER_SIZE {
|
||||||
|
bail!("detected short payload");
|
||||||
|
}
|
||||||
|
let need = (head.size - HEADER_SIZE) as usize;
|
||||||
|
//self.reader.seek(SeekFrom::Current(need as i64))?;
|
||||||
|
|
||||||
|
let mut done = 0;
|
||||||
|
while (done < need) {
|
||||||
|
let todo = need - done;
|
||||||
|
let n = if todo > read_buffer.len() { read_buffer.len() } else { todo };
|
||||||
|
let data = &mut read_buffer[..n];
|
||||||
|
self.reader.read_exact(data)?;
|
||||||
|
file.write_all(data)?;
|
||||||
|
done += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.restore_mode(&entry, file.as_raw_fd())?;
|
||||||
|
self.restore_mtime(&entry, file.as_raw_fd())?;
|
||||||
|
self.restore_ugid(&entry, file.as_raw_fd())?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,3 +545,20 @@ fn symlinkat(target: &Path, parent: RawFd, linkname: &OsStr) -> Result<(), Error
|
||||||
})?
|
})?
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nsec_to_update_timespec(mtime_nsec: u64) -> [libc::timespec; 2] {
|
||||||
|
|
||||||
|
// restore mtime
|
||||||
|
const UTIME_OMIT: i64 = ((1 << 30) - 2);
|
||||||
|
const NANOS_PER_SEC: i64 = 1_000_000_000;
|
||||||
|
|
||||||
|
let sec = (mtime_nsec as i64) / NANOS_PER_SEC;
|
||||||
|
let nsec = (mtime_nsec as i64) % NANOS_PER_SEC;
|
||||||
|
|
||||||
|
let times: [libc::timespec; 2] = [
|
||||||
|
libc::timespec { tv_sec: 0, tv_nsec: UTIME_OMIT },
|
||||||
|
libc::timespec { tv_sec: sec, tv_nsec: nsec },
|
||||||
|
];
|
||||||
|
|
||||||
|
times
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue