1 /* 2 * Copyright 2013 Francois Gouget 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include <windows.h> 20 21 #include "wine/test.h" 22 23 24 static DWORD runcmd(const char* cmd) 25 { 26 STARTUPINFOA si = {sizeof(STARTUPINFOA)}; 27 PROCESS_INFORMATION pi; 28 char* wcmd; 29 DWORD rc; 30 31 /* Create a writable copy for CreateProcessA() */ 32 wcmd = HeapAlloc(GetProcessHeap(), 0, strlen(cmd) + 1); 33 strcpy(wcmd, cmd); 34 35 /* On Windows 2003 and older, xcopy.exe fails if stdin is not a console 36 * handle, even with '/I /Y' options. 37 */ 38 rc = CreateProcessA(NULL, wcmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); 39 HeapFree(GetProcessHeap(), 0, wcmd); 40 if (!rc) 41 return 260; 42 43 rc = WaitForSingleObject(pi.hProcess, 5000); 44 if (rc == WAIT_OBJECT_0) 45 GetExitCodeProcess(pi.hProcess, &rc); 46 else 47 TerminateProcess(pi.hProcess, 1); 48 CloseHandle(pi.hThread); 49 CloseHandle(pi.hProcess); 50 51 return rc; 52 } 53 54 static void test_date_format(void) 55 { 56 DWORD rc; 57 58 rc = runcmd("xcopy /D:20-01-2000 xcopy1 xcopytest"); 59 ok(rc == 4, "xcopy /D:d-m-y test returned rc=%u\n", rc); 60 ok(GetFileAttributesA("xcopytest\\xcopy1") == INVALID_FILE_ATTRIBUTES, 61 "xcopy should not have created xcopytest\\xcopy1\n"); 62 63 rc = runcmd("xcopy /D:01-20-2000 xcopy1 xcopytest"); 64 ok(rc == 0, "xcopy /D:m-d-y test failed rc=%u\n", rc); 65 ok(GetFileAttributesA("xcopytest\\xcopy1") != INVALID_FILE_ATTRIBUTES, 66 "xcopy did not create xcopytest\\xcopy1\n"); 67 DeleteFileA("xcopytest\\xcopy1"); 68 69 rc = runcmd("xcopy /D:1-20-2000 xcopy1 xcopytest"); 70 ok(rc == 0, "xcopy /D:m-d-y test failed rc=%u\n", rc); 71 ok(GetFileAttributesA("xcopytest\\xcopy1") != INVALID_FILE_ATTRIBUTES, 72 "xcopy did not create xcopytest\\xcopy1\n"); 73 DeleteFileA("xcopytest\\xcopy1"); 74 } 75 76 static void test_parms_syntax(void) 77 { 78 DWORD rc; 79 80 rc = runcmd("xcopy /H/D:20-01-2000 xcopy1 xcopytest"); 81 ok(rc == 4, "xcopy /H/D:d-m-y test returned rc=%u\n", rc); 82 ok(GetFileAttributesA("xcopytest\\xcopy1") == INVALID_FILE_ATTRIBUTES, 83 "xcopy should not have created xcopytest\\xcopy1\n"); 84 85 rc = runcmd("xcopy /D:01-20-2000/H xcopy1 xcopytest"); 86 ok(rc == 0, "xcopy /H/D:m-d-y test failed rc=%u\n", rc); 87 ok(GetFileAttributesA("xcopytest\\xcopy1") != INVALID_FILE_ATTRIBUTES, 88 "xcopy did not create xcopytest\\xcopy1\n"); 89 DeleteFileA("xcopytest\\xcopy1"); 90 91 /* The following test is commented out as under wine it generates 92 a recursively deep directory tree (todo_wine) 93 rc = runcmd("xcopy /D:1-20-2000/E xcopy1 xcopytest"); 94 ok(rc == 0, "xcopy /D:m-d-y/E test failed rc=%u\n", rc); 95 ok(GetFileAttributesA("xcopytest\\xcopy1") != INVALID_FILE_ATTRIBUTES, 96 "xcopy did not create xcopytest\\xcopy1\n"); 97 DeleteFileA("xcopytest\\xcopy1"); */ 98 99 rc = runcmd("xcopy /D/S xcopytest xcopytest2\\"); 100 ok(rc == 0, "xcopy /D/S test failed rc=%u\n", rc); 101 ok(GetFileAttributesA("xcopytest2") == INVALID_FILE_ATTRIBUTES, 102 "xcopy copied empty directory incorrectly\n"); 103 104 rc = runcmd("xcopy /D/S/E xcopytest xcopytest2\\"); 105 ok(rc == 0, "xcopy /D/S/E test failed rc=%u\n", rc); 106 ok(GetFileAttributesA("xcopytest2") != INVALID_FILE_ATTRIBUTES, 107 "xcopy failed to copy empty directory\n"); 108 RemoveDirectoryA("xcopytest2"); 109 } 110 111 static void test_keep_attributes(void) 112 { 113 DWORD rc; 114 115 SetFileAttributesA("xcopy1", FILE_ATTRIBUTE_READONLY); 116 117 rc = runcmd("xcopy xcopy1 xcopytest"); 118 ok(rc == 0, "xcopy failed to copy read only file\n"); 119 ok((GetFileAttributesA("xcopytest\\xcopy1") & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY, 120 "xcopy should not have copied file permissions\n"); 121 SetFileAttributesA("xcopytest\\xcopy1", FILE_ATTRIBUTE_NORMAL); 122 DeleteFileA("xcopytest\\xcopy1"); 123 124 rc = runcmd("xcopy /K xcopy1 xcopytest"); 125 ok(rc == 0, "xcopy failed to copy read only file with /k\n"); 126 ok((GetFileAttributesA("xcopytest\\xcopy1") & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY, 127 "xcopy did not keep file permissions\n"); 128 SetFileAttributesA("xcopytest\\xcopy1", FILE_ATTRIBUTE_NORMAL); 129 DeleteFileA("xcopytest\\xcopy1"); 130 131 SetFileAttributesA("xcopy1", FILE_ATTRIBUTE_NORMAL); 132 133 } 134 135 START_TEST(xcopy) 136 { 137 char tmpdir[MAX_PATH]; 138 HANDLE hfile; 139 140 GetTempPathA(MAX_PATH, tmpdir); 141 SetCurrentDirectoryA(tmpdir); 142 trace("%s\n", tmpdir); 143 144 CreateDirectoryA("xcopytest", NULL); 145 hfile = CreateFileA("xcopy1", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 146 FILE_ATTRIBUTE_NORMAL, NULL); 147 ok(hfile != INVALID_HANDLE_VALUE, "Failed to create xcopy1 file\n"); 148 if (hfile == INVALID_HANDLE_VALUE) 149 { 150 skip("skipping xcopy tests\n"); 151 return; 152 } 153 CloseHandle(hfile); 154 155 test_date_format(); 156 test_parms_syntax(); 157 test_keep_attributes(); 158 159 DeleteFileA("xcopy1"); 160 RemoveDirectoryA("xcopytest"); 161 } 162