setupapi: Win64 printf format warning fixes.
[wine] / dlls / setupapi / misc.c
1 /*
2  * Setupapi miscellaneous functions
3  *
4  * Copyright 2005 Eric Kohl
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "setupapi.h"
29
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32
33 #include "setupapi_private.h"
34
35
36 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
37
38
39 /**************************************************************************
40  * MyFree [SETUPAPI.@]
41  *
42  * Frees an allocated memory block from the process heap.
43  *
44  * PARAMS
45  *     lpMem [I] pointer to memory block which will be freed
46  *
47  * RETURNS
48  *     None
49  */
50 VOID WINAPI MyFree(LPVOID lpMem)
51 {
52     TRACE("%p\n", lpMem);
53     HeapFree(GetProcessHeap(), 0, lpMem);
54 }
55
56
57 /**************************************************************************
58  * MyMalloc [SETUPAPI.@]
59  *
60  * Allocates memory block from the process heap.
61  *
62  * PARAMS
63  *     dwSize [I] size of the allocated memory block
64  *
65  * RETURNS
66  *     Success: pointer to allocated memory block
67  *     Failure: NULL
68  */
69 LPVOID WINAPI MyMalloc(DWORD dwSize)
70 {
71     TRACE("%u\n", dwSize);
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     TRACE("%p %u\n", lpSrc, dwSize);
97
98     if (lpSrc == NULL)
99         return HeapAlloc(GetProcessHeap(), 0, dwSize);
100
101     return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize);
102 }
103
104
105 /**************************************************************************
106  * DuplicateString [SETUPAPI.@]
107  *
108  * Duplicates a unicode string.
109  *
110  * PARAMS
111  *     lpSrc  [I] pointer to the unicode string that will be duplicated
112  *
113  * RETURNS
114  *     Success: pointer to the duplicated unicode string
115  *     Failure: NULL
116  *
117  * NOTES
118  *     Call MyFree() to release the duplicated string.
119  */
120 LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc)
121 {
122     LPWSTR lpDst;
123
124     TRACE("%s\n", debugstr_w(lpSrc));
125
126     lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));
127     if (lpDst == NULL)
128         return NULL;
129
130     strcpyW(lpDst, lpSrc);
131
132     return lpDst;
133 }
134
135
136 /**************************************************************************
137  * QueryRegistryValue [SETUPAPI.@]
138  *
139  * Retrieves value data from the registry and allocates memory for the
140  * value data.
141  *
142  * PARAMS
143  *     hKey        [I] Handle of the key to query
144  *     lpValueName [I] Name of value under hkey to query
145  *     lpData      [O] Destination for the values contents,
146  *     lpType      [O] Destination for the value type
147  *     lpcbData    [O] Destination for the size of data
148  *
149  * RETURNS
150  *     Success: ERROR_SUCCESS
151  *     Failure: Otherwise
152  *
153  * NOTES
154  *     Use MyFree to release the lpData buffer.
155  */
156 LONG WINAPI QueryRegistryValue(HKEY hKey,
157                                LPCWSTR lpValueName,
158                                LPBYTE  *lpData,
159                                LPDWORD lpType,
160                                LPDWORD lpcbData)
161 {
162     LONG lError;
163
164     TRACE("%p %s %p %p %p\n",
165           hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);
166
167     /* Get required buffer size */
168     *lpcbData = 0;
169     lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);
170     if (lError != ERROR_SUCCESS)
171         return lError;
172
173     /* Allocate buffer */
174     *lpData = MyMalloc(*lpcbData);
175     if (*lpData == NULL)
176         return ERROR_NOT_ENOUGH_MEMORY;
177
178     /* Query registry value */
179     lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);
180     if (lError != ERROR_SUCCESS)
181         MyFree(*lpData);
182
183     return lError;
184 }
185
186
187 /**************************************************************************
188  * IsUserAdmin [SETUPAPI.@]
189  *
190  * Checks whether the current user is a member of the Administrators group.
191  *
192  * PARAMS
193  *     None
194  *
195  * RETURNS
196  *     Success: TRUE
197  *     Failure: FALSE
198  */
199 BOOL WINAPI IsUserAdmin(VOID)
200 {
201     SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
202     HANDLE hToken;
203     DWORD dwSize;
204     PTOKEN_GROUPS lpGroups;
205     PSID lpSid;
206     DWORD i;
207     BOOL bResult = FALSE;
208
209     TRACE("\n");
210
211     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
212     {
213         return FALSE;
214     }
215
216     if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
217     {
218         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
219         {
220             CloseHandle(hToken);
221             return FALSE;
222         }
223     }
224
225     lpGroups = MyMalloc(dwSize);
226     if (lpGroups == NULL)
227     {
228         CloseHandle(hToken);
229         return FALSE;
230     }
231
232     if (!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))
233     {
234         MyFree(lpGroups);
235         CloseHandle(hToken);
236         return FALSE;
237     }
238
239     CloseHandle(hToken);
240
241     if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID,
242                                   DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
243                                   &lpSid))
244     {
245         MyFree(lpGroups);
246         return FALSE;
247     }
248
249     for (i = 0; i < lpGroups->GroupCount; i++)
250     {
251         if (EqualSid(lpSid, lpGroups->Groups[i].Sid))
252         {
253             bResult = TRUE;
254             break;
255         }
256     }
257
258     FreeSid(lpSid);
259     MyFree(lpGroups);
260
261     return bResult;
262 }
263
264
265 /**************************************************************************
266  * MultiByteToUnicode [SETUPAPI.@]
267  *
268  * Converts a multi-byte string to a Unicode string.
269  *
270  * PARAMS
271  *     lpMultiByteStr  [I] Multi-byte string to be converted
272  *     uCodePage       [I] Code page
273  *
274  * RETURNS
275  *     Success: pointer to the converted Unicode string
276  *     Failure: NULL
277  *
278  * NOTE
279  *     Use MyFree to release the returned Unicode string.
280  */
281 LPWSTR WINAPI MultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)
282 {
283     LPWSTR lpUnicodeStr;
284     int nLength;
285
286     TRACE("%s %d\n", debugstr_a(lpMultiByteStr), uCodePage);
287
288     nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
289                                   -1, NULL, 0);
290     if (nLength == 0)
291         return NULL;
292
293     lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));
294     if (lpUnicodeStr == NULL)
295         return NULL;
296
297     if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
298                              nLength, lpUnicodeStr, nLength))
299     {
300         MyFree(lpUnicodeStr);
301         return NULL;
302     }
303
304     return lpUnicodeStr;
305 }
306
307
308 /**************************************************************************
309  * UnicodeToMultiByte [SETUPAPI.@]
310  *
311  * Converts a Unicode string to a multi-byte string.
312  *
313  * PARAMS
314  *     lpUnicodeStr  [I] Unicode string to be converted
315  *     uCodePage     [I] Code page
316  *
317  * RETURNS
318  *     Success: pointer to the converted multi-byte string
319  *     Failure: NULL
320  *
321  * NOTE
322  *     Use MyFree to release the returned multi-byte string.
323  */
324 LPSTR WINAPI UnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)
325 {
326     LPSTR lpMultiByteStr;
327     int nLength;
328
329     TRACE("%s %d\n", debugstr_w(lpUnicodeStr), uCodePage);
330
331     nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
332                                   NULL, 0, NULL, NULL);
333     if (nLength == 0)
334         return NULL;
335
336     lpMultiByteStr = MyMalloc(nLength);
337     if (lpMultiByteStr == NULL)
338         return NULL;
339
340     if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
341                              lpMultiByteStr, nLength, NULL, NULL))
342     {
343         MyFree(lpMultiByteStr);
344         return NULL;
345     }
346
347     return lpMultiByteStr;
348 }
349
350
351 /**************************************************************************
352  * DoesUserHavePrivilege [SETUPAPI.@]
353  *
354  * Check whether the current user has got a given privilege.
355  *
356  * PARAMS
357  *     lpPrivilegeName  [I] Name of the privilege to be checked
358  *
359  * RETURNS
360  *     Success: TRUE
361  *     Failure: FALSE
362  */
363 BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)
364 {
365     HANDLE hToken;
366     DWORD dwSize;
367     PTOKEN_PRIVILEGES lpPrivileges;
368     LUID PrivilegeLuid;
369     DWORD i;
370     BOOL bResult = FALSE;
371
372     TRACE("%s\n", debugstr_w(lpPrivilegeName));
373
374     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
375         return FALSE;
376
377     if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
378     {
379         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
380         {
381             CloseHandle(hToken);
382             return FALSE;
383         }
384     }
385
386     lpPrivileges = MyMalloc(dwSize);
387     if (lpPrivileges == NULL)
388     {
389         CloseHandle(hToken);
390         return FALSE;
391     }
392
393     if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))
394     {
395         MyFree(lpPrivileges);
396         CloseHandle(hToken);
397         return FALSE;
398     }
399
400     CloseHandle(hToken);
401
402     if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))
403     {
404         MyFree(lpPrivileges);
405         return FALSE;
406     }
407
408     for (i = 0; i < lpPrivileges->PrivilegeCount; i++)
409     {
410         if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&
411             lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)
412         {
413             bResult = TRUE;
414         }
415     }
416
417     MyFree(lpPrivileges);
418
419     return bResult;
420 }
421
422
423 /**************************************************************************
424  * EnablePrivilege [SETUPAPI.@]
425  *
426  * Enables or disables one of the current users privileges.
427  *
428  * PARAMS
429  *     lpPrivilegeName  [I] Name of the privilege to be changed
430  *     bEnable          [I] TRUE: Enables the privilege
431  *                          FALSE: Disables the privilege
432  *
433  * RETURNS
434  *     Success: TRUE
435  *     Failure: FALSE
436  */
437 BOOL WINAPI EnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)
438 {
439     TOKEN_PRIVILEGES Privileges;
440     HANDLE hToken;
441     BOOL bResult;
442
443     TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");
444
445     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
446         return FALSE;
447
448     Privileges.PrivilegeCount = 1;
449     Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
450
451     if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,
452                                &Privileges.Privileges[0].Luid))
453     {
454         CloseHandle(hToken);
455         return FALSE;
456     }
457
458     bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);
459
460     CloseHandle(hToken);
461
462     return bResult;
463 }
464
465
466 /**************************************************************************
467  * DelayedMove [SETUPAPI.@]
468  *
469  * Moves a file upon the next reboot.
470  *
471  * PARAMS
472  *     lpExistingFileName  [I] Current file name
473  *     lpNewFileName       [I] New file name
474  *
475  * RETURNS
476  *     Success: TRUE
477  *     Failure: FALSE
478  */
479 BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
480 {
481     return MoveFileExW(lpExistingFileName, lpNewFileName,
482                        MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
483 }
484
485
486 /**************************************************************************
487  * FileExists [SETUPAPI.@]
488  *
489  * Checks whether a file exists.
490  *
491  * PARAMS
492  *     lpFileName     [I] Name of the file to check
493  *     lpNewFileName  [O] Optional information about the existing file
494  *
495  * RETURNS
496  *     Success: TRUE
497  *     Failure: FALSE
498  */
499 BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)
500 {
501     WIN32_FIND_DATAW FindData;
502     HANDLE hFind;
503     UINT uErrorMode;
504     DWORD dwError;
505
506     uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
507
508     hFind = FindFirstFileW(lpFileName, &FindData);
509     if (hFind == INVALID_HANDLE_VALUE)
510     {
511         dwError = GetLastError();
512         SetErrorMode(uErrorMode);
513         SetLastError(dwError);
514         return FALSE;
515     }
516
517     FindClose(hFind);
518
519     if (lpFileFindData)
520         memcpy(lpFileFindData, &FindData, sizeof(WIN32_FIND_DATAW));
521
522     SetErrorMode(uErrorMode);
523
524     return TRUE;
525 }
526
527
528 /**************************************************************************
529  * CaptureStringArg [SETUPAPI.@]
530  *
531  * Captures a UNICODE string.
532  *
533  * PARAMS
534  *     lpSrc  [I] UNICODE string to be captured
535  *     lpDst  [O] Pointer to the captured UNICODE string
536  *
537  * RETURNS
538  *     Success: ERROR_SUCCESS
539  *     Failure: ERROR_INVALID_PARAMETER
540  *
541  * NOTE
542  *     Call MyFree to release the captured UNICODE string.
543  */
544 DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)
545 {
546     if (pDst == NULL)
547         return ERROR_INVALID_PARAMETER;
548
549     *pDst = DuplicateString(pSrc);
550
551     return ERROR_SUCCESS;
552 }
553
554
555 /**************************************************************************
556  * CaptureAndConvertAnsiArg [SETUPAPI.@]
557  *
558  * Captures an ANSI string and converts it to a UNICODE string.
559  *
560  * PARAMS
561  *     lpSrc  [I] ANSI string to be captured
562  *     lpDst  [O] Pointer to the captured UNICODE string
563  *
564  * RETURNS
565  *     Success: ERROR_SUCCESS
566  *     Failure: ERROR_INVALID_PARAMETER
567  *
568  * NOTE
569  *     Call MyFree to release the captured UNICODE string.
570  */
571 DWORD WINAPI CaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)
572 {
573     if (pDst == NULL)
574         return ERROR_INVALID_PARAMETER;
575
576     *pDst = MultiByteToUnicode(pSrc, CP_ACP);
577
578     return ERROR_SUCCESS;
579 }
580
581
582 /**************************************************************************
583  * OpenAndMapFileForRead [SETUPAPI.@]
584  *
585  * Open and map a file to a buffer.
586  *
587  * PARAMS
588  *     lpFileName [I] Name of the file to be opened
589  *     lpSize     [O] Pointer to the file size
590  *     lpFile     [0] Pointer to the file handle
591  *     lpMapping  [0] Pointer to the mapping handle
592  *     lpBuffer   [0] Pointer to the file buffer
593  *
594  * RETURNS
595  *     Success: ERROR_SUCCESS
596  *     Failure: Other
597  *
598  * NOTE
599  *     Call UnmapAndCloseFile to release the file.
600  */
601 DWORD WINAPI OpenAndMapFileForRead(LPCWSTR lpFileName,
602                                    LPDWORD lpSize,
603                                    LPHANDLE lpFile,
604                                    LPHANDLE lpMapping,
605                                    LPVOID *lpBuffer)
606 {
607     DWORD dwError;
608
609     TRACE("%s %p %p %p %p\n",
610           debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);
611
612     *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
613                           OPEN_EXISTING, 0, NULL);
614     if (*lpFile == INVALID_HANDLE_VALUE)
615         return GetLastError();
616
617     *lpSize = GetFileSize(*lpFile, NULL);
618     if (*lpSize == INVALID_FILE_SIZE)
619     {
620         dwError = GetLastError();
621         CloseHandle(*lpFile);
622         return dwError;
623     }
624
625     *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,
626                                     *lpSize, NULL);
627     if (*lpMapping == NULL)
628     {
629         dwError = GetLastError();
630         CloseHandle(*lpFile);
631         return dwError;
632     }
633
634     *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);
635     if (*lpBuffer == NULL)
636     {
637         dwError = GetLastError();
638         CloseHandle(*lpMapping);
639         CloseHandle(*lpFile);
640         return dwError;
641     }
642
643     return ERROR_SUCCESS;
644 }
645
646
647 /**************************************************************************
648  * UnmapAndCloseFile [SETUPAPI.@]
649  *
650  * Unmap and close a mapped file.
651  *
652  * PARAMS
653  *     hFile    [I] Handle to the file
654  *     hMapping [I] Handle to the file mapping
655  *     lpBuffer [I] Pointer to the file buffer
656  *
657  * RETURNS
658  *     Success: TRUE
659  *     Failure: FALSE
660  */
661 BOOL WINAPI UnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)
662 {
663     TRACE("%p %p %p\n",
664           hFile, hMapping, lpBuffer);
665
666     if (!UnmapViewOfFile(lpBuffer))
667         return FALSE;
668
669     if (!CloseHandle(hMapping))
670         return FALSE;
671
672     if (!CloseHandle(hFile))
673         return FALSE;
674
675     return TRUE;
676 }
677
678
679 /**************************************************************************
680  * StampFileSecurity [SETUPAPI.@]
681  *
682  * Assign a new security descriptor to the given file.
683  *
684  * PARAMS
685  *     lpFileName          [I] Name of the file
686  *     pSecurityDescriptor [I] New security descriptor
687  *
688  * RETURNS
689  *     Success: ERROR_SUCCESS
690  *     Failure: other
691  */
692 DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)
693 {
694     TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
695
696     if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
697                           GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
698                           pSecurityDescriptor))
699         return GetLastError();
700
701     return ERROR_SUCCESS;
702 }
703
704
705 /**************************************************************************
706  * TakeOwnershipOfFile [SETUPAPI.@]
707  *
708  * Takes the ownership of the given file.
709  *
710  * PARAMS
711  *     lpFileName [I] Name of the file
712  *
713  * RETURNS
714  *     Success: ERROR_SUCCESS
715  *     Failure: other
716  */
717 DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)
718 {
719     SECURITY_DESCRIPTOR SecDesc;
720     HANDLE hToken = NULL;
721     PTOKEN_OWNER pOwner = NULL;
722     DWORD dwError;
723     DWORD dwSize;
724
725     TRACE("%s\n", debugstr_w(lpFileName));
726
727     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
728         return GetLastError();
729
730     if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))
731     {
732         goto fail;
733     }
734
735     pOwner = (PTOKEN_OWNER)MyMalloc(dwSize);
736     if (pOwner == NULL)
737     {
738         CloseHandle(hToken);
739         return ERROR_NOT_ENOUGH_MEMORY;
740     }
741
742     if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))
743     {
744         goto fail;
745     }
746
747     if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
748     {
749         goto fail;
750     }
751
752     if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))
753     {
754         goto fail;
755     }
756
757     if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))
758     {
759         goto fail;
760     }
761
762     MyFree(pOwner);
763     CloseHandle(hToken);
764
765     return ERROR_SUCCESS;
766
767 fail:;
768     dwError = GetLastError();
769
770     MyFree(pOwner);
771
772     if (hToken != NULL)
773         CloseHandle(hToken);
774
775     return dwError;
776 }
777
778
779 /**************************************************************************
780  * RetreiveFileSecurity [SETUPAPI.@]
781  *
782  * Retrieve the security descriptor that is associated with the given file.
783  *
784  * PARAMS
785  *     lpFileName [I] Name of the file
786  *
787  * RETURNS
788  *     Success: ERROR_SUCCESS
789  *     Failure: other
790  */
791 DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,
792                                   PSECURITY_DESCRIPTOR *pSecurityDescriptor)
793 {
794     PSECURITY_DESCRIPTOR SecDesc;
795     DWORD dwSize = 0x100;
796     DWORD dwError;
797
798     SecDesc = (PSECURITY_DESCRIPTOR)MyMalloc(dwSize);
799     if (SecDesc == NULL)
800         return ERROR_NOT_ENOUGH_MEMORY;
801
802     if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
803                          GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
804                          SecDesc, dwSize, &dwSize))
805     {
806       *pSecurityDescriptor = SecDesc;
807       return ERROR_SUCCESS;
808     }
809
810     dwError = GetLastError();
811     if (dwError != ERROR_INSUFFICIENT_BUFFER)
812     {
813         MyFree(SecDesc);
814         return dwError;
815     }
816
817     SecDesc = (PSECURITY_DESCRIPTOR)MyRealloc(SecDesc, dwSize);
818     if (SecDesc == NULL)
819         return ERROR_NOT_ENOUGH_MEMORY;
820
821     if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
822                          GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
823                          SecDesc, dwSize, &dwSize))
824     {
825       *pSecurityDescriptor = SecDesc;
826       return ERROR_SUCCESS;
827     }
828
829     dwError = GetLastError();
830     MyFree(SecDesc);
831
832     return dwError;
833 }
834
835
836 static DWORD global_flags = 0;  /* FIXME: what should be in here? */
837
838 /***********************************************************************
839  *              pSetupGetGlobalFlags  (SETUPAPI.@)
840  */
841 DWORD WINAPI pSetupGetGlobalFlags(void)
842 {
843     FIXME( "stub\n" );
844     return global_flags;
845 }
846
847
848 /***********************************************************************
849  *              pSetupSetGlobalFlags  (SETUPAPI.@)
850  */
851 void WINAPI pSetupSetGlobalFlags( DWORD flags )
852 {
853     global_flags = flags;
854 }
855
856 /***********************************************************************
857  *              CMP_WaitNoPendingInstallEvents  (SETUPAPI.@)
858  */
859 DWORD WINAPI CMP_WaitNoPendingInstallEvents( DWORD dwTimeout )
860 {
861     FIXME("%d\n", dwTimeout);
862     return WAIT_OBJECT_0;
863 }