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