win32_apply.c: Fallback to RtlDosPathNameToNtPathName_U()
[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 /* Pointers to dynamically loaded functions  */
375
376 /* ntdll.dll  */
377
378 NTSTATUS (WINAPI *func_NtCreateFile)(PHANDLE FileHandle,
379                                      ACCESS_MASK DesiredAccess,
380                                      POBJECT_ATTRIBUTES ObjectAttributes,
381                                      PIO_STATUS_BLOCK IoStatusBlock,
382                                      PLARGE_INTEGER AllocationSize,
383                                      ULONG FileAttributes,
384                                      ULONG ShareAccess,
385                                      ULONG CreateDisposition,
386                                      ULONG CreateOptions,
387                                      PVOID EaBuffer,
388                                      ULONG EaLength);
389
390 NTSTATUS (WINAPI *func_NtOpenFile) (PHANDLE FileHandle,
391                                     ACCESS_MASK DesiredAccess,
392                                     POBJECT_ATTRIBUTES ObjectAttributes,
393                                     PIO_STATUS_BLOCK IoStatusBlock,
394                                     ULONG ShareAccess,
395                                     ULONG OpenOptions);
396
397 NTSTATUS (WINAPI *func_NtReadFile) (HANDLE FileHandle,
398                                     HANDLE Event,
399                                     PIO_APC_ROUTINE ApcRoutine,
400                                     PVOID ApcContext,
401                                     PIO_STATUS_BLOCK IoStatusBlock,
402                                     PVOID Buffer,
403                                     ULONG Length,
404                                     PLARGE_INTEGER ByteOffset,
405                                     PULONG Key);
406
407 NTSTATUS (WINAPI *func_NtWriteFile) (HANDLE FileHandle,
408                                      HANDLE Event,
409                                      PIO_APC_ROUTINE ApcRoutine,
410                                      PVOID ApcContext,
411                                      PIO_STATUS_BLOCK IoStatusBlock,
412                                      PVOID Buffer,
413                                      ULONG Length,
414                                      PLARGE_INTEGER ByteOffset,
415                                      PULONG Key);
416
417 NTSTATUS (WINAPI *func_NtQueryInformationFile)(HANDLE FileHandle,
418                                                PIO_STATUS_BLOCK IoStatusBlock,
419                                                PVOID FileInformation,
420                                                ULONG Length,
421                                                FILE_INFORMATION_CLASS FileInformationClass);
422
423 NTSTATUS (WINAPI *func_NtQuerySecurityObject)(HANDLE handle,
424                                               SECURITY_INFORMATION SecurityInformation,
425                                               PSECURITY_DESCRIPTOR SecurityDescriptor,
426                                               ULONG Length,
427                                               PULONG LengthNeeded);
428
429 NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle,
430                                               HANDLE Event,
431                                               PIO_APC_ROUTINE ApcRoutine,
432                                               PVOID ApcContext,
433                                               PIO_STATUS_BLOCK IoStatusBlock,
434                                               PVOID FileInformation,
435                                               ULONG Length,
436                                               FILE_INFORMATION_CLASS FileInformationClass,
437                                               BOOLEAN ReturnSingleEntry,
438                                               PUNICODE_STRING FileName,
439                                               BOOLEAN RestartScan);
440
441 NTSTATUS (WINAPI *func_NtQueryVolumeInformationFile) (HANDLE FileHandle,
442                                                       PIO_STATUS_BLOCK IoStatusBlock,
443                                                       PVOID FsInformation,
444                                                       ULONG Length,
445                                                       FS_INFORMATION_CLASS FsInformationClass);
446
447 NTSTATUS (WINAPI *func_NtSetInformationFile)(HANDLE FileHandle,
448                                              PIO_STATUS_BLOCK IoStatusBlock,
449                                              PVOID FileInformation,
450                                              ULONG Length,
451                                              FILE_INFORMATION_CLASS FileInformationClass);
452
453 NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle,
454                                             SECURITY_INFORMATION SecurityInformation,
455                                             PSECURITY_DESCRIPTOR SecurityDescriptor);
456
457 NTSTATUS (WINAPI *func_NtFsControlFile) (HANDLE FileHandle,
458                                          HANDLE Event,
459                                          PIO_APC_ROUTINE ApcRoutine,
460                                          PVOID ApcContext,
461                                          PIO_STATUS_BLOCK IoStatusBlock,
462                                          ULONG FsControlCode,
463                                          PVOID InputBuffer,
464                                          ULONG InputBufferLength,
465                                          PVOID OutputBuffer,
466                                          ULONG OutputBufferLength);
467
468 NTSTATUS (WINAPI *func_NtClose) (HANDLE Handle);
469
470 DWORD (WINAPI *func_RtlNtStatusToDosError)(NTSTATUS status);
471
472 BOOLEAN (WINAPI *func_RtlDosPathNameToNtPathName_U)
473                   (IN PCWSTR DosName,
474                    OUT PUNICODE_STRING NtName,
475                    OUT PCWSTR *PartName,
476                    OUT PRTL_RELATIVE_NAME_U RelativeName);
477
478 NTSTATUS (WINAPI *func_RtlDosPathNameToNtPathName_U_WithStatus)
479                 (IN PCWSTR DosName,
480                  OUT PUNICODE_STRING NtName,
481                  OUT PCWSTR *PartName,
482                  OUT PRTL_RELATIVE_NAME_U RelativeName);
483
484 NTSTATUS (WINAPI *func_RtlCreateSystemVolumeInformationFolder)
485                 (PCUNICODE_STRING VolumeRootPath);
486
487 static OSVERSIONINFO windows_version_info = {
488         .dwOSVersionInfoSize = sizeof(OSVERSIONINFO),
489 };
490
491 static bool acquired_privileges = false;
492
493 bool
494 windows_version_is_at_least(unsigned major, unsigned minor)
495 {
496         return windows_version_info.dwMajorVersion > major ||
497                 (windows_version_info.dwMajorVersion == major &&
498                  windows_version_info.dwMinorVersion >= minor);
499 }
500
501 struct dll_sym {
502         void **func_ptr;
503         const char *name;
504         bool required;
505 };
506
507 #define DLL_SYM(name, required) { (void **)&func_##name, #name, required }
508
509 #define for_each_sym(sym, spec) \
510         for ((sym) = (spec)->syms; (sym)->name; (sym)++)
511
512 struct dll_spec {
513         const wchar_t *name;
514         HMODULE handle;
515         const struct dll_sym syms[];
516 };
517
518 struct dll_spec ntdll_spec = {
519         .name = L"ntdll.dll",
520         .syms = {
521                 DLL_SYM(NtCreateFile, true),
522                 DLL_SYM(NtOpenFile, true),
523                 DLL_SYM(NtReadFile, true),
524                 DLL_SYM(NtWriteFile, true),
525                 DLL_SYM(NtQueryInformationFile, true),
526                 DLL_SYM(NtQuerySecurityObject, true),
527                 DLL_SYM(NtQueryDirectoryFile, true),
528                 DLL_SYM(NtQueryVolumeInformationFile, true),
529                 DLL_SYM(NtSetInformationFile, true),
530                 DLL_SYM(NtSetSecurityObject, true),
531                 DLL_SYM(NtFsControlFile, true),
532                 DLL_SYM(NtClose, true),
533                 DLL_SYM(RtlNtStatusToDosError, true),
534                 DLL_SYM(RtlCreateSystemVolumeInformationFolder, false),
535                 DLL_SYM(RtlDosPathNameToNtPathName_U, true),
536                 DLL_SYM(RtlDosPathNameToNtPathName_U_WithStatus, false), /* Not present on XP  */
537                 {NULL, NULL},
538         },
539 };
540
541 static int
542 init_dll(struct dll_spec *spec)
543 {
544         const struct dll_sym *sym;
545         void *addr;
546
547         if (!spec->handle)
548                 spec->handle = LoadLibrary(spec->name);
549         if (!spec->handle) {
550                 for_each_sym(sym, spec) {
551                         if (sym->required) {
552                                 ERROR("%ls could not be loaded!", spec->name);
553                                 return WIMLIB_ERR_UNSUPPORTED;
554                         }
555                 }
556                 return 0;
557         }
558         for_each_sym(sym, spec) {
559                 addr = (void *)GetProcAddress(spec->handle, sym->name);
560                 if (addr) {
561                         *(sym->func_ptr) = addr;
562                 } else if (sym->required) {
563                         ERROR("Can't find %s in %ls", sym->name, spec->name);
564                         return WIMLIB_ERR_UNSUPPORTED;
565                 }
566         }
567         return 0;
568 }
569
570 static void
571 cleanup_dll(struct dll_spec *spec)
572 {
573         const struct dll_sym *sym;
574
575         if (spec->handle) {
576                 FreeLibrary(spec->handle);
577                 spec->handle = NULL;
578
579                 for_each_sym(sym, spec)
580                         *(sym->func_ptr) = NULL;
581         }
582 }
583
584 /* One-time initialization for Windows capture/apply code.  */
585 int
586 win32_global_init(int init_flags)
587 {
588         int ret;
589
590         /* Try to acquire useful privileges.  */
591         if (!(init_flags & WIMLIB_INIT_FLAG_DONT_ACQUIRE_PRIVILEGES)) {
592                 ret = WIMLIB_ERR_INSUFFICIENT_PRIVILEGES;
593                 if (!win32_modify_capture_privileges(true))
594                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_CAPTURE_PRIVILEGES)
595                                 goto out_drop_privs;
596                 if (!win32_modify_apply_privileges(true))
597                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES)
598                                 goto out_drop_privs;
599                 acquired_privileges = true;
600         }
601
602         /* Get Windows version information.  */
603         GetVersionEx(&windows_version_info);
604
605         ret = init_dll(&ntdll_spec);
606         if (ret)
607                 goto out_drop_privs;
608
609         return 0;
610
611 out_drop_privs:
612         win32_release_capture_and_apply_privileges();
613         return ret;
614 }
615
616 void
617 win32_global_cleanup(void)
618 {
619         if (acquired_privileges)
620                 win32_release_capture_and_apply_privileges();
621
622         cleanup_dll(&ntdll_spec);
623 }
624
625 #endif /* __WIN32__ */