winspool: Start support for XcvMonitor and XcvPort in OpenPrinter.
[wine] / dlls / cabinet / tests / extract.c
1 /*
2  * Unit tests for cabinet.dll extract 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdio.h>
22 #include <windows.h>
23 #include "fci.h"
24 #include "wine/test.h"
25
26 /* make the max size large so there is only one cab file */
27 #define MEDIA_SIZE          999999999
28 #define FOLDER_THRESHOLD    900000
29
30 /* The following defintions were copied from dlls/cabinet/cabinet.h
31  * because they are undocumented in windows.
32  */
33
34 /* EXTRACTdest flags */
35 #define EXTRACT_FILLFILELIST  0x00000001
36 #define EXTRACT_EXTRACTFILES  0x00000002
37
38 struct ExtractFileList {
39     LPSTR  filename;
40     struct ExtractFileList *next;
41     BOOL   flag;
42 };
43
44 /* the first parameter of the function extract */
45 typedef struct {
46     long   result1;          /* 0x000 */
47     long   unknown1[3];      /* 0x004 */
48     struct ExtractFileList *filelist; /* 0x010 */
49     long   filecount;        /* 0x014 */
50     long   flags;            /* 0x018 */
51     char   directory[MAX_PATH]; /* 0x01c */
52     char   lastfile[MAX_PATH];  /* 0x120 */
53     char   unknown2[MAX_PATH];  /* 0x224 */
54     struct ExtractFileList *filterlist; /* 0x328 */
55 } EXTRACTDEST;
56
57 /* function pointers */
58 HMODULE hCabinet;
59 static HRESULT (WINAPI *pExtract)(EXTRACTDEST*, LPCSTR);
60
61 CHAR CURR_DIR[MAX_PATH];
62
63 static void init_function_pointers(void)
64 {
65     hCabinet = LoadLibraryA("cabinet.dll");
66
67     if (hCabinet)
68     {
69         pExtract = (void *)GetProcAddress(hCabinet, "Extract");
70     }
71 }
72
73 /* creates a file with the specified name for tests */
74 static void createTestFile(const CHAR *name)
75 {
76     HANDLE file;
77     DWORD written;
78
79     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
80     ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
81     WriteFile(file, name, strlen(name), &written, NULL);
82     WriteFile(file, "\n", strlen("\n"), &written, NULL);
83     CloseHandle(file);
84 }
85
86 static void create_test_files(void)
87 {
88     int len;
89
90     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
91     len = lstrlenA(CURR_DIR);
92
93     if(len && (CURR_DIR[len-1] == '\\'))
94         CURR_DIR[len-1] = 0;
95
96     createTestFile("a.txt");
97     createTestFile("b.txt");
98     CreateDirectoryA("testdir", NULL);
99     createTestFile("testdir\\c.txt");
100     createTestFile("testdir\\d.txt");
101     CreateDirectoryA("dest", NULL);
102 }
103
104 static void delete_test_files(void)
105 {
106     DeleteFileA("a.txt");
107     DeleteFileA("b.txt");
108     DeleteFileA("testdir\\c.txt");
109     DeleteFileA("testdir\\d.txt");
110     RemoveDirectoryA("testdir");
111
112     DeleteFileA("extract.cab");
113 }
114
115 /* the FCI callbacks */
116
117 static void *mem_alloc(ULONG cb)
118 {
119     return HeapAlloc(GetProcessHeap(), 0, cb);
120 }
121
122 static void mem_free(void *memory)
123 {
124     HeapFree(GetProcessHeap(), 0, memory);
125 }
126
127 static BOOL get_next_cabinet(PCCAB pccab, ULONG  cbPrevCab, void *pv)
128 {
129     return TRUE;
130 }
131
132 static long progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv)
133 {
134     return 0;
135 }
136
137 static int file_placed(PCCAB pccab, char *pszFile, long cbFile,
138                        BOOL fContinuation, void *pv)
139 {
140     return 0;
141 }
142
143 static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv)
144 {
145     HANDLE handle;
146     DWORD dwAccess = 0;
147     DWORD dwShareMode = 0;
148     DWORD dwCreateDisposition = OPEN_EXISTING;
149     
150     dwAccess = GENERIC_READ | GENERIC_WRITE;
151     /* FILE_SHARE_DELETE is not supported by Windows Me/98/95 */
152     dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
153
154     if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
155         dwCreateDisposition = OPEN_EXISTING;
156     else
157         dwCreateDisposition = CREATE_NEW;
158
159     handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
160                          dwCreateDisposition, 0, NULL);
161
162     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszFile);
163
164     return (INT_PTR)handle;
165 }
166
167 static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
168 {
169     HANDLE handle = (HANDLE)hf;
170     DWORD dwRead;
171     BOOL res;
172     
173     res = ReadFile(handle, memory, cb, &dwRead, NULL);
174     ok(res, "Failed to ReadFile\n");
175
176     return dwRead;
177 }
178
179 static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
180 {
181     HANDLE handle = (HANDLE)hf;
182     DWORD dwWritten;
183     BOOL res;
184
185     res = WriteFile(handle, memory, cb, &dwWritten, NULL);
186     ok(res, "Failed to WriteFile\n");
187
188     return dwWritten;
189 }
190
191 static int fci_close(INT_PTR hf, int *err, void *pv)
192 {
193     HANDLE handle = (HANDLE)hf;
194     ok(CloseHandle(handle), "Failed to CloseHandle\n");
195
196     return 0;
197 }
198
199 static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv)
200 {
201     HANDLE handle = (HANDLE)hf;
202     DWORD ret;
203     
204     ret = SetFilePointer(handle, dist, NULL, seektype);
205     ok(ret != INVALID_SET_FILE_POINTER, "Failed to SetFilePointer\n");
206
207     return ret;
208 }
209
210 static int fci_delete(char *pszFile, int *err, void *pv)
211 {
212     BOOL ret = DeleteFileA(pszFile);
213     ok(ret, "Failed to DeleteFile %s\n", pszFile);
214
215     return 0;
216 }
217
218 static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv)
219 {
220     LPSTR tempname;
221
222     tempname = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
223     GetTempFileNameA(".", "xx", 0, tempname);
224
225     if (tempname && (strlen(tempname) < (unsigned)cbTempName))
226     {
227         lstrcpyA(pszTempName, tempname);
228         HeapFree(GetProcessHeap(), 0, tempname);
229         return TRUE;
230     }
231
232     HeapFree(GetProcessHeap(), 0, tempname);
233
234     return FALSE;
235 }
236
237 static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime,
238                              USHORT *pattribs, int *err, void *pv)
239 {
240     BY_HANDLE_FILE_INFORMATION finfo;
241     FILETIME filetime;
242     HANDLE handle;
243     DWORD attrs;
244     BOOL res;
245
246     handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
247                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
248
249     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszName);
250
251     res = GetFileInformationByHandle(handle, &finfo);
252     ok(res, "Expected GetFileInformationByHandle to succeed\n");
253    
254     FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime);
255     FileTimeToDosDateTime(&filetime, pdate, ptime);
256
257     attrs = GetFileAttributes(pszName);
258     ok(attrs != INVALID_FILE_ATTRIBUTES, "Failed to GetFileAttributes\n");
259
260     return (INT_PTR)handle;
261 }
262
263 static void add_file(HFCI hfci, char *file)
264 {
265     char path[MAX_PATH];
266     BOOL res;
267
268     lstrcpyA(path, CURR_DIR);
269     lstrcatA(path, "\\");
270     lstrcatA(path, file);
271
272     res = FCIAddFile(hfci, path, file, FALSE, get_next_cabinet, progress,
273                      get_open_info, tcompTYPE_MSZIP);
274     ok(res, "Expected FCIAddFile to succeed\n");
275 }
276
277 static void set_cab_parameters(PCCAB pCabParams)
278 {
279     ZeroMemory(pCabParams, sizeof(CCAB));
280
281     pCabParams->cb = MEDIA_SIZE;
282     pCabParams->cbFolderThresh = FOLDER_THRESHOLD;
283     pCabParams->setID = 0xbeef;
284     lstrcpyA(pCabParams->szCabPath, CURR_DIR);
285     lstrcatA(pCabParams->szCabPath, "\\");
286     lstrcpyA(pCabParams->szCab, "extract.cab");
287 }
288
289 static void create_cab_file(void)
290 {
291     CCAB cabParams;
292     HFCI hfci;
293     ERF erf;
294     static CHAR a_txt[]         = "a.txt",
295                 b_txt[]         = "b.txt",
296                 testdir_c_txt[] = "testdir\\c.txt",
297                 testdir_d_txt[] = "testdir\\d.txt";
298     BOOL res;
299
300     set_cab_parameters(&cabParams);
301
302     hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
303                       fci_read, fci_write, fci_close, fci_seek, fci_delete,
304                       get_temp_file, &cabParams, NULL);
305
306     ok(hfci != NULL, "Failed to create an FCI context\n");
307
308     add_file(hfci, a_txt);
309     add_file(hfci, b_txt);
310     add_file(hfci, testdir_c_txt);
311     add_file(hfci, testdir_d_txt);
312
313     res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
314     ok(res, "Failed to flush the cabinet\n");
315
316     res = FCIDestroy(hfci);
317     ok(res, "Failed to destroy the cabinet\n");
318 }
319
320 static BOOL check_list(EXTRACTDEST *dest, const char *filename, BOOL flag)
321 {
322     struct ExtractFileList *i;
323
324     for (i = dest->filelist; i; i=i->next)
325         if (!lstrcmp(filename, i->filename))
326             return (flag == i->flag);
327     return FALSE;
328 }
329
330 static void test_Extract(void)
331 {
332     EXTRACTDEST extractDest;
333     HRESULT res;
334
335     /* native windows crashes if
336     *   - invalid parameters are sent in
337     *   - you call EXTRACT_EXTRACTFILES without calling
338     *     EXTRACT_FILLFILELIST first or at the same time
339     */
340
341     /* try to extract all files */
342     ZeroMemory(&extractDest, sizeof(EXTRACTDEST));
343     lstrcpyA(extractDest.directory, "dest");
344     extractDest.flags = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
345     res = pExtract(&extractDest, "extract.cab");
346     ok(res == S_OK, "Expected S_OK, got %d\n", res);
347     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
348     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
349     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
350     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
351     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
352
353     /* try fill file list operation */
354     ZeroMemory(&extractDest, sizeof(EXTRACTDEST));
355     lstrcpyA(extractDest.directory, "dest");
356     extractDest.flags = EXTRACT_FILLFILELIST;
357     res = pExtract(&extractDest, "extract.cab");
358     ok(res == S_OK, "Expected S_OK, got %d\n", res);
359     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
360     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
361     ok(extractDest.filecount == 4, "Expected 4 files, got %ld\n", extractDest.filecount);
362     ok(!lstrcmpA(extractDest.lastfile, "dest\\testdir\\d.txt"),
363         "Expected last file to be dest\\testdir\\d.txt, got %s\n", extractDest.lastfile);
364
365     /* try extract files operation once file list is filled */
366     extractDest.flags = EXTRACT_EXTRACTFILES;
367     res = pExtract(&extractDest, "extract.cab");
368     ok(res == S_OK, "Expected S_OK, got %d\n", res);
369     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
370     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
371     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
372     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
373     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
374     ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
375
376     /* Extract does not extract files if the dest dir does not exist */
377     res = pExtract(&extractDest, "extract.cab");
378     ok(res == S_OK, "Expected S_OK, got %d\n", res);
379     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
380     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
381
382     ok(check_list(&extractDest, "testdir\\d.txt", FALSE), "list entry wrong\n");
383     ok(check_list(&extractDest, "testdir\\c.txt", FALSE), "list entry wrong\n");
384     ok(check_list(&extractDest, "b.txt", FALSE), "list entry wrong\n");
385     ok(check_list(&extractDest, "a.txt", FALSE), "list entry wrong\n");
386
387     /* remove two of the files in the list */
388     extractDest.filelist->next = extractDest.filelist->next->next;
389     extractDest.filelist->next->next = NULL;
390     extractDest.filterlist = NULL;
391     CreateDirectoryA("dest", NULL);
392     res = pExtract(&extractDest, "extract.cab");
393     ok(res == S_OK, "Expected S_OK, got %d\n", res);
394     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
395     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
396     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
397     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
398
399     todo_wine {
400     ok(check_list(&extractDest, "testdir\\d.txt", FALSE), "list entry wrong\n");
401     ok(!check_list(&extractDest, "testdir\\c.txt", FALSE), "list entry wrong\n");
402     ok(check_list(&extractDest, "b.txt", FALSE), "list entry wrong\n");
403     ok(!check_list(&extractDest, "a.txt", FALSE), "list entry wrong\n");
404     }
405
406     extractDest.flags = 1;
407     extractDest.filelist = NULL;
408     res = pExtract(&extractDest, "extract.cab");
409     ok(res == S_OK, "Expected S_OK, got %d\n", res);
410     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
411     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
412     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
413     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
414
415     todo_wine {
416     ok(check_list(&extractDest, "testdir\\d.txt", TRUE), "list entry wrong\n");
417     ok(check_list(&extractDest, "testdir\\c.txt", TRUE), "list entry wrong\n");
418     ok(check_list(&extractDest, "b.txt", TRUE), "list entry wrong\n");
419     ok(check_list(&extractDest, "a.txt", TRUE), "list entry wrong\n");
420     }
421
422     extractDest.flags = 0;
423     res = pExtract(&extractDest, "extract.cab");
424     ok(res == S_OK, "Expected S_OK, got %d\n", res);
425     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
426     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
427     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
428     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
429
430     todo_wine {
431     ok(check_list(&extractDest, "testdir\\d.txt", TRUE), "list entry wrong\n");
432     ok(check_list(&extractDest, "testdir\\c.txt", TRUE), "list entry wrong\n");
433     ok(check_list(&extractDest, "b.txt", TRUE), "list entry wrong\n");
434     ok(check_list(&extractDest, "a.txt", TRUE), "list entry wrong\n");
435     }
436
437     extractDest.flags = 0;
438     extractDest.filterlist = extractDest.filelist;
439     res = pExtract(&extractDest, "extract.cab");
440     ok(res == S_OK, "Expected S_OK, got %d\n", res);
441     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
442     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
443     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
444     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
445
446     ok(check_list(&extractDest, "testdir\\d.txt", FALSE), "list entry wrong\n");
447     ok(check_list(&extractDest, "testdir\\c.txt", FALSE), "list entry wrong\n");
448     ok(check_list(&extractDest, "b.txt", FALSE), "list entry wrong\n");
449     ok(check_list(&extractDest, "a.txt", FALSE), "list entry wrong\n");
450
451     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
452     ok(RemoveDirectoryA("dest"), "Expected dest\\testdir to exist\n");
453 }
454
455 START_TEST(extract)
456 {
457     init_function_pointers();
458     create_test_files();
459     create_cab_file();
460
461     test_Extract();
462
463     delete_test_files();
464 }