Skip to content

Commit eadf572

Browse files
committed
refactor(mv): enhance error handling in ownership and permission preservation
- Capture return values from chown/lchown and set_permissions calls - Emit warnings for non-permission errors to inform users of preservation failures - Keep operations non-fatal as preservation is best-effort on Unix systems
1 parent 80c7d3e commit eadf572

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

src/uu/mv/src/mv.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,13 @@ fn is_fifo(_filetype: fs::FileType) -> bool {
817817
}
818818

819819
#[cfg(unix)]
820+
/// Best-effort ownership preservation for `to` using `from_meta`.
821+
///
822+
/// On Unix, this tries to set `uid`/`gid` on `to`. If `follow_symlinks` is
823+
/// true it uses `chown`, otherwise it uses `lchown` so the link itself (not its
824+
/// target) is updated. `chown`/`lchown` failures are non-fatal; permission
825+
/// errors are ignored, and other failures emit a warning because ownership
826+
/// preservation is optional.
820827
fn try_preserve_ownership(from_meta: &fs::Metadata, to: &Path, follow_symlinks: bool) {
821828
use std::ffi::CString;
822829
use std::os::unix::ffi::OsStrExt as _;
@@ -829,22 +836,43 @@ fn try_preserve_ownership(from_meta: &fs::Metadata, to: &Path, follow_symlinks:
829836
return;
830837
};
831838

832-
unsafe {
839+
let result = unsafe {
833840
if follow_symlinks {
834-
let _ = libc::chown(to_cstr.as_ptr(), uid, gid);
841+
libc::chown(to_cstr.as_ptr(), uid, gid)
835842
} else {
836-
let _ = libc::lchown(to_cstr.as_ptr(), uid, gid);
843+
libc::lchown(to_cstr.as_ptr(), uid, gid)
844+
}
845+
};
846+
if result != 0 {
847+
let err = io::Error::last_os_error();
848+
if err.kind() != io::ErrorKind::PermissionDenied {
849+
eprintln!(
850+
"mv: warning: failed to preserve ownership for {}: {err}",
851+
to.quote()
852+
);
837853
}
838854
}
839855
}
840856

841857
#[cfg(unix)]
858+
/// Best-effort permission preservation for `to` using `from_meta`.
859+
///
860+
/// Only the mode bits are applied (`chmod` does not accept file type bits).
861+
/// Failures are non-fatal; permission errors are ignored, and other failures
862+
/// emit a warning because this is optional.
842863
fn try_preserve_permissions(from_meta: &fs::Metadata, to: &Path) {
843864
use std::os::unix::fs::{MetadataExt as _, PermissionsExt as _};
844865

845866
// Keep mode bits only (file type bits are not allowed in chmod).
846867
let mode = from_meta.mode() & 0o7777;
847-
let _ = fs::set_permissions(to, fs::Permissions::from_mode(mode));
868+
if let Err(err) = fs::set_permissions(to, fs::Permissions::from_mode(mode)) {
869+
if err.kind() != io::ErrorKind::PermissionDenied {
870+
eprintln!(
871+
"mv: warning: failed to preserve permissions for {}: {err}",
872+
to.quote()
873+
);
874+
}
875+
}
848876
}
849877

850878
#[cfg(unix)]

0 commit comments

Comments
 (0)