sync: Verify that the files can be opened

This commit is contained in:
Sylvestre Ledru 2022-09-24 14:54:19 +02:00
parent fc1c7755b9
commit 6edf8ebf41
4 changed files with 73 additions and 5 deletions

1
Cargo.lock generated
View file

@ -2834,6 +2834,7 @@ version = "0.0.15"
dependencies = [
"clap",
"libc",
"nix",
"uucore",
"winapi",
]

View file

@ -19,6 +19,9 @@ clap = { version = "3.2", features = ["wrap_help", "cargo"] }
libc = "0.2.132"
uucore = { version=">=0.0.15", package="uucore", path="../../uucore", features=["wide"] }
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
nix = "0.25"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["errhandlingapi", "fileapi", "handleapi", "std", "winbase", "winerror"] }

View file

@ -10,6 +10,12 @@
extern crate libc;
use clap::{crate_version, Arg, Command};
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::errno::Errno;
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::fcntl::{open, OFlag};
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::sys::stat::Mode;
use std::path::Path;
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError};
@ -174,11 +180,40 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}
for f in &files {
if !Path::new(&f).exists() {
return Err(USimpleError::new(
1,
format!("cannot stat {}: No such file or directory", f.quote()),
));
// Use the Nix open to be able to set the NONBLOCK flags for fifo files
#[cfg(any(target_os = "linux", target_os = "android"))]
{
match open(Path::new(&f), OFlag::O_NONBLOCK, Mode::empty()) {
Ok(_) => {}
Err(e) => {
if e == Errno::ENOENT {
return Err(USimpleError::new(
1,
format!("cannot stat {}: No such file or directory", f.quote()),
));
}
if e == Errno::EACCES {
if Path::new(&f).is_dir() {
return Err(USimpleError::new(
1,
format!("error opening {}: Permission denied", f.quote()),
));
} else {
// ignore the issue
// ./target/debug/coreutils sync --data file
}
}
}
}
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
{
if !Path::new(&f).exists() {
return Err(USimpleError::new(
1,
format!("cannot stat {}: No such file or directory", f.quote()),
));
}
}
}

View file

@ -52,3 +52,32 @@ fn test_sync_data_but_not_file() {
.fails()
.stderr_contains("sync: --data needs at least one argument");
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg(feature = "chmod")]
#[test]
fn test_sync_no_permission_dir() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
let dir = "foo";
at.mkdir_all(dir);
ts.ccmd("chmod").arg("0").arg(dir).succeeds();
let result = ts.ucmd().arg("--data").arg(dir).fails();
result.stderr_contains("sync: error opening 'foo': Permission denied");
let result = ts.ucmd().arg(dir).fails();
result.stderr_contains("sync: error opening 'foo': Permission denied");
}
#[cfg(not(target_os = "windows"))]
#[cfg(feature = "chmod")]
#[test]
fn test_sync_no_permission_file() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
let f = "file";
at.touch(f);
ts.ccmd("chmod").arg("0200").arg(f).succeeds();
ts.ucmd().arg(f).succeeds();
}