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