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
35 #include "setupapi_private.h"
37 #include "wine/debug.h"
39 OSVERSIONINFOW OsVersionInfo
;
41 HINSTANCE SETUPAPI_hInstance
= 0;
45 PSP_FILE_CALLBACK_A msghandler
;
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
)
59 static void CDECL
sc_cb_free(void *pv
)
64 static INT_PTR CDECL
sc_cb_open(char *pszFile
, int oflag
, int pmode
)
66 DWORD creation
= 0, sharing
= 0;
68 SECURITY_ATTRIBUTES sa
;
70 switch(oflag
& (_O_RDONLY
| _O_WRONLY
| _O_RDWR
)) {
72 ioflag
|= GENERIC_READ
;
75 ioflag
|= GENERIC_WRITE
;
78 ioflag
|= GENERIC_READ
| GENERIC_WRITE
;
82 if (oflag
& _O_CREAT
) {
84 creation
= CREATE_NEW
;
85 else if (oflag
& _O_TRUNC
)
86 creation
= CREATE_ALWAYS
;
88 creation
= OPEN_ALWAYS
;
91 creation
= TRUNCATE_EXISTING
;
93 creation
= OPEN_EXISTING
;
96 switch( pmode
& 0x70 ) {
101 sharing
= FILE_SHARE_READ
;
104 sharing
= FILE_SHARE_WRITE
;
108 sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
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
)
123 if (!ReadFile((HANDLE
)hf
, pv
, cb
, &num_read
, NULL
))
128 static UINT CDECL
sc_cb_write(INT_PTR hf
, void *pv
, UINT cb
)
132 if (!WriteFile((HANDLE
)hf
, pv
, cb
, &num_written
, NULL
))
137 static int CDECL
sc_cb_close(INT_PTR hf
)
139 if (!CloseHandle((HANDLE
)hf
))
144 static LONG CDECL
sc_cb_lseek(INT_PTR hf
, LONG dist
, int seektype
)
148 if (seektype
< 0 || seektype
> 2)
151 if (((ret
= SetFilePointer((HANDLE
)hf
, dist
, NULL
, seektype
)) == INVALID_SET_FILE_POINTER
) && GetLastError())
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
;
166 CHAR mysterio
[SIZEOF_MYSTERIO
]; /* how big? undocumented! probably 256... */
168 memset(mysterio
, 0, SIZEOF_MYSTERIO
);
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);
181 case fdintPARTIAL_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
;
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
);
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
);
205 TRACE("Callback skipped file.\n");
208 case fdintCLOSE_FILE_INFO
:
209 TRACE("File extracted.\n");
210 fp
.Source
= phsc
->last_cab
;
211 fp
.Target
= phsc
->most_recent_target
;
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);
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
);
238 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
239 lstrcpynA(pfdin
->psz3
, mysterio
, SIZEOF_MYSTERIO
);
244 FIXME("Unknown notification type %d.\n", fdint
);
249 /***********************************************************************
250 * SetupIterateCabinetA (SETUPAPI.@)
252 BOOL WINAPI
SetupIterateCabinetA(const char *file
, DWORD reserved
,
253 PSP_FILE_CALLBACK_A callback
, void *context
)
258 CHAR pszCabinet
[MAX_PATH
], pszCabPath
[MAX_PATH
], *filepart
= NULL
;
259 size_t path_size
= 0;
265 TRACE("file %s, reserved %#lx, callback %p, context %p.\n",
266 debugstr_a(file
), reserved
, callback
, context
);
270 SetLastError(ERROR_INVALID_PARAMETER
);
274 if (strlen(file
) >= MAX_PATH
)
276 SetLastError(ERROR_BAD_PATHNAME
);
280 fpnsize
= GetFullPathNameA(file
, MAX_PATH
, pszCabPath
, &filepart
);
281 if (fpnsize
> MAX_PATH
)
283 SetLastError(ERROR_BAD_PATHNAME
);
289 strcpy(pszCabinet
, filepart
);
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
);
323 struct iterate_wtoa_ctx
325 PSP_FILE_CALLBACK_A orig_cb
;
329 static UINT WINAPI
iterate_wtoa_cb(void *pctx
, UINT message
, UINT_PTR param1
, UINT_PTR param2
)
331 struct iterate_wtoa_ctx
*ctx
= pctx
;
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
,
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);
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
);
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
,
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
);
391 case SPFILENOTIFY_FILEEXTRACTED
:
393 const FILEPATHS_A
*pathsA
= (const FILEPATHS_A
*)param1
;
394 WCHAR targetW
[MAX_PATH
], sourceW
[MAX_PATH
];
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);
409 FIXME("Unexpected callback %#x.\n", message
);
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
))
426 return SetupIterateCabinetA(fileA
, reserved
, iterate_wtoa_cb
, &ctx
);
429 /***********************************************************************
433 * hinstDLL [I] handle to the DLL's instance
435 * lpvReserved [I] reserved, must be NULL
442 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
445 case DLL_PROCESS_ATTACH
:
446 DisableThreadLibraryCalls(hinstDLL
);
447 OsVersionInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
448 if (!GetVersionExW(&OsVersionInfo
))
450 SETUPAPI_hInstance
= hinstDLL
;
452 case DLL_PROCESS_DETACH
:
453 if (lpvReserved
) break;