setupapi: Fix memory leak on realloc failure in RetreiveFileSecurity.
[wine.git] / dlls / setupapi / misc.c
blob5a4b899dc9d81f96d940cdd45e51d9cea1c9c5c1
1 /*
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
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "setupapi.h"
30 #include "lzexpand.h"
31 #include "softpub.h"
32 #include "mscat.h"
33 #include "shlobj.h"
34 #include "shlwapi.h"
36 #include "wine/debug.h"
38 #include "setupapi_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
42 /* arbitrary limit not related to what native actually uses */
43 #define OEM_INDEX_LIMIT 999
45 /* Handles and critical sections for the SetupLog API */
46 static HANDLE setupact = INVALID_HANDLE_VALUE;
47 static HANDLE setuperr = INVALID_HANDLE_VALUE;
48 static CRITICAL_SECTION setupapi_cs;
49 static CRITICAL_SECTION_DEBUG critsect_debug =
51 0, 0, &setupapi_cs,
52 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
53 0, 0, { (DWORD_PTR)(__FILE__ ": setupapi_cs") }
55 static CRITICAL_SECTION setupapi_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
57 /**************************************************************************
58 * MyFree [SETUPAPI.@]
60 * Frees an allocated memory block from the process heap.
62 * PARAMS
63 * lpMem [I] pointer to memory block which will be freed
65 * RETURNS
66 * None
68 VOID WINAPI MyFree(LPVOID lpMem)
70 HeapFree(GetProcessHeap(), 0, lpMem);
74 /**************************************************************************
75 * MyMalloc [SETUPAPI.@]
77 * Allocates memory block from the process heap.
79 * PARAMS
80 * dwSize [I] size of the allocated memory block
82 * RETURNS
83 * Success: pointer to allocated memory block
84 * Failure: NULL
86 LPVOID WINAPI MyMalloc(DWORD dwSize)
88 return HeapAlloc(GetProcessHeap(), 0, dwSize);
92 /**************************************************************************
93 * MyRealloc [SETUPAPI.@]
95 * Changes the size of an allocated memory block or allocates a memory
96 * block from the process heap.
98 * PARAMS
99 * lpSrc [I] pointer to memory block which will be resized
100 * dwSize [I] new size of the memory block
102 * RETURNS
103 * Success: pointer to the resized memory block
104 * Failure: NULL
106 * NOTES
107 * If lpSrc is a NULL-pointer, then MyRealloc allocates a memory
108 * block like MyMalloc.
110 LPVOID WINAPI MyRealloc(LPVOID lpSrc, DWORD dwSize)
112 if (lpSrc == NULL)
113 return HeapAlloc(GetProcessHeap(), 0, dwSize);
115 return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize);
119 /**************************************************************************
120 * DuplicateString [SETUPAPI.@]
122 * Duplicates a unicode string.
124 * PARAMS
125 * lpSrc [I] pointer to the unicode string that will be duplicated
127 * RETURNS
128 * Success: pointer to the duplicated unicode string
129 * Failure: NULL
131 * NOTES
132 * Call MyFree() to release the duplicated string.
134 LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc)
136 LPWSTR lpDst;
138 lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));
139 if (lpDst == NULL)
140 return NULL;
142 lstrcpyW(lpDst, lpSrc);
144 return lpDst;
148 /**************************************************************************
149 * QueryRegistryValue [SETUPAPI.@]
151 * Retrieves value data from the registry and allocates memory for the
152 * value data.
154 * PARAMS
155 * hKey [I] Handle of the key to query
156 * lpValueName [I] Name of value under hkey to query
157 * lpData [O] Destination for the values contents,
158 * lpType [O] Destination for the value type
159 * lpcbData [O] Destination for the size of data
161 * RETURNS
162 * Success: ERROR_SUCCESS
163 * Failure: Otherwise
165 * NOTES
166 * Use MyFree to release the lpData buffer.
168 LONG WINAPI QueryRegistryValue(HKEY hKey,
169 LPCWSTR lpValueName,
170 LPBYTE *lpData,
171 LPDWORD lpType,
172 LPDWORD lpcbData)
174 LONG lError;
176 TRACE("%p %s %p %p %p\n",
177 hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);
179 /* Get required buffer size */
180 *lpcbData = 0;
181 lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);
182 if (lError != ERROR_SUCCESS)
183 return lError;
185 /* Allocate buffer */
186 *lpData = MyMalloc(*lpcbData);
187 if (*lpData == NULL)
188 return ERROR_NOT_ENOUGH_MEMORY;
190 /* Query registry value */
191 lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);
192 if (lError != ERROR_SUCCESS)
193 MyFree(*lpData);
195 return lError;
199 /**************************************************************************
200 * IsUserAdmin [SETUPAPI.@]
202 * Checks whether the current user is a member of the Administrators group.
204 * PARAMS
205 * None
207 * RETURNS
208 * Success: TRUE
209 * Failure: FALSE
211 BOOL WINAPI IsUserAdmin(VOID)
213 TRACE("\n");
214 return IsUserAnAdmin();
218 /**************************************************************************
219 * MultiByteToUnicode [SETUPAPI.@]
221 * Converts a multi-byte string to a Unicode string.
223 * PARAMS
224 * lpMultiByteStr [I] Multi-byte string to be converted
225 * uCodePage [I] Code page
227 * RETURNS
228 * Success: pointer to the converted Unicode string
229 * Failure: NULL
231 * NOTE
232 * Use MyFree to release the returned Unicode string.
234 LPWSTR WINAPI MultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)
236 LPWSTR lpUnicodeStr;
237 int nLength;
239 nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
240 -1, NULL, 0);
241 if (nLength == 0)
242 return NULL;
244 lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));
245 if (lpUnicodeStr == NULL)
246 return NULL;
248 if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
249 nLength, lpUnicodeStr, nLength))
251 MyFree(lpUnicodeStr);
252 return NULL;
255 return lpUnicodeStr;
259 /**************************************************************************
260 * UnicodeToMultiByte [SETUPAPI.@]
262 * Converts a Unicode string to a multi-byte string.
264 * PARAMS
265 * lpUnicodeStr [I] Unicode string to be converted
266 * uCodePage [I] Code page
268 * RETURNS
269 * Success: pointer to the converted multi-byte string
270 * Failure: NULL
272 * NOTE
273 * Use MyFree to release the returned multi-byte string.
275 LPSTR WINAPI UnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)
277 LPSTR lpMultiByteStr;
278 int nLength;
280 nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
281 NULL, 0, NULL, NULL);
282 if (nLength == 0)
283 return NULL;
285 lpMultiByteStr = MyMalloc(nLength);
286 if (lpMultiByteStr == NULL)
287 return NULL;
289 if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
290 lpMultiByteStr, nLength, NULL, NULL))
292 MyFree(lpMultiByteStr);
293 return NULL;
296 return lpMultiByteStr;
300 /**************************************************************************
301 * DoesUserHavePrivilege [SETUPAPI.@]
303 * Check whether the current user has got a given privilege.
305 * PARAMS
306 * lpPrivilegeName [I] Name of the privilege to be checked
308 * RETURNS
309 * Success: TRUE
310 * Failure: FALSE
312 BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)
314 HANDLE hToken;
315 DWORD dwSize;
316 PTOKEN_PRIVILEGES lpPrivileges;
317 LUID PrivilegeLuid;
318 DWORD i;
319 BOOL bResult = FALSE;
321 TRACE("%s\n", debugstr_w(lpPrivilegeName));
323 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
324 return FALSE;
326 if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
328 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
330 CloseHandle(hToken);
331 return FALSE;
335 lpPrivileges = MyMalloc(dwSize);
336 if (lpPrivileges == NULL)
338 CloseHandle(hToken);
339 return FALSE;
342 if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))
344 MyFree(lpPrivileges);
345 CloseHandle(hToken);
346 return FALSE;
349 CloseHandle(hToken);
351 if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))
353 MyFree(lpPrivileges);
354 return FALSE;
357 for (i = 0; i < lpPrivileges->PrivilegeCount; i++)
359 if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&
360 lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)
362 bResult = TRUE;
366 MyFree(lpPrivileges);
368 return bResult;
372 /**************************************************************************
373 * EnablePrivilege [SETUPAPI.@]
375 * Enables or disables one of the current users privileges.
377 * PARAMS
378 * lpPrivilegeName [I] Name of the privilege to be changed
379 * bEnable [I] TRUE: Enables the privilege
380 * FALSE: Disables the privilege
382 * RETURNS
383 * Success: TRUE
384 * Failure: FALSE
386 BOOL WINAPI EnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)
388 TOKEN_PRIVILEGES Privileges;
389 HANDLE hToken;
390 BOOL bResult;
392 TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");
394 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
395 return FALSE;
397 Privileges.PrivilegeCount = 1;
398 Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
400 if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,
401 &Privileges.Privileges[0].Luid))
403 CloseHandle(hToken);
404 return FALSE;
407 bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);
409 CloseHandle(hToken);
411 return bResult;
415 /**************************************************************************
416 * DelayedMove [SETUPAPI.@]
418 * Moves a file upon the next reboot.
420 * PARAMS
421 * lpExistingFileName [I] Current file name
422 * lpNewFileName [I] New file name
424 * RETURNS
425 * Success: TRUE
426 * Failure: FALSE
428 BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
430 return MoveFileExW(lpExistingFileName, lpNewFileName,
431 MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
435 /**************************************************************************
436 * FileExists [SETUPAPI.@]
438 * Checks whether a file exists.
440 * PARAMS
441 * lpFileName [I] Name of the file to check
442 * lpNewFileName [O] Optional information about the existing file
444 * RETURNS
445 * Success: TRUE
446 * Failure: FALSE
448 BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)
450 WIN32_FIND_DATAW FindData;
451 HANDLE hFind;
452 UINT uErrorMode;
453 DWORD dwError;
455 uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
457 hFind = FindFirstFileW(lpFileName, &FindData);
458 if (hFind == INVALID_HANDLE_VALUE)
460 dwError = GetLastError();
461 SetErrorMode(uErrorMode);
462 SetLastError(dwError);
463 return FALSE;
466 FindClose(hFind);
468 if (lpFileFindData)
469 *lpFileFindData = FindData;
471 SetErrorMode(uErrorMode);
473 return TRUE;
477 /**************************************************************************
478 * CaptureStringArg [SETUPAPI.@]
480 * Captures a UNICODE string.
482 * PARAMS
483 * lpSrc [I] UNICODE string to be captured
484 * lpDst [O] Pointer to the captured UNICODE string
486 * RETURNS
487 * Success: ERROR_SUCCESS
488 * Failure: ERROR_INVALID_PARAMETER
490 * NOTE
491 * Call MyFree to release the captured UNICODE string.
493 DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)
495 if (pDst == NULL)
496 return ERROR_INVALID_PARAMETER;
498 *pDst = DuplicateString(pSrc);
500 return ERROR_SUCCESS;
504 /**************************************************************************
505 * CaptureAndConvertAnsiArg [SETUPAPI.@]
507 * Captures an ANSI string and converts it to a UNICODE string.
509 * PARAMS
510 * lpSrc [I] ANSI string to be captured
511 * lpDst [O] Pointer to the captured UNICODE string
513 * RETURNS
514 * Success: ERROR_SUCCESS
515 * Failure: ERROR_INVALID_PARAMETER
517 * NOTE
518 * Call MyFree to release the captured UNICODE string.
520 DWORD WINAPI CaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)
522 if (pDst == NULL)
523 return ERROR_INVALID_PARAMETER;
525 *pDst = MultiByteToUnicode(pSrc, CP_ACP);
527 return ERROR_SUCCESS;
531 /**************************************************************************
532 * OpenAndMapFileForRead [SETUPAPI.@]
534 * Open and map a file to a buffer.
536 * PARAMS
537 * lpFileName [I] Name of the file to be opened
538 * lpSize [O] Pointer to the file size
539 * lpFile [0] Pointer to the file handle
540 * lpMapping [0] Pointer to the mapping handle
541 * lpBuffer [0] Pointer to the file buffer
543 * RETURNS
544 * Success: ERROR_SUCCESS
545 * Failure: Other
547 * NOTE
548 * Call UnmapAndCloseFile to release the file.
550 DWORD WINAPI OpenAndMapFileForRead(LPCWSTR lpFileName,
551 LPDWORD lpSize,
552 LPHANDLE lpFile,
553 LPHANDLE lpMapping,
554 LPVOID *lpBuffer)
556 DWORD dwError;
558 TRACE("%s %p %p %p %p\n",
559 debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);
561 *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
562 OPEN_EXISTING, 0, NULL);
563 if (*lpFile == INVALID_HANDLE_VALUE)
564 return GetLastError();
566 *lpSize = GetFileSize(*lpFile, NULL);
567 if (*lpSize == INVALID_FILE_SIZE)
569 dwError = GetLastError();
570 CloseHandle(*lpFile);
571 return dwError;
574 *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,
575 *lpSize, NULL);
576 if (*lpMapping == NULL)
578 dwError = GetLastError();
579 CloseHandle(*lpFile);
580 return dwError;
583 *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);
584 if (*lpBuffer == NULL)
586 dwError = GetLastError();
587 CloseHandle(*lpMapping);
588 CloseHandle(*lpFile);
589 return dwError;
592 return ERROR_SUCCESS;
596 /**************************************************************************
597 * UnmapAndCloseFile [SETUPAPI.@]
599 * Unmap and close a mapped file.
601 * PARAMS
602 * hFile [I] Handle to the file
603 * hMapping [I] Handle to the file mapping
604 * lpBuffer [I] Pointer to the file buffer
606 * RETURNS
607 * Success: TRUE
608 * Failure: FALSE
610 BOOL WINAPI UnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)
612 TRACE("%p %p %p\n",
613 hFile, hMapping, lpBuffer);
615 if (!UnmapViewOfFile(lpBuffer))
616 return FALSE;
618 if (!CloseHandle(hMapping))
619 return FALSE;
621 if (!CloseHandle(hFile))
622 return FALSE;
624 return TRUE;
628 /**************************************************************************
629 * StampFileSecurity [SETUPAPI.@]
631 * Assign a new security descriptor to the given file.
633 * PARAMS
634 * lpFileName [I] Name of the file
635 * pSecurityDescriptor [I] New security descriptor
637 * RETURNS
638 * Success: ERROR_SUCCESS
639 * Failure: other
641 DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)
643 TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
645 if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
646 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
647 pSecurityDescriptor))
648 return GetLastError();
650 return ERROR_SUCCESS;
654 /**************************************************************************
655 * TakeOwnershipOfFile [SETUPAPI.@]
657 * Takes the ownership of the given file.
659 * PARAMS
660 * lpFileName [I] Name of the file
662 * RETURNS
663 * Success: ERROR_SUCCESS
664 * Failure: other
666 DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)
668 SECURITY_DESCRIPTOR SecDesc;
669 HANDLE hToken = NULL;
670 PTOKEN_OWNER pOwner = NULL;
671 DWORD dwError;
672 DWORD dwSize;
674 TRACE("%s\n", debugstr_w(lpFileName));
676 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
677 return GetLastError();
679 if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))
681 goto fail;
684 pOwner = MyMalloc(dwSize);
685 if (pOwner == NULL)
687 CloseHandle(hToken);
688 return ERROR_NOT_ENOUGH_MEMORY;
691 if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))
693 goto fail;
696 if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
698 goto fail;
701 if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))
703 goto fail;
706 if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))
708 goto fail;
711 MyFree(pOwner);
712 CloseHandle(hToken);
714 return ERROR_SUCCESS;
716 fail:;
717 dwError = GetLastError();
719 MyFree(pOwner);
721 if (hToken != NULL)
722 CloseHandle(hToken);
724 return dwError;
728 /**************************************************************************
729 * RetreiveFileSecurity [SETUPAPI.@]
731 * Retrieve the security descriptor that is associated with the given file.
733 * PARAMS
734 * lpFileName [I] Name of the file
736 * RETURNS
737 * Success: ERROR_SUCCESS
738 * Failure: other
740 DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,
741 PSECURITY_DESCRIPTOR *pSecurityDescriptor)
743 SECURITY_DESCRIPTOR *SecDesc, *NewSecDesc;
744 DWORD dwSize = 0x100;
745 DWORD dwError;
747 SecDesc = MyMalloc(dwSize);
748 if (SecDesc == NULL)
749 return ERROR_NOT_ENOUGH_MEMORY;
751 if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
752 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
753 SecDesc, dwSize, &dwSize))
755 *pSecurityDescriptor = SecDesc;
756 return ERROR_SUCCESS;
759 dwError = GetLastError();
760 if (dwError != ERROR_INSUFFICIENT_BUFFER)
762 MyFree(SecDesc);
763 return dwError;
766 NewSecDesc = MyRealloc(SecDesc, dwSize);
767 if (NewSecDesc == NULL)
769 MyFree(SecDesc);
770 return ERROR_NOT_ENOUGH_MEMORY;
772 SecDesc = NewSecDesc;
774 if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
775 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
776 SecDesc, dwSize, &dwSize))
778 *pSecurityDescriptor = SecDesc;
779 return ERROR_SUCCESS;
782 dwError = GetLastError();
783 MyFree(SecDesc);
785 return dwError;
789 static DWORD global_flags = 0; /* FIXME: what should be in here? */
791 /***********************************************************************
792 * pSetupGetGlobalFlags (SETUPAPI.@)
794 DWORD WINAPI pSetupGetGlobalFlags(void)
796 FIXME( "stub\n" );
797 return global_flags;
801 /***********************************************************************
802 * pSetupSetGlobalFlags (SETUPAPI.@)
804 void WINAPI pSetupSetGlobalFlags( DWORD flags )
806 global_flags = flags;
809 /***********************************************************************
810 * CMP_WaitNoPendingInstallEvents (SETUPAPI.@)
812 DWORD WINAPI CMP_WaitNoPendingInstallEvents( DWORD dwTimeout )
814 static BOOL warned = FALSE;
816 if (!warned)
818 FIXME("%ld\n", dwTimeout);
819 warned = TRUE;
821 return WAIT_OBJECT_0;
824 /***********************************************************************
825 * AssertFail (SETUPAPI.@)
827 * Shows an assert fail error messagebox
829 * PARAMS
830 * lpFile [I] file where assert failed
831 * uLine [I] line number in file
832 * lpMessage [I] assert message
835 void WINAPI AssertFail(LPCSTR lpFile, UINT uLine, LPCSTR lpMessage)
837 FIXME("%s %u %s\n", lpFile, uLine, lpMessage);
840 /***********************************************************************
841 * SetupCopyOEMInfA (SETUPAPI.@)
843 BOOL WINAPI SetupCopyOEMInfA( PCSTR source, PCSTR location,
844 DWORD media_type, DWORD style, PSTR dest,
845 DWORD buffer_size, PDWORD required_size, PSTR *component )
847 BOOL ret = FALSE;
848 LPWSTR destW = NULL, sourceW = NULL, locationW = NULL;
849 DWORD size;
851 TRACE("%s, %s, %ld, %ld, %p, %ld, %p, %p\n", debugstr_a(source), debugstr_a(location),
852 media_type, style, dest, buffer_size, required_size, component);
854 if (dest && !(destW = MyMalloc( buffer_size * sizeof(WCHAR) ))) return FALSE;
855 if (source && !(sourceW = strdupAtoW( source ))) goto done;
856 if (location && !(locationW = strdupAtoW( location ))) goto done;
858 ret = SetupCopyOEMInfW( sourceW, locationW, media_type, style, destW, buffer_size, &size, NULL );
860 if (required_size) *required_size = size;
862 if (dest)
864 if (buffer_size >= size)
866 WideCharToMultiByte( CP_ACP, 0, destW, -1, dest, buffer_size, NULL, NULL );
867 if (component) *component = strrchr( dest, '\\' ) + 1;
869 else
870 SetLastError( ERROR_INSUFFICIENT_BUFFER );
873 done:
874 MyFree( destW );
875 HeapFree( GetProcessHeap(), 0, sourceW );
876 HeapFree( GetProcessHeap(), 0, locationW );
877 if (ret) SetLastError(ERROR_SUCCESS);
878 return ret;
881 static int compare_files( HANDLE file1, HANDLE file2 )
883 char buffer1[2048];
884 char buffer2[2048];
885 DWORD size1;
886 DWORD size2;
888 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) &&
889 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) )
891 int ret;
892 if (size1 != size2)
893 return size1 > size2 ? 1 : -1;
894 if (!size1)
895 return 0;
896 ret = memcmp( buffer1, buffer2, size1 );
897 if (ret)
898 return ret;
901 return 0;
904 static BOOL find_existing_inf(const WCHAR *source, WCHAR *target)
906 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
907 static const WCHAR wildcardW[] = {'*',0};
909 LARGE_INTEGER source_file_size, dest_file_size;
910 HANDLE source_file, dest_file;
911 WIN32_FIND_DATAW find_data;
912 HANDLE find_handle;
914 source_file = CreateFileW( source, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
915 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
916 NULL, OPEN_EXISTING, 0, NULL );
917 if (source_file == INVALID_HANDLE_VALUE)
918 return FALSE;
920 if (!GetFileSizeEx( source_file, &source_file_size ))
922 CloseHandle( source_file );
923 return FALSE;
926 GetWindowsDirectoryW( target, MAX_PATH );
927 lstrcatW( target, infW );
928 lstrcatW( target, wildcardW );
929 if ((find_handle = FindFirstFileW( target, &find_data )) != INVALID_HANDLE_VALUE)
931 do {
932 GetWindowsDirectoryW( target, MAX_PATH );
933 lstrcatW( target, infW );
934 lstrcatW( target, find_data.cFileName );
935 dest_file = CreateFileW( target, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
936 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
937 NULL, OPEN_EXISTING, 0, NULL );
938 if (dest_file == INVALID_HANDLE_VALUE)
939 continue;
941 SetFilePointer( source_file, 0, NULL, FILE_BEGIN );
943 if (GetFileSizeEx( dest_file, &dest_file_size )
944 && dest_file_size.QuadPart == source_file_size.QuadPart
945 && !compare_files( source_file, dest_file ))
947 CloseHandle( dest_file );
948 CloseHandle( source_file );
949 FindClose( find_handle );
950 return TRUE;
952 CloseHandle( dest_file );
953 } while (FindNextFileW( find_handle, &find_data ));
955 FindClose( find_handle );
958 CloseHandle( source_file );
959 return FALSE;
962 /***********************************************************************
963 * SetupCopyOEMInfW (SETUPAPI.@)
965 BOOL WINAPI SetupCopyOEMInfW( PCWSTR source, PCWSTR location,
966 DWORD media_type, DWORD style, PWSTR dest,
967 DWORD buffer_size, DWORD *required_size, WCHAR **filepart )
969 BOOL ret = FALSE;
970 WCHAR target[MAX_PATH], catalog_file[MAX_PATH], pnf_path[MAX_PATH], *p;
971 static const WCHAR inf[] = { '\\','i','n','f','\\',0 };
972 static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 };
973 static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 };
974 FILE *pnf_file;
975 unsigned int i;
976 DWORD size;
977 HINF hinf;
979 TRACE("%s, %s, %ld, %ld, %p, %ld, %p, %p\n", debugstr_w(source), debugstr_w(location),
980 media_type, style, dest, buffer_size, required_size, filepart);
982 if (!source)
984 SetLastError(ERROR_INVALID_PARAMETER);
985 return FALSE;
988 /* check for a relative path */
989 if (!(*source == '\\' || (*source && source[1] == ':')))
991 SetLastError(ERROR_FILE_NOT_FOUND);
992 return FALSE;
995 if (find_existing_inf( source, target ))
997 TRACE("Found existing INF %s.\n", debugstr_w(target));
998 if (style & SP_COPY_NOOVERWRITE)
1000 SetLastError( ERROR_FILE_EXISTS );
1001 ret = FALSE;
1003 else
1004 ret = TRUE;
1005 goto done;
1008 GetWindowsDirectoryW( target, ARRAY_SIZE(target) );
1009 lstrcatW( target, inf );
1010 lstrcatW( target, wcsrchr( source, '\\' ) + 1 );
1011 if (GetFileAttributesW( target ) != INVALID_FILE_ATTRIBUTES)
1013 for (i = 0; i < OEM_INDEX_LIMIT; i++)
1015 static const WCHAR formatW[] = {'o','e','m','%','u','.','i','n','f',0};
1017 GetWindowsDirectoryW( target, ARRAY_SIZE(target) );
1018 lstrcatW( target, inf );
1019 swprintf( target + lstrlenW(target), ARRAY_SIZE(target) - lstrlenW(target), formatW, i );
1021 if (GetFileAttributesW( target ) == INVALID_FILE_ATTRIBUTES)
1022 break;
1024 if (i == OEM_INDEX_LIMIT)
1026 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1027 return FALSE;
1031 hinf = SetupOpenInfFileW( source, NULL, INF_STYLE_WIN4, NULL );
1032 if (hinf == INVALID_HANDLE_VALUE) return FALSE;
1034 if (SetupGetLineTextW( NULL, hinf, wszVersion, wszCatalogFile, catalog_file,
1035 ARRAY_SIZE( catalog_file ), NULL ))
1037 WCHAR source_cat[MAX_PATH];
1038 HCATADMIN handle;
1039 HCATINFO cat;
1040 GUID msguid = DRIVER_ACTION_VERIFY;
1042 SetupCloseInfFile( hinf );
1044 lstrcpyW( source_cat, source );
1045 p = wcsrchr( source_cat, '\\' );
1046 if (p) p++;
1047 else p = source_cat;
1048 lstrcpyW( p, catalog_file );
1050 TRACE("installing catalog file %s\n", debugstr_w( source_cat ));
1052 if (!CryptCATAdminAcquireContext(&handle, &msguid, 0))
1054 ERR("Could not acquire security context\n");
1055 return FALSE;
1058 if (!(cat = CryptCATAdminAddCatalog(handle, source_cat, catalog_file, 0)))
1060 ERR("Could not add catalog\n");
1061 CryptCATAdminReleaseContext(handle, 0);
1062 return FALSE;
1065 CryptCATAdminReleaseCatalogContext(handle, cat, 0);
1066 CryptCATAdminReleaseContext(handle, 0);
1068 else
1069 SetupCloseInfFile( hinf );
1071 if (!(ret = CopyFileW( source, target, TRUE )))
1072 return ret;
1074 done:
1075 if (style & SP_COPY_DELETESOURCE)
1076 DeleteFileW( source );
1078 if (ret)
1080 wcscpy(pnf_path, target);
1081 PathRemoveExtensionW(pnf_path);
1082 PathAddExtensionW(pnf_path, L".pnf");
1083 if ((pnf_file = _wfopen(pnf_path, L"w")))
1085 fputws(PNF_HEADER, pnf_file);
1086 fputws(source, pnf_file);
1087 fclose(pnf_file);
1091 size = lstrlenW( target ) + 1;
1092 if (dest)
1094 if (buffer_size >= size)
1096 lstrcpyW( dest, target );
1097 if (filepart) *filepart = wcsrchr( dest, '\\' ) + 1;
1099 else
1101 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1102 ret = FALSE;
1106 if (required_size) *required_size = size;
1107 if (ret) SetLastError(ERROR_SUCCESS);
1109 return ret;
1112 /***********************************************************************
1113 * SetupUninstallOEMInfA (SETUPAPI.@)
1115 BOOL WINAPI SetupUninstallOEMInfA( PCSTR inf_file, DWORD flags, PVOID reserved )
1117 BOOL ret;
1118 WCHAR *inf_fileW = NULL;
1120 TRACE("%s, 0x%08lx, %p\n", debugstr_a(inf_file), flags, reserved);
1122 if (inf_file && !(inf_fileW = strdupAtoW( inf_file ))) return FALSE;
1123 ret = SetupUninstallOEMInfW( inf_fileW, flags, reserved );
1124 HeapFree( GetProcessHeap(), 0, inf_fileW );
1125 return ret;
1128 /***********************************************************************
1129 * SetupUninstallOEMInfW (SETUPAPI.@)
1131 BOOL WINAPI SetupUninstallOEMInfW( PCWSTR inf_file, DWORD flags, PVOID reserved )
1133 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
1134 WCHAR target[MAX_PATH];
1136 TRACE("%s, 0x%08lx, %p\n", debugstr_w(inf_file), flags, reserved);
1138 if (!inf_file)
1140 SetLastError(ERROR_INVALID_PARAMETER);
1141 return FALSE;
1144 if (!GetWindowsDirectoryW( target, ARRAY_SIZE( target ))) return FALSE;
1146 lstrcatW( target, infW );
1147 lstrcatW( target, inf_file );
1149 if (flags & SUOI_FORCEDELETE)
1150 return DeleteFileW(target);
1152 FIXME("not deleting %s\n", debugstr_w(target));
1154 return TRUE;
1157 /***********************************************************************
1158 * InstallCatalog (SETUPAPI.@)
1160 DWORD WINAPI InstallCatalog( LPCSTR catalog, LPCSTR basename, LPSTR fullname )
1162 FIXME("%s, %s, %p\n", debugstr_a(catalog), debugstr_a(basename), fullname);
1163 return 0;
1166 /***********************************************************************
1167 * pSetupInstallCatalog (SETUPAPI.@)
1169 DWORD WINAPI pSetupInstallCatalog( LPCWSTR catalog, LPCWSTR basename, LPWSTR fullname )
1171 HCATADMIN admin;
1172 HCATINFO cat;
1174 TRACE ("%s, %s, %p\n", debugstr_w(catalog), debugstr_w(basename), fullname);
1176 if (!CryptCATAdminAcquireContext(&admin,NULL,0))
1177 return GetLastError();
1179 if (!(cat = CryptCATAdminAddCatalog( admin, (PWSTR)catalog, (PWSTR)basename, 0 )))
1181 DWORD rc = GetLastError();
1182 CryptCATAdminReleaseContext(admin, 0);
1183 return rc;
1185 CryptCATAdminReleaseCatalogContext(admin, cat, 0);
1186 CryptCATAdminReleaseContext(admin,0);
1188 if (fullname)
1189 FIXME("not returning full installed catalog path\n");
1191 return NO_ERROR;
1194 static UINT detect_compression_type( LPCWSTR file )
1196 DWORD size;
1197 HANDLE handle;
1198 UINT type = FILE_COMPRESSION_NONE;
1199 static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1200 static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1201 static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1202 BYTE buffer[8];
1204 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1205 if (handle == INVALID_HANDLE_VALUE)
1207 ERR("cannot open file %s\n", debugstr_w(file));
1208 return FILE_COMPRESSION_NONE;
1210 if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1212 CloseHandle( handle );
1213 return FILE_COMPRESSION_NONE;
1215 if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1216 else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1217 else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1219 CloseHandle( handle );
1220 return type;
1223 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1225 HANDLE handle;
1227 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1228 if (handle == INVALID_HANDLE_VALUE)
1230 ERR("cannot open file %s\n", debugstr_w(file));
1231 return FALSE;
1233 *size = GetFileSize( handle, NULL );
1234 CloseHandle( handle );
1235 return TRUE;
1238 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1240 DWORD size;
1242 if (!get_file_size( source, &size )) return FALSE;
1243 if (source_size) *source_size = size;
1244 if (target_size) *target_size = size;
1245 return TRUE;
1248 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1250 DWORD size;
1251 BOOL ret = TRUE;
1253 if (source_size)
1255 if (!get_file_size( source, &size )) ret = FALSE;
1256 else *source_size = size;
1258 if (target_size)
1260 INT file;
1261 OFSTRUCT of;
1263 if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1265 ERR("cannot open source file for reading\n");
1266 return FALSE;
1268 *target_size = LZSeek( file, 0, 2 );
1269 LZClose( file );
1271 return ret;
1274 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1276 DWORD *size = context;
1277 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1279 switch (notification)
1281 case SPFILENOTIFY_FILEINCABINET:
1283 *size = info->FileSize;
1284 return FILEOP_SKIP;
1286 default: return NO_ERROR;
1290 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1292 DWORD size;
1293 BOOL ret = TRUE;
1295 if (source_size)
1297 if (!get_file_size( source, &size )) ret = FALSE;
1298 else *source_size = size;
1300 if (target_size)
1302 ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1304 return ret;
1307 /***********************************************************************
1308 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1310 * See SetupGetFileCompressionInfoExW.
1312 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1313 PDWORD source_size, PDWORD target_size, PUINT type )
1315 BOOL ret;
1316 WCHAR *nameW = NULL, *sourceW = NULL;
1317 DWORD nb_chars = 0;
1318 LPSTR nameA;
1320 TRACE("%s, %p, %ld, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1321 source_size, target_size, type);
1323 if (!source || !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1325 if (name)
1327 ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1328 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, nb_chars * sizeof(WCHAR) )))
1330 MyFree( sourceW );
1331 return FALSE;
1334 ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1335 if (ret)
1337 if ((nameA = UnicodeToMultiByte( nameW, CP_ACP )))
1339 if (name && len >= nb_chars) lstrcpyA( name, nameA );
1340 else
1342 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1343 ret = FALSE;
1345 MyFree( nameA );
1348 if (required) *required = nb_chars;
1349 HeapFree( GetProcessHeap(), 0, nameW );
1350 MyFree( sourceW );
1352 return ret;
1355 /***********************************************************************
1356 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1358 * Get compression type and compressed/uncompressed sizes of a given file.
1360 * PARAMS
1361 * source [I] File to examine.
1362 * name [O] Actual filename used.
1363 * len [I] Length in characters of 'name' buffer.
1364 * required [O] Number of characters written to 'name'.
1365 * source_size [O] Size of compressed file.
1366 * target_size [O] Size of uncompressed file.
1367 * type [O] Compression type.
1369 * RETURNS
1370 * Success: TRUE
1371 * Failure: FALSE
1373 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1374 PDWORD source_size, PDWORD target_size, PUINT type )
1376 UINT comp;
1377 BOOL ret = FALSE;
1378 DWORD source_len;
1380 TRACE("%s, %p, %ld, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1381 source_size, target_size, type);
1383 if (!source) return FALSE;
1385 source_len = lstrlenW( source ) + 1;
1386 if (required) *required = source_len;
1387 if (name && len >= source_len)
1389 lstrcpyW( name, source );
1390 ret = TRUE;
1392 else return FALSE;
1394 comp = detect_compression_type( source );
1395 if (type) *type = comp;
1397 switch (comp)
1399 case FILE_COMPRESSION_MSZIP:
1400 case FILE_COMPRESSION_NTCAB: ret = get_file_sizes_cab( source, source_size, target_size ); break;
1401 case FILE_COMPRESSION_NONE: ret = get_file_sizes_none( source, source_size, target_size ); break;
1402 case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1403 default: break;
1405 return ret;
1408 /***********************************************************************
1409 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1411 * See SetupGetFileCompressionInfoW.
1413 DWORD WINAPI SetupGetFileCompressionInfoA( PCSTR source, PSTR *name, PDWORD source_size,
1414 PDWORD target_size, PUINT type )
1416 BOOL ret;
1417 DWORD error, required;
1418 LPSTR actual_name;
1420 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source), name, source_size, target_size, type);
1422 if (!source || !name || !source_size || !target_size || !type)
1423 return ERROR_INVALID_PARAMETER;
1425 ret = SetupGetFileCompressionInfoExA( source, NULL, 0, &required, NULL, NULL, NULL );
1426 if (!(actual_name = MyMalloc( required ))) return ERROR_NOT_ENOUGH_MEMORY;
1428 ret = SetupGetFileCompressionInfoExA( source, actual_name, required, &required,
1429 source_size, target_size, type );
1430 if (!ret)
1432 error = GetLastError();
1433 MyFree( actual_name );
1434 return error;
1436 *name = actual_name;
1437 return ERROR_SUCCESS;
1440 /***********************************************************************
1441 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1443 * Get compression type and compressed/uncompressed sizes of a given file.
1445 * PARAMS
1446 * source [I] File to examine.
1447 * name [O] Actual filename used.
1448 * source_size [O] Size of compressed file.
1449 * target_size [O] Size of uncompressed file.
1450 * type [O] Compression type.
1452 * RETURNS
1453 * Success: ERROR_SUCCESS
1454 * Failure: Win32 error code.
1456 DWORD WINAPI SetupGetFileCompressionInfoW( PCWSTR source, PWSTR *name, PDWORD source_size,
1457 PDWORD target_size, PUINT type )
1459 BOOL ret;
1460 DWORD error, required;
1461 LPWSTR actual_name;
1463 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source), name, source_size, target_size, type);
1465 if (!source || !name || !source_size || !target_size || !type)
1466 return ERROR_INVALID_PARAMETER;
1468 ret = SetupGetFileCompressionInfoExW( source, NULL, 0, &required, NULL, NULL, NULL );
1469 if (!(actual_name = MyMalloc( required * sizeof(WCHAR) )))
1470 return ERROR_NOT_ENOUGH_MEMORY;
1472 ret = SetupGetFileCompressionInfoExW( source, actual_name, required, &required,
1473 source_size, target_size, type );
1474 if (!ret)
1476 error = GetLastError();
1477 MyFree( actual_name );
1478 return error;
1480 *name = actual_name;
1481 return ERROR_SUCCESS;
1484 static DWORD decompress_file_lz( LPCWSTR source, LPCWSTR target )
1486 DWORD ret;
1487 LONG error;
1488 INT src, dst;
1489 OFSTRUCT sof, dof;
1491 if ((src = LZOpenFileW( (LPWSTR)source, &sof, OF_READ )) < 0)
1493 ERR("cannot open source file for reading\n");
1494 return ERROR_FILE_NOT_FOUND;
1496 if ((dst = LZOpenFileW( (LPWSTR)target, &dof, OF_CREATE )) < 0)
1498 ERR("cannot open target file for writing\n");
1499 LZClose( src );
1500 return ERROR_FILE_NOT_FOUND;
1502 if ((error = LZCopy( src, dst )) >= 0) ret = ERROR_SUCCESS;
1503 else
1505 WARN("failed to decompress file %ld\n", error);
1506 ret = ERROR_INVALID_DATA;
1509 LZClose( src );
1510 LZClose( dst );
1511 return ret;
1514 struct callback_context
1516 BOOL has_extracted;
1517 LPCWSTR target;
1520 static UINT CALLBACK decompress_or_copy_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1522 struct callback_context *context_info = context;
1523 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1525 switch (notification)
1527 case SPFILENOTIFY_FILEINCABINET:
1529 if (context_info->has_extracted)
1530 return FILEOP_ABORT;
1532 TRACE("Requesting extraction of cabinet file %s\n",
1533 wine_dbgstr_w(info->NameInCabinet));
1534 lstrcpyW( info->FullTargetName, context_info->target );
1535 context_info->has_extracted = TRUE;
1536 return FILEOP_DOIT;
1538 default: return NO_ERROR;
1542 static DWORD decompress_file_cab( LPCWSTR source, LPCWSTR target )
1544 struct callback_context context = {0, target};
1545 BOOL ret;
1547 ret = SetupIterateCabinetW( source, 0, decompress_or_copy_callback, &context );
1549 if (ret) return ERROR_SUCCESS;
1550 else return GetLastError();
1553 /***********************************************************************
1554 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1556 * See SetupDecompressOrCopyFileW.
1558 DWORD WINAPI SetupDecompressOrCopyFileA( PCSTR source, PCSTR target, PUINT type )
1560 DWORD ret = 0;
1561 WCHAR *sourceW = NULL, *targetW = NULL;
1563 if (source && !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1564 if (target && !(targetW = MultiByteToUnicode( target, CP_ACP )))
1566 MyFree( sourceW );
1567 return ERROR_NOT_ENOUGH_MEMORY;
1570 ret = SetupDecompressOrCopyFileW( sourceW, targetW, type );
1572 MyFree( sourceW );
1573 MyFree( targetW );
1575 return ret;
1578 /***********************************************************************
1579 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1581 * Copy a file and decompress it if needed.
1583 * PARAMS
1584 * source [I] File to copy.
1585 * target [I] Filename of the copy.
1586 * type [I] Compression type.
1588 * RETURNS
1589 * Success: ERROR_SUCCESS
1590 * Failure: Win32 error code.
1592 DWORD WINAPI SetupDecompressOrCopyFileW( PCWSTR source, PCWSTR target, PUINT type )
1594 UINT comp;
1595 DWORD ret = ERROR_INVALID_PARAMETER;
1597 TRACE("(%s, %s, %p)\n", debugstr_w(source), debugstr_w(target), type);
1599 if (!source || !target) return ERROR_INVALID_PARAMETER;
1601 if (!type)
1603 comp = detect_compression_type( source );
1604 TRACE("Detected compression type %u\n", comp);
1606 else
1608 comp = *type;
1609 TRACE("Using specified compression type %u\n", comp);
1612 switch (comp)
1614 case FILE_COMPRESSION_NONE:
1615 if (CopyFileW( source, target, FALSE )) ret = ERROR_SUCCESS;
1616 else ret = GetLastError();
1617 break;
1618 case FILE_COMPRESSION_WINLZA:
1619 ret = decompress_file_lz( source, target );
1620 break;
1621 case FILE_COMPRESSION_NTCAB:
1622 case FILE_COMPRESSION_MSZIP:
1623 ret = decompress_file_cab( source, target );
1624 break;
1625 default:
1626 WARN("unknown compression type %d\n", comp);
1627 break;
1630 TRACE("%s -> %s %d\n", debugstr_w(source), debugstr_w(target), comp);
1631 return ret;
1634 static BOOL non_interactive_mode;
1636 /***********************************************************************
1637 * SetupGetNonInteractiveMode (SETUPAPI.@)
1639 BOOL WINAPI SetupGetNonInteractiveMode( void )
1641 FIXME("\n");
1642 return non_interactive_mode;
1645 /***********************************************************************
1646 * SetupSetNonInteractiveMode (SETUPAPI.@)
1648 BOOL WINAPI SetupSetNonInteractiveMode( BOOL flag )
1650 BOOL ret = non_interactive_mode;
1652 FIXME("%d\n", flag);
1654 non_interactive_mode = flag;
1655 return ret;
1658 /***********************************************************************
1659 * SetupCloseLog(SETUPAPI.@)
1661 void WINAPI SetupCloseLog(void)
1663 EnterCriticalSection(&setupapi_cs);
1665 CloseHandle(setupact);
1666 setupact = INVALID_HANDLE_VALUE;
1668 CloseHandle(setuperr);
1669 setuperr = INVALID_HANDLE_VALUE;
1671 LeaveCriticalSection(&setupapi_cs);
1674 /***********************************************************************
1675 * SetupOpenLog(SETUPAPI.@)
1677 BOOL WINAPI SetupOpenLog(BOOL reserved)
1679 WCHAR path[MAX_PATH];
1681 static const WCHAR setupactlog[] = {'\\','s','e','t','u','p','a','c','t','.','l','o','g',0};
1682 static const WCHAR setuperrlog[] = {'\\','s','e','t','u','p','e','r','r','.','l','o','g',0};
1684 EnterCriticalSection(&setupapi_cs);
1686 if (setupact != INVALID_HANDLE_VALUE && setuperr != INVALID_HANDLE_VALUE)
1688 LeaveCriticalSection(&setupapi_cs);
1689 return TRUE;
1692 GetWindowsDirectoryW(path, MAX_PATH);
1693 lstrcatW(path, setupactlog);
1695 setupact = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1696 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1697 if (setupact == INVALID_HANDLE_VALUE)
1699 LeaveCriticalSection(&setupapi_cs);
1700 return FALSE;
1703 SetFilePointer(setupact, 0, NULL, FILE_END);
1705 GetWindowsDirectoryW(path, MAX_PATH);
1706 lstrcatW(path, setuperrlog);
1708 setuperr = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
1709 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1710 if (setuperr == INVALID_HANDLE_VALUE)
1712 CloseHandle(setupact);
1713 setupact = INVALID_HANDLE_VALUE;
1714 LeaveCriticalSection(&setupapi_cs);
1715 return FALSE;
1718 SetFilePointer(setuperr, 0, NULL, FILE_END);
1720 LeaveCriticalSection(&setupapi_cs);
1722 return TRUE;
1725 /***********************************************************************
1726 * SetupLogErrorA(SETUPAPI.@)
1728 BOOL WINAPI SetupLogErrorA(LPCSTR message, LogSeverity severity)
1730 static const char null[] = "(null)";
1731 BOOL ret;
1732 DWORD written;
1733 DWORD len;
1735 EnterCriticalSection(&setupapi_cs);
1737 if (setupact == INVALID_HANDLE_VALUE || setuperr == INVALID_HANDLE_VALUE)
1739 SetLastError(ERROR_FILE_INVALID);
1740 ret = FALSE;
1741 goto done;
1744 if (message == NULL)
1745 message = null;
1747 len = lstrlenA(message);
1749 ret = WriteFile(setupact, message, len, &written, NULL);
1750 if (!ret)
1751 goto done;
1753 if (severity >= LogSevMaximum)
1755 ret = FALSE;
1756 goto done;
1759 if (severity > LogSevInformation)
1760 ret = WriteFile(setuperr, message, len, &written, NULL);
1762 done:
1763 LeaveCriticalSection(&setupapi_cs);
1764 return ret;
1767 /***********************************************************************
1768 * SetupLogErrorW(SETUPAPI.@)
1770 BOOL WINAPI SetupLogErrorW(LPCWSTR message, LogSeverity severity)
1772 LPSTR msg = NULL;
1773 DWORD len;
1774 BOOL ret;
1776 if (message)
1778 len = WideCharToMultiByte(CP_ACP, 0, message, -1, NULL, 0, NULL, NULL);
1779 msg = HeapAlloc(GetProcessHeap(), 0, len);
1780 if (msg == NULL)
1782 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1783 return FALSE;
1785 WideCharToMultiByte(CP_ACP, 0, message, -1, msg, len, NULL, NULL);
1788 /* This is the normal way to proceed. The log files are ANSI files
1789 * and W is to be converted.
1791 ret = SetupLogErrorA(msg, severity);
1793 HeapFree(GetProcessHeap(), 0, msg);
1794 return ret;
1797 /***********************************************************************
1798 * CM_Get_Version (SETUPAPI.@)
1800 WORD WINAPI CM_Get_Version(void)
1802 TRACE("()\n");
1803 return 0x0400;