Skip to content

Commit fafa775

Browse files
sync: open file with nonblock (#10765)
* open file with nonblock and add test * fix spellcheck * remove libc dependency; improve errors --------- Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
1 parent 5648194 commit fafa775

File tree

4 files changed

+39
-4
lines changed

4 files changed

+39
-4
lines changed

src/uu/sync/locales/en-US.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ sync-help-data = sync only file data, no unneeded metadata (Linux only)
99
sync-error-data-needs-argument = --data needs at least one argument
1010
sync-error-opening-file = error opening { $file }
1111
sync-error-no-such-file = error opening { $file }: No such file or directory
12+
sync-error-syncing-file = error syncing { $file }
1213
1314
# Warning messages
1415
sync-warning-fcntl-failed = warning: failed to reset O_NONBLOCK flag for { $file }: { $error }

src/uu/sync/locales/fr-FR.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ sync-help-data = synchroniser seulement les données des fichiers, pas les méta
99
sync-error-data-needs-argument = --data nécessite au moins un argument
1010
sync-error-opening-file = erreur lors de l'ouverture de { $file }
1111
sync-error-no-such-file = erreur lors de l'ouverture de { $file } : Aucun fichier ou répertoire de ce type
12+
sync-error-syncing-file = erreur lors de la synchronisation de { $file }
1213
1314
# Messages d'avertissement
1415
sync-warning-fcntl-failed = avertissement : échec de la réinitialisation du drapeau O_NONBLOCK pour { $file } : { $error }

src/uu/sync/src/sync.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ mod platform {
3535
#[cfg(any(target_os = "linux", target_os = "android"))]
3636
use nix::unistd::{fdatasync, syncfs};
3737
#[cfg(any(target_os = "linux", target_os = "android"))]
38-
use std::fs::File;
38+
use std::fs::{File, OpenOptions};
39+
#[cfg(any(target_os = "linux", target_os = "android"))]
40+
use std::os::unix::fs::OpenOptionsExt;
41+
#[cfg(any(target_os = "linux", target_os = "android"))]
42+
use uucore::display::Quotable;
3943
#[cfg(any(target_os = "linux", target_os = "android"))]
4044
use uucore::error::FromIo;
4145
#[cfg(any(target_os = "linux", target_os = "android"))]
@@ -57,7 +61,11 @@ mod platform {
5761
/// Logs a warning if fcntl fails but doesn't abort the operation.
5862
#[cfg(any(target_os = "linux", target_os = "android"))]
5963
fn open_and_reset_nonblock(path: &str) -> UResult<File> {
60-
let f = File::open(path).map_err_context(|| path.to_string())?;
64+
let f = OpenOptions::new()
65+
.read(true)
66+
.custom_flags(OFlag::O_NONBLOCK.bits())
67+
.open(path)
68+
.map_err_context(|| path.to_string())?;
6169
// Reset O_NONBLOCK flag if it was set (matches GNU behavior)
6270
// This is non-critical, so we log errors but don't fail
6371
if let Err(e) = fcntl(&f, FcntlArg::F_SETFL(OFlag::empty())) {
@@ -73,7 +81,9 @@ mod platform {
7381
pub fn do_syncfs(files: Vec<String>) -> UResult<()> {
7482
for path in files {
7583
let f = open_and_reset_nonblock(&path)?;
76-
syncfs(f)?;
84+
syncfs(f).map_err_context(
85+
|| translate!("sync-error-syncing-file", "file" => path.quote()),
86+
)?;
7787
}
7888
Ok(())
7989
}
@@ -82,7 +92,9 @@ mod platform {
8292
pub fn do_fdatasync(files: Vec<String>) -> UResult<()> {
8393
for path in files {
8494
let f = open_and_reset_nonblock(&path)?;
85-
fdatasync(f)?;
95+
fdatasync(f).map_err_context(
96+
|| translate!("sync-error-syncing-file", "file" => path.quote()),
97+
)?;
8698
}
8799
Ok(())
88100
}

tests/by-util/test_sync.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,24 @@ fn test_sync_multiple_files() {
167167
// Sync both files
168168
new_ucmd!().arg("--data").arg(&file1).arg(&file2).succeeds();
169169
}
170+
171+
#[cfg(any(target_os = "linux", target_os = "android"))]
172+
#[test]
173+
fn test_sync_data_fifo_fails_immediately() {
174+
use std::time::Duration;
175+
use uutests::util::TestScenario;
176+
use uutests::util_name;
177+
178+
let ts = TestScenario::new(util_name!());
179+
let at = &ts.fixtures;
180+
at.mkfifo("test-fifo");
181+
182+
ts.ucmd()
183+
.arg("--data")
184+
.arg(at.plus_as_string("test-fifo"))
185+
.timeout(Duration::from_secs(2))
186+
.fails()
187+
.stderr_contains("error syncing")
188+
.stderr_contains("test-fifo")
189+
.stderr_contains("Invalid input");
190+
}

0 commit comments

Comments
 (0)