diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/tar.rs | 18 | ||||
-rw-r--r-- | src/util/unix.rs (renamed from src/util/uid.rs) | 25 |
2 files changed, 33 insertions, 10 deletions
diff --git a/src/util/tar.rs b/src/util/tar.rs index 885663e..1014abc 100644 --- a/src/util/tar.rs +++ b/src/util/tar.rs @@ -1,33 +1,35 @@ use std::{ ffi::CString, fs::DirBuilder, - io::{self, Read, Write}, + io::{self, Read, Result, Write}, os::unix::ffi::OsStrExt, path::Path, }; +use walkdir::WalkDir; + +use super::unix; pub fn pack<W: Write, P: AsRef<Path>, E: AsRef<Path>, I: Iterator<Item = E>>( archive: W, source: P, entries: I, -) -> io::Result<W> { +) -> Result<W> { + let _chdir = unix::chdir(source)?; + let mut ar = tar::Builder::new(archive); ar.mode(tar::HeaderMode::Deterministic); ar.follow_symlinks(false); for entry in entries { - let path = source.as_ref().join(entry.as_ref()); - if path.is_dir() { - ar.append_dir_all(entry.as_ref(), path)?; - } else { - ar.append_path_with_name(path, entry.as_ref())?; + for dir_entry in WalkDir::new(entry).sort_by_file_name() { + ar.append_path(dir_entry?.path())?; } } ar.into_inner() } -pub fn unpack<R: Read, P: AsRef<Path>>(archive: R, dest: P) -> io::Result<()> { +pub fn unpack<R: Read, P: AsRef<Path>>(archive: R, dest: P) -> Result<()> { let dest_path = dest.as_ref(); DirBuilder::new().recursive(true).create(dest_path)?; diff --git a/src/util/uid.rs b/src/util/unix.rs index ee1e16b..ee0507c 100644 --- a/src/util/uid.rs +++ b/src/util/unix.rs @@ -1,6 +1,6 @@ -use std::{fs::File, io::Result, path::Path}; +use std::{fs::File, io::Result, os::unix::prelude::AsRawFd, path::Path}; -use nix::unistd; +use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode, unistd}; use super::ToIOResult; @@ -42,3 +42,24 @@ pub fn create_as<P: AsRef<Path>>( File::create(path) } + +pub struct Chdir(Dir); + +impl Drop for Chdir { + fn drop(&mut self) { + unistd::fchdir(self.0.as_raw_fd()).expect("failed to revert directory change"); + } +} + +pub fn chdir<P: AsRef<Path>>(path: P) -> Result<Chdir> { + let dir = Dir::open( + ".", + OFlag::O_PATH | OFlag::O_CLOEXEC | OFlag::O_NOFOLLOW, + Mode::empty(), + ) + .to_io_result()?; + + unistd::chdir(path.as_ref()).to_io_result()?; + + Ok(Chdir(dir)) +} |