]> wimlib.net Git - wimlib/blob - src/win32_common.c
win32_common.c: Remove unused headers
[wimlib] / src / win32_common.c
1 /*
2  * win32_common.c - Windows code common to applying and capturing images.
3  */
4
5 /*
6  * Copyright (C) 2013, 2014 Eric Biggers
7  *
8  * This file is part of wimlib, a library for working with WIM files.
9  *
10  * wimlib is free software; you can redistribute it and/or modify it under the
11  * terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 3 of the License, or (at your option)
13  * any later version.
14  *
15  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17  * A PARTICULAR PURPOSE. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with wimlib; if not, see http://www.gnu.org/licenses/.
22  */
23
24 #ifdef __WIN32__
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include <errno.h>
31
32 #include "wimlib/win32_common.h"
33 #include "wimlib/error.h"
34 #include "wimlib/util.h"
35
36 static int
37 win32_error_to_errno(DWORD err_code)
38 {
39         /* This mapping is that used in Cygwin.
40          * Some of these choices are arbitrary. */
41         switch (err_code) {
42         case ERROR_ACCESS_DENIED:
43                 return EACCES;
44         case ERROR_ACTIVE_CONNECTIONS:
45                 return EAGAIN;
46         case ERROR_ALREADY_EXISTS:
47                 return EEXIST;
48         case ERROR_BAD_DEVICE:
49                 return ENODEV;
50         case ERROR_BAD_EXE_FORMAT:
51                 return ENOEXEC;
52         case ERROR_BAD_NETPATH:
53                 return ENOENT;
54         case ERROR_BAD_NET_NAME:
55                 return ENOENT;
56         case ERROR_BAD_NET_RESP:
57                 return ENOSYS;
58         case ERROR_BAD_PATHNAME:
59                 return ENOENT;
60         case ERROR_BAD_PIPE:
61                 return EINVAL;
62         case ERROR_BAD_UNIT:
63                 return ENODEV;
64         case ERROR_BAD_USERNAME:
65                 return EINVAL;
66         case ERROR_BEGINNING_OF_MEDIA:
67                 return EIO;
68         case ERROR_BROKEN_PIPE:
69                 return EPIPE;
70         case ERROR_BUSY:
71                 return EBUSY;
72         case ERROR_BUS_RESET:
73                 return EIO;
74         case ERROR_CALL_NOT_IMPLEMENTED:
75                 return ENOSYS;
76         case ERROR_CANNOT_MAKE:
77                 return EPERM;
78         case ERROR_CHILD_NOT_COMPLETE:
79                 return EBUSY;
80         case ERROR_COMMITMENT_LIMIT:
81                 return EAGAIN;
82         case ERROR_CRC:
83                 return EIO;
84         case ERROR_DEVICE_DOOR_OPEN:
85                 return EIO;
86         case ERROR_DEVICE_IN_USE:
87                 return EAGAIN;
88         case ERROR_DEVICE_REQUIRES_CLEANING:
89                 return EIO;
90         case ERROR_DIRECTORY:
91                 return ENOTDIR;
92         case ERROR_DIR_NOT_EMPTY:
93                 return ENOTEMPTY;
94         case ERROR_DISK_CORRUPT:
95                 return EIO;
96         case ERROR_DISK_FULL:
97                 return ENOSPC;
98 #ifdef ENOTUNIQ
99         case ERROR_DUP_NAME:
100                 return ENOTUNIQ;
101 #endif
102         case ERROR_EAS_DIDNT_FIT:
103                 return ENOSPC;
104 #ifdef ENOTSUP
105         case ERROR_EAS_NOT_SUPPORTED:
106                 return ENOTSUP;
107 #endif
108         case ERROR_EA_LIST_INCONSISTENT:
109                 return EINVAL;
110         case ERROR_EA_TABLE_FULL:
111                 return ENOSPC;
112         case ERROR_END_OF_MEDIA:
113                 return ENOSPC;
114         case ERROR_EOM_OVERFLOW:
115                 return EIO;
116         case ERROR_EXE_MACHINE_TYPE_MISMATCH:
117                 return ENOEXEC;
118         case ERROR_EXE_MARKED_INVALID:
119                 return ENOEXEC;
120         case ERROR_FILEMARK_DETECTED:
121                 return EIO;
122         case ERROR_FILENAME_EXCED_RANGE:
123                 return ENAMETOOLONG;
124         case ERROR_FILE_CORRUPT:
125                 return EEXIST;
126         case ERROR_FILE_EXISTS:
127                 return EEXIST;
128         case ERROR_FILE_INVALID:
129                 return ENXIO;
130         case ERROR_FILE_NOT_FOUND:
131                 return ENOENT;
132         case ERROR_HANDLE_DISK_FULL:
133                 return ENOSPC;
134 #ifdef ENODATA
135         case ERROR_HANDLE_EOF:
136                 return ENODATA;
137 #endif
138         case ERROR_INVALID_ADDRESS:
139                 return EINVAL;
140         case ERROR_INVALID_AT_INTERRUPT_TIME:
141                 return EINTR;
142         case ERROR_INVALID_BLOCK_LENGTH:
143                 return EIO;
144         case ERROR_INVALID_DATA:
145                 return EINVAL;
146         case ERROR_INVALID_DRIVE:
147                 return ENODEV;
148         case ERROR_INVALID_EA_NAME:
149                 return EINVAL;
150         case ERROR_INVALID_EXE_SIGNATURE:
151                 return ENOEXEC;
152 #ifdef EBADRQC
153         case ERROR_INVALID_FUNCTION:
154                 return EBADRQC;
155 #endif
156         case ERROR_INVALID_HANDLE:
157                 return EBADF;
158         case ERROR_INVALID_NAME:
159                 return ENOENT;
160         case ERROR_INVALID_PARAMETER:
161                 return EINVAL;
162         case ERROR_INVALID_SIGNAL_NUMBER:
163                 return EINVAL;
164         case ERROR_IOPL_NOT_ENABLED:
165                 return ENOEXEC;
166         case ERROR_IO_DEVICE:
167                 return EIO;
168         case ERROR_IO_INCOMPLETE:
169                 return EAGAIN;
170         case ERROR_IO_PENDING:
171                 return EAGAIN;
172         case ERROR_LOCK_VIOLATION:
173                 return EBUSY;
174         case ERROR_MAX_THRDS_REACHED:
175                 return EAGAIN;
176         case ERROR_META_EXPANSION_TOO_LONG:
177                 return EINVAL;
178         case ERROR_MOD_NOT_FOUND:
179                 return ENOENT;
180 #ifdef EMSGSIZE
181         case ERROR_MORE_DATA:
182                 return EMSGSIZE;
183 #endif
184         case ERROR_NEGATIVE_SEEK:
185                 return EINVAL;
186         case ERROR_NETNAME_DELETED:
187                 return ENOENT;
188         case ERROR_NOACCESS:
189                 return EFAULT;
190         case ERROR_NONE_MAPPED:
191                 return EINVAL;
192         case ERROR_NONPAGED_SYSTEM_RESOURCES:
193                 return EAGAIN;
194 #ifdef ENOLINK
195         case ERROR_NOT_CONNECTED:
196                 return ENOLINK;
197 #endif
198         case ERROR_NOT_ENOUGH_MEMORY:
199                 return ENOMEM;
200         case ERROR_NOT_OWNER:
201                 return EPERM;
202 #ifdef ENOMEDIUM
203         case ERROR_NOT_READY:
204                 return ENOMEDIUM;
205 #endif
206         case ERROR_NOT_SAME_DEVICE:
207                 return EXDEV;
208         case ERROR_NOT_SUPPORTED:
209                 return ENOSYS;
210         case ERROR_NO_DATA:
211                 return EPIPE;
212         case ERROR_NO_DATA_DETECTED:
213                 return EIO;
214 #ifdef ENOMEDIUM
215         case ERROR_NO_MEDIA_IN_DRIVE:
216                 return ENOMEDIUM;
217 #endif
218 #ifdef ENMFILE
219         case ERROR_NO_MORE_FILES:
220                 return ENMFILE;
221 #endif
222 #ifdef ENMFILE
223         case ERROR_NO_MORE_ITEMS:
224                 return ENMFILE;
225 #endif
226         case ERROR_NO_MORE_SEARCH_HANDLES:
227                 return ENFILE;
228         case ERROR_NO_PROC_SLOTS:
229                 return EAGAIN;
230         case ERROR_NO_SIGNAL_SENT:
231                 return EIO;
232         case ERROR_NO_SYSTEM_RESOURCES:
233                 return EFBIG;
234         case ERROR_NO_TOKEN:
235                 return EINVAL;
236         case ERROR_OPEN_FAILED:
237                 return EIO;
238         case ERROR_OPEN_FILES:
239                 return EAGAIN;
240         case ERROR_OUTOFMEMORY:
241                 return ENOMEM;
242         case ERROR_PAGED_SYSTEM_RESOURCES:
243                 return EAGAIN;
244         case ERROR_PAGEFILE_QUOTA:
245                 return EAGAIN;
246         case ERROR_PATH_NOT_FOUND:
247                 return ENOENT;
248         case ERROR_PIPE_BUSY:
249                 return EBUSY;
250         case ERROR_PIPE_CONNECTED:
251                 return EBUSY;
252 #ifdef ECOMM
253         case ERROR_PIPE_LISTENING:
254                 return ECOMM;
255         case ERROR_PIPE_NOT_CONNECTED:
256                 return ECOMM;
257 #endif
258         case ERROR_POSSIBLE_DEADLOCK:
259                 return EDEADLOCK;
260         case ERROR_PRIVILEGE_NOT_HELD:
261                 return EPERM;
262         case ERROR_PROCESS_ABORTED:
263                 return EFAULT;
264         case ERROR_PROC_NOT_FOUND:
265                 return ESRCH;
266 #ifdef ENONET
267         case ERROR_REM_NOT_LIST:
268                 return ENONET;
269 #endif
270         case ERROR_SECTOR_NOT_FOUND:
271                 return EINVAL;
272         case ERROR_SEEK:
273                 return EINVAL;
274         case ERROR_SETMARK_DETECTED:
275                 return EIO;
276         case ERROR_SHARING_BUFFER_EXCEEDED:
277                 return ENOLCK;
278         case ERROR_SHARING_VIOLATION:
279                 return EBUSY;
280         case ERROR_SIGNAL_PENDING:
281                 return EBUSY;
282         case ERROR_SIGNAL_REFUSED:
283                 return EIO;
284 #ifdef ELIBBAD
285         case ERROR_SXS_CANT_GEN_ACTCTX:
286                 return ELIBBAD;
287 #endif
288         case ERROR_THREAD_1_INACTIVE:
289                 return EINVAL;
290         case ERROR_TOO_MANY_LINKS:
291                 return EMLINK;
292         case ERROR_TOO_MANY_OPEN_FILES:
293                 return EMFILE;
294         case ERROR_WAIT_NO_CHILDREN:
295                 return ECHILD;
296         case ERROR_WORKING_SET_QUOTA:
297                 return EAGAIN;
298         case ERROR_WRITE_PROTECT:
299                 return EROFS;
300         default:
301                 return -1;
302         }
303 }
304
305
306 void
307 set_errno_from_win32_error(DWORD err)
308 {
309         errno = win32_error_to_errno(err);
310 }
311
312 void
313 set_errno_from_GetLastError(void)
314 {
315         set_errno_from_win32_error(GetLastError());
316 }
317
318 void
319 set_errno_from_nt_status(NTSTATUS status)
320 {
321         set_errno_from_win32_error((*func_RtlNtStatusToDosError)(status));
322 }
323
324 /* Given a Windows-style path, return the number of characters of the prefix
325  * that specify the path to the root directory of a drive, or return 0 if the
326  * drive is relative (or at least on the current drive, in the case of
327  * absolute-but-not-really-absolute paths like \Windows\System32) */
328 static size_t
329 win32_path_drive_spec_len(const wchar_t *path)
330 {
331         size_t n = 0;
332
333         if (!wcsncmp(path, L"\\\\?\\", 4)) {
334                 /* \\?\-prefixed path.  Check for following drive letter and
335                  * path separator. */
336                 if (path[4] != L'\0' && path[5] == L':' &&
337                     is_any_path_separator(path[6]))
338                         n = 7;
339         } else {
340                 /* Not a \\?\-prefixed path.  Check for an initial drive letter
341                  * and path separator. */
342                 if (path[0] != L'\0' && path[1] == L':' &&
343                     is_any_path_separator(path[2]))
344                         n = 3;
345         }
346         /* Include any additional path separators.*/
347         if (n > 0)
348                 while (is_any_path_separator(path[n]))
349                         n++;
350         return n;
351 }
352
353 bool
354 win32_path_is_root_of_drive(const wchar_t *path)
355 {
356         size_t drive_spec_len;
357         wchar_t full_path[32768];
358         DWORD ret;
359
360         ret = GetFullPathName(path, ARRAY_LEN(full_path), full_path, NULL);
361         if (ret > 0 && ret < ARRAY_LEN(full_path))
362                 path = full_path;
363
364         /* Explicit drive letter and path separator? */
365         drive_spec_len = win32_path_drive_spec_len(path);
366         if (drive_spec_len > 0 && path[drive_spec_len] == L'\0')
367                 return true;
368
369         /* All path separators? */
370         for (const wchar_t *p = path; *p != L'\0'; p++)
371                 if (!is_any_path_separator(*p))
372                         return false;
373         return true;
374 }
375
376
377 /* Given a path, which may not yet exist, get a set of flags that describe the
378  * features of the volume the path is on. */
379 int
380 win32_get_vol_flags(const wchar_t *path, unsigned *vol_flags_ret,
381                     bool *supports_SetFileShortName_ret)
382 {
383         wchar_t *volume;
384         BOOL bret;
385         DWORD vol_flags;
386         size_t drive_spec_len;
387         wchar_t filesystem_name[MAX_PATH + 1];
388
389         if (supports_SetFileShortName_ret)
390                 *supports_SetFileShortName_ret = false;
391
392         drive_spec_len = win32_path_drive_spec_len(path);
393
394         if (drive_spec_len == 0)
395                 if (path[0] != L'\0' && path[1] == L':') /* Drive-relative path? */
396                         drive_spec_len = 2;
397
398         if (drive_spec_len == 0) {
399                 /* Path does not start with a drive letter; use the volume of
400                  * the current working directory. */
401                 volume = NULL;
402         } else {
403                 /* Path starts with a drive letter (or \\?\ followed by a drive
404                  * letter); use it. */
405                 volume = alloca((drive_spec_len + 2) * sizeof(wchar_t));
406                 wmemcpy(volume, path, drive_spec_len);
407                 /* Add trailing backslash in case this was a drive-relative
408                  * path. */
409                 volume[drive_spec_len] = L'\\';
410                 volume[drive_spec_len + 1] = L'\0';
411         }
412         bret = GetVolumeInformation(
413                         volume,                         /* lpRootPathName */
414                         NULL,                           /* lpVolumeNameBuffer */
415                         0,                              /* nVolumeNameSize */
416                         NULL,                           /* lpVolumeSerialNumber */
417                         NULL,                           /* lpMaximumComponentLength */
418                         &vol_flags,                     /* lpFileSystemFlags */
419                         filesystem_name,                /* lpFileSystemNameBuffer */
420                         ARRAY_LEN(filesystem_name));    /* nFileSystemNameSize */
421         if (!bret) {
422                 set_errno_from_GetLastError();
423                 WARNING_WITH_ERRNO("Failed to get volume information for "
424                                    "path \"%ls\"", path);
425                 vol_flags = 0xffffffff;
426                 goto out;
427         }
428
429         if (wcsstr(filesystem_name, L"NTFS")) {
430                 /* FILE_SUPPORTS_HARD_LINKS is only supported on Windows 7 and later.
431                  * Force it on anyway if filesystem is NTFS.  */
432                 vol_flags |= FILE_SUPPORTS_HARD_LINKS;
433
434                 if (supports_SetFileShortName_ret)
435                         *supports_SetFileShortName_ret = true;
436         }
437
438 out:
439         DEBUG("using vol_flags = %x", vol_flags);
440         *vol_flags_ret = vol_flags;
441         return 0;
442 }
443
444 static bool
445 win32_modify_privilege(const wchar_t *privilege, bool enable)
446 {
447         HANDLE hToken;
448         LUID luid;
449         TOKEN_PRIVILEGES newState;
450         bool ret = FALSE;
451
452         if (!OpenProcessToken(GetCurrentProcess(),
453                               TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
454                               &hToken))
455                 goto out;
456
457         if (!LookupPrivilegeValue(NULL, privilege, &luid))
458                 goto out_close_handle;
459
460         newState.PrivilegeCount = 1;
461         newState.Privileges[0].Luid = luid;
462         newState.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0);
463         SetLastError(ERROR_SUCCESS);
464         ret = AdjustTokenPrivileges(hToken, FALSE, &newState, 0, NULL, NULL);
465         if (ret && GetLastError() == ERROR_NOT_ALL_ASSIGNED)
466                 ret = FALSE;
467 out_close_handle:
468         CloseHandle(hToken);
469 out:
470         return ret;
471 }
472
473 static bool
474 win32_modify_capture_privileges(bool enable)
475 {
476         return win32_modify_privilege(SE_BACKUP_NAME, enable)
477             && win32_modify_privilege(SE_SECURITY_NAME, enable);
478 }
479
480 static bool
481 win32_modify_apply_privileges(bool enable)
482 {
483         return win32_modify_privilege(SE_RESTORE_NAME, enable)
484             && win32_modify_privilege(SE_SECURITY_NAME, enable)
485             && win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable);
486 }
487
488 static void
489 win32_release_capture_and_apply_privileges(void)
490 {
491         win32_modify_capture_privileges(false);
492         win32_modify_apply_privileges(false);
493 }
494
495 HANDLE
496 win32_open_existing_file(const wchar_t *path, DWORD dwDesiredAccess)
497 {
498         return CreateFile(path,
499                           dwDesiredAccess,
500                           FILE_SHARE_READ,
501                           NULL, /* lpSecurityAttributes */
502                           OPEN_EXISTING,
503                           FILE_FLAG_BACKUP_SEMANTICS |
504                                 FILE_FLAG_OPEN_REPARSE_POINT,
505                           NULL /* hTemplateFile */);
506 }
507
508 /* Pointers to dynamically loaded functions  */
509
510 /* kernel32.dll:  Vista and later */
511 BOOL (WINAPI *func_CreateSymbolicLinkW)(const wchar_t *lpSymlinkFileName,
512                                         const wchar_t *lpTargetFileName,
513                                         DWORD dwFlags);
514
515 /* ntdll.dll  */
516
517 NTSTATUS (WINAPI *func_NtOpenFile) (PHANDLE FileHandle,
518                                     ACCESS_MASK DesiredAccess,
519                                     POBJECT_ATTRIBUTES ObjectAttributes,
520                                     PIO_STATUS_BLOCK IoStatusBlock,
521                                     ULONG ShareAccess,
522                                     ULONG OpenOptions);
523
524 NTSTATUS (WINAPI *func_NtReadFile) (HANDLE FileHandle,
525                                     HANDLE Event,
526                                     PIO_APC_ROUTINE ApcRoutine,
527                                     PVOID ApcContext,
528                                     PIO_STATUS_BLOCK IoStatusBlock,
529                                     PVOID Buffer,
530                                     ULONG Length,
531                                     PLARGE_INTEGER ByteOffset,
532                                     PULONG Key);
533
534 NTSTATUS (WINAPI *func_NtOpenFile) (PHANDLE FileHandle,
535                                     ACCESS_MASK DesiredAccess,
536                                     POBJECT_ATTRIBUTES ObjectAttributes,
537                                     PIO_STATUS_BLOCK IoStatusBlock,
538                                     ULONG ShareAccess,
539                                     ULONG OpenOptions);
540
541 NTSTATUS (WINAPI *func_NtQueryInformationFile)(HANDLE FileHandle,
542                                                PIO_STATUS_BLOCK IoStatusBlock,
543                                                PVOID FileInformation,
544                                                ULONG Length,
545                                                FILE_INFORMATION_CLASS FileInformationClass);
546
547 NTSTATUS (WINAPI *func_NtQuerySecurityObject)(HANDLE handle,
548                                               SECURITY_INFORMATION SecurityInformation,
549                                               PSECURITY_DESCRIPTOR SecurityDescriptor,
550                                               ULONG Length,
551                                               PULONG LengthNeeded);
552
553 NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle,
554                                               HANDLE Event,
555                                               PIO_APC_ROUTINE ApcRoutine,
556                                               PVOID ApcContext,
557                                               PIO_STATUS_BLOCK IoStatusBlock,
558                                               PVOID FileInformation,
559                                               ULONG Length,
560                                               FILE_INFORMATION_CLASS FileInformationClass,
561                                               BOOLEAN ReturnSingleEntry,
562                                               PUNICODE_STRING FileName,
563                                               BOOLEAN RestartScan);
564
565 NTSTATUS (WINAPI *func_NtQueryVolumeInformationFile) (HANDLE FileHandle,
566                                                       PIO_STATUS_BLOCK IoStatusBlock,
567                                                       PVOID FsInformation,
568                                                       ULONG Length,
569                                                       FS_INFORMATION_CLASS FsInformationClass);
570
571 NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle,
572                                             SECURITY_INFORMATION SecurityInformation,
573                                             PSECURITY_DESCRIPTOR SecurityDescriptor);
574
575 NTSTATUS (WINAPI *func_NtClose) (HANDLE Handle);
576
577 DWORD (WINAPI *func_RtlNtStatusToDosError)(NTSTATUS status);
578
579 NTSTATUS (WINAPI *func_RtlCreateSystemVolumeInformationFolder)
580                 (PCUNICODE_STRING VolumeRootPath);
581
582 static OSVERSIONINFO windows_version_info = {
583         .dwOSVersionInfoSize = sizeof(OSVERSIONINFO),
584 };
585
586 static bool acquired_privileges = false;
587
588 bool
589 windows_version_is_at_least(unsigned major, unsigned minor)
590 {
591         return windows_version_info.dwMajorVersion > major ||
592                 (windows_version_info.dwMajorVersion == major &&
593                  windows_version_info.dwMinorVersion >= minor);
594 }
595
596 struct dll_sym {
597         void **func_ptr;
598         const char *name;
599         bool required;
600 };
601
602 #define DLL_SYM(name, required) { (void **)&func_##name, #name, required }
603
604 #define for_each_sym(sym, spec) \
605         for ((sym) = (spec)->syms; (sym)->name; (sym)++)
606
607 struct dll_spec {
608         const wchar_t *name;
609         HMODULE handle;
610         const struct dll_sym syms[];
611 };
612
613 struct dll_spec ntdll_spec = {
614         .name = L"ntdll.dll",
615         .syms = {
616                 DLL_SYM(NtOpenFile, true),
617                 DLL_SYM(NtReadFile, true),
618                 DLL_SYM(NtQueryInformationFile, true),
619                 DLL_SYM(NtQuerySecurityObject, true),
620                 DLL_SYM(NtQueryDirectoryFile, true),
621                 DLL_SYM(NtQueryVolumeInformationFile, true),
622                 DLL_SYM(NtSetSecurityObject, true),
623                 DLL_SYM(NtClose, true),
624                 DLL_SYM(RtlNtStatusToDosError, true),
625                 DLL_SYM(RtlCreateSystemVolumeInformationFolder, false),
626                 {NULL, NULL},
627         },
628 };
629
630 struct dll_spec kernel32_spec = {
631         .name = L"kernel32.dll",
632         .syms = {
633                 DLL_SYM(CreateSymbolicLinkW, false),
634                 {NULL, NULL},
635         },
636 };
637
638 static int
639 init_dll(struct dll_spec *spec)
640 {
641         const struct dll_sym *sym;
642         void *addr;
643
644         if (!spec->handle)
645                 spec->handle = LoadLibrary(spec->name);
646         if (!spec->handle) {
647                 for_each_sym(sym, spec) {
648                         if (sym->required) {
649                                 ERROR("%ls could not be loaded!", spec->name);
650                                 return WIMLIB_ERR_UNSUPPORTED;
651                         }
652                 }
653                 return 0;
654         }
655         for_each_sym(sym, spec) {
656                 addr = (void *)GetProcAddress(spec->handle, sym->name);
657                 if (addr) {
658                         *(sym->func_ptr) = addr;
659                 } else if (sym->required) {
660                         ERROR("Can't find %s in %ls", sym->name, spec->name);
661                         return WIMLIB_ERR_UNSUPPORTED;
662                 }
663         }
664         return 0;
665 }
666
667 static void
668 cleanup_dll(struct dll_spec *spec)
669 {
670         const struct dll_sym *sym;
671
672         if (spec->handle) {
673                 FreeLibrary(spec->handle);
674                 spec->handle = NULL;
675
676                 for_each_sym(sym, spec)
677                         *(sym->func_ptr) = NULL;
678         }
679 }
680
681 /* One-time initialization for Windows capture/apply code.  */
682 int
683 win32_global_init(int init_flags)
684 {
685         int ret;
686
687         /* Try to acquire useful privileges.  */
688         if (!(init_flags & WIMLIB_INIT_FLAG_DONT_ACQUIRE_PRIVILEGES)) {
689                 ret = WIMLIB_ERR_INSUFFICIENT_PRIVILEGES;
690                 if (!win32_modify_capture_privileges(true))
691                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_CAPTURE_PRIVILEGES)
692                                 goto out_drop_privs;
693                 if (!win32_modify_apply_privileges(true))
694                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES)
695                                 goto out_drop_privs;
696                 acquired_privileges = true;
697         }
698
699         /* Get Windows version information.  */
700         GetVersionEx(&windows_version_info);
701
702         /* Try to dynamically load some functions.  */
703         ret = init_dll(&kernel32_spec);
704         if (ret)
705                 goto out_drop_privs;
706
707         ret = init_dll(&ntdll_spec);
708         if (ret)
709                 goto out_cleanup_kernel32;
710
711         return 0;
712
713 out_cleanup_kernel32:
714         cleanup_dll(&kernel32_spec);
715 out_drop_privs:
716         win32_release_capture_and_apply_privileges();
717         return ret;
718 }
719
720 void
721 win32_global_cleanup(void)
722 {
723         if (acquired_privileges)
724                 win32_release_capture_and_apply_privileges();
725
726         cleanup_dll(&kernel32_spec);
727         cleanup_dll(&ntdll_spec);
728 }
729
730 #endif /* __WIN32__ */