From 824394a26a42a3ea1245116e5659f6d0d256f576 Mon Sep 17 00:00:00 2001 From: oech3 <79379754+oech3@users.noreply.github.com> Date: Mon, 26 Oct 2026 00:49:01 +0900 Subject: [PATCH] sync: support -d/--data on more platforms --- Cargo.toml | 2 +- src/uu/sync/locales/en-US.ftl | 2 +- src/uu/sync/locales/fr-FR.ftl | 2 +- src/uu/sync/src/sync.rs | 45 +++++++++++++++++++++++++++++------ 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6b646b58359..c1fe0510495 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -590,7 +590,7 @@ feat_Tier1 = [ ## (primary platforms) feature sets # "feat_wasm" == set of utilities which can be built for wasm target # We don't need to support all of wasm targets. So the ambiguous name is used at here -feat_wasm = ["feat_common_core", "nproc"] +feat_wasm = ["feat_common_core", "nproc", "sync"] # "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms. feat_os_unix = [ "feat_Tier1", diff --git a/src/uu/sync/locales/en-US.ftl b/src/uu/sync/locales/en-US.ftl index 272e5a822d2..a13c76250e2 100644 --- a/src/uu/sync/locales/en-US.ftl +++ b/src/uu/sync/locales/en-US.ftl @@ -3,7 +3,7 @@ sync-usage = sync [OPTION]... FILE... # Help messages sync-help-file-system = sync the file systems that contain the files (Linux and Windows only) -sync-help-data = sync only file data, no unneeded metadata (Linux only) +sync-help-data = sync only file data, no unneeded metadata # Error messages sync-error-data-needs-argument = --data needs at least one argument diff --git a/src/uu/sync/locales/fr-FR.ftl b/src/uu/sync/locales/fr-FR.ftl index 31c51aa4d6e..123ecdfb254 100644 --- a/src/uu/sync/locales/fr-FR.ftl +++ b/src/uu/sync/locales/fr-FR.ftl @@ -3,7 +3,7 @@ sync-usage = sync [OPTION]... FICHIER... # Messages d'aide sync-help-file-system = synchroniser les systèmes de fichiers qui contiennent les fichiers (Linux et Windows uniquement) -sync-help-data = synchroniser seulement les données des fichiers, pas les métadonnées inutiles (Linux uniquement) +sync-help-data = synchroniser seulement les données des fichiers, pas les métadonnées inutiles # Messages d'erreur sync-error-data-needs-argument = --data nécessite au moins un argument diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index 9339031d2fa..4f0b91e2f3e 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -18,12 +18,17 @@ pub mod options { static ARG_FILES: &str = "files"; -#[cfg(unix)] +#[cfg(not(windows))] mod platform { + #[cfg(unix)] use std::fs::{File, OpenOptions}; + #[cfg(unix)] use std::os::unix::fs::OpenOptionsExt; + #[cfg(unix)] use uucore::display::Quotable; + #[cfg(unix)] use uucore::error::FromIo; + #[cfg(unix)] use uucore::translate; use uucore::error::UResult; @@ -33,6 +38,8 @@ mod platform { reason = "fn sig must match on all platforms" )] pub fn do_sync() -> UResult<()> { + // maximize compatibility of scripts by noop on targets global sync is impossible + #[cfg(unix)] rustix::fs::sync(); Ok(()) } @@ -40,6 +47,7 @@ mod platform { /// Opens a file and resets its `O_NONBLOCK` flag to match GNU behavior. /// Returns the opened file or an error if opening fails. /// Logs a warning if fcntl fails but doesn't abort the operation. + #[cfg(unix)] fn open_and_reset_nonblock(path: &str) -> UResult { let f = OpenOptions::new() .read(true) @@ -57,6 +65,7 @@ mod platform { Ok(f) } + #[cfg(unix)] pub fn do_sync_with(files: &[String], op: F) -> UResult<()> where F: Fn(File) -> std::io::Result<()>, @@ -76,10 +85,6 @@ mod platform { rustix::fs::syncfs(f).map_err(std::io::Error::from) }) } - - pub fn do_fdatasync(files: &[String]) -> UResult<()> { - do_sync_with(files, |f| f.sync_data()) - } } #[cfg(windows)] @@ -248,7 +253,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { syncfs(&files)?; } } else if matches.get_flag(options::DATA) { - #[cfg(unix)] fdatasync(&files)?; } else { sync()?; @@ -297,5 +301,32 @@ fn syncfs(files: &[String]) -> UResult<()> { #[cfg(unix)] fn fdatasync(files: &[String]) -> UResult<()> { - platform::do_fdatasync(files) + platform::do_sync_with(files, |f| f.sync_data()) +} + +#[cfg(not(unix))] +fn fdatasync(files: &[String]) -> UResult<()> { + do_sync_with_regular_file(files, |f| f.sync_data()) +} + +#[cfg(not(unix))] +fn do_sync_with_regular_file(files: &[String], op: F) -> UResult<()> +where + F: Fn(std::fs::File) -> std::io::Result<()>, +{ + #[cfg(windows)] + use std::os::windows::fs::OpenOptionsExt as _; + use uucore::error::FromIo; + for path in files { + let mut f = std::fs::OpenOptions::new(); + f.read(true); + #[cfg(windows)] + f.write(true); + // allow opening directory + #[cfg(windows)] + f.custom_flags(windows_sys::Win32::Storage::FileSystem::FILE_FLAG_BACKUP_SEMANTICS); + op(f.open(path)?) + .map_err_context(|| translate!("sync-error-syncing-file", "file" => path.quote()))?; + } + Ok(()) }