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