mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-06 19:45:29 +00:00
add tar symlink pack and unpack test case
Signed-off-by: tommady <tommady@users.noreply.github.com>
This commit is contained in:
parent
8a26eac6a2
commit
48516eae81
@ -30,8 +30,26 @@ pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path, quiet: bool)
|
|||||||
let mut files_unpacked = 0;
|
let mut files_unpacked = 0;
|
||||||
for file in archive.entries()? {
|
for file in archive.entries()? {
|
||||||
let mut file = file?;
|
let mut file = file?;
|
||||||
|
let entry_type = file.header().entry_type();
|
||||||
|
let relative_path = file.path()?.to_path_buf();
|
||||||
|
let full_path = output_folder.join(&relative_path);
|
||||||
|
|
||||||
file.unpack_in(output_folder)?;
|
match entry_type {
|
||||||
|
tar::EntryType::Symlink => {
|
||||||
|
let target = file
|
||||||
|
.link_name()?
|
||||||
|
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::InvalidData, "Missing symlink target"))?;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
std::os::unix::fs::symlink(&target, &full_path)?;
|
||||||
|
#[cfg(windows)]
|
||||||
|
std::os::windows::symlink_file(&target, &full_path)?;
|
||||||
|
}
|
||||||
|
tar::EntryType::Regular | tar::EntryType::Directory => {
|
||||||
|
file.unpack_in(output_folder)?;
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
|
||||||
// This is printed for every file in the archive and has little
|
// This is printed for every file in the archive and has little
|
||||||
// importance for most users, but would generate lots of
|
// importance for most users, but would generate lots of
|
||||||
@ -134,23 +152,11 @@ where
|
|||||||
header.set_entry_type(tar::EntryType::Symlink);
|
header.set_entry_type(tar::EntryType::Symlink);
|
||||||
header.set_size(0);
|
header.set_size(0);
|
||||||
|
|
||||||
let entry_name = path.to_str().ok_or_else(|| {
|
builder.append_link(&mut header, path, &target_path).map_err(|err| {
|
||||||
FinalError::with_title("Tar requires that all directories names are valid UTF-8")
|
FinalError::with_title("Could not create archive")
|
||||||
.detail(format!("File at '{path:?}' has a non-UTF-8 name"))
|
.detail("Unexpected error while trying to read link")
|
||||||
|
.detail(format!("Error: {err}."))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let target_name = target_path.to_str().ok_or_else(|| {
|
|
||||||
FinalError::with_title("Tar requires that all directories names are valid UTF-8")
|
|
||||||
.detail(format!("File at '{target_path:?}' has a non-UTF-8 name"))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
builder
|
|
||||||
.append_link(&mut header, entry_name, target_name)
|
|
||||||
.map_err(|err| {
|
|
||||||
FinalError::with_title("Could not create archive")
|
|
||||||
.detail("Unexpected error while trying to read link")
|
|
||||||
.detail(format!("Error: {err}."))
|
|
||||||
})?;
|
|
||||||
} else {
|
} else {
|
||||||
let mut file = match fs::File::open(path) {
|
let mut file = match fs::File::open(path) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
|
@ -54,7 +54,7 @@ fn canonicalize_files(files: &[impl AsRef<Path>]) -> io::Result<Vec<PathBuf>> {
|
|||||||
files
|
files
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
if is_path_stdin(f.as_ref()) {
|
if is_path_stdin(f.as_ref()) || f.as_ref().is_symlink() {
|
||||||
Ok(f.as_ref().to_path_buf())
|
Ok(f.as_ref().to_path_buf())
|
||||||
} else {
|
} else {
|
||||||
fs::canonicalize(f)
|
fs::canonicalize(f)
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use std::{io::Write, iter::once, path::PathBuf};
|
use std::{
|
||||||
|
io::Write,
|
||||||
|
iter::once,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
use parse_display::Display;
|
use parse_display::Display;
|
||||||
@ -467,3 +471,59 @@ fn unpack_rar_stdin() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tar_symlink_pack_and_unpack() {
|
||||||
|
let temp_dir = tempdir().unwrap();
|
||||||
|
let root_path = temp_dir.path();
|
||||||
|
|
||||||
|
let src_files_path = root_path.join("src_files");
|
||||||
|
fs::create_dir_all(&src_files_path).unwrap();
|
||||||
|
|
||||||
|
let mut files_path = ["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"]
|
||||||
|
.into_iter()
|
||||||
|
.map(|f| src_files_path.join(f))
|
||||||
|
.map(|path| {
|
||||||
|
let mut file = fs::File::create(&path).unwrap();
|
||||||
|
file.write_all("Some content".as_bytes()).unwrap();
|
||||||
|
path
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let dest_files_path = root_path.join("dest_files");
|
||||||
|
fs::create_dir_all(&dest_files_path).unwrap();
|
||||||
|
|
||||||
|
let symlink_path = src_files_path.join(Path::new("symlink"));
|
||||||
|
#[cfg(unix)]
|
||||||
|
std::os::unix::fs::symlink(&files_path[0], &symlink_path).unwrap();
|
||||||
|
#[cfg(windows)]
|
||||||
|
std::os::windows::symlink_file(&files_path[0], &symlink_path).unwrap();
|
||||||
|
|
||||||
|
files_path.push(symlink_path);
|
||||||
|
|
||||||
|
let archive = &root_path.join("archive.tar");
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.arg("compress")
|
||||||
|
.args(files_path)
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.arg("decompress")
|
||||||
|
.arg(archive)
|
||||||
|
.arg("-d")
|
||||||
|
.arg(&dest_files_path)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
assert_same_directory(&src_files_path, &dest_files_path, false);
|
||||||
|
// check the symlink stand still
|
||||||
|
for f in dest_files_path.as_path().read_dir().unwrap() {
|
||||||
|
let f = f.unwrap();
|
||||||
|
if f.file_name() == "symlink" {
|
||||||
|
assert!(f.file_type().unwrap().is_symlink())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -88,7 +88,7 @@ pub fn assert_same_directory(x: impl Into<PathBuf>, y: impl Into<PathBuf>, prese
|
|||||||
|
|
||||||
if ft_x.is_dir() && ft_y.is_dir() {
|
if ft_x.is_dir() && ft_y.is_dir() {
|
||||||
assert_same_directory(x.path(), y.path(), preserve_permissions);
|
assert_same_directory(x.path(), y.path(), preserve_permissions);
|
||||||
} else if ft_x.is_file() && ft_y.is_file() {
|
} else if (ft_x.is_file() && ft_y.is_file()) || (ft_x.is_symlink() && ft_y.is_symlink()) {
|
||||||
assert_eq!(meta_x.len(), meta_y.len());
|
assert_eq!(meta_x.len(), meta_y.len());
|
||||||
assert_eq!(fs::read(x.path()).unwrap(), fs::read(y.path()).unwrap());
|
assert_eq!(fs::read(x.path()).unwrap(), fs::read(y.path()).unwrap());
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user