ntdll: Make wine_build a hidden symbol.
[wine.git] / dlls / setupapi / setupcab.c
blobd4d475c98cb7a27facf67018d8dba35e62db65d7
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>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "winreg.h"
33 #include "setupapi.h"
34 #include "setupapi_private.h"
35 #include "fdi.h"
36 #include "wine/debug.h"
38 OSVERSIONINFOW OsVersionInfo;
40 HINSTANCE SETUPAPI_hInstance = 0;
42 typedef struct
44 PSP_FILE_CALLBACK_A msghandler;
45 void *context;
46 char cab_path[MAX_PATH];
47 char last_cab[MAX_PATH];
48 char most_recent_target[MAX_PATH];
49 } SC_HSC_A, *PSC_HSC_A;
51 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
53 static void * CDECL sc_cb_alloc(ULONG cb)
55 return HeapAlloc(GetProcessHeap(), 0, cb);
58 static void CDECL sc_cb_free(void *pv)
60 HeapFree(GetProcessHeap(), 0, pv);
63 static INT_PTR CDECL sc_cb_open(char *pszFile, int oflag, int pmode)
65 DWORD creation = 0, sharing = 0;
66 int ioflag = 0;
67 SECURITY_ATTRIBUTES sa;
69 switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
70 case _O_RDONLY:
71 ioflag |= GENERIC_READ;
72 break;
73 case _O_WRONLY:
74 ioflag |= GENERIC_WRITE;
75 break;
76 case _O_RDWR:
77 ioflag |= GENERIC_READ | GENERIC_WRITE;
78 break;
81 if (oflag & _O_CREAT) {
82 if (oflag & _O_EXCL)
83 creation = CREATE_NEW;
84 else if (oflag & _O_TRUNC)
85 creation = CREATE_ALWAYS;
86 else
87 creation = OPEN_ALWAYS;
88 } else {
89 if (oflag & _O_TRUNC)
90 creation = TRUNCATE_EXISTING;
91 else
92 creation = OPEN_EXISTING;
95 switch( pmode & 0x70 ) {
96 case _SH_DENYRW:
97 sharing = 0L;
98 break;
99 case _SH_DENYWR:
100 sharing = FILE_SHARE_READ;
101 break;
102 case _SH_DENYRD:
103 sharing = FILE_SHARE_WRITE;
104 break;
105 case _SH_COMPAT:
106 case _SH_DENYNO:
107 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
108 break;
111 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
112 sa.lpSecurityDescriptor = NULL;
113 sa.bInheritHandle = !(ioflag & _O_NOINHERIT);
115 return (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
118 static UINT CDECL sc_cb_read(INT_PTR hf, void *pv, UINT cb)
120 DWORD num_read;
122 if (!ReadFile((HANDLE)hf, pv, cb, &num_read, NULL))
123 return -1;
124 return num_read;
127 static UINT CDECL sc_cb_write(INT_PTR hf, void *pv, UINT cb)
129 DWORD num_written;
131 if (!WriteFile((HANDLE)hf, pv, cb, &num_written, NULL))
132 return -1;
133 return num_written;
136 static int CDECL sc_cb_close(INT_PTR hf)
138 if (!CloseHandle((HANDLE)hf))
139 return -1;
140 return 0;
143 static LONG CDECL sc_cb_lseek(INT_PTR hf, LONG dist, int seektype)
145 DWORD ret;
147 if (seektype < 0 || seektype > 2)
148 return -1;
150 if (((ret = SetFilePointer((HANDLE)hf, dist, NULL, seektype)) == INVALID_SET_FILE_POINTER) && GetLastError())
151 return -1;
152 return ret;
155 #define SIZEOF_MYSTERIO (MAX_PATH*3)
157 static INT_PTR CDECL sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
159 FILE_IN_CABINET_INFO_A fici;
160 PSC_HSC_A phsc = pfdin->pv;
161 CABINET_INFO_A ci;
162 FILEPATHS_A fp;
163 UINT err;
165 CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
167 memset(mysterio, 0, SIZEOF_MYSTERIO);
169 switch (fdint) {
170 case fdintCABINET_INFO:
171 TRACE("New cabinet, path %s, set %u, number %u, next disk %s, next cabinet %s.\n",
172 debugstr_a(pfdin->psz3), pfdin->setID, pfdin->iCabinet, debugstr_a(pfdin->psz2), debugstr_a(pfdin->psz1));
173 ci.CabinetFile = pfdin->psz1;
174 ci.CabinetPath = pfdin->psz3;
175 ci.DiskName = pfdin->psz2;
176 ci.SetId = pfdin->setID;
177 ci.CabinetNumber = pfdin->iCabinet;
178 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR) &ci, 0);
179 return 0;
180 case fdintPARTIAL_FILE:
181 return 0;
182 case fdintCOPY_FILE:
183 TRACE("Copy file %s, length %d, date %#x, time %#x, attributes %#x.\n",
184 debugstr_a(pfdin->psz1), pfdin->cb, pfdin->date, pfdin->time, pfdin->attribs);
185 fici.NameInCabinet = pfdin->psz1;
186 fici.FileSize = pfdin->cb;
187 fici.Win32Error = 0;
188 fici.DosDate = pfdin->date;
189 fici.DosTime = pfdin->time;
190 fici.DosAttribs = pfdin->attribs;
191 memset(fici.FullTargetName, 0, MAX_PATH);
192 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
193 (UINT_PTR)&fici, (UINT_PTR)phsc->last_cab);
194 if (err == FILEOP_DOIT) {
195 TRACE("Callback specified filename: %s\n", debugstr_a(fici.FullTargetName));
196 if (!fici.FullTargetName[0]) {
197 WARN("Empty return string causing abort.\n");
198 SetLastError(ERROR_PATH_NOT_FOUND);
199 return -1;
201 strcpy( phsc->most_recent_target, fici.FullTargetName );
202 return sc_cb_open(fici.FullTargetName, _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
203 } else {
204 TRACE("Callback skipped file.\n");
205 return 0;
207 case fdintCLOSE_FILE_INFO:
208 TRACE("File extracted.\n");
209 fp.Source = phsc->last_cab;
210 fp.Target = phsc->most_recent_target;
211 fp.Win32Error = 0;
212 fp.Flags = 0;
213 /* FIXME: set file time and attributes */
214 sc_cb_close(pfdin->hf);
215 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
216 if (err) {
217 SetLastError(err);
218 return FALSE;
219 } else
220 return TRUE;
221 case fdintNEXT_CABINET:
222 TRACE("Need new cabinet, path %s, file %s, disk %s, set %u, number %u.\n",
223 debugstr_a(pfdin->psz3), debugstr_a(pfdin->psz1),
224 debugstr_a(pfdin->psz2), pfdin->setID, pfdin->iCabinet);
225 ci.CabinetFile = pfdin->psz1;
226 ci.CabinetPath = pfdin->psz3;
227 ci.DiskName = pfdin->psz2;
228 ci.SetId = pfdin->setID;
229 ci.CabinetNumber = pfdin->iCabinet;
230 sprintf(phsc->last_cab, "%s%s", phsc->cab_path, ci.CabinetFile);
231 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
232 if (err) {
233 SetLastError(err);
234 return -1;
235 } else {
236 if (mysterio[0]) {
237 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
238 lstrcpynA(pfdin->psz3, mysterio, SIZEOF_MYSTERIO);
240 return 0;
242 default:
243 FIXME("Unknown notification type %d.\n", fdint);
244 return 0;
248 /***********************************************************************
249 * SetupIterateCabinetA (SETUPAPI.@)
251 BOOL WINAPI SetupIterateCabinetA(const char *file, DWORD reserved,
252 PSP_FILE_CALLBACK_A callback, void *context)
255 SC_HSC_A my_hsc;
256 ERF erf;
257 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *filepart = NULL;
258 size_t path_size = 0;
259 const char *p;
260 DWORD fpnsize;
261 HFDI hfdi;
262 BOOL ret;
264 TRACE("file %s, reserved %#x, callback %p, context %p.\n",
265 debugstr_a(file), reserved, callback, context);
267 if (!file)
269 SetLastError(ERROR_INVALID_PARAMETER);
270 return FALSE;
273 if (strlen(file) >= MAX_PATH)
275 SetLastError(ERROR_BAD_PATHNAME);
276 return FALSE;
279 fpnsize = GetFullPathNameA(file, MAX_PATH, pszCabPath, &filepart);
280 if (fpnsize > MAX_PATH)
282 SetLastError(ERROR_BAD_PATHNAME);
283 return FALSE;
286 if (filepart)
288 strcpy(pszCabinet, filepart);
289 *filepart = '\0';
291 else
293 strcpy(pszCabinet, file);
294 pszCabPath[0] = '\0';
297 for (p = file; *p; ++p)
299 if (*p == '/' || *p == '\\')
300 path_size = p - file;
302 memcpy(my_hsc.cab_path, file, path_size);
303 my_hsc.cab_path[path_size] = 0;
305 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
307 strcpy(my_hsc.last_cab, file);
309 my_hsc.msghandler = callback;
310 my_hsc.context = context;
311 hfdi = FDICreate(sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
312 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf);
314 if (!hfdi) return FALSE;
316 ret = FDICopy(hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_A, NULL, &my_hsc);
318 FDIDestroy(hfdi);
319 return ret;
322 struct iterate_wtoa_ctx
324 PSP_FILE_CALLBACK_A orig_cb;
325 void *orig_ctx;
328 static UINT WINAPI iterate_wtoa_cb(void *pctx, UINT message, UINT_PTR param1, UINT_PTR param2)
330 struct iterate_wtoa_ctx *ctx = pctx;
332 switch (message)
334 case SPFILENOTIFY_CABINETINFO:
335 case SPFILENOTIFY_NEEDNEWCABINET:
337 const CABINET_INFO_A *infoA = (const CABINET_INFO_A *)param1;
338 WCHAR pathW[MAX_PATH], fileW[MAX_PATH], diskW[MAX_PATH];
339 CABINET_INFO_W infoW =
341 .CabinetPath = pathW,
342 .CabinetFile = fileW,
343 .DiskName = diskW,
344 .SetId = infoA->SetId,
345 .CabinetNumber = infoA->CabinetNumber,
348 MultiByteToWideChar(CP_ACP, 0, infoA->CabinetPath, -1, pathW, ARRAY_SIZE(pathW));
349 MultiByteToWideChar(CP_ACP, 0, infoA->CabinetFile, -1, fileW, ARRAY_SIZE(fileW));
350 MultiByteToWideChar(CP_ACP, 0, infoA->DiskName, -1, diskW, ARRAY_SIZE(diskW));
352 if (message == SPFILENOTIFY_CABINETINFO)
353 return ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, 0);
354 else
356 char *newpathA = (char *)param2;
357 WCHAR newpathW[MAX_PATH] = {0};
358 BOOL ret = ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, (UINT_PTR)newpathW);
360 WideCharToMultiByte(CP_ACP, 0, newpathW, -1, newpathA, MAX_PATH, NULL, NULL);
361 return ret;
364 case SPFILENOTIFY_FILEINCABINET:
366 FILE_IN_CABINET_INFO_A *infoA = (FILE_IN_CABINET_INFO_A *)param1;
367 const char *cabA = (const char *)param2;
368 WCHAR cabW[MAX_PATH], fileW[MAX_PATH];
369 FILE_IN_CABINET_INFO_W infoW =
371 .NameInCabinet = fileW,
372 .FileSize = infoA->FileSize,
373 .Win32Error = infoA->Win32Error,
374 .DosDate = infoA->DosDate,
375 .DosTime = infoA->DosTime,
376 .DosAttribs = infoA->DosAttribs,
378 BOOL ret;
380 MultiByteToWideChar(CP_ACP, 0, infoA->NameInCabinet, -1, fileW, ARRAY_SIZE(fileW));
381 MultiByteToWideChar(CP_ACP, 0, cabA, -1, cabW, ARRAY_SIZE(cabW));
383 ret = ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, (UINT_PTR)cabW);
385 WideCharToMultiByte(CP_ACP, 0, infoW.FullTargetName, -1, infoA->FullTargetName,
386 ARRAY_SIZE(infoA->FullTargetName), NULL, NULL);
388 return ret;
390 case SPFILENOTIFY_FILEEXTRACTED:
392 const FILEPATHS_A *pathsA = (const FILEPATHS_A *)param1;
393 WCHAR targetW[MAX_PATH], sourceW[MAX_PATH];
394 FILEPATHS_W pathsW =
396 .Target = targetW,
397 .Source = sourceW,
398 .Win32Error = pathsA->Win32Error,
399 .Flags = pathsA->Flags,
402 MultiByteToWideChar(CP_ACP, 0, pathsA->Target, -1, targetW, ARRAY_SIZE(targetW));
403 MultiByteToWideChar(CP_ACP, 0, pathsA->Source, -1, sourceW, ARRAY_SIZE(sourceW));
405 return ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&pathsW, 0);
407 default:
408 FIXME("Unexpected callback %#x.\n", message);
409 return FALSE;
413 /***********************************************************************
414 * SetupIterateCabinetW (SETUPAPI.@)
416 BOOL WINAPI SetupIterateCabinetW(const WCHAR *fileW, DWORD reserved,
417 PSP_FILE_CALLBACK_W handler, void *context)
419 struct iterate_wtoa_ctx ctx = {handler, context};
420 char fileA[MAX_PATH];
422 if (!WideCharToMultiByte(CP_ACP, 0, fileW, -1, fileA, ARRAY_SIZE(fileA), NULL, NULL))
423 return FALSE;
425 return SetupIterateCabinetA(fileA, reserved, iterate_wtoa_cb, &ctx);
428 /***********************************************************************
429 * DllMain
431 * PARAMS
432 * hinstDLL [I] handle to the DLL's instance
433 * fdwReason [I]
434 * lpvReserved [I] reserved, must be NULL
436 * RETURNS
437 * Success: TRUE
438 * Failure: FALSE
441 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
443 switch (fdwReason) {
444 case DLL_PROCESS_ATTACH:
445 DisableThreadLibraryCalls(hinstDLL);
446 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
447 if (!GetVersionExW(&OsVersionInfo))
448 return FALSE;
449 SETUPAPI_hInstance = hinstDLL;
450 break;
451 case DLL_PROCESS_DETACH:
452 if (lpvReserved) break;
453 SetupCloseLog();
454 break;
457 return TRUE;