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