crypt32: Test decoding a big CRL.
[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     dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
152
153     if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
154         dwCreateDisposition = OPEN_EXISTING;
155     else
156         dwCreateDisposition = CREATE_NEW;
157
158     handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
159                          dwCreateDisposition, 0, NULL);
160
161     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszFile);
162
163     return (INT_PTR)handle;
164 }
165
166 static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
167 {
168     HANDLE handle = (HANDLE)hf;
169     DWORD dwRead;
170     BOOL res;
171     
172     res = ReadFile(handle, memory, cb, &dwRead, NULL);
173     ok(res, "Failed to ReadFile\n");
174
175     return dwRead;
176 }
177
178 static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
179 {
180     HANDLE handle = (HANDLE)hf;
181     DWORD dwWritten;
182     BOOL res;
183
184     res = WriteFile(handle, memory, cb, &dwWritten, NULL);
185     ok(res, "Failed to WriteFile\n");
186
187     return dwWritten;
188 }
189
190 static int fci_close(INT_PTR hf, int *err, void *pv)
191 {
192     HANDLE handle = (HANDLE)hf;
193     ok(CloseHandle(handle), "Failed to CloseHandle\n");
194
195     return 0;
196 }
197
198 static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv)
199 {
200     HANDLE handle = (HANDLE)hf;
201     DWORD ret;
202     
203     ret = SetFilePointer(handle, dist, NULL, seektype);
204     ok(ret != INVALID_SET_FILE_POINTER, "Failed to SetFilePointer\n");
205
206     return ret;
207 }
208
209 static int fci_delete(char *pszFile, int *err, void *pv)
210 {
211     BOOL ret = DeleteFileA(pszFile);
212     ok(ret, "Failed to DeleteFile %s\n", pszFile);
213
214     return 0;
215 }
216
217 static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv)
218 {
219     LPSTR tempname;
220
221     tempname = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
222     GetTempFileNameA(".", "xx", 0, tempname);
223
224     if (tempname && (strlen(tempname) < (unsigned)cbTempName))
225     {
226         lstrcpyA(pszTempName, tempname);
227         HeapFree(GetProcessHeap(), 0, tempname);
228         return TRUE;
229     }
230
231     HeapFree(GetProcessHeap(), 0, tempname);
232
233     return FALSE;
234 }
235
236 static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime,
237                              USHORT *pattribs, int *err, void *pv)
238 {
239     BY_HANDLE_FILE_INFORMATION finfo;
240     FILETIME filetime;
241     HANDLE handle;
242     DWORD attrs;
243     BOOL res;
244
245     handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
246                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
247
248     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszName);
249
250     res = GetFileInformationByHandle(handle, &finfo);
251     ok(res, "Expected GetFileInformationByHandle to succeed\n");
252    
253     FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime);
254     FileTimeToDosDateTime(&filetime, pdate, ptime);
255
256     attrs = GetFileAttributes(pszName);
257     ok(attrs != INVALID_FILE_ATTRIBUTES, "Failed to GetFileAttributes\n");
258
259     return (INT_PTR)handle;
260 }
261
262 static void add_file(HFCI hfci, char *file)
263 {
264     char path[MAX_PATH];
265     BOOL res;
266
267     lstrcpyA(path, CURR_DIR);
268     lstrcatA(path, "\\");
269     lstrcatA(path, file);
270
271     res = FCIAddFile(hfci, path, file, FALSE, get_next_cabinet, progress,
272                      get_open_info, tcompTYPE_MSZIP);
273     ok(res, "Expected FCIAddFile to succeed\n");
274 }
275
276 static void set_cab_parameters(PCCAB pCabParams)
277 {
278     ZeroMemory(pCabParams, sizeof(CCAB));
279
280     pCabParams->cb = MEDIA_SIZE;
281     pCabParams->cbFolderThresh = FOLDER_THRESHOLD;
282     pCabParams->setID = 0xbeef;
283     lstrcpyA(pCabParams->szCabPath, CURR_DIR);
284     lstrcatA(pCabParams->szCabPath, "\\");
285     lstrcpyA(pCabParams->szCab, "extract.cab");
286 }
287
288 static void create_cab_file(void)
289 {
290     CCAB cabParams;
291     HFCI hfci;
292     ERF erf;
293     static CHAR a_txt[]         = "a.txt",
294                 b_txt[]         = "b.txt",
295                 testdir_c_txt[] = "testdir\\c.txt",
296                 testdir_d_txt[] = "testdir\\d.txt";
297     BOOL res;
298
299     set_cab_parameters(&cabParams);
300
301     hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
302                       fci_read, fci_write, fci_close, fci_seek, fci_delete,
303                       get_temp_file, &cabParams, NULL);
304
305     ok(hfci != NULL, "Failed to create an FCI context\n");
306
307     add_file(hfci, a_txt);
308     add_file(hfci, b_txt);
309     add_file(hfci, testdir_c_txt);
310     add_file(hfci, testdir_d_txt);
311
312     res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
313     ok(res, "Failed to flush the cabinet\n");
314
315     res = FCIDestroy(hfci);
316     ok(res, "Failed to destroy the cabinet\n");
317 }
318
319 static BOOL check_list(EXTRACTDEST *dest, const char *filename, BOOL flag)
320 {
321     struct ExtractFileList *i;
322
323     for (i = dest->filelist; i; i=i->next)
324         if (!lstrcmp(filename, i->filename))
325             return (flag == i->flag);
326     return FALSE;
327 }
328
329 static void test_Extract(void)
330 {
331     EXTRACTDEST extractDest;
332     HRESULT res;
333
334     /* native windows crashes if
335     *   - invalid parameters are sent in
336     *   - you call EXTRACT_EXTRACTFILES without calling
337     *     EXTRACT_FILLFILELIST first or at the same time
338     */
339
340     /* try to extract all files */
341     ZeroMemory(&extractDest, sizeof(EXTRACTDEST));
342     lstrcpyA(extractDest.directory, "dest");
343     extractDest.flags = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
344     res = pExtract(&extractDest, "extract.cab");
345     ok(res == S_OK, "Expected S_OK, got %ld\n", res);
346     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
347     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
348     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
349     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
350     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
351
352     /* try fill file list operation */
353     ZeroMemory(&extractDest, sizeof(EXTRACTDEST));
354     lstrcpyA(extractDest.directory, "dest");
355     extractDest.flags = EXTRACT_FILLFILELIST;
356     res = pExtract(&extractDest, "extract.cab");
357     ok(res == S_OK, "Expected S_OK, got %ld\n", res);
358     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
359     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
360     ok(extractDest.filecount == 4, "Expected 4 files, got %ld\n", extractDest.filecount);
361     ok(!lstrcmpA(extractDest.lastfile, "dest\\testdir\\d.txt"),
362         "Expected last file to be dest\\testdir\\d.txt, got %s\n", extractDest.lastfile);
363
364     /* try extract files operation once file list is filled */
365     extractDest.flags = EXTRACT_EXTRACTFILES;
366     res = pExtract(&extractDest, "extract.cab");
367     ok(res == S_OK, "Expected S_OK, got %ld\n", res);
368     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
369     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
370     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
371     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
372     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
373     ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
374
375     /* Extract does not extract files if the dest dir does not exist */
376     res = pExtract(&extractDest, "extract.cab");
377     ok(res == S_OK, "Expected S_OK, got %ld\n", res);
378     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
379     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
380
381     ok(check_list(&extractDest, "testdir\\d.txt", FALSE), "list entry wrong\n");
382     ok(check_list(&extractDest, "testdir\\c.txt", FALSE), "list entry wrong\n");
383     ok(check_list(&extractDest, "b.txt", FALSE), "list entry wrong\n");
384     ok(check_list(&extractDest, "a.txt", FALSE), "list entry wrong\n");
385
386     /* remove two of the files in the list */
387     extractDest.filelist->next = extractDest.filelist->next->next;
388     extractDest.filelist->next->next = NULL;
389     extractDest.filterlist = NULL;
390     CreateDirectoryA("dest", NULL);
391     res = pExtract(&extractDest, "extract.cab");
392     ok(res == S_OK, "Expected S_OK, got %ld\n", res);
393     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
394     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
395     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
396     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
397
398     todo_wine {
399     ok(check_list(&extractDest, "testdir\\d.txt", FALSE), "list entry wrong\n");
400     ok(!check_list(&extractDest, "testdir\\c.txt", FALSE), "list entry wrong\n");
401     ok(check_list(&extractDest, "b.txt", FALSE), "list entry wrong\n");
402     ok(!check_list(&extractDest, "a.txt", FALSE), "list entry wrong\n");
403     }
404
405     extractDest.flags = 1;
406     extractDest.filelist = NULL;
407     res = pExtract(&extractDest, "extract.cab");
408     ok(res == S_OK, "Expected S_OK, got %ld\n", res);
409     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
410     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
411     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
412     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
413
414     todo_wine {
415     ok(check_list(&extractDest, "testdir\\d.txt", TRUE), "list entry wrong\n");
416     ok(check_list(&extractDest, "testdir\\c.txt", TRUE), "list entry wrong\n");
417     ok(check_list(&extractDest, "b.txt", TRUE), "list entry wrong\n");
418     ok(check_list(&extractDest, "a.txt", TRUE), "list entry wrong\n");
419     }
420
421     extractDest.flags = 0;
422     res = pExtract(&extractDest, "extract.cab");
423     ok(res == S_OK, "Expected S_OK, got %ld\n", res);
424     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
425     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
426     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
427     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
428
429     todo_wine {
430     ok(check_list(&extractDest, "testdir\\d.txt", TRUE), "list entry wrong\n");
431     ok(check_list(&extractDest, "testdir\\c.txt", TRUE), "list entry wrong\n");
432     ok(check_list(&extractDest, "b.txt", TRUE), "list entry wrong\n");
433     ok(check_list(&extractDest, "a.txt", TRUE), "list entry wrong\n");
434     }
435
436     extractDest.flags = 0;
437     extractDest.filterlist = extractDest.filelist;
438     res = pExtract(&extractDest, "extract.cab");
439     ok(res == S_OK, "Expected S_OK, got %ld\n", res);
440     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
441     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
442     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
443     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
444
445     ok(check_list(&extractDest, "testdir\\d.txt", FALSE), "list entry wrong\n");
446     ok(check_list(&extractDest, "testdir\\c.txt", FALSE), "list entry wrong\n");
447     ok(check_list(&extractDest, "b.txt", FALSE), "list entry wrong\n");
448     ok(check_list(&extractDest, "a.txt", FALSE), "list entry wrong\n");
449
450     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
451     ok(RemoveDirectoryA("dest"), "Expected dest\\testdir to exist\n");
452 }
453
454 START_TEST(extract)
455 {
456     init_function_pointers();
457     create_test_files();
458     create_cab_file();
459
460     test_Extract();
461
462     delete_test_files();
463 }