From 711d80c37b8d4c0b579ecbef4f2354b5d24d3555 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Thu, 5 Feb 2026 23:37:37 +0800 Subject: [PATCH 1/5] sync: return after checking all inputs --- src/uu/sync/src/sync.rs | 26 +++++++++++++++++--------- tests/by-util/test_sync.rs | 8 ++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index 0e5b864b9cd..5e927c4a1ee 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -14,10 +14,9 @@ use nix::fcntl::{OFlag, open}; use nix::sys::stat::Mode; use std::path::Path; use uucore::display::Quotable; -#[cfg(any(target_os = "linux", target_os = "android"))] -use uucore::error::FromIo; use uucore::error::{UResult, USimpleError}; use uucore::format_usage; +use uucore::show_error; use uucore::translate; pub mod options { @@ -216,6 +215,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { )); } + let mut has_error = false; + for f in &files { // Use the Nix open to be able to set the NONBLOCK flags for fifo files #[cfg(any(target_os = "linux", target_os = "android"))] @@ -223,23 +224,30 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let path = Path::new(&f); if let Err(e) = open(path, OFlag::O_NONBLOCK, Mode::empty()) { if e != Errno::EACCES || (e == Errno::EACCES && path.is_dir()) { - e.map_err_context( - || translate!("sync-error-opening-file", "file" => f.quote()), - )?; + show_error!( + "{}", + translate!("sync-error-no-such-file", "file" => f.quote()) + ); + has_error = true; } } } #[cfg(not(any(target_os = "linux", target_os = "android")))] { if !Path::new(&f).exists() { - return Err(USimpleError::new( - 1, - translate!("sync-error-no-such-file", "file" => f.quote()), - )); + show_error!( + "{}", + translate!("sync-error-no-such-file", "file" => f.quote()) + ); + has_error = true; } } } + if has_error { + return Err(USimpleError::new(1, "")); + } + #[allow(clippy::if_same_then_else)] if matches.get_flag(options::FILE_SYSTEM) { #[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))] diff --git a/tests/by-util/test_sync.rs b/tests/by-util/test_sync.rs index 9c3df3a1e61..61026a03fb8 100644 --- a/tests/by-util/test_sync.rs +++ b/tests/by-util/test_sync.rs @@ -167,3 +167,11 @@ fn test_sync_multiple_files() { // Sync both files new_ucmd!().arg("--data").arg(&file1).arg(&file2).succeeds(); } + +#[test] +fn test_sync_multiple_nonexistent_files() { + let result = new_ucmd!().arg("--data").arg("bad1").arg("bad2").fails(); + + result.stderr_contains("sync: error opening 'bad1': No such file or directory"); + result.stderr_contains("sync: error opening 'bad2': No such file or directory"); +} From c0fd3381b7c27f3641cae0788da038a1cafba7a2 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Fri, 6 Feb 2026 00:18:38 +0800 Subject: [PATCH 2/5] fix missing error context --- src/uu/sync/src/sync.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index 5e927c4a1ee..2b24934bb44 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -14,6 +14,8 @@ use nix::fcntl::{OFlag, open}; use nix::sys::stat::Mode; use std::path::Path; use uucore::display::Quotable; +#[cfg(any(target_os = "linux", target_os = "android"))] +use uucore::error::FromIo; use uucore::error::{UResult, USimpleError}; use uucore::format_usage; use uucore::show_error; @@ -224,11 +226,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let path = Path::new(&f); if let Err(e) = open(path, OFlag::O_NONBLOCK, Mode::empty()) { if e != Errno::EACCES || (e == Errno::EACCES && path.is_dir()) { - show_error!( - "{}", - translate!("sync-error-no-such-file", "file" => f.quote()) + let err: UResult<()> = e.map_err_context( + || translate!("sync-error-opening-file", "file" => f.quote()), ); - has_error = true; + if let Err(err) = err { + show_error!("{}", err.to_string()); + has_error = true; + } } } } From cee1b5fd4cbd32d70887a594ea03f8b4ed4fb8c2 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Fri, 6 Feb 2026 22:42:23 +0800 Subject: [PATCH 3/5] use set_exit_code and update translation templates to show errors --- Cargo.lock | 1 + src/uu/sync/Cargo.toml | 1 + src/uu/sync/locales/en-US.ftl | 2 +- src/uu/sync/locales/fr-FR.ftl | 2 +- src/uu/sync/src/sync.rs | 20 +++++++------------- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 489778c5a07..36f01cd5c7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4172,6 +4172,7 @@ dependencies = [ "clap", "fluent", "nix", + "thiserror 2.0.18", "uucore", "windows-sys 0.61.2", ] diff --git a/src/uu/sync/Cargo.toml b/src/uu/sync/Cargo.toml index 6d00339abb3..ec48121aa22 100644 --- a/src/uu/sync/Cargo.toml +++ b/src/uu/sync/Cargo.toml @@ -21,6 +21,7 @@ path = "src/sync.rs" clap = { workspace = true } uucore = { workspace = true, features = ["wide"] } fluent = { workspace = true } +thiserror = { workspace = true } [target.'cfg(unix)'.dependencies] nix = { workspace = true } diff --git a/src/uu/sync/locales/en-US.ftl b/src/uu/sync/locales/en-US.ftl index d0b520bcb95..6ab75c83950 100644 --- a/src/uu/sync/locales/en-US.ftl +++ b/src/uu/sync/locales/en-US.ftl @@ -7,7 +7,7 @@ sync-help-data = sync only file data, no unneeded metadata (Linux only) # Error messages sync-error-data-needs-argument = --data needs at least one argument -sync-error-opening-file = error opening { $file } +sync-error-opening-file = error opening { $file }: { $err } sync-error-no-such-file = error opening { $file }: No such file or directory # Warning messages diff --git a/src/uu/sync/locales/fr-FR.ftl b/src/uu/sync/locales/fr-FR.ftl index f0d00db03ba..f8847969010 100644 --- a/src/uu/sync/locales/fr-FR.ftl +++ b/src/uu/sync/locales/fr-FR.ftl @@ -7,7 +7,7 @@ sync-help-data = synchroniser seulement les données des fichiers, pas les méta # Messages d'erreur sync-error-data-needs-argument = --data nécessite au moins un argument -sync-error-opening-file = erreur lors de l'ouverture de { $file } +sync-error-opening-file = erreur lors de l'ouverture de { $file } : { $err } sync-error-no-such-file = erreur lors de l'ouverture de { $file } : Aucun fichier ou répertoire de ce type # Messages d'avertissement diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index 2b24934bb44..830f2473857 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -14,9 +14,7 @@ use nix::fcntl::{OFlag, open}; use nix::sys::stat::Mode; use std::path::Path; use uucore::display::Quotable; -#[cfg(any(target_os = "linux", target_os = "android"))] -use uucore::error::FromIo; -use uucore::error::{UResult, USimpleError}; +use uucore::error::{UResult, USimpleError, get_exit_code, set_exit_code}; use uucore::format_usage; use uucore::show_error; use uucore::translate; @@ -217,8 +215,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { )); } - let mut has_error = false; - for f in &files { // Use the Nix open to be able to set the NONBLOCK flags for fifo files #[cfg(any(target_os = "linux", target_os = "android"))] @@ -226,13 +222,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let path = Path::new(&f); if let Err(e) = open(path, OFlag::O_NONBLOCK, Mode::empty()) { if e != Errno::EACCES || (e == Errno::EACCES && path.is_dir()) { - let err: UResult<()> = e.map_err_context( - || translate!("sync-error-opening-file", "file" => f.quote()), + show_error!( + "{}", + translate!("sync-error-opening-file", "file" => f.quote(), "err" => e.desc()) ); - if let Err(err) = err { - show_error!("{}", err.to_string()); - has_error = true; - } + set_exit_code(1); } } } @@ -243,12 +237,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { "{}", translate!("sync-error-no-such-file", "file" => f.quote()) ); - has_error = true; + set_exit_code(1); } } } - if has_error { + if get_exit_code() != 0 { return Err(USimpleError::new(1, "")); } From 5440fc53f8e6030fe6253311972440cb4399bf44 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Fri, 6 Feb 2026 22:58:45 +0800 Subject: [PATCH 4/5] remove thiserror dependency --- Cargo.lock | 1 - src/uu/sync/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36f01cd5c7d..489778c5a07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4172,7 +4172,6 @@ dependencies = [ "clap", "fluent", "nix", - "thiserror 2.0.18", "uucore", "windows-sys 0.61.2", ] diff --git a/src/uu/sync/Cargo.toml b/src/uu/sync/Cargo.toml index ec48121aa22..6d00339abb3 100644 --- a/src/uu/sync/Cargo.toml +++ b/src/uu/sync/Cargo.toml @@ -21,7 +21,6 @@ path = "src/sync.rs" clap = { workspace = true } uucore = { workspace = true, features = ["wide"] } fluent = { workspace = true } -thiserror = { workspace = true } [target.'cfg(unix)'.dependencies] nix = { workspace = true } From 315e3cdaf4f8c607f21c301b8a0cc45a254e7dee Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Sun, 8 Feb 2026 00:23:31 +0800 Subject: [PATCH 5/5] fix typo --- tests/by-util/test_sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/by-util/test_sync.rs b/tests/by-util/test_sync.rs index 8335f2eba73..8c09d86372a 100644 --- a/tests/by-util/test_sync.rs +++ b/tests/by-util/test_sync.rs @@ -174,6 +174,7 @@ fn test_sync_multiple_nonexistent_files() { result.stderr_contains("sync: error opening 'bad1': No such file or directory"); result.stderr_contains("sync: error opening 'bad2': No such file or directory"); +} #[cfg(any(target_os = "linux", target_os = "android"))] #[test]