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