kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / advpack / tests / files.c
1 /*
2  * Unit tests for advpack.dll file functions
3  *
4  * Copyright (C) 2006 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdio.h>
22 #include <windows.h>
23 #include <advpub.h>
24 #include <fci.h>
25 #include "wine/test.h"
26
27 /* make the max size large so there is only one cab file */
28 #define MEDIA_SIZE          999999999
29 #define FOLDER_THRESHOLD    900000
30
31 /* function pointers */
32 HMODULE hAdvPack;
33 static HRESULT (WINAPI *pExtractFiles)(LPCSTR, LPCSTR, DWORD, LPCSTR, LPVOID, DWORD);
34 static HRESULT (WINAPI *pAdvInstallFile)(HWND,LPCSTR,LPCSTR,LPCSTR,LPCSTR,DWORD,DWORD);
35
36 CHAR CURR_DIR[MAX_PATH];
37
38 static void init_function_pointers()
39 {
40     hAdvPack = LoadLibraryA("advpack.dll");
41
42     if (hAdvPack)
43     {
44         pExtractFiles = (void *)GetProcAddress(hAdvPack, "ExtractFiles");
45         pAdvInstallFile = (void*)GetProcAddress(hAdvPack, "AdvInstallFile");
46     }
47 }
48
49 /* creates a file with the specified name for tests */
50 static void createTestFile(const CHAR *name)
51 {
52     HANDLE file;
53     DWORD written;
54
55     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
56     ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
57     WriteFile(file, name, strlen(name), &written, NULL);
58     WriteFile(file, "\n", strlen("\n"), &written, NULL);
59     CloseHandle(file);
60 }
61
62 static void create_test_files()
63 {
64     int len;
65
66     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
67     len = lstrlenA(CURR_DIR);
68
69     if(len && (CURR_DIR[len-1] == '\\'))
70         CURR_DIR[len-1] = 0;
71
72     createTestFile("a.txt");
73     createTestFile("b.txt");
74     CreateDirectoryA("testdir", NULL);
75     createTestFile("testdir\\c.txt");
76     createTestFile("testdir\\d.txt");
77     CreateDirectoryA("dest", NULL);
78 }
79
80 static void delete_test_files()
81 {
82     DeleteFileA("a.txt");
83     DeleteFileA("b.txt");
84     DeleteFileA("testdir\\c.txt");
85     DeleteFileA("testdir\\d.txt");
86     RemoveDirectoryA("testdir");
87     RemoveDirectoryA("dest");
88
89     DeleteFileA("extract.cab");
90 }
91
92 /* the FCI callbacks */
93
94 static void *mem_alloc(ULONG cb)
95 {
96     return HeapAlloc(GetProcessHeap(), 0, cb);
97 }
98
99 static void mem_free(void *memory)
100 {
101     HeapFree(GetProcessHeap(), 0, memory);
102 }
103
104 static BOOL get_next_cabinet(PCCAB pccab, ULONG  cbPrevCab, void *pv)
105 {
106     return TRUE;
107 }
108
109 static long progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv)
110 {
111     return 0;
112 }
113
114 static int file_placed(PCCAB pccab, char *pszFile, long cbFile,
115                        BOOL fContinuation, void *pv)
116 {
117     return 0;
118 }
119
120 static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv)
121 {
122     HANDLE handle;
123     DWORD dwAccess = 0;
124     DWORD dwShareMode = 0;
125     DWORD dwCreateDisposition = OPEN_EXISTING;
126     
127     dwAccess = GENERIC_READ | GENERIC_WRITE;
128     dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
129
130     if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
131         dwCreateDisposition = OPEN_EXISTING;
132     else
133         dwCreateDisposition = CREATE_NEW;
134
135     handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
136                          dwCreateDisposition, 0, NULL);
137
138     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszFile);
139
140     return (INT_PTR)handle;
141 }
142
143 static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
144 {
145     HANDLE handle = (HANDLE)hf;
146     DWORD dwRead;
147     BOOL res;
148     
149     res = ReadFile(handle, memory, cb, &dwRead, NULL);
150     ok(res, "Failed to ReadFile\n");
151
152     return dwRead;
153 }
154
155 static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
156 {
157     HANDLE handle = (HANDLE)hf;
158     DWORD dwWritten;
159     BOOL res;
160
161     res = WriteFile(handle, memory, cb, &dwWritten, NULL);
162     ok(res, "Failed to WriteFile\n");
163
164     return dwWritten;
165 }
166
167 static int fci_close(INT_PTR hf, int *err, void *pv)
168 {
169     HANDLE handle = (HANDLE)hf;
170     ok(CloseHandle(handle), "Failed to CloseHandle\n");
171
172     return 0;
173 }
174
175 static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv)
176 {
177     HANDLE handle = (HANDLE)hf;
178     DWORD ret;
179     
180     ret = SetFilePointer(handle, dist, NULL, seektype);
181     ok(ret != INVALID_SET_FILE_POINTER, "Failed to SetFilePointer\n");
182
183     return ret;
184 }
185
186 static int fci_delete(char *pszFile, int *err, void *pv)
187 {
188     BOOL ret = DeleteFileA(pszFile);
189     ok(ret, "Failed to DeleteFile %s\n", pszFile);
190
191     return 0;
192 }
193
194 static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv)
195 {
196     LPSTR tempname;
197
198     tempname = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
199     GetTempFileNameA(".", "xx", 0, tempname);
200
201     if (tempname && (strlen(tempname) < (unsigned)cbTempName))
202     {
203         lstrcpyA(pszTempName, tempname);
204         HeapFree(GetProcessHeap(), 0, tempname);
205         return TRUE;
206     }
207
208     HeapFree(GetProcessHeap(), 0, tempname);
209
210     return FALSE;
211 }
212
213 static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime,
214                              USHORT *pattribs, int *err, void *pv)
215 {
216     BY_HANDLE_FILE_INFORMATION finfo;
217     FILETIME filetime;
218     HANDLE handle;
219     DWORD attrs;
220     BOOL res;
221
222     handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
223                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
224
225     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszName);
226
227     res = GetFileInformationByHandle(handle, &finfo);
228     ok(res, "Expected GetFileInformationByHandle to succeed\n");
229    
230     FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime);
231     FileTimeToDosDateTime(&filetime, pdate, ptime);
232
233     attrs = GetFileAttributes(pszName);
234     ok(attrs != INVALID_FILE_ATTRIBUTES, "Failed to GetFileAttributes\n");
235
236     return (INT_PTR)handle;
237 }
238
239 static void add_file(HFCI hfci, char *file)
240 {
241     char path[MAX_PATH];
242     BOOL res;
243
244     lstrcpyA(path, CURR_DIR);
245     lstrcatA(path, "\\");
246     lstrcatA(path, file);
247
248     res = FCIAddFile(hfci, path, file, FALSE, get_next_cabinet, progress,
249                      get_open_info, tcompTYPE_MSZIP);
250     ok(res, "Expected FCIAddFile to succeed\n");
251 }
252
253 static void set_cab_parameters(PCCAB pCabParams)
254 {
255     ZeroMemory(pCabParams, sizeof(CCAB));
256
257     pCabParams->cb = MEDIA_SIZE;
258     pCabParams->cbFolderThresh = FOLDER_THRESHOLD;
259     pCabParams->setID = 0xbeef;
260     lstrcpyA(pCabParams->szCabPath, CURR_DIR);
261     lstrcatA(pCabParams->szCabPath, "\\");
262     lstrcpyA(pCabParams->szCab, "extract.cab");
263 }
264
265 static void create_cab_file()
266 {
267     CCAB cabParams;
268     HFCI hfci;
269     ERF erf;
270     BOOL res;
271
272     set_cab_parameters(&cabParams);
273
274     hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
275                       fci_read, fci_write, fci_close, fci_seek, fci_delete,
276                       get_temp_file, &cabParams, NULL);
277
278     ok(hfci != NULL, "Failed to create an FCI context\n");
279
280     add_file(hfci, "a.txt");
281     add_file(hfci, "b.txt");
282     add_file(hfci, "testdir\\c.txt");
283     add_file(hfci, "testdir\\d.txt");
284
285     res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
286     ok(res, "Failed to flush the cabinet\n");
287
288     res = FCIDestroy(hfci);
289     ok(res, "Failed to destroy the cabinet\n");
290 }
291
292 static void test_ExtractFiles()
293 {
294     HRESULT hr;
295     char destFolder[MAX_PATH];
296
297     lstrcpyA(destFolder, CURR_DIR);
298     lstrcatA(destFolder, "\\");
299     lstrcatA(destFolder, "dest");
300
301     /* try NULL cab file */
302     hr = pExtractFiles(NULL, destFolder, 0, NULL, NULL, 0);
303     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
304     ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
305     
306     /* try NULL destination */
307     hr = pExtractFiles("extract.cab", NULL, 0, NULL, NULL, 0);
308     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
309     ok(!RemoveDirectoryA("dest"), "Expected dest to not exist\n");
310
311     /* extract all files in the cab to nonexistent destination directory */
312     hr = pExtractFiles("extract.cab", destFolder, 0, NULL, NULL, 0);
313     ok(hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND),
314        "Expected %ld, got %ld\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), hr);
315     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
316     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
317     ok(!RemoveDirectoryA("dest\\testdir"), "Exepected dest\\testdir to not exist\n");
318     ok(!RemoveDirectoryA("dest"), "Expected dest to not exist\n");
319
320     /* extract all files in the cab to the destination directory */
321     CreateDirectoryA("dest", NULL);
322     hr = pExtractFiles("extract.cab", destFolder, 0, NULL, NULL, 0);
323     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
324     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
325     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
326     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
327     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
328     ok(RemoveDirectoryA("dest\\testdir"), "Exepected dest\\testdir to exist\n");
329
330     /* extract all files to a relative destination directory */
331     hr = pExtractFiles("extract.cab", "dest", 0, NULL, NULL, 0);
332     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
333     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
334     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
335     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
336     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
337     ok(RemoveDirectoryA("dest\\testdir"), "Exepected dest\\testdir to exist\n");
338
339     /* only extract two of the files from the cab */
340     hr = pExtractFiles("extract.cab", "dest", 0, "a.txt:testdir\\c.txt", NULL, 0);
341     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
342     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
343     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
344     ok(RemoveDirectoryA("dest\\testdir"), "Exepected dest\\testdir to exist\n");
345     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
346     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
347
348     /* use valid chars before and after file list */
349     hr = pExtractFiles("extract.cab", "dest", 0, " :\t: a.txt:testdir\\c.txt  \t:", NULL, 0);
350     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
351     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
352     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
353     ok(RemoveDirectoryA("dest\\testdir"), "Exepected dest\\testdir to exist\n");
354     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
355     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
356
357     /* use invalid chars before and after file list */
358     hr = pExtractFiles("extract.cab", "dest", 0, " +-\\ a.txt:testdir\\c.txt  a_:", NULL, 0);
359     ok(hr == E_FAIL, "Expected E_FAIL, got %ld\n", hr);
360     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
361     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
362     ok(!RemoveDirectoryA("dest\\testdir"), "Exepected dest\\testdir to not exist\n");
363
364     /* try an empty file list */
365     hr = pExtractFiles("extract.cab", "dest", 0, "", NULL, 0);
366     ok(hr == E_FAIL, "Expected E_FAIL, got %ld\n", hr);
367     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
368     ok(!RemoveDirectoryA("dest\\testdir"), "Exepected dest\\testdir to not exist\n");
369
370     /* try a nonexistent file in the file list */
371     hr = pExtractFiles("extract.cab", "dest", 0, "a.txt:idontexist:testdir\\c.txt", NULL, 0);
372     ok(hr == E_FAIL, "Expected E_FAIL, got %ld\n", hr);
373     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
374     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
375     ok(!RemoveDirectoryA("dest\\testdir"), "Exepected dest\\testdir to not exist\n");
376 }
377
378 static void test_AdvInstallFile(void)
379 {
380     HRESULT hr;
381     char CURR_DIR[MAX_PATH];
382     char destFolder[MAX_PATH];
383
384     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
385
386     lstrcpyA(destFolder, CURR_DIR);
387     lstrcatA(destFolder, "\\");
388     lstrcatA(destFolder, "dest");
389
390     createTestFile("source.txt");
391
392     /* try invalid source directory */
393     hr = pAdvInstallFile(NULL, NULL, "source.txt", destFolder, "destination.txt", 0, 0);
394     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
395     ok(!DeleteFileA("dest\\destination.txt"), "Expected dest\\destination.txt to not exist\n");
396
397     /* try invalid source file */
398     hr = pAdvInstallFile(NULL, CURR_DIR, NULL, destFolder, "destination.txt", 0, 0);
399     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
400     ok(!DeleteFileA("dest\\destination.txt"), "Expected dest\\destination.txt to not exist\n");
401
402     /* try invalid destination directory */
403     hr = pAdvInstallFile(NULL, CURR_DIR, "source.txt", NULL, "destination.txt", 0, 0);
404     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %ld\n", hr);
405     ok(!DeleteFileA("dest\\destination.txt"), "Expected dest\\destination.txt to not exist\n");
406
407     /* try copying to nonexistent destination directory */
408     hr = pAdvInstallFile(NULL, CURR_DIR, "source.txt", destFolder, "destination.txt", 0, 0);
409     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
410     ok(DeleteFileA("dest\\destination.txt"), "Expected dest\\destination.txt to exist\n");
411
412     /* native windows screws up if the source file doesn't exist */
413
414     /* test AIF_NOOVERWRITE behavior, asks the user to overwrite if AIF_QUIET is not specified */
415     createTestFile("dest\\destination.txt");
416     hr = pAdvInstallFile(NULL, CURR_DIR, "source.txt", destFolder,
417                          "destination.txt", AIF_NOOVERWRITE | AIF_QUIET, 0);
418     ok(hr == S_OK, "Expected S_OK, got %ld\n", hr);
419     ok(DeleteFileA("dest\\destination.txt"), "Expected dest\\destination.txt to exist\n");
420     ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
421
422     DeleteFileA("source.txt");
423 }
424
425 START_TEST(files)
426 {
427     init_function_pointers();
428     create_test_files();
429     create_cab_file();
430
431     test_ExtractFiles();
432     test_AdvInstallFile();
433
434     delete_test_files();
435 }