]> wimlib.net Git - wimlib/blob - src/win32_common.c
win32_common.c: Remove duplicate declaration of func_NtOpenFile
[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 void
306 set_errno_from_win32_error(DWORD err)
307 {
308         errno = win32_error_to_errno(err);
309 }
310
311 void
312 set_errno_from_GetLastError(void)
313 {
314         set_errno_from_win32_error(GetLastError());
315 }
316
317 void
318 set_errno_from_nt_status(NTSTATUS status)
319 {
320         set_errno_from_win32_error((*func_RtlNtStatusToDosError)(status));
321 }
322
323 static bool
324 win32_modify_privilege(const wchar_t *privilege, bool enable)
325 {
326         HANDLE hToken;
327         LUID luid;
328         TOKEN_PRIVILEGES newState;
329         bool ret = FALSE;
330
331         if (!OpenProcessToken(GetCurrentProcess(),
332                               TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
333                               &hToken))
334                 goto out;
335
336         if (!LookupPrivilegeValue(NULL, privilege, &luid))
337                 goto out_close_handle;
338
339         newState.PrivilegeCount = 1;
340         newState.Privileges[0].Luid = luid;
341         newState.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0);
342         SetLastError(ERROR_SUCCESS);
343         ret = AdjustTokenPrivileges(hToken, FALSE, &newState, 0, NULL, NULL);
344         if (ret && GetLastError() == ERROR_NOT_ALL_ASSIGNED)
345                 ret = FALSE;
346 out_close_handle:
347         CloseHandle(hToken);
348 out:
349         return ret;
350 }
351
352 static bool
353 win32_modify_capture_privileges(bool enable)
354 {
355         return win32_modify_privilege(SE_BACKUP_NAME, enable)
356             && win32_modify_privilege(SE_SECURITY_NAME, enable);
357 }
358
359 static bool
360 win32_modify_apply_privileges(bool enable)
361 {
362         return win32_modify_privilege(SE_RESTORE_NAME, enable)
363             && win32_modify_privilege(SE_SECURITY_NAME, enable)
364             && win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable);
365 }
366
367 static void
368 win32_release_capture_and_apply_privileges(void)
369 {
370         win32_modify_capture_privileges(false);
371         win32_modify_apply_privileges(false);
372 }
373
374 HANDLE
375 win32_open_existing_file(const wchar_t *path, DWORD dwDesiredAccess)
376 {
377         return CreateFile(path,
378                           dwDesiredAccess,
379                           FILE_SHARE_READ,
380                           NULL, /* lpSecurityAttributes */
381                           OPEN_EXISTING,
382                           FILE_FLAG_BACKUP_SEMANTICS |
383                                 FILE_FLAG_OPEN_REPARSE_POINT,
384                           NULL /* hTemplateFile */);
385 }
386
387 /* Pointers to dynamically loaded functions  */
388
389 /* kernel32.dll:  Vista and later */
390 BOOL (WINAPI *func_CreateSymbolicLinkW)(const wchar_t *lpSymlinkFileName,
391                                         const wchar_t *lpTargetFileName,
392                                         DWORD dwFlags);
393
394 /* ntdll.dll  */
395
396 NTSTATUS (WINAPI *func_NtOpenFile) (PHANDLE FileHandle,
397                                     ACCESS_MASK DesiredAccess,
398                                     POBJECT_ATTRIBUTES ObjectAttributes,
399                                     PIO_STATUS_BLOCK IoStatusBlock,
400                                     ULONG ShareAccess,
401                                     ULONG OpenOptions);
402
403 NTSTATUS (WINAPI *func_NtReadFile) (HANDLE FileHandle,
404                                     HANDLE Event,
405                                     PIO_APC_ROUTINE ApcRoutine,
406                                     PVOID ApcContext,
407                                     PIO_STATUS_BLOCK IoStatusBlock,
408                                     PVOID Buffer,
409                                     ULONG Length,
410                                     PLARGE_INTEGER ByteOffset,
411                                     PULONG Key);
412
413 NTSTATUS (WINAPI *func_NtQueryInformationFile)(HANDLE FileHandle,
414                                                PIO_STATUS_BLOCK IoStatusBlock,
415                                                PVOID FileInformation,
416                                                ULONG Length,
417                                                FILE_INFORMATION_CLASS FileInformationClass);
418
419 NTSTATUS (WINAPI *func_NtQuerySecurityObject)(HANDLE handle,
420                                               SECURITY_INFORMATION SecurityInformation,
421                                               PSECURITY_DESCRIPTOR SecurityDescriptor,
422                                               ULONG Length,
423                                               PULONG LengthNeeded);
424
425 NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle,
426                                               HANDLE Event,
427                                               PIO_APC_ROUTINE ApcRoutine,
428                                               PVOID ApcContext,
429                                               PIO_STATUS_BLOCK IoStatusBlock,
430                                               PVOID FileInformation,
431                                               ULONG Length,
432                                               FILE_INFORMATION_CLASS FileInformationClass,
433                                               BOOLEAN ReturnSingleEntry,
434                                               PUNICODE_STRING FileName,
435                                               BOOLEAN RestartScan);
436
437 NTSTATUS (WINAPI *func_NtQueryVolumeInformationFile) (HANDLE FileHandle,
438                                                       PIO_STATUS_BLOCK IoStatusBlock,
439                                                       PVOID FsInformation,
440                                                       ULONG Length,
441                                                       FS_INFORMATION_CLASS FsInformationClass);
442
443 NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle,
444                                             SECURITY_INFORMATION SecurityInformation,
445                                             PSECURITY_DESCRIPTOR SecurityDescriptor);
446
447 NTSTATUS (WINAPI *func_NtClose) (HANDLE Handle);
448
449 DWORD (WINAPI *func_RtlNtStatusToDosError)(NTSTATUS status);
450
451 NTSTATUS (WINAPI *func_RtlCreateSystemVolumeInformationFolder)
452                 (PCUNICODE_STRING VolumeRootPath);
453
454 static OSVERSIONINFO windows_version_info = {
455         .dwOSVersionInfoSize = sizeof(OSVERSIONINFO),
456 };
457
458 static bool acquired_privileges = false;
459
460 bool
461 windows_version_is_at_least(unsigned major, unsigned minor)
462 {
463         return windows_version_info.dwMajorVersion > major ||
464                 (windows_version_info.dwMajorVersion == major &&
465                  windows_version_info.dwMinorVersion >= minor);
466 }
467
468 struct dll_sym {
469         void **func_ptr;
470         const char *name;
471         bool required;
472 };
473
474 #define DLL_SYM(name, required) { (void **)&func_##name, #name, required }
475
476 #define for_each_sym(sym, spec) \
477         for ((sym) = (spec)->syms; (sym)->name; (sym)++)
478
479 struct dll_spec {
480         const wchar_t *name;
481         HMODULE handle;
482         const struct dll_sym syms[];
483 };
484
485 struct dll_spec ntdll_spec = {
486         .name = L"ntdll.dll",
487         .syms = {
488                 DLL_SYM(NtOpenFile, true),
489                 DLL_SYM(NtReadFile, true),
490                 DLL_SYM(NtQueryInformationFile, true),
491                 DLL_SYM(NtQuerySecurityObject, true),
492                 DLL_SYM(NtQueryDirectoryFile, true),
493                 DLL_SYM(NtQueryVolumeInformationFile, true),
494                 DLL_SYM(NtSetSecurityObject, true),
495                 DLL_SYM(NtClose, true),
496                 DLL_SYM(RtlNtStatusToDosError, true),
497                 DLL_SYM(RtlCreateSystemVolumeInformationFolder, false),
498                 {NULL, NULL},
499         },
500 };
501
502 struct dll_spec kernel32_spec = {
503         .name = L"kernel32.dll",
504         .syms = {
505                 DLL_SYM(CreateSymbolicLinkW, false),
506                 {NULL, NULL},
507         },
508 };
509
510 static int
511 init_dll(struct dll_spec *spec)
512 {
513         const struct dll_sym *sym;
514         void *addr;
515
516         if (!spec->handle)
517                 spec->handle = LoadLibrary(spec->name);
518         if (!spec->handle) {
519                 for_each_sym(sym, spec) {
520                         if (sym->required) {
521                                 ERROR("%ls could not be loaded!", spec->name);
522                                 return WIMLIB_ERR_UNSUPPORTED;
523                         }
524                 }
525                 return 0;
526         }
527         for_each_sym(sym, spec) {
528                 addr = (void *)GetProcAddress(spec->handle, sym->name);
529                 if (addr) {
530                         *(sym->func_ptr) = addr;
531                 } else if (sym->required) {
532                         ERROR("Can't find %s in %ls", sym->name, spec->name);
533                         return WIMLIB_ERR_UNSUPPORTED;
534                 }
535         }
536         return 0;
537 }
538
539 static void
540 cleanup_dll(struct dll_spec *spec)
541 {
542         const struct dll_sym *sym;
543
544         if (spec->handle) {
545                 FreeLibrary(spec->handle);
546                 spec->handle = NULL;
547
548                 for_each_sym(sym, spec)
549                         *(sym->func_ptr) = NULL;
550         }
551 }
552
553 /* One-time initialization for Windows capture/apply code.  */
554 int
555 win32_global_init(int init_flags)
556 {
557         int ret;
558
559         /* Try to acquire useful privileges.  */
560         if (!(init_flags & WIMLIB_INIT_FLAG_DONT_ACQUIRE_PRIVILEGES)) {
561                 ret = WIMLIB_ERR_INSUFFICIENT_PRIVILEGES;
562                 if (!win32_modify_capture_privileges(true))
563                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_CAPTURE_PRIVILEGES)
564                                 goto out_drop_privs;
565                 if (!win32_modify_apply_privileges(true))
566                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES)
567                                 goto out_drop_privs;
568                 acquired_privileges = true;
569         }
570
571         /* Get Windows version information.  */
572         GetVersionEx(&windows_version_info);
573
574         /* Try to dynamically load some functions.  */
575         ret = init_dll(&kernel32_spec);
576         if (ret)
577                 goto out_drop_privs;
578
579         ret = init_dll(&ntdll_spec);
580         if (ret)
581                 goto out_cleanup_kernel32;
582
583         return 0;
584
585 out_cleanup_kernel32:
586         cleanup_dll(&kernel32_spec);
587 out_drop_privs:
588         win32_release_capture_and_apply_privileges();
589         return ret;
590 }
591
592 void
593 win32_global_cleanup(void)
594 {
595         if (acquired_privileges)
596                 win32_release_capture_and_apply_privileges();
597
598         cleanup_dll(&kernel32_spec);
599         cleanup_dll(&ntdll_spec);
600 }
601
602 #endif /* __WIN32__ */