setupapi: Implement SetupGetFileCompressionInfoEx{A, W}.
[wine] / dlls / 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 <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "setupapi.h"
30 #include "lzexpand.h"
31
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34
35 #include "setupapi_private.h"
36
37
38 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
39
40
41 /**************************************************************************
42  * MyFree [SETUPAPI.@]
43  *
44  * Frees an allocated memory block from the process heap.
45  *
46  * PARAMS
47  *     lpMem [I] pointer to memory block which will be freed
48  *
49  * RETURNS
50  *     None
51  */
52 VOID WINAPI MyFree(LPVOID lpMem)
53 {
54     TRACE("%p\n", lpMem);
55     HeapFree(GetProcessHeap(), 0, lpMem);
56 }
57
58
59 /**************************************************************************
60  * MyMalloc [SETUPAPI.@]
61  *
62  * Allocates memory block from the process heap.
63  *
64  * PARAMS
65  *     dwSize [I] size of the allocated memory block
66  *
67  * RETURNS
68  *     Success: pointer to allocated memory block
69  *     Failure: NULL
70  */
71 LPVOID WINAPI MyMalloc(DWORD dwSize)
72 {
73     TRACE("%u\n", dwSize);
74     return HeapAlloc(GetProcessHeap(), 0, dwSize);
75 }
76
77
78 /**************************************************************************
79  * MyRealloc [SETUPAPI.@]
80  *
81  * Changes the size of an allocated memory block or allocates a memory
82  * block from the process heap.
83  *
84  * PARAMS
85  *     lpSrc  [I] pointer to memory block which will be resized
86  *     dwSize [I] new size of the memory block
87  *
88  * RETURNS
89  *     Success: pointer to the resized memory block
90  *     Failure: NULL
91  *
92  * NOTES
93  *     If lpSrc is a NULL-pointer, then MyRealloc allocates a memory
94  *     block like MyMalloc.
95  */
96 LPVOID WINAPI MyRealloc(LPVOID lpSrc, DWORD dwSize)
97 {
98     TRACE("%p %u\n", lpSrc, dwSize);
99
100     if (lpSrc == NULL)
101         return HeapAlloc(GetProcessHeap(), 0, dwSize);
102
103     return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize);
104 }
105
106
107 /**************************************************************************
108  * DuplicateString [SETUPAPI.@]
109  *
110  * Duplicates a unicode string.
111  *
112  * PARAMS
113  *     lpSrc  [I] pointer to the unicode string that will be duplicated
114  *
115  * RETURNS
116  *     Success: pointer to the duplicated unicode string
117  *     Failure: NULL
118  *
119  * NOTES
120  *     Call MyFree() to release the duplicated string.
121  */
122 LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc)
123 {
124     LPWSTR lpDst;
125
126     TRACE("%s\n", debugstr_w(lpSrc));
127
128     lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));
129     if (lpDst == NULL)
130         return NULL;
131
132     strcpyW(lpDst, lpSrc);
133
134     return lpDst;
135 }
136
137
138 /**************************************************************************
139  * QueryRegistryValue [SETUPAPI.@]
140  *
141  * Retrieves value data from the registry and allocates memory for the
142  * value data.
143  *
144  * PARAMS
145  *     hKey        [I] Handle of the key to query
146  *     lpValueName [I] Name of value under hkey to query
147  *     lpData      [O] Destination for the values contents,
148  *     lpType      [O] Destination for the value type
149  *     lpcbData    [O] Destination for the size of data
150  *
151  * RETURNS
152  *     Success: ERROR_SUCCESS
153  *     Failure: Otherwise
154  *
155  * NOTES
156  *     Use MyFree to release the lpData buffer.
157  */
158 LONG WINAPI QueryRegistryValue(HKEY hKey,
159                                LPCWSTR lpValueName,
160                                LPBYTE  *lpData,
161                                LPDWORD lpType,
162                                LPDWORD lpcbData)
163 {
164     LONG lError;
165
166     TRACE("%p %s %p %p %p\n",
167           hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);
168
169     /* Get required buffer size */
170     *lpcbData = 0;
171     lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);
172     if (lError != ERROR_SUCCESS)
173         return lError;
174
175     /* Allocate buffer */
176     *lpData = MyMalloc(*lpcbData);
177     if (*lpData == NULL)
178         return ERROR_NOT_ENOUGH_MEMORY;
179
180     /* Query registry value */
181     lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);
182     if (lError != ERROR_SUCCESS)
183         MyFree(*lpData);
184
185     return lError;
186 }
187
188
189 /**************************************************************************
190  * IsUserAdmin [SETUPAPI.@]
191  *
192  * Checks whether the current user is a member of the Administrators group.
193  *
194  * PARAMS
195  *     None
196  *
197  * RETURNS
198  *     Success: TRUE
199  *     Failure: FALSE
200  */
201 BOOL WINAPI IsUserAdmin(VOID)
202 {
203     SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
204     HANDLE hToken;
205     DWORD dwSize;
206     PTOKEN_GROUPS lpGroups;
207     PSID lpSid;
208     DWORD i;
209     BOOL bResult = FALSE;
210
211     TRACE("\n");
212
213     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
214     {
215         return FALSE;
216     }
217
218     if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
219     {
220         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
221         {
222             CloseHandle(hToken);
223             return FALSE;
224         }
225     }
226
227     lpGroups = MyMalloc(dwSize);
228     if (lpGroups == NULL)
229     {
230         CloseHandle(hToken);
231         return FALSE;
232     }
233
234     if (!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))
235     {
236         MyFree(lpGroups);
237         CloseHandle(hToken);
238         return FALSE;
239     }
240
241     CloseHandle(hToken);
242
243     if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID,
244                                   DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
245                                   &lpSid))
246     {
247         MyFree(lpGroups);
248         return FALSE;
249     }
250
251     for (i = 0; i < lpGroups->GroupCount; i++)
252     {
253         if (EqualSid(lpSid, lpGroups->Groups[i].Sid))
254         {
255             bResult = TRUE;
256             break;
257         }
258     }
259
260     FreeSid(lpSid);
261     MyFree(lpGroups);
262
263     return bResult;
264 }
265
266
267 /**************************************************************************
268  * MultiByteToUnicode [SETUPAPI.@]
269  *
270  * Converts a multi-byte string to a Unicode string.
271  *
272  * PARAMS
273  *     lpMultiByteStr  [I] Multi-byte string to be converted
274  *     uCodePage       [I] Code page
275  *
276  * RETURNS
277  *     Success: pointer to the converted Unicode string
278  *     Failure: NULL
279  *
280  * NOTE
281  *     Use MyFree to release the returned Unicode string.
282  */
283 LPWSTR WINAPI MultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)
284 {
285     LPWSTR lpUnicodeStr;
286     int nLength;
287
288     TRACE("%s %d\n", debugstr_a(lpMultiByteStr), uCodePage);
289
290     nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
291                                   -1, NULL, 0);
292     if (nLength == 0)
293         return NULL;
294
295     lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));
296     if (lpUnicodeStr == NULL)
297         return NULL;
298
299     if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
300                              nLength, lpUnicodeStr, nLength))
301     {
302         MyFree(lpUnicodeStr);
303         return NULL;
304     }
305
306     return lpUnicodeStr;
307 }
308
309
310 /**************************************************************************
311  * UnicodeToMultiByte [SETUPAPI.@]
312  *
313  * Converts a Unicode string to a multi-byte string.
314  *
315  * PARAMS
316  *     lpUnicodeStr  [I] Unicode string to be converted
317  *     uCodePage     [I] Code page
318  *
319  * RETURNS
320  *     Success: pointer to the converted multi-byte string
321  *     Failure: NULL
322  *
323  * NOTE
324  *     Use MyFree to release the returned multi-byte string.
325  */
326 LPSTR WINAPI UnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)
327 {
328     LPSTR lpMultiByteStr;
329     int nLength;
330
331     TRACE("%s %d\n", debugstr_w(lpUnicodeStr), uCodePage);
332
333     nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
334                                   NULL, 0, NULL, NULL);
335     if (nLength == 0)
336         return NULL;
337
338     lpMultiByteStr = MyMalloc(nLength);
339     if (lpMultiByteStr == NULL)
340         return NULL;
341
342     if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
343                              lpMultiByteStr, nLength, NULL, NULL))
344     {
345         MyFree(lpMultiByteStr);
346         return NULL;
347     }
348
349     return lpMultiByteStr;
350 }
351
352
353 /**************************************************************************
354  * DoesUserHavePrivilege [SETUPAPI.@]
355  *
356  * Check whether the current user has got a given privilege.
357  *
358  * PARAMS
359  *     lpPrivilegeName  [I] Name of the privilege to be checked
360  *
361  * RETURNS
362  *     Success: TRUE
363  *     Failure: FALSE
364  */
365 BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)
366 {
367     HANDLE hToken;
368     DWORD dwSize;
369     PTOKEN_PRIVILEGES lpPrivileges;
370     LUID PrivilegeLuid;
371     DWORD i;
372     BOOL bResult = FALSE;
373
374     TRACE("%s\n", debugstr_w(lpPrivilegeName));
375
376     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
377         return FALSE;
378
379     if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
380     {
381         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
382         {
383             CloseHandle(hToken);
384             return FALSE;
385         }
386     }
387
388     lpPrivileges = MyMalloc(dwSize);
389     if (lpPrivileges == NULL)
390     {
391         CloseHandle(hToken);
392         return FALSE;
393     }
394
395     if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))
396     {
397         MyFree(lpPrivileges);
398         CloseHandle(hToken);
399         return FALSE;
400     }
401
402     CloseHandle(hToken);
403
404     if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))
405     {
406         MyFree(lpPrivileges);
407         return FALSE;
408     }
409
410     for (i = 0; i < lpPrivileges->PrivilegeCount; i++)
411     {
412         if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&
413             lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)
414         {
415             bResult = TRUE;
416         }
417     }
418
419     MyFree(lpPrivileges);
420
421     return bResult;
422 }
423
424
425 /**************************************************************************
426  * EnablePrivilege [SETUPAPI.@]
427  *
428  * Enables or disables one of the current users privileges.
429  *
430  * PARAMS
431  *     lpPrivilegeName  [I] Name of the privilege to be changed
432  *     bEnable          [I] TRUE: Enables the privilege
433  *                          FALSE: Disables the privilege
434  *
435  * RETURNS
436  *     Success: TRUE
437  *     Failure: FALSE
438  */
439 BOOL WINAPI EnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)
440 {
441     TOKEN_PRIVILEGES Privileges;
442     HANDLE hToken;
443     BOOL bResult;
444
445     TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");
446
447     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
448         return FALSE;
449
450     Privileges.PrivilegeCount = 1;
451     Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
452
453     if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,
454                                &Privileges.Privileges[0].Luid))
455     {
456         CloseHandle(hToken);
457         return FALSE;
458     }
459
460     bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);
461
462     CloseHandle(hToken);
463
464     return bResult;
465 }
466
467
468 /**************************************************************************
469  * DelayedMove [SETUPAPI.@]
470  *
471  * Moves a file upon the next reboot.
472  *
473  * PARAMS
474  *     lpExistingFileName  [I] Current file name
475  *     lpNewFileName       [I] New file name
476  *
477  * RETURNS
478  *     Success: TRUE
479  *     Failure: FALSE
480  */
481 BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
482 {
483     return MoveFileExW(lpExistingFileName, lpNewFileName,
484                        MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
485 }
486
487
488 /**************************************************************************
489  * FileExists [SETUPAPI.@]
490  *
491  * Checks whether a file exists.
492  *
493  * PARAMS
494  *     lpFileName     [I] Name of the file to check
495  *     lpNewFileName  [O] Optional information about the existing file
496  *
497  * RETURNS
498  *     Success: TRUE
499  *     Failure: FALSE
500  */
501 BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)
502 {
503     WIN32_FIND_DATAW FindData;
504     HANDLE hFind;
505     UINT uErrorMode;
506     DWORD dwError;
507
508     uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
509
510     hFind = FindFirstFileW(lpFileName, &FindData);
511     if (hFind == INVALID_HANDLE_VALUE)
512     {
513         dwError = GetLastError();
514         SetErrorMode(uErrorMode);
515         SetLastError(dwError);
516         return FALSE;
517     }
518
519     FindClose(hFind);
520
521     if (lpFileFindData)
522         memcpy(lpFileFindData, &FindData, sizeof(WIN32_FIND_DATAW));
523
524     SetErrorMode(uErrorMode);
525
526     return TRUE;
527 }
528
529
530 /**************************************************************************
531  * CaptureStringArg [SETUPAPI.@]
532  *
533  * Captures a UNICODE string.
534  *
535  * PARAMS
536  *     lpSrc  [I] UNICODE string to be captured
537  *     lpDst  [O] Pointer to the captured UNICODE string
538  *
539  * RETURNS
540  *     Success: ERROR_SUCCESS
541  *     Failure: ERROR_INVALID_PARAMETER
542  *
543  * NOTE
544  *     Call MyFree to release the captured UNICODE string.
545  */
546 DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)
547 {
548     if (pDst == NULL)
549         return ERROR_INVALID_PARAMETER;
550
551     *pDst = DuplicateString(pSrc);
552
553     return ERROR_SUCCESS;
554 }
555
556
557 /**************************************************************************
558  * CaptureAndConvertAnsiArg [SETUPAPI.@]
559  *
560  * Captures an ANSI string and converts it to a UNICODE string.
561  *
562  * PARAMS
563  *     lpSrc  [I] ANSI string to be captured
564  *     lpDst  [O] Pointer to the captured UNICODE string
565  *
566  * RETURNS
567  *     Success: ERROR_SUCCESS
568  *     Failure: ERROR_INVALID_PARAMETER
569  *
570  * NOTE
571  *     Call MyFree to release the captured UNICODE string.
572  */
573 DWORD WINAPI CaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)
574 {
575     if (pDst == NULL)
576         return ERROR_INVALID_PARAMETER;
577
578     *pDst = MultiByteToUnicode(pSrc, CP_ACP);
579
580     return ERROR_SUCCESS;
581 }
582
583
584 /**************************************************************************
585  * OpenAndMapFileForRead [SETUPAPI.@]
586  *
587  * Open and map a file to a buffer.
588  *
589  * PARAMS
590  *     lpFileName [I] Name of the file to be opened
591  *     lpSize     [O] Pointer to the file size
592  *     lpFile     [0] Pointer to the file handle
593  *     lpMapping  [0] Pointer to the mapping handle
594  *     lpBuffer   [0] Pointer to the file buffer
595  *
596  * RETURNS
597  *     Success: ERROR_SUCCESS
598  *     Failure: Other
599  *
600  * NOTE
601  *     Call UnmapAndCloseFile to release the file.
602  */
603 DWORD WINAPI OpenAndMapFileForRead(LPCWSTR lpFileName,
604                                    LPDWORD lpSize,
605                                    LPHANDLE lpFile,
606                                    LPHANDLE lpMapping,
607                                    LPVOID *lpBuffer)
608 {
609     DWORD dwError;
610
611     TRACE("%s %p %p %p %p\n",
612           debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);
613
614     *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
615                           OPEN_EXISTING, 0, NULL);
616     if (*lpFile == INVALID_HANDLE_VALUE)
617         return GetLastError();
618
619     *lpSize = GetFileSize(*lpFile, NULL);
620     if (*lpSize == INVALID_FILE_SIZE)
621     {
622         dwError = GetLastError();
623         CloseHandle(*lpFile);
624         return dwError;
625     }
626
627     *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,
628                                     *lpSize, NULL);
629     if (*lpMapping == NULL)
630     {
631         dwError = GetLastError();
632         CloseHandle(*lpFile);
633         return dwError;
634     }
635
636     *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);
637     if (*lpBuffer == NULL)
638     {
639         dwError = GetLastError();
640         CloseHandle(*lpMapping);
641         CloseHandle(*lpFile);
642         return dwError;
643     }
644
645     return ERROR_SUCCESS;
646 }
647
648
649 /**************************************************************************
650  * UnmapAndCloseFile [SETUPAPI.@]
651  *
652  * Unmap and close a mapped file.
653  *
654  * PARAMS
655  *     hFile    [I] Handle to the file
656  *     hMapping [I] Handle to the file mapping
657  *     lpBuffer [I] Pointer to the file buffer
658  *
659  * RETURNS
660  *     Success: TRUE
661  *     Failure: FALSE
662  */
663 BOOL WINAPI UnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)
664 {
665     TRACE("%p %p %p\n",
666           hFile, hMapping, lpBuffer);
667
668     if (!UnmapViewOfFile(lpBuffer))
669         return FALSE;
670
671     if (!CloseHandle(hMapping))
672         return FALSE;
673
674     if (!CloseHandle(hFile))
675         return FALSE;
676
677     return TRUE;
678 }
679
680
681 /**************************************************************************
682  * StampFileSecurity [SETUPAPI.@]
683  *
684  * Assign a new security descriptor to the given file.
685  *
686  * PARAMS
687  *     lpFileName          [I] Name of the file
688  *     pSecurityDescriptor [I] New security descriptor
689  *
690  * RETURNS
691  *     Success: ERROR_SUCCESS
692  *     Failure: other
693  */
694 DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)
695 {
696     TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
697
698     if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
699                           GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
700                           pSecurityDescriptor))
701         return GetLastError();
702
703     return ERROR_SUCCESS;
704 }
705
706
707 /**************************************************************************
708  * TakeOwnershipOfFile [SETUPAPI.@]
709  *
710  * Takes the ownership of the given file.
711  *
712  * PARAMS
713  *     lpFileName [I] Name of the file
714  *
715  * RETURNS
716  *     Success: ERROR_SUCCESS
717  *     Failure: other
718  */
719 DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)
720 {
721     SECURITY_DESCRIPTOR SecDesc;
722     HANDLE hToken = NULL;
723     PTOKEN_OWNER pOwner = NULL;
724     DWORD dwError;
725     DWORD dwSize;
726
727     TRACE("%s\n", debugstr_w(lpFileName));
728
729     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
730         return GetLastError();
731
732     if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))
733     {
734         goto fail;
735     }
736
737     pOwner = (PTOKEN_OWNER)MyMalloc(dwSize);
738     if (pOwner == NULL)
739     {
740         CloseHandle(hToken);
741         return ERROR_NOT_ENOUGH_MEMORY;
742     }
743
744     if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))
745     {
746         goto fail;
747     }
748
749     if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
750     {
751         goto fail;
752     }
753
754     if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))
755     {
756         goto fail;
757     }
758
759     if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))
760     {
761         goto fail;
762     }
763
764     MyFree(pOwner);
765     CloseHandle(hToken);
766
767     return ERROR_SUCCESS;
768
769 fail:;
770     dwError = GetLastError();
771
772     MyFree(pOwner);
773
774     if (hToken != NULL)
775         CloseHandle(hToken);
776
777     return dwError;
778 }
779
780
781 /**************************************************************************
782  * RetreiveFileSecurity [SETUPAPI.@]
783  *
784  * Retrieve the security descriptor that is associated with the given file.
785  *
786  * PARAMS
787  *     lpFileName [I] Name of the file
788  *
789  * RETURNS
790  *     Success: ERROR_SUCCESS
791  *     Failure: other
792  */
793 DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,
794                                   PSECURITY_DESCRIPTOR *pSecurityDescriptor)
795 {
796     PSECURITY_DESCRIPTOR SecDesc;
797     DWORD dwSize = 0x100;
798     DWORD dwError;
799
800     SecDesc = (PSECURITY_DESCRIPTOR)MyMalloc(dwSize);
801     if (SecDesc == NULL)
802         return ERROR_NOT_ENOUGH_MEMORY;
803
804     if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
805                          GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
806                          SecDesc, dwSize, &dwSize))
807     {
808       *pSecurityDescriptor = SecDesc;
809       return ERROR_SUCCESS;
810     }
811
812     dwError = GetLastError();
813     if (dwError != ERROR_INSUFFICIENT_BUFFER)
814     {
815         MyFree(SecDesc);
816         return dwError;
817     }
818
819     SecDesc = (PSECURITY_DESCRIPTOR)MyRealloc(SecDesc, dwSize);
820     if (SecDesc == NULL)
821         return ERROR_NOT_ENOUGH_MEMORY;
822
823     if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
824                          GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
825                          SecDesc, dwSize, &dwSize))
826     {
827       *pSecurityDescriptor = SecDesc;
828       return ERROR_SUCCESS;
829     }
830
831     dwError = GetLastError();
832     MyFree(SecDesc);
833
834     return dwError;
835 }
836
837
838 static DWORD global_flags = 0;  /* FIXME: what should be in here? */
839
840 /***********************************************************************
841  *              pSetupGetGlobalFlags  (SETUPAPI.@)
842  */
843 DWORD WINAPI pSetupGetGlobalFlags(void)
844 {
845     FIXME( "stub\n" );
846     return global_flags;
847 }
848
849
850 /***********************************************************************
851  *              pSetupSetGlobalFlags  (SETUPAPI.@)
852  */
853 void WINAPI pSetupSetGlobalFlags( DWORD flags )
854 {
855     global_flags = flags;
856 }
857
858 /***********************************************************************
859  *              CMP_WaitNoPendingInstallEvents  (SETUPAPI.@)
860  */
861 DWORD WINAPI CMP_WaitNoPendingInstallEvents( DWORD dwTimeout )
862 {
863     FIXME("%d\n", dwTimeout);
864     return WAIT_OBJECT_0;
865 }
866
867 /***********************************************************************
868  *              AssertFail  (SETUPAPI.@)
869  *
870  * Shows an assert fail error messagebox
871  *
872  * PARAMS
873  *   lpFile [I]         file where assert failed
874  *   uLine [I]          line number in file
875  *   lpMessage [I]      assert message
876  *
877  */
878 void WINAPI AssertFail(LPCSTR lpFile, UINT uLine, LPCSTR lpMessage)
879 {
880     FIXME("%s %u %s\n", lpFile, uLine, lpMessage);
881 }
882
883 /***********************************************************************
884  *      SetupCopyOEMInfA  (SETUPAPI.@)
885  */
886 BOOL WINAPI SetupCopyOEMInfA( PCSTR source, PCSTR location,
887                               DWORD media_type, DWORD style, PSTR dest,
888                               DWORD buffer_size, PDWORD required_size, PSTR *component )
889 {
890     BOOL ret = FALSE;
891     LPWSTR destW = NULL, sourceW = NULL, locationW = NULL;
892     DWORD size;
893
894     TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_a(source), debugstr_a(location),
895           media_type, style, dest, buffer_size, required_size, component);
896
897     if (dest && !(destW = MyMalloc( buffer_size * sizeof(WCHAR) ))) return FALSE;
898     if (source && !(sourceW = strdupAtoW( source ))) goto done;
899     if (location && !(locationW = strdupAtoW( location ))) goto done;
900
901     if (!(ret = SetupCopyOEMInfW( sourceW, locationW, media_type, style, destW,
902                                   buffer_size, &size, NULL )))
903     {
904         if (required_size) *required_size = size;
905         goto done;
906     }
907
908     if (dest)
909     {
910         if (buffer_size >= size)
911         {
912             WideCharToMultiByte( CP_ACP, 0, destW, -1, dest, buffer_size, NULL, NULL );
913             if (component) *component = strrchr( dest, '\\' ) + 1;
914         }
915         else
916         {
917             SetLastError( ERROR_INSUFFICIENT_BUFFER );
918             goto done;
919         }
920     }
921
922 done:
923     MyFree( destW );
924     HeapFree( GetProcessHeap(), 0, sourceW );
925     HeapFree( GetProcessHeap(), 0, locationW );
926     if (ret) SetLastError(ERROR_SUCCESS);
927     return ret;
928 }
929
930 /***********************************************************************
931  *      SetupCopyOEMInfW  (SETUPAPI.@)
932  */
933 BOOL WINAPI SetupCopyOEMInfW( PCWSTR source, PCWSTR location,
934                               DWORD media_type, DWORD style, PWSTR dest,
935                               DWORD buffer_size, PDWORD required_size, PWSTR *component )
936 {
937     BOOL ret = FALSE;
938     WCHAR target[MAX_PATH], *p;
939     static const WCHAR inf_oem[] = { '\\','i','n','f','\\','O','E','M',0 };
940     DWORD size;
941
942     TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_w(source), debugstr_w(location),
943           media_type, style, dest, buffer_size, required_size, component);
944
945     if (!source)
946     {
947         SetLastError(ERROR_INVALID_PARAMETER);
948         return FALSE;
949     }
950
951     /* check for a relative path */
952     if (!(*source == '\\' || (*source && source[1] == ':')))
953     {
954         SetLastError(ERROR_FILE_NOT_FOUND);
955         return FALSE;
956     }
957
958     if (!GetWindowsDirectoryW( target, sizeof(target)/sizeof(WCHAR) )) return FALSE;
959
960     strcatW( target, inf_oem );
961     if ((p = strrchrW( source, '\\' )))
962         strcatW( target, p + 1 );
963
964     if (!(ret = CopyFileW( source, target, (style & SP_COPY_NOOVERWRITE) != 0 )))
965         return ret;
966
967     if (style & SP_COPY_DELETESOURCE)
968         DeleteFileW( source );
969
970     size = strlenW( target ) + 1;
971     if (dest)
972     {
973         if (buffer_size >= size)
974         {
975             strcpyW( dest, target );
976         }
977         else
978         {
979             SetLastError( ERROR_INSUFFICIENT_BUFFER );
980             ret = FALSE;
981         }
982     }
983
984     if (component) *component = p + 1;
985     if (required_size) *required_size = size;
986     if (ret) SetLastError(ERROR_SUCCESS);
987
988     return ret;
989 }
990
991 /***********************************************************************
992  *      InstallCatalog  (SETUPAPI.@)
993  */
994 DWORD WINAPI InstallCatalog( LPCSTR catalog, LPCSTR basename, LPSTR fullname )
995 {
996     FIXME("%s, %s, %p\n", debugstr_a(catalog), debugstr_a(basename), fullname);
997     return 0;
998 }
999
1000 static UINT detect_compression_type( LPCWSTR file )
1001 {
1002     DWORD size;
1003     HANDLE handle;
1004     UINT type = FILE_COMPRESSION_NONE;
1005     static const BYTE LZ_MAGIC[] = { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 };
1006     static const BYTE MSZIP_MAGIC[] = { 0x4b, 0x57, 0x41, 0x4a };
1007     static const BYTE NTCAB_MAGIC[] = { 0x4d, 0x53, 0x43, 0x46 };
1008     BYTE buffer[8];
1009
1010     handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1011     if (handle == INVALID_HANDLE_VALUE)
1012     {
1013         ERR("cannot open file %s\n", debugstr_w(file));
1014         return FILE_COMPRESSION_NONE;
1015     }
1016     if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer))
1017     {
1018         CloseHandle( handle );
1019         return FILE_COMPRESSION_NONE;
1020     }
1021     if (!memcmp( buffer, LZ_MAGIC, sizeof(LZ_MAGIC) )) type = FILE_COMPRESSION_WINLZA;
1022     else if (!memcmp( buffer, MSZIP_MAGIC, sizeof(MSZIP_MAGIC) )) type = FILE_COMPRESSION_MSZIP;
1023     else if (!memcmp( buffer, NTCAB_MAGIC, sizeof(NTCAB_MAGIC) )) type = FILE_COMPRESSION_MSZIP; /* not a typo */
1024
1025     CloseHandle( handle );
1026     return type;
1027 }
1028
1029 static BOOL get_file_size( LPCWSTR file, DWORD *size )
1030 {
1031     HANDLE handle;
1032
1033     handle = CreateFileW( file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
1034     if (handle == INVALID_HANDLE_VALUE)
1035     {
1036         ERR("cannot open file %s\n", debugstr_w(file));
1037         return FALSE;
1038     }
1039     *size = GetFileSize( handle, NULL );
1040     CloseHandle( handle );
1041     return TRUE;
1042 }
1043
1044 static BOOL get_file_sizes_none( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1045 {
1046     DWORD size;
1047
1048     if (!get_file_size( source, &size )) return FALSE;
1049     if (source_size) *source_size = size;
1050     if (target_size) *target_size = size;
1051     return TRUE;
1052 }
1053
1054 static BOOL get_file_sizes_lz( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1055 {
1056     DWORD size;
1057     BOOL ret = TRUE;
1058
1059     if (source_size)
1060     {
1061         if (!get_file_size( source, &size )) ret = FALSE;
1062         else *source_size = size;
1063     }
1064     if (target_size)
1065     {
1066         INT file;
1067         OFSTRUCT of;
1068
1069         if ((file = LZOpenFileW( (LPWSTR)source, &of, OF_READ )) < 0)
1070         {
1071             ERR("cannot open source file for reading\n");
1072             return FALSE;
1073         }
1074         *target_size = LZSeek( file, 0, 2 );
1075         LZClose( file );
1076     }
1077     return ret;
1078 }
1079
1080 static UINT CALLBACK file_compression_info_callback( PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2 )
1081 {
1082     DWORD *size = context;
1083     FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
1084
1085     switch (notification)
1086     {
1087     case SPFILENOTIFY_FILEINCABINET:
1088     {
1089         *size = info->FileSize;
1090         return FILEOP_SKIP;
1091     }
1092     default: return NO_ERROR;
1093     }
1094 }
1095
1096 static BOOL get_file_sizes_cab( LPCWSTR source, DWORD *source_size, DWORD *target_size )
1097 {
1098     DWORD size;
1099     BOOL ret = TRUE;
1100
1101     if (source_size)
1102     {
1103         if (!get_file_size( source, &size )) ret = FALSE;
1104         else *source_size = size;
1105     }
1106     if (target_size)
1107     {
1108         ret = SetupIterateCabinetW( source, 0, file_compression_info_callback, target_size );
1109     }
1110     return ret;
1111 }
1112
1113 /***********************************************************************
1114  *      SetupGetFileCompressionInfoExA  (SETUPAPI.@)
1115  *
1116  * See SetupGetFileCompressionInfoExW.
1117  */
1118 BOOL WINAPI SetupGetFileCompressionInfoExA( PCSTR source, PSTR name, DWORD len, PDWORD required,
1119                                             PDWORD source_size, PDWORD target_size, PUINT type )
1120 {
1121     BOOL ret;
1122     WCHAR *nameW = NULL, *sourceW = NULL;
1123     DWORD nb_chars = 0;
1124     LPSTR nameA;
1125
1126     TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_a(source), name, len, required,
1127           source_size, target_size, type);
1128
1129     if (!source || !(sourceW = MultiByteToUnicode( source, CP_ACP ))) return FALSE;
1130
1131     if (name)
1132     {
1133         ret = SetupGetFileCompressionInfoExW( sourceW, NULL, 0, &nb_chars, NULL, NULL, NULL );
1134         if (!(nameW = HeapAlloc( GetProcessHeap(), 0, nb_chars * sizeof(WCHAR) )))
1135         {
1136             MyFree( sourceW );
1137             return FALSE;
1138         }
1139     }
1140     ret = SetupGetFileCompressionInfoExW( sourceW, nameW, nb_chars, &nb_chars, source_size, target_size, type );
1141     if (ret)
1142     {
1143         if ((nameA = UnicodeToMultiByte( nameW, CP_ACP )))
1144         {
1145             if (name && len >= nb_chars) lstrcpyA( name, nameA );
1146             else
1147             {
1148                 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1149                 ret = FALSE;
1150             }
1151             MyFree( nameA );
1152         }
1153     }
1154     if (required) *required = nb_chars;
1155     HeapFree( GetProcessHeap(), 0, nameW );
1156     MyFree( sourceW );
1157
1158     return ret;
1159 }
1160
1161 /***********************************************************************
1162  *      SetupGetFileCompressionInfoExW  (SETUPAPI.@)
1163  *
1164  * Get compression type and compressed/uncompressed sizes of a given file.
1165  *
1166  * PARAMS
1167  *  source      [I] File to examine.
1168  *  name        [O] Actual filename used.
1169  *  len         [I] Length in characters of 'name' buffer.
1170  *  required    [O] Number of characters written to 'name'.
1171  *  source_size [O] Size of compressed file.
1172  *  target_size [O] Size of uncompressed file.
1173  *  type        [O] Compression type.
1174  *
1175  * RETURNS
1176  *  Success: TRUE
1177  *  Failure: FALSE
1178  */
1179 BOOL WINAPI SetupGetFileCompressionInfoExW( PCWSTR source, PWSTR name, DWORD len, PDWORD required,
1180                                             PDWORD source_size, PDWORD target_size, PUINT type )
1181 {
1182     UINT comp;
1183     BOOL ret = FALSE;
1184     DWORD source_len;
1185
1186     TRACE("%s, %p, %d, %p, %p, %p, %p\n", debugstr_w(source), name, len, required,
1187           source_size, target_size, type);
1188
1189     if (!source) return FALSE;
1190
1191     source_len = lstrlenW( source ) + 1;
1192     if (required) *required = source_len;
1193     if (name && len >= source_len)
1194     {
1195         lstrcpyW( name, source );
1196         ret = TRUE;
1197     }
1198     else return FALSE;
1199
1200     comp = detect_compression_type( source );
1201     if (type) *type = comp;
1202
1203     switch (comp)
1204     {
1205     case FILE_COMPRESSION_MSZIP:
1206     case FILE_COMPRESSION_NTCAB:  ret = get_file_sizes_cab( source, source_size, target_size ); break;
1207     case FILE_COMPRESSION_NONE:   ret = get_file_sizes_none( source, source_size, target_size ); break;
1208     case FILE_COMPRESSION_WINLZA: ret = get_file_sizes_lz( source, source_size, target_size ); break;
1209     default: break;
1210     }
1211     return ret;
1212 }