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