701af294924179921a98777aac88bd06639b8b71
[reactos.git] / dll / win32 / setupapi / misc.c
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
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
850 DWORD WINAPI pSetupGetGlobalFlags(void)
851 {
852 return GlobalSetupFlags;
853 }
854
855 /***********************************************************************
856 * pSetupModifyGlobalFlags (SETUPAPI.@)
857 */
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 */
867 void WINAPI pSetupSetGlobalFlags( DWORD flags )
868 {
869 pSetupModifyGlobalFlags(0xFFFFFFFF, flags);
870 }
871
872
873 /***********************************************************************
874 * AssertFail (SETUPAPI.@)
875 *
876 * Shows an assert fail error messagebox
877 *
878 * PARAMS
879 * lpFile [I] file where assert failed
880 * uLine [I] line number in file
881 * lpMessage [I] assert message
882 *
883 */
884 VOID WINAPI AssertFail(LPSTR lpFile, UINT uLine, LPSTR lpMessage)
885 {
886 CHAR szModule[MAX_PATH];
887 CHAR szBuffer[2048];
888 LPSTR lpName;
889 // LPSTR lpBuffer;
890
891 TRACE("%s %u %s\n", lpFile, uLine, lpMessage);
892
893 GetModuleFileNameA(hInstance, szModule, MAX_PATH);
894 lpName = strrchr(szModule, '\\');
895 if (lpName != NULL)
896 lpName++;
897 else
898 lpName = szModule;
899
900 wsprintfA(szBuffer,
901 "Assertion failure at line %u in file %s: %s\n\nCall DebugBreak()?",
902 uLine, lpFile, lpMessage);
903
904 if (MessageBoxA(NULL, szBuffer, lpName, MB_SETFOREGROUND |
905 MB_TASKMODAL | MB_ICONERROR | MB_YESNO) == IDYES)
906 DebugBreak();
907 }
908
909
910 /**************************************************************************
911 * GetSetFileTimestamp [SETUPAPI.@]
912 *
913 * Gets or sets a files timestamp.
914 *
915 * PARAMS
916 * lpFileName [I] File name
917 * lpCreationTime [I/O] Creation time
918 * lpLastAccessTime [I/O] Last access time
919 * lpLastWriteTime [I/O] Last write time
920 * bSetFileTime [I] TRUE: Set file times
921 * FALSE: Get file times
922 *
923 * RETURNS
924 * Success: ERROR_SUCCESS
925 * Failure: other
926 */
927 DWORD WINAPI GetSetFileTimestamp(LPCWSTR lpFileName,
928 LPFILETIME lpCreationTime,
929 LPFILETIME lpLastAccessTime,
930 LPFILETIME lpLastWriteTime,
931 BOOLEAN bSetFileTime)
932 {
933 HANDLE hFile;
934 BOOLEAN bRet;
935 DWORD dwError = ERROR_SUCCESS;
936
937 TRACE("%s %p %p %p %x\n", debugstr_w(lpFileName), lpCreationTime,
938 lpLastAccessTime, lpLastWriteTime, bSetFileTime);
939
940 hFile = CreateFileW(lpFileName,
941 bSetFileTime ? GENERIC_WRITE : GENERIC_READ,
942 FILE_SHARE_READ | FILE_SHARE_WRITE,
943 NULL,
944 OPEN_EXISTING,
945 0,
946 NULL);
947
948 if (hFile == INVALID_HANDLE_VALUE)
949 return GetLastError();
950
951 if (bSetFileTime)
952 bRet = SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
953 else
954 bRet = GetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
955
956 if (bRet == FALSE)
957 dwError = GetLastError();
958
959 CloseHandle(hFile);
960
961 return dwError;
962 }
963
964
965 /**************************************************************************
966 * pSetupGetFileTitle [SETUPAPI.@]
967 *
968 * Returns a pointer to the last part of a fully qualified file name.
969 *
970 * PARAMS
971 * lpFileName [I] File name
972 *
973 * RETURNS
974 * Pointer to a files name.
975 */
976 LPWSTR WINAPI
977 pSetupGetFileTitle(LPCWSTR lpFileName)
978 {
979 LPWSTR ptr;
980 LPWSTR ret;
981 WCHAR c;
982
983 TRACE("%s\n", debugstr_w(lpFileName));
984
985 ptr = (LPWSTR)lpFileName;
986 ret = ptr;
987 while (TRUE)
988 {
989 c = *ptr;
990
991 if (c == 0)
992 break;
993
994 ptr++;
995 if (c == (WCHAR)'\\' || c == (WCHAR)'/' || c == (WCHAR)':')
996 ret = ptr;
997 }
998
999 return ret;
1000 }
1001
1002
1003 /**************************************************************************
1004 * pSetupConcatenatePaths [SETUPAPI.@]
1005 *
1006 * Concatenates two paths.
1007 *
1008 * PARAMS
1009 * lpPath [I/O] Path to append path to
1010 * lpAppend [I] Path to append
1011 * dwBufferSize [I] Size of the path buffer
1012 * lpRequiredSize [O] Required size for the concatenated path. Optional
1013 *
1014 * RETURNS
1015 * Success: TRUE
1016 * Failure: FALSE
1017 */
1018 BOOL WINAPI
1019 pSetupConcatenatePaths(LPWSTR lpPath,
1020 LPCWSTR lpAppend,
1021 DWORD dwBufferSize,
1022 LPDWORD lpRequiredSize)
1023 {
1024 DWORD dwPathSize;
1025 DWORD dwAppendSize;
1026 DWORD dwTotalSize;
1027 BOOL bBackslash = FALSE;
1028
1029 TRACE("%s %s %lu %p\n", debugstr_w(lpPath), debugstr_w(lpAppend),
1030 dwBufferSize, lpRequiredSize);
1031
1032 dwPathSize = lstrlenW(lpPath);
1033
1034 /* Ignore trailing backslash */
1035 if (lpPath[dwPathSize - 1] == (WCHAR)'\\')
1036 dwPathSize--;
1037
1038 dwAppendSize = lstrlenW(lpAppend);
1039
1040 /* Does the source string have a leading backslash? */
1041 if (lpAppend[0] == (WCHAR)'\\')
1042 {
1043 bBackslash = TRUE;
1044 dwAppendSize--;
1045 }
1046
1047 dwTotalSize = dwPathSize + dwAppendSize + 2;
1048 if (lpRequiredSize != NULL)
1049 *lpRequiredSize = dwTotalSize;
1050
1051 /* Append a backslash to the destination string */
1052 if (bBackslash == FALSE)
1053 {
1054 if (dwPathSize < dwBufferSize)
1055 {
1056 lpPath[dwPathSize - 1] = (WCHAR)'\\';
1057 dwPathSize++;
1058 }
1059 }
1060
1061 if (dwPathSize + dwAppendSize < dwBufferSize)
1062 {
1063 lstrcpynW(&lpPath[dwPathSize],
1064 lpAppend,
1065 dwAppendSize);
1066 }
1067
1068 if (dwBufferSize >= dwTotalSize)
1069 lpPath[dwTotalSize - 1] = 0;
1070
1071 return (dwBufferSize >= dwTotalSize);
1072 }
1073
1074
1075 /**************************************************************************
1076 * pSetupCenterWindowRelativeToParent [SETUPAPI.@]
1077 *
1078 * Centers a window relative to its parent.
1079 *
1080 * PARAMS
1081 * hwnd [I] Window to center.
1082 *
1083 * RETURNS
1084 * None
1085 */
1086 VOID WINAPI
1087 pSetupCenterWindowRelativeToParent(HWND hwnd)
1088 {
1089 HWND hwndOwner;
1090 POINT ptOrigin;
1091 RECT rcWindow;
1092 RECT rcOwner;
1093 INT nWindowWidth, nWindowHeight;
1094 INT nOwnerWidth, nOwnerHeight;
1095 INT posX, posY;
1096
1097 hwndOwner = GetWindow(hwnd, GW_OWNER);
1098 if (hwndOwner == NULL)
1099 return;
1100
1101 ptOrigin.x = 0;
1102 ptOrigin.y = 0;
1103 ClientToScreen(hwndOwner, &ptOrigin);
1104
1105 GetWindowRect(hwnd, &rcWindow);
1106 GetClientRect(hwndOwner, &rcOwner);
1107
1108 nWindowWidth = rcWindow.right - rcWindow.left;
1109 nWindowHeight = rcWindow.bottom - rcWindow.top;
1110
1111 nOwnerWidth = rcOwner.right - rcOwner.left;
1112 nOwnerHeight = rcOwner.bottom - rcOwner.top;
1113
1114 posX = ((nOwnerWidth - nWindowWidth) / 2) + ptOrigin.x;
1115 posY = ((nOwnerHeight - nWindowHeight) / 2) + ptOrigin.y;
1116
1117 MoveWindow(hwnd, posX, posY, nWindowWidth, nWindowHeight, 0);
1118 }
1119
1120
1121 /**************************************************************************
1122 * pSetupGetVersionInfoFromImage [SETUPAPI.@]
1123 *
1124 * Retrieves version information for a given file.
1125 *
1126 * PARAMS
1127 * lpFileName [I] File name
1128 * lpFileVersion [O] Pointer to the full file version
1129 * lpVersionVarSize [O] Pointer to the size of the variable version
1130 * information
1131 *
1132 * RETURNS
1133 * Success: TRUE
1134 * Failure: FALSE
1135 */
1136 BOOL WINAPI
1137 pSetupGetVersionInfoFromImage(LPWSTR lpFileName,
1138 PULARGE_INTEGER lpFileVersion,
1139 LPWORD lpVersionVarSize)
1140 {
1141 DWORD dwHandle;
1142 DWORD dwSize;
1143 LPVOID lpInfo;
1144 UINT uSize;
1145 VS_FIXEDFILEINFO *lpFixedInfo;
1146 LPWORD lpVarSize;
1147
1148 dwSize = GetFileVersionInfoSizeW(lpFileName, &dwHandle);
1149 if (dwSize == 0)
1150 return FALSE;
1151
1152 lpInfo = MyMalloc(dwSize);
1153 if (lpInfo == NULL)
1154 return FALSE;
1155
1156 if (!GetFileVersionInfoW(lpFileName, 0, dwSize, lpInfo))
1157 {
1158 MyFree(lpInfo);
1159 return FALSE;
1160 }
1161
1162 if (!VerQueryValueW(lpInfo, BackSlash,
1163 (LPVOID*)&lpFixedInfo, &uSize))
1164 {
1165 MyFree(lpInfo);
1166 return FALSE;
1167 }
1168
1169 lpFileVersion->LowPart = lpFixedInfo->dwFileVersionLS;
1170 lpFileVersion->HighPart = lpFixedInfo->dwFileVersionMS;
1171
1172 *lpVersionVarSize = 0;
1173 if (!VerQueryValueW(lpInfo, TranslationRegKey,
1174 (LPVOID*)&lpVarSize, &uSize))
1175 {
1176 MyFree(lpInfo);
1177 return TRUE;
1178 }
1179
1180 if (uSize >= 4)
1181 {
1182 *lpVersionVarSize = *lpVarSize;
1183 }
1184
1185 MyFree(lpInfo);
1186
1187 return TRUE;
1188 }
1189
1190 /***********************************************************************
1191 * SetupUninstallOEMInfW (SETUPAPI.@)
1192 */
1193 BOOL WINAPI SetupUninstallOEMInfW( PCWSTR inf_file, DWORD flags, PVOID reserved )
1194 {
1195 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
1196 WCHAR target[MAX_PATH];
1197
1198 TRACE("%s, 0x%08x, %p\n", debugstr_w(inf_file), flags, reserved);
1199
1200 if (!inf_file)
1201 {
1202 SetLastError(ERROR_INVALID_PARAMETER);
1203 return FALSE;
1204 }
1205
1206 if (!GetWindowsDirectoryW( target, sizeof(target)/sizeof(WCHAR) )) return FALSE;
1207
1208 strcatW( target, infW );
1209 strcatW( target, inf_file );
1210
1211 if (flags & SUOI_FORCEDELETE)
1212 return DeleteFileW(target);
1213
1214 FIXME("not deleting %s\n", debugstr_w(target));
1215
1216 return TRUE;
1217 }
1218
1219 /***********************************************************************
1220 * SetupUninstallOEMInfA (SETUPAPI.@)
1221 */
1222 BOOL WINAPI SetupUninstallOEMInfA( PCSTR inf_file, DWORD flags, PVOID reserved )
1223 {
1224 BOOL ret;
1225 WCHAR *inf_fileW = NULL;
1226
1227 TRACE("%s, 0x%08x, %p\n", debugstr_a(inf_file), flags, reserved);
1228
1229 if (inf_file && !(inf_fileW = strdupAtoW( inf_file ))) return FALSE;
1230 ret = SetupUninstallOEMInfW( inf_fileW, flags, reserved );
1231 HeapFree( GetProcessHeap(), 0, inf_fileW );
1232 return ret;
1233 }
1234
1235 /***********************************************************************
1236 * InstallCatalog (SETUPAPI.@)
1237 */
1238 DWORD WINAPI InstallCatalog( LPCSTR catalog, LPCSTR basename, LPSTR fullname )
1239 {
1240 FIXME("%s, %s, %p\n", debugstr_a(catalog), debugstr_a(basename), fullname);
1241 return 0;
1242 }
1243
1244 /***********************************************************************
1245 * pSetupInstallCatalog (SETUPAPI.@)
1246 */
1247 DWORD WINAPI pSetupInstallCatalog( LPCWSTR catalog, LPCWSTR basename, LPWSTR fullname )
1248 {
1249 HCATADMIN admin;
1250 HCATINFO cat;
1251
1252 TRACE ("%s, %s, %p\n", debugstr_w(catalog), debugstr_w(basename), fullname);
1253
1254 if (!CryptCATAdminAcquireContext(&admin,NULL,0))
1255 return GetLastError();
1256
1257 if (!(cat = CryptCATAdminAddCatalog( admin, (PWSTR)catalog, (PWSTR)basename, 0 )))
1258 {
1259 DWORD rc = GetLastError();
1260 CryptCATAdminReleaseContext(admin, 0);
1261 return rc;
1262 }
1263 CryptCATAdminReleaseCatalogContext(admin, cat, 0);
1264 CryptCATAdminReleaseContext(admin,0);
1265
1266 if (fullname)
1267 FIXME("not returning full installed catalog path\n");
1268
1269 return NO_ERROR;
1270 }
1271
1272 static UINT detect_compression_type( LPCWSTR file )
1273 {
1274 DWORD size;
1275 HANDLE handle;
1276 UINT type = FILE_COMPRESSION_NONE;
1277 static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1278 static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1279 static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1280 BYTE buffer[8];
1281
1282 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1283 if (handle == INVALID_HANDLE_VALUE)
1284 {
1285 ERR("cannot open file %s\n", debugstr_w(file));
1286 return FILE_COMPRESSION_NONE;
1287 }
1288 if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1289 {
1290 CloseHandle( handle );
1291 return FILE_COMPRESSION_NONE;
1292 }
1293 if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1294 else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1295 else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1296
1297 CloseHandle( handle );
1298 return type;
1299 }
1300
1301 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1302 {
1303 HANDLE handle;
1304
1305 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1306 if (handle == INVALID_HANDLE_VALUE)
1307 {
1308 ERR("cannot open file %s\n", debugstr_w(file));
1309 return FALSE;
1310 }
1311 *size = GetFileSize( handle, NULL );
1312 CloseHandle( handle );
1313 return TRUE;
1314 }
1315
1316 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1317 {
1318 DWORD size;
1319
1320 if (!get_file_size( source, &size )) return FALSE;
1321 if (source_size) *source_size = size;
1322 if (target_size) *target_size = size;
1323 return TRUE;
1324 }
1325
1326 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1327 {
1328 DWORD size;
1329 BOOL ret = TRUE;
1330
1331 if (source_size)
1332 {
1333 if (!get_file_size( source, &size )) ret = FALSE;
1334 else *source_size = size;
1335 }
1336 if (target_size)
1337 {
1338 INT file;
1339 OFSTRUCT of;
1340
1341 if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1342 {
1343 ERR("cannot open source file for reading\n");
1344 return FALSE;
1345 }
1346 *target_size = LZSeek( file, 0, 2 );
1347 LZClose( file );
1348 }
1349 return ret;
1350 }
1351
1352 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1353 {
1354 DWORD *size = context;
1355 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1356
1357 switch (notification)
1358 {
1359 case SPFILENOTIFY_FILEINCABINET:
1360 {
1361 *size = info->FileSize;
1362 return FILEOP_SKIP;
1363 }
1364 default: return NO_ERROR;
1365 }
1366 }
1367
1368 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1369 {
1370 DWORD size;
1371 BOOL ret = TRUE;
1372
1373 if (source_size)
1374 {
1375 if (!get_file_size( source, &size )) ret = FALSE;
1376 else *source_size = size;
1377 }
1378 if (target_size)
1379 {
1380 ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1381 }
1382 return ret;
1383 }
1384
1385 /***********************************************************************
1386 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1387 *
1388 * See SetupGetFileCompressionInfoExW.
1389 */
1390 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1391 PDWORD source_size, PDWORD target_size, PUINT type )
1392 {
1393 BOOL ret;
1394 WCHAR *nameW = NULL, *sourceW = NULL;
1395 DWORD nb_chars = 0;
1396 LPSTR nameA;
1397
1398 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1399 source_size, target_size, type);
1400
1401 if (!source || !(sourceW = pSetupMultiByteToUnicode( source, CP_ACP ))) return FALSE;
1402
1403 if (name)
1404 {
1405 ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1406 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, nb_chars * sizeof(WCHAR) )))
1407 {
1408 MyFree( sourceW );
1409 return FALSE;
1410 }
1411 }
1412 ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1413 if (ret)
1414 {
1415 if ((nameA = pSetupUnicodeToMultiByte( nameW, CP_ACP )))
1416 {
1417 if (name && len >= nb_chars) lstrcpyA( name, nameA );
1418 else
1419 {
1420 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1421 ret = FALSE;
1422 }
1423 MyFree( nameA );
1424 }
1425 }
1426 if (required) *required = nb_chars;
1427 HeapFree( GetProcessHeap(), 0, nameW );
1428 MyFree( sourceW );
1429
1430 return ret;
1431 }
1432
1433 /***********************************************************************
1434 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1435 *
1436 * Get compression type and compressed/uncompressed sizes of a given file.
1437 *
1438 * PARAMS
1439 * source [I] File to examine.
1440 * name [O] Actual filename used.
1441 * len [I] Length in characters of 'name' buffer.
1442 * required [O] Number of characters written to 'name'.
1443 * source_size [O] Size of compressed file.
1444 * target_size [O] Size of uncompressed file.
1445 * type [O] Compression type.
1446 *
1447 * RETURNS
1448 * Success: TRUE
1449 * Failure: FALSE
1450 */
1451 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1452 PDWORD source_size, PDWORD target_size, PUINT type )
1453 {
1454 UINT comp;
1455 BOOL ret = FALSE;
1456 DWORD source_len;
1457
1458 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1459 source_size, target_size, type);
1460
1461 if (!source) return FALSE;
1462
1463 source_len = lstrlenW( source ) + 1;
1464 if (required) *required = source_len;
1465 if (name && len >= source_len)
1466 {
1467 lstrcpyW( name, source );
1468 ret = TRUE;
1469 }
1470 else return FALSE;
1471
1472 comp = detect_compression_type( source );
1473 if (type) *type = comp;
1474
1475 switch (comp)
1476 {
1477 case FILE_COMPRESSION_MSZIP:
1478 case FILE_COMPRESSION_NTCAB: ret = get_file_sizes_cab( source, source_size, target_size ); break;
1479 case FILE_COMPRESSION_NONE: ret = get_file_sizes_none( source, source_size, target_size ); break;
1480 case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1481 default: break;
1482 }
1483 return ret;
1484 }
1485
1486 /***********************************************************************
1487 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1488 *
1489 * See SetupGetFileCompressionInfoW.
1490 */
1491 DWORD WINAPI SetupGetFileCompressionInfoA( PCSTR source, PSTR *name, PDWORD source_size,
1492 PDWORD target_size, PUINT type )
1493 {
1494 BOOL ret;
1495 DWORD error, required;
1496 LPSTR actual_name;
1497
1498 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source), name, source_size, target_size, type);
1499
1500 if (!source || !name || !source_size || !target_size || !type)
1501 return ERROR_INVALID_PARAMETER;
1502
1503 ret = SetupGetFileCompressionInfoExA( source, NULL, 0, &required, NULL, NULL, NULL );
1504 if (!(actual_name = MyMalloc( required ))) return ERROR_NOT_ENOUGH_MEMORY;
1505
1506 ret = SetupGetFileCompressionInfoExA( source, actual_name, required, &required,
1507 source_size, target_size, type );
1508 if (!ret)
1509 {
1510 error = GetLastError();
1511 MyFree( actual_name );
1512 return error;
1513 }
1514 *name = actual_name;
1515 return ERROR_SUCCESS;
1516 }
1517
1518 /***********************************************************************
1519 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1520 *
1521 * Get compression type and compressed/uncompressed sizes of a given file.
1522 *
1523 * PARAMS
1524 * source [I] File to examine.
1525 * name [O] Actual filename used.
1526 * source_size [O] Size of compressed file.
1527 * target_size [O] Size of uncompressed file.
1528 * type [O] Compression type.
1529 *
1530 * RETURNS
1531 * Success: ERROR_SUCCESS
1532 * Failure: Win32 error code.
1533 */
1534 DWORD WINAPI SetupGetFileCompressionInfoW( PCWSTR source, PWSTR *name, PDWORD source_size,
1535 PDWORD target_size, PUINT type )
1536 {
1537 BOOL ret;
1538 DWORD error, required;
1539 LPWSTR actual_name;
1540
1541 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source), name, source_size, target_size, type);
1542
1543 if (!source || !name || !source_size || !target_size || !type)
1544 return ERROR_INVALID_PARAMETER;
1545
1546 ret = SetupGetFileCompressionInfoExW( source, NULL, 0, &required, NULL, NULL, NULL );
1547 if (!(actual_name = MyMalloc( required*sizeof(WCHAR) ))) return ERROR_NOT_ENOUGH_MEMORY;
1548
1549 ret = SetupGetFileCompressionInfoExW( source, actual_name, required, &required,
1550 source_size, target_size, type );
1551 if (!ret)
1552 {
1553 error = GetLastError();
1554 MyFree( actual_name );
1555 return error;
1556 }
1557 *name = actual_name;
1558 return ERROR_SUCCESS;
1559 }
1560
1561 static DWORD decompress_file_lz( LPCWSTR source, LPCWSTR target )
1562 {
1563 DWORD ret;
1564 LONG error;
1565 INT src, dst;
1566 OFSTRUCT sof, dof;
1567
1568 if ((src = LZOpenFileW( (LPWSTR)source, &sof, OF_READ )) < 0)
1569 {
1570 ERR("cannot open source file for reading\n");
1571 return ERROR_FILE_NOT_FOUND;
1572 }
1573 if ((dst = LZOpenFileW( (LPWSTR)target, &dof, OF_CREATE )) < 0)
1574 {
1575 ERR("cannot open target file for writing\n");
1576 LZClose( src );
1577 return ERROR_FILE_NOT_FOUND;
1578 }
1579 if ((error = LZCopy( src, dst )) >= 0) ret = ERROR_SUCCESS;
1580 else
1581 {
1582 WARN("failed to decompress file %d\n", error);
1583 ret = ERROR_INVALID_DATA;
1584 }
1585
1586 LZClose( src );
1587 LZClose( dst );
1588 return ret;
1589 }
1590
1591 struct callback_context
1592 {
1593 BOOL has_extracted;
1594 LPCWSTR target;
1595 };
1596
1597 static UINT CALLBACK decompress_or_copy_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1598 {
1599 struct callback_context *context_info = context;
1600 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1601
1602 switch (notification)
1603 {
1604 case SPFILENOTIFY_FILEINCABINET:
1605 {
1606 if (context_info->has_extracted)
1607 return FILEOP_ABORT;
1608
1609 TRACE("Requesting extraction of cabinet file %s\n",
1610 wine_dbgstr_w(info->NameInCabinet));
1611 strcpyW( info->FullTargetName, context_info->target );
1612 context_info->has_extracted = TRUE;
1613 return FILEOP_DOIT;
1614 }
1615 default: return NO_ERROR;
1616 }
1617 }
1618
1619 static DWORD decompress_file_cab( LPCWSTR source, LPCWSTR target )
1620 {
1621 struct callback_context context = {0, target};
1622 BOOL ret;
1623
1624 ret = SetupIterateCabinetW( source, 0, decompress_or_copy_callback, &context );
1625
1626 if (ret) return ERROR_SUCCESS;
1627 else return GetLastError();
1628 }
1629
1630 /***********************************************************************
1631 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1632 *
1633 * See SetupDecompressOrCopyFileW.
1634 */
1635 DWORD WINAPI SetupDecompressOrCopyFileA( PCSTR source, PCSTR target, PUINT type )
1636 {
1637 DWORD ret = 0;
1638 WCHAR *sourceW = NULL, *targetW = NULL;
1639
1640 if (source && !(sourceW = pSetupMultiByteToUnicode( source, CP_ACP ))) return FALSE;
1641 if (target && !(targetW = pSetupMultiByteToUnicode( target, CP_ACP )))
1642 {
1643 MyFree( sourceW );
1644 return ERROR_NOT_ENOUGH_MEMORY;
1645 }
1646
1647 ret = SetupDecompressOrCopyFileW( sourceW, targetW, type );
1648
1649 MyFree( sourceW );
1650 MyFree( targetW );
1651
1652 return ret;
1653 }
1654
1655 /***********************************************************************
1656 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1657 *
1658 * Copy a file and decompress it if needed.
1659 *
1660 * PARAMS
1661 * source [I] File to copy.
1662 * target [I] Filename of the copy.
1663 * type [I] Compression type.
1664 *
1665 * RETURNS
1666 * Success: ERROR_SUCCESS
1667 * Failure: Win32 error code.
1668 */
1669 DWORD WINAPI SetupDecompressOrCopyFileW( PCWSTR source, PCWSTR target, PUINT type )
1670 {
1671 UINT comp;
1672 DWORD ret = ERROR_INVALID_PARAMETER;
1673
1674 if (!source || !target) return ERROR_INVALID_PARAMETER;
1675
1676 if (!type) comp = detect_compression_type( source );
1677 else comp = *type;
1678
1679 switch (comp)
1680 {
1681 case FILE_COMPRESSION_NONE:
1682 if (CopyFileW( source, target, FALSE )) ret = ERROR_SUCCESS;
1683 else ret = GetLastError();
1684 break;
1685 case FILE_COMPRESSION_WINLZA:
1686 ret = decompress_file_lz( source, target );
1687 break;
1688 case FILE_COMPRESSION_NTCAB:
1689 case FILE_COMPRESSION_MSZIP:
1690 ret = decompress_file_cab( source, target );
1691 break;
1692 default:
1693 WARN("unknown compression type %d\n", comp);
1694 break;
1695 }
1696
1697 TRACE("%s -> %s %d\n", debugstr_w(source), debugstr_w(target), comp);
1698 return ret;
1699 }
1700
1701 /*
1702 * implemented (used by pSetupGuidFromString)
1703 */
1704 static BOOL TrimGuidString(PCWSTR szString, LPWSTR szNewString)
1705 {
1706 WCHAR szBuffer[39];
1707 INT Index;
1708
1709 if (wcslen(szString) == 38)
1710 {
1711 if ((szString[0] == L'{') && (szString[37] == L'}'))
1712 {
1713 for (Index = 0; Index < wcslen(szString); Index++)
1714 szBuffer[Index] = szString[Index + 1];
1715
1716 szBuffer[36] = L'\0';
1717 wcscpy(szNewString, szBuffer);
1718 return TRUE;
1719 }
1720 }
1721 szNewString[0] = L'\0';
1722 return FALSE;
1723 }
1724
1725 /*
1726 * implemented
1727 */
1728 DWORD
1729 WINAPI
1730 pSetupGuidFromString(PCWSTR pString, LPGUID lpGUID)
1731 {
1732 RPC_STATUS Status;
1733 WCHAR szBuffer[39];
1734
1735 if (!TrimGuidString(pString, szBuffer))
1736 {
1737 return RPC_S_INVALID_STRING_UUID;
1738 }
1739
1740 Status = UuidFromStringW(szBuffer, lpGUID);
1741 if (Status != RPC_S_OK)
1742 {
1743 return RPC_S_INVALID_STRING_UUID;
1744 }
1745
1746 return NO_ERROR;
1747 }
1748
1749 /*
1750 * implemented
1751 */
1752 DWORD
1753 WINAPI
1754 pSetupStringFromGuid(LPGUID lpGUID, PWSTR pString, DWORD dwStringLen)
1755 {
1756 RPC_STATUS Status;
1757 RPC_WSTR rpcBuffer;
1758 WCHAR szBuffer[39];
1759
1760 if (dwStringLen < 39)
1761 {
1762 return ERROR_INSUFFICIENT_BUFFER;
1763 }
1764
1765 Status = UuidToStringW(lpGUID, &rpcBuffer);
1766 if (Status != RPC_S_OK)
1767 {
1768 return Status;
1769 }
1770
1771 wcscpy(szBuffer, L"{");
1772 wcscat(szBuffer, rpcBuffer);
1773 wcscat(szBuffer, L"}");
1774
1775 wcscpy(pString, szBuffer);
1776
1777 RpcStringFreeW(&rpcBuffer);
1778 return NO_ERROR;
1779 }
1780
1781 /*
1782 * implemented
1783 */
1784 BOOL
1785 WINAPI
1786 pSetupIsGuidNull(LPGUID lpGUID)
1787 {
1788 return IsEqualGUID(lpGUID, &GUID_NULL);
1789 }
1790
1791 /*
1792 * implemented
1793 */
1794 BOOL
1795 WINAPI
1796 pSetupIsUserAdmin(VOID)
1797 {
1798 SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
1799 BOOL bResult = FALSE;
1800 PSID lpSid;
1801
1802 if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID,
1803 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
1804 &lpSid))
1805 {
1806 return FALSE;
1807 }
1808
1809 if (!CheckTokenMembership(NULL, lpSid, &bResult))
1810 {
1811 bResult = FALSE;
1812 }
1813
1814 FreeSid(lpSid);
1815
1816 return bResult;
1817 }
1818
1819 /***********************************************************************
1820 * SetupInitializeFileLogW(SETUPAPI.@)
1821 */
1822 HSPFILELOG WINAPI SetupInitializeFileLogW(LPCWSTR LogFileName, DWORD Flags)
1823 {
1824 struct FileLog * Log;
1825 HANDLE hLog;
1826 WCHAR Windir[MAX_PATH];
1827 DWORD ret;
1828
1829 TRACE("%s, 0x%x\n",debugstr_w(LogFileName),Flags);
1830
1831 if (Flags & SPFILELOG_SYSTEMLOG)
1832 {
1833 if (!pSetupIsUserAdmin() && !(Flags & SPFILELOG_QUERYONLY))
1834 {
1835 /* insufficient privileges */
1836 SetLastError(ERROR_ACCESS_DENIED);
1837 return INVALID_HANDLE_VALUE;
1838 }
1839
1840 if (LogFileName || (Flags & SPFILELOG_FORCENEW))
1841 {
1842 /* invalid parameter */
1843 SetLastError(ERROR_INVALID_PARAMETER);
1844 return INVALID_HANDLE_VALUE;
1845 }
1846
1847 ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
1848 if (!ret || ret >= MAX_PATH)
1849 {
1850 /* generic failure */
1851 return INVALID_HANDLE_VALUE;
1852 }
1853
1854 /* append path */
1855 wcscat(Windir, L"repair\\setup.log");
1856 }
1857 else
1858 {
1859 if (!LogFileName)
1860 {
1861 /* invalid parameter */
1862 SetLastError(ERROR_INVALID_PARAMETER);
1863 return INVALID_HANDLE_VALUE;
1864 }
1865 /* copy filename */
1866 wcsncpy(Windir, LogFileName, MAX_PATH);
1867 }
1868
1869 if (FileExists(Windir, NULL))
1870 {
1871 /* take ownership */
1872 ret = TakeOwnershipOfFile(Windir);
1873
1874 if (ret != ERROR_SUCCESS)
1875 {
1876 /* failed */
1877 SetLastError(ret);
1878 return INVALID_HANDLE_VALUE;
1879 }
1880
1881 if (!SetFileAttributesW(Windir, FILE_ATTRIBUTE_NORMAL))
1882 {
1883 /* failed */
1884 return INVALID_HANDLE_VALUE;
1885 }
1886
1887 if ((Flags & SPFILELOG_FORCENEW))
1888 {
1889 if (!DeleteFileW(Windir))
1890 {
1891 /* failed */
1892 return INVALID_HANDLE_VALUE;
1893 }
1894 }
1895 }
1896
1897 /* open log file */
1898 hLog = CreateFileW(Windir,
1899 (Flags & SPFILELOG_QUERYONLY) ? GENERIC_READ : GENERIC_WRITE,
1900 FILE_SHARE_READ | FILE_SHARE_WRITE,
1901 NULL,
1902 OPEN_ALWAYS,
1903 FILE_ATTRIBUTE_NORMAL,
1904 NULL);
1905
1906 if (hLog == INVALID_HANDLE_VALUE)
1907 {
1908 /* failed */
1909 return INVALID_HANDLE_VALUE;
1910 }
1911
1912 /* close log handle */
1913 CloseHandle(hLog);
1914
1915 /* allocate file log struct */
1916 Log = HeapAlloc(GetProcessHeap(), 0, sizeof(struct FileLog));
1917 if (!Log)
1918 {
1919 /* not enough memory */
1920 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1921 return INVALID_HANDLE_VALUE;
1922 }
1923
1924 /* initialize log */
1925 Log->LogName = HeapAlloc(GetProcessHeap(), 0, (wcslen(Windir)+1) * sizeof(WCHAR));
1926 if (!Log->LogName)
1927 {
1928 /* not enough memory */
1929 HeapFree(GetProcessHeap(), 0, Log);
1930 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1931 return INVALID_HANDLE_VALUE;
1932 }
1933
1934 wcscpy(Log->LogName, Windir);
1935 Log->ReadOnly = (Flags & SPFILELOG_QUERYONLY);
1936 Log->SystemLog = (Flags & SPFILELOG_SYSTEMLOG);
1937
1938 return (HSPFILELOG)Log;
1939 }
1940
1941 /***********************************************************************
1942 * SetupInitializeFileLogA(SETUPAPI.@)
1943 */
1944 HSPFILELOG WINAPI SetupInitializeFileLogA(LPCSTR LogFileName, DWORD Flags)
1945 {
1946 HSPFILELOG hLog;
1947 LPWSTR LogFileNameW = NULL;
1948
1949 TRACE("%s, 0x%x\n",debugstr_a(LogFileName),Flags);
1950
1951 if (LogFileName)
1952 {
1953 LogFileNameW = strdupAtoW(LogFileName);
1954
1955 if (!LogFileNameW)
1956 {
1957 /* not enough memory */
1958 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1959 return INVALID_HANDLE_VALUE;
1960 }
1961
1962 hLog = SetupInitializeFileLogW(LogFileNameW, Flags);
1963 HeapFree(GetProcessHeap(), 0, LogFileNameW);
1964 }
1965 else
1966 {
1967 hLog = SetupInitializeFileLogW(NULL, Flags);
1968 }
1969
1970 return hLog;
1971 }
1972
1973 /***********************************************************************
1974 * SetupTerminateFileLog(SETUPAPI.@)
1975 */
1976 BOOL WINAPI SetupTerminateFileLog(HANDLE FileLogHandle)
1977 {
1978 struct FileLog * Log;
1979
1980 TRACE ("%p\n",FileLogHandle);
1981
1982 Log = (struct FileLog *)FileLogHandle;
1983
1984 /* free file log handle */
1985 HeapFree(GetProcessHeap(), 0, Log->LogName);
1986 HeapFree(GetProcessHeap(), 0, Log);
1987
1988 SetLastError(ERROR_SUCCESS);
1989
1990 return TRUE;
1991 }
1992
1993 /***********************************************************************
1994 * SetupCloseLog(SETUPAPI.@)
1995 */
1996 void WINAPI SetupCloseLog(void)
1997 {
1998 EnterCriticalSection(&setupapi_cs);
1999
2000 CloseHandle(setupact);
2001 setupact = INVALID_HANDLE_VALUE;
2002
2003 CloseHandle(setuperr);
2004 setuperr = INVALID_HANDLE_VALUE;
2005
2006 LeaveCriticalSection(&setupapi_cs);
2007 }
2008
2009 /***********************************************************************
2010 * SetupOpenLog(SETUPAPI.@)
2011 */
2012 BOOL WINAPI SetupOpenLog(BOOL reserved)
2013 {
2014 WCHAR path[MAX_PATH];
2015
2016 static const WCHAR setupactlog[] = {'\\','s','e','t','u','p','a','c','t','.','l','o','g',0};
2017 static const WCHAR setuperrlog[] = {'\\','s','e','t','u','p','e','r','r','.','l','o','g',0};
2018
2019 EnterCriticalSection(&setupapi_cs);
2020
2021 if (setupact != INVALID_HANDLE_VALUE && setuperr != INVALID_HANDLE_VALUE)
2022 {
2023 LeaveCriticalSection(&setupapi_cs);
2024 return TRUE;
2025 }
2026
2027 GetWindowsDirectoryW(path, MAX_PATH);
2028 lstrcatW(path, setupactlog);
2029
2030 setupact = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
2031 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2032 if (setupact == INVALID_HANDLE_VALUE)
2033 {
2034 LeaveCriticalSection(&setupapi_cs);
2035 return FALSE;
2036 }
2037
2038 SetFilePointer(setupact, 0, NULL, FILE_END);
2039
2040 GetWindowsDirectoryW(path, MAX_PATH);
2041 lstrcatW(path, setuperrlog);
2042
2043 setuperr = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
2044 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2045 if (setuperr == INVALID_HANDLE_VALUE)
2046 {
2047 CloseHandle(setupact);
2048 setupact = INVALID_HANDLE_VALUE;
2049 LeaveCriticalSection(&setupapi_cs);
2050 return FALSE;
2051 }
2052
2053 SetFilePointer(setuperr, 0, NULL, FILE_END);
2054
2055 LeaveCriticalSection(&setupapi_cs);
2056
2057 return TRUE;
2058 }
2059
2060 /***********************************************************************
2061 * SetupLogErrorA(SETUPAPI.@)
2062 */
2063 BOOL WINAPI SetupLogErrorA(LPCSTR message, LogSeverity severity)
2064 {
2065 static const char null[] = "(null)";
2066 BOOL ret;
2067 DWORD written;
2068 DWORD len;
2069
2070 EnterCriticalSection(&setupapi_cs);
2071
2072 if (setupact == INVALID_HANDLE_VALUE || setuperr == INVALID_HANDLE_VALUE)
2073 {
2074 SetLastError(ERROR_FILE_INVALID);
2075 ret = FALSE;
2076 goto done;
2077 }
2078
2079 if (message == NULL)
2080 message = null;
2081
2082 len = lstrlenA(message);
2083
2084 ret = WriteFile(setupact, message, len, &written, NULL);
2085 if (!ret)
2086 goto done;
2087
2088 if (severity >= LogSevMaximum)
2089 {
2090 ret = FALSE;
2091 goto done;
2092 }
2093
2094 if (severity > LogSevInformation)
2095 ret = WriteFile(setuperr, message, len, &written, NULL);
2096
2097 done:
2098 LeaveCriticalSection(&setupapi_cs);
2099 return ret;
2100 }
2101
2102 /***********************************************************************
2103 * SetupLogErrorW(SETUPAPI.@)
2104 */
2105 BOOL WINAPI SetupLogErrorW(LPCWSTR message, LogSeverity severity)
2106 {
2107 LPSTR msg = NULL;
2108 DWORD len;
2109 BOOL ret;
2110
2111 if (message)
2112 {
2113 len = WideCharToMultiByte(CP_ACP, 0, message, -1, NULL, 0, NULL, NULL);
2114 msg = HeapAlloc(GetProcessHeap(), 0, len);
2115 if (msg == NULL)
2116 {
2117 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2118 return FALSE;
2119 }
2120 WideCharToMultiByte(CP_ACP, 0, message, -1, msg, len, NULL, NULL);
2121 }
2122
2123 /* This is the normal way to proceed. The log files are ASCII files
2124 * and W is to be converted.
2125 */
2126 ret = SetupLogErrorA(msg, severity);
2127
2128 HeapFree(GetProcessHeap(), 0, msg);
2129 return ret;
2130 }