winecfg: Added missing break (Coverity).
[wine] / dlls / cabinet / tests / fdi.c
1 /*
2  * Unit tests for the File Decompression Interface
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 static CHAR CURR_DIR[MAX_PATH];
32
33 /* FDI callbacks */
34
35 static void * CDECL fdi_alloc(ULONG cb)
36 {
37     return HeapAlloc(GetProcessHeap(), 0, cb);
38 }
39
40 static void * CDECL fdi_alloc_bad(ULONG cb)
41 {
42     return NULL;
43 }
44
45 static void CDECL fdi_free(void *pv)
46 {
47     HeapFree(GetProcessHeap(), 0, pv);
48 }
49
50 static INT_PTR CDECL fdi_open(char *pszFile, int oflag, int pmode)
51 {
52     HANDLE handle;
53     handle = CreateFileA(pszFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
54                           OPEN_EXISTING, 0, NULL );
55     if (handle == INVALID_HANDLE_VALUE)
56         return 0;
57     return (INT_PTR) handle;
58 }
59
60 static UINT CDECL fdi_read(INT_PTR hf, void *pv, UINT cb)
61 {
62     HANDLE handle = (HANDLE) hf;
63     DWORD dwRead;
64     if (ReadFile(handle, pv, cb, &dwRead, NULL))
65         return dwRead;
66     return 0;
67 }
68
69 static UINT CDECL fdi_write(INT_PTR hf, void *pv, UINT cb)
70 {
71     HANDLE handle = (HANDLE) hf;
72     DWORD dwWritten;
73     if (WriteFile(handle, pv, cb, &dwWritten, NULL))
74         return dwWritten;
75     return 0;
76 }
77
78 static int CDECL fdi_close(INT_PTR hf)
79 {
80     HANDLE handle = (HANDLE) hf;
81     return CloseHandle(handle) ? 0 : -1;
82 }
83
84 static LONG CDECL fdi_seek(INT_PTR hf, LONG dist, int seektype)
85 {
86     HANDLE handle = (HANDLE) hf;
87     return SetFilePointer(handle, dist, NULL, seektype);
88 }
89
90 static void test_FDICreate(void)
91 {
92     HFDI hfdi;
93     ERF erf;
94
95     /* native crashes if pfnalloc is NULL */
96
97     /* FDICreate does not crash with a NULL pfnfree,
98      * but FDIDestroy will crash when it tries to access it.
99      */
100     if (0)
101     {
102         SetLastError(0xdeadbeef);
103         erf.erfOper = 0x1abe11ed;
104         erf.erfType = 0x5eed1e55;
105         erf.fError = 0x1ead1e55;
106         hfdi = FDICreate(fdi_alloc, NULL, fdi_open, fdi_read,
107                          fdi_write, fdi_close, fdi_seek,
108                          cpuUNKNOWN, &erf);
109         ok(hfdi != NULL, "Expected non-NULL context\n");
110         ok(GetLastError() == 0xdeadbeef,
111            "Expected 0xdeadbeef, got %d\n", GetLastError());
112         ok(erf.erfOper == 0x1abe11ed, "Expected 0x1abe11ed, got %d\n", erf.erfOper);
113         ok(erf.erfType == 0x5eed1e55, "Expected 0x5eed1e55, got %d\n", erf.erfType);
114         ok(erf.fError == 0x1ead1e55, "Expected 0x1ead1e55, got %d\n", erf.fError);
115
116         FDIDestroy(hfdi);
117     }
118
119     SetLastError(0xdeadbeef);
120     erf.erfOper = 0x1abe11ed;
121     erf.erfType = 0x5eed1e55;
122     erf.fError = 0x1ead1e55;
123     hfdi = FDICreate(fdi_alloc, fdi_free, NULL, fdi_read,
124                      fdi_write, fdi_close, fdi_seek,
125                      cpuUNKNOWN, &erf);
126     ok(hfdi != NULL, "Expected non-NULL context\n");
127     ok(GetLastError() == 0xdeadbeef,
128        "Expected 0xdeadbeef, got %d\n", GetLastError());
129     ok((erf.erfOper == 0x1abe11ed || erf.erfOper == 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf.erfOper);
130     ok((erf.erfType == 0x5eed1e55 || erf.erfType == 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf.erfType);
131     ok((erf.fError == 0x1ead1e55 || erf.fError == 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf.fError);
132
133     FDIDestroy(hfdi);
134
135     SetLastError(0xdeadbeef);
136     erf.erfOper = 0x1abe11ed;
137     erf.erfType = 0x5eed1e55;
138     erf.fError = 0x1ead1e55;
139     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, NULL,
140                      fdi_write, fdi_close, fdi_seek,
141                      cpuUNKNOWN, &erf);
142     ok(hfdi != NULL, "Expected non-NULL context\n");
143     ok(GetLastError() == 0xdeadbeef,
144        "Expected 0xdeadbeef, got %d\n", GetLastError());
145     ok((erf.erfOper == 0x1abe11ed || erf.erfOper == 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf.erfOper);
146     ok((erf.erfType == 0x5eed1e55 || erf.erfType == 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf.erfType);
147     ok((erf.fError == 0x1ead1e55 || erf.fError == 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf.fError);
148
149     FDIDestroy(hfdi);
150
151     SetLastError(0xdeadbeef);
152     erf.erfOper = 0x1abe11ed;
153     erf.erfType = 0x5eed1e55;
154     erf.fError = 0x1ead1e55;
155     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
156                      NULL, fdi_close, fdi_seek,
157                      cpuUNKNOWN, &erf);
158     ok(hfdi != NULL, "Expected non-NULL context\n");
159     ok(GetLastError() == 0xdeadbeef,
160        "Expected 0xdeadbeef, got %d\n", GetLastError());
161     ok((erf.erfOper == 0x1abe11ed || erf.erfOper == 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf.erfOper);
162     ok((erf.erfType == 0x5eed1e55 || erf.erfType == 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf.erfType);
163     ok((erf.fError == 0x1ead1e55 || erf.fError == 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf.fError);
164
165     FDIDestroy(hfdi);
166
167     SetLastError(0xdeadbeef);
168     erf.erfOper = 0x1abe11ed;
169     erf.erfType = 0x5eed1e55;
170     erf.fError = 0x1ead1e55;
171     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
172                      fdi_write, NULL, fdi_seek,
173                      cpuUNKNOWN, &erf);
174     ok(hfdi != NULL, "Expected non-NULL context\n");
175     ok(GetLastError() == 0xdeadbeef,
176        "Expected 0xdeadbeef, got %d\n", GetLastError());
177     ok((erf.erfOper == 0x1abe11ed || erf.erfOper == 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf.erfOper);
178     ok((erf.erfType == 0x5eed1e55 || erf.erfType == 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf.erfType);
179     ok((erf.fError == 0x1ead1e55 || erf.fError == 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf.fError);
180
181     FDIDestroy(hfdi);
182
183     SetLastError(0xdeadbeef);
184     erf.erfOper = 0x1abe11ed;
185     erf.erfType = 0x5eed1e55;
186     erf.fError = 0x1ead1e55;
187     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
188                      fdi_write, fdi_close, NULL,
189                      cpuUNKNOWN, &erf);
190     ok(hfdi != NULL, "Expected non-NULL context\n");
191     ok(GetLastError() == 0xdeadbeef,
192        "Expected 0xdeadbeef, got %d\n", GetLastError());
193     ok((erf.erfOper == 0x1abe11ed || erf.erfOper == 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf.erfOper);
194     ok((erf.erfType == 0x5eed1e55 || erf.erfType == 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf.erfType);
195     ok((erf.fError == 0x1ead1e55 || erf.fError == 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf.fError);
196
197     FDIDestroy(hfdi);
198
199     SetLastError(0xdeadbeef);
200     erf.erfOper = 0x1abe11ed;
201     erf.erfType = 0x5eed1e55;
202     erf.fError = 0x1ead1e55;
203     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
204                      fdi_write, fdi_close, fdi_seek,
205                      cpuUNKNOWN, NULL);
206     /* XP sets hfdi to a non-NULL value, but Vista sets it to NULL! */
207     ok(GetLastError() == 0xdeadbeef,
208        "Expected 0xdeadbeef, got %d\n", GetLastError());
209     /* NULL is passed to FDICreate instead of &erf, so don't retest the erf member values. */
210
211     FDIDestroy(hfdi);
212
213     /* bad cpu type */
214     SetLastError(0xdeadbeef);
215     erf.erfOper = 0x1abe11ed;
216     erf.erfType = 0x5eed1e55;
217     erf.fError = 0x1ead1e55;
218     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
219                      fdi_write, fdi_close, fdi_seek,
220                      0xcafebabe, &erf);
221     ok(hfdi != NULL, "Expected non-NULL context\n");
222     ok(GetLastError() == 0xdeadbeef,
223        "Expected 0xdeadbeef, got %d\n", GetLastError());
224     ok((erf.erfOper == 0x1abe11ed || erf.erfOper == 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf.erfOper);
225     ok((erf.erfType == 0x5eed1e55 || erf.erfType == 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf.erfType);
226     ok((erf.fError == 0x1ead1e55 || erf.fError == 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf.fError);
227
228     FDIDestroy(hfdi);
229
230     /* pfnalloc fails */
231     SetLastError(0xdeadbeef);
232     erf.erfOper = 0x1abe11ed;
233     erf.erfType = 0x5eed1e55;
234     erf.fError = 0x1ead1e55;
235     hfdi = FDICreate(fdi_alloc_bad, fdi_free, fdi_open, fdi_read,
236                      fdi_write, fdi_close, fdi_seek,
237                      cpuUNKNOWN, &erf);
238     ok(hfdi == NULL, "Expected NULL context, got %p\n", hfdi);
239     ok(erf.erfOper == FDIERROR_ALLOC_FAIL,
240        "Expected FDIERROR_ALLOC_FAIL, got %d\n", erf.erfOper);
241     ok(erf.fError == TRUE, "Expected TRUE, got %d\n", erf.fError);
242     ok(GetLastError() == 0xdeadbeef,
243        "Expected 0xdeadbeef, got %d\n", GetLastError());
244     ok(erf.erfType == 0, "Expected 0, got %d\n", erf.erfType);
245 }
246
247 static void test_FDIDestroy(void)
248 {
249     HFDI hfdi;
250     ERF erf;
251     BOOL ret;
252
253     /* native crashes if hfdi is NULL or invalid */
254
255     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
256                      fdi_write, fdi_close, fdi_seek,
257                      cpuUNKNOWN, &erf);
258     ok(hfdi != NULL, "Expected non-NULL context\n");
259
260     /* successfully destroy hfdi */
261     ret = FDIDestroy(hfdi);
262     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
263
264     /* native crashes if you try to destroy hfdi twice */
265     if (0)
266     {
267         /* try to destroy hfdi again */
268         ret = FDIDestroy(hfdi);
269         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
270     }
271 }
272
273 static void createTestFile(const CHAR *name)
274 {
275     HANDLE file;
276     DWORD written;
277
278     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
279     ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
280     WriteFile(file, name, strlen(name), &written, NULL);
281     WriteFile(file, "\n", strlen("\n"), &written, NULL);
282     CloseHandle(file);
283 }
284
285 static void create_test_files(void)
286 {
287     DWORD len;
288
289     len = GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
290
291     if(len && (CURR_DIR[len-1] == '\\'))
292         CURR_DIR[len-1] = 0;
293
294     createTestFile("a.txt");
295     createTestFile("b.txt");
296     CreateDirectoryA("testdir", NULL);
297     createTestFile("testdir\\c.txt");
298     createTestFile("testdir\\d.txt");
299 }
300
301 static void delete_test_files(void)
302 {
303     DeleteFileA("a.txt");
304     DeleteFileA("b.txt");
305     DeleteFileA("testdir\\c.txt");
306     DeleteFileA("testdir\\d.txt");
307     RemoveDirectoryA("testdir");
308
309     DeleteFileA("extract.cab");
310 }
311
312 /* FCI callbacks */
313
314 static void * CDECL mem_alloc(ULONG cb)
315 {
316     return HeapAlloc(GetProcessHeap(), 0, cb);
317 }
318
319 static void CDECL mem_free(void *memory)
320 {
321     HeapFree(GetProcessHeap(), 0, memory);
322 }
323
324 static BOOL CDECL get_next_cabinet(PCCAB pccab, ULONG  cbPrevCab, void *pv)
325 {
326     return TRUE;
327 }
328
329 static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv)
330 {
331     return 0;
332 }
333
334 static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile,
335                              BOOL fContinuation, void *pv)
336 {
337     return 0;
338 }
339
340 static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv)
341 {
342     HANDLE handle;
343     DWORD dwAccess = 0;
344     DWORD dwShareMode = 0;
345     DWORD dwCreateDisposition = OPEN_EXISTING;
346
347     dwAccess = GENERIC_READ | GENERIC_WRITE;
348     /* FILE_SHARE_DELETE is not supported by Windows Me/98/95 */
349     dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
350
351     if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
352         dwCreateDisposition = OPEN_EXISTING;
353     else
354         dwCreateDisposition = CREATE_NEW;
355
356     handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
357                          dwCreateDisposition, 0, NULL);
358
359     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszFile);
360
361     return (INT_PTR)handle;
362 }
363
364 static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
365 {
366     HANDLE handle = (HANDLE)hf;
367     DWORD dwRead;
368     BOOL res;
369
370     res = ReadFile(handle, memory, cb, &dwRead, NULL);
371     ok(res, "Failed to ReadFile\n");
372
373     return dwRead;
374 }
375
376 static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
377 {
378     HANDLE handle = (HANDLE)hf;
379     DWORD dwWritten;
380     BOOL res;
381
382     res = WriteFile(handle, memory, cb, &dwWritten, NULL);
383     ok(res, "Failed to WriteFile\n");
384
385     return dwWritten;
386 }
387
388 static int CDECL fci_close(INT_PTR hf, int *err, void *pv)
389 {
390     HANDLE handle = (HANDLE)hf;
391     ok(CloseHandle(handle), "Failed to CloseHandle\n");
392
393     return 0;
394 }
395
396 static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv)
397 {
398     HANDLE handle = (HANDLE)hf;
399     DWORD ret;
400
401     ret = SetFilePointer(handle, dist, NULL, seektype);
402     ok(ret != INVALID_SET_FILE_POINTER, "Failed to SetFilePointer\n");
403
404     return ret;
405 }
406
407 static int CDECL fci_delete(char *pszFile, int *err, void *pv)
408 {
409     BOOL ret = DeleteFileA(pszFile);
410     ok(ret, "Failed to DeleteFile %s\n", pszFile);
411
412     return 0;
413 }
414
415 static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv)
416 {
417     LPSTR tempname;
418
419     tempname = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
420     GetTempFileNameA(".", "xx", 0, tempname);
421
422     if (tempname && (strlen(tempname) < (unsigned)cbTempName))
423     {
424         lstrcpyA(pszTempName, tempname);
425         HeapFree(GetProcessHeap(), 0, tempname);
426         return TRUE;
427     }
428
429     HeapFree(GetProcessHeap(), 0, tempname);
430
431     return FALSE;
432 }
433
434 static INT_PTR CDECL get_open_info(char *pszName, USHORT *pdate, USHORT *ptime,
435                                    USHORT *pattribs, int *err, void *pv)
436 {
437     BY_HANDLE_FILE_INFORMATION finfo;
438     FILETIME filetime;
439     HANDLE handle;
440     DWORD attrs;
441     BOOL res;
442
443     handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
444                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
445
446     ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszName);
447
448     res = GetFileInformationByHandle(handle, &finfo);
449     ok(res, "Expected GetFileInformationByHandle to succeed\n");
450
451     FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime);
452     FileTimeToDosDateTime(&filetime, pdate, ptime);
453
454     attrs = GetFileAttributes(pszName);
455     ok(attrs != INVALID_FILE_ATTRIBUTES, "Failed to GetFileAttributes\n");
456     /* fixme: should convert attrs to *pattribs, make sure
457      * have a test that catches the fact that we don't?
458      */
459
460     return (INT_PTR)handle;
461 }
462
463 static void add_file(HFCI hfci, char *file)
464 {
465     char path[MAX_PATH];
466     BOOL res;
467
468     lstrcpyA(path, CURR_DIR);
469     lstrcatA(path, "\\");
470     lstrcatA(path, file);
471
472     res = FCIAddFile(hfci, path, file, FALSE, get_next_cabinet, progress,
473                      get_open_info, tcompTYPE_MSZIP);
474     ok(res, "Expected FCIAddFile to succeed\n");
475 }
476
477 static void set_cab_parameters(PCCAB pCabParams)
478 {
479     ZeroMemory(pCabParams, sizeof(CCAB));
480
481     pCabParams->cb = MEDIA_SIZE;
482     pCabParams->cbFolderThresh = FOLDER_THRESHOLD;
483     pCabParams->setID = 0xbeef;
484     lstrcpyA(pCabParams->szCabPath, CURR_DIR);
485     lstrcatA(pCabParams->szCabPath, "\\");
486     lstrcpyA(pCabParams->szCab, "extract.cab");
487 }
488
489 static void create_cab_file(void)
490 {
491     CCAB cabParams;
492     HFCI hfci;
493     ERF erf;
494     static CHAR a_txt[]         = "a.txt",
495                 b_txt[]         = "b.txt",
496                 testdir_c_txt[] = "testdir\\c.txt",
497                 testdir_d_txt[] = "testdir\\d.txt";
498     BOOL res;
499
500     set_cab_parameters(&cabParams);
501
502     hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
503                       fci_read, fci_write, fci_close, fci_seek, fci_delete,
504                       get_temp_file, &cabParams, NULL);
505
506     ok(hfci != NULL, "Failed to create an FCI context\n");
507
508     add_file(hfci, a_txt);
509     add_file(hfci, b_txt);
510     add_file(hfci, testdir_c_txt);
511     add_file(hfci, testdir_d_txt);
512
513     res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
514     ok(res, "Failed to flush the cabinet\n");
515
516     res = FCIDestroy(hfci);
517     ok(res, "Failed to destroy the cabinet\n");
518 }
519
520 static void test_FDIIsCabinet(void)
521 {
522     ERF erf;
523     BOOL ret;
524     HFDI hfdi;
525     INT_PTR fd;
526     FDICABINETINFO cabinfo;
527     char temp[] = "temp.txt";
528     char extract[] = "extract.cab";
529
530     create_test_files();
531     create_cab_file();
532
533     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
534                      fdi_write, fdi_close, fdi_seek,
535                      cpuUNKNOWN, &erf);
536     ok(hfdi != NULL, "Expected non-NULL context\n");
537
538     /* native crashes if hfdi or cabinfo are NULL or invalid */
539
540     /* invalid file handle */
541     ZeroMemory(&cabinfo, sizeof(FDICABINETINFO));
542     SetLastError(0xdeadbeef);
543     ret = FDIIsCabinet(hfdi, -1, &cabinfo);
544     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
545     ok(GetLastError() == ERROR_INVALID_HANDLE,
546        "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
547     ok(cabinfo.cbCabinet == 0, "Expected 0, got %d\n", cabinfo.cbCabinet);
548     ok(cabinfo.cFiles == 0, "Expected 0, got %d\n", cabinfo.cFiles);
549     ok(cabinfo.cFolders == 0, "Expected 0, got %d\n", cabinfo.cFolders);
550     ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet);
551     ok(cabinfo.setID == 0, "Expected 0, got %d\n", cabinfo.setID);
552
553     createTestFile("temp.txt");
554     fd = fdi_open(temp, 0, 0);
555
556     /* file handle doesn't point to a cabinet */
557     ZeroMemory(&cabinfo, sizeof(FDICABINETINFO));
558     SetLastError(0xdeadbeef);
559     ret = FDIIsCabinet(hfdi, fd, &cabinfo);
560     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
561     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
562     ok(cabinfo.cbCabinet == 0, "Expected 0, got %d\n", cabinfo.cbCabinet);
563     ok(cabinfo.cFiles == 0, "Expected 0, got %d\n", cabinfo.cFiles);
564     ok(cabinfo.cFolders == 0, "Expected 0, got %d\n", cabinfo.cFolders);
565     ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet);
566     ok(cabinfo.setID == 0, "Expected 0, got %d\n", cabinfo.setID);
567
568     fdi_close(fd);
569     DeleteFileA("temp.txt");
570
571     /* try a real cab */
572     fd = fdi_open(extract, 0, 0);
573     ZeroMemory(&cabinfo, sizeof(FDICABINETINFO));
574     SetLastError(0xdeadbeef);
575     ret = FDIIsCabinet(hfdi, fd, &cabinfo);
576     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
577     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
578     ok(cabinfo.cFiles == 4, "Expected 4, got %d\n", cabinfo.cFiles);
579     ok(cabinfo.cFolders == 1, "Expected 1, got %d\n", cabinfo.cFolders);
580     ok(cabinfo.setID == 0xbeef, "Expected 0xbeef, got %d\n", cabinfo.setID);
581     ok(cabinfo.cbCabinet == 182, "Expected 182, got %d\n", cabinfo.cbCabinet);
582     ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet);
583
584     fdi_close(fd);
585     FDIDestroy(hfdi);
586     delete_test_files();
587 }
588
589
590 static INT_PTR __cdecl CopyProgress(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
591 {
592     return 0;
593 }
594
595 static void test_FDICopy(void)
596 {
597     CCAB cabParams;
598     HFDI hfdi;
599     HFCI hfci;
600     ERF erf;
601     BOOL ret;
602     char name[] = "extract.cab";
603     char path[MAX_PATH + 1];
604
605     set_cab_parameters(&cabParams);
606
607     hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
608                      fci_read, fci_write, fci_close, fci_seek,
609                      fci_delete, get_temp_file, &cabParams, NULL);
610
611     ret = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
612     ok(ret, "Failed to flush the cabinet\n");
613
614     FCIDestroy(hfci);
615
616     lstrcpyA(path, CURR_DIR);
617
618     /* path doesn't have a trailing backslash */
619     if (lstrlenA(path) > 2)
620     {
621         hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
622                          fdi_write, fdi_close, fdi_seek,
623                          cpuUNKNOWN, &erf);
624
625         SetLastError(0xdeadbeef);
626         ret = FDICopy(hfdi, name, path, 0, CopyProgress, NULL, 0);
627         ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
628         ok(GetLastError() == ERROR_INVALID_HANDLE,
629            "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
630
631         FDIDestroy(hfdi);
632     }
633     else
634         skip("Running on a root drive directory.\n");
635
636     lstrcatA(path, "\\");
637
638     hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
639                      fdi_write, fdi_close, fdi_seek,
640                      cpuUNKNOWN, &erf);
641
642     /* cabinet with no files or folders */
643     SetLastError(0xdeadbeef);
644     ret = FDICopy(hfdi, name, path, 0, CopyProgress, NULL, 0);
645     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
646     ok(GetLastError() == 0, "Expected 0f, got %d\n", GetLastError());
647
648     FDIDestroy(hfdi);
649
650     DeleteFileA(name);
651 }
652
653
654 START_TEST(fdi)
655 {
656     test_FDICreate();
657     test_FDIDestroy();
658     test_FDIIsCabinet();
659     test_FDICopy();
660 }