From 8c45737007db0719a08bd899bdab227d0f355634 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 24 Jul 2025 17:47:32 +0800 Subject: [PATCH] cp: Try to change gid only if changing uid+gid fails For example, if a file with ownership `root:wheel` is copied with `-p`, we expect the copy to have ownership `$USER:wheel` (assuming `$USER` is part of `wheel` group) It's not possible to add a unit test for this, as it requires a file with non-$USER ownership, which can only be created by root (or another user). --- src/uu/cp/src/cp.rs | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 7cf409ff284..770c558ff67 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1708,20 +1708,30 @@ pub(crate) fn copy_attributes( let dest_uid = source_metadata.uid(); let dest_gid = source_metadata.gid(); - // gnu compatibility: cp doesn't report an error if it fails to set the ownership. - let _ = wrap_chown( - dest, - &dest - .symlink_metadata() - .map_err(|e| CpError::IoErrContext(e, context.to_owned()))?, - Some(dest_uid), - Some(dest_gid), - false, - Verbosity { - groups_only: false, - level: VerbosityLevel::Silent, - }, - ); + let meta = &dest + .symlink_metadata() + .map_err(|e| CpError::IoErrContext(e, context.to_owned()))?; + + let try_chown = { + |uid| { + wrap_chown( + dest, + meta, + uid, + Some(dest_gid), + false, + Verbosity { + groups_only: false, + level: VerbosityLevel::Silent, + }, + ) + } + }; + // gnu compatibility: cp doesn't report an error if it fails to set the ownership, + // and will fall back to changing only the gid if possible. + if try_chown(Some(dest_uid)).is_err() { + let _ = try_chown(None); + } Ok(()) })?;