strmbase: COM cleanup for BasePin, BaseInputPin, and BaseOutputPin.
[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 "fdi.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 /* The following definitions were copied from dlls/cabinet/cabinet.h
32  * because they are undocumented in windows.
33  */
34
35 /* SESSION Operation */
36 #define EXTRACT_FILLFILELIST  0x00000001
37 #define EXTRACT_EXTRACTFILES  0x00000002
38
39 struct FILELIST{
40     LPSTR FileName;
41     struct FILELIST *next;
42     BOOL DoExtract;
43 };
44
45 typedef struct {
46     INT FileSize;
47     ERF Error;
48     struct FILELIST *FileList;
49     INT FileCount;
50     INT Operation;
51     CHAR Destination[MAX_PATH];
52     CHAR CurrentFile[MAX_PATH];
53     CHAR Reserved[MAX_PATH];
54     struct FILELIST *FilterList;
55 } SESSION;
56
57 /* function pointers */
58 static HMODULE hCabinet;
59 static HRESULT (WINAPI *pExtract)(SESSION*, LPCSTR);
60
61 static CHAR CURR_DIR[MAX_PATH];
62
63 static void init_function_pointers(void)
64 {
65     hCabinet = GetModuleHandleA("cabinet.dll");
66
67     pExtract = (void *)GetProcAddress(hCabinet, "Extract");
68 }
69
70 /* creates a file with the specified name for tests */
71 static void createTestFile(const CHAR *name)
72 {
73     HANDLE file;
74     DWORD written;
75
76     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
77     ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
78     WriteFile(file, name, strlen(name), &written, NULL);
79     WriteFile(file, "\n", strlen("\n"), &written, NULL);
80     CloseHandle(file);
81 }
82
83 static void create_test_files(void)
84 {
85     int len;
86
87     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
88     len = lstrlenA(CURR_DIR);
89
90     if(len && (CURR_DIR[len-1] == '\\'))
91         CURR_DIR[len-1] = 0;
92
93     createTestFile("a.txt");
94     createTestFile("b.txt");
95     CreateDirectoryA("testdir", NULL);
96     createTestFile("testdir\\c.txt");
97     createTestFile("testdir\\d.txt");
98     CreateDirectoryA("dest", NULL);
99 }
100
101 static void delete_test_files(void)
102 {
103     DeleteFileA("a.txt");
104     DeleteFileA("b.txt");
105     DeleteFileA("testdir\\c.txt");
106     DeleteFileA("testdir\\d.txt");
107     RemoveDirectoryA("testdir");
108
109     DeleteFileA("extract.cab");
110 }
111
112 /* the FCI callbacks */
113
114 static void * CDECL mem_alloc(ULONG cb)
115 {
116     return HeapAlloc(GetProcessHeap(), 0, cb);
117 }
118
119 static void CDECL mem_free(void *memory)
120 {
121     HeapFree(GetProcessHeap(), 0, memory);
122 }
123
124 static BOOL CDECL get_next_cabinet(PCCAB pccab, ULONG  cbPrevCab, void *pv)
125 {
126     return TRUE;
127 }
128
129 static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv)
130 {
131     return 0;
132 }
133
134 static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile,
135                              BOOL fContinuation, void *pv)
136 {
137     return 0;
138 }
139
140 static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv)
141 {
142     HANDLE handle;
143     DWORD dwAccess = 0;
144     DWORD dwShareMode = 0;
145     DWORD dwCreateDisposition = OPEN_EXISTING;
146     
147     dwAccess = GENERIC_READ | GENERIC_WRITE;
148     /* FILE_SHARE_DELETE is not supported by Windows Me/98/95 */
149     dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
150
151     if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
152         dwCreateDisposition = OPEN_EXISTING;
153     else
154         dwCreateDisposition = CREATE_NEW;
155
156     handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
157                          dwCreateDisposition, 0, NULL);
158
159     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszFile);
160
161     return (INT_PTR)handle;
162 }
163
164 static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
165 {
166     HANDLE handle = (HANDLE)hf;
167     DWORD dwRead;
168     BOOL res;
169     
170     res = ReadFile(handle, memory, cb, &dwRead, NULL);
171     ok(res, "Failed to ReadFile\n");
172
173     return dwRead;
174 }
175
176 static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
177 {
178     HANDLE handle = (HANDLE)hf;
179     DWORD dwWritten;
180     BOOL res;
181
182     res = WriteFile(handle, memory, cb, &dwWritten, NULL);
183     ok(res, "Failed to WriteFile\n");
184
185     return dwWritten;
186 }
187
188 static int CDECL fci_close(INT_PTR hf, int *err, void *pv)
189 {
190     HANDLE handle = (HANDLE)hf;
191     ok(CloseHandle(handle), "Failed to CloseHandle\n");
192
193     return 0;
194 }
195
196 static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv)
197 {
198     HANDLE handle = (HANDLE)hf;
199     DWORD ret;
200     
201     ret = SetFilePointer(handle, dist, NULL, seektype);
202     ok(ret != INVALID_SET_FILE_POINTER, "Failed to SetFilePointer\n");
203
204     return ret;
205 }
206
207 static int CDECL fci_delete(char *pszFile, int *err, void *pv)
208 {
209     BOOL ret = DeleteFileA(pszFile);
210     ok(ret, "Failed to DeleteFile %s\n", pszFile);
211
212     return 0;
213 }
214
215 static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv)
216 {
217     LPSTR tempname;
218
219     tempname = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
220     GetTempFileNameA(".", "xx", 0, tempname);
221
222     if (tempname && (strlen(tempname) < (unsigned)cbTempName))
223     {
224         lstrcpyA(pszTempName, tempname);
225         HeapFree(GetProcessHeap(), 0, tempname);
226         return TRUE;
227     }
228
229     HeapFree(GetProcessHeap(), 0, tempname);
230
231     return FALSE;
232 }
233
234 static INT_PTR CDECL get_open_info(char *pszName, USHORT *pdate, USHORT *ptime,
235                                    USHORT *pattribs, int *err, void *pv)
236 {
237     BY_HANDLE_FILE_INFORMATION finfo;
238     FILETIME filetime;
239     HANDLE handle;
240     DWORD attrs;
241     BOOL res;
242
243     handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
244                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
245
246     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszName);
247
248     res = GetFileInformationByHandle(handle, &finfo);
249     ok(res, "Expected GetFileInformationByHandle to succeed\n");
250    
251     FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime);
252     FileTimeToDosDateTime(&filetime, pdate, ptime);
253
254     attrs = GetFileAttributes(pszName);
255     ok(attrs != INVALID_FILE_ATTRIBUTES, "Failed to GetFileAttributes\n");
256
257     return (INT_PTR)handle;
258 }
259
260 static void add_file(HFCI hfci, char *file)
261 {
262     char path[MAX_PATH];
263     BOOL res;
264
265     lstrcpyA(path, CURR_DIR);
266     lstrcatA(path, "\\");
267     lstrcatA(path, file);
268
269     res = FCIAddFile(hfci, path, file, FALSE, get_next_cabinet, progress,
270                      get_open_info, tcompTYPE_MSZIP);
271     ok(res, "Expected FCIAddFile to succeed\n");
272 }
273
274 static void set_cab_parameters(PCCAB pCabParams)
275 {
276     ZeroMemory(pCabParams, sizeof(CCAB));
277
278     pCabParams->cb = MEDIA_SIZE;
279     pCabParams->cbFolderThresh = FOLDER_THRESHOLD;
280     pCabParams->setID = 0xbeef;
281     lstrcpyA(pCabParams->szCabPath, CURR_DIR);
282     lstrcatA(pCabParams->szCabPath, "\\");
283     lstrcpyA(pCabParams->szCab, "extract.cab");
284 }
285
286 static void create_cab_file(void)
287 {
288     CCAB cabParams;
289     HFCI hfci;
290     ERF erf;
291     static CHAR a_txt[]         = "a.txt",
292                 b_txt[]         = "b.txt",
293                 testdir_c_txt[] = "testdir\\c.txt",
294                 testdir_d_txt[] = "testdir\\d.txt";
295     BOOL res;
296
297     set_cab_parameters(&cabParams);
298
299     hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
300                       fci_read, fci_write, fci_close, fci_seek, fci_delete,
301                       get_temp_file, &cabParams, NULL);
302
303     ok(hfci != NULL, "Failed to create an FCI context\n");
304
305     add_file(hfci, a_txt);
306     add_file(hfci, b_txt);
307     add_file(hfci, testdir_c_txt);
308     add_file(hfci, testdir_d_txt);
309
310     res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
311     ok(res, "Failed to flush the cabinet\n");
312
313     res = FCIDestroy(hfci);
314     ok(res, "Failed to destroy the cabinet\n");
315 }
316
317 static BOOL check_list(struct FILELIST **node, const char *filename, BOOL do_extract)
318 {
319     if (!*node)
320         return FALSE;
321
322     if (lstrcmpA((*node)->FileName, filename))
323         return FALSE;
324
325     if ((*node)->DoExtract != do_extract)
326         return FALSE;
327
328     *node = (*node)->next;
329     return TRUE;
330 }
331
332 static void free_file_node(struct FILELIST *node)
333 {
334     HeapFree(GetProcessHeap(), 0, node->FileName);
335     HeapFree(GetProcessHeap(), 0, node);
336 }
337
338 static void free_file_list(SESSION* session)
339 {
340     struct FILELIST *next, *curr = session->FileList;
341
342     while (curr)
343     {
344         next = curr->next;
345         free_file_node(curr);
346         curr = next;
347     }
348
349     session->FileList = NULL;
350 }
351
352 static void test_Extract(void)
353 {
354     SESSION session;
355     HRESULT res;
356     struct FILELIST *node;
357
358     /* native windows crashes if
359     *   - invalid parameters are sent in
360     *   - you call EXTRACT_EXTRACTFILES without calling
361     *     EXTRACT_FILLFILELIST first or at the same time
362     */
363
364     /* try to extract all files */
365     ZeroMemory(&session, sizeof(SESSION));
366     lstrcpyA(session.Destination, "dest");
367     session.Operation = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
368     res = pExtract(&session, "extract.cab");
369     node = session.FileList;
370     ok(res == S_OK, "Expected S_OK, got %d\n", res);
371     ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
372     ok(session.Error.erfOper == FDIERROR_NONE,
373        "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
374     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
375     ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
376     ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
377     ok(session.Operation == (EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES),
378        "Expected EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
379     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
380     ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
381        "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
382     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
383     ok(!session.FilterList, "Expected empty filter list\n");
384     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
385     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
386     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
387     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
388     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
389     ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
390     ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
391     ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
392     ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");
393     free_file_list(&session);
394
395     /* try fill file list operation */
396     ZeroMemory(&session, sizeof(SESSION));
397     lstrcpyA(session.Destination, "dest");
398     session.Operation = EXTRACT_FILLFILELIST;
399     res = pExtract(&session, "extract.cab");
400     node = session.FileList;
401     ok(res == S_OK, "Expected S_OK, got %d\n", res);
402     ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
403     ok(session.Error.erfOper == FDIERROR_NONE,
404        "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
405     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
406     ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
407     ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
408     ok(session.Operation == EXTRACT_FILLFILELIST,
409        "Expected EXTRACT_FILLFILELIST, got %d\n", session.Operation);
410     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
411     ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
412        "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
413     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
414     ok(!session.FilterList, "Expected empty filter list\n");
415     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
416     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
417     ok(check_list(&node, "testdir\\d.txt", TRUE), "list entry wrong\n");
418     ok(check_list(&node, "testdir\\c.txt", TRUE), "list entry wrong\n");
419     ok(check_list(&node, "b.txt", TRUE), "list entry wrong\n");
420     ok(check_list(&node, "a.txt", TRUE), "list entry wrong\n");
421
422     /* try extract files operation once file list is filled */
423     session.Operation = EXTRACT_EXTRACTFILES;
424     res = pExtract(&session, "extract.cab");
425     node = session.FileList;
426     ok(res == S_OK, "Expected S_OK, got %d\n", res);
427     ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
428     ok(session.Error.erfOper == FDIERROR_NONE,
429        "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
430     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
431     ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
432     ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
433     ok(session.Operation == EXTRACT_EXTRACTFILES,
434        "Expected EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
435     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
436     ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
437        "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
438     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
439     ok(!session.FilterList, "Expected empty filter list\n");
440     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
441     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
442     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
443     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
444     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
445     ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
446     ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
447     ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
448     ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
449     ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");
450
451     /* Extract does not extract files if the dest dir does not exist */
452     res = pExtract(&session, "extract.cab");
453     node = session.FileList;
454     ok(res == S_OK, "Expected S_OK, got %d\n", res);
455     ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
456     ok(session.Error.erfOper == FDIERROR_NONE,
457        "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
458     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
459     ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
460     ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
461     ok(session.Operation == EXTRACT_EXTRACTFILES,
462        "Expected EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
463     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
464     ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
465        "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
466     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
467     ok(!session.FilterList, "Expected empty filter list\n");
468     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
469     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
470     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
471     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
472     ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
473     ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
474     ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
475     ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");
476
477     /* remove two of the files in the list */
478     node = session.FileList->next;
479     session.FileList->next = session.FileList->next->next;
480     free_file_node(node);
481     free_file_node(session.FileList->next->next);
482     session.FileList->next->next = NULL;
483     session.FilterList = NULL;
484     CreateDirectoryA("dest", NULL);
485     res = pExtract(&session, "extract.cab");
486     node = session.FileList;
487     ok(res == S_OK, "Expected S_OK, got %d\n", res);
488     ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
489     ok(session.Error.erfOper == FDIERROR_NONE,
490        "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
491     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
492     ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
493     ok(session.FileCount == 4, "Expected 4, got %d\n", session.FileCount);
494     ok(session.Operation == EXTRACT_EXTRACTFILES,
495        "Expected EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
496     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
497     ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
498        "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
499     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
500     ok(!session.FilterList, "Expected empty filter list\n");
501     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
502     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
503     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
504     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
505     ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
506     ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
507     ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
508     ok(!check_list(&node, "a.txt", FALSE), "list entry wrong\n");
509     free_file_list(&session);
510
511     session.Operation = EXTRACT_FILLFILELIST;
512     session.FileList = NULL;
513     res = pExtract(&session, "extract.cab");
514     node = session.FileList;
515     ok(res == S_OK, "Expected S_OK, got %d\n", res);
516     ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
517     ok(session.Error.erfOper == FDIERROR_NONE,
518        "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
519     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
520     ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
521     ok(session.FileCount == 8, "Expected 8, got %d\n", session.FileCount);
522     ok(session.Operation == EXTRACT_FILLFILELIST,
523        "Expected EXTRACT_FILLFILELIST, got %d\n", session.Operation);
524     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
525     ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
526        "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
527     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
528     ok(!session.FilterList, "Expected empty filter list\n");
529     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
530     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
531     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
532     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
533     ok(check_list(&node, "testdir\\d.txt", TRUE), "list entry wrong\n");
534     ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
535     ok(!check_list(&node, "b.txt", FALSE), "list entry wrong\n");
536     ok(!check_list(&node, "a.txt", FALSE), "list entry wrong\n");
537
538     session.Operation = 0;
539     res = pExtract(&session, "extract.cab");
540     node = session.FileList;
541     ok(res == S_OK, "Expected S_OK, got %d\n", res);
542     ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
543     ok(session.Error.erfOper == FDIERROR_NONE,
544        "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
545     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
546     ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
547     ok(session.FileCount == 8, "Expected 8, got %d\n", session.FileCount);
548     ok(session.Operation == 0, "Expected 0, got %d\n", session.Operation);
549     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
550     ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
551        "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
552     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
553     ok(!session.FilterList, "Expected empty filter list\n");
554     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
555     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
556     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
557     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
558     ok(check_list(&node, "testdir\\d.txt", TRUE), "list entry wrong\n");
559     ok(check_list(&node, "testdir\\c.txt", TRUE), "list entry wrong\n");
560     ok(check_list(&node, "b.txt", TRUE), "list entry wrong\n");
561     ok(check_list(&node, "a.txt", TRUE), "list entry wrong\n");
562
563     session.Operation = 0;
564     session.FilterList = session.FileList;
565     res = pExtract(&session, "extract.cab");
566     node = session.FileList;
567     ok(res == S_OK, "Expected S_OK, got %d\n", res);
568     ok(session.FileSize == 40, "Expected 40, got %d\n", session.FileSize);
569     ok(session.Error.erfOper == FDIERROR_NONE,
570        "Expected FDIERROR_NONE, got %d\n", session.Error.erfOper);
571     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
572     ok(session.Error.fError == FALSE, "Expected FALSE, got %d\n", session.Error.fError);
573     ok(session.FileCount == 8, "Expected 8, got %d\n", session.FileCount);
574     ok(session.Operation == 0, "Expected 0, got %d\n", session.Operation);
575     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
576     ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\d.txt"),
577        "Expected dest\\testdir\\d.txt, got %s\n", session.CurrentFile);
578     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
579     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
580     ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
581     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
582     ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
583     ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
584     ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
585     ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
586     ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");
587     node = session.FilterList;
588     ok(check_list(&node, "testdir\\d.txt", FALSE), "list entry wrong\n");
589     ok(check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
590     ok(check_list(&node, "b.txt", FALSE), "list entry wrong\n");
591     ok(check_list(&node, "a.txt", FALSE), "list entry wrong\n");
592     free_file_list(&session);
593
594     /* cabinet does not exist */
595     ZeroMemory(&session, sizeof(SESSION));
596     lstrcpyA(session.Destination, "dest");
597     session.Operation = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
598     res = pExtract(&session, "nonexistent.cab");
599     node = session.FileList;
600     ok(res == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
601        "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", res);
602     ok(session.Error.erfOper == FDIERROR_CABINET_NOT_FOUND,
603        "Expected FDIERROR_CABINET_NOT_FOUND, got %d\n", session.Error.erfOper);
604     ok(session.FileSize == 0, "Expected 0, got %d\n", session.FileSize);
605     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
606     ok(session.Error.fError == TRUE, "Expected TRUE, got %d\n", session.Error.fError);
607     ok(session.FileCount == 0, "Expected 0, got %d\n", session.FileCount);
608     ok(session.Operation == (EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES),
609        "Expected EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
610     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
611     ok(!*session.CurrentFile, "Expected empty string, got %s\n", session.CurrentFile);
612     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
613     ok(!session.FilterList, "Expected empty filter list\n");
614     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
615     ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
616     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
617     ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
618     ok(!check_list(&node, "testdir\\d.txt", FALSE), "list entry should not exist\n");
619     ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry should not exist\n");
620     ok(!check_list(&node, "b.txt", FALSE), "list entry should not exist\n");
621     ok(!check_list(&node, "a.txt", FALSE), "list entry should not exist\n");
622     free_file_list(&session);
623
624     /* first file exists */
625     createTestFile("dest\\a.txt");
626     SetFileAttributes("dest\\a.txt", FILE_ATTRIBUTE_READONLY);
627     ZeroMemory(&session, sizeof(SESSION));
628     lstrcpyA(session.Destination, "dest");
629     session.Operation = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
630     res = pExtract(&session, "extract.cab");
631     node = session.FileList;
632     todo_wine
633     {
634         ok(res == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) || res == E_FAIL,
635            "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) or E_FAIL, got %08x\n", res);
636         ok(session.FileSize == 6, "Expected 6, got %d\n", session.FileSize);
637         ok(session.Error.erfOper == FDIERROR_USER_ABORT,
638            "Expected FDIERROR_USER_ABORT, got %d\n", session.Error.erfOper);
639         ok(session.Error.fError == TRUE, "Expected TRUE, got %d\n", session.Error.fError);
640         ok(session.FileCount == 1, "Expected 1, got %d\n", session.FileCount);
641         ok(!lstrcmpA(session.CurrentFile, "dest\\a.txt"),
642            "Expected dest\\a.txt, got %s\n", session.CurrentFile);
643     }
644     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
645     ok(session.Operation == (EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES),
646        "Expected EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
647     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
648     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
649     ok(!session.FilterList, "Expected empty filter list\n");
650     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
651     todo_wine
652     {
653         ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
654         ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
655         ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
656         ok(!check_list(&node, "testdir\\d.txt", FALSE), "list entry should not exist\n");
657         ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry should not exist\n");
658         ok(!check_list(&node, "b.txt", FALSE), "list entry should not exist\n");
659     }
660     ok(!check_list(&node, "a.txt", FALSE), "list entry should not exist\n");
661     free_file_list(&session);
662
663     SetFileAttributesA("dest\\a.txt", FILE_ATTRIBUTE_NORMAL);
664     DeleteFileA("dest\\a.txt");
665
666     /* third file exists */
667     createTestFile("dest\\testdir\\c.txt");
668     SetFileAttributes("dest\\testdir\\c.txt", FILE_ATTRIBUTE_READONLY);
669     ZeroMemory(&session, sizeof(SESSION));
670     lstrcpyA(session.Destination, "dest");
671     session.Operation = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
672     res = pExtract(&session, "extract.cab");
673     node = session.FileList;
674     todo_wine
675     {
676         ok(res == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) || res == E_FAIL,
677            "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) or E_FAIL, got %08x\n", res);
678         ok(session.FileSize == 26, "Expected 26, got %d\n", session.FileSize);
679         ok(session.Error.erfOper == FDIERROR_USER_ABORT,
680            "Expected FDIERROR_USER_ABORT, got %d\n", session.Error.erfOper);
681         ok(session.Error.fError == TRUE, "Expected TRUE, got %d\n", session.Error.fError);
682         ok(session.FileCount == 3, "Expected 3, got %d\n", session.FileCount);
683         ok(!lstrcmpA(session.CurrentFile, "dest\\testdir\\c.txt"),
684            "Expected dest\\c.txt, got %s\n", session.CurrentFile);
685     }
686     ok(session.Error.erfType == 0, "Expected 0, got %d\n", session.Error.erfType);
687     ok(session.Operation == (EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES),
688        "Expected EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES, got %d\n", session.Operation);
689     ok(!lstrcmpA(session.Destination, "dest"), "Expected dest, got %s\n", session.Destination);
690     ok(!*session.Reserved, "Expected empty string, got %s\n", session.Reserved);
691     ok(!session.FilterList, "Expected empty filter list\n");
692     ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
693     ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
694     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
695     todo_wine
696     {
697         ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
698         ok(!check_list(&node, "testdir\\d.txt", FALSE), "list entry should not exist\n");
699     }
700     ok(!check_list(&node, "testdir\\c.txt", FALSE), "list entry wrong\n");
701     ok(!check_list(&node, "b.txt", FALSE), "list entry wrong\n");
702     ok(!check_list(&node, "a.txt", TRUE), "list entry wrong\n");
703     free_file_list(&session);
704
705     SetFileAttributesA("dest\\testdir\\c.txt", FILE_ATTRIBUTE_NORMAL);
706     DeleteFileA("dest\\testdir\\c.txt");
707
708     ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
709     ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
710 }
711
712 START_TEST(extract)
713 {
714     init_function_pointers();
715     create_test_files();
716     create_cab_file();
717
718     test_Extract();
719
720     delete_test_files();
721 }