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
34 #include "setupapi_private.h"
36 #include "wine/debug.h"
38 OSVERSIONINFOW OsVersionInfo
;
40 HINSTANCE SETUPAPI_hInstance
= 0;
44 PSP_FILE_CALLBACK_A msghandler
;
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;
67 SECURITY_ATTRIBUTES sa
;
69 switch(oflag
& (_O_RDONLY
| _O_WRONLY
| _O_RDWR
)) {
71 ioflag
|= GENERIC_READ
;
74 ioflag
|= GENERIC_WRITE
;
77 ioflag
|= GENERIC_READ
| GENERIC_WRITE
;
81 if (oflag
& _O_CREAT
) {
83 creation
= CREATE_NEW
;
84 else if (oflag
& _O_TRUNC
)
85 creation
= CREATE_ALWAYS
;
87 creation
= OPEN_ALWAYS
;
90 creation
= TRUNCATE_EXISTING
;
92 creation
= OPEN_EXISTING
;
95 switch( pmode
& 0x70 ) {
100 sharing
= FILE_SHARE_READ
;
103 sharing
= FILE_SHARE_WRITE
;
107 sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
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
)
122 if (!ReadFile((HANDLE
)hf
, pv
, cb
, &num_read
, NULL
))
127 static UINT CDECL
sc_cb_write(INT_PTR hf
, void *pv
, UINT cb
)
131 if (!WriteFile((HANDLE
)hf
, pv
, cb
, &num_written
, NULL
))
136 static int CDECL
sc_cb_close(INT_PTR hf
)
138 if (!CloseHandle((HANDLE
)hf
))
143 static LONG CDECL
sc_cb_lseek(INT_PTR hf
, LONG dist
, int seektype
)
147 if (seektype
< 0 || seektype
> 2)
150 if (((ret
= SetFilePointer((HANDLE
)hf
, dist
, NULL
, seektype
)) == INVALID_SET_FILE_POINTER
) && GetLastError())
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
;
165 CHAR mysterio
[SIZEOF_MYSTERIO
]; /* how big? undocumented! probably 256... */
167 memset(mysterio
, 0, SIZEOF_MYSTERIO
);
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);
180 case fdintPARTIAL_FILE
:
183 TRACE("Copy file %s, length %ld, 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
;
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
);
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
);
204 TRACE("Callback skipped file.\n");
207 case fdintCLOSE_FILE_INFO
:
208 TRACE("File extracted.\n");
209 fp
.Source
= phsc
->last_cab
;
210 fp
.Target
= phsc
->most_recent_target
;
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);
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
);
237 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
238 lstrcpynA(pfdin
->psz3
, mysterio
, SIZEOF_MYSTERIO
);
243 FIXME("Unknown notification type %d.\n", fdint
);
248 /***********************************************************************
249 * SetupIterateCabinetA (SETUPAPI.@)
251 BOOL WINAPI
SetupIterateCabinetA(const char *file
, DWORD reserved
,
252 PSP_FILE_CALLBACK_A callback
, void *context
)
257 CHAR pszCabinet
[MAX_PATH
], pszCabPath
[MAX_PATH
], *filepart
= NULL
;
258 size_t path_size
= 0;
264 TRACE("file %s, reserved %#lx, callback %p, context %p.\n",
265 debugstr_a(file
), reserved
, callback
, context
);
269 SetLastError(ERROR_INVALID_PARAMETER
);
273 if (strlen(file
) >= MAX_PATH
)
275 SetLastError(ERROR_BAD_PATHNAME
);
279 fpnsize
= GetFullPathNameA(file
, MAX_PATH
, pszCabPath
, &filepart
);
280 if (fpnsize
> MAX_PATH
)
282 SetLastError(ERROR_BAD_PATHNAME
);
288 strcpy(pszCabinet
, filepart
);
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
);
322 struct iterate_wtoa_ctx
324 PSP_FILE_CALLBACK_A orig_cb
;
328 static UINT WINAPI
iterate_wtoa_cb(void *pctx
, UINT message
, UINT_PTR param1
, UINT_PTR param2
)
330 struct iterate_wtoa_ctx
*ctx
= pctx
;
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
,
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);
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
);
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
,
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
);
390 case SPFILENOTIFY_FILEEXTRACTED
:
392 const FILEPATHS_A
*pathsA
= (const FILEPATHS_A
*)param1
;
393 WCHAR targetW
[MAX_PATH
], sourceW
[MAX_PATH
];
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);
408 FIXME("Unexpected callback %#x.\n", message
);
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
))
425 return SetupIterateCabinetA(fileA
, reserved
, iterate_wtoa_cb
, &ctx
);
428 /***********************************************************************
432 * hinstDLL [I] handle to the DLL's instance
434 * lpvReserved [I] reserved, must be NULL
441 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
444 case DLL_PROCESS_ATTACH
:
445 DisableThreadLibraryCalls(hinstDLL
);
446 OsVersionInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
447 if (!GetVersionExW(&OsVersionInfo
))
449 SETUPAPI_hInstance
= hinstDLL
;
451 case DLL_PROCESS_DETACH
:
452 if (lpvReserved
) break;