xref: /reactos/dll/win32/setupapi/misc.c (revision 3f570f33)
1 /*
2  * Setupapi miscellaneous functions
3  *
4  * Copyright 2005 Eric Kohl
5  * Copyright 2007 Hans Leidekker
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #include "setupapi_private.h"
23 
24 #include <winver.h>
25 #include <lzexpand.h>
26 
27 /* Unicode constants */
28 static const WCHAR BackSlash[] = {'\\',0};
29 static const WCHAR TranslationRegKey[] = {'\\','V','e','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n',0};
30 
31 /* Handles and critical sections for the SetupLog API */
32 static HANDLE setupact = INVALID_HANDLE_VALUE;
33 static HANDLE setuperr = INVALID_HANDLE_VALUE;
34 static CRITICAL_SECTION setupapi_cs;
35 static CRITICAL_SECTION_DEBUG critsect_debug =
36 {
37     0, 0, &setupapi_cs,
38     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
39     0, 0, { (DWORD_PTR)(__FILE__ ": setupapi_cs") }
40 };
41 static CRITICAL_SECTION setupapi_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
42 
43 DWORD
GetFunctionPointer(IN PWSTR InstallerName,OUT HMODULE * ModulePointer,OUT PVOID * FunctionPointer)44 GetFunctionPointer(
45     IN PWSTR InstallerName,
46     OUT HMODULE* ModulePointer,
47     OUT PVOID* FunctionPointer)
48 {
49     HMODULE hModule = NULL;
50     LPSTR FunctionNameA = NULL;
51     PWCHAR Comma;
52     DWORD rc;
53 
54     *ModulePointer = NULL;
55     *FunctionPointer = NULL;
56 
57     Comma = strchrW(InstallerName, ',');
58     if (!Comma)
59     {
60         rc = ERROR_INVALID_PARAMETER;
61         goto cleanup;
62     }
63 
64     /* Load library */
65     *Comma = '\0';
66     hModule = LoadLibraryW(InstallerName);
67     *Comma = ',';
68     if (!hModule)
69     {
70         rc = GetLastError();
71         goto cleanup;
72     }
73 
74     /* Skip comma spaces */
75     while (*Comma == ',' || isspaceW(*Comma))
76         Comma++;
77 
78     /* W->A conversion for function name */
79     FunctionNameA = pSetupUnicodeToMultiByte(Comma, CP_ACP);
80     if (!FunctionNameA)
81     {
82         rc = GetLastError();
83         goto cleanup;
84     }
85 
86     /* Search function */
87     *FunctionPointer = GetProcAddress(hModule, FunctionNameA);
88     if (!*FunctionPointer)
89     {
90         rc = GetLastError();
91         goto cleanup;
92     }
93 
94     *ModulePointer = hModule;
95     rc = ERROR_SUCCESS;
96 
97 cleanup:
98     if (rc != ERROR_SUCCESS && hModule)
99         FreeLibrary(hModule);
100     MyFree(FunctionNameA);
101     return rc;
102 }
103 
104 DWORD
FreeFunctionPointer(IN HMODULE ModulePointer,IN PVOID FunctionPointer)105 FreeFunctionPointer(
106     IN HMODULE ModulePointer,
107     IN PVOID FunctionPointer)
108 {
109     if (ModulePointer == NULL)
110         return ERROR_SUCCESS;
111     if (FreeLibrary(ModulePointer))
112        return ERROR_SUCCESS;
113     else
114        return GetLastError();
115 }
116 
117 /**************************************************************************
118  * MyFree [SETUPAPI.@]
119  *
120  * Frees an allocated memory block from the process heap.
121  *
122  * PARAMS
123  *     lpMem [I] pointer to memory block which will be freed
124  *
125  * RETURNS
126  *     None
127  */
MyFree(LPVOID lpMem)128 VOID WINAPI MyFree(LPVOID lpMem)
129 {
130     TRACE("%p\n", lpMem);
131     HeapFree(GetProcessHeap(), 0, lpMem);
132 }
133 
134 
135 /**************************************************************************
136  * MyMalloc [SETUPAPI.@]
137  *
138  * Allocates memory block from the process heap.
139  *
140  * PARAMS
141  *     dwSize [I] size of the allocated memory block
142  *
143  * RETURNS
144  *     Success: pointer to allocated memory block
145  *     Failure: NULL
146  */
MyMalloc(DWORD dwSize)147 LPVOID WINAPI MyMalloc(DWORD dwSize)
148 {
149     TRACE("%lu\n", dwSize);
150     return HeapAlloc(GetProcessHeap(), 0, dwSize);
151 }
152 
153 
154 /**************************************************************************
155  * MyRealloc [SETUPAPI.@]
156  *
157  * Changes the size of an allocated memory block or allocates a memory
158  * block from the process heap.
159  *
160  * PARAMS
161  *     lpSrc  [I] pointer to memory block which will be resized
162  *     dwSize [I] new size of the memory block
163  *
164  * RETURNS
165  *     Success: pointer to the resized memory block
166  *     Failure: NULL
167  *
168  * NOTES
169  *     If lpSrc is a NULL-pointer, then MyRealloc allocates a memory
170  *     block like MyMalloc.
171  */
MyRealloc(LPVOID lpSrc,DWORD dwSize)172 LPVOID WINAPI MyRealloc(LPVOID lpSrc, DWORD dwSize)
173 {
174     TRACE("%p %lu\n", lpSrc, dwSize);
175 
176     if (lpSrc == NULL)
177         return HeapAlloc(GetProcessHeap(), 0, dwSize);
178 
179     return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize);
180 }
181 
182 
183 /**************************************************************************
184  * pSetupDuplicateString [SETUPAPI.@]
185  *
186  * Duplicates a unicode string.
187  *
188  * PARAMS
189  *     lpSrc  [I] pointer to the unicode string that will be duplicated
190  *
191  * RETURNS
192  *     Success: pointer to the duplicated unicode string
193  *     Failure: NULL
194  *
195  * NOTES
196  *     Call MyFree() to release the duplicated string.
197  */
pSetupDuplicateString(LPCWSTR lpSrc)198 LPWSTR WINAPI pSetupDuplicateString(LPCWSTR lpSrc)
199 {
200     LPWSTR lpDst;
201 
202     TRACE("%s\n", debugstr_w(lpSrc));
203 
204     lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));
205     if (lpDst == NULL)
206         return NULL;
207 
208     strcpyW(lpDst, lpSrc);
209 
210     return lpDst;
211 }
212 
213 
214 /**************************************************************************
215  * QueryRegistryValue [SETUPAPI.@]
216  *
217  * Retrieves value data from the registry and allocates memory for the
218  * value data.
219  *
220  * PARAMS
221  *     hKey        [I] Handle of the key to query
222  *     lpValueName [I] Name of value under hkey to query
223  *     lpData      [O] Destination for the values contents,
224  *     lpType      [O] Destination for the value type
225  *     lpcbData    [O] Destination for the size of data
226  *
227  * RETURNS
228  *     Success: ERROR_SUCCESS
229  *     Failure: Otherwise
230  *
231  * NOTES
232  *     Use MyFree to release the lpData buffer.
233  */
QueryRegistryValue(HKEY hKey,LPCWSTR lpValueName,LPBYTE * lpData,LPDWORD lpType,LPDWORD lpcbData)234 LONG WINAPI QueryRegistryValue(HKEY hKey,
235                                LPCWSTR lpValueName,
236                                LPBYTE  *lpData,
237                                LPDWORD lpType,
238                                LPDWORD lpcbData)
239 {
240     LONG lError;
241 
242     TRACE("%p %s %p %p %p\n",
243           hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);
244 
245     /* Get required buffer size */
246     *lpcbData = 0;
247     lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);
248     if (lError != ERROR_SUCCESS)
249         return lError;
250 
251     /* Allocate buffer */
252     *lpData = MyMalloc(*lpcbData);
253     if (*lpData == NULL)
254         return ERROR_NOT_ENOUGH_MEMORY;
255 
256     /* Query registry value */
257     lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);
258     if (lError != ERROR_SUCCESS)
259         MyFree(*lpData);
260 
261     return lError;
262 }
263 
264 
265 /**************************************************************************
266  * pSetupMultiByteToUnicode [SETUPAPI.@]
267  *
268  * Converts a multi-byte string to a Unicode string.
269  *
270  * PARAMS
271  *     lpMultiByteStr  [I] Multi-byte string to be converted
272  *     uCodePage       [I] Code page
273  *
274  * RETURNS
275  *     Success: pointer to the converted Unicode string
276  *     Failure: NULL
277  *
278  * NOTE
279  *     Use MyFree to release the returned Unicode string.
280  */
pSetupMultiByteToUnicode(LPCSTR lpMultiByteStr,UINT uCodePage)281 LPWSTR WINAPI pSetupMultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)
282 {
283     LPWSTR lpUnicodeStr;
284     int nLength;
285 
286     TRACE("%s %d\n", debugstr_a(lpMultiByteStr), uCodePage);
287 
288     nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
289                                   -1, NULL, 0);
290     if (nLength == 0)
291         return NULL;
292 
293     lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));
294     if (lpUnicodeStr == NULL)
295     {
296         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
297         return NULL;
298     }
299 
300     if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
301                              nLength, lpUnicodeStr, nLength))
302     {
303         MyFree(lpUnicodeStr);
304         return NULL;
305     }
306 
307     return lpUnicodeStr;
308 }
309 
310 
311 /**************************************************************************
312  * pSetupUnicodeToMultiByte [SETUPAPI.@]
313  *
314  * Converts a Unicode string to a multi-byte string.
315  *
316  * PARAMS
317  *     lpUnicodeStr  [I] Unicode string to be converted
318  *     uCodePage     [I] Code page
319  *
320  * RETURNS
321  *     Success: pointer to the converted multi-byte string
322  *     Failure: NULL
323  *
324  * NOTE
325  *     Use MyFree to release the returned multi-byte string.
326  */
pSetupUnicodeToMultiByte(LPCWSTR lpUnicodeStr,UINT uCodePage)327 LPSTR WINAPI pSetupUnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)
328 {
329     LPSTR lpMultiByteStr;
330     int nLength;
331 
332     TRACE("%s %d\n", debugstr_w(lpUnicodeStr), uCodePage);
333 
334     nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
335                                   NULL, 0, NULL, NULL);
336     if (nLength == 0)
337         return NULL;
338 
339     lpMultiByteStr = MyMalloc(nLength);
340     if (lpMultiByteStr == NULL)
341         return NULL;
342 
343     if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
344                              lpMultiByteStr, nLength, NULL, NULL))
345     {
346         MyFree(lpMultiByteStr);
347         return NULL;
348     }
349 
350     return lpMultiByteStr;
351 }
352 
353 
354 /**************************************************************************
355  * DoesUserHavePrivilege [SETUPAPI.@]
356  *
357  * Check whether the current user has got a given privilege.
358  *
359  * PARAMS
360  *     lpPrivilegeName  [I] Name of the privilege to be checked
361  *
362  * RETURNS
363  *     Success: TRUE
364  *     Failure: FALSE
365  */
DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)366 BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)
367 {
368     HANDLE hToken;
369     DWORD dwSize;
370     PTOKEN_PRIVILEGES lpPrivileges;
371     LUID PrivilegeLuid;
372     DWORD i;
373     BOOL bResult = FALSE;
374 
375     TRACE("%s\n", debugstr_w(lpPrivilegeName));
376 
377     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
378         return FALSE;
379 
380     if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
381     {
382         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
383         {
384             CloseHandle(hToken);
385             return FALSE;
386         }
387     }
388 
389     lpPrivileges = MyMalloc(dwSize);
390     if (lpPrivileges == NULL)
391     {
392         CloseHandle(hToken);
393         return FALSE;
394     }
395 
396     if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))
397     {
398         MyFree(lpPrivileges);
399         CloseHandle(hToken);
400         return FALSE;
401     }
402 
403     CloseHandle(hToken);
404 
405     if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))
406     {
407         MyFree(lpPrivileges);
408         return FALSE;
409     }
410 
411     for (i = 0; i < lpPrivileges->PrivilegeCount; i++)
412     {
413         if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&
414             lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)
415         {
416             bResult = TRUE;
417         }
418     }
419 
420     MyFree(lpPrivileges);
421 
422     return bResult;
423 }
424 
425 
426 /**************************************************************************
427  * pSetupEnablePrivilege [SETUPAPI.@]
428  *
429  * Enables or disables one of the current users privileges.
430  *
431  * PARAMS
432  *     lpPrivilegeName  [I] Name of the privilege to be changed
433  *     bEnable          [I] TRUE: Enables the privilege
434  *                          FALSE: Disables the privilege
435  *
436  * RETURNS
437  *     Success: TRUE
438  *     Failure: FALSE
439  */
pSetupEnablePrivilege(LPCWSTR lpPrivilegeName,BOOL bEnable)440 BOOL WINAPI pSetupEnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)
441 {
442     TOKEN_PRIVILEGES Privileges;
443     HANDLE hToken;
444     BOOL bResult;
445 
446     TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");
447 
448     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
449         return FALSE;
450 
451     Privileges.PrivilegeCount = 1;
452     Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
453 
454     if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,
455                                &Privileges.Privileges[0].Luid))
456     {
457         CloseHandle(hToken);
458         return FALSE;
459     }
460 
461     bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);
462 
463     CloseHandle(hToken);
464 
465     return bResult;
466 }
467 
468 
469 /**************************************************************************
470  * DelayedMove [SETUPAPI.@]
471  *
472  * Moves a file upon the next reboot.
473  *
474  * PARAMS
475  *     lpExistingFileName  [I] Current file name
476  *     lpNewFileName       [I] New file name
477  *
478  * RETURNS
479  *     Success: TRUE
480  *     Failure: FALSE
481  */
DelayedMove(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName)482 BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
483 {
484     return MoveFileExW(lpExistingFileName, lpNewFileName,
485                        MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
486 }
487 
488 
489 /**************************************************************************
490  * FileExists [SETUPAPI.@]
491  *
492  * Checks whether a file exists.
493  *
494  * PARAMS
495  *     lpFileName     [I] Name of the file to check
496  *     lpNewFileName  [O] Optional information about the existing file
497  *
498  * RETURNS
499  *     Success: TRUE
500  *     Failure: FALSE
501  */
FileExists(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFileFindData)502 BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)
503 {
504     WIN32_FIND_DATAW FindData;
505     HANDLE hFind;
506     UINT uErrorMode;
507     DWORD dwError;
508 
509     uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
510 
511     hFind = FindFirstFileW(lpFileName, &FindData);
512     if (hFind == INVALID_HANDLE_VALUE)
513     {
514         dwError = GetLastError();
515         SetErrorMode(uErrorMode);
516         SetLastError(dwError);
517         return FALSE;
518     }
519 
520     FindClose(hFind);
521 
522     if (lpFileFindData)
523         memcpy(lpFileFindData, &FindData, sizeof(WIN32_FIND_DATAW));
524 
525     SetErrorMode(uErrorMode);
526 
527     return TRUE;
528 }
529 
530 
531 /**************************************************************************
532  * CaptureStringArg [SETUPAPI.@]
533  *
534  * Captures a UNICODE string.
535  *
536  * PARAMS
537  *     lpSrc  [I] UNICODE string to be captured
538  *     lpDst  [O] Pointer to the captured UNICODE string
539  *
540  * RETURNS
541  *     Success: ERROR_SUCCESS
542  *     Failure: ERROR_INVALID_PARAMETER
543  *
544  * NOTE
545  *     Call MyFree to release the captured UNICODE string.
546  */
CaptureStringArg(LPCWSTR pSrc,LPWSTR * pDst)547 DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)
548 {
549     if (pDst == NULL)
550         return ERROR_INVALID_PARAMETER;
551 
552     *pDst = pSetupDuplicateString(pSrc);
553 
554     return ERROR_SUCCESS;
555 }
556 
557 
558 /**************************************************************************
559  * pSetupCaptureAndConvertAnsiArg [SETUPAPI.@]
560  *
561  * Captures an ANSI string and converts it to a UNICODE string.
562  *
563  * PARAMS
564  *     lpSrc  [I] ANSI string to be captured
565  *     lpDst  [O] Pointer to the captured UNICODE string
566  *
567  * RETURNS
568  *     Success: ERROR_SUCCESS
569  *     Failure: ERROR_INVALID_PARAMETER
570  *
571  * NOTE
572  *     Call MyFree to release the captured UNICODE string.
573  */
pSetupCaptureAndConvertAnsiArg(LPCSTR pSrc,LPWSTR * pDst)574 DWORD WINAPI pSetupCaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)
575 {
576     if (pDst == NULL)
577         return ERROR_INVALID_PARAMETER;
578 
579     *pDst = pSetupMultiByteToUnicode(pSrc, CP_ACP);
580 
581     return ERROR_SUCCESS;
582 }
583 
584 
585 /**************************************************************************
586  * pSetupOpenAndMapFileForRead [SETUPAPI.@]
587  *
588  * Open and map a file to a buffer.
589  *
590  * PARAMS
591  *     lpFileName [I] Name of the file to be opened
592  *     lpSize     [O] Pointer to the file size
593  *     lpFile     [0] Pointer to the file handle
594  *     lpMapping  [0] Pointer to the mapping handle
595  *     lpBuffer   [0] Pointer to the file buffer
596  *
597  * RETURNS
598  *     Success: ERROR_SUCCESS
599  *     Failure: Other
600  *
601  * NOTE
602  *     Call UnmapAndCloseFile to release the file.
603  */
pSetupOpenAndMapFileForRead(LPCWSTR lpFileName,LPDWORD lpSize,LPHANDLE lpFile,LPHANDLE lpMapping,LPVOID * lpBuffer)604 DWORD WINAPI pSetupOpenAndMapFileForRead(LPCWSTR lpFileName,
605                                          LPDWORD lpSize,
606                                          LPHANDLE lpFile,
607                                          LPHANDLE lpMapping,
608                                          LPVOID *lpBuffer)
609 {
610     DWORD dwError;
611 
612     TRACE("%s %p %p %p %p\n",
613           debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);
614 
615     *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
616                           OPEN_EXISTING, 0, NULL);
617     if (*lpFile == INVALID_HANDLE_VALUE)
618         return GetLastError();
619 
620     *lpSize = GetFileSize(*lpFile, NULL);
621     if (*lpSize == INVALID_FILE_SIZE)
622     {
623         dwError = GetLastError();
624         CloseHandle(*lpFile);
625         return dwError;
626     }
627 
628     *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,
629                                     *lpSize, NULL);
630     if (*lpMapping == NULL)
631     {
632         dwError = GetLastError();
633         CloseHandle(*lpFile);
634         return dwError;
635     }
636 
637     *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);
638     if (*lpBuffer == NULL)
639     {
640         dwError = GetLastError();
641         CloseHandle(*lpMapping);
642         CloseHandle(*lpFile);
643         return dwError;
644     }
645 
646     return ERROR_SUCCESS;
647 }
648 
649 
650 /**************************************************************************
651  * pSetupUnmapAndCloseFile [SETUPAPI.@]
652  *
653  * Unmap and close a mapped file.
654  *
655  * PARAMS
656  *     hFile    [I] Handle to the file
657  *     hMapping [I] Handle to the file mapping
658  *     lpBuffer [I] Pointer to the file buffer
659  *
660  * RETURNS
661  *     Success: TRUE
662  *     Failure: FALSE
663  */
pSetupUnmapAndCloseFile(HANDLE hFile,HANDLE hMapping,LPVOID lpBuffer)664 BOOL WINAPI pSetupUnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)
665 {
666     TRACE("%p %p %p\n",
667           hFile, hMapping, lpBuffer);
668 
669     if (!UnmapViewOfFile(lpBuffer))
670         return FALSE;
671 
672     if (!CloseHandle(hMapping))
673         return FALSE;
674 
675     if (!CloseHandle(hFile))
676         return FALSE;
677 
678     return TRUE;
679 }
680 
681 
682 /**************************************************************************
683  * StampFileSecurity [SETUPAPI.@]
684  *
685  * Assign a new security descriptor to the given file.
686  *
687  * PARAMS
688  *     lpFileName          [I] Name of the file
689  *     pSecurityDescriptor [I] New security descriptor
690  *
691  * RETURNS
692  *     Success: ERROR_SUCCESS
693  *     Failure: other
694  */
StampFileSecurity(LPCWSTR lpFileName,PSECURITY_DESCRIPTOR pSecurityDescriptor)695 DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)
696 {
697     TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
698 
699     if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
700                           GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
701                           pSecurityDescriptor))
702         return GetLastError();
703 
704     return ERROR_SUCCESS;
705 }
706 
707 
708 /**************************************************************************
709  * TakeOwnershipOfFile [SETUPAPI.@]
710  *
711  * Takes the ownership of the given file.
712  *
713  * PARAMS
714  *     lpFileName [I] Name of the file
715  *
716  * RETURNS
717  *     Success: ERROR_SUCCESS
718  *     Failure: other
719  */
TakeOwnershipOfFile(LPCWSTR lpFileName)720 DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)
721 {
722     SECURITY_DESCRIPTOR SecDesc;
723     HANDLE hToken = NULL;
724     PTOKEN_OWNER pOwner = NULL;
725     DWORD dwError;
726     DWORD dwSize;
727 
728     TRACE("%s\n", debugstr_w(lpFileName));
729 
730     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
731         return GetLastError();
732 
733     if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))
734     {
735         goto fail;
736     }
737 
738     pOwner = (PTOKEN_OWNER)MyMalloc(dwSize);
739     if (pOwner == NULL)
740     {
741         CloseHandle(hToken);
742         return ERROR_NOT_ENOUGH_MEMORY;
743     }
744 
745     if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))
746     {
747         goto fail;
748     }
749 
750     if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
751     {
752         goto fail;
753     }
754 
755     if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))
756     {
757         goto fail;
758     }
759 
760     if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))
761     {
762         goto fail;
763     }
764 
765     MyFree(pOwner);
766     CloseHandle(hToken);
767 
768     return ERROR_SUCCESS;
769 
770 fail:;
771     dwError = GetLastError();
772 
773     MyFree(pOwner);
774 
775     if (hToken != NULL)
776         CloseHandle(hToken);
777 
778     return dwError;
779 }
780 
781 
782 /**************************************************************************
783  * RetreiveFileSecurity [SETUPAPI.@]
784  *
785  * Retrieve the security descriptor that is associated with the given file.
786  *
787  * PARAMS
788  *     lpFileName [I] Name of the file
789  *
790  * RETURNS
791  *     Success: ERROR_SUCCESS
792  *     Failure: other
793  */
RetreiveFileSecurity(LPCWSTR lpFileName,PSECURITY_DESCRIPTOR * pSecurityDescriptor)794 DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,
795                                   PSECURITY_DESCRIPTOR *pSecurityDescriptor)
796 {
797     PSECURITY_DESCRIPTOR SecDesc;
798     DWORD dwSize = 0x100;
799     DWORD dwError;
800 
801     TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
802 
803     SecDesc = MyMalloc(dwSize);
804     if (SecDesc == NULL)
805         return ERROR_NOT_ENOUGH_MEMORY;
806 
807     if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
808                          GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
809                          SecDesc, dwSize, &dwSize))
810     {
811       *pSecurityDescriptor = SecDesc;
812       return ERROR_SUCCESS;
813     }
814 
815     dwError = GetLastError();
816     if (dwError != ERROR_INSUFFICIENT_BUFFER)
817     {
818         MyFree(SecDesc);
819         return dwError;
820     }
821 
822     SecDesc = MyRealloc(SecDesc, dwSize);
823     if (SecDesc == NULL)
824         return ERROR_NOT_ENOUGH_MEMORY;
825 
826     if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
827                          GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
828                          SecDesc, dwSize, &dwSize))
829     {
830       *pSecurityDescriptor = SecDesc;
831       return ERROR_SUCCESS;
832     }
833 
834     dwError = GetLastError();
835     MyFree(SecDesc);
836 
837     return dwError;
838 }
839 
840 
841 /*
842  * See: https://msdn.microsoft.com/en-us/library/bb432397(v=vs.85).aspx
843  * for more information.
844  */
845 DWORD GlobalSetupFlags = 0;
846 
847 /***********************************************************************
848  *		pSetupGetGlobalFlags  (SETUPAPI.@)
849  */
pSetupGetGlobalFlags(void)850 DWORD WINAPI pSetupGetGlobalFlags(void)
851 {
852     return GlobalSetupFlags;
853 }
854 
855 /***********************************************************************
856  *		pSetupModifyGlobalFlags  (SETUPAPI.@)
857  */
pSetupModifyGlobalFlags(DWORD mask,DWORD flags)858 void WINAPI pSetupModifyGlobalFlags( DWORD mask, DWORD flags )
859 {
860     FIXME( "stub\n" );
861     GlobalSetupFlags = (GlobalSetupFlags & ~mask) | (flags & mask);
862 }
863 
864 /***********************************************************************
865  *		pSetupSetGlobalFlags  (SETUPAPI.@)
866  */
pSetupSetGlobalFlags(DWORD flags)867 void WINAPI pSetupSetGlobalFlags( DWORD flags )
868 {
869     pSetupModifyGlobalFlags(0xFFFFFFFF, flags);
870 }
871 
872 /***********************************************************************
873  *		SetupGetNonInteractiveMode  (SETUPAPI.@)
874  */
SetupGetNonInteractiveMode(VOID)875 BOOL WINAPI SetupGetNonInteractiveMode(VOID)
876 {
877     return (GlobalSetupFlags & PSPGF_NONINTERACTIVE);
878 }
879 
880 /***********************************************************************
881  *		SetupSetNonInteractiveMode  (SETUPAPI.@)
882  */
SetupSetNonInteractiveMode(BOOL NonInteractiveFlag)883 BOOL WINAPI SetupSetNonInteractiveMode(BOOL NonInteractiveFlag)
884 {
885     BOOL OldValue;
886 
887     OldValue = (GlobalSetupFlags & PSPGF_NONINTERACTIVE);
888     pSetupModifyGlobalFlags(PSPGF_NONINTERACTIVE,
889                             NonInteractiveFlag ? PSPGF_NONINTERACTIVE : 0);
890 
891     return OldValue;
892 }
893 
894 /***********************************************************************
895  *              AssertFail  (SETUPAPI.@)
896  *
897  * Shows an assert fail error messagebox
898  *
899  * PARAMS
900  *   lpFile [I]         file where assert failed
901  *   uLine [I]          line number in file
902  *   lpMessage [I]      assert message
903  *
904  */
AssertFail(LPSTR lpFile,UINT uLine,LPSTR lpMessage)905 VOID WINAPI AssertFail(LPSTR lpFile, UINT uLine, LPSTR lpMessage)
906 {
907     CHAR szModule[MAX_PATH];
908     CHAR szBuffer[2048];
909     LPSTR lpName;
910 //    LPSTR lpBuffer;
911 
912     TRACE("%s %u %s\n", lpFile, uLine, lpMessage);
913 
914     GetModuleFileNameA(hInstance, szModule, MAX_PATH);
915     lpName = strrchr(szModule, '\\');
916     if (lpName != NULL)
917         lpName++;
918     else
919         lpName = szModule;
920 
921     wsprintfA(szBuffer,
922               "Assertion failure at line %u in file %s: %s\n\nCall DebugBreak()?",
923               uLine, lpFile, lpMessage);
924 
925     if (MessageBoxA(NULL, szBuffer, lpName, MB_SETFOREGROUND |
926                     MB_TASKMODAL | MB_ICONERROR | MB_YESNO) == IDYES)
927         DebugBreak();
928 }
929 
930 
931 /**************************************************************************
932  * GetSetFileTimestamp [SETUPAPI.@]
933  *
934  * Gets or sets a files timestamp.
935  *
936  * PARAMS
937  *     lpFileName       [I]   File name
938  *     lpCreationTime   [I/O] Creation time
939  *     lpLastAccessTime [I/O] Last access time
940  *     lpLastWriteTime  [I/O] Last write time
941  *     bSetFileTime     [I]   TRUE: Set file times
942  *                            FALSE: Get file times
943  *
944  * RETURNS
945  *     Success: ERROR_SUCCESS
946  *     Failure: other
947  */
GetSetFileTimestamp(LPCWSTR lpFileName,LPFILETIME lpCreationTime,LPFILETIME lpLastAccessTime,LPFILETIME lpLastWriteTime,BOOLEAN bSetFileTime)948 DWORD WINAPI GetSetFileTimestamp(LPCWSTR lpFileName,
949                                  LPFILETIME lpCreationTime,
950                                  LPFILETIME lpLastAccessTime,
951                                  LPFILETIME lpLastWriteTime,
952                                  BOOLEAN bSetFileTime)
953 {
954     HANDLE hFile;
955     BOOLEAN bRet;
956     DWORD dwError = ERROR_SUCCESS;
957 
958     TRACE("%s %p %p %p %x\n", debugstr_w(lpFileName), lpCreationTime,
959           lpLastAccessTime, lpLastWriteTime, bSetFileTime);
960 
961     hFile = CreateFileW(lpFileName,
962                         bSetFileTime ? GENERIC_WRITE : GENERIC_READ,
963                         FILE_SHARE_READ | FILE_SHARE_WRITE,
964                         NULL,
965                         OPEN_EXISTING,
966                         0,
967                         NULL);
968 
969     if (hFile == INVALID_HANDLE_VALUE)
970         return GetLastError();
971 
972     if (bSetFileTime)
973         bRet = SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
974     else
975         bRet = GetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
976 
977     if (bRet == FALSE)
978         dwError = GetLastError();
979 
980      CloseHandle(hFile);
981 
982      return dwError;
983 }
984 
985 
986 /**************************************************************************
987  * pSetupGetFileTitle [SETUPAPI.@]
988  *
989  * Returns a pointer to the last part of a fully qualified file name.
990  *
991  * PARAMS
992  *     lpFileName [I] File name
993  *
994  * RETURNS
995  *     Pointer to a files name.
996  */
997 LPWSTR WINAPI
pSetupGetFileTitle(LPCWSTR lpFileName)998 pSetupGetFileTitle(LPCWSTR lpFileName)
999 {
1000     LPWSTR ptr;
1001     LPWSTR ret;
1002     WCHAR c;
1003 
1004     TRACE("%s\n", debugstr_w(lpFileName));
1005 
1006     ptr = (LPWSTR)lpFileName;
1007     ret = ptr;
1008     while (TRUE)
1009     {
1010         c = *ptr;
1011 
1012         if (c == 0)
1013             break;
1014 
1015         ptr++;
1016         if (c == (WCHAR)'\\' || c == (WCHAR)'/' || c == (WCHAR)':')
1017             ret = ptr;
1018     }
1019 
1020     return ret;
1021 }
1022 
1023 
1024 /**************************************************************************
1025  * pSetupConcatenatePaths [SETUPAPI.@]
1026  *
1027  * Concatenates two paths.
1028  *
1029  * PARAMS
1030  *     lpPath         [I/O] Path to append path to
1031  *     lpAppend       [I]   Path to append
1032  *     dwBufferSize   [I]   Size of the path buffer
1033  *     lpRequiredSize [O]   Required size for the concatenated path. Optional
1034  *
1035  * RETURNS
1036  *     Success: TRUE
1037  *     Failure: FALSE
1038  */
1039 BOOL WINAPI
pSetupConcatenatePaths(LPWSTR lpPath,LPCWSTR lpAppend,DWORD dwBufferSize,LPDWORD lpRequiredSize)1040 pSetupConcatenatePaths(LPWSTR lpPath,
1041                        LPCWSTR lpAppend,
1042                        DWORD dwBufferSize,
1043                        LPDWORD lpRequiredSize)
1044 {
1045     DWORD dwPathSize;
1046     DWORD dwAppendSize;
1047     DWORD dwTotalSize;
1048     BOOL bBackslash = FALSE;
1049 
1050     TRACE("%s %s %lu %p\n", debugstr_w(lpPath), debugstr_w(lpAppend),
1051           dwBufferSize, lpRequiredSize);
1052 
1053     dwPathSize = lstrlenW(lpPath);
1054 
1055     /* Ignore trailing backslash */
1056     if (lpPath[dwPathSize - 1] == (WCHAR)'\\')
1057         dwPathSize--;
1058 
1059     dwAppendSize = lstrlenW(lpAppend);
1060 
1061     /* Does the source string have a leading backslash? */
1062     if (lpAppend[0] == (WCHAR)'\\')
1063     {
1064         bBackslash = TRUE;
1065         dwAppendSize--;
1066     }
1067 
1068     dwTotalSize = dwPathSize + dwAppendSize + 2;
1069     if (lpRequiredSize != NULL)
1070         *lpRequiredSize = dwTotalSize;
1071 
1072     /* Append a backslash to the destination string */
1073     if (bBackslash == FALSE)
1074     {
1075         if (dwPathSize < dwBufferSize)
1076         {
1077             lpPath[dwPathSize - 1] = (WCHAR)'\\';
1078             dwPathSize++;
1079         }
1080     }
1081 
1082     if (dwPathSize + dwAppendSize < dwBufferSize)
1083     {
1084         lstrcpynW(&lpPath[dwPathSize],
1085                   lpAppend,
1086                   dwAppendSize);
1087     }
1088 
1089     if (dwBufferSize >= dwTotalSize)
1090         lpPath[dwTotalSize - 1] = 0;
1091 
1092     return (dwBufferSize >= dwTotalSize);
1093 }
1094 
1095 
1096 /**************************************************************************
1097  * pSetupCenterWindowRelativeToParent [SETUPAPI.@]
1098  *
1099  * Centers a window relative to its parent.
1100  *
1101  * PARAMS
1102  *     hwnd [I] Window to center.
1103  *
1104  * RETURNS
1105  *     None
1106  */
1107 VOID WINAPI
pSetupCenterWindowRelativeToParent(HWND hwnd)1108 pSetupCenterWindowRelativeToParent(HWND hwnd)
1109 {
1110     HWND hwndOwner;
1111     POINT ptOrigin;
1112     RECT rcWindow;
1113     RECT rcOwner;
1114     INT nWindowWidth, nWindowHeight;
1115     INT nOwnerWidth, nOwnerHeight;
1116     INT posX, posY;
1117 
1118     hwndOwner = GetWindow(hwnd, GW_OWNER);
1119     if (hwndOwner == NULL)
1120         return;
1121 
1122     ptOrigin.x = 0;
1123     ptOrigin.y = 0;
1124     ClientToScreen(hwndOwner, &ptOrigin);
1125 
1126     GetWindowRect(hwnd, &rcWindow);
1127     GetClientRect(hwndOwner, &rcOwner);
1128 
1129     nWindowWidth = rcWindow.right - rcWindow.left;
1130     nWindowHeight = rcWindow.bottom - rcWindow.top;
1131 
1132     nOwnerWidth = rcOwner.right - rcOwner.left;
1133     nOwnerHeight = rcOwner.bottom - rcOwner.top;
1134 
1135     posX = ((nOwnerWidth - nWindowWidth) / 2) + ptOrigin.x;
1136     posY = ((nOwnerHeight - nWindowHeight) / 2) + ptOrigin.y;
1137 
1138     MoveWindow(hwnd, posX, posY, nWindowWidth, nWindowHeight, 0);
1139 }
1140 
1141 
1142 /**************************************************************************
1143  * pSetupGetVersionInfoFromImage [SETUPAPI.@]
1144  *
1145  * Retrieves version information for a given file.
1146  *
1147  * PARAMS
1148  *     lpFileName       [I] File name
1149  *     lpFileVersion    [O] Pointer to the full file version
1150  *     lpVersionVarSize [O] Pointer to the size of the variable version
1151  *                          information
1152  *
1153  * RETURNS
1154  *     Success: TRUE
1155  *     Failure: FALSE
1156  */
1157 BOOL WINAPI
pSetupGetVersionInfoFromImage(LPWSTR lpFileName,PULARGE_INTEGER lpFileVersion,LPWORD lpVersionVarSize)1158 pSetupGetVersionInfoFromImage(LPWSTR lpFileName,
1159                               PULARGE_INTEGER lpFileVersion,
1160                               LPWORD lpVersionVarSize)
1161 {
1162     DWORD dwHandle;
1163     DWORD dwSize;
1164     LPVOID lpInfo;
1165     UINT uSize;
1166     VS_FIXEDFILEINFO *lpFixedInfo;
1167     LPWORD lpVarSize;
1168 
1169     dwSize = GetFileVersionInfoSizeW(lpFileName, &dwHandle);
1170     if (dwSize == 0)
1171         return FALSE;
1172 
1173     lpInfo = MyMalloc(dwSize);
1174     if (lpInfo == NULL)
1175         return FALSE;
1176 
1177     if (!GetFileVersionInfoW(lpFileName, 0, dwSize, lpInfo))
1178     {
1179         MyFree(lpInfo);
1180         return FALSE;
1181     }
1182 
1183     if (!VerQueryValueW(lpInfo, BackSlash,
1184                         (LPVOID*)&lpFixedInfo, &uSize))
1185     {
1186         MyFree(lpInfo);
1187         return FALSE;
1188     }
1189 
1190     lpFileVersion->LowPart = lpFixedInfo->dwFileVersionLS;
1191     lpFileVersion->HighPart = lpFixedInfo->dwFileVersionMS;
1192 
1193     *lpVersionVarSize = 0;
1194     if (!VerQueryValueW(lpInfo, TranslationRegKey,
1195                         (LPVOID*)&lpVarSize, &uSize))
1196     {
1197         MyFree(lpInfo);
1198         return TRUE;
1199     }
1200 
1201     if (uSize >= 4)
1202     {
1203         *lpVersionVarSize = *lpVarSize;
1204     }
1205 
1206     MyFree(lpInfo);
1207 
1208     return TRUE;
1209 }
1210 
1211 /***********************************************************************
1212  *      SetupUninstallOEMInfW  (SETUPAPI.@)
1213  */
SetupUninstallOEMInfW(PCWSTR inf_file,DWORD flags,PVOID reserved)1214 BOOL WINAPI SetupUninstallOEMInfW( PCWSTR inf_file, DWORD flags, PVOID reserved )
1215 {
1216     static const WCHAR infW[] = {'\\','i','n','f','\\',0};
1217     WCHAR target[MAX_PATH];
1218 
1219     TRACE("%s, 0x%08x, %p\n", debugstr_w(inf_file), flags, reserved);
1220 
1221     if (!inf_file)
1222     {
1223         SetLastError(ERROR_INVALID_PARAMETER);
1224         return FALSE;
1225     }
1226 
1227     if (!GetWindowsDirectoryW( target, sizeof(target)/sizeof(WCHAR) )) return FALSE;
1228 
1229     strcatW( target, infW );
1230     strcatW( target, inf_file );
1231 
1232     if (flags & SUOI_FORCEDELETE)
1233         return DeleteFileW(target);
1234 
1235     FIXME("not deleting %s\n", debugstr_w(target));
1236 
1237     return TRUE;
1238 }
1239 
1240 /***********************************************************************
1241  *      SetupUninstallOEMInfA  (SETUPAPI.@)
1242  */
SetupUninstallOEMInfA(PCSTR inf_file,DWORD flags,PVOID reserved)1243 BOOL WINAPI SetupUninstallOEMInfA( PCSTR inf_file, DWORD flags, PVOID reserved )
1244 {
1245     BOOL ret;
1246     WCHAR *inf_fileW = NULL;
1247 
1248     TRACE("%s, 0x%08x, %p\n", debugstr_a(inf_file), flags, reserved);
1249 
1250     if (inf_file && !(inf_fileW = strdupAtoW( inf_file ))) return FALSE;
1251     ret = SetupUninstallOEMInfW( inf_fileW, flags, reserved );
1252     HeapFree( GetProcessHeap(), 0, inf_fileW );
1253     return ret;
1254 }
1255 
1256 /***********************************************************************
1257  *      InstallCatalog  (SETUPAPI.@)
1258  */
InstallCatalog(LPCSTR catalog,LPCSTR basename,LPSTR fullname)1259 DWORD WINAPI InstallCatalog( LPCSTR catalog, LPCSTR basename, LPSTR fullname )
1260 {
1261     FIXME("%s, %s, %p\n", debugstr_a(catalog), debugstr_a(basename), fullname);
1262     return 0;
1263 }
1264 
1265 /***********************************************************************
1266  *      pSetupInstallCatalog  (SETUPAPI.@)
1267  */
pSetupInstallCatalog(LPCWSTR catalog,LPCWSTR basename,LPWSTR fullname)1268 DWORD WINAPI pSetupInstallCatalog( LPCWSTR catalog, LPCWSTR basename, LPWSTR fullname )
1269 {
1270     HCATADMIN admin;
1271     HCATINFO cat;
1272 
1273     TRACE ("%s, %s, %p\n", debugstr_w(catalog), debugstr_w(basename), fullname);
1274 
1275     if (!CryptCATAdminAcquireContext(&admin,NULL,0))
1276         return GetLastError();
1277 
1278     if (!(cat = CryptCATAdminAddCatalog( admin, (PWSTR)catalog, (PWSTR)basename, 0 )))
1279     {
1280         DWORD rc = GetLastError();
1281         CryptCATAdminReleaseContext(admin, 0);
1282         return rc;
1283     }
1284     CryptCATAdminReleaseCatalogContext(admin, cat, 0);
1285     CryptCATAdminReleaseContext(admin,0);
1286 
1287     if (fullname)
1288         FIXME("not returning full installed catalog path\n");
1289 
1290     return NO_ERROR;
1291 }
1292 
detect_compression_type(LPCWSTR file)1293 static UINT detect_compression_type( LPCWSTR file )
1294 {
1295     DWORD size;
1296     HANDLE handle;
1297     UINT type = FILE_COMPRESSION_NONE;
1298     static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1299     static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1300     static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1301     BYTE buffer[8];
1302 
1303     handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1304     if (handle == INVALID_HANDLE_VALUE)
1305     {
1306         ERR("cannot open file %s\n", debugstr_w(file));
1307         return FILE_COMPRESSION_NONE;
1308     }
1309     if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1310     {
1311         CloseHandle( handle );
1312         return FILE_COMPRESSION_NONE;
1313     }
1314     if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1315     else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1316     else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1317 
1318     CloseHandle( handle );
1319     return type;
1320 }
1321 
get_file_size(LPCWSTR file,DWORD * size)1322 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1323 {
1324     HANDLE handle;
1325 
1326     handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1327     if (handle == INVALID_HANDLE_VALUE)
1328     {
1329         ERR("cannot open file %s\n", debugstr_w(file));
1330         return FALSE;
1331     }
1332     *size = GetFileSize( handle, NULL );
1333     CloseHandle( handle );
1334     return TRUE;
1335 }
1336 
get_file_sizes_none(LPCWSTR source,DWORD * source_size,DWORD * target_size)1337 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1338 {
1339     DWORD size;
1340 
1341     if (!get_file_size( source, &size )) return FALSE;
1342     if (source_size) *source_size = size;
1343     if (target_size) *target_size = size;
1344     return TRUE;
1345 }
1346 
get_file_sizes_lz(LPCWSTR source,DWORD * source_size,DWORD * target_size)1347 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1348 {
1349     DWORD size;
1350     BOOL ret = TRUE;
1351 
1352     if (source_size)
1353     {
1354         if (!get_file_size( source, &size )) ret = FALSE;
1355         else *source_size = size;
1356     }
1357     if (target_size)
1358     {
1359         INT file;
1360         OFSTRUCT of;
1361 
1362         if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1363         {
1364             ERR("cannot open source file for reading\n");
1365             return FALSE;
1366         }
1367         *target_size = LZSeek( file, 0, 2 );
1368         LZClose( file );
1369     }
1370     return ret;
1371 }
1372 
file_compression_info_callback(PVOID context,UINT notification,UINT_PTR param1,UINT_PTR param2)1373 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1374 {
1375     DWORD *size = context;
1376     FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1377 
1378     switch (notification)
1379     {
1380     case SPFILENOTIFY_FILEINCABINET:
1381     {
1382         *size = info->FileSize;
1383         return FILEOP_SKIP;
1384     }
1385     default: return NO_ERROR;
1386     }
1387 }
1388 
get_file_sizes_cab(LPCWSTR source,DWORD * source_size,DWORD * target_size)1389 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1390 {
1391     DWORD size;
1392     BOOL ret = TRUE;
1393 
1394     if (source_size)
1395     {
1396         if (!get_file_size( source, &size )) ret = FALSE;
1397         else *source_size = size;
1398     }
1399     if (target_size)
1400     {
1401         ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1402     }
1403     return ret;
1404 }
1405 
1406 /***********************************************************************
1407  *      SetupGetFileCompressionInfoExA  (SETUPAPI.@)
1408  *
1409  * See SetupGetFileCompressionInfoExW.
1410  */
SetupGetFileCompressionInfoExA(PCSTR source,PSTR name,DWORD len,PDWORD required,PDWORD source_size,PDWORD target_size,PUINT type)1411 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1412                                             PDWORD source_size, PDWORD target_size, PUINT type )
1413 {
1414     BOOL ret;
1415     WCHAR *nameW = NULL, *sourceW = NULL;
1416     DWORD nb_chars = 0;
1417     LPSTR nameA;
1418 
1419     TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1420           source_size, target_size, type);
1421 
1422     if (!source || !(sourceW = pSetupMultiByteToUnicode( source, CP_ACP ))) return FALSE;
1423 
1424     if (name)
1425     {
1426         ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1427         if (!(nameW = HeapAlloc( GetProcessHeap(), 0, nb_chars * sizeof(WCHAR) )))
1428         {
1429             MyFree( sourceW );
1430             return FALSE;
1431         }
1432     }
1433     ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1434     if (ret)
1435     {
1436         if ((nameA = pSetupUnicodeToMultiByte( nameW, CP_ACP )))
1437         {
1438             if (name && len >= nb_chars) lstrcpyA( name, nameA );
1439             else
1440             {
1441                 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1442                 ret = FALSE;
1443             }
1444             MyFree( nameA );
1445         }
1446     }
1447     if (required) *required = nb_chars;
1448     HeapFree( GetProcessHeap(), 0, nameW );
1449     MyFree( sourceW );
1450 
1451     return ret;
1452 }
1453 
1454 /***********************************************************************
1455  *      SetupGetFileCompressionInfoExW  (SETUPAPI.@)
1456  *
1457  * Get compression type and compressed/uncompressed sizes of a given file.
1458  *
1459  * PARAMS
1460  *  source      [I] File to examine.
1461  *  name        [O] Actual filename used.
1462  *  len         [I] Length in characters of 'name' buffer.
1463  *  required    [O] Number of characters written to 'name'.
1464  *  source_size [O] Size of compressed file.
1465  *  target_size [O] Size of uncompressed file.
1466  *  type        [O] Compression type.
1467  *
1468  * RETURNS
1469  *  Success: TRUE
1470  *  Failure: FALSE
1471  */
SetupGetFileCompressionInfoExW(PCWSTR source,PWSTR name,DWORD len,PDWORD required,PDWORD source_size,PDWORD target_size,PUINT type)1472 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1473                                             PDWORD source_size, PDWORD target_size, PUINT type )
1474 {
1475     UINT comp;
1476     BOOL ret = FALSE;
1477     DWORD source_len;
1478 
1479     TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1480           source_size, target_size, type);
1481 
1482     if (!source) return FALSE;
1483 
1484     source_len = lstrlenW( source ) + 1;
1485     if (required) *required = source_len;
1486     if (name && len >= source_len)
1487     {
1488         lstrcpyW( name, source );
1489         ret = TRUE;
1490     }
1491     else return FALSE;
1492 
1493     comp = detect_compression_type( source );
1494     if (type) *type = comp;
1495 
1496     switch (comp)
1497     {
1498     case FILE_COMPRESSION_MSZIP:
1499     case FILE_COMPRESSION_NTCAB:  ret = get_file_sizes_cab( source, source_size, target_size ); break;
1500     case FILE_COMPRESSION_NONE:   ret = get_file_sizes_none( source, source_size, target_size ); break;
1501     case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1502     default: break;
1503     }
1504     return ret;
1505 }
1506 
1507 /***********************************************************************
1508  *      SetupGetFileCompressionInfoA  (SETUPAPI.@)
1509  *
1510  * See SetupGetFileCompressionInfoW.
1511  */
SetupGetFileCompressionInfoA(PCSTR source,PSTR * name,PDWORD source_size,PDWORD target_size,PUINT type)1512 DWORD WINAPI SetupGetFileCompressionInfoA( PCSTR source, PSTR *name, PDWORD source_size,
1513                                            PDWORD target_size, PUINT type )
1514 {
1515     BOOL ret;
1516     DWORD error, required;
1517     LPSTR actual_name;
1518 
1519     TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source), name, source_size, target_size, type);
1520 
1521     if (!source || !name || !source_size || !target_size || !type)
1522         return ERROR_INVALID_PARAMETER;
1523 
1524     ret = SetupGetFileCompressionInfoExA( source, NULL, 0, &required, NULL, NULL, NULL );
1525     if (!(actual_name = MyMalloc( required ))) return ERROR_NOT_ENOUGH_MEMORY;
1526 
1527     ret = SetupGetFileCompressionInfoExA( source, actual_name, required, &required,
1528                                           source_size, target_size, type );
1529     if (!ret)
1530     {
1531         error = GetLastError();
1532         MyFree( actual_name );
1533         return error;
1534     }
1535     *name = actual_name;
1536     return ERROR_SUCCESS;
1537 }
1538 
1539 /***********************************************************************
1540  *      SetupGetFileCompressionInfoW  (SETUPAPI.@)
1541  *
1542  * Get compression type and compressed/uncompressed sizes of a given file.
1543  *
1544  * PARAMS
1545  *  source      [I] File to examine.
1546  *  name        [O] Actual filename used.
1547  *  source_size [O] Size of compressed file.
1548  *  target_size [O] Size of uncompressed file.
1549  *  type        [O] Compression type.
1550  *
1551  * RETURNS
1552  *  Success: ERROR_SUCCESS
1553  *  Failure: Win32 error code.
1554  */
SetupGetFileCompressionInfoW(PCWSTR source,PWSTR * name,PDWORD source_size,PDWORD target_size,PUINT type)1555 DWORD WINAPI SetupGetFileCompressionInfoW( PCWSTR source, PWSTR *name, PDWORD source_size,
1556                                            PDWORD target_size, PUINT type )
1557 {
1558     BOOL ret;
1559     DWORD error, required;
1560     LPWSTR actual_name;
1561 
1562     TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source), name, source_size, target_size, type);
1563 
1564     if (!source || !name || !source_size || !target_size || !type)
1565         return ERROR_INVALID_PARAMETER;
1566 
1567     ret = SetupGetFileCompressionInfoExW( source, NULL, 0, &required, NULL, NULL, NULL );
1568     if (!(actual_name = MyMalloc( required*sizeof(WCHAR) ))) return ERROR_NOT_ENOUGH_MEMORY;
1569 
1570     ret = SetupGetFileCompressionInfoExW( source, actual_name, required, &required,
1571                                           source_size, target_size, type );
1572     if (!ret)
1573     {
1574         error = GetLastError();
1575         MyFree( actual_name );
1576         return error;
1577     }
1578     *name = actual_name;
1579     return ERROR_SUCCESS;
1580 }
1581 
decompress_file_lz(LPCWSTR source,LPCWSTR target)1582 static DWORD decompress_file_lz( LPCWSTR source, LPCWSTR target )
1583 {
1584     DWORD ret;
1585     LONG error;
1586     INT src, dst;
1587     OFSTRUCT sof, dof;
1588 
1589     if ((src = LZOpenFileW( (LPWSTR)source, &sof, OF_READ )) < 0)
1590     {
1591         ERR("cannot open source file for reading\n");
1592         return ERROR_FILE_NOT_FOUND;
1593     }
1594     if ((dst = LZOpenFileW( (LPWSTR)target, &dof, OF_CREATE )) < 0)
1595     {
1596         ERR("cannot open target file for writing\n");
1597         LZClose( src );
1598         return ERROR_FILE_NOT_FOUND;
1599     }
1600     if ((error = LZCopy( src, dst )) >= 0) ret = ERROR_SUCCESS;
1601     else
1602     {
1603         WARN("failed to decompress file %d\n", error);
1604         ret = ERROR_INVALID_DATA;
1605     }
1606 
1607     LZClose( src );
1608     LZClose( dst );
1609     return ret;
1610 }
1611 
1612 struct callback_context
1613 {
1614     BOOL has_extracted;
1615     LPCWSTR target;
1616 };
1617 
decompress_or_copy_callback(PVOID context,UINT notification,UINT_PTR param1,UINT_PTR param2)1618 static UINT CALLBACK decompress_or_copy_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1619 {
1620     struct callback_context *context_info = context;
1621     FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1622 
1623     switch (notification)
1624     {
1625     case SPFILENOTIFY_FILEINCABINET:
1626     {
1627         if (context_info->has_extracted)
1628             return FILEOP_ABORT;
1629 
1630         TRACE("Requesting extraction of cabinet file %s\n",
1631               wine_dbgstr_w(info->NameInCabinet));
1632         strcpyW( info->FullTargetName, context_info->target );
1633         context_info->has_extracted = TRUE;
1634         return FILEOP_DOIT;
1635     }
1636     default: return NO_ERROR;
1637     }
1638 }
1639 
decompress_file_cab(LPCWSTR source,LPCWSTR target)1640 static DWORD decompress_file_cab( LPCWSTR source, LPCWSTR target )
1641 {
1642     struct callback_context context = {0, target};
1643     BOOL ret;
1644 
1645     ret = SetupIterateCabinetW( source, 0, decompress_or_copy_callback, &context );
1646 
1647     if (ret) return ERROR_SUCCESS;
1648     else return GetLastError();
1649 }
1650 
1651 /***********************************************************************
1652  *      SetupDecompressOrCopyFileA  (SETUPAPI.@)
1653  *
1654  * See SetupDecompressOrCopyFileW.
1655  */
SetupDecompressOrCopyFileA(PCSTR source,PCSTR target,PUINT type)1656 DWORD WINAPI SetupDecompressOrCopyFileA( PCSTR source, PCSTR target, PUINT type )
1657 {
1658     DWORD ret = 0;
1659     WCHAR *sourceW = NULL, *targetW = NULL;
1660 
1661     if (source && !(sourceW = pSetupMultiByteToUnicode( source, CP_ACP ))) return FALSE;
1662     if (target && !(targetW = pSetupMultiByteToUnicode( target, CP_ACP )))
1663     {
1664         MyFree( sourceW );
1665         return ERROR_NOT_ENOUGH_MEMORY;
1666     }
1667 
1668     ret = SetupDecompressOrCopyFileW( sourceW, targetW, type );
1669 
1670     MyFree( sourceW );
1671     MyFree( targetW );
1672 
1673     return ret;
1674 }
1675 
1676 /***********************************************************************
1677  *      SetupDecompressOrCopyFileW  (SETUPAPI.@)
1678  *
1679  * Copy a file and decompress it if needed.
1680  *
1681  * PARAMS
1682  *  source [I] File to copy.
1683  *  target [I] Filename of the copy.
1684  *  type   [I] Compression type.
1685  *
1686  * RETURNS
1687  *  Success: ERROR_SUCCESS
1688  *  Failure: Win32 error code.
1689  */
SetupDecompressOrCopyFileW(PCWSTR source,PCWSTR target,PUINT type)1690 DWORD WINAPI SetupDecompressOrCopyFileW( PCWSTR source, PCWSTR target, PUINT type )
1691 {
1692     UINT comp;
1693     DWORD ret = ERROR_INVALID_PARAMETER;
1694 
1695     if (!source || !target) return ERROR_INVALID_PARAMETER;
1696 
1697     if (!type) comp = detect_compression_type( source );
1698     else comp = *type;
1699 
1700     switch (comp)
1701     {
1702     case FILE_COMPRESSION_NONE:
1703         if (CopyFileW( source, target, FALSE )) ret = ERROR_SUCCESS;
1704         else ret = GetLastError();
1705         break;
1706     case FILE_COMPRESSION_WINLZA:
1707         ret = decompress_file_lz( source, target );
1708         break;
1709     case FILE_COMPRESSION_NTCAB:
1710     case FILE_COMPRESSION_MSZIP:
1711         ret = decompress_file_cab( source, target );
1712         break;
1713     default:
1714         WARN("unknown compression type %d\n", comp);
1715         break;
1716     }
1717 
1718     TRACE("%s -> %s %d\n", debugstr_w(source), debugstr_w(target), comp);
1719     return ret;
1720 }
1721 
1722 /*
1723  * implemented (used by pSetupGuidFromString)
1724  */
TrimGuidString(PCWSTR szString,LPWSTR szNewString)1725 static BOOL TrimGuidString(PCWSTR szString, LPWSTR szNewString)
1726 {
1727     WCHAR szBuffer[39];
1728     INT Index;
1729 
1730     if (wcslen(szString) == 38)
1731     {
1732         if ((szString[0] == L'{') && (szString[37] == L'}'))
1733         {
1734             for (Index = 0; Index < wcslen(szString); Index++)
1735                 szBuffer[Index] = szString[Index + 1];
1736 
1737             szBuffer[36] = L'\0';
1738             wcscpy(szNewString, szBuffer);
1739             return TRUE;
1740         }
1741     }
1742     szNewString[0] = L'\0';
1743     return FALSE;
1744 }
1745 
1746 /*
1747  * implemented
1748  */
1749 DWORD
1750 WINAPI
pSetupGuidFromString(PCWSTR pString,LPGUID lpGUID)1751 pSetupGuidFromString(PCWSTR pString, LPGUID lpGUID)
1752 {
1753     RPC_STATUS Status;
1754     WCHAR szBuffer[39];
1755 
1756     if (!TrimGuidString(pString, szBuffer))
1757     {
1758         return RPC_S_INVALID_STRING_UUID;
1759     }
1760 
1761     Status = UuidFromStringW(szBuffer, lpGUID);
1762     if (Status != RPC_S_OK)
1763     {
1764         return RPC_S_INVALID_STRING_UUID;
1765     }
1766 
1767     return NO_ERROR;
1768 }
1769 
1770 /*
1771  * implemented
1772  */
1773 DWORD
1774 WINAPI
pSetupStringFromGuid(LPGUID lpGUID,PWSTR pString,DWORD dwStringLen)1775 pSetupStringFromGuid(LPGUID lpGUID, PWSTR pString, DWORD dwStringLen)
1776 {
1777     RPC_STATUS Status;
1778     RPC_WSTR rpcBuffer;
1779     WCHAR szBuffer[39];
1780 
1781     if (dwStringLen < 39)
1782     {
1783         return ERROR_INSUFFICIENT_BUFFER;
1784     }
1785 
1786     Status = UuidToStringW(lpGUID, &rpcBuffer);
1787     if (Status != RPC_S_OK)
1788     {
1789         return Status;
1790     }
1791 
1792     wcscpy(szBuffer, L"{");
1793     wcscat(szBuffer, rpcBuffer);
1794     wcscat(szBuffer, L"}");
1795 
1796     wcscpy(pString, szBuffer);
1797 
1798     RpcStringFreeW(&rpcBuffer);
1799     return NO_ERROR;
1800 }
1801 
1802 /*
1803  * implemented
1804  */
1805 BOOL
1806 WINAPI
pSetupIsGuidNull(LPGUID lpGUID)1807 pSetupIsGuidNull(LPGUID lpGUID)
1808 {
1809     return IsEqualGUID(lpGUID, &GUID_NULL);
1810 }
1811 
1812 /*
1813  * implemented
1814  */
1815 BOOL
1816 WINAPI
pSetupIsUserAdmin(VOID)1817 pSetupIsUserAdmin(VOID)
1818 {
1819     SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
1820     BOOL bResult = FALSE;
1821     PSID lpSid;
1822 
1823     if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID,
1824                                   DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
1825                                   &lpSid))
1826     {
1827         return FALSE;
1828     }
1829 
1830     if (!CheckTokenMembership(NULL, lpSid, &bResult))
1831     {
1832         bResult = FALSE;
1833     }
1834 
1835     FreeSid(lpSid);
1836 
1837     return bResult;
1838 }
1839 
1840 /***********************************************************************
1841  *		SetupInitializeFileLogW(SETUPAPI.@)
1842  */
SetupInitializeFileLogW(LPCWSTR LogFileName,DWORD Flags)1843 HSPFILELOG WINAPI SetupInitializeFileLogW(LPCWSTR LogFileName, DWORD Flags)
1844 {
1845     struct FileLog * Log;
1846     HANDLE hLog;
1847     WCHAR Windir[MAX_PATH];
1848     DWORD ret;
1849 
1850     TRACE("%s, 0x%x\n",debugstr_w(LogFileName),Flags);
1851 
1852     if (Flags & SPFILELOG_SYSTEMLOG)
1853     {
1854         if (!pSetupIsUserAdmin() && !(Flags & SPFILELOG_QUERYONLY))
1855         {
1856             /* insufficient privileges */
1857             SetLastError(ERROR_ACCESS_DENIED);
1858             return INVALID_HANDLE_VALUE;
1859         }
1860 
1861         if (LogFileName || (Flags & SPFILELOG_FORCENEW))
1862         {
1863             /* invalid parameter */
1864             SetLastError(ERROR_INVALID_PARAMETER);
1865             return INVALID_HANDLE_VALUE;
1866         }
1867 
1868         ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
1869         if (!ret || ret >= MAX_PATH)
1870         {
1871             /* generic failure */
1872             return INVALID_HANDLE_VALUE;
1873         }
1874 
1875         /* append path */
1876         wcscat(Windir, L"repair\\setup.log");
1877     }
1878     else
1879     {
1880         if (!LogFileName)
1881         {
1882             /* invalid parameter */
1883             SetLastError(ERROR_INVALID_PARAMETER);
1884             return INVALID_HANDLE_VALUE;
1885         }
1886         /* copy filename */
1887         wcsncpy(Windir, LogFileName, MAX_PATH);
1888     }
1889 
1890     if (FileExists(Windir, NULL))
1891     {
1892         /* take ownership */
1893         ret = TakeOwnershipOfFile(Windir);
1894 
1895         if (ret != ERROR_SUCCESS)
1896         {
1897             /* failed */
1898             SetLastError(ret);
1899             return INVALID_HANDLE_VALUE;
1900         }
1901 
1902         if (!SetFileAttributesW(Windir, FILE_ATTRIBUTE_NORMAL))
1903         {
1904             /* failed */
1905             return INVALID_HANDLE_VALUE;
1906         }
1907 
1908         if ((Flags & SPFILELOG_FORCENEW))
1909         {
1910             if (!DeleteFileW(Windir))
1911             {
1912                 /* failed */
1913                 return INVALID_HANDLE_VALUE;
1914             }
1915         }
1916     }
1917 
1918     /* open log file */
1919     hLog = CreateFileW(Windir,
1920                        (Flags & SPFILELOG_QUERYONLY) ? GENERIC_READ : GENERIC_WRITE,
1921                        FILE_SHARE_READ | FILE_SHARE_WRITE,
1922                        NULL,
1923                        OPEN_ALWAYS,
1924                        FILE_ATTRIBUTE_NORMAL,
1925                        NULL);
1926 
1927     if (hLog == INVALID_HANDLE_VALUE)
1928     {
1929         /* failed */
1930         return INVALID_HANDLE_VALUE;
1931     }
1932 
1933     /* close log handle */
1934     CloseHandle(hLog);
1935 
1936     /* allocate file log struct */
1937     Log = HeapAlloc(GetProcessHeap(), 0, sizeof(struct FileLog));
1938     if (!Log)
1939     {
1940         /* not enough memory */
1941         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1942         return INVALID_HANDLE_VALUE;
1943     }
1944 
1945     /* initialize log */
1946     Log->LogName = HeapAlloc(GetProcessHeap(), 0, (wcslen(Windir)+1) * sizeof(WCHAR));
1947     if (!Log->LogName)
1948     {
1949         /* not enough memory */
1950         HeapFree(GetProcessHeap(), 0, Log);
1951         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1952         return INVALID_HANDLE_VALUE;
1953     }
1954 
1955     wcscpy(Log->LogName, Windir);
1956     Log->ReadOnly = (Flags & SPFILELOG_QUERYONLY);
1957     Log->SystemLog = (Flags & SPFILELOG_SYSTEMLOG);
1958 
1959     return (HSPFILELOG)Log;
1960 }
1961 
1962 /***********************************************************************
1963  *		SetupInitializeFileLogA(SETUPAPI.@)
1964  */
SetupInitializeFileLogA(LPCSTR LogFileName,DWORD Flags)1965 HSPFILELOG WINAPI SetupInitializeFileLogA(LPCSTR LogFileName, DWORD Flags)
1966 {
1967     HSPFILELOG hLog;
1968     LPWSTR LogFileNameW = NULL;
1969 
1970     TRACE("%s, 0x%x\n",debugstr_a(LogFileName),Flags);
1971 
1972     if (LogFileName)
1973     {
1974         LogFileNameW = strdupAtoW(LogFileName);
1975 
1976         if (!LogFileNameW)
1977         {
1978             /* not enough memory */
1979             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1980             return INVALID_HANDLE_VALUE;
1981         }
1982 
1983         hLog = SetupInitializeFileLogW(LogFileNameW, Flags);
1984         HeapFree(GetProcessHeap(), 0, LogFileNameW);
1985     }
1986     else
1987     {
1988         hLog = SetupInitializeFileLogW(NULL, Flags);
1989     }
1990 
1991     return hLog;
1992 }
1993 
1994 /***********************************************************************
1995  *		SetupTerminateFileLog(SETUPAPI.@)
1996  */
SetupTerminateFileLog(HANDLE FileLogHandle)1997 BOOL WINAPI SetupTerminateFileLog(HANDLE FileLogHandle)
1998 {
1999     struct FileLog * Log;
2000 
2001     TRACE ("%p\n",FileLogHandle);
2002 
2003     Log = (struct FileLog *)FileLogHandle;
2004 
2005     /* free file log handle */
2006     HeapFree(GetProcessHeap(), 0, Log->LogName);
2007     HeapFree(GetProcessHeap(), 0, Log);
2008 
2009     SetLastError(ERROR_SUCCESS);
2010 
2011     return TRUE;
2012 }
2013 
2014 /***********************************************************************
2015  *      SetupCloseLog(SETUPAPI.@)
2016  */
SetupCloseLog(void)2017 void WINAPI SetupCloseLog(void)
2018 {
2019     EnterCriticalSection(&setupapi_cs);
2020 
2021     CloseHandle(setupact);
2022     setupact = INVALID_HANDLE_VALUE;
2023 
2024     CloseHandle(setuperr);
2025     setuperr = INVALID_HANDLE_VALUE;
2026 
2027     LeaveCriticalSection(&setupapi_cs);
2028 }
2029 
2030 /***********************************************************************
2031  *      SetupOpenLog(SETUPAPI.@)
2032  */
SetupOpenLog(BOOL reserved)2033 BOOL WINAPI SetupOpenLog(BOOL reserved)
2034 {
2035     WCHAR path[MAX_PATH];
2036 
2037     static const WCHAR setupactlog[] = {'\\','s','e','t','u','p','a','c','t','.','l','o','g',0};
2038     static const WCHAR setuperrlog[] = {'\\','s','e','t','u','p','e','r','r','.','l','o','g',0};
2039 
2040     EnterCriticalSection(&setupapi_cs);
2041 
2042     if (setupact != INVALID_HANDLE_VALUE && setuperr != INVALID_HANDLE_VALUE)
2043     {
2044         LeaveCriticalSection(&setupapi_cs);
2045         return TRUE;
2046     }
2047 
2048     GetWindowsDirectoryW(path, MAX_PATH);
2049     lstrcatW(path, setupactlog);
2050 
2051     setupact = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
2052                            NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2053     if (setupact == INVALID_HANDLE_VALUE)
2054     {
2055         LeaveCriticalSection(&setupapi_cs);
2056         return FALSE;
2057     }
2058 
2059     SetFilePointer(setupact, 0, NULL, FILE_END);
2060 
2061     GetWindowsDirectoryW(path, MAX_PATH);
2062     lstrcatW(path, setuperrlog);
2063 
2064     setuperr = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
2065                            NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2066     if (setuperr == INVALID_HANDLE_VALUE)
2067     {
2068         CloseHandle(setupact);
2069         setupact = INVALID_HANDLE_VALUE;
2070         LeaveCriticalSection(&setupapi_cs);
2071         return FALSE;
2072     }
2073 
2074     SetFilePointer(setuperr, 0, NULL, FILE_END);
2075 
2076     LeaveCriticalSection(&setupapi_cs);
2077 
2078     return TRUE;
2079 }
2080 
2081 /***********************************************************************
2082  *      SetupLogErrorA(SETUPAPI.@)
2083  */
SetupLogErrorA(LPCSTR message,LogSeverity severity)2084 BOOL WINAPI SetupLogErrorA(LPCSTR message, LogSeverity severity)
2085 {
2086     static const char null[] = "(null)";
2087     BOOL ret;
2088     DWORD written;
2089     DWORD len;
2090 
2091     EnterCriticalSection(&setupapi_cs);
2092 
2093     if (setupact == INVALID_HANDLE_VALUE || setuperr == INVALID_HANDLE_VALUE)
2094     {
2095         SetLastError(ERROR_FILE_INVALID);
2096         ret = FALSE;
2097         goto done;
2098     }
2099 
2100     if (message == NULL)
2101         message = null;
2102 
2103     len = lstrlenA(message);
2104 
2105     ret = WriteFile(setupact, message, len, &written, NULL);
2106     if (!ret)
2107         goto done;
2108 
2109     if (severity >= LogSevMaximum)
2110     {
2111         ret = FALSE;
2112         goto done;
2113     }
2114 
2115     if (severity > LogSevInformation)
2116         ret = WriteFile(setuperr, message, len, &written, NULL);
2117 
2118 done:
2119     LeaveCriticalSection(&setupapi_cs);
2120     return ret;
2121 }
2122 
2123 /***********************************************************************
2124  *      SetupLogErrorW(SETUPAPI.@)
2125  */
SetupLogErrorW(LPCWSTR message,LogSeverity severity)2126 BOOL WINAPI SetupLogErrorW(LPCWSTR message, LogSeverity severity)
2127 {
2128     LPSTR msg = NULL;
2129     DWORD len;
2130     BOOL ret;
2131 
2132     if (message)
2133     {
2134         len = WideCharToMultiByte(CP_ACP, 0, message, -1, NULL, 0, NULL, NULL);
2135         msg = HeapAlloc(GetProcessHeap(), 0, len);
2136         if (msg == NULL)
2137         {
2138             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2139             return FALSE;
2140         }
2141         WideCharToMultiByte(CP_ACP, 0, message, -1, msg, len, NULL, NULL);
2142     }
2143 
2144     /* This is the normal way to proceed. The log files are ASCII files
2145      * and W is to be converted.
2146      */
2147     ret = SetupLogErrorA(msg, severity);
2148 
2149     HeapFree(GetProcessHeap(), 0, msg);
2150     return ret;
2151 }
2152