catar/encoder.rs: pass magic fs number to encode_dir

This commit is contained in:
Dietmar Maurer 2019-01-12 08:51:04 +01:00
parent dce0ebd505
commit 1c4804cf67
1 changed files with 59 additions and 19 deletions

View File

@ -63,7 +63,9 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
bail!("got unexpected file type {:?} (not a directory)", me.current_path); bail!("got unexpected file type {:?} (not a directory)", me.current_path);
} }
me.encode_dir(dir, &stat)?; let magic = detect_fs_type(dir)?;
me.encode_dir(dir, &stat, magic)?;
Ok(()) Ok(())
} }
@ -220,7 +222,7 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
Ok(()) Ok(())
} }
fn encode_dir(&mut self, dir: &mut nix::dir::Dir, dir_stat: &FileStat) -> Result<(), Error> { fn encode_dir(&mut self, dir: &mut nix::dir::Dir, dir_stat: &FileStat, magic: i64) -> Result<(), Error> {
//println!("encode_dir: {:?} start {}", self.current_path, self.writer_pos); //println!("encode_dir: {:?} start {}", self.current_path, self.writer_pos);
@ -278,28 +280,43 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
let start_pos = self.writer_pos; let start_pos = self.writer_pos;
self.write_filename(&filename)?;
let ifmt = stat.st_mode & libc::S_IFMT; let ifmt = stat.st_mode & libc::S_IFMT;
if ifmt == libc::S_IFDIR { if ifmt == libc::S_IFDIR {
match nix::dir::Dir::openat(rawfd, filename.as_ref(), OFlag::O_DIRECTORY|OFlag::O_NOFOLLOW, Mode::empty()) { let mut dir = match nix::dir::Dir::openat(rawfd, filename.as_ref(), OFlag::O_DIRECTORY|OFlag::O_NOFOLLOW, Mode::empty()) {
Ok(mut dir) => self.encode_dir(&mut dir, &stat)?, Ok(dir) => dir,
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)?;
continue; // fixme!!
},
Err(err) => bail!("open dir {:?} failed - {}", self.current_path, err), Err(err) => bail!("open dir {:?} failed - {}", self.current_path, err),
} };
let child_magic = if dir_stat.st_dev != stat.st_dev {
detect_fs_type(&dir)?
} else {
magic
};
self.write_filename(&filename)?;
self.encode_dir(&mut dir, &stat, child_magic)?;
} else if ifmt == libc::S_IFREG { } else if ifmt == libc::S_IFREG {
match nix::fcntl::openat(rawfd, filename.as_ref(), OFlag::O_NOFOLLOW, Mode::empty()) { let filefd = match nix::fcntl::openat(rawfd, filename.as_ref(), OFlag::O_NOFOLLOW, Mode::empty()) {
Ok(filefd) => { Ok(filefd) => filefd,
let res = self.encode_file(filefd, &stat); Err(nix::Error::Sys(Errno::ENOENT)) => {
let _ = nix::unistd::close(filefd); // ignore close errors self.report_vanished_file(&self.current_path)?;
res?; continue;
} },
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),
} };
self.write_filename(&filename)?;
let res = self.encode_file(filefd, &stat);
let _ = nix::unistd::close(filefd); // ignore close errors
res?;
} else if 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];
@ -310,15 +327,21 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
match Errno::result(res) { match Errno::result(res) {
Ok(len) => { Ok(len) => {
buffer[len as usize] = 0u8; // add Nul byte buffer[len as usize] = 0u8; // add Nul byte
self.write_filename(&filename)?;
self.encode_symlink(&buffer[..((len+1) as usize)], &stat)? self.encode_symlink(&buffer[..((len+1) as usize)], &stat)?
} }
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)?;
continue;
}
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) { } else if (ifmt == libc::S_IFBLK) || (ifmt == libc::S_IFCHR) {
self.write_filename(&filename)?;
self.encode_device(&stat)?; self.encode_device(&stat)?;
} else if (ifmt == libc::S_IFIFO) || (ifmt == libc::S_IFSOCK) { } else if (ifmt == libc::S_IFIFO) || (ifmt == libc::S_IFSOCK) {
// nothing do do - entry already contains all information self.write_filename(&filename)?;
self.encode_special(&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);
} }
@ -398,7 +421,7 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
fn encode_device(&mut self, stat: &FileStat) -> Result<(), Error> { fn encode_device(&mut self, stat: &FileStat) -> Result<(), Error> {
let mut entry = self.create_entry(&stat)?; let entry = self.create_entry(&stat)?;
self.write_entry(entry)?; self.write_entry(entry)?;
@ -413,6 +436,16 @@ impl <'a, W: Write> CaTarEncoder<'a, W> {
Ok(()) Ok(())
} }
// FIFO or Socket
fn encode_special(&mut self, stat: &FileStat) -> Result<(), Error> {
let entry = self.create_entry(&stat)?;
self.write_entry(entry)?;
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);
@ -446,6 +479,13 @@ fn errno_is_unsupported(errno: Errno) -> bool {
} }
} }
fn detect_fs_type<T: AsRawFd>(fd: &T) -> Result<i64, Error> {
let mut fs_stat: libc::statfs = unsafe { std::mem::uninitialized() };
nix::sys::statfs::fstatfs(fd, &mut fs_stat)?;
Ok(fs_stat.f_type)
}
use nix::{convert_ioctl_res, request_code_read, ioc}; use nix::{convert_ioctl_res, request_code_read, ioc};
// /usr/include/linux/fs.h: #define FS_IOC_GETFLAGS _IOR('f', 1, long) // /usr/include/linux/fs.h: #define FS_IOC_GETFLAGS _IOR('f', 1, long)