mirror of
https://github.com/ouch-org/ouch.git
synced 2025-07-19 16:10:53 +00:00
Merge 15b2b06a72047202acd04a971002670fdf705438 into d0494504a1df4e13ecd4eeae0495066c81060cad
This commit is contained in:
commit
864d3c99a9
108
Cargo.lock
generated
108
Cargo.lock
generated
@ -93,6 +93,15 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arbitrary"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
||||||
|
dependencies = [
|
||||||
|
"derive_arbitrary",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assert_cmd"
|
name = "assert_cmd"
|
||||||
version = "2.0.16"
|
version = "2.0.16"
|
||||||
@ -126,12 +135,6 @@ version = "1.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64ct"
|
|
||||||
version = "1.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.63.0"
|
version = "0.63.0"
|
||||||
@ -452,9 +455,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.1.5"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core_affinity"
|
name = "core_affinity"
|
||||||
@ -529,6 +532,17 @@ dependencies = [
|
|||||||
"powerfmt",
|
"powerfmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_arbitrary"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.98",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diff"
|
name = "diff"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
@ -570,6 +584,12 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.10"
|
version = "0.3.10"
|
||||||
@ -611,9 +631,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.1.0"
|
version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"libz-sys",
|
"libz-sys",
|
||||||
@ -690,8 +710,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.13.3+wasi-0.2.2",
|
"wasi 0.13.3+wasi-0.2.2",
|
||||||
|
"wasm-bindgen",
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -731,6 +753,12 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -786,6 +814,16 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "infer"
|
name = "infer"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
@ -1164,27 +1202,14 @@ dependencies = [
|
|||||||
"syn 2.0.98",
|
"syn 2.0.98",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "password-hash"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
|
||||||
dependencies = [
|
|
||||||
"base64ct",
|
|
||||||
"rand_core 0.6.4",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pbkdf2"
|
name = "pbkdf2"
|
||||||
version = "0.11.0"
|
version = "0.12.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
|
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
"hmac",
|
"hmac",
|
||||||
"password-hash",
|
|
||||||
"sha2",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2135,21 +2160,44 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zip"
|
name = "zeroize"
|
||||||
version = "0.6.6"
|
version = "1.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize_derive"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.98",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zip"
|
||||||
|
version = "4.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95ab361742de920c5535880f89bbd611ee62002bf11341d16a5f057bb8ba6899"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"byteorder",
|
"arbitrary",
|
||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"crossbeam-utils",
|
|
||||||
"flate2",
|
"flate2",
|
||||||
|
"getrandom 0.3.1",
|
||||||
"hmac",
|
"hmac",
|
||||||
|
"indexmap",
|
||||||
|
"memchr",
|
||||||
"pbkdf2",
|
"pbkdf2",
|
||||||
"sha1",
|
"sha1",
|
||||||
"time",
|
"time",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -42,7 +42,7 @@ tempfile = "3.10.1"
|
|||||||
time = { version = "0.3.36", default-features = false }
|
time = { version = "0.3.36", default-features = false }
|
||||||
unrar = { version = "0.5.7", optional = true }
|
unrar = { version = "0.5.7", optional = true }
|
||||||
xz2 = "0.1.7"
|
xz2 = "0.1.7"
|
||||||
zip = { version = "0.6.6", default-features = false, features = [
|
zip = { version = "4.2", default-features = false, features = [
|
||||||
"time",
|
"time",
|
||||||
"aes-crypto",
|
"aes-crypto",
|
||||||
] }
|
] }
|
||||||
@ -76,7 +76,7 @@ test-strategy = "0.4.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["unrar", "use_zlib", "use_zstd_thin", "bzip3"]
|
default = ["unrar", "use_zlib", "use_zstd_thin", "bzip3"]
|
||||||
use_zlib = ["flate2/zlib", "gzp/deflate_zlib", "zip/deflate-zlib"]
|
use_zlib = ["flate2/zlib", "gzp/deflate_zlib", "zip/deflate-flate2-zlib"]
|
||||||
use_zstd_thin = ["zstd/thin"]
|
use_zstd_thin = ["zstd/thin"]
|
||||||
allow_piped_choice = []
|
allow_piped_choice = []
|
||||||
|
|
||||||
|
@ -41,9 +41,7 @@ where
|
|||||||
|
|
||||||
for idx in 0..archive.len() {
|
for idx in 0..archive.len() {
|
||||||
let mut file = match password {
|
let mut file = match password {
|
||||||
Some(password) => archive
|
Some(password) => archive.by_index_decrypt(idx, password)?,
|
||||||
.by_index_decrypt(idx, password)?
|
|
||||||
.map_err(|_| zip::result::ZipError::UnsupportedArchive("Password required to decrypt file"))?,
|
|
||||||
None => archive.by_index(idx)?,
|
None => archive.by_index(idx)?,
|
||||||
};
|
};
|
||||||
let file_path = match file.enclosed_name() {
|
let file_path = match file.enclosed_name() {
|
||||||
@ -65,6 +63,9 @@ where
|
|||||||
info(format!("File {} extracted to \"{}\"", idx, file_path.display()));
|
info(format!("File {} extracted to \"{}\"", idx, file_path.display()));
|
||||||
}
|
}
|
||||||
fs::create_dir_all(&file_path)?;
|
fs::create_dir_all(&file_path)?;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
unix_set_permissions(&file_path, &file)?;
|
||||||
}
|
}
|
||||||
_is_file @ false => {
|
_is_file @ false => {
|
||||||
if let Some(path) = file_path.parent() {
|
if let Some(path) = file_path.parent() {
|
||||||
@ -74,15 +75,6 @@ where
|
|||||||
}
|
}
|
||||||
let file_path = strip_cur_dir(file_path.as_path());
|
let file_path = strip_cur_dir(file_path.as_path());
|
||||||
|
|
||||||
// same reason is in _is_dir: long, often not needed text
|
|
||||||
if !quiet {
|
|
||||||
info(format!(
|
|
||||||
"extracted ({}) {:?}",
|
|
||||||
Bytes::new(file.size()),
|
|
||||||
file_path.display(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mode = file.unix_mode();
|
let mode = file.unix_mode();
|
||||||
let is_symlink = mode.is_some_and(|mode| mode & 0o170000 == 0o120000);
|
let is_symlink = mode.is_some_and(|mode| mode & 0o170000 == 0o120000);
|
||||||
|
|
||||||
@ -90,6 +82,10 @@ where
|
|||||||
let mut target = String::new();
|
let mut target = String::new();
|
||||||
file.read_to_string(&mut target)?;
|
file.read_to_string(&mut target)?;
|
||||||
|
|
||||||
|
if !quiet {
|
||||||
|
info(format!("linking {} -> {}", file_path.display(), target));
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
std::os::unix::fs::symlink(&target, file_path)?;
|
std::os::unix::fs::symlink(&target, file_path)?;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -97,14 +93,21 @@ where
|
|||||||
} else {
|
} else {
|
||||||
let mut output_file = fs::File::create(file_path)?;
|
let mut output_file = fs::File::create(file_path)?;
|
||||||
io::copy(&mut file, &mut output_file)?;
|
io::copy(&mut file, &mut output_file)?;
|
||||||
}
|
|
||||||
|
|
||||||
set_last_modified_time(&file, file_path)?;
|
set_last_modified_time(&file, file_path)?;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
unix_set_permissions(&file_path, &file)?;
|
unix_set_permissions(&file_path, &file)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// same reason is in _is_dir: long, often not needed text
|
||||||
|
if !quiet {
|
||||||
|
info(format!(
|
||||||
|
"extracted ({}) {:?}",
|
||||||
|
Bytes::new(file.size()),
|
||||||
|
file_path.display(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unpacked_files += 1;
|
unpacked_files += 1;
|
||||||
}
|
}
|
||||||
@ -136,9 +139,7 @@ where
|
|||||||
for idx in 0..archive.len() {
|
for idx in 0..archive.len() {
|
||||||
let file_in_archive = (|| {
|
let file_in_archive = (|| {
|
||||||
let zip_result = match password.clone() {
|
let zip_result = match password.clone() {
|
||||||
Some(password) => archive
|
Some(password) => archive.by_index_decrypt(idx, &password),
|
||||||
.by_index_decrypt(idx, &password)?
|
|
||||||
.map_err(|_| zip::result::ZipError::UnsupportedArchive("Password required to decrypt file")),
|
|
||||||
None => archive.by_index(idx),
|
None => archive.by_index(idx),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -147,7 +148,7 @@ where
|
|||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = file.enclosed_name().unwrap_or(&*file.mangled_name()).to_owned();
|
let path = file.enclosed_name().unwrap_or_else(|| file.mangled_name()).to_owned();
|
||||||
let is_dir = file.is_dir();
|
let is_dir = file.is_dir();
|
||||||
|
|
||||||
Ok(FileInArchive { path, is_dir })
|
Ok(FileInArchive { path, is_dir })
|
||||||
@ -174,7 +175,7 @@ where
|
|||||||
let mut writer = zip::ZipWriter::new(writer);
|
let mut writer = zip::ZipWriter::new(writer);
|
||||||
// always use ZIP64 to allow compression of files larger than 4GB
|
// always use ZIP64 to allow compression of files larger than 4GB
|
||||||
// the format is widely supported and the extra 20B is negligible in most cases
|
// the format is widely supported and the extra 20B is negligible in most cases
|
||||||
let options = zip::write::FileOptions::default().large_file(true);
|
let options = zip::write::SimpleFileOptions::default().large_file(true);
|
||||||
let output_handle = Handle::from_path(output_path);
|
let output_handle = Handle::from_path(output_path);
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
@ -241,6 +242,8 @@ where
|
|||||||
FinalError::with_title("Zip requires that all directories names are valid UTF-8")
|
FinalError::with_title("Zip requires that all directories names are valid UTF-8")
|
||||||
.detail(format!("File at '{path:?}' has a non-UTF-8 name"))
|
.detail(format!("File at '{path:?}' has a non-UTF-8 name"))
|
||||||
})?;
|
})?;
|
||||||
|
// ZIP format requires forward slashes as path separators, regardless of platform
|
||||||
|
let entry_name = entry_name.replace(std::path::MAIN_SEPARATOR, "/");
|
||||||
|
|
||||||
if metadata.is_dir() {
|
if metadata.is_dir() {
|
||||||
writer.add_directory(entry_name, options)?;
|
writer.add_directory(entry_name, options)?;
|
||||||
@ -250,6 +253,8 @@ where
|
|||||||
FinalError::with_title("Zip requires that all directories names are valid UTF-8")
|
FinalError::with_title("Zip requires that all directories names are valid UTF-8")
|
||||||
.detail(format!("File at '{target_path:?}' has a non-UTF-8 name"))
|
.detail(format!("File at '{target_path:?}' has a non-UTF-8 name"))
|
||||||
})?;
|
})?;
|
||||||
|
// ZIP format requires forward slashes as path separators, regardless of platform
|
||||||
|
let target_name = target_name.replace(std::path::MAIN_SEPARATOR, "/");
|
||||||
|
|
||||||
// This approach writes the symlink target path as the content of the symlink entry.
|
// This approach writes the symlink target path as the content of the symlink entry.
|
||||||
// We detect symlinks during extraction by checking for the Unix symlink mode (0o120000) in the entry's permissions.
|
// We detect symlinks during extraction by checking for the Unix symlink mode (0o120000) in the entry's permissions.
|
||||||
@ -286,7 +291,7 @@ where
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_zip_comment_if_exists(file: &ZipFile) {
|
fn display_zip_comment_if_exists<R: Read>(file: &ZipFile<'_, R>) {
|
||||||
let comment = file.comment();
|
let comment = file.comment();
|
||||||
if !comment.is_empty() {
|
if !comment.is_empty() {
|
||||||
// Zip file comments seem to be pretty rare, but if they are used,
|
// Zip file comments seem to be pretty rare, but if they are used,
|
||||||
@ -311,23 +316,26 @@ fn get_last_modified_time(file: &fs::File) -> DateTime {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_last_modified_time(zip_file: &ZipFile, path: &Path) -> crate::Result<()> {
|
fn set_last_modified_time<R: Read>(zip_file: &ZipFile<'_, R>, path: &Path) -> crate::Result<()> {
|
||||||
let modification_time = zip_file.last_modified().to_time();
|
// Extract modification time from zip file and convert to FileTime
|
||||||
|
let file_time = zip_file
|
||||||
let Ok(time_in_seconds) = modification_time else {
|
.last_modified()
|
||||||
return Ok(());
|
.and_then(|datetime| OffsetDateTime::try_from(datetime).ok())
|
||||||
};
|
.map(|time| {
|
||||||
|
|
||||||
// Zip does not support nanoseconds, so we can assume zero here
|
// Zip does not support nanoseconds, so we can assume zero here
|
||||||
let modification_time = FileTime::from_unix_time(time_in_seconds.unix_timestamp(), 0);
|
FileTime::from_unix_time(time.unix_timestamp(), 0)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the modification time if available
|
||||||
|
if let Some(modification_time) = file_time {
|
||||||
set_file_mtime(path, modification_time)?;
|
set_file_mtime(path, modification_time)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn unix_set_permissions(file_path: &Path, file: &ZipFile) -> crate::Result<()> {
|
fn unix_set_permissions<R: Read>(file_path: &Path, file: &ZipFile<'_, R>) -> crate::Result<()> {
|
||||||
use std::fs::Permissions;
|
use std::fs::Permissions;
|
||||||
|
|
||||||
if let Some(mode) = file.unix_mode() {
|
if let Some(mode) = file.unix_mode() {
|
||||||
|
14
src/error.rs
14
src/error.rs
@ -27,11 +27,11 @@ pub enum Error {
|
|||||||
/// NEEDS MORE CONTEXT
|
/// NEEDS MORE CONTEXT
|
||||||
AlreadyExists { error_title: String },
|
AlreadyExists { error_title: String },
|
||||||
/// From zip::result::ZipError::InvalidArchive
|
/// From zip::result::ZipError::InvalidArchive
|
||||||
InvalidZipArchive(&'static str),
|
InvalidZipArchive(String),
|
||||||
/// Detected from io::Error if .kind() is io::ErrorKind::PermissionDenied
|
/// Detected from io::Error if .kind() is io::ErrorKind::PermissionDenied
|
||||||
PermissionDenied { error_title: String },
|
PermissionDenied { error_title: String },
|
||||||
/// From zip::result::ZipError::UnsupportedArchive
|
/// From zip::result::ZipError::UnsupportedArchive
|
||||||
UnsupportedZipArchive(&'static str),
|
UnsupportedZipArchive(String),
|
||||||
/// We don't support compressing the root folder.
|
/// We don't support compressing the root folder.
|
||||||
CompressingRootFolder,
|
CompressingRootFolder,
|
||||||
/// Specialized walkdir's io::Error wrapper with additional information on the error
|
/// Specialized walkdir's io::Error wrapper with additional information on the error
|
||||||
@ -218,11 +218,17 @@ impl From<zip::result::ZipError> for Error {
|
|||||||
use zip::result::ZipError;
|
use zip::result::ZipError;
|
||||||
match err {
|
match err {
|
||||||
ZipError::Io(io_err) => Self::from(io_err),
|
ZipError::Io(io_err) => Self::from(io_err),
|
||||||
ZipError::InvalidArchive(filename) => Self::InvalidZipArchive(filename),
|
ZipError::InvalidArchive(filename) => Self::InvalidZipArchive(filename.to_string()),
|
||||||
ZipError::FileNotFound => Self::Custom {
|
ZipError::FileNotFound => Self::Custom {
|
||||||
reason: FinalError::with_title("Unexpected error in zip archive").detail("File not found"),
|
reason: FinalError::with_title("Unexpected error in zip archive").detail("File not found"),
|
||||||
},
|
},
|
||||||
ZipError::UnsupportedArchive(filename) => Self::UnsupportedZipArchive(filename),
|
ZipError::UnsupportedArchive(filename) => Self::UnsupportedZipArchive(filename.to_string()),
|
||||||
|
ZipError::InvalidPassword => Self::InvalidPassword {
|
||||||
|
reason: "The provided password is incorrect".to_string(),
|
||||||
|
},
|
||||||
|
_ => Self::Custom {
|
||||||
|
reason: FinalError::with_title("Unexpected error in zip archive").detail(err.to_string()),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
src/list.rs
34
src/list.rs
@ -52,22 +52,28 @@ pub fn list_files(
|
|||||||
fn print_entry(out: &mut impl Write, name: impl std::fmt::Display, is_dir: bool) {
|
fn print_entry(out: &mut impl Write, name: impl std::fmt::Display, is_dir: bool) {
|
||||||
use crate::utils::colors::*;
|
use crate::utils::colors::*;
|
||||||
|
|
||||||
if is_dir {
|
if !is_dir {
|
||||||
// if colors are deactivated, print final / to mark directories
|
// Not a directory -> just print the file name
|
||||||
if BLUE.is_empty() {
|
|
||||||
let _ = writeln!(out, "{name}/");
|
|
||||||
// if in ACCESSIBLE mode, use colors but print final / in case colors
|
|
||||||
// aren't read out aloud with a screen reader or aren't printed on a
|
|
||||||
// braille reader
|
|
||||||
} else if is_running_in_accessible_mode() {
|
|
||||||
let _ = writeln!(out, "{}{}{}/{}", *BLUE, *STYLE_BOLD, name, *ALL_RESET);
|
|
||||||
} else {
|
|
||||||
let _ = writeln!(out, "{}{}{}{}", *BLUE, *STYLE_BOLD, name, *ALL_RESET);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// not a dir -> just print the file name
|
|
||||||
let _ = writeln!(out, "{name}");
|
let _ = writeln!(out, "{name}");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle directory display
|
||||||
|
let name_str = name.to_string();
|
||||||
|
let display_name = name_str.strip_suffix('/').unwrap_or(&name_str);
|
||||||
|
|
||||||
|
let output = if BLUE.is_empty() {
|
||||||
|
// Colors are deactivated, print final / to mark directories
|
||||||
|
format!("{display_name}/")
|
||||||
|
} else if is_running_in_accessible_mode() {
|
||||||
|
// Accessible mode: use colors but print final / for screen readers
|
||||||
|
format!("{}{}{}/{}", *BLUE, *STYLE_BOLD, display_name, *ALL_RESET)
|
||||||
|
} else {
|
||||||
|
// Normal mode: use colors without trailing slash
|
||||||
|
format!("{}{}{}{}", *BLUE, *STYLE_BOLD, display_name, *ALL_RESET)
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = writeln!(out, "{output}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Since archives store files as a list of entries -> without direct
|
/// Since archives store files as a list of entries -> without direct
|
||||||
|
Loading…
x
Reference in New Issue
Block a user