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