include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / setupapi / setupcab.c
blobcba244d97f2dc93c1144e283c3af5591950cfcab
1 /*
2 * Setupapi cabinet routines
4 * Copyright 2003 Gregory M. Turner
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.
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.
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
21 #include <stdarg.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <share.h>
26 #include <sys/stat.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "winreg.h"
34 #include "setupapi.h"
35 #include "setupapi_private.h"
36 #include "fdi.h"
37 #include "wine/debug.h"
39 OSVERSIONINFOW OsVersionInfo;
41 HINSTANCE SETUPAPI_hInstance = 0;
43 typedef struct
45 PSP_FILE_CALLBACK_A msghandler;
46 void *context;
47 char cab_path[MAX_PATH];
48 char last_cab[MAX_PATH];
49 char most_recent_target[MAX_PATH];
50 } SC_HSC_A, *PSC_HSC_A;
52 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
54 static void * CDECL sc_cb_alloc(ULONG cb)
56 return malloc(cb);
59 static void CDECL sc_cb_free(void *pv)
61 free(pv);
64 static INT_PTR CDECL sc_cb_open(char *pszFile, int oflag, int pmode)
66 DWORD creation = 0, sharing = 0;
67 int ioflag = 0;
68 SECURITY_ATTRIBUTES sa;
70 switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
71 case _O_RDONLY:
72 ioflag |= GENERIC_READ;
73 break;
74 case _O_WRONLY:
75 ioflag |= GENERIC_WRITE;
76 break;
77 case _O_RDWR:
78 ioflag |= GENERIC_READ | GENERIC_WRITE;
79 break;
82 if (oflag & _O_CREAT) {
83 if (oflag & _O_EXCL)
84 creation = CREATE_NEW;
85 else if (oflag & _O_TRUNC)
86 creation = CREATE_ALWAYS;
87 else
88 creation = OPEN_ALWAYS;
89 } else {
90 if (oflag & _O_TRUNC)
91 creation = TRUNCATE_EXISTING;
92 else
93 creation = OPEN_EXISTING;
96 switch( pmode & 0x70 ) {
97 case _SH_DENYRW:
98 sharing = 0L;
99 break;
100 case _SH_DENYWR:
101 sharing = FILE_SHARE_READ;
102 break;
103 case _SH_DENYRD:
104 sharing = FILE_SHARE_WRITE;
105 break;
106 case _SH_COMPAT:
107 case _SH_DENYNO:
108 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
109 break;
112 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
113 sa.lpSecurityDescriptor = NULL;
114 sa.bInheritHandle = !(ioflag & _O_NOINHERIT);
116 return (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
119 static UINT CDECL sc_cb_read(INT_PTR hf, void *pv, UINT cb)
121 DWORD num_read;
123 if (!ReadFile((HANDLE)hf, pv, cb, &num_read, NULL))
124 return -1;
125 return num_read;
128 static UINT CDECL sc_cb_write(INT_PTR hf, void *pv, UINT cb)
130 DWORD num_written;
132 if (!WriteFile((HANDLE)hf, pv, cb, &num_written, NULL))
133 return -1;
134 return num_written;
137 static int CDECL sc_cb_close(INT_PTR hf)
139 if (!CloseHandle((HANDLE)hf))
140 return -1;
141 return 0;
144 static LONG CDECL sc_cb_lseek(INT_PTR hf, LONG dist, int seektype)
146 DWORD ret;
148 if (seektype < 0 || seektype > 2)
149 return -1;
151 if (((ret = SetFilePointer((HANDLE)hf, dist, NULL, seektype)) == INVALID_SET_FILE_POINTER) && GetLastError())
152 return -1;
153 return ret;
156 #define SIZEOF_MYSTERIO (MAX_PATH*3)
158 static INT_PTR CDECL sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
160 FILE_IN_CABINET_INFO_A fici;
161 PSC_HSC_A phsc = pfdin->pv;
162 CABINET_INFO_A ci;
163 FILEPATHS_A fp;
164 UINT err;
166 CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
168 memset(mysterio, 0, SIZEOF_MYSTERIO);
170 switch (fdint) {
171 case fdintCABINET_INFO:
172 TRACE("New cabinet, path %s, set %u, number %u, next disk %s, next cabinet %s.\n",
173 debugstr_a(pfdin->psz3), pfdin->setID, pfdin->iCabinet, debugstr_a(pfdin->psz2), debugstr_a(pfdin->psz1));
174 ci.CabinetFile = pfdin->psz1;
175 ci.CabinetPath = pfdin->psz3;
176 ci.DiskName = pfdin->psz2;
177 ci.SetId = pfdin->setID;
178 ci.CabinetNumber = pfdin->iCabinet;
179 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR) &ci, 0);
180 return 0;
181 case fdintPARTIAL_FILE:
182 return 0;
183 case fdintCOPY_FILE:
184 TRACE("Copy file %s, length %ld, date %#x, time %#x, attributes %#x.\n",
185 debugstr_a(pfdin->psz1), pfdin->cb, pfdin->date, pfdin->time, pfdin->attribs);
186 fici.NameInCabinet = pfdin->psz1;
187 fici.FileSize = pfdin->cb;
188 fici.Win32Error = 0;
189 fici.DosDate = pfdin->date;
190 fici.DosTime = pfdin->time;
191 fici.DosAttribs = pfdin->attribs;
192 memset(fici.FullTargetName, 0, MAX_PATH);
193 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
194 (UINT_PTR)&fici, (UINT_PTR)phsc->last_cab);
195 if (err == FILEOP_DOIT) {
196 TRACE("Callback specified filename: %s\n", debugstr_a(fici.FullTargetName));
197 if (!fici.FullTargetName[0]) {
198 WARN("Empty return string causing abort.\n");
199 SetLastError(ERROR_PATH_NOT_FOUND);
200 return -1;
202 strcpy( phsc->most_recent_target, fici.FullTargetName );
203 return sc_cb_open(fici.FullTargetName, _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
204 } else {
205 TRACE("Callback skipped file.\n");
206 return 0;
208 case fdintCLOSE_FILE_INFO:
209 TRACE("File extracted.\n");
210 fp.Source = phsc->last_cab;
211 fp.Target = phsc->most_recent_target;
212 fp.Win32Error = 0;
213 fp.Flags = 0;
214 /* FIXME: set file time and attributes */
215 sc_cb_close(pfdin->hf);
216 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
217 if (err) {
218 SetLastError(err);
219 return FALSE;
220 } else
221 return TRUE;
222 case fdintNEXT_CABINET:
223 TRACE("Need new cabinet, path %s, file %s, disk %s, set %u, number %u.\n",
224 debugstr_a(pfdin->psz3), debugstr_a(pfdin->psz1),
225 debugstr_a(pfdin->psz2), pfdin->setID, pfdin->iCabinet);
226 ci.CabinetFile = pfdin->psz1;
227 ci.CabinetPath = pfdin->psz3;
228 ci.DiskName = pfdin->psz2;
229 ci.SetId = pfdin->setID;
230 ci.CabinetNumber = pfdin->iCabinet;
231 sprintf(phsc->last_cab, "%s%s", phsc->cab_path, ci.CabinetFile);
232 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
233 if (err) {
234 SetLastError(err);
235 return -1;
236 } else {
237 if (mysterio[0]) {
238 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
239 lstrcpynA(pfdin->psz3, mysterio, SIZEOF_MYSTERIO);
241 return 0;
243 default:
244 FIXME("Unknown notification type %d.\n", fdint);
245 return 0;
249 /***********************************************************************
250 * SetupIterateCabinetA (SETUPAPI.@)
252 BOOL WINAPI SetupIterateCabinetA(const char *file, DWORD reserved,
253 PSP_FILE_CALLBACK_A callback, void *context)
256 SC_HSC_A my_hsc;
257 ERF erf;
258 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *filepart = NULL;
259 size_t path_size = 0;
260 const char *p;
261 DWORD fpnsize;
262 HFDI hfdi;
263 BOOL ret;
265 TRACE("file %s, reserved %#lx, callback %p, context %p.\n",
266 debugstr_a(file), reserved, callback, context);
268 if (!file)
270 SetLastError(ERROR_INVALID_PARAMETER);
271 return FALSE;
274 if (strlen(file) >= MAX_PATH)
276 SetLastError(ERROR_BAD_PATHNAME);
277 return FALSE;
280 fpnsize = GetFullPathNameA(file, MAX_PATH, pszCabPath, &filepart);
281 if (fpnsize > MAX_PATH)
283 SetLastError(ERROR_BAD_PATHNAME);
284 return FALSE;
287 if (filepart)
289 strcpy(pszCabinet, filepart);
290 *filepart = '\0';
292 else
294 strcpy(pszCabinet, file);
295 pszCabPath[0] = '\0';
298 for (p = file; *p; ++p)
300 if (*p == '/' || *p == '\\')
301 path_size = p - file;
303 memcpy(my_hsc.cab_path, file, path_size);
304 my_hsc.cab_path[path_size] = 0;
306 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
308 strcpy(my_hsc.last_cab, file);
310 my_hsc.msghandler = callback;
311 my_hsc.context = context;
312 hfdi = FDICreate(sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
313 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf);
315 if (!hfdi) return FALSE;
317 ret = FDICopy(hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_A, NULL, &my_hsc);
319 FDIDestroy(hfdi);
320 return ret;
323 struct iterate_wtoa_ctx
325 PSP_FILE_CALLBACK_A orig_cb;
326 void *orig_ctx;
329 static UINT WINAPI iterate_wtoa_cb(void *pctx, UINT message, UINT_PTR param1, UINT_PTR param2)
331 struct iterate_wtoa_ctx *ctx = pctx;
333 switch (message)
335 case SPFILENOTIFY_CABINETINFO:
336 case SPFILENOTIFY_NEEDNEWCABINET:
338 const CABINET_INFO_A *infoA = (const CABINET_INFO_A *)param1;
339 WCHAR pathW[MAX_PATH], fileW[MAX_PATH], diskW[MAX_PATH];
340 CABINET_INFO_W infoW =
342 .CabinetPath = pathW,
343 .CabinetFile = fileW,
344 .DiskName = diskW,
345 .SetId = infoA->SetId,
346 .CabinetNumber = infoA->CabinetNumber,
349 MultiByteToWideChar(CP_ACP, 0, infoA->CabinetPath, -1, pathW, ARRAY_SIZE(pathW));
350 MultiByteToWideChar(CP_ACP, 0, infoA->CabinetFile, -1, fileW, ARRAY_SIZE(fileW));
351 MultiByteToWideChar(CP_ACP, 0, infoA->DiskName, -1, diskW, ARRAY_SIZE(diskW));
353 if (message == SPFILENOTIFY_CABINETINFO)
354 return ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, 0);
355 else
357 char *newpathA = (char *)param2;
358 WCHAR newpathW[MAX_PATH] = {0};
359 BOOL ret = ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, (UINT_PTR)newpathW);
361 WideCharToMultiByte(CP_ACP, 0, newpathW, -1, newpathA, MAX_PATH, NULL, NULL);
362 return ret;
365 case SPFILENOTIFY_FILEINCABINET:
367 FILE_IN_CABINET_INFO_A *infoA = (FILE_IN_CABINET_INFO_A *)param1;
368 const char *cabA = (const char *)param2;
369 WCHAR cabW[MAX_PATH], fileW[MAX_PATH];
370 FILE_IN_CABINET_INFO_W infoW =
372 .NameInCabinet = fileW,
373 .FileSize = infoA->FileSize,
374 .Win32Error = infoA->Win32Error,
375 .DosDate = infoA->DosDate,
376 .DosTime = infoA->DosTime,
377 .DosAttribs = infoA->DosAttribs,
379 BOOL ret;
381 MultiByteToWideChar(CP_ACP, 0, infoA->NameInCabinet, -1, fileW, ARRAY_SIZE(fileW));
382 MultiByteToWideChar(CP_ACP, 0, cabA, -1, cabW, ARRAY_SIZE(cabW));
384 ret = ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, (UINT_PTR)cabW);
386 WideCharToMultiByte(CP_ACP, 0, infoW.FullTargetName, -1, infoA->FullTargetName,
387 ARRAY_SIZE(infoA->FullTargetName), NULL, NULL);
389 return ret;
391 case SPFILENOTIFY_FILEEXTRACTED:
393 const FILEPATHS_A *pathsA = (const FILEPATHS_A *)param1;
394 WCHAR targetW[MAX_PATH], sourceW[MAX_PATH];
395 FILEPATHS_W pathsW =
397 .Target = targetW,
398 .Source = sourceW,
399 .Win32Error = pathsA->Win32Error,
400 .Flags = pathsA->Flags,
403 MultiByteToWideChar(CP_ACP, 0, pathsA->Target, -1, targetW, ARRAY_SIZE(targetW));
404 MultiByteToWideChar(CP_ACP, 0, pathsA->Source, -1, sourceW, ARRAY_SIZE(sourceW));
406 return ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&pathsW, 0);
408 default:
409 FIXME("Unexpected callback %#x.\n", message);
410 return FALSE;
414 /***********************************************************************
415 * SetupIterateCabinetW (SETUPAPI.@)
417 BOOL WINAPI SetupIterateCabinetW(const WCHAR *fileW, DWORD reserved,
418 PSP_FILE_CALLBACK_W handler, void *context)
420 struct iterate_wtoa_ctx ctx = {handler, context};
421 char fileA[MAX_PATH];
423 if (!WideCharToMultiByte(CP_ACP, 0, fileW, -1, fileA, ARRAY_SIZE(fileA), NULL, NULL))
424 return FALSE;
426 return SetupIterateCabinetA(fileA, reserved, iterate_wtoa_cb, &ctx);
429 /***********************************************************************
430 * DllMain
432 * PARAMS
433 * hinstDLL [I] handle to the DLL's instance
434 * fdwReason [I]
435 * lpvReserved [I] reserved, must be NULL
437 * RETURNS
438 * Success: TRUE
439 * Failure: FALSE
442 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
444 switch (fdwReason) {
445 case DLL_PROCESS_ATTACH:
446 DisableThreadLibraryCalls(hinstDLL);
447 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
448 if (!GetVersionExW(&OsVersionInfo))
449 return FALSE;
450 SETUPAPI_hInstance = hinstDLL;
451 break;
452 case DLL_PROCESS_DETACH:
453 if (lpvReserved) break;
454 SetupCloseLog();
455 break;
458 return TRUE;