[PATCH 4/4] [programs\xcopy] Add support for xcopy /k

Jason Edmeades us at edmeades.me.uk
Wed Jul 4 16:08:41 CDT 2018


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 at 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"
-- 
2.17.1




More information about the wine-devel mailing list