[setupapi]
[reactos.git] / reactos / dll / win32 / setupapi / misc.c
1 /*
2 * Setupapi miscellaneous functions
3 *
4 * Copyright 2005 Eric Kohl
5 * Copyright 2007 Hans Leidekker
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "setupapi_private.h"
23
24 #include <winver.h>
25 #include <lzexpand.h>
26
27 /* Unicode constants */
28 static const WCHAR BackSlash[] = {'\\',0};
29 static const WCHAR TranslationRegKey[] = {'\\','V','e','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n',0};
30
31 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 /***********************************************************************
1221 * pSetupInstallCatalog (SETUPAPI.@)
1222 */
1223 DWORD WINAPI pSetupInstallCatalog( LPCWSTR catalog, LPCWSTR basename, LPWSTR fullname )
1224 {
1225 HCATADMIN admin;
1226 HCATINFO cat;
1227
1228 TRACE ("%s, %s, %p\n", debugstr_w(catalog), debugstr_w(basename), fullname);
1229
1230 if (!CryptCATAdminAcquireContext(&admin,NULL,0))
1231 return GetLastError();
1232
1233 if (!(cat = CryptCATAdminAddCatalog( admin, (PWSTR)catalog, (PWSTR)basename, 0 )))
1234 {
1235 DWORD rc = GetLastError();
1236 CryptCATAdminReleaseContext(admin, 0);
1237 return rc;
1238 }
1239 CryptCATAdminReleaseCatalogContext(admin, cat, 0);
1240 CryptCATAdminReleaseContext(admin,0);
1241
1242 if (fullname)
1243 FIXME("not returning full installed catalog path\n");
1244
1245 return NO_ERROR;
1246 }
1247
1248 static UINT detect_compression_type( LPCWSTR file )
1249 {
1250 DWORD size;
1251 HANDLE handle;
1252 UINT type = FILE_COMPRESSION_NONE;
1253 static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1254 static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1255 static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1256 BYTE buffer[8];
1257
1258 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1259 if (handle == INVALID_HANDLE_VALUE)
1260 {
1261 ERR("cannot open file %s\n", debugstr_w(file));
1262 return FILE_COMPRESSION_NONE;
1263 }
1264 if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1265 {
1266 CloseHandle( handle );
1267 return FILE_COMPRESSION_NONE;
1268 }
1269 if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1270 else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1271 else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1272
1273 CloseHandle( handle );
1274 return type;
1275 }
1276
1277 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1278 {
1279 HANDLE handle;
1280
1281 handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1282 if (handle == INVALID_HANDLE_VALUE)
1283 {
1284 ERR("cannot open file %s\n", debugstr_w(file));
1285 return FALSE;
1286 }
1287 *size = GetFileSize( handle, NULL );
1288 CloseHandle( handle );
1289 return TRUE;
1290 }
1291
1292 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1293 {
1294 DWORD size;
1295
1296 if (!get_file_size( source, &size )) return FALSE;
1297 if (source_size) *source_size = size;
1298 if (target_size) *target_size = size;
1299 return TRUE;
1300 }
1301
1302 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1303 {
1304 DWORD size;
1305 BOOL ret = TRUE;
1306
1307 if (source_size)
1308 {
1309 if (!get_file_size( source, &size )) ret = FALSE;
1310 else *source_size = size;
1311 }
1312 if (target_size)
1313 {
1314 INT file;
1315 OFSTRUCT of;
1316
1317 if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1318 {
1319 ERR("cannot open source file for reading\n");
1320 return FALSE;
1321 }
1322 *target_size = LZSeek( file, 0, 2 );
1323 LZClose( file );
1324 }
1325 return ret;
1326 }
1327
1328 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1329 {
1330 DWORD *size = context;
1331 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1332
1333 switch (notification)
1334 {
1335 case SPFILENOTIFY_FILEINCABINET:
1336 {
1337 *size = info->FileSize;
1338 return FILEOP_SKIP;
1339 }
1340 default: return NO_ERROR;
1341 }
1342 }
1343
1344 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1345 {
1346 DWORD size;
1347 BOOL ret = TRUE;
1348
1349 if (source_size)
1350 {
1351 if (!get_file_size( source, &size )) ret = FALSE;
1352 else *source_size = size;
1353 }
1354 if (target_size)
1355 {
1356 ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1357 }
1358 return ret;
1359 }
1360
1361 /***********************************************************************
1362 * SetupGetFileCompressionInfoExA (SETUPAPI.@)
1363 *
1364 * See SetupGetFileCompressionInfoExW.
1365 */
1366 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1367 PDWORD source_size, PDWORD target_size, PUINT type )
1368 {
1369 BOOL ret;
1370 WCHAR *nameW = NULL, *sourceW = NULL;
1371 DWORD nb_chars = 0;
1372 LPSTR nameA;
1373
1374 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1375 source_size, target_size, type);
1376
1377 if (!source || !(sourceW = pSetupMultiByteToUnicode( source, CP_ACP ))) return FALSE;
1378
1379 if (name)
1380 {
1381 ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1382 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, nb_chars * sizeof(WCHAR) )))
1383 {
1384 MyFree( sourceW );
1385 return FALSE;
1386 }
1387 }
1388 ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1389 if (ret)
1390 {
1391 if ((nameA = pSetupUnicodeToMultiByte( nameW, CP_ACP )))
1392 {
1393 if (name && len >= nb_chars) lstrcpyA( name, nameA );
1394 else
1395 {
1396 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1397 ret = FALSE;
1398 }
1399 MyFree( nameA );
1400 }
1401 }
1402 if (required) *required = nb_chars;
1403 HeapFree( GetProcessHeap(), 0, nameW );
1404 MyFree( sourceW );
1405
1406 return ret;
1407 }
1408
1409 /***********************************************************************
1410 * SetupGetFileCompressionInfoExW (SETUPAPI.@)
1411 *
1412 * Get compression type and compressed/uncompressed sizes of a given file.
1413 *
1414 * PARAMS
1415 * source [I] File to examine.
1416 * name [O] Actual filename used.
1417 * len [I] Length in characters of 'name' buffer.
1418 * required [O] Number of characters written to 'name'.
1419 * source_size [O] Size of compressed file.
1420 * target_size [O] Size of uncompressed file.
1421 * type [O] Compression type.
1422 *
1423 * RETURNS
1424 * Success: TRUE
1425 * Failure: FALSE
1426 */
1427 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1428 PDWORD source_size, PDWORD target_size, PUINT type )
1429 {
1430 UINT comp;
1431 BOOL ret = FALSE;
1432 DWORD source_len;
1433
1434 TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1435 source_size, target_size, type);
1436
1437 if (!source) return FALSE;
1438
1439 source_len = lstrlenW( source ) + 1;
1440 if (required) *required = source_len;
1441 if (name && len >= source_len)
1442 {
1443 lstrcpyW( name, source );
1444 ret = TRUE;
1445 }
1446 else return FALSE;
1447
1448 comp = detect_compression_type( source );
1449 if (type) *type = comp;
1450
1451 switch (comp)
1452 {
1453 case FILE_COMPRESSION_MSZIP:
1454 case FILE_COMPRESSION_NTCAB: ret = get_file_sizes_cab( source, source_size, target_size ); break;
1455 case FILE_COMPRESSION_NONE: ret = get_file_sizes_none( source, source_size, target_size ); break;
1456 case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1457 default: break;
1458 }
1459 return ret;
1460 }
1461
1462 /***********************************************************************
1463 * SetupGetFileCompressionInfoA (SETUPAPI.@)
1464 *
1465 * See SetupGetFileCompressionInfoW.
1466 */
1467 DWORD WINAPI SetupGetFileCompressionInfoA( PCSTR source, PSTR *name, PDWORD source_size,
1468 PDWORD target_size, PUINT type )
1469 {
1470 BOOL ret;
1471 DWORD error, required;
1472 LPSTR actual_name;
1473
1474 TRACE("%s, %p, %p, %p, %p\n", debugstr_a(source), name, source_size, target_size, type);
1475
1476 if (!source || !name || !source_size || !target_size || !type)
1477 return ERROR_INVALID_PARAMETER;
1478
1479 ret = SetupGetFileCompressionInfoExA( source, NULL, 0, &required, NULL, NULL, NULL );
1480 if (!(actual_name = MyMalloc( required ))) return ERROR_NOT_ENOUGH_MEMORY;
1481
1482 ret = SetupGetFileCompressionInfoExA( source, actual_name, required, &required,
1483 source_size, target_size, type );
1484 if (!ret)
1485 {
1486 error = GetLastError();
1487 MyFree( actual_name );
1488 return error;
1489 }
1490 *name = actual_name;
1491 return ERROR_SUCCESS;
1492 }
1493
1494 /***********************************************************************
1495 * SetupGetFileCompressionInfoW (SETUPAPI.@)
1496 *
1497 * Get compression type and compressed/uncompressed sizes of a given file.
1498 *
1499 * PARAMS
1500 * source [I] File to examine.
1501 * name [O] Actual filename used.
1502 * source_size [O] Size of compressed file.
1503 * target_size [O] Size of uncompressed file.
1504 * type [O] Compression type.
1505 *
1506 * RETURNS
1507 * Success: ERROR_SUCCESS
1508 * Failure: Win32 error code.
1509 */
1510 DWORD WINAPI SetupGetFileCompressionInfoW( PCWSTR source, PWSTR *name, PDWORD source_size,
1511 PDWORD target_size, PUINT type )
1512 {
1513 BOOL ret;
1514 DWORD error, required;
1515 LPWSTR actual_name;
1516
1517 TRACE("%s, %p, %p, %p, %p\n", debugstr_w(source), name, source_size, target_size, type);
1518
1519 if (!source || !name || !source_size || !target_size || !type)
1520 return ERROR_INVALID_PARAMETER;
1521
1522 ret = SetupGetFileCompressionInfoExW( source, NULL, 0, &required, NULL, NULL, NULL );
1523 if (!(actual_name = MyMalloc( required*sizeof(WCHAR) ))) return ERROR_NOT_ENOUGH_MEMORY;
1524
1525 ret = SetupGetFileCompressionInfoExW( source, actual_name, required, &required,
1526 source_size, target_size, type );
1527 if (!ret)
1528 {
1529 error = GetLastError();
1530 MyFree( actual_name );
1531 return error;
1532 }
1533 *name = actual_name;
1534 return ERROR_SUCCESS;
1535 }
1536
1537 static DWORD decompress_file_lz( LPCWSTR source, LPCWSTR target )
1538 {
1539 DWORD ret;
1540 LONG error;
1541 INT src, dst;
1542 OFSTRUCT sof, dof;
1543
1544 if ((src = LZOpenFileW( (LPWSTR)source, &sof, OF_READ )) < 0)
1545 {
1546 ERR("cannot open source file for reading\n");
1547 return ERROR_FILE_NOT_FOUND;
1548 }
1549 if ((dst = LZOpenFileW( (LPWSTR)target, &dof, OF_CREATE )) < 0)
1550 {
1551 ERR("cannot open target file for writing\n");
1552 LZClose( src );
1553 return ERROR_FILE_NOT_FOUND;
1554 }
1555 if ((error = LZCopy( src, dst )) >= 0) ret = ERROR_SUCCESS;
1556 else
1557 {
1558 WARN("failed to decompress file %d\n", error);
1559 ret = ERROR_INVALID_DATA;
1560 }
1561
1562 LZClose( src );
1563 LZClose( dst );
1564 return ret;
1565 }
1566
1567 struct callback_context
1568 {
1569 BOOL has_extracted;
1570 LPCWSTR target;
1571 };
1572
1573 static UINT CALLBACK decompress_or_copy_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1574 {
1575 struct callback_context *context_info = context;
1576 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1577
1578 switch (notification)
1579 {
1580 case SPFILENOTIFY_FILEINCABINET:
1581 {
1582 if (context_info->has_extracted)
1583 return FILEOP_ABORT;
1584
1585 TRACE("Requesting extraction of cabinet file %s\n",
1586 wine_dbgstr_w(info->NameInCabinet));
1587 strcpyW( info->FullTargetName, context_info->target );
1588 context_info->has_extracted = TRUE;
1589 return FILEOP_DOIT;
1590 }
1591 default: return NO_ERROR;
1592 }
1593 }
1594
1595 static DWORD decompress_file_cab( LPCWSTR source, LPCWSTR target )
1596 {
1597 struct callback_context context = {0, target};
1598 BOOL ret;
1599
1600 ret = SetupIterateCabinetW( source, 0, decompress_or_copy_callback, &context );
1601
1602 if (ret) return ERROR_SUCCESS;
1603 else return GetLastError();
1604 }
1605
1606 /***********************************************************************
1607 * SetupDecompressOrCopyFileA (SETUPAPI.@)
1608 *
1609 * See SetupDecompressOrCopyFileW.
1610 */
1611 DWORD WINAPI SetupDecompressOrCopyFileA( PCSTR source, PCSTR target, PUINT type )
1612 {
1613 DWORD ret = 0;
1614 WCHAR *sourceW = NULL, *targetW = NULL;
1615
1616 if (source && !(sourceW = pSetupMultiByteToUnicode( source, CP_ACP ))) return FALSE;
1617 if (target && !(targetW = pSetupMultiByteToUnicode( target, CP_ACP )))
1618 {
1619 MyFree( sourceW );
1620 return ERROR_NOT_ENOUGH_MEMORY;
1621 }
1622
1623 ret = SetupDecompressOrCopyFileW( sourceW, targetW, type );
1624
1625 MyFree( sourceW );
1626 MyFree( targetW );
1627
1628 return ret;
1629 }
1630
1631 /***********************************************************************
1632 * SetupDecompressOrCopyFileW (SETUPAPI.@)
1633 *
1634 * Copy a file and decompress it if needed.
1635 *
1636 * PARAMS
1637 * source [I] File to copy.
1638 * target [I] Filename of the copy.
1639 * type [I] Compression type.
1640 *
1641 * RETURNS
1642 * Success: ERROR_SUCCESS
1643 * Failure: Win32 error code.
1644 */
1645 DWORD WINAPI SetupDecompressOrCopyFileW( PCWSTR source, PCWSTR target, PUINT type )
1646 {
1647 UINT comp;
1648 DWORD ret = ERROR_INVALID_PARAMETER;
1649
1650 if (!source || !target) return ERROR_INVALID_PARAMETER;
1651
1652 if (!type) comp = detect_compression_type( source );
1653 else comp = *type;
1654
1655 switch (comp)
1656 {
1657 case FILE_COMPRESSION_NONE:
1658 if (CopyFileW( source, target, FALSE )) ret = ERROR_SUCCESS;
1659 else ret = GetLastError();
1660 break;
1661 case FILE_COMPRESSION_WINLZA:
1662 ret = decompress_file_lz( source, target );
1663 break;
1664 case FILE_COMPRESSION_NTCAB:
1665 case FILE_COMPRESSION_MSZIP:
1666 ret = decompress_file_cab( source, target );
1667 break;
1668 default:
1669 WARN("unknown compression type %d\n", comp);
1670 break;
1671 }
1672
1673 TRACE("%s -> %s %d\n", debugstr_w(source), debugstr_w(target), comp);
1674 return ret;
1675 }
1676
1677 /*
1678 * implemented (used by pSetupGuidFromString)
1679 */
1680 static BOOL TrimGuidString(PCWSTR szString, LPWSTR szNewString)
1681 {
1682 WCHAR szBuffer[39];
1683 INT Index;
1684
1685 if (wcslen(szString) == 38)
1686 {
1687 if ((szString[0] == L'{') && (szString[37] == L'}'))
1688 {
1689 for (Index = 0; Index < wcslen(szString); Index++)
1690 szBuffer[Index] = szString[Index + 1];
1691
1692 szBuffer[36] = L'\0';
1693 wcscpy(szNewString, szBuffer);
1694 return TRUE;
1695 }
1696 }
1697 szNewString[0] = L'\0';
1698 return FALSE;
1699 }
1700
1701 /*
1702 * implemented
1703 */
1704 DWORD
1705 WINAPI
1706 pSetupGuidFromString(PCWSTR pString, LPGUID lpGUID)
1707 {
1708 RPC_STATUS Status;
1709 WCHAR szBuffer[39];
1710
1711 if (!TrimGuidString(pString, szBuffer))
1712 {
1713 return RPC_S_INVALID_STRING_UUID;
1714 }
1715
1716 Status = UuidFromStringW(szBuffer, lpGUID);
1717 if (Status != RPC_S_OK)
1718 {
1719 return RPC_S_INVALID_STRING_UUID;
1720 }
1721
1722 return NO_ERROR;
1723 }
1724
1725 /*
1726 * implemented
1727 */
1728 DWORD
1729 WINAPI
1730 pSetupStringFromGuid(LPGUID lpGUID, PWSTR pString, DWORD dwStringLen)
1731 {
1732 RPC_STATUS Status;
1733 RPC_WSTR rpcBuffer;
1734 WCHAR szBuffer[39];
1735
1736 if (dwStringLen < 39)
1737 {
1738 return ERROR_INSUFFICIENT_BUFFER;
1739 }
1740
1741 Status = UuidToStringW(lpGUID, &rpcBuffer);
1742 if (Status != RPC_S_OK)
1743 {
1744 return Status;
1745 }
1746
1747 wcscpy(szBuffer, L"{");
1748 wcscat(szBuffer, rpcBuffer);
1749 wcscat(szBuffer, L"}");
1750
1751 wcscpy(pString, szBuffer);
1752
1753 RpcStringFreeW(&rpcBuffer);
1754 return NO_ERROR;
1755 }
1756
1757 /*
1758 * implemented
1759 */
1760 BOOL
1761 WINAPI
1762 pSetupIsGuidNull(LPGUID lpGUID)
1763 {
1764 return IsEqualGUID(lpGUID, &GUID_NULL);
1765 }
1766
1767 /*
1768 * implemented
1769 */
1770 BOOL
1771 WINAPI
1772 pSetupIsUserAdmin(VOID)
1773 {
1774 SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
1775 BOOL bResult = FALSE;
1776 PSID lpSid;
1777
1778 if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID,
1779 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
1780 &lpSid))
1781 {
1782 return FALSE;
1783 }
1784
1785 if (!CheckTokenMembership(NULL, lpSid, &bResult))
1786 {
1787 bResult = FALSE;
1788 }
1789
1790 FreeSid(lpSid);
1791
1792 return bResult;
1793 }
1794
1795 /***********************************************************************
1796 * SetupInitializeFileLogW(SETUPAPI.@)
1797 */
1798 HSPFILELOG WINAPI SetupInitializeFileLogW(LPCWSTR LogFileName, DWORD Flags)
1799 {
1800 struct FileLog * Log;
1801 HANDLE hLog;
1802 WCHAR Windir[MAX_PATH];
1803 DWORD ret;
1804
1805 TRACE("%s, 0x%x\n",debugstr_w(LogFileName),Flags);
1806
1807 if (Flags & SPFILELOG_SYSTEMLOG)
1808 {
1809 if (!pSetupIsUserAdmin() && !(Flags & SPFILELOG_QUERYONLY))
1810 {
1811 /* insufficient privileges */
1812 SetLastError(ERROR_ACCESS_DENIED);
1813 return INVALID_HANDLE_VALUE;
1814 }
1815
1816 if (LogFileName || (Flags & SPFILELOG_FORCENEW))
1817 {
1818 /* invalid parameter */
1819 SetLastError(ERROR_INVALID_PARAMETER);
1820 return INVALID_HANDLE_VALUE;
1821 }
1822
1823 ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
1824 if (!ret || ret >= MAX_PATH)
1825 {
1826 /* generic failure */
1827 return INVALID_HANDLE_VALUE;
1828 }
1829
1830 /* append path */
1831 wcscat(Windir, L"repair\\setup.log");
1832 }
1833 else
1834 {
1835 if (!LogFileName)
1836 {
1837 /* invalid parameter */
1838 SetLastError(ERROR_INVALID_PARAMETER);
1839 return INVALID_HANDLE_VALUE;
1840 }
1841 /* copy filename */
1842 wcsncpy(Windir, LogFileName, MAX_PATH);
1843 }
1844
1845 if (FileExists(Windir, NULL))
1846 {
1847 /* take ownership */
1848 ret = TakeOwnershipOfFile(Windir);
1849
1850 if (ret != ERROR_SUCCESS)
1851 {
1852 /* failed */
1853 SetLastError(ret);
1854 return INVALID_HANDLE_VALUE;
1855 }
1856
1857 if (!SetFileAttributesW(Windir, FILE_ATTRIBUTE_NORMAL))
1858 {
1859 /* failed */
1860 return INVALID_HANDLE_VALUE;
1861 }
1862
1863 if ((Flags & SPFILELOG_FORCENEW))
1864 {
1865 if (!DeleteFileW(Windir))
1866 {
1867 /* failed */
1868 return INVALID_HANDLE_VALUE;
1869 }
1870 }
1871 }
1872
1873 /* open log file */
1874 hLog = CreateFileW(Windir,
1875 (Flags & SPFILELOG_QUERYONLY) ? GENERIC_READ : GENERIC_WRITE,
1876 FILE_SHARE_READ | FILE_SHARE_WRITE,
1877 NULL,
1878 OPEN_ALWAYS,
1879 FILE_ATTRIBUTE_NORMAL,
1880 NULL);
1881
1882 if (hLog == INVALID_HANDLE_VALUE)
1883 {
1884 /* failed */
1885 return INVALID_HANDLE_VALUE;
1886 }
1887
1888 /* close log handle */
1889 CloseHandle(hLog);
1890
1891 /* allocate file log struct */
1892 Log = HeapAlloc(GetProcessHeap(), 0, sizeof(struct FileLog));
1893 if (!Log)
1894 {
1895 /* not enough memory */
1896 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1897 return INVALID_HANDLE_VALUE;
1898 }
1899
1900 /* initialize log */
1901 Log->LogName = HeapAlloc(GetProcessHeap(), 0, (wcslen(Windir)+1) * sizeof(WCHAR));
1902 if (!Log->LogName)
1903 {
1904 /* not enough memory */
1905 HeapFree(GetProcessHeap(), 0, Log);
1906 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1907 return INVALID_HANDLE_VALUE;
1908 }
1909
1910 wcscpy(Log->LogName, Windir);
1911 Log->ReadOnly = (Flags & SPFILELOG_QUERYONLY);
1912 Log->SystemLog = (Flags & SPFILELOG_SYSTEMLOG);
1913
1914 return (HSPFILELOG)Log;
1915 }
1916
1917 /***********************************************************************
1918 * SetupInitializeFileLogA(SETUPAPI.@)
1919 */
1920 HSPFILELOG WINAPI SetupInitializeFileLogA(LPCSTR LogFileName, DWORD Flags)
1921 {
1922 HSPFILELOG hLog;
1923 LPWSTR LogFileNameW = NULL;
1924
1925 TRACE("%s, 0x%x\n",debugstr_a(LogFileName),Flags);
1926
1927 if (LogFileName)
1928 {
1929 LogFileNameW = strdupAtoW(LogFileName);
1930
1931 if (!LogFileNameW)
1932 {
1933 /* not enough memory */
1934 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1935 return INVALID_HANDLE_VALUE;
1936 }
1937
1938 hLog = SetupInitializeFileLogW(LogFileNameW, Flags);
1939 HeapFree(GetProcessHeap(), 0, LogFileNameW);
1940 }
1941 else
1942 {
1943 hLog = SetupInitializeFileLogW(NULL, Flags);
1944 }
1945
1946 return hLog;
1947 }
1948
1949 /***********************************************************************
1950 * SetupTerminateFileLog(SETUPAPI.@)
1951 */
1952 BOOL WINAPI SetupTerminateFileLog(HANDLE FileLogHandle)
1953 {
1954 struct FileLog * Log;
1955
1956 TRACE ("%p\n",FileLogHandle);
1957
1958 Log = (struct FileLog *)FileLogHandle;
1959
1960 /* free file log handle */
1961 HeapFree(GetProcessHeap(), 0, Log->LogName);
1962 HeapFree(GetProcessHeap(), 0, Log);
1963
1964 SetLastError(ERROR_SUCCESS);
1965
1966 return TRUE;
1967 }