cmd.exe: Support cd .. when saving current directory.
[wine] / dlls / setupapi / setupcab.c
1 /* 
2  * Setupapi cabinet routines
3  *
4  * Copyright 2003 Gregory M. Turner
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  * Many useful traces are commented in code, uncomment them if you have
22  * trouble and run with WINEDEBUG=+setupapi
23  * 
24  */
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winnls.h"
35 #include "winreg.h"
36 #include "setupapi.h"
37 #include "setupapi_private.h"
38 #include "fdi.h"
39 #include "wine/unicode.h"
40
41 #include "msvcrt/fcntl.h"
42 #include "msvcrt/share.h"
43
44 #include "wine/debug.h"
45
46 OSVERSIONINFOW OsVersionInfo;
47
48 static HINSTANCE CABINET_hInstance = 0;
49
50 static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN,
51                 PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF);
52
53 static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int,
54                 PFNFDINOTIFY, PFNFDIDECRYPT, void *);
55
56 static BOOL (__cdecl *sc_FDIDestroy)(HFDI);
57
58 #define SC_HSC_A_MAGIC 0xACABFEED
59 typedef struct {
60   UINT magic;
61   HFDI hfdi;
62   PSP_FILE_CALLBACK_A msghandler;
63   PVOID context;
64   CHAR most_recent_cabinet_name[MAX_PATH];
65 } SC_HSC_A, *PSC_HSC_A;
66
67 #define SC_HSC_W_MAGIC 0x0CABFEED
68 typedef struct {
69   UINT magic;
70   HFDI hfdi;
71   PSP_FILE_CALLBACK_W msghandler;
72   PVOID context;
73   WCHAR most_recent_cabinet_name[MAX_PATH];
74 } SC_HSC_W, *PSC_HSC_W;
75
76 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
77
78 static BOOL LoadCABINETDll(void)
79 {
80   if (!CABINET_hInstance) {
81     CABINET_hInstance = LoadLibraryA("cabinet.dll");
82     if (CABINET_hInstance)  {
83       sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate");
84       sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy");
85       sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy");
86       return TRUE;
87     } else {
88       ERR("load cabinet dll failed.\n");
89       return FALSE;
90     }
91   } else
92     return TRUE;
93 }
94
95 static void UnloadCABINETDll(void)
96 {
97   if (CABINET_hInstance) {
98     FreeLibrary(CABINET_hInstance);
99     CABINET_hInstance = 0;
100   }
101 }
102
103 /* FDICreate callbacks */
104
105 static void *sc_cb_alloc(ULONG cb)
106 {
107   return HeapAlloc(GetProcessHeap(), 0, cb);
108 }
109
110 static void sc_cb_free(void *pv)
111 {
112   HeapFree(GetProcessHeap(), 0, pv);
113 }
114
115 static INT_PTR sc_cb_open(char *pszFile, int oflag, int pmode)
116 {
117   DWORD creation = 0, sharing = 0;
118   int ioflag = 0;
119   INT_PTR ret = 0;
120   SECURITY_ATTRIBUTES sa;
121
122   /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
123
124   switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
125   case _O_RDONLY:
126     ioflag |= GENERIC_READ;
127     break;
128   case _O_WRONLY:
129     ioflag |= GENERIC_WRITE;
130     break;
131   case _O_RDWR:
132     ioflag |= GENERIC_READ & GENERIC_WRITE;
133     break;
134   case _O_WRONLY | _O_RDWR: /* hmmm.. */
135     ERR("_O_WRONLY & _O_RDWR in oflag?\n");
136     return -1;
137   }
138
139   if (oflag & _O_CREAT) {
140     if (oflag & _O_EXCL)
141       creation = CREATE_NEW;
142     else if (oflag & _O_TRUNC)
143       creation = CREATE_ALWAYS;
144     else
145       creation = OPEN_ALWAYS;
146   } else  /* no _O_CREAT */ {
147     if (oflag & _O_TRUNC)
148       creation = TRUNCATE_EXISTING;
149     else
150       creation = OPEN_EXISTING;
151   }
152
153   switch( pmode & 0x70 ) {
154     case _SH_DENYRW:
155       sharing = 0L;
156       break;
157     case _SH_DENYWR:
158       sharing = FILE_SHARE_READ;
159       break;
160     case _SH_DENYRD:
161       sharing = FILE_SHARE_WRITE;
162       break;
163     case _SH_COMPAT:
164     case _SH_DENYNO:
165       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
166       break;
167     default:
168       ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode);
169       return -1;
170   }
171
172   if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT))
173     WARN("unsupported oflag 0x%04x\n",oflag);
174
175   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
176   sa.lpSecurityDescriptor = NULL;
177   sa.bInheritHandle       = (ioflag & _O_NOINHERIT) ? FALSE : TRUE;
178
179   ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
180
181   /* TRACE("<-- %d\n", ret); */
182
183   return ret;
184 }
185
186 static UINT sc_cb_read(INT_PTR hf, void *pv, UINT cb)
187 {
188   DWORD num_read;
189   BOOL rslt;
190
191   /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
192
193   rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
194
195
196   /* eof and failure both give "-1" return */
197   if ((! rslt) || ((cb > 0) && (num_read == 0))) {
198     /* TRACE("<-- -1\n"); */
199     return -1;
200   }
201
202   /* TRACE("<-- %lu\n", num_read); */
203   return num_read;
204 }
205
206 static UINT sc_cb_write(INT_PTR hf, void *pv, UINT cb)
207 {
208   DWORD num_written;
209   /* BOOL rv; */
210
211   /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
212
213   if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */
214        && (num_written == cb)) {
215     /* TRACE("<-- %lu\n", num_written); */
216     return num_written;
217   } else {
218     /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
219     /* TRACE("<-- -1\n"); */
220     return -1;
221   }
222 }
223
224 static int sc_cb_close(INT_PTR hf)
225 {
226   /* TRACE("(hf == %d)\n", hf); */
227
228   if (CloseHandle((HANDLE) hf))
229     return 0;
230   else
231     return -1;
232 }
233
234 static long sc_cb_lseek(INT_PTR hf, long dist, int seektype)
235 {
236   DWORD ret;
237
238   /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
239
240   if (seektype < 0 || seektype > 2)
241     return -1;
242
243   if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) {
244     /* TRACE("<-- %lu\n", ret); */
245     return ret;
246   } else {
247     /* TRACE("<-- -1\n"); */
248     return -1;
249   }
250 }
251
252 #define SIZEOF_MYSTERIO (MAX_PATH*3)
253
254 /* FDICopy callbacks */
255
256 static INT_PTR sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
257 {
258   FILE_IN_CABINET_INFO_A fici;
259   PSC_HSC_A phsc;
260   CABINET_INFO_A ci;
261   FILEPATHS_A fp;
262   UINT err;
263
264   CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
265
266   memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO);
267
268   TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
269
270   if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_A_MAGIC))
271     phsc = (PSC_HSC_A) pfdin->pv;
272   else {
273     ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL);
274     return -1;
275   }
276
277   switch (fdint) {
278   case fdintCABINET_INFO:
279     TRACE("Cabinet info notification\n");
280     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
281     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
282     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
283     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
284     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
285     WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
286     ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
287     ci.CabinetPath = pfdin->psz3;
288     ci.DiskName = pfdin->psz2;
289     ci.SetId = pfdin->setID;
290     ci.CabinetNumber = pfdin->iCabinet;
291     phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0);
292     return 0;
293   case fdintPARTIAL_FILE:
294     TRACE("Partial file notification\n");
295     /* TRACE("  Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
296     return 0;
297   case fdintCOPY_FILE:
298     TRACE("Copy file notification\n");
299     TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
300     /* TRACE("  File size: %ld\n", pfdin->cb);
301     TRACE("  File date: %u\n", pfdin->date);
302     TRACE("  File time: %u\n", pfdin->time);
303     TRACE("  File attr: %u\n", pfdin->attribs); */
304     fici.NameInCabinet = pfdin->psz1;
305     fici.FileSize = pfdin->cb;
306     fici.Win32Error = 0;
307     fici.DosDate = pfdin->date;
308     fici.DosTime = pfdin->time;
309     fici.DosAttribs = pfdin->attribs;
310     memset(&(fici.FullTargetName[0]), 0, MAX_PATH);
311     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
312                            (UINT) &fici, (UINT) pfdin->psz1);
313     if (err == FILEOP_DOIT) {
314       TRACE("  Callback specified filename: %s\n", debugstr_a(&(fici.FullTargetName[0])));
315       if (!fici.FullTargetName[0]) {
316         WARN("  Empty return string causing abort.\n");
317         SetLastError(ERROR_PATH_NOT_FOUND);
318         return -1;
319       }
320       return sc_cb_open(&(fici.FullTargetName[0]), _O_BINARY | _O_CREAT | _O_WRONLY,  _S_IREAD | _S_IWRITE);
321     } else {
322       TRACE("  Callback skipped file.\n");
323       return 0;
324     }
325   case fdintCLOSE_FILE_INFO:
326     TRACE("Close file notification\n");
327     /* TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
328     TRACE("  Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
329     TRACE("  File hndl: %d\n", pfdin->hf); */
330     fp.Source = &(phsc->most_recent_cabinet_name[0]);
331     fp.Target = pfdin->psz1;
332     fp.Win32Error = 0;
333     fp.Flags = 0;
334     /* the following should be a fixme -- but it occurs too many times */
335     WARN("Should set file date/time/attribs (and execute files?)\n");
336     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0);
337     if (sc_cb_close(pfdin->hf))
338       WARN("_close failed.\n");
339     if (err) {
340       SetLastError(err);
341       return FALSE;
342     } else
343       return TRUE;
344   case fdintNEXT_CABINET:
345     TRACE("Next cabinet notification\n");
346     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
347     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
348     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
349     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
350     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
351     ci.CabinetFile = pfdin->psz1;
352     ci.CabinetPath = pfdin->psz3;
353     ci.DiskName = pfdin->psz2;
354     ci.SetId = pfdin->setID;
355     ci.CabinetNumber = pfdin->iCabinet;
356     /* remember the new cabinet name */
357     strcpy(&(phsc->most_recent_cabinet_name[0]), pfdin->psz1);
358     err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0]));
359     if (err) {
360       SetLastError(err);
361       return -1;
362     } else {
363       if (mysterio[0]) {
364         /* some easy paranoia.  no such carefulness exists on the wide API IIRC */
365         lstrcpynA(pfdin->psz3, &(mysterio[0]), SIZEOF_MYSTERIO);
366       }
367       return 0;
368     }
369   default:
370     FIXME("Unknown notification type %d.\n", fdint);
371     return 0;
372   }
373 }
374
375 static INT_PTR sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
376 {
377   FILE_IN_CABINET_INFO_W fici;
378   PSC_HSC_W phsc;
379   CABINET_INFO_W ci;
380   FILEPATHS_W fp;
381   UINT err;
382   int len;
383
384   WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
385   WCHAR buf[MAX_PATH], buf2[MAX_PATH];
386   CHAR charbuf[MAX_PATH];
387
388   memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
389   memset(&(buf[0]), 0, MAX_PATH * sizeof(WCHAR));
390   memset(&(buf2[0]), 0, MAX_PATH * sizeof(WCHAR));
391   memset(&(charbuf[0]), 0, MAX_PATH);
392
393   TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
394
395   if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_W_MAGIC))
396     phsc = (PSC_HSC_W) pfdin->pv;
397   else {
398     ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
399     return -1;
400   }
401
402   switch (fdint) {
403   case fdintCABINET_INFO:
404     TRACE("Cabinet info notification\n");
405     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
406     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
407     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
408     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
409     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
410     WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
411     ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
412     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
413     if ((len > MAX_PATH) || (len <= 1))
414       buf[0] = '\0';
415     ci.CabinetPath = &(buf[0]);
416     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
417     if ((len > MAX_PATH) || (len <= 1))
418       buf2[0] = '\0';
419     ci.DiskName = &(buf2[0]);
420     ci.SetId = pfdin->setID;
421     ci.CabinetNumber = pfdin->iCabinet;
422     phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0);
423     return 0;
424   case fdintPARTIAL_FILE:
425     TRACE("Partial file notification\n");
426     /* TRACE("  Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
427     return 0;
428   case fdintCOPY_FILE:
429     TRACE("Copy file notification\n");
430     TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
431     /* TRACE("  File size: %ld\n", pfdin->cb);
432     TRACE("  File date: %u\n", pfdin->date);
433     TRACE("  File time: %u\n", pfdin->time);
434     TRACE("  File attr: %u\n", pfdin->attribs); */
435     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf2[0]), MAX_PATH);
436     if ((len > MAX_PATH) || (len <= 1))
437       buf2[0] = '\0';
438     fici.NameInCabinet = &(buf2[0]);
439     fici.FileSize = pfdin->cb;
440     fici.Win32Error = 0;
441     fici.DosDate = pfdin->date;
442     fici.DosTime = pfdin->time;
443     fici.DosAttribs = pfdin->attribs;
444     memset(&(fici.FullTargetName[0]), 0, MAX_PATH * sizeof(WCHAR));
445     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
446                            (UINT) &fici, (UINT) pfdin->psz1);
447     if (err == FILEOP_DOIT) {
448       TRACE("  Callback specified filename: %s\n", debugstr_w(&(fici.FullTargetName[0])));
449       if (fici.FullTargetName[0]) {
450         len = strlenW(&(fici.FullTargetName[0])) + 1;
451         if ((len > MAX_PATH ) || (len <= 1))
452           return 0;
453         if (!WideCharToMultiByte(CP_ACP, 0, &(fici.FullTargetName[0]), len, &(charbuf[0]), MAX_PATH, 0, 0))
454           return 0;
455       } else {
456         WARN("Empty buffer string caused abort.\n");
457         SetLastError(ERROR_PATH_NOT_FOUND);
458         return -1;
459       }
460       return sc_cb_open(&(charbuf[0]), _O_BINARY | _O_CREAT | _O_WRONLY,  _S_IREAD | _S_IWRITE);
461     } else {
462       TRACE("  Callback skipped file.\n");
463       return 0;
464     }
465   case fdintCLOSE_FILE_INFO:
466     TRACE("Close file notification\n");
467     /* TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
468     TRACE("  Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
469     TRACE("  File hndl: %d\n", pfdin->hf); */
470     fp.Source = &(phsc->most_recent_cabinet_name[0]);
471     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf[0]), MAX_PATH);
472     if ((len > MAX_PATH) || (len <= 1))
473       buf[0] = '\0';
474     fp.Target = &(buf[0]);
475     fp.Win32Error = 0;
476     fp.Flags = 0;
477     /* a valid fixme -- but occurs too many times */
478     /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
479     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0);
480     if (sc_cb_close(pfdin->hf))
481       WARN("_close failed.\n");
482     if (err) {
483       SetLastError(err);
484       return FALSE;
485     } else
486       return TRUE;
487   case fdintNEXT_CABINET:
488     TRACE("Next cabinet notification\n");
489     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
490     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
491     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
492     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
493     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
494     /* remember the new cabinet name */
495     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(phsc->most_recent_cabinet_name[0]), MAX_PATH);
496     if ((len > MAX_PATH) || (len <= 1))
497       phsc->most_recent_cabinet_name[0] = '\0';
498     ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
499     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
500     if ((len > MAX_PATH) || (len <= 1))
501       buf[0] = '\0';
502     ci.CabinetPath = &(buf[0]);
503     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
504     if ((len > MAX_PATH) || (len <= 1))
505       buf2[0] = '\0';
506     ci.DiskName = &(buf2[0]);
507     ci.SetId = pfdin->setID;
508     ci.CabinetNumber = pfdin->iCabinet;
509     err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0]));
510     if (err) {
511       SetLastError(err);
512       return -1;
513     } else {
514       if (mysterio[0]) {
515         len = strlenW(&(mysterio[0])) + 1;
516         if ((len > 255) || (len <= 1))
517           return 0;
518         if (!WideCharToMultiByte(CP_ACP, 0, &(mysterio[0]), len, pfdin->psz3, 255, 0, 0))
519           return 0;
520       }
521       return 0;
522     }
523   default:
524     FIXME("Unknown notification type %d.\n", fdint);
525     return 0;
526   }
527 }
528
529 /***********************************************************************
530  *              SetupIterateCabinetA (SETUPAPI.@)
531  */
532 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
533                                  PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
534 {
535
536   SC_HSC_A my_hsc;
537   ERF erf;
538   CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p;
539   DWORD fpnsize;
540   BOOL ret;
541
542
543   TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
544         debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
545
546   if (! LoadCABINETDll()) 
547     return FALSE;
548
549   memset(&my_hsc, 0, sizeof(SC_HSC_A));
550   pszCabinet[0] = '\0';
551   pszCabPath[0] = '\0';
552
553   fpnsize = strlen(CabinetFile);
554   if (fpnsize >= MAX_PATH) {
555     SetLastError(ERROR_BAD_PATHNAME);
556     return FALSE;
557   }
558
559   fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p);
560   if (fpnsize > MAX_PATH) {
561     SetLastError(ERROR_BAD_PATHNAME);
562     return FALSE;
563   }
564
565   if (p) {
566     strcpy(pszCabinet, p);
567     *p = '\0';
568   } else {
569     strcpy(pszCabinet, CabinetFile);
570     pszCabPath[0] = '\0';
571   }
572
573   TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
574
575   /* remember the cabinet name */
576   strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet);
577
578   my_hsc.magic = SC_HSC_A_MAGIC;
579   my_hsc.msghandler = MsgHandler;
580   my_hsc.context = Context;
581   my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
582                            sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
583
584   if (!my_hsc.hfdi) return FALSE;
585
586   ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
587                      0, sc_FNNOTIFY_A, NULL, &my_hsc)     ) ? TRUE : FALSE;
588
589   sc_FDIDestroy(my_hsc.hfdi);
590   return ret;
591 }
592
593
594 /***********************************************************************
595  *              SetupIterateCabinetW (SETUPAPI.@)
596  */
597 BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
598                                  PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
599 {
600   CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH];
601   UINT len;
602   SC_HSC_W my_hsc;
603   ERF erf;
604   WCHAR pszCabPathW[MAX_PATH], *p;
605   DWORD fpnsize;
606   BOOL ret;
607
608   TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
609         debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
610
611   if (!LoadCABINETDll())
612     return FALSE;
613
614   if (!CabinetFile) return FALSE;
615
616   memset(&my_hsc, 0, sizeof(SC_HSC_W));
617
618   fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p);
619   if (fpnsize > MAX_PATH) {
620     SetLastError(ERROR_BAD_PATHNAME);
621     return FALSE;
622   }
623
624   if (p) {
625     strcpyW(my_hsc.most_recent_cabinet_name, p);
626     *p = 0;
627     len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath,
628                                 MAX_PATH, 0, 0);
629     if (!len) return FALSE;
630   } else {
631     strcpyW(my_hsc.most_recent_cabinet_name, CabinetFile);
632     pszCabPath[0] = '\0';
633   }
634
635   len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1,
636                                 pszCabinet, MAX_PATH, 0, 0);
637   if (!len) return FALSE;
638
639   TRACE("path: %s, cabfile: %s\n",
640         debugstr_a(pszCabPath), debugstr_a(pszCabinet));
641
642   my_hsc.magic = SC_HSC_W_MAGIC;
643   my_hsc.msghandler = MsgHandler;
644   my_hsc.context = Context;
645   my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
646                               sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
647
648   if (!my_hsc.hfdi) return FALSE;
649
650   ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
651                      0, sc_FNNOTIFY_W, NULL, &my_hsc)     ) ? TRUE : FALSE;
652
653   sc_FDIDestroy(my_hsc.hfdi);
654   return ret;
655 }
656
657
658 /***********************************************************************
659  * DllMain
660  *
661  * PARAMS
662  *     hinstDLL    [I] handle to the DLL's instance
663  *     fdwReason   [I]
664  *     lpvReserved [I] reserved, must be NULL
665  *
666  * RETURNS
667  *     Success: TRUE
668  *     Failure: FALSE
669  */
670
671 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
672 {
673     switch (fdwReason) {
674     case DLL_PROCESS_ATTACH:
675         DisableThreadLibraryCalls(hinstDLL);
676         OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
677         if (!GetVersionExW(&OsVersionInfo))
678             return FALSE;
679         break;
680     case DLL_PROCESS_DETACH:
681         UnloadCABINETDll();
682         break;
683     }
684
685     return TRUE;
686 }