Fixes bug#40706
xcopy should remove read only permissions from the destination file unless the /k option is supplied.
Signed-off-by: Jason Edmeades us@edmeades.me.uk --- programs/xcopy/tests/xcopy.c | 25 +++++++++++++++++++++++++ programs/xcopy/xcopy.c | 25 ++++++++++++++++++------- programs/xcopy/xcopy.h | 1 + programs/xcopy/xcopy.rc | 1 + 4 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/programs/xcopy/tests/xcopy.c b/programs/xcopy/tests/xcopy.c index 94cede6f67..17b4406b74 100644 --- a/programs/xcopy/tests/xcopy.c +++ b/programs/xcopy/tests/xcopy.c @@ -108,6 +108,30 @@ static void test_parms_syntax(void) RemoveDirectoryA("xcopytest2"); }
+static void test_keep_attributes(void) +{ + DWORD rc; + + SetFileAttributesA("xcopy1", FILE_ATTRIBUTE_READONLY); + + rc = runcmd("xcopy xcopy1 xcopytest"); + ok(rc == 0, "xcopy failed to copy read only file\n"); + ok((GetFileAttributesA("xcopytest\xcopy1") & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY, + "xcopy should not have copied file permissions\n"); + SetFileAttributesA("xcopytest\xcopy1", FILE_ATTRIBUTE_NORMAL); + DeleteFileA("xcopytest\xcopy1"); + + rc = runcmd("xcopy /K xcopy1 xcopytest"); + ok(rc == 0, "xcopy failed to copy read only file with /k\n"); + ok((GetFileAttributesA("xcopytest\xcopy1") & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY, + "xcopy did not keep file permissions\n"); + SetFileAttributesA("xcopytest\xcopy1", FILE_ATTRIBUTE_NORMAL); + DeleteFileA("xcopytest\xcopy1"); + + SetFileAttributesA("xcopy1", FILE_ATTRIBUTE_NORMAL); + + } + START_TEST(xcopy) { char tmpdir[MAX_PATH]; @@ -130,6 +154,7 @@ START_TEST(xcopy)
test_date_format(); test_parms_syntax(); + test_keep_attributes();
DeleteFileA("xcopy1"); RemoveDirectoryA("xcopytest"); diff --git a/programs/xcopy/xcopy.c b/programs/xcopy/xcopy.c index e380cde226..cdf0bdfb26 100644 --- a/programs/xcopy/xcopy.c +++ b/programs/xcopy/xcopy.c @@ -570,15 +570,25 @@ static int XCOPY_DoCopy(WCHAR *srcstem, WCHAR *srcspec, ret = RC_WRITEERROR; goto cleanup; } - } + } else {
- /* If /M supplied, remove the archive bit after successful copy */ - if (!skipFile) { - if ((srcAttribs & FILE_ATTRIBUTE_ARCHIVE) && - (flags & OPT_REMOVEARCH)) { - SetFileAttributesW(copyFrom, (srcAttribs & ~FILE_ATTRIBUTE_ARCHIVE)); + if (!skipFile) { + /* If keeping attributes, update the destination attributes + otherwise remove the read only attribute */ + if (flags & OPT_KEEPATTRS) { + SetFileAttributesW(copyTo, srcAttribs | FILE_ATTRIBUTE_ARCHIVE); + } else { + SetFileAttributesW(copyTo, + (GetFileAttributesW(copyTo) & ~FILE_ATTRIBUTE_READONLY)); + } + + /* If /M supplied, remove the archive bit after successful copy */ + if ((srcAttribs & FILE_ATTRIBUTE_ARCHIVE) && + (flags & OPT_REMOVEARCH)) { + SetFileAttributesW(copyFrom, (srcAttribs & ~FILE_ATTRIBUTE_ARCHIVE)); + } + filesCopied++; } - filesCopied++; } } } @@ -764,6 +774,7 @@ static int XCOPY_ParseCommandLine(WCHAR *suppliedsource, case 'N': flags |= OPT_SHORTNAME; break; case 'U': flags |= OPT_MUSTEXIST; break; case 'R': flags |= OPT_REPLACEREAD; break; + case 'K': flags |= OPT_KEEPATTRS; break; case 'H': flags |= OPT_COPYHIDSYS; break; case 'C': flags |= OPT_IGNOREERRORS; break; case 'P': flags |= OPT_SRCPROMPT; break; diff --git a/programs/xcopy/xcopy.h b/programs/xcopy/xcopy.h index 3e9644efe8..9c6ee1176f 100644 --- a/programs/xcopy/xcopy.h +++ b/programs/xcopy/xcopy.h @@ -48,6 +48,7 @@ #define OPT_EXCLUDELIST 0x00020000 #define OPT_DATERANGE 0x00040000 #define OPT_DATENEWER 0x00080000 +#define OPT_KEEPATTRS 0x00100000
#define MAXSTRING 8192
diff --git a/programs/xcopy/xcopy.rc b/programs/xcopy/xcopy.rc index fac3519175..e303f35bdd 100644 --- a/programs/xcopy/xcopy.rc +++ b/programs/xcopy/xcopy.rc @@ -74,6 +74,7 @@ Where:\n\ [/A] Only copy files with archive attribute set.\n\ [/M] Only copy files with archive attribute set, removes the\n\ \tarchive attribute.\n\ +[/K] Copy file attributes, without this attributes are not preserved.\n\ [/D | /D:m-d-y] Copy new files or those modified after the supplied date.\n\ \t\tIf no date is supplied, only copy if destination is older\n\ \t\tthan source.\n\n"