mirror of
https://github.com/uutils/tar.git
synced 2026-06-10 16:14:35 -07:00
tar: refuse to write archive to terminal, lock stdout, and buffer output
This commit is contained in:
Generated
+1
@@ -1681,6 +1681,7 @@ dependencies = [
|
||||
"clap",
|
||||
"regex",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
@@ -26,3 +26,6 @@ path = "src/tar.rs"
|
||||
[[bin]]
|
||||
name = "tar"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = { workspace = true }
|
||||
|
||||
@@ -54,6 +54,10 @@ pub enum TarError {
|
||||
/// Cannot finalize the archive
|
||||
#[error("tar: Cannot finalize archive: {0}")]
|
||||
CannotFinalizeArchive(io::Error),
|
||||
|
||||
/// Refusing to write archive contents to terminal
|
||||
#[error("tar: Refusing to write archive contents to terminal (missing -f option?)")]
|
||||
RefuseWriteArchiveToTerminal,
|
||||
}
|
||||
|
||||
impl TarError {
|
||||
|
||||
@@ -77,8 +77,8 @@ pub fn create_archive(
|
||||
.iter()
|
||||
.collect();
|
||||
writeln!(
|
||||
status_output,
|
||||
"Removing leading `{}' from member names",
|
||||
std::io::stderr(),
|
||||
"tar: Removing leading `{}' from member names",
|
||||
removed.display()
|
||||
)
|
||||
.map_err(TarError::Io)?;
|
||||
@@ -146,3 +146,32 @@ fn normalize_path(path: &Path, allow_absolute: bool) -> Option<PathBuf> {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io::{self, Write};
|
||||
use tempfile::TempDir;
|
||||
|
||||
struct FailFlushWriter;
|
||||
impl Write for FailFlushWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Err(io::Error::other("flush failed"))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_archive_flush_failed() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let file_path = dir.path().join("test.txt");
|
||||
fs::write(&file_path, "hello").unwrap();
|
||||
|
||||
let output = FailFlushWriter;
|
||||
let status_output = io::sink();
|
||||
|
||||
let res = create_archive(output, status_output, &[file_path.as_path()], false, false);
|
||||
assert!(res.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
+15
-11
@@ -9,7 +9,7 @@ pub mod operations;
|
||||
use crate::errors::TarError;
|
||||
use clap::{arg, crate_version, ArgAction, Command};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{self, IsTerminal};
|
||||
use std::path::{Path, PathBuf};
|
||||
use uucore::error::UResult;
|
||||
use uucore::format_usage;
|
||||
@@ -171,21 +171,25 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
|
||||
let output_is_stdout = archive_path == Path::new("-");
|
||||
return if output_is_stdout {
|
||||
let output = io::stdout();
|
||||
let status_output = io::stderr();
|
||||
operations::create::create_archive(
|
||||
output,
|
||||
status_output,
|
||||
&files,
|
||||
allow_absolute,
|
||||
verbose,
|
||||
)
|
||||
if io::stdout().is_terminal() {
|
||||
Err(TarError::RefuseWriteArchiveToTerminal.into())
|
||||
} else {
|
||||
let output = io::stdout().lock();
|
||||
let status_output = io::stderr();
|
||||
operations::create::create_archive(
|
||||
output,
|
||||
status_output,
|
||||
&files,
|
||||
allow_absolute,
|
||||
verbose,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let output = File::create(archive_path).map_err(|e| TarError::CannotCreateArchive {
|
||||
path: archive_path.clone(),
|
||||
source: e,
|
||||
})?;
|
||||
let status_output = io::stdout();
|
||||
let status_output = io::stdout().lock();
|
||||
operations::create::create_archive(
|
||||
output,
|
||||
status_output,
|
||||
|
||||
@@ -190,7 +190,7 @@ fn test_create_absolute_path() {
|
||||
&file_abs_path.display().to_string(),
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_contains("Removing leading");
|
||||
.stderr_contains("tar: Removing leading");
|
||||
|
||||
assert!(at.file_exists("archive-trimed.tar"));
|
||||
|
||||
@@ -868,6 +868,10 @@ fn test_create_verbose_to_stdout_keeps_stdout_as_tar_data() {
|
||||
"tar header should contain filename"
|
||||
);
|
||||
assert_eq!(&bytes[..8], b"file.txt");
|
||||
assert_eq!(
|
||||
bytes[8], 0,
|
||||
"stdout should not contain verbose output prefix"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user