Skip to content

Commit bc8845e

Browse files
committed
Merge branch 'main' into refactor-tail-continued
2 parents 12b9f2b + f32f89c commit bc8845e

File tree

4 files changed

+94
-26
lines changed

4 files changed

+94
-26
lines changed

src/uu/sync/src/sync.rs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ use nix::fcntl::{open, OFlag};
1818
use nix::sys::stat::Mode;
1919
use std::path::Path;
2020
use uucore::display::Quotable;
21+
#[cfg(any(target_os = "linux", target_os = "android"))]
22+
use uucore::error::FromIo;
2123
use uucore::error::{UResult, USimpleError};
2224
use uucore::format_usage;
2325

@@ -170,29 +172,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
170172
// Use the Nix open to be able to set the NONBLOCK flags for fifo files
171173
#[cfg(any(target_os = "linux", target_os = "android"))]
172174
{
173-
match open(Path::new(&f), OFlag::O_NONBLOCK, Mode::empty()) {
174-
Ok(_) => {}
175-
Err(e) => {
176-
if e == Errno::ENOENT {
177-
return Err(USimpleError::new(
178-
1,
179-
format!("cannot stat {}: No such file or directory", f.quote()),
180-
));
181-
}
182-
if e == Errno::EACCES {
183-
if Path::new(&f).is_dir() {
184-
return Err(USimpleError::new(
185-
1,
186-
format!("error opening {}: Permission denied", f.quote()),
187-
));
188-
} else {
189-
// ignore the issue
190-
// ./target/debug/coreutils sync --data file
191-
}
192-
}
175+
let path = Path::new(&f);
176+
if let Err(e) = open(path, OFlag::O_NONBLOCK, Mode::empty()) {
177+
if e != Errno::EACCES || (e == Errno::EACCES && path.is_dir()) {
178+
return e.map_err_context(|| format!("cannot stat {}", f.quote()))?;
193179
}
194180
}
195181
}
182+
196183
#[cfg(not(any(target_os = "linux", target_os = "android")))]
197184
{
198185
if !Path::new(&f).exists() {

src/uucore/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ os_display = "0.1.3"
3838

3939
[target.'cfg(unix)'.dependencies]
4040
walkdir = { version="2.3.2", optional=true }
41-
nix = { version = "0.25", optional = true, default-features = false, features = ["fs", "uio", "zerocopy"] }
41+
nix = { version = "0.25", default-features = false, features = ["fs", "uio", "zerocopy"] }
4242

4343
[dev-dependencies]
4444
clap = "4.0"
@@ -53,8 +53,8 @@ default = []
5353
# * non-default features
5454
encoding = ["data-encoding", "data-encoding-macro", "z85", "thiserror"]
5555
entries = ["libc"]
56-
fs = ["libc", "nix", "winapi-util", "windows-sys"]
57-
fsext = ["libc", "nix", "time", "windows-sys"]
56+
fs = ["libc", "winapi-util", "windows-sys"]
57+
fsext = ["libc", "time", "windows-sys"]
5858
lines = []
5959
memo = ["itertools"]
6060
mode = ["libc"]
@@ -65,4 +65,4 @@ signals = []
6565
utf8 = []
6666
utmpx = ["time", "time/macros", "libc", "dns-lookup"]
6767
wide = []
68-
pipes = ["nix"]
68+
pipes = []

src/uucore/src/lib/mods/error.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,60 @@ impl From<std::io::Error> for Box<dyn UError> {
508508
}
509509
}
510510

511+
/// Enables the conversion from [`Result<T, nix::Error>`] to [`UResult<T>`].
512+
///
513+
/// # Examples
514+
///
515+
/// ```
516+
/// use uucore::error::FromIo;
517+
/// use nix::errno::Errno;
518+
///
519+
/// let nix_err = Err::<(), nix::Error>(Errno::EACCES);
520+
/// let uio_result = nix_err.map_err_context(|| String::from("fix me please!"));
521+
///
522+
/// // prints "fix me please!: Permission denied"
523+
/// println!("{}", uio_result.unwrap_err());
524+
/// ```
525+
#[cfg(any(target_os = "linux", target_os = "android"))]
526+
impl<T> FromIo<UResult<T>> for Result<T, nix::Error> {
527+
fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> {
528+
self.map_err(|e| {
529+
Box::new(UIoError {
530+
context: Some((context)()),
531+
inner: std::io::Error::from_raw_os_error(e as i32),
532+
}) as Box<dyn UError>
533+
})
534+
}
535+
}
536+
537+
#[cfg(any(target_os = "linux", target_os = "android"))]
538+
impl<T> FromIo<UResult<T>> for nix::Error {
539+
fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> {
540+
Err(Box::new(UIoError {
541+
context: Some((context)()),
542+
inner: std::io::Error::from_raw_os_error(self as i32),
543+
}) as Box<dyn UError>)
544+
}
545+
}
546+
547+
#[cfg(any(target_os = "linux", target_os = "android"))]
548+
impl From<nix::Error> for UIoError {
549+
fn from(f: nix::Error) -> Self {
550+
Self {
551+
context: None,
552+
inner: std::io::Error::from_raw_os_error(f as i32),
553+
}
554+
}
555+
}
556+
557+
#[cfg(any(target_os = "linux", target_os = "android"))]
558+
impl From<nix::Error> for Box<dyn UError> {
559+
fn from(f: nix::Error) -> Self {
560+
let u_error: UIoError = f.into();
561+
Box::new(u_error) as Self
562+
}
563+
}
564+
511565
/// Shorthand to construct [`UIoError`]-instances.
512566
///
513567
/// This macro serves as a convenience call to quickly construct instances of
@@ -693,3 +747,30 @@ impl Display for ClapErrorWrapper {
693747
Ok(())
694748
}
695749
}
750+
751+
#[cfg(test)]
752+
mod tests {
753+
#[test]
754+
#[cfg(any(target_os = "linux", target_os = "android"))]
755+
fn test_nix_error_conversion() {
756+
use super::{FromIo, UIoError};
757+
use nix::errno::Errno;
758+
use std::io::ErrorKind;
759+
760+
for (nix_error, expected_error_kind) in [
761+
(Errno::EACCES, ErrorKind::PermissionDenied),
762+
(Errno::ENOENT, ErrorKind::NotFound),
763+
(Errno::EEXIST, ErrorKind::AlreadyExists),
764+
] {
765+
let error = UIoError::from(nix_error);
766+
assert_eq!(expected_error_kind, error.inner.kind());
767+
}
768+
assert_eq!(
769+
"test: Permission denied",
770+
Err::<(), nix::Error>(Errno::EACCES)
771+
.map_err_context(|| String::from("test"))
772+
.unwrap_err()
773+
.to_string()
774+
)
775+
}
776+
}

tests/by-util/test_sync.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ fn test_sync_no_permission_dir() {
6464

6565
ts.ccmd("chmod").arg("0").arg(dir).succeeds();
6666
let result = ts.ucmd().arg("--data").arg(dir).fails();
67-
result.stderr_contains("sync: error opening 'foo': Permission denied");
67+
result.stderr_contains("sync: cannot stat 'foo': Permission denied");
6868
let result = ts.ucmd().arg(dir).fails();
69-
result.stderr_contains("sync: error opening 'foo': Permission denied");
69+
result.stderr_contains("sync: cannot stat 'foo': Permission denied");
7070
}
7171

7272
#[cfg(not(target_os = "windows"))]

0 commit comments

Comments
 (0)