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