1 /*
2  * CopyFile, MoveFile and related routines test
3  */
4 
5 #include <ctype.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <tchar.h>
9 #include <windows.h>
10 
11 static TCHAR
12 FindOtherDrive()
13 {
14 	DWORD drives = GetLogicalDrives();
15 	BOOL found = FALSE;
16 	TCHAR drive;
17 	TCHAR rootdir[] = _T( "?:\\" );
18 	TCHAR currentdir[MAX_PATH + 1];
19 
20 	if (0 != GetCurrentDirectory(MAX_PATH + 1, currentdir)) {
21 		for (drive = _T('A'); ! found && drive <= _T('Z'); drive++) {
22 			if (0 != (drives & (1 << (drive - _T('A'))))&&
23 			    drive != _totupper(currentdir[0])) {
24 				rootdir[0] = drive;
25 				found = (DRIVE_FIXED == GetDriveType(rootdir));
26 			}
27 		}
28 	}
29 
30 	return found ? drive - 1 : _T( ' ' );
31 }
32 
33 static void
34 DeleteTestFile(LPCTSTR filename)
35 {
36 	SetFileAttributes(filename, FILE_ATTRIBUTE_NORMAL);
37 	DeleteFile(filename);
38 }
39 
40 static void
41 CreateTestFile(LPCTSTR filename, DWORD attributes)
42 {
43 	HANDLE file;
44 	char buffer[4096];
45 	DWORD wrote;
46 	int c;
47 
48 	DeleteTestFile(filename);
49 	file = CreateFile(filename,
50 	                  GENERIC_READ | GENERIC_WRITE,
51 	                  0,
52 	                  NULL,
53 	                  CREATE_ALWAYS,
54 	                  0,
55 	                  0);
56 
57 	if (INVALID_HANDLE_VALUE == file) {
58 		fprintf(stderr, "CreateFile failed with code %lu\n", GetLastError());
59 		exit(1);
60 	}
61 	for(c = 0; c < sizeof(buffer); c++) {
62 		buffer[c] = (char) c;
63 	}
64 	if (! WriteFile(file, buffer, sizeof(buffer), &wrote, NULL)) {
65 		fprintf(stderr, "WriteFile failed with code %lu\n", GetLastError());
66 		exit(1);
67 	}
68 	CloseHandle(file);
69 
70 	if (! SetFileAttributes(filename, attributes)) {
71 		fprintf(stderr, "SetFileAttributes failed with code %lu\n", GetLastError());
72 		exit(1);
73 	}
74 }
75 
76 static void
77 DeleteTestDir(LPCTSTR dirname)
78 {
79 	RemoveDirectory(dirname);
80 }
81 
82 static void
83 CreateTestDir(LPCTSTR dirname)
84 {
85 	if (! CreateDirectory(dirname, NULL)) {
86 		fprintf(stderr, "CreateDirectory failed with code %lu\n", GetLastError());
87 		exit(1);
88 	}
89 }
90 
91 static void
92 CheckTestFile(LPCTSTR filename, DWORD attributes)
93 {
94 	HANDLE file;
95 	char buffer[4096];
96 	DWORD read;
97 	int c;
98 	DWORD diskattr;
99 
100 	file = CreateFile(filename,
101 	                  GENERIC_READ,
102 	                  0,
103 	                  NULL,
104 	                  OPEN_EXISTING,
105 	                  0,
106 	                  0);
107 
108 	if (INVALID_HANDLE_VALUE == file) {
109 		fprintf(stderr, "CreateFile failed with code %lu\n", GetLastError());
110 		exit(1);
111 	}
112 
113 	if (! ReadFile(file, buffer, sizeof(buffer), &read, NULL)) {
114 		fprintf(stderr, "ReadFile failed with code %lu\n", GetLastError());
115 		exit(1);
116 	}
117 	if (read != sizeof(buffer)) {
118 		fprintf(stderr, "Trying to read %u bytes but got %lu bytes\n", sizeof(buffer), read);
119 		exit(1);
120 	}
121 	for(c = 0; c < sizeof(buffer); c++) {
122 		if (buffer[c] != (char) c) {
123 			fprintf(stderr, "File contents changed at position %u\n", c);
124 			exit(1);
125 		}
126 	}
127 
128 	CloseHandle(file);
129 
130 	diskattr = GetFileAttributes(filename);
131 	if (INVALID_FILE_ATTRIBUTES == diskattr) {
132 		fprintf(stderr, "GetFileAttributes failed with code %lu\n", GetLastError());
133 		exit(1);
134 	}
135 	if (diskattr != attributes) {
136 		fprintf(stderr, "Attribute mismatch, expected 0x%08lx found 0x%08lx\n", attributes, diskattr);
137 		exit(1);
138 	}
139 }
140 
141 int
142 main(int argc, char *argv[])
143 {
144 	TCHAR otherdrive;
145 	TCHAR otherfile[ ] = _T("?:\\other.dat");
146 
147 	otherdrive = FindOtherDrive();
148 
149 	printf("Testing simple move\n");
150 	CreateTestFile(_T("begin.dat"), FILE_ATTRIBUTE_ARCHIVE);
151 	DeleteTestFile(_T("end.dat"));
152 	if (! MoveFile(_T("begin.dat"), _T("end.dat"))) {
153 		fprintf(stderr, "MoveFile failed with code %lu\n", GetLastError());
154 		exit(1);
155 	}
156 	CheckTestFile(_T("end.dat"), FILE_ATTRIBUTE_ARCHIVE);
157 	DeleteTestFile(_T("end.dat"));
158 
159 	printf("Testing move of non-existing file\n");
160 	DeleteTestFile(_T("begin.dat"));
161 	DeleteTestFile(_T("end.dat"));
162 	if (MoveFile(_T("begin.dat"), _T("end.dat"))) {
163 		fprintf(stderr, "MoveFile succeeded but shouldn't have\n");
164 		exit(1);
165 	} else if (ERROR_FILE_NOT_FOUND != GetLastError()) {
166 		fprintf(stderr, "MoveFile failed with unexpected code %lu\n", GetLastError());
167 		exit(1);
168 	}
169 	DeleteTestFile(_T("end.dat"));
170 
171 /* Not correctly implemented in ros, destination file is kept open after this */
172 #if 0
173 	printf("Testing move to existing file\n");
174 	CreateTestFile(_T("begin.dat"), FILE_ATTRIBUTE_ARCHIVE);
175 	CreateTestFile(_T("end.dat"), FILE_ATTRIBUTE_ARCHIVE);
176 	if (MoveFile(_T("begin.dat"), _T("end.dat"))) {
177 		fprintf(stderr, "MoveFile succeeded but shouldn't have\n");
178 		exit(1);
179 	} else if (ERROR_ALREADY_EXISTS != GetLastError()) {
180 		fprintf(stderr, "MoveFile failed with unexpected code %lu\n", GetLastError());
181 		exit(1);
182 	}
183 	DeleteTestFile(_T("begin.dat"));
184 	DeleteTestFile(_T("end.dat"));
185 #endif
186 
187 /* Not implemented yet in ros */
188 #if 0
189 	printf("Testing directory move\n");
190 	CreateTestDir(_T("begin"));
191 	CreateTestFile(_T("begin\\file.dat"), FILE_ATTRIBUTE_NORMAL);
192 	DeleteTestDir(_T("end"));
193 	if (! MoveFile(_T("begin"), _T("end"))) {
194 		fprintf(stderr, "MoveFile failed with code %lu\n", GetLastError());
195 		exit(1);
196 	}
197 	CheckTestFile(_T("end\\file.dat"), FILE_ATTRIBUTE_NORMAL);
198 	DeleteTestFile(_T("end\\file.dat"));
199 	DeleteTestDir(_T("end"));
200 #endif
201 
202 	printf("Testing file move to different directory\n");
203 	CreateTestFile(_T("file.dat"), FILE_ATTRIBUTE_NORMAL);
204 	CreateTestDir(_T("end"));
205 	if (! MoveFile(_T("file.dat"), _T("end\\file.dat"))) {
206 		fprintf(stderr, "MoveFile failed with code %lu\n", GetLastError());
207 		exit(1);
208 	}
209 	CheckTestFile(_T("end\\file.dat"), FILE_ATTRIBUTE_ARCHIVE);
210 	DeleteTestFile(_T("end\\file.dat"));
211 	DeleteTestDir(_T("end"));
212 
213 	printf("Testing move of read-only file\n");
214 	CreateTestFile(_T("begin.dat"), FILE_ATTRIBUTE_READONLY);
215 	DeleteTestFile(_T("end.dat"));
216 	if (! MoveFile(_T("begin.dat"), _T("end.dat"))) {
217 		fprintf(stderr, "MoveFile failed with code %lu\n", GetLastError());
218 		exit(1);
219 	}
220 	CheckTestFile(_T("end.dat"), FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY);
221 	DeleteTestFile(_T("end.dat"));
222 
223 	printf("Testing move to different drive\n");
224 	if (_T(' ') != otherdrive) {
225 		otherfile[0] = otherdrive;
226 		CreateTestFile(_T("begin.dat"), FILE_ATTRIBUTE_ARCHIVE);
227 		DeleteTestFile(otherfile);
228 		if (! MoveFile(_T("begin.dat"), otherfile)) {
229 			fprintf(stderr, "MoveFile failed with code %lu\n", GetLastError());
230 			exit(1);
231 		}
232 		CheckTestFile(otherfile, FILE_ATTRIBUTE_ARCHIVE);
233 		DeleteTestFile(otherfile);
234 	} else {
235 		printf("  Test skipped, no other drive available\n");
236 	}
237 
238 	printf("Testing move/overwrite of existing file\n");
239 	CreateTestFile(_T("begin.dat"), FILE_ATTRIBUTE_ARCHIVE);
240 	CreateTestFile(_T("end.dat"), FILE_ATTRIBUTE_ARCHIVE);
241 	if (! MoveFileEx(_T("begin.dat"), _T("end.dat"), MOVEFILE_REPLACE_EXISTING)) {
242 		fprintf(stderr, "MoveFileEx failed with code %lu\n", GetLastError());
243 		exit(1);
244 	}
245 	DeleteTestFile(_T("begin.dat"));
246 	DeleteTestFile(_T("end.dat"));
247 
248 /* Not (correctly) implemented in ros yet */
249 #if 0
250 	printf("Testing move/overwrite of existing readonly file\n");
251 	CreateTestFile(_T("begin.dat"), FILE_ATTRIBUTE_ARCHIVE);
252 	CreateTestFile(_T("end.dat"), FILE_ATTRIBUTE_READONLY);
253 	if (MoveFileEx(_T("begin.dat"), _T("end.dat"), MOVEFILE_REPLACE_EXISTING)) {
254 		fprintf(stderr, "MoveFileEx succeeded but shouldn't have\n");
255 		exit(1);
256 	} else if (ERROR_ALREADY_EXISTS != GetLastError() &&
257 	           ERROR_ACCESS_DENIED != GetLastError()) {
258 		fprintf(stderr, "MoveFileEx failed with unexpected code %lu\n", GetLastError());
259 		exit(1);
260 	}
261 	DeleteTestFile(_T("begin.dat"));
262 	DeleteTestFile(_T("end.dat"));
263 #endif
264 
265 /* Not implemented in ros yet */
266 #if 0
267 	printf("Testing move to different drive without COPY_ALLOWED\n");
268 	if (_T(' ') != otherdrive) {
269 		otherfile[0] = otherdrive;
270 		CreateTestFile(_T("begin.dat"), FILE_ATTRIBUTE_ARCHIVE);
271 		DeleteTestFile(otherfile);
272 		if (MoveFileEx(_T("begin.dat"), otherfile, 0)) {
273 			fprintf(stderr, "MoveFileEx succeeded but shouldn't have\n");
274 			exit(1);
275 		} else if (ERROR_NOT_SAME_DEVICE != GetLastError()) {
276 			fprintf(stderr, "MoveFileEx failed with unexpected code %lu\n", GetLastError());
277 			exit(1);
278 		}
279 		DeleteTestFile(otherfile);
280 	} else {
281 		printf("  Test skipped, no other drive available\n");
282 	}
283 #endif
284 
285 	printf("Testing move to different drive with COPY_ALLOWED\n");
286 	if (_T(' ') != otherdrive) {
287 		otherfile[0] = otherdrive;
288 		CreateTestFile(_T("begin.dat"), FILE_ATTRIBUTE_ARCHIVE);
289 		DeleteTestFile(otherfile);
290 		if (! MoveFileEx(_T("begin.dat"), otherfile, MOVEFILE_COPY_ALLOWED)) {
291 			fprintf(stderr, "MoveFileEx failed with code %lu\n", GetLastError());
292 			exit(1);
293 		}
294 		CheckTestFile(otherfile, FILE_ATTRIBUTE_ARCHIVE);
295 		DeleteTestFile(otherfile);
296 	} else {
297 		printf("  Test skipped, no other drive available\n");
298 	}
299 
300 	printf("All tests successfully completed\n");
301 
302 	return 0;
303 }
304