2 * Setupapi miscellaneous functions
4 * Copyright 2005 Eric Kohl
5 * Copyright 2007 Hans Leidekker
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
37 #include "setupapi_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
41 /* arbitrary limit not related to what native actually uses */
42 #define OEM_INDEX_LIMIT 999
44 /**************************************************************************
47 * Frees an allocated memory block from the process heap.
50 * lpMem [I] pointer to memory block which will be freed
55 VOID WINAPI
MyFree(LPVOID lpMem
)
57 HeapFree(GetProcessHeap(), 0, lpMem
);
61 /**************************************************************************
62 * MyMalloc [SETUPAPI.@]
64 * Allocates memory block from the process heap.
67 * dwSize [I] size of the allocated memory block
70 * Success: pointer to allocated memory block
73 LPVOID WINAPI
MyMalloc(DWORD dwSize
)
75 return HeapAlloc(GetProcessHeap(), 0, dwSize
);
79 /**************************************************************************
80 * MyRealloc [SETUPAPI.@]
82 * Changes the size of an allocated memory block or allocates a memory
83 * block from the process heap.
86 * lpSrc [I] pointer to memory block which will be resized
87 * dwSize [I] new size of the memory block
90 * Success: pointer to the resized memory block
94 * If lpSrc is a NULL-pointer, then MyRealloc allocates a memory
95 * block like MyMalloc.
97 LPVOID WINAPI
MyRealloc(LPVOID lpSrc
, DWORD dwSize
)
100 return HeapAlloc(GetProcessHeap(), 0, dwSize
);
102 return HeapReAlloc(GetProcessHeap(), 0, lpSrc
, dwSize
);
106 /**************************************************************************
107 * DuplicateString [SETUPAPI.@]
109 * Duplicates a unicode string.
112 * lpSrc [I] pointer to the unicode string that will be duplicated
115 * Success: pointer to the duplicated unicode string
119 * Call MyFree() to release the duplicated string.
121 LPWSTR WINAPI
DuplicateString(LPCWSTR lpSrc
)
125 lpDst
= MyMalloc((lstrlenW(lpSrc
) + 1) * sizeof(WCHAR
));
129 strcpyW(lpDst
, lpSrc
);
135 /**************************************************************************
136 * QueryRegistryValue [SETUPAPI.@]
138 * Retrieves value data from the registry and allocates memory for the
142 * hKey [I] Handle of the key to query
143 * lpValueName [I] Name of value under hkey to query
144 * lpData [O] Destination for the values contents,
145 * lpType [O] Destination for the value type
146 * lpcbData [O] Destination for the size of data
149 * Success: ERROR_SUCCESS
153 * Use MyFree to release the lpData buffer.
155 LONG WINAPI
QueryRegistryValue(HKEY hKey
,
163 TRACE("%p %s %p %p %p\n",
164 hKey
, debugstr_w(lpValueName
), lpData
, lpType
, lpcbData
);
166 /* Get required buffer size */
168 lError
= RegQueryValueExW(hKey
, lpValueName
, 0, lpType
, NULL
, lpcbData
);
169 if (lError
!= ERROR_SUCCESS
)
172 /* Allocate buffer */
173 *lpData
= MyMalloc(*lpcbData
);
175 return ERROR_NOT_ENOUGH_MEMORY
;
177 /* Query registry value */
178 lError
= RegQueryValueExW(hKey
, lpValueName
, 0, lpType
, *lpData
, lpcbData
);
179 if (lError
!= ERROR_SUCCESS
)
186 /**************************************************************************
187 * IsUserAdmin [SETUPAPI.@]
189 * Checks whether the current user is a member of the Administrators group.
198 BOOL WINAPI
IsUserAdmin(VOID
)
200 SID_IDENTIFIER_AUTHORITY Authority
= {SECURITY_NT_AUTHORITY
};
203 PTOKEN_GROUPS lpGroups
;
206 BOOL bResult
= FALSE
;
210 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
215 if (!GetTokenInformation(hToken
, TokenGroups
, NULL
, 0, &dwSize
))
217 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
224 lpGroups
= MyMalloc(dwSize
);
225 if (lpGroups
== NULL
)
231 if (!GetTokenInformation(hToken
, TokenGroups
, lpGroups
, dwSize
, &dwSize
))
240 if (!AllocateAndInitializeSid(&Authority
, 2, SECURITY_BUILTIN_DOMAIN_RID
,
241 DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0,
248 for (i
= 0; i
< lpGroups
->GroupCount
; i
++)
250 if (EqualSid(lpSid
, lpGroups
->Groups
[i
].Sid
))
264 /**************************************************************************
265 * MultiByteToUnicode [SETUPAPI.@]
267 * Converts a multi-byte string to a Unicode string.
270 * lpMultiByteStr [I] Multi-byte string to be converted
271 * uCodePage [I] Code page
274 * Success: pointer to the converted Unicode string
278 * Use MyFree to release the returned Unicode string.
280 LPWSTR WINAPI
MultiByteToUnicode(LPCSTR lpMultiByteStr
, UINT uCodePage
)
285 nLength
= MultiByteToWideChar(uCodePage
, 0, lpMultiByteStr
,
290 lpUnicodeStr
= MyMalloc(nLength
* sizeof(WCHAR
));
291 if (lpUnicodeStr
== NULL
)
294 if (!MultiByteToWideChar(uCodePage
, 0, lpMultiByteStr
,
295 nLength
, lpUnicodeStr
, nLength
))
297 MyFree(lpUnicodeStr
);
305 /**************************************************************************
306 * UnicodeToMultiByte [SETUPAPI.@]
308 * Converts a Unicode string to a multi-byte string.
311 * lpUnicodeStr [I] Unicode string to be converted
312 * uCodePage [I] Code page
315 * Success: pointer to the converted multi-byte string
319 * Use MyFree to release the returned multi-byte string.
321 LPSTR WINAPI
UnicodeToMultiByte(LPCWSTR lpUnicodeStr
, UINT uCodePage
)
323 LPSTR lpMultiByteStr
;
326 nLength
= WideCharToMultiByte(uCodePage
, 0, lpUnicodeStr
, -1,
327 NULL
, 0, NULL
, NULL
);
331 lpMultiByteStr
= MyMalloc(nLength
);
332 if (lpMultiByteStr
== NULL
)
335 if (!WideCharToMultiByte(uCodePage
, 0, lpUnicodeStr
, -1,
336 lpMultiByteStr
, nLength
, NULL
, NULL
))
338 MyFree(lpMultiByteStr
);
342 return lpMultiByteStr
;
346 /**************************************************************************
347 * DoesUserHavePrivilege [SETUPAPI.@]
349 * Check whether the current user has got a given privilege.
352 * lpPrivilegeName [I] Name of the privilege to be checked
358 BOOL WINAPI
DoesUserHavePrivilege(LPCWSTR lpPrivilegeName
)
362 PTOKEN_PRIVILEGES lpPrivileges
;
365 BOOL bResult
= FALSE
;
367 TRACE("%s\n", debugstr_w(lpPrivilegeName
));
369 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
372 if (!GetTokenInformation(hToken
, TokenPrivileges
, NULL
, 0, &dwSize
))
374 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
381 lpPrivileges
= MyMalloc(dwSize
);
382 if (lpPrivileges
== NULL
)
388 if (!GetTokenInformation(hToken
, TokenPrivileges
, lpPrivileges
, dwSize
, &dwSize
))
390 MyFree(lpPrivileges
);
397 if (!LookupPrivilegeValueW(NULL
, lpPrivilegeName
, &PrivilegeLuid
))
399 MyFree(lpPrivileges
);
403 for (i
= 0; i
< lpPrivileges
->PrivilegeCount
; i
++)
405 if (lpPrivileges
->Privileges
[i
].Luid
.HighPart
== PrivilegeLuid
.HighPart
&&
406 lpPrivileges
->Privileges
[i
].Luid
.LowPart
== PrivilegeLuid
.LowPart
)
412 MyFree(lpPrivileges
);
418 /**************************************************************************
419 * EnablePrivilege [SETUPAPI.@]
421 * Enables or disables one of the current users privileges.
424 * lpPrivilegeName [I] Name of the privilege to be changed
425 * bEnable [I] TRUE: Enables the privilege
426 * FALSE: Disables the privilege
432 BOOL WINAPI
EnablePrivilege(LPCWSTR lpPrivilegeName
, BOOL bEnable
)
434 TOKEN_PRIVILEGES Privileges
;
438 TRACE("%s %s\n", debugstr_w(lpPrivilegeName
), bEnable
? "TRUE" : "FALSE");
440 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
443 Privileges
.PrivilegeCount
= 1;
444 Privileges
.Privileges
[0].Attributes
= (bEnable
) ? SE_PRIVILEGE_ENABLED
: 0;
446 if (!LookupPrivilegeValueW(NULL
, lpPrivilegeName
,
447 &Privileges
.Privileges
[0].Luid
))
453 bResult
= AdjustTokenPrivileges(hToken
, FALSE
, &Privileges
, 0, NULL
, NULL
);
461 /**************************************************************************
462 * DelayedMove [SETUPAPI.@]
464 * Moves a file upon the next reboot.
467 * lpExistingFileName [I] Current file name
468 * lpNewFileName [I] New file name
474 BOOL WINAPI
DelayedMove(LPCWSTR lpExistingFileName
, LPCWSTR lpNewFileName
)
476 return MoveFileExW(lpExistingFileName
, lpNewFileName
,
477 MOVEFILE_REPLACE_EXISTING
| MOVEFILE_DELAY_UNTIL_REBOOT
);
481 /**************************************************************************
482 * FileExists [SETUPAPI.@]
484 * Checks whether a file exists.
487 * lpFileName [I] Name of the file to check
488 * lpNewFileName [O] Optional information about the existing file
494 BOOL WINAPI
FileExists(LPCWSTR lpFileName
, LPWIN32_FIND_DATAW lpFileFindData
)
496 WIN32_FIND_DATAW FindData
;
501 uErrorMode
= SetErrorMode(SEM_FAILCRITICALERRORS
);
503 hFind
= FindFirstFileW(lpFileName
, &FindData
);
504 if (hFind
== INVALID_HANDLE_VALUE
)
506 dwError
= GetLastError();
507 SetErrorMode(uErrorMode
);
508 SetLastError(dwError
);
515 *lpFileFindData
= FindData
;
517 SetErrorMode(uErrorMode
);
523 /**************************************************************************
524 * CaptureStringArg [SETUPAPI.@]
526 * Captures a UNICODE string.
529 * lpSrc [I] UNICODE string to be captured
530 * lpDst [O] Pointer to the captured UNICODE string
533 * Success: ERROR_SUCCESS
534 * Failure: ERROR_INVALID_PARAMETER
537 * Call MyFree to release the captured UNICODE string.
539 DWORD WINAPI
CaptureStringArg(LPCWSTR pSrc
, LPWSTR
*pDst
)
542 return ERROR_INVALID_PARAMETER
;
544 *pDst
= DuplicateString(pSrc
);
546 return ERROR_SUCCESS
;
550 /**************************************************************************
551 * CaptureAndConvertAnsiArg [SETUPAPI.@]
553 * Captures an ANSI string and converts it to a UNICODE string.
556 * lpSrc [I] ANSI string to be captured
557 * lpDst [O] Pointer to the captured UNICODE string
560 * Success: ERROR_SUCCESS
561 * Failure: ERROR_INVALID_PARAMETER
564 * Call MyFree to release the captured UNICODE string.
566 DWORD WINAPI
CaptureAndConvertAnsiArg(LPCSTR pSrc
, LPWSTR
*pDst
)
569 return ERROR_INVALID_PARAMETER
;
571 *pDst
= MultiByteToUnicode(pSrc
, CP_ACP
);
573 return ERROR_SUCCESS
;
577 /**************************************************************************
578 * OpenAndMapFileForRead [SETUPAPI.@]
580 * Open and map a file to a buffer.
583 * lpFileName [I] Name of the file to be opened
584 * lpSize [O] Pointer to the file size
585 * lpFile [0] Pointer to the file handle
586 * lpMapping [0] Pointer to the mapping handle
587 * lpBuffer [0] Pointer to the file buffer
590 * Success: ERROR_SUCCESS
594 * Call UnmapAndCloseFile to release the file.
596 DWORD WINAPI
OpenAndMapFileForRead(LPCWSTR lpFileName
,
604 TRACE("%s %p %p %p %p\n",
605 debugstr_w(lpFileName
), lpSize
, lpFile
, lpMapping
, lpBuffer
);
607 *lpFile
= CreateFileW(lpFileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
608 OPEN_EXISTING
, 0, NULL
);
609 if (*lpFile
== INVALID_HANDLE_VALUE
)
610 return GetLastError();
612 *lpSize
= GetFileSize(*lpFile
, NULL
);
613 if (*lpSize
== INVALID_FILE_SIZE
)
615 dwError
= GetLastError();
616 CloseHandle(*lpFile
);
620 *lpMapping
= CreateFileMappingW(*lpFile
, NULL
, PAGE_READONLY
, 0,
622 if (*lpMapping
== NULL
)
624 dwError
= GetLastError();
625 CloseHandle(*lpFile
);
629 *lpBuffer
= MapViewOfFile(*lpMapping
, FILE_MAP_READ
, 0, 0, *lpSize
);
630 if (*lpBuffer
== NULL
)
632 dwError
= GetLastError();
633 CloseHandle(*lpMapping
);
634 CloseHandle(*lpFile
);
638 return ERROR_SUCCESS
;
642 /**************************************************************************
643 * UnmapAndCloseFile [SETUPAPI.@]
645 * Unmap and close a mapped file.
648 * hFile [I] Handle to the file
649 * hMapping [I] Handle to the file mapping
650 * lpBuffer [I] Pointer to the file buffer
656 BOOL WINAPI
UnmapAndCloseFile(HANDLE hFile
, HANDLE hMapping
, LPVOID lpBuffer
)
659 hFile
, hMapping
, lpBuffer
);
661 if (!UnmapViewOfFile(lpBuffer
))
664 if (!CloseHandle(hMapping
))
667 if (!CloseHandle(hFile
))
674 /**************************************************************************
675 * StampFileSecurity [SETUPAPI.@]
677 * Assign a new security descriptor to the given file.
680 * lpFileName [I] Name of the file
681 * pSecurityDescriptor [I] New security descriptor
684 * Success: ERROR_SUCCESS
687 DWORD WINAPI
StampFileSecurity(LPCWSTR lpFileName
, PSECURITY_DESCRIPTOR pSecurityDescriptor
)
689 TRACE("%s %p\n", debugstr_w(lpFileName
), pSecurityDescriptor
);
691 if (!SetFileSecurityW(lpFileName
, OWNER_SECURITY_INFORMATION
|
692 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
693 pSecurityDescriptor
))
694 return GetLastError();
696 return ERROR_SUCCESS
;
700 /**************************************************************************
701 * TakeOwnershipOfFile [SETUPAPI.@]
703 * Takes the ownership of the given file.
706 * lpFileName [I] Name of the file
709 * Success: ERROR_SUCCESS
712 DWORD WINAPI
TakeOwnershipOfFile(LPCWSTR lpFileName
)
714 SECURITY_DESCRIPTOR SecDesc
;
715 HANDLE hToken
= NULL
;
716 PTOKEN_OWNER pOwner
= NULL
;
720 TRACE("%s\n", debugstr_w(lpFileName
));
722 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
723 return GetLastError();
725 if (!GetTokenInformation(hToken
, TokenOwner
, NULL
, 0, &dwSize
))
730 pOwner
= (PTOKEN_OWNER
)MyMalloc(dwSize
);
734 return ERROR_NOT_ENOUGH_MEMORY
;
737 if (!GetTokenInformation(hToken
, TokenOwner
, pOwner
, dwSize
, &dwSize
))
742 if (!InitializeSecurityDescriptor(&SecDesc
, SECURITY_DESCRIPTOR_REVISION
))
747 if (!SetSecurityDescriptorOwner(&SecDesc
, pOwner
->Owner
, FALSE
))
752 if (!SetFileSecurityW(lpFileName
, OWNER_SECURITY_INFORMATION
, &SecDesc
))
760 return ERROR_SUCCESS
;
763 dwError
= GetLastError();
774 /**************************************************************************
775 * RetreiveFileSecurity [SETUPAPI.@]
777 * Retrieve the security descriptor that is associated with the given file.
780 * lpFileName [I] Name of the file
783 * Success: ERROR_SUCCESS
786 DWORD WINAPI
RetreiveFileSecurity(LPCWSTR lpFileName
,
787 PSECURITY_DESCRIPTOR
*pSecurityDescriptor
)
789 PSECURITY_DESCRIPTOR SecDesc
;
790 DWORD dwSize
= 0x100;
793 SecDesc
= MyMalloc(dwSize
);
795 return ERROR_NOT_ENOUGH_MEMORY
;
797 if (GetFileSecurityW(lpFileName
, OWNER_SECURITY_INFORMATION
|
798 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
799 SecDesc
, dwSize
, &dwSize
))
801 *pSecurityDescriptor
= SecDesc
;
802 return ERROR_SUCCESS
;
805 dwError
= GetLastError();
806 if (dwError
!= ERROR_INSUFFICIENT_BUFFER
)
812 SecDesc
= MyRealloc(SecDesc
, dwSize
);
814 return ERROR_NOT_ENOUGH_MEMORY
;
816 if (GetFileSecurityW(lpFileName
, OWNER_SECURITY_INFORMATION
|
817 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
818 SecDesc
, dwSize
, &dwSize
))
820 *pSecurityDescriptor
= SecDesc
;
821 return ERROR_SUCCESS
;
824 dwError
= GetLastError();
831 static DWORD global_flags
= 0; /* FIXME: what should be in here? */
833 /***********************************************************************
834 * pSetupGetGlobalFlags (SETUPAPI.@)
836 DWORD WINAPI
pSetupGetGlobalFlags(void)
843 /***********************************************************************
844 * pSetupSetGlobalFlags (SETUPAPI.@)
846 void WINAPI
pSetupSetGlobalFlags( DWORD flags
)
848 global_flags
= flags
;
851 /***********************************************************************
852 * CMP_WaitNoPendingInstallEvents (SETUPAPI.@)
854 DWORD WINAPI
CMP_WaitNoPendingInstallEvents( DWORD dwTimeout
)
856 static BOOL warned
= FALSE
;
860 FIXME("%d\n", dwTimeout
);
863 return WAIT_OBJECT_0
;
866 /***********************************************************************
867 * AssertFail (SETUPAPI.@)
869 * Shows an assert fail error messagebox
872 * lpFile [I] file where assert failed
873 * uLine [I] line number in file
874 * lpMessage [I] assert message
877 void WINAPI
AssertFail(LPCSTR lpFile
, UINT uLine
, LPCSTR lpMessage
)
879 FIXME("%s %u %s\n", lpFile
, uLine
, lpMessage
);
882 /***********************************************************************
883 * SetupCopyOEMInfA (SETUPAPI.@)
885 BOOL WINAPI
SetupCopyOEMInfA( PCSTR source
, PCSTR location
,
886 DWORD media_type
, DWORD style
, PSTR dest
,
887 DWORD buffer_size
, PDWORD required_size
, PSTR
*component
)
890 LPWSTR destW
= NULL
, sourceW
= NULL
, locationW
= NULL
;
893 TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_a(source
), debugstr_a(location
),
894 media_type
, style
, dest
, buffer_size
, required_size
, component
);
896 if (dest
&& !(destW
= MyMalloc( buffer_size
* sizeof(WCHAR
) ))) return FALSE
;
897 if (source
&& !(sourceW
= strdupAtoW( source
))) goto done
;
898 if (location
&& !(locationW
= strdupAtoW( location
))) goto done
;
900 if (!(ret
= SetupCopyOEMInfW( sourceW
, locationW
, media_type
, style
, destW
,
901 buffer_size
, &size
, NULL
)))
903 if (required_size
) *required_size
= size
;
909 if (buffer_size
>= size
)
911 WideCharToMultiByte( CP_ACP
, 0, destW
, -1, dest
, buffer_size
, NULL
, NULL
);
912 if (component
) *component
= strrchr( dest
, '\\' ) + 1;
916 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
923 HeapFree( GetProcessHeap(), 0, sourceW
);
924 HeapFree( GetProcessHeap(), 0, locationW
);
925 if (ret
) SetLastError(ERROR_SUCCESS
);
929 static int compare_files( HANDLE file1
, HANDLE file2
)
936 while( ReadFile(file1
, buffer1
, sizeof(buffer1
), &size1
, NULL
) &&
937 ReadFile(file2
, buffer2
, sizeof(buffer2
), &size2
, NULL
) )
941 return size1
> size2
? 1 : -1;
944 ret
= memcmp( buffer1
, buffer2
, size1
);
952 /***********************************************************************
953 * SetupCopyOEMInfW (SETUPAPI.@)
955 BOOL WINAPI
SetupCopyOEMInfW( PCWSTR source
, PCWSTR location
,
956 DWORD media_type
, DWORD style
, PWSTR dest
,
957 DWORD buffer_size
, PDWORD required_size
, PWSTR
*component
)
960 WCHAR target
[MAX_PATH
], catalog_file
[MAX_PATH
], *p
;
961 static const WCHAR inf
[] = { '\\','i','n','f','\\',0 };
962 static const WCHAR wszVersion
[] = { 'V','e','r','s','i','o','n',0 };
963 static const WCHAR wszCatalogFile
[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 };
967 TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_w(source
), debugstr_w(location
),
968 media_type
, style
, dest
, buffer_size
, required_size
, component
);
972 SetLastError(ERROR_INVALID_PARAMETER
);
976 /* check for a relative path */
977 if (!(*source
== '\\' || (*source
&& source
[1] == ':')))
979 SetLastError(ERROR_FILE_NOT_FOUND
);
983 if (!GetWindowsDirectoryW( target
, sizeof(target
)/sizeof(WCHAR
) )) return FALSE
;
985 strcatW( target
, inf
);
986 if ((p
= strrchrW( source
, '\\' )))
987 strcatW( target
, p
+ 1 );
989 /* does the file exist already? */
990 if ((GetFileAttributesW( target
) != INVALID_FILE_ATTRIBUTES
) &&
991 !(style
& SP_COPY_NOOVERWRITE
))
993 static const WCHAR oem
[] = { 'o','e','m',0 };
995 LARGE_INTEGER source_file_size
;
998 source_file
= CreateFileW( source
, FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
999 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
1000 NULL
, OPEN_EXISTING
, 0, NULL
);
1001 if (source_file
== INVALID_HANDLE_VALUE
)
1004 if (!GetFileSizeEx( source_file
, &source_file_size
))
1006 CloseHandle( source_file
);
1010 p
= strrchrW( target
, '\\' ) + 1;
1011 memcpy( p
, oem
, sizeof(oem
) );
1012 p
+= sizeof(oem
)/sizeof(oem
[0]) - 1;
1014 /* generate OEMnnn.inf ending */
1015 for (i
= 0; i
< OEM_INDEX_LIMIT
; i
++)
1017 static const WCHAR format
[] = { '%','u','.','i','n','f',0 };
1019 LARGE_INTEGER dest_file_size
;
1021 wsprintfW( p
, format
, i
);
1022 dest_file
= CreateFileW( target
, FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
1023 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
1024 NULL
, OPEN_EXISTING
, 0, NULL
);
1025 /* if we found a file name that doesn't exist then we're done */
1026 if (dest_file
== INVALID_HANDLE_VALUE
)
1028 /* now check if the same inf file has already been copied to the inf
1029 * directory. if so, use that file and don't create a new one */
1030 if (!GetFileSizeEx( dest_file
, &dest_file_size
) ||
1031 (dest_file_size
.QuadPart
!= source_file_size
.QuadPart
) ||
1032 compare_files( source_file
, dest_file
))
1034 CloseHandle( dest_file
);
1037 CloseHandle( dest_file
);
1041 CloseHandle( source_file
);
1042 if (i
== OEM_INDEX_LIMIT
)
1044 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
1049 hinf
= SetupOpenInfFileW( source
, NULL
, INF_STYLE_WIN4
, NULL
);
1050 if (hinf
== INVALID_HANDLE_VALUE
) return FALSE
;
1052 if (SetupGetLineTextW( NULL
, hinf
, wszVersion
, wszCatalogFile
, catalog_file
,
1053 sizeof(catalog_file
)/sizeof(catalog_file
[0]), NULL
))
1055 WCHAR source_cat
[MAX_PATH
];
1058 GUID msguid
= DRIVER_ACTION_VERIFY
;
1060 SetupCloseInfFile( hinf
);
1062 strcpyW( source_cat
, source
);
1063 p
= strrchrW( source_cat
, '\\' );
1065 else p
= source_cat
;
1066 strcpyW( p
, catalog_file
);
1068 TRACE("installing catalog file %s\n", debugstr_w( source_cat
));
1070 if (!CryptCATAdminAcquireContext(&handle
, &msguid
, 0))
1072 ERR("Could not acquire security context\n");
1076 if (!(cat
= CryptCATAdminAddCatalog(handle
, source_cat
, catalog_file
, 0)))
1078 ERR("Could not add catalog\n");
1079 CryptCATAdminReleaseContext(handle
, 0);
1083 CryptCATAdminReleaseCatalogContext(handle
, cat
, 0);
1084 CryptCATAdminReleaseContext(handle
, 0);
1087 SetupCloseInfFile( hinf
);
1089 if (!(ret
= CopyFileW( source
, target
, (style
& SP_COPY_NOOVERWRITE
) != 0 )))
1092 if (style
& SP_COPY_DELETESOURCE
)
1093 DeleteFileW( source
);
1095 size
= strlenW( target
) + 1;
1098 if (buffer_size
>= size
)
1100 strcpyW( dest
, target
);
1104 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1109 if (component
) *component
= p
+ 1;
1110 if (required_size
) *required_size
= size
;
1111 if (ret
) SetLastError(ERROR_SUCCESS
);
1116 /***********************************************************************
1117 * InstallCatalog (SETUPAPI.@)
1119 DWORD WINAPI
InstallCatalog( LPCSTR catalog
, LPCSTR basename
, LPSTR fullname
)
1121 FIXME("%s, %s, %p\n", debugstr_a(catalog
), debugstr_a(basename
), fullname
);
1125 static UINT
detect_compression_type( LPCWSTR file
)
1129 UINT type
= FILE_COMPRESSION_NONE
;
1130 static const BYTE LZ_MAGIC
[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1131 static const BYTE MSZIP_MAGIC
[] = { 0x4b, 0x57, 0x41, 0x4a };
1132 static const BYTE NTCAB_MAGIC
[] = { 0x4d, 0x53, 0x43, 0x46 };
1135 handle
= CreateFileW( file
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
1136 if (handle
== INVALID_HANDLE_VALUE
)
1138 ERR("cannot open file %s\n", debugstr_w(file
));
1139 return FILE_COMPRESSION_NONE
;
1141 if (!ReadFile( handle
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
1143 CloseHandle( handle
);
1144 return FILE_COMPRESSION_NONE
;
1146 if (!memcmp( buffer
, LZ_MAGIC
, sizeof(LZ_MAGIC
) )) type
= FILE_COMPRESSION_WINLZA
;
1147 else if (!memcmp( buffer
, MSZIP_MAGIC
, sizeof(MSZIP_MAGIC
) )) type
= FILE_COMPRESSION_MSZIP
;
1148 else if (!memcmp( buffer
, NTCAB_MAGIC
, sizeof(NTCAB_MAGIC
) )) type
= FILE_COMPRESSION_MSZIP
; /* not a typo */
1150 CloseHandle( handle
);
1154 static BOOL
get_file_size( LPCWSTR file
, DWORD
*size
)
1158 handle
= CreateFileW( file
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
1159 if (handle
== INVALID_HANDLE_VALUE
)
1161 ERR("cannot open file %s\n", debugstr_w(file
));
1164 *size
= GetFileSize( handle
, NULL
);
1165 CloseHandle( handle
);
1169 static BOOL
get_file_sizes_none( LPCWSTR source
, DWORD
*source_size
, DWORD
*target_size
)
1173 if (!get_file_size( source
, &size
)) return FALSE
;
1174 if (source_size
) *source_size
= size
;
1175 if (target_size
) *target_size
= size
;
1179 static BOOL
get_file_sizes_lz( LPCWSTR source
, DWORD
*source_size
, DWORD
*target_size
)
1186 if (!get_file_size( source
, &size
)) ret
= FALSE
;
1187 else *source_size
= size
;
1194 if ((file
= LZOpenFileW( (LPWSTR
)source
, &of
, OF_READ
)) < 0)
1196 ERR("cannot open source file for reading\n");
1199 *target_size
= LZSeek( file
, 0, 2 );
1205 static UINT CALLBACK
file_compression_info_callback( PVOID context
, UINT notification
, UINT_PTR param1
, UINT_PTR param2
)
1207 DWORD
*size
= context
;
1208 FILE_IN_CABINET_INFO_W
*info
= (FILE_IN_CABINET_INFO_W
*)param1
;
1210 switch (notification
)
1212 case SPFILENOTIFY_FILEINCABINET
:
1214 *size
= info
->FileSize
;
1217 default: return NO_ERROR
;
1221 static BOOL
get_file_sizes_cab( LPCWSTR source
, DWORD
*source_size
, DWORD
*target_size
)
1228 if (!get_file_size( source
, &size
)) ret
= FALSE
;
1229 else *source_size
= size
;
1233 ret
= SetupIterateCabinetW( source
, 0, file_compression_info_callback
, target_size
);
1238 /***********************************************************************
1239 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1241 * See SetupGetFileCompressionInfoExW.
1243 BOOL WINAPI
SetupGetFileCompressionInfoExA( PCSTR source
, PSTR name
, DWORD len
, PDWORD required
,
1244 PDWORD source_size
, PDWORD target_size
, PUINT type
)
1247 WCHAR
*nameW
= NULL
, *sourceW
= NULL
;
1251 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source
), name
, len
, required
,
1252 source_size
, target_size
, type
);
1254 if (!source
|| !(sourceW
= MultiByteToUnicode( source
, CP_ACP
))) return FALSE
;
1258 ret
= SetupGetFileCompressionInfoExW( sourceW
, NULL
, 0, &nb_chars
, NULL
, NULL
, NULL
);
1259 if (!(nameW
= HeapAlloc( GetProcessHeap(), 0, nb_chars
* sizeof(WCHAR
) )))
1265 ret
= SetupGetFileCompressionInfoExW( sourceW
, nameW
, nb_chars
, &nb_chars
, source_size
, target_size
, type
);
1268 if ((nameA
= UnicodeToMultiByte( nameW
, CP_ACP
)))
1270 if (name
&& len
>= nb_chars
) lstrcpyA( name
, nameA
);
1273 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1279 if (required
) *required
= nb_chars
;
1280 HeapFree( GetProcessHeap(), 0, nameW
);
1286 /***********************************************************************
1287 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1289 * Get compression type and compressed/uncompressed sizes of a given file.
1292 * source [I] File to examine.
1293 * name [O] Actual filename used.
1294 * len [I] Length in characters of 'name' buffer.
1295 * required [O] Number of characters written to 'name'.
1296 * source_size [O] Size of compressed file.
1297 * target_size [O] Size of uncompressed file.
1298 * type [O] Compression type.
1304 BOOL WINAPI
SetupGetFileCompressionInfoExW( PCWSTR source
, PWSTR name
, DWORD len
, PDWORD required
,
1305 PDWORD source_size
, PDWORD target_size
, PUINT type
)
1311 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source
), name
, len
, required
,
1312 source_size
, target_size
, type
);
1314 if (!source
) return FALSE
;
1316 source_len
= lstrlenW( source
) + 1;
1317 if (required
) *required
= source_len
;
1318 if (name
&& len
>= source_len
)
1320 lstrcpyW( name
, source
);
1325 comp
= detect_compression_type( source
);
1326 if (type
) *type
= comp
;
1330 case FILE_COMPRESSION_MSZIP
:
1331 case FILE_COMPRESSION_NTCAB
: ret
= get_file_sizes_cab( source
, source_size
, target_size
); break;
1332 case FILE_COMPRESSION_NONE
: ret
= get_file_sizes_none( source
, source_size
, target_size
); break;
1333 case FILE_COMPRESSION_WINLZA
: ret
= get_file_sizes_lz( source
, source_size
, target_size
); break;
1339 /***********************************************************************
1340 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1342 * See SetupGetFileCompressionInfoW.
1344 DWORD WINAPI
SetupGetFileCompressionInfoA( PCSTR source
, PSTR
*name
, PDWORD source_size
,
1345 PDWORD target_size
, PUINT type
)
1348 DWORD error
, required
;
1351 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source
), name
, source_size
, target_size
, type
);
1353 if (!source
|| !name
|| !source_size
|| !target_size
|| !type
)
1354 return ERROR_INVALID_PARAMETER
;
1356 ret
= SetupGetFileCompressionInfoExA( source
, NULL
, 0, &required
, NULL
, NULL
, NULL
);
1357 if (!(actual_name
= MyMalloc( required
))) return ERROR_NOT_ENOUGH_MEMORY
;
1359 ret
= SetupGetFileCompressionInfoExA( source
, actual_name
, required
, &required
,
1360 source_size
, target_size
, type
);
1363 error
= GetLastError();
1364 MyFree( actual_name
);
1367 *name
= actual_name
;
1368 return ERROR_SUCCESS
;
1371 /***********************************************************************
1372 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1374 * Get compression type and compressed/uncompressed sizes of a given file.
1377 * source [I] File to examine.
1378 * name [O] Actual filename used.
1379 * source_size [O] Size of compressed file.
1380 * target_size [O] Size of uncompressed file.
1381 * type [O] Compression type.
1384 * Success: ERROR_SUCCESS
1385 * Failure: Win32 error code.
1387 DWORD WINAPI
SetupGetFileCompressionInfoW( PCWSTR source
, PWSTR
*name
, PDWORD source_size
,
1388 PDWORD target_size
, PUINT type
)
1391 DWORD error
, required
;
1394 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source
), name
, source_size
, target_size
, type
);
1396 if (!source
|| !name
|| !source_size
|| !target_size
|| !type
)
1397 return ERROR_INVALID_PARAMETER
;
1399 ret
= SetupGetFileCompressionInfoExW( source
, NULL
, 0, &required
, NULL
, NULL
, NULL
);
1400 if (!(actual_name
= MyMalloc( required
))) return ERROR_NOT_ENOUGH_MEMORY
;
1402 ret
= SetupGetFileCompressionInfoExW( source
, actual_name
, required
, &required
,
1403 source_size
, target_size
, type
);
1406 error
= GetLastError();
1407 MyFree( actual_name
);
1410 *name
= actual_name
;
1411 return ERROR_SUCCESS
;
1414 static DWORD
decompress_file_lz( LPCWSTR source
, LPCWSTR target
)
1421 if ((src
= LZOpenFileW( (LPWSTR
)source
, &sof
, OF_READ
)) < 0)
1423 ERR("cannot open source file for reading\n");
1424 return ERROR_FILE_NOT_FOUND
;
1426 if ((dst
= LZOpenFileW( (LPWSTR
)target
, &dof
, OF_CREATE
)) < 0)
1428 ERR("cannot open target file for writing\n");
1430 return ERROR_FILE_NOT_FOUND
;
1432 if ((error
= LZCopy( src
, dst
)) >= 0) ret
= ERROR_SUCCESS
;
1435 WARN("failed to decompress file %d\n", error
);
1436 ret
= ERROR_INVALID_DATA
;
1444 static UINT CALLBACK
decompress_or_copy_callback( PVOID context
, UINT notification
, UINT_PTR param1
, UINT_PTR param2
)
1446 FILE_IN_CABINET_INFO_W
*info
= (FILE_IN_CABINET_INFO_W
*)param1
;
1448 switch (notification
)
1450 case SPFILENOTIFY_FILEINCABINET
:
1452 LPCWSTR filename
, targetname
= context
;
1455 if ((p
= strrchrW( targetname
, '\\' ))) filename
= p
+ 1;
1456 else filename
= targetname
;
1458 if (!lstrcmpiW( filename
, info
->NameInCabinet
))
1460 strcpyW( info
->FullTargetName
, targetname
);
1465 default: return NO_ERROR
;
1469 static DWORD
decompress_file_cab( LPCWSTR source
, LPCWSTR target
)
1473 ret
= SetupIterateCabinetW( source
, 0, decompress_or_copy_callback
, (PVOID
)target
);
1475 if (ret
) return ERROR_SUCCESS
;
1476 else return GetLastError();
1479 /***********************************************************************
1480 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1482 * See SetupDecompressOrCopyFileW.
1484 DWORD WINAPI
SetupDecompressOrCopyFileA( PCSTR source
, PCSTR target
, PUINT type
)
1487 WCHAR
*sourceW
= NULL
, *targetW
= NULL
;
1489 if (source
&& !(sourceW
= MultiByteToUnicode( source
, CP_ACP
))) return FALSE
;
1490 if (target
&& !(targetW
= MultiByteToUnicode( target
, CP_ACP
)))
1493 return ERROR_NOT_ENOUGH_MEMORY
;
1496 ret
= SetupDecompressOrCopyFileW( sourceW
, targetW
, type
);
1504 /***********************************************************************
1505 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1507 * Copy a file and decompress it if needed.
1510 * source [I] File to copy.
1511 * target [I] Filename of the copy.
1512 * type [I] Compression type.
1515 * Success: ERROR_SUCCESS
1516 * Failure: Win32 error code.
1518 DWORD WINAPI
SetupDecompressOrCopyFileW( PCWSTR source
, PCWSTR target
, PUINT type
)
1521 DWORD ret
= ERROR_INVALID_PARAMETER
;
1523 if (!source
|| !target
) return ERROR_INVALID_PARAMETER
;
1525 if (!type
) comp
= detect_compression_type( source
);
1530 case FILE_COMPRESSION_NONE
:
1531 if (CopyFileW( source
, target
, FALSE
)) ret
= ERROR_SUCCESS
;
1532 else ret
= GetLastError();
1534 case FILE_COMPRESSION_WINLZA
:
1535 ret
= decompress_file_lz( source
, target
);
1537 case FILE_COMPRESSION_NTCAB
:
1538 case FILE_COMPRESSION_MSZIP
:
1539 ret
= decompress_file_cab( source
, target
);
1542 WARN("unknown compression type %d\n", comp
);
1546 TRACE("%s -> %s %d\n", debugstr_w(source
), debugstr_w(target
), comp
);