mirror of
https://github.com/uutils/tar.git
synced 2026-06-10 16:14:35 -07:00
perf: use BufWriter<StdoutLock> for all verbose/listing output
Replace println! in list, create, and extract operations with writeln! on a BufWriter<StdoutLock>. This acquires stdout's mutex once per operation instead of once per write call, and batches writes to reduce write(2) syscalls. Also propagates write errors (e.g. broken pipe) gracefully instead of panicking.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
use crate::errors::TarError;
|
||||
use std::collections::VecDeque;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, BufWriter, Write};
|
||||
use std::path::Component::{self, ParentDir, Prefix, RootDir};
|
||||
use std::path::{self, Path, PathBuf};
|
||||
use tar::Builder;
|
||||
@@ -34,6 +35,7 @@ pub fn create_archive(archive_path: &Path, files: &[&Path], verbose: bool) -> UR
|
||||
|
||||
// Create Builder instance
|
||||
let mut builder = Builder::new(file);
|
||||
let mut out = BufWriter::new(io::stdout().lock());
|
||||
|
||||
// Add each file or directory to the archive
|
||||
for &path in files {
|
||||
@@ -58,7 +60,7 @@ pub fn create_archive(archive_path: &Path, files: &[&Path], verbose: bool) -> UR
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
println!("{to_print}");
|
||||
writeln!(out, "{to_print}").map_err(TarError::Io)?;
|
||||
}
|
||||
|
||||
// Normalize path if needed (so far, handles only absolute paths)
|
||||
@@ -70,7 +72,12 @@ pub fn create_archive(archive_path: &Path, files: &[&Path], verbose: bool) -> UR
|
||||
[..original_components.len() - normalized_components.len()]
|
||||
.iter()
|
||||
.collect();
|
||||
println!("Removing leading `{}' from member names", removed.display());
|
||||
writeln!(
|
||||
out,
|
||||
"Removing leading `{}' from member names",
|
||||
removed.display()
|
||||
)
|
||||
.map_err(TarError::Io)?;
|
||||
}
|
||||
|
||||
normalized
|
||||
@@ -98,6 +105,7 @@ pub fn create_archive(archive_path: &Path, files: &[&Path], verbose: bool) -> UR
|
||||
}
|
||||
|
||||
// Finish writing the archive
|
||||
out.flush().map_err(TarError::Io)?;
|
||||
builder.finish().map_err(TarError::CannotFinalizeArchive)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
use crate::errors::TarError;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufWriter, Write};
|
||||
use std::path::Path;
|
||||
use tar::Archive;
|
||||
use uucore::error::UResult;
|
||||
@@ -28,10 +29,11 @@ pub fn extract_archive(archive_path: &Path, verbose: bool) -> UResult<()> {
|
||||
|
||||
// Create Archive instance
|
||||
let mut archive = Archive::new(file);
|
||||
let mut out = BufWriter::new(io::stdout().lock());
|
||||
|
||||
// Extract to current directory
|
||||
if verbose {
|
||||
println!("Extracting archive: {}", archive_path.display());
|
||||
writeln!(out, "Extracting archive: {}", archive_path.display()).map_err(TarError::Io)?;
|
||||
}
|
||||
|
||||
// Iterate through entries for verbose output and error handling
|
||||
@@ -45,7 +47,7 @@ pub fn extract_archive(archive_path: &Path, verbose: bool) -> UResult<()> {
|
||||
.to_path_buf();
|
||||
|
||||
if verbose {
|
||||
println!("{}", path.display());
|
||||
writeln!(out, "{}", path.display()).map_err(TarError::Io)?;
|
||||
}
|
||||
|
||||
// Unpack the entry
|
||||
@@ -55,5 +57,6 @@ pub fn extract_archive(archive_path: &Path, verbose: bool) -> UResult<()> {
|
||||
})?;
|
||||
}
|
||||
|
||||
out.flush().map_err(TarError::Io)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
use crate::errors::TarError;
|
||||
use chrono::{TimeZone, Utc};
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufWriter, Write};
|
||||
use std::path::Path;
|
||||
use tar::Archive;
|
||||
use uucore::error::UResult;
|
||||
@@ -16,6 +17,7 @@ pub fn list_archive(archive_path: &Path, verbose: bool) -> UResult<()> {
|
||||
let file: File =
|
||||
File::open(archive_path).map_err(|e| TarError::from_io_error(e, archive_path))?;
|
||||
let mut archive = Archive::new(file);
|
||||
let mut out = BufWriter::new(io::stdout().lock());
|
||||
|
||||
for entry_result in archive.entries().map_err(TarError::CannotReadEntries)? {
|
||||
let entry = entry_result.map_err(TarError::CannotReadEntry)?;
|
||||
@@ -68,16 +70,19 @@ pub fn list_archive(archive_path: &Path, verbose: bool) -> UResult<()> {
|
||||
.unwrap_or_else(Utc::now);
|
||||
let date_str = dt.format("%Y-%m-%d %H:%M");
|
||||
|
||||
println!(
|
||||
writeln!(
|
||||
out,
|
||||
"{permissions} {owner}/{group} {size:>8} {date_str} {}",
|
||||
path.display()
|
||||
);
|
||||
)
|
||||
.map_err(TarError::Io)?;
|
||||
} else {
|
||||
let path = entry.path().map_err(TarError::CannotReadEntryPath)?;
|
||||
|
||||
println!("{}", path.display());
|
||||
writeln!(out, "{}", path.display()).map_err(TarError::Io)?;
|
||||
}
|
||||
}
|
||||
|
||||
out.flush().map_err(TarError::Io)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -44,10 +44,7 @@ fn test_tar_error_code() {
|
||||
.code(),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
TarError::Io(io::Error::new(io::ErrorKind::Other, "test")).code(),
|
||||
2
|
||||
);
|
||||
assert_eq!(TarError::Io(io::Error::other("test")).code(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user