]> wimlib.net Git - wimlib/blob - src/win32_apply.c
read_wim_header(): Check return value of lseek()
[wimlib] / src / win32_apply.c
1 /*
2  * win32_apply.c - Windows-specific code for applying files from a WIM image.
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 "wimlib/win32_common.h"
31
32 #include "wimlib/apply.h"
33 #include "wimlib/capture.h" /* for mangle_pat() and match_pattern_list()  */
34 #include "wimlib/dentry.h"
35 #include "wimlib/error.h"
36 #include "wimlib/lookup_table.h"
37 #include "wimlib/metadata.h"
38 #include "wimlib/reparse.h"
39 #include "wimlib/textfile.h"
40 #include "wimlib/xml.h"
41 #include "wimlib/wimboot.h"
42
43 struct win32_apply_ctx {
44
45         /* Extract flags, the pointer to the WIMStruct, etc.  */
46         struct apply_ctx common;
47
48         /* WIMBoot information, only filled in if WIMLIB_EXTRACT_FLAG_WIMBOOT
49          * was provided  */
50         struct {
51                 u64 data_source_id;
52                 struct string_set *prepopulate_pats;
53                 void *mem_prepopulate_pats;
54                 u8 wim_lookup_table_hash[SHA1_HASH_SIZE];
55                 bool wof_running;
56         } wimboot;
57
58         /* Open handle to the target directory  */
59         HANDLE h_target;
60
61         /* NT namespace path to the target directory (buffer allocated)  */
62         UNICODE_STRING target_ntpath;
63
64         /* Temporary buffer for building paths (buffer allocated)  */
65         UNICODE_STRING pathbuf;
66
67         /* Object attributes to reuse for opening files in the target directory.
68          * (attr.ObjectName == &pathbuf) and (attr.RootDirectory == h_target).
69          */
70         OBJECT_ATTRIBUTES attr;
71
72         /* Temporary I/O status block for system calls  */
73         IO_STATUS_BLOCK iosb;
74
75         /* Allocated buffer for creating "printable" paths from our
76          * target-relative NT paths  */
77         wchar_t *print_buffer;
78
79         /* Allocated buffer for reading stream data when it cannot be extracted
80          * directly  */
81         u8 *data_buffer;
82
83         /* Pointer to the next byte in @data_buffer to fill  */
84         u8 *data_buffer_ptr;
85
86         /* Size allocated in @data_buffer  */
87         size_t data_buffer_size;
88
89         /* Current offset in the raw encrypted file being written  */
90         size_t encrypted_offset;
91
92         /* Current size of the raw encrypted file being written  */
93         size_t encrypted_size;
94
95         /* Temporary buffer for reparse data  */
96         struct reparse_buffer_disk rpbuf;
97
98         /* Temporary buffer for reparse data of "fixed" absolute symbolic links
99          * and junctions  */
100         struct reparse_buffer_disk rpfixbuf;
101
102         /* Array of open handles to filesystem streams currently being written
103          */
104         HANDLE open_handles[MAX_OPEN_STREAMS];
105
106         /* Number of handles in @open_handles currently open (filled in from the
107          * beginning of the array)  */
108         unsigned num_open_handles;
109
110         /* List of dentries, joined by @tmp_list, that need to have reparse data
111          * extracted as soon as the whole stream has been read into
112          * @data_buffer.  */
113         struct list_head reparse_dentries;
114
115         /* List of dentries, joined by @tmp_list, that need to have raw
116          * encrypted data extracted as soon as the whole stream has been read
117          * into @data_buffer.  */
118         struct list_head encrypted_dentries;
119
120         /* Number of files for which we didn't have permission to set the full
121          * security descriptor.  */
122         unsigned long partial_security_descriptors;
123
124         /* Number of files for which we didn't have permission to set any part
125          * of the security descriptor.  */
126         unsigned long no_security_descriptors;
127 };
128
129 /* Get the drive letter from a Windows path, or return the null character if the
130  * path is relative.  */
131 static wchar_t
132 get_drive_letter(const wchar_t *path)
133 {
134         /* Skip \\?\ prefix  */
135         if (!wcsncmp(path, L"\\\\?\\", 4))
136                 path += 4;
137
138         /* Return drive letter if valid  */
139         if (((path[0] >= L'a' && path[0] <= L'z') ||
140              (path[0] >= L'A' && path[0] <= L'Z')) && path[1] == L':')
141                 return path[0];
142
143         return L'\0';
144 }
145
146 static void
147 get_vol_flags(const wchar_t *target, DWORD *vol_flags_ret,
148               bool *short_names_supported_ret)
149 {
150         wchar_t filesystem_name[MAX_PATH + 1];
151         wchar_t drive[4];
152         wchar_t *volume = NULL;
153
154         *vol_flags_ret = 0;
155         *short_names_supported_ret = false;
156
157         drive[0] = get_drive_letter(target);
158         if (drive[0]) {
159                 drive[1] = L':';
160                 drive[2] = L'\\';
161                 drive[3] = L'\0';
162                 volume = drive;
163         }
164
165         if (!GetVolumeInformation(volume, NULL, 0, NULL, NULL,
166                                   vol_flags_ret, filesystem_name,
167                                   ARRAY_LEN(filesystem_name)))
168         {
169                 DWORD err = GetLastError();
170                 set_errno_from_win32_error(err);
171                 WARNING_WITH_ERRNO("Failed to get volume information for "
172                                    "\"%ls\" (err=%"PRIu32")",
173                                    target, (u32)err);
174                 return;
175         }
176
177         if (wcsstr(filesystem_name, L"NTFS")) {
178                 /* FILE_SUPPORTS_HARD_LINKS is only supported on Windows 7 and
179                  * later.  Force it on anyway if filesystem is NTFS.  */
180                 *vol_flags_ret |= FILE_SUPPORTS_HARD_LINKS;
181
182                 /* There's no volume flag for short names, but according to the
183                  * MS documentation they are only user-settable on NTFS.  */
184                 *short_names_supported_ret = true;
185         }
186 }
187
188 static int
189 win32_get_supported_features(const wchar_t *target,
190                              struct wim_features *supported_features)
191 {
192         DWORD vol_flags;
193         bool short_names_supported;
194
195         /* Query the features of the target volume.  */
196
197         get_vol_flags(target, &vol_flags, &short_names_supported);
198
199         supported_features->archive_files = 1;
200         supported_features->hidden_files = 1;
201         supported_features->system_files = 1;
202
203         if (vol_flags & FILE_FILE_COMPRESSION)
204                 supported_features->compressed_files = 1;
205
206         if (vol_flags & FILE_SUPPORTS_ENCRYPTION) {
207                 supported_features->encrypted_files = 1;
208                 supported_features->encrypted_directories = 1;
209         }
210
211         supported_features->not_context_indexed_files = 1;
212
213         /* Don't do anything with FILE_SUPPORTS_SPARSE_FILES.  */
214
215         if (vol_flags & FILE_NAMED_STREAMS)
216                 supported_features->named_data_streams = 1;
217
218         if (vol_flags & FILE_SUPPORTS_HARD_LINKS)
219                 supported_features->hard_links = 1;
220
221         if (vol_flags & FILE_SUPPORTS_REPARSE_POINTS)
222                 supported_features->reparse_points = 1;
223
224         if (vol_flags & FILE_PERSISTENT_ACLS)
225                 supported_features->security_descriptors = 1;
226
227         if (short_names_supported)
228                 supported_features->short_names = 1;
229
230         supported_features->timestamps = 1;
231
232         /* Note: Windows does not support case sensitive filenames!  At least
233          * not without changing the registry and rebooting...  */
234
235         return 0;
236 }
237
238 /* Load the patterns from [PrepopulateList] of WimBootCompress.ini in the WIM
239  * image being extracted.  */
240 static int
241 load_prepopulate_pats(struct win32_apply_ctx *ctx)
242 {
243         const wchar_t *path = L"\\Windows\\System32\\WimBootCompress.ini";
244         struct wim_dentry *dentry;
245         struct wim_lookup_table_entry *lte;
246         int ret;
247         void *buf;
248         struct string_set *s;
249         void *mem;
250         struct text_file_section sec;
251
252         dentry = get_dentry(ctx->common.wim, path, WIMLIB_CASE_INSENSITIVE);
253         if (!dentry ||
254             (dentry->d_inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
255                                               FILE_ATTRIBUTE_REPARSE_POINT |
256                                               FILE_ATTRIBUTE_ENCRYPTED)) ||
257             !(lte = inode_unnamed_lte(dentry->d_inode, ctx->common.wim->lookup_table)))
258         {
259                 WARNING("%ls does not exist in WIM image!", path);
260                 return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
261         }
262
263         ret = read_full_stream_into_alloc_buf(lte, &buf);
264         if (ret)
265                 return ret;
266
267         s = CALLOC(1, sizeof(struct string_set));
268         if (!s) {
269                 FREE(buf);
270                 return WIMLIB_ERR_NOMEM;
271         }
272
273         sec.name = T("PrepopulateList");
274         sec.strings = s;
275
276         ret = do_load_text_file(path, buf, lte->size, &mem, &sec, 1,
277                                 LOAD_TEXT_FILE_REMOVE_QUOTES |
278                                         LOAD_TEXT_FILE_NO_WARNINGS,
279                                 mangle_pat);
280         BUILD_BUG_ON(OS_PREFERRED_PATH_SEPARATOR != WIM_PATH_SEPARATOR);
281         FREE(buf);
282         if (ret) {
283                 FREE(s);
284                 return ret;
285         }
286         ctx->wimboot.prepopulate_pats = s;
287         ctx->wimboot.mem_prepopulate_pats = mem;
288         return 0;
289 }
290
291 /* Returns %true if the path to @dentry matches a pattern in [PrepopulateList]
292  * of WimBootCompress.ini.  Otherwise returns %false.
293  *
294  * @dentry must have had its full path calculated.  */
295 static bool
296 in_prepopulate_list(struct wim_dentry *dentry,
297                     const struct win32_apply_ctx *ctx)
298 {
299         const struct string_set *pats = ctx->wimboot.prepopulate_pats;
300
301         if (!pats || !pats->num_strings)
302                 return false;
303
304         return match_pattern_list(dentry->_full_path,
305                                   wcslen(dentry->_full_path), pats);
306 }
307
308 /* Calculates the SHA-1 message digest of the WIM's lookup table.  */
309 static int
310 hash_lookup_table(WIMStruct *wim, u8 hash[SHA1_HASH_SIZE])
311 {
312         return wim_reshdr_to_hash(&wim->hdr.lookup_table_reshdr, wim, hash);
313 }
314
315 /* Prepare for doing a "WIMBoot" extraction by loading patterns from
316  * [PrepopulateList] of WimBootCompress.ini and allocating a WOF data source ID
317  * on the target volume.  */
318 static int
319 start_wimboot_extraction(struct win32_apply_ctx *ctx)
320 {
321         int ret;
322         WIMStruct *wim = ctx->common.wim;
323
324         ret = load_prepopulate_pats(ctx);
325         if (ret == WIMLIB_ERR_NOMEM)
326                 return ret;
327
328         if (!wim_info_get_wimboot(wim->wim_info, wim->current_image))
329                 WARNING("Image is not marked as WIMBoot compatible!");
330
331         ret = hash_lookup_table(ctx->common.wim,
332                                 ctx->wimboot.wim_lookup_table_hash);
333         if (ret)
334                 return ret;
335
336         /* TODO: DISM seems to set HKEY_LOCAL_MACHINE\SOFTWARE\Setup
337          * "WimBoot"=dword:00000001 in the registry of the extracted image.  Do
338          * we need to do this too?  I'd really prefer not to be mucking around
339          * with the extracted files, and certainly not the registry...
340          *
341          * It changed two other keys as well:
342          *
343          * [HKEY_LOCAL_MACHINE\SOFTWARE\ControlSet001\Control\ProductOptions]
344          *         value "ProductPolicy"
345          *
346          * [HKEY_LOCAL_MACHINE\SOFTWARE\ControlSet001\Control\SessionManager\AppCompatCache]
347          *         value "AppCompatCache"
348          */
349
350         return wimboot_alloc_data_source_id(wim->filename,
351                                             wim->hdr.guid,
352                                             wim->current_image,
353                                             ctx->common.target,
354                                             &ctx->wimboot.data_source_id,
355                                             &ctx->wimboot.wof_running);
356 }
357
358 /* Returns the number of wide characters needed to represent the path to the
359  * specified @dentry, relative to the target directory, when extracted.
360  *
361  * Does not include null terminator (not needed for NtCreateFile).  */
362 static size_t
363 dentry_extraction_path_length(const struct wim_dentry *dentry)
364 {
365         size_t len = 0;
366         const struct wim_dentry *d;
367
368         d = dentry;
369         do {
370                 len += d->d_extraction_name_nchars + 1;
371                 d = d->d_parent;
372         } while (!dentry_is_root(d) && will_extract_dentry(d));
373
374         return --len;  /* No leading slash  */
375 }
376
377 /* Returns the length of the longest string that might need to be appended to
378  * the path to an alias of an inode to open or create a named data stream.
379  *
380  * If the inode has no named data streams, this will be 0.  Otherwise, this will
381  * be 1 plus the length of the longest-named data stream, since the data stream
382  * name must be separated from the path by the ':' character.  */
383 static size_t
384 inode_longest_named_data_stream_spec(const struct wim_inode *inode)
385 {
386         size_t max = 0;
387         for (u16 i = 0; i < inode->i_num_ads; i++) {
388                 size_t len = inode->i_ads_entries[i].stream_name_nbytes;
389                 if (len > max)
390                         max = len;
391         }
392         if (max)
393                 max = 1 + (max / sizeof(wchar_t));
394         return max;
395 }
396
397 /* Find the length, in wide characters, of the longest path needed for
398  * extraction of any file in @dentry_list relative to the target directory.
399  *
400  * Accounts for named data streams, but does not include null terminator (not
401  * needed for NtCreateFile).  */
402 static size_t
403 compute_path_max(struct list_head *dentry_list)
404 {
405         size_t max = 0;
406         const struct wim_dentry *dentry;
407
408         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
409                 size_t len;
410
411                 len = dentry_extraction_path_length(dentry);
412
413                 /* Account for named data streams  */
414                 len += inode_longest_named_data_stream_spec(dentry->d_inode);
415
416                 if (len > max)
417                         max = len;
418         }
419
420         return max;
421 }
422
423 /* Build the path at which to extract the @dentry, relative to the target
424  * directory.
425  *
426  * The path is saved in ctx->pathbuf.  */
427 static void
428 build_extraction_path(const struct wim_dentry *dentry,
429                       struct win32_apply_ctx *ctx)
430 {
431         size_t len;
432         wchar_t *p;
433         const struct wim_dentry *d;
434
435         len = dentry_extraction_path_length(dentry);
436
437         ctx->pathbuf.Length = len * sizeof(wchar_t);
438         p = ctx->pathbuf.Buffer + len;
439         for (d = dentry;
440              !dentry_is_root(d->d_parent) && will_extract_dentry(d->d_parent);
441              d = d->d_parent)
442         {
443                 p -= d->d_extraction_name_nchars;
444                 wmemcpy(p, d->d_extraction_name, d->d_extraction_name_nchars);
445                 *--p = '\\';
446         }
447         /* No leading slash  */
448         p -= d->d_extraction_name_nchars;
449         wmemcpy(p, d->d_extraction_name, d->d_extraction_name_nchars);
450 }
451
452 /* Build the path at which to extract the @dentry, relative to the target
453  * directory, adding the suffix for a named data stream.
454  *
455  * The path is saved in ctx->pathbuf.  */
456 static void
457 build_extraction_path_with_ads(const struct wim_dentry *dentry,
458                                struct win32_apply_ctx *ctx,
459                                const wchar_t *stream_name,
460                                size_t stream_name_nchars)
461 {
462         wchar_t *p;
463
464         build_extraction_path(dentry, ctx);
465
466         /* Add :NAME for named data stream  */
467         p = ctx->pathbuf.Buffer + (ctx->pathbuf.Length / sizeof(wchar_t));
468         *p++ = L':';
469         wmemcpy(p, stream_name, stream_name_nchars);
470         ctx->pathbuf.Length += (1 + stream_name_nchars) * sizeof(wchar_t);
471 }
472
473 /* Build the Win32 namespace path to the specified @dentry when extracted.
474  *
475  * The path is saved in ctx->pathbuf and will be null terminated.
476  *
477  * XXX: We could get rid of this if it wasn't needed for the file encryption
478  * APIs.  */
479 static void
480 build_win32_extraction_path(const struct wim_dentry *dentry,
481                             struct win32_apply_ctx *ctx)
482 {
483         build_extraction_path(dentry, ctx);
484
485         /* Prepend target_ntpath to our relative path, then change \??\ into \\?\  */
486
487         memmove(ctx->pathbuf.Buffer +
488                         (ctx->target_ntpath.Length / sizeof(wchar_t)) + 1,
489                 ctx->pathbuf.Buffer, ctx->pathbuf.Length);
490         memcpy(ctx->pathbuf.Buffer, ctx->target_ntpath.Buffer,
491                 ctx->target_ntpath.Length);
492         ctx->pathbuf.Buffer[ctx->target_ntpath.Length / sizeof(wchar_t)] = L'\\';
493         ctx->pathbuf.Length += ctx->target_ntpath.Length + sizeof(wchar_t);
494         ctx->pathbuf.Buffer[ctx->pathbuf.Length / sizeof(wchar_t)] = L'\0';
495
496         wimlib_assert(ctx->pathbuf.Length >= 4 * sizeof(wchar_t) &&
497                       !wmemcmp(ctx->pathbuf.Buffer, L"\\??\\", 4));
498
499         ctx->pathbuf.Buffer[1] = L'\\';
500
501 }
502
503 /* Returns a "printable" representation of the last relative NT path that was
504  * constructed with build_extraction_path() or build_extraction_path_with_ads().
505  *
506  * This will be overwritten by the next call to this function.  */
507 static const wchar_t *
508 current_path(struct win32_apply_ctx *ctx)
509 {
510         wchar_t *p = ctx->print_buffer;
511
512         p = wmempcpy(p, ctx->common.target, ctx->common.target_nchars);
513         *p++ = L'\\';
514         p = wmempcpy(p, ctx->pathbuf.Buffer, ctx->pathbuf.Length / sizeof(wchar_t));
515         *p = L'\0';
516         return ctx->print_buffer;
517 }
518
519 /*
520  * Ensures the target directory exists and opens a handle to it, in preparation
521  * of using paths relative to it.
522  */
523 static int
524 prepare_target(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
525 {
526         int ret;
527         NTSTATUS status;
528         size_t path_max;
529
530         /* Open handle to the target directory (possibly creating it).  */
531
532         ret = win32_path_to_nt_path(ctx->common.target, &ctx->target_ntpath);
533         if (ret)
534                 return ret;
535
536         ctx->attr.Length = sizeof(ctx->attr);
537         ctx->attr.ObjectName = &ctx->target_ntpath;
538
539         status = (*func_NtCreateFile)(&ctx->h_target,
540                                       FILE_TRAVERSE,
541                                       &ctx->attr,
542                                       &ctx->iosb,
543                                       NULL,
544                                       0,
545                                       FILE_SHARE_VALID_FLAGS,
546                                       FILE_OPEN_IF,
547                                       FILE_DIRECTORY_FILE |
548                                               FILE_OPEN_REPARSE_POINT |
549                                               FILE_OPEN_FOR_BACKUP_INTENT,
550                                       NULL,
551                                       0);
552
553         if (!NT_SUCCESS(status)) {
554                 set_errno_from_nt_status(status);
555                 ERROR_WITH_ERRNO("Can't open or create directory \"%ls\" "
556                                  "(status=0x%08"PRIx32")",
557                                  ctx->common.target, (u32)status);
558                 return WIMLIB_ERR_OPENDIR;
559         }
560
561         path_max = compute_path_max(dentry_list);
562
563         /* Add some extra for building Win32 paths for the file encryption APIs
564          * ...  */
565         path_max += 2 + (ctx->target_ntpath.Length / sizeof(wchar_t));
566
567         ctx->pathbuf.MaximumLength = path_max * sizeof(wchar_t);
568         ctx->pathbuf.Buffer = MALLOC(ctx->pathbuf.MaximumLength);
569         if (!ctx->pathbuf.Buffer)
570                 return WIMLIB_ERR_NOMEM;
571
572         ctx->attr.RootDirectory = ctx->h_target;
573         ctx->attr.ObjectName = &ctx->pathbuf;
574
575         ctx->print_buffer = MALLOC((ctx->common.target_nchars + 1 + path_max + 1) *
576                                    sizeof(wchar_t));
577         if (!ctx->print_buffer)
578                 return WIMLIB_ERR_NOMEM;
579
580         return 0;
581 }
582
583 /* When creating an inode that will have a short (DOS) name, we create it using
584  * the long name associated with the short name.  This ensures that the short
585  * name gets associated with the correct long name.  */
586 static const struct wim_dentry *
587 first_extraction_alias(const struct wim_inode *inode)
588 {
589         const struct list_head *next = inode->i_extraction_aliases.next;
590         const struct wim_dentry *dentry;
591
592         do {
593                 dentry = list_entry(next, struct wim_dentry,
594                                     d_extraction_alias_node);
595                 if (dentry_has_short_name(dentry))
596                         break;
597                 next = next->next;
598         } while (next != &inode->i_extraction_aliases);
599         return dentry;
600 }
601
602 /*
603  * Set or clear FILE_ATTRIBUTE_COMPRESSED if the inherited value is different
604  * from the desired value.
605  *
606  * Note that you can NOT override the inherited value of
607  * FILE_ATTRIBUTE_COMPRESSED directly with NtCreateFile().
608  */
609 static int
610 adjust_compression_attribute(HANDLE h, const struct wim_dentry *dentry,
611                              struct win32_apply_ctx *ctx)
612 {
613         const bool compressed = (dentry->d_inode->i_attributes &
614                                  FILE_ATTRIBUTE_COMPRESSED);
615
616         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)
617                 return 0;
618
619         if (!ctx->common.supported_features.compressed_files)
620                 return 0;
621
622         FILE_BASIC_INFORMATION info;
623         NTSTATUS status;
624         USHORT compression_state;
625
626         /* Get current attributes  */
627         status = (*func_NtQueryInformationFile)(h, &ctx->iosb,
628                                                 &info, sizeof(info),
629                                                 FileBasicInformation);
630         if (NT_SUCCESS(status) &&
631             compressed == !!(info.FileAttributes & FILE_ATTRIBUTE_COMPRESSED))
632         {
633                 /* Nothing needs to be done.  */
634                 return 0;
635         }
636
637         /* Set the new compression state  */
638
639         if (compressed)
640                 compression_state = COMPRESSION_FORMAT_DEFAULT;
641         else
642                 compression_state = COMPRESSION_FORMAT_NONE;
643
644         status = (*func_NtFsControlFile)(h,
645                                          NULL,
646                                          NULL,
647                                          NULL,
648                                          &ctx->iosb,
649                                          FSCTL_SET_COMPRESSION,
650                                          &compression_state,
651                                          sizeof(USHORT),
652                                          NULL,
653                                          0);
654         if (NT_SUCCESS(status))
655                 return 0;
656
657         set_errno_from_nt_status(status);
658         ERROR_WITH_ERRNO("Can't %s compression attribute on \"%ls\" "
659                          "(status=0x%08"PRIx32")",
660                          (compressed ? "set" : "clear"),
661                          current_path(ctx), status);
662         return WIMLIB_ERR_SET_ATTRIBUTES;
663 }
664
665 /*
666  * Clear FILE_ATTRIBUTE_ENCRYPTED if the file or directory is not supposed to be
667  * encrypted.
668  *
669  * You can provide FILE_ATTRIBUTE_ENCRYPTED to NtCreateFile() to set it on the
670  * created file.  However, the file or directory will otherwise default to the
671  * encryption state of the parent directory.  This function works around this
672  * limitation by using DecryptFile() to remove FILE_ATTRIBUTE_ENCRYPTED on files
673  * (and directories) that are not supposed to have it set.
674  *
675  * Regardless of whether it succeeds or fails, this function may close the
676  * handle to the file.  If it does, it sets it to NULL.
677  */
678 static int
679 maybe_clear_encryption_attribute(HANDLE *h_ptr, const struct wim_dentry *dentry,
680                                  struct win32_apply_ctx *ctx)
681 {
682         if (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)
683                 return 0;
684
685         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)
686                 return 0;
687
688         if (!ctx->common.supported_features.encrypted_files)
689                 return 0;
690
691         FILE_BASIC_INFORMATION info;
692         NTSTATUS status;
693         BOOL bret;
694
695         /* Get current attributes  */
696         status = (*func_NtQueryInformationFile)(*h_ptr, &ctx->iosb,
697                                                 &info, sizeof(info),
698                                                 FileBasicInformation);
699         if (NT_SUCCESS(status) &&
700             !(info.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED))
701         {
702                 /* Nothing needs to be done.  */
703                 return 0;
704         }
705
706         /* Set the new encryption state  */
707
708         /* Due to Windows' crappy file encryption APIs, we need to close the
709          * handle to the file so we don't get ERROR_SHARING_VIOLATION.  We also
710          * hack together a Win32 path, although we will use the \\?\ prefix so
711          * it will actually be a NT path in disguise...  */
712         (*func_NtClose)(*h_ptr);
713         *h_ptr = NULL;
714
715         build_win32_extraction_path(dentry, ctx);
716
717         bret = DecryptFile(ctx->pathbuf.Buffer, 0);
718
719         /* Restore the NT namespace path  */
720         build_extraction_path(dentry, ctx);
721
722         if (!bret) {
723                 DWORD err = GetLastError();
724                 set_errno_from_win32_error(err);
725                 ERROR_WITH_ERRNO("Can't decrypt file \"%ls\" (err=%"PRIu32")",
726                                   current_path(ctx), (u32)err);
727                 return WIMLIB_ERR_SET_ATTRIBUTES;
728         }
729         return 0;
730 }
731
732 /* Set the short name on the open file @h which has been created at the location
733  * indicated by @dentry.
734  *
735  * Note that this may add, change, or remove the short name.
736  *
737  * @h must be opened with DELETE access.
738  *
739  * Returns 0 or WIMLIB_ERR_SET_SHORT_NAME.  The latter only happens in
740  * STRICT_SHORT_NAMES mode.
741  */
742 static int
743 set_short_name(HANDLE h, const struct wim_dentry *dentry,
744                struct win32_apply_ctx *ctx)
745 {
746         size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) +
747                          dentry->short_name_nbytes;
748         u8 buf[bufsize] _aligned_attribute(8);
749         FILE_NAME_INFORMATION *info = (FILE_NAME_INFORMATION *)buf;
750         NTSTATUS status;
751
752         info->FileNameLength = dentry->short_name_nbytes;
753         memcpy(info->FileName, dentry->short_name, dentry->short_name_nbytes);
754
755         status = (*func_NtSetInformationFile)(h, &ctx->iosb, info, bufsize,
756                                               FileShortNameInformation);
757         if (NT_SUCCESS(status))
758                 return 0;
759
760         /* By default, failure to set short names is not an error (since short
761          * names aren't too important anymore...).  */
762         if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES))
763                 return 0;
764
765         if (status == STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME) {
766                 if (dentry->short_name_nbytes == 0)
767                         return 0;
768                 ERROR("Can't extract short name when short "
769                       "names are not enabled on the volume!");
770         } else {
771                 ERROR("Can't set short name on \"%ls\" (status=0x%08"PRIx32")",
772                       current_path(ctx), (u32)status);
773         }
774         return WIMLIB_ERR_SET_SHORT_NAME;
775 }
776
777 /*
778  * A wrapper around NtCreateFile() to make it slightly more usable...
779  * This uses the path currently constructed in ctx->pathbuf.
780  *
781  * Also, we always specify FILE_OPEN_FOR_BACKUP_INTENT and
782  * FILE_OPEN_REPARSE_POINT.
783  */
784 static NTSTATUS
785 do_create_file(PHANDLE FileHandle,
786                ACCESS_MASK DesiredAccess,
787                PLARGE_INTEGER AllocationSize,
788                ULONG FileAttributes,
789                ULONG CreateDisposition,
790                ULONG CreateOptions,
791                struct win32_apply_ctx *ctx)
792 {
793         return (*func_NtCreateFile)(FileHandle,
794                                     DesiredAccess,
795                                     &ctx->attr,
796                                     &ctx->iosb,
797                                     AllocationSize,
798                                     FileAttributes,
799                                     FILE_SHARE_VALID_FLAGS,
800                                     CreateDisposition,
801                                     CreateOptions |
802                                         FILE_OPEN_FOR_BACKUP_INTENT |
803                                         FILE_OPEN_REPARSE_POINT,
804                                     NULL,
805                                     0);
806 }
807
808 /* Like do_create_file(), but builds the extraction path of the @dentry first.
809  */
810 static NTSTATUS
811 create_file(PHANDLE FileHandle,
812             ACCESS_MASK DesiredAccess,
813             PLARGE_INTEGER AllocationSize,
814             ULONG FileAttributes,
815             ULONG CreateDisposition,
816             ULONG CreateOptions,
817             const struct wim_dentry *dentry,
818             struct win32_apply_ctx *ctx)
819 {
820         build_extraction_path(dentry, ctx);
821         return do_create_file(FileHandle,
822                               DesiredAccess,
823                               AllocationSize,
824                               FileAttributes,
825                               CreateDisposition,
826                               CreateOptions,
827                               ctx);
828 }
829
830 /* Create empty named data streams.
831  *
832  * Since these won't have 'struct wim_lookup_table_entry's, they won't show up
833  * in the call to extract_stream_list().  Hence the need for the special case.
834  */
835 static int
836 create_any_empty_ads(const struct wim_dentry *dentry,
837                      struct win32_apply_ctx *ctx)
838 {
839         const struct wim_inode *inode = dentry->d_inode;
840         LARGE_INTEGER allocation_size;
841         bool path_modified = false;
842         int ret = 0;
843
844         if (!ctx->common.supported_features.named_data_streams)
845                 return 0;
846
847         for (u16 i = 0; i < inode->i_num_ads; i++) {
848                 const struct wim_ads_entry *entry;
849                 NTSTATUS status;
850                 HANDLE h;
851
852                 entry = &inode->i_ads_entries[i];
853
854                 /* Not named?  */
855                 if (!entry->stream_name_nbytes)
856                         continue;
857
858                 /* Not empty?  */
859                 if (entry->lte)
860                         continue;
861
862                 /* Probably setting the allocation size to 0 has no effect, but
863                  * we might as well try.  */
864                 allocation_size.QuadPart = 0;
865
866                 build_extraction_path_with_ads(dentry, ctx,
867                                                entry->stream_name,
868                                                entry->stream_name_nbytes /
869                                                         sizeof(wchar_t));
870                 path_modified = true;
871                 status = do_create_file(&h, FILE_WRITE_DATA, &allocation_size,
872                                         0, FILE_SUPERSEDE, 0, ctx);
873                 if (!NT_SUCCESS(status)) {
874                         set_errno_from_nt_status(status);
875                         ERROR_WITH_ERRNO("Can't create \"%ls\" "
876                                          "(status=0x%08"PRIx32")",
877                                          current_path(ctx), (u32)status);
878                         ret = WIMLIB_ERR_OPEN;
879                         break;
880                 }
881                 (*func_NtClose)(h);
882         }
883         /* Restore the path to the dentry itself  */
884         if (path_modified)
885                 build_extraction_path(dentry, ctx);
886         return ret;
887 }
888
889 /*
890  * Creates the directory named by @dentry, or uses an existing directory at that
891  * location.  If necessary, sets the short name and/or fixes compression and
892  * encryption attributes.
893  *
894  * Returns 0, WIMLIB_ERR_MKDIR, or WIMLIB_ERR_SET_SHORT_NAME.
895  */
896 static int
897 create_directory(const struct wim_dentry *dentry,
898                  struct win32_apply_ctx *ctx)
899 {
900         HANDLE h;
901         NTSTATUS status;
902         int ret;
903         ULONG attrib;
904
905         /* Special attributes:
906          *
907          * Use FILE_ATTRIBUTE_ENCRYPTED if the directory needs to have it set.
908          * This doesn't work for FILE_ATTRIBUTE_COMPRESSED (unfortunately).
909          *
910          * Don't specify FILE_ATTRIBUTE_DIRECTORY; it gets set anyway as a
911          * result of the FILE_DIRECTORY_FILE option.  */
912         attrib = (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED);
913
914         /* DELETE is needed for set_short_name().
915          * GENERIC_READ and GENERIC_WRITE are needed for
916          * adjust_compression_attribute().  */
917         status = create_file(&h, GENERIC_READ | GENERIC_WRITE | DELETE, NULL,
918                              attrib, FILE_OPEN_IF, FILE_DIRECTORY_FILE,
919                              dentry, ctx);
920         if (!NT_SUCCESS(status)) {
921                 set_errno_from_nt_status(status);
922                 ERROR_WITH_ERRNO("Can't create directory \"%ls\" "
923                                  "(status=0x%08"PRIx32")",
924                                  current_path(ctx), (u32)status);
925                 return WIMLIB_ERR_MKDIR;
926         }
927
928         ret = set_short_name(h, dentry, ctx);
929
930         if (!ret)
931                 ret = adjust_compression_attribute(h, dentry, ctx);
932
933         if (!ret)
934                 ret = maybe_clear_encryption_attribute(&h, dentry, ctx);
935                 /* May close the handle!!! */
936
937         if (h)
938                 (*func_NtClose)(h);
939         return ret;
940 }
941
942 /*
943  * Create all the directories being extracted, other than the target directory
944  * itself.
945  *
946  * Note: we don't honor directory hard links.  However, we don't allow them to
947  * exist in WIM images anyway (see inode_fixup.c).
948  */
949 static int
950 create_directories(struct list_head *dentry_list,
951                    struct win32_apply_ctx *ctx)
952 {
953         const struct wim_dentry *dentry;
954         int ret;
955
956         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
957
958                 if (!(dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
959                         continue;
960
961                 /* Note: Here we include files with
962                  * FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT, but we
963                  * wait until later to actually set the reparse data.  */
964
965                 /* If the root dentry is being extracted, it was already done so
966                  * in prepare_target().  */
967                 if (dentry_is_root(dentry))
968                         continue;
969
970                 ret = create_directory(dentry, ctx);
971                 if (ret)
972                         return ret;
973
974                 ret = create_any_empty_ads(dentry, ctx);
975                 if (ret)
976                         return ret;
977
978                 ret = report_file_created(&ctx->common);
979                 if (ret)
980                         return ret;
981         }
982         return 0;
983 }
984
985 /*
986  * Creates the nondirectory file named by @dentry.
987  *
988  * On success, returns an open handle to the file in @h_ret, with GENERIC_READ,
989  * GENERIC_WRITE, and DELETE access.  Also, the path to the file will be saved
990  * in ctx->pathbuf.  On failure, returns WIMLIB_ERR_OPEN.
991  */
992 static int
993 create_nondirectory_inode(HANDLE *h_ret, const struct wim_dentry *dentry,
994                           struct win32_apply_ctx *ctx)
995 {
996         const struct wim_inode *inode;
997         ULONG attrib;
998         NTSTATUS status;
999         bool retried = false;
1000
1001         inode = dentry->d_inode;
1002
1003         /* If the file already exists and has FILE_ATTRIBUTE_SYSTEM and/or
1004          * FILE_ATTRIBUTE_HIDDEN, these must be specified in order to supersede
1005          * the file.
1006          *
1007          * Normally the user shouldn't be trying to overwrite such files anyway,
1008          * but we at least provide FILE_ATTRIBUTE_SYSTEM and
1009          * FILE_ATTRIBUTE_HIDDEN if the WIM inode has those attributes so that
1010          * we catch the case where the user extracts the same files to the same
1011          * location more than one time.
1012          *
1013          * Also specify FILE_ATTRIBUTE_ENCRYPTED if the file needs to be
1014          * encrypted.
1015          *
1016          * In NO_ATTRIBUTES mode just don't specify any attributes at all.
1017          */
1018         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES) {
1019                 attrib = 0;
1020         } else {
1021                 attrib = (inode->i_attributes & (FILE_ATTRIBUTE_SYSTEM |
1022                                                  FILE_ATTRIBUTE_HIDDEN |
1023                                                  FILE_ATTRIBUTE_ENCRYPTED));
1024         }
1025         build_extraction_path(dentry, ctx);
1026 retry:
1027         status = do_create_file(h_ret, GENERIC_READ | GENERIC_WRITE | DELETE,
1028                                 NULL, attrib, FILE_SUPERSEDE,
1029                                 FILE_NON_DIRECTORY_FILE, ctx);
1030         if (NT_SUCCESS(status)) {
1031                 int ret;
1032
1033                 ret = adjust_compression_attribute(*h_ret, dentry, ctx);
1034                 if (ret) {
1035                         (*func_NtClose)(*h_ret);
1036                         return ret;
1037                 }
1038
1039                 ret = maybe_clear_encryption_attribute(h_ret, dentry, ctx);
1040                 /* May close the handle!!! */
1041
1042                 if (ret) {
1043                         if (*h_ret)
1044                                 (*func_NtClose)(*h_ret);
1045                         return ret;
1046                 }
1047
1048                 if (!*h_ret) {
1049                         /* Re-open the handle so that we can return it on
1050                          * success.  */
1051                         status = do_create_file(h_ret,
1052                                                 GENERIC_READ |
1053                                                         GENERIC_WRITE | DELETE,
1054                                                 NULL, 0, FILE_OPEN,
1055                                                 FILE_NON_DIRECTORY_FILE, ctx);
1056                         if (!NT_SUCCESS(status))
1057                                 goto fail;
1058                 }
1059
1060                 ret = create_any_empty_ads(dentry, ctx);
1061                 if (ret) {
1062                         (*func_NtClose)(*h_ret);
1063                         return ret;
1064                 }
1065                 return 0;
1066         }
1067
1068         if (status == STATUS_ACCESS_DENIED && !retried) {
1069                 /* We also can't supersede an existing file that has
1070                  * FILE_ATTRIBUTE_READONLY set; doing so causes NtCreateFile()
1071                  * to return STATUS_ACCESS_DENIED .  The only workaround seems
1072                  * to be to explicitly remove FILE_ATTRIBUTE_READONLY on the
1073                  * existing file, then try again.  */
1074
1075                 FILE_BASIC_INFORMATION info;
1076                 HANDLE h;
1077
1078                 status = do_create_file(&h, FILE_WRITE_ATTRIBUTES, NULL, 0,
1079                                         FILE_OPEN, FILE_NON_DIRECTORY_FILE, ctx);
1080                 if (!NT_SUCCESS(status))
1081                         goto fail;
1082
1083                 memset(&info, 0, sizeof(info));
1084                 info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
1085
1086                 status = (*func_NtSetInformationFile)(h, &ctx->iosb,
1087                                                       &info, sizeof(info),
1088                                                       FileBasicInformation);
1089                 (*func_NtClose)(h);
1090                 if (!NT_SUCCESS(status))
1091                         goto fail;
1092                 retried = true;
1093                 goto retry;
1094         }
1095 fail:
1096         set_errno_from_nt_status(status);
1097         ERROR_WITH_ERRNO("Can't create file \"%ls\" (status=0x%08"PRIx32")",
1098                          current_path(ctx), (u32)status);
1099         return WIMLIB_ERR_OPEN;
1100 }
1101
1102 /* Creates a hard link at the location named by @dentry to the file represented
1103  * by the open handle @h.  Or, if the target volume does not support hard links,
1104  * create a separate file instead.  */
1105 static int
1106 create_link(HANDLE h, const struct wim_dentry *dentry,
1107             struct win32_apply_ctx *ctx)
1108 {
1109         if (ctx->common.supported_features.hard_links) {
1110
1111                 build_extraction_path(dentry, ctx);
1112
1113                 size_t bufsize = offsetof(FILE_LINK_INFORMATION, FileName) +
1114                                  ctx->pathbuf.Length + sizeof(wchar_t);
1115                 u8 buf[bufsize] _aligned_attribute(8);
1116                 FILE_LINK_INFORMATION *info = (FILE_LINK_INFORMATION *)buf;
1117                 NTSTATUS status;
1118
1119                 info->ReplaceIfExists = TRUE;
1120                 info->RootDirectory = ctx->attr.RootDirectory;
1121                 info->FileNameLength = ctx->pathbuf.Length;
1122                 memcpy(info->FileName, ctx->pathbuf.Buffer, ctx->pathbuf.Length);
1123                 info->FileName[info->FileNameLength / 2] = L'\0';
1124
1125                 /* Note: the null terminator isn't actually necessary,
1126                  * but if you don't add the extra character, you get
1127                  * STATUS_INFO_LENGTH_MISMATCH when FileNameLength
1128                  * happens to be 2  */
1129
1130                 status = (*func_NtSetInformationFile)(h, &ctx->iosb,
1131                                                       info, bufsize,
1132                                                       FileLinkInformation);
1133                 if (NT_SUCCESS(status))
1134                         return 0;
1135                 ERROR("Failed to create link \"%ls\" (status=0x%08"PRIx32")",
1136                       current_path(ctx), (u32)status);
1137                 return WIMLIB_ERR_LINK;
1138         } else {
1139                 HANDLE h2;
1140                 int ret;
1141
1142                 ret = create_nondirectory_inode(&h2, dentry, ctx);
1143                 if (ret)
1144                         return ret;
1145
1146                 (*func_NtClose)(h2);
1147                 return 0;
1148         }
1149 }
1150
1151 /* Given an inode (represented by the open handle @h) for which one link has
1152  * been created (named by @first_dentry), create the other links.
1153  *
1154  * Or, if the target volume does not support hard links, create separate files.
1155  *
1156  * Note: This uses ctx->pathbuf and does not reset it.
1157  */
1158 static int
1159 create_links(HANDLE h, const struct wim_dentry *first_dentry,
1160              struct win32_apply_ctx *ctx)
1161 {
1162         const struct wim_inode *inode;
1163         const struct list_head *next;
1164         const struct wim_dentry *dentry;
1165         int ret;
1166
1167         inode = first_dentry->d_inode;
1168         next = inode->i_extraction_aliases.next;
1169         do {
1170                 dentry = list_entry(next, struct wim_dentry,
1171                                     d_extraction_alias_node);
1172                 if (dentry != first_dentry) {
1173                         ret = create_link(h, dentry, ctx);
1174                         if (ret)
1175                                 return ret;
1176                 }
1177                 next = next->next;
1178         } while (next != &inode->i_extraction_aliases);
1179         return 0;
1180 }
1181
1182 /* Create a nondirectory file, including all links.  */
1183 static int
1184 create_nondirectory(const struct wim_inode *inode, struct win32_apply_ctx *ctx)
1185 {
1186         const struct wim_dentry *first_dentry;
1187         HANDLE h;
1188         int ret;
1189
1190         first_dentry = first_extraction_alias(inode);
1191
1192         /* Create first link.  */
1193         ret = create_nondirectory_inode(&h, first_dentry, ctx);
1194         if (ret)
1195                 return ret;
1196
1197         /* Set short name.  */
1198         ret = set_short_name(h, first_dentry, ctx);
1199
1200         /* Create additional links, OR if hard links are not supported just
1201          * create more files.  */
1202         if (!ret)
1203                 ret = create_links(h, first_dentry, ctx);
1204
1205         (*func_NtClose)(h);
1206         return ret;
1207 }
1208
1209 /* Create all the nondirectory files being extracted, including all aliases
1210  * (hard links).  */
1211 static int
1212 create_nondirectories(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
1213 {
1214         const struct wim_dentry *dentry;
1215         const struct wim_inode *inode;
1216         int ret;
1217
1218         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1219                 inode = dentry->d_inode;
1220                 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
1221                         continue;
1222                 /* Call create_nondirectory() only once per inode  */
1223                 if (dentry != inode_first_extraction_dentry(inode))
1224                         continue;
1225                 ret = create_nondirectory(inode, ctx);
1226                 if (ret)
1227                         return ret;
1228                 ret = report_file_created(&ctx->common);
1229                 if (ret)
1230                         return ret;
1231         }
1232         return 0;
1233 }
1234
1235 static void
1236 close_handles(struct win32_apply_ctx *ctx)
1237 {
1238         for (unsigned i = 0; i < ctx->num_open_handles; i++)
1239                 (*func_NtClose)(ctx->open_handles[i]);
1240 }
1241
1242 /* Prepare to read the next stream, which has size @stream_size, into an
1243  * in-memory buffer.  */
1244 static int
1245 prepare_data_buffer(struct win32_apply_ctx *ctx, u64 stream_size)
1246 {
1247         if (stream_size > ctx->data_buffer_size) {
1248                 /* Larger buffer needed.  */
1249                 void *new_buffer;
1250                 if ((size_t)stream_size != stream_size)
1251                         return WIMLIB_ERR_NOMEM;
1252                 new_buffer = REALLOC(ctx->data_buffer, stream_size);
1253                 if (!new_buffer)
1254                         return WIMLIB_ERR_NOMEM;
1255                 ctx->data_buffer = new_buffer;
1256                 ctx->data_buffer_size = stream_size;
1257         }
1258         /* On the first call this changes data_buffer_ptr from NULL, which tells
1259          * extract_chunk() that the data buffer needs to be filled while reading
1260          * the stream data.  */
1261         ctx->data_buffer_ptr = ctx->data_buffer;
1262         return 0;
1263 }
1264
1265 static int
1266 begin_extract_stream_instance(const struct wim_lookup_table_entry *stream,
1267                               struct wim_dentry *dentry,
1268                               const wchar_t *stream_name,
1269                               struct win32_apply_ctx *ctx)
1270 {
1271         const struct wim_inode *inode = dentry->d_inode;
1272         size_t stream_name_nchars = 0;
1273         FILE_ALLOCATION_INFORMATION alloc_info;
1274         HANDLE h;
1275         NTSTATUS status;
1276
1277         if (unlikely(stream_name))
1278                 stream_name_nchars = wcslen(stream_name);
1279
1280         if (unlikely(stream_name_nchars)) {
1281                 build_extraction_path_with_ads(dentry, ctx,
1282                                                stream_name, stream_name_nchars);
1283         } else {
1284                 build_extraction_path(dentry, ctx);
1285         }
1286
1287         /* Reparse point?  */
1288         if (unlikely(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)
1289             && (stream_name_nchars == 0))
1290         {
1291                 if (!ctx->common.supported_features.reparse_points)
1292                         return 0;
1293
1294                 /* We can't write the reparse stream directly; we must set it
1295                  * with FSCTL_SET_REPARSE_POINT, which requires that all the
1296                  * data be available.  So, stage the data in a buffer.  */
1297
1298                 list_add_tail(&dentry->tmp_list, &ctx->reparse_dentries);
1299                 return prepare_data_buffer(ctx, stream->size);
1300         }
1301
1302         /* Encrypted file?  */
1303         if (unlikely(inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)
1304             && (stream_name_nchars == 0))
1305         {
1306                 if (!ctx->common.supported_features.encrypted_files)
1307                         return 0;
1308
1309                 /* We can't write encrypted file streams directly; we must use
1310                  * WriteEncryptedFileRaw(), which requires providing the data
1311                  * through a callback function.  This can't easily be combined
1312                  * with our own callback-based approach.
1313                  *
1314                  * The current workaround is to simply read the stream into
1315                  * memory and write the encrypted file from that.
1316                  *
1317                  * TODO: This isn't sufficient for extremely large encrypted
1318                  * files.  Perhaps we should create an extra thread to write
1319                  * such files...  */
1320                 list_add_tail(&dentry->tmp_list, &ctx->encrypted_dentries);
1321                 return prepare_data_buffer(ctx, stream->size);
1322         }
1323
1324         /* Extracting unnamed data stream in WIMBoot mode?  */
1325         if (unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT)
1326             && (stream_name_nchars == 0)
1327             && (stream->resource_location == RESOURCE_IN_WIM)
1328             && (stream->rspec->wim == ctx->common.wim)
1329             && (stream->size == stream->rspec->uncompressed_size))
1330         {
1331                 int ret = calculate_dentry_full_path(dentry);
1332                 if (ret)
1333                         return ret;
1334                 if (in_prepopulate_list(dentry, ctx)) {
1335                         union wimlib_progress_info info;
1336
1337                         info.wimboot_exclude.path_in_wim = dentry->_full_path;
1338                         info.wimboot_exclude.extraction_path = current_path(ctx);
1339
1340                         ret = call_progress(ctx->common.progfunc,
1341                                             WIMLIB_PROGRESS_MSG_WIMBOOT_EXCLUDE,
1342                                             &info, ctx->common.progctx);
1343                         FREE(dentry->_full_path);
1344                         dentry->_full_path = NULL;
1345                         if (ret)
1346                                 return ret;
1347                         /* Go on and open the file for normal extraction.  */
1348                 } else {
1349                         FREE(dentry->_full_path);
1350                         dentry->_full_path = NULL;
1351                         return wimboot_set_pointer(&ctx->attr,
1352                                                    current_path(ctx),
1353                                                    stream,
1354                                                    ctx->wimboot.data_source_id,
1355                                                    ctx->wimboot.wim_lookup_table_hash,
1356                                                    ctx->wimboot.wof_running);
1357                 }
1358         }
1359
1360         if (ctx->num_open_handles == MAX_OPEN_STREAMS) {
1361                 /* XXX: Fix this.  But because of the checks in
1362                  * extract_stream_list(), this can now only happen on a
1363                  * filesystem that does not support hard links.  */
1364                 ERROR("Can't extract data: too many open files!");
1365                 return WIMLIB_ERR_UNSUPPORTED;
1366         }
1367
1368         /* Open a new handle  */
1369         status = do_create_file(&h,
1370                                 FILE_WRITE_DATA | SYNCHRONIZE,
1371                                 NULL, 0, FILE_OPEN_IF,
1372                                 FILE_SEQUENTIAL_ONLY |
1373                                         FILE_SYNCHRONOUS_IO_NONALERT,
1374                                 ctx);
1375         if (!NT_SUCCESS(status)) {
1376                 set_errno_from_nt_status(status);
1377                 ERROR_WITH_ERRNO("Can't open \"%ls\" for writing "
1378                                  "(status=0x%08"PRIx32")",
1379                                  current_path(ctx), (u32)status);
1380                 return WIMLIB_ERR_OPEN;
1381         }
1382
1383         ctx->open_handles[ctx->num_open_handles++] = h;
1384
1385         /* Allocate space for the data.  */
1386         alloc_info.AllocationSize.QuadPart = stream->size;
1387         (*func_NtSetInformationFile)(h, &ctx->iosb,
1388                                      &alloc_info, sizeof(alloc_info),
1389                                      FileAllocationInformation);
1390         return 0;
1391 }
1392
1393 /* Set the reparse data @rpbuf of length @rpbuflen on the extracted file
1394  * corresponding to the WIM dentry @dentry.  */
1395 static int
1396 do_set_reparse_data(const struct wim_dentry *dentry,
1397                     const void *rpbuf, u16 rpbuflen,
1398                     struct win32_apply_ctx *ctx)
1399 {
1400         NTSTATUS status;
1401         HANDLE h;
1402
1403         status = create_file(&h, GENERIC_WRITE, NULL,
1404                              0, FILE_OPEN, 0, dentry, ctx);
1405         if (!NT_SUCCESS(status))
1406                 goto fail;
1407
1408         status = (*func_NtFsControlFile)(h, NULL, NULL, NULL,
1409                                          &ctx->iosb, FSCTL_SET_REPARSE_POINT,
1410                                          (void *)rpbuf, rpbuflen,
1411                                          NULL, 0);
1412         (*func_NtClose)(h);
1413
1414         if (NT_SUCCESS(status))
1415                 return 0;
1416
1417         /* On Windows, by default only the Administrator can create symbolic
1418          * links for some reason.  By default we just issue a warning if this
1419          * appears to be the problem.  Use WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS
1420          * to get a hard error.  */
1421         if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS)
1422             && (status == STATUS_PRIVILEGE_NOT_HELD ||
1423                 status == STATUS_ACCESS_DENIED)
1424             && (dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
1425                 dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT))
1426         {
1427                 WARNING("Can't create symbolic link \"%ls\"!              \n"
1428                         "          (Need Administrator rights, or at least "
1429                         "the\n"
1430                         "          SeCreateSymbolicLink privilege.)",
1431                         current_path(ctx));
1432                 return 0;
1433         }
1434
1435 fail:
1436         set_errno_from_nt_status(status);
1437         ERROR_WITH_ERRNO("Can't set reparse data on \"%ls\" "
1438                          "(status=0x%08"PRIx32")",
1439                          current_path(ctx), (u32)status);
1440         return WIMLIB_ERR_SET_REPARSE_DATA;
1441 }
1442
1443 /* Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a
1444  * pointer to the suffix of the path that begins with the device directly, such
1445  * as e:\Windows\System32.  */
1446 static const wchar_t *
1447 skip_nt_toplevel_component(const wchar_t *path, size_t path_nchars)
1448 {
1449         static const wchar_t * const dirs[] = {
1450                 L"\\??\\",
1451                 L"\\DosDevices\\",
1452                 L"\\Device\\",
1453         };
1454         size_t first_dir_len = 0;
1455         const wchar_t * const end = path + path_nchars;
1456
1457         for (size_t i = 0; i < ARRAY_LEN(dirs); i++) {
1458                 size_t len = wcslen(dirs[i]);
1459                 if (len <= (end - path) && !wcsnicmp(path, dirs[i], len)) {
1460                         first_dir_len = len;
1461                         break;
1462                 }
1463         }
1464         if (first_dir_len == 0)
1465                 return path;
1466         path += first_dir_len;
1467         while (path != end && *path == L'\\')
1468                 path++;
1469         return path;
1470 }
1471
1472 /* Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a
1473  * pointer to the suffix of the path that is device-relative, such as
1474  * Windows\System32.
1475  *
1476  * The path has an explicit length and is not necessarily null terminated.
1477  *
1478  * If the path just something like \??\e: then the returned pointer will point
1479  * just past the colon.  In this case the length of the result will be 0
1480  * characters.  */
1481 static const wchar_t *
1482 get_device_relative_path(const wchar_t *path, size_t path_nchars)
1483 {
1484         const wchar_t * const orig_path = path;
1485         const wchar_t * const end = path + path_nchars;
1486
1487         path = skip_nt_toplevel_component(path, path_nchars);
1488         if (path == orig_path)
1489                 return orig_path;
1490
1491         path = wmemchr(path, L'\\', (end - path));
1492         if (!path)
1493                 return end;
1494         do {
1495                 path++;
1496         } while (path != end && *path == L'\\');
1497         return path;
1498 }
1499
1500 /*
1501  * Given a reparse point buffer for a symbolic link or junction, adjust its
1502  * contents so that the target of the link is consistent with the new location
1503  * of the files.
1504  */
1505 static void
1506 try_rpfix(u8 *rpbuf, u16 *rpbuflen_p, struct win32_apply_ctx *ctx)
1507 {
1508         struct reparse_data rpdata;
1509         size_t orig_subst_name_nchars;
1510         const wchar_t *relpath;
1511         size_t relpath_nchars;
1512         size_t target_ntpath_nchars;
1513         size_t fixed_subst_name_nchars;
1514         const wchar_t *fixed_print_name;
1515         size_t fixed_print_name_nchars;
1516
1517         if (parse_reparse_data(rpbuf, *rpbuflen_p, &rpdata)) {
1518                 /* Do nothing if the reparse data is invalid.  */
1519                 return;
1520         }
1521
1522         if (rpdata.rptag == WIM_IO_REPARSE_TAG_SYMLINK &&
1523             (rpdata.rpflags & SYMBOLIC_LINK_RELATIVE))
1524         {
1525                 /* Do nothing if it's a relative symbolic link.  */
1526                 return;
1527         }
1528
1529         /* Build the new substitute name from the NT namespace path to the
1530          * target directory, then a path separator, then the "device relative"
1531          * part of the old substitute name.  */
1532
1533         orig_subst_name_nchars = rpdata.substitute_name_nbytes / sizeof(wchar_t);
1534
1535         relpath = get_device_relative_path(rpdata.substitute_name,
1536                                            orig_subst_name_nchars);
1537         relpath_nchars = orig_subst_name_nchars -
1538                          (relpath - rpdata.substitute_name);
1539
1540         target_ntpath_nchars = ctx->target_ntpath.Length / sizeof(wchar_t);
1541
1542         fixed_subst_name_nchars = target_ntpath_nchars;
1543         if (relpath_nchars)
1544                 fixed_subst_name_nchars += 1 + relpath_nchars;
1545         wchar_t fixed_subst_name[fixed_subst_name_nchars];
1546
1547         wmemcpy(fixed_subst_name, ctx->target_ntpath.Buffer,
1548                 target_ntpath_nchars);
1549         if (relpath_nchars) {
1550                 fixed_subst_name[target_ntpath_nchars] = L'\\';
1551                 wmemcpy(&fixed_subst_name[target_ntpath_nchars + 1],
1552                         relpath, relpath_nchars);
1553         }
1554         /* Doesn't need to be null-terminated.  */
1555
1556         /* Print name should be Win32, but not all NT names can even be
1557          * translated to Win32 names.  But we can at least delete the top-level
1558          * directory, such as \??\, and this will have the expected result in
1559          * the usual case.  */
1560         fixed_print_name = skip_nt_toplevel_component(fixed_subst_name,
1561                                                       fixed_subst_name_nchars);
1562         fixed_print_name_nchars = fixed_subst_name_nchars - (fixed_print_name -
1563                                                              fixed_subst_name);
1564
1565         rpdata.substitute_name = fixed_subst_name;
1566         rpdata.substitute_name_nbytes = fixed_subst_name_nchars * sizeof(wchar_t);
1567         rpdata.print_name = (wchar_t *)fixed_print_name;
1568         rpdata.print_name_nbytes = fixed_print_name_nchars * sizeof(wchar_t);
1569         make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p);
1570 }
1571
1572 /* Sets reparse data on the specified file.  This handles "fixing" the targets
1573  * of absolute symbolic links and junctions if WIMLIB_EXTRACT_FLAG_RPFIX was
1574  * specified.  */
1575 static int
1576 set_reparse_data(const struct wim_dentry *dentry,
1577                  const void *_rpbuf, u16 rpbuflen, struct win32_apply_ctx *ctx)
1578 {
1579         const struct wim_inode *inode = dentry->d_inode;
1580         const void *rpbuf = _rpbuf;
1581
1582         if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX)
1583             && !inode->i_not_rpfixed
1584             && (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
1585                 inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT))
1586         {
1587                 memcpy(&ctx->rpfixbuf, _rpbuf, rpbuflen);
1588                 try_rpfix((u8 *)&ctx->rpfixbuf, &rpbuflen, ctx);
1589                 rpbuf = &ctx->rpfixbuf;
1590         }
1591         return do_set_reparse_data(dentry, rpbuf, rpbuflen, ctx);
1592
1593 }
1594
1595 /* Import the next block of raw encrypted data  */
1596 static DWORD WINAPI
1597 import_encrypted_data(PBYTE pbData, PVOID pvCallbackContext, PULONG Length)
1598 {
1599         struct win32_apply_ctx *ctx = pvCallbackContext;
1600         ULONG copy_len;
1601
1602         copy_len = min(ctx->encrypted_size - ctx->encrypted_offset, *Length);
1603         memcpy(pbData, &ctx->data_buffer[ctx->encrypted_offset], copy_len);
1604         ctx->encrypted_offset += copy_len;
1605         *Length = copy_len;
1606         return ERROR_SUCCESS;
1607 }
1608
1609 /* Write the raw encrypted data to the already-created file corresponding to
1610  * @dentry.
1611  *
1612  * The raw encrypted data is provided in ctx->data_buffer, and its size is
1613  * ctx->encrypted_size.  */
1614 static int
1615 extract_encrypted_file(const struct wim_dentry *dentry,
1616                        struct win32_apply_ctx *ctx)
1617 {
1618         void *rawctx;
1619         DWORD err;
1620
1621         /* Temporarily build a Win32 path for OpenEncryptedFileRaw()  */
1622         build_win32_extraction_path(dentry, ctx);
1623
1624         err = OpenEncryptedFileRaw(ctx->pathbuf.Buffer,
1625                                    CREATE_FOR_IMPORT, &rawctx);
1626
1627         /* Restore the NT namespace path  */
1628         build_extraction_path(dentry, ctx);
1629
1630         if (err != ERROR_SUCCESS) {
1631                 set_errno_from_win32_error(err);
1632                 ERROR_WITH_ERRNO("Can't open \"%ls\" for encrypted import "
1633                                  "(err=%"PRIu32")", current_path(ctx), (u32)err);
1634                 return WIMLIB_ERR_OPEN;
1635         }
1636
1637         ctx->encrypted_offset = 0;
1638
1639         err = WriteEncryptedFileRaw(import_encrypted_data, ctx, rawctx);
1640
1641         CloseEncryptedFileRaw(rawctx);
1642
1643         if (err != ERROR_SUCCESS) {
1644                 set_errno_from_win32_error(err);
1645                 ERROR_WITH_ERRNO("Can't import encrypted file \"%ls\" "
1646                                  "(err=%"PRIu32")", current_path(ctx), (u32)err);
1647                 return WIMLIB_ERR_WRITE;
1648         }
1649
1650         return 0;
1651 }
1652
1653 /* Called when starting to read a stream for extraction on Windows  */
1654 static int
1655 begin_extract_stream(struct wim_lookup_table_entry *stream, void *_ctx)
1656 {
1657         struct win32_apply_ctx *ctx = _ctx;
1658         const struct stream_owner *owners = stream_owners(stream);
1659         int ret;
1660
1661         ctx->num_open_handles = 0;
1662         ctx->data_buffer_ptr = NULL;
1663         INIT_LIST_HEAD(&ctx->reparse_dentries);
1664         INIT_LIST_HEAD(&ctx->encrypted_dentries);
1665
1666         for (u32 i = 0; i < stream->out_refcnt; i++) {
1667                 const struct wim_inode *inode = owners[i].inode;
1668                 const wchar_t *stream_name = owners[i].stream_name;
1669                 struct wim_dentry *dentry;
1670
1671                 /* A copy of the stream needs to be extracted to @inode.  */
1672
1673                 if (ctx->common.supported_features.hard_links) {
1674                         dentry = inode_first_extraction_dentry(inode);
1675                         ret = begin_extract_stream_instance(stream, dentry,
1676                                                             stream_name, ctx);
1677                         if (ret)
1678                                 goto fail;
1679                 } else {
1680                         /* Hard links not supported.  Extract the stream
1681                          * separately to each alias of the inode.  */
1682                         struct list_head *next;
1683
1684                         next = inode->i_extraction_aliases.next;
1685                         do {
1686                                 dentry = list_entry(next, struct wim_dentry,
1687                                                     d_extraction_alias_node);
1688                                 ret = begin_extract_stream_instance(stream,
1689                                                                     dentry,
1690                                                                     stream_name,
1691                                                                     ctx);
1692                                 if (ret)
1693                                         goto fail;
1694                                 next = next->next;
1695                         } while (next != &inode->i_extraction_aliases);
1696                 }
1697         }
1698
1699         return 0;
1700
1701 fail:
1702         close_handles(ctx);
1703         return ret;
1704 }
1705
1706 /* Called when the next chunk of a stream has been read for extraction on
1707  * Windows  */
1708 static int
1709 extract_chunk(const void *chunk, size_t size, void *_ctx)
1710 {
1711         struct win32_apply_ctx *ctx = _ctx;
1712
1713         /* Write the data chunk to each open handle  */
1714         for (unsigned i = 0; i < ctx->num_open_handles; i++) {
1715                 u8 *bufptr = (u8 *)chunk;
1716                 size_t bytes_remaining = size;
1717                 NTSTATUS status;
1718                 while (bytes_remaining) {
1719                         ULONG count = min(0xFFFFFFFF, bytes_remaining);
1720
1721                         status = (*func_NtWriteFile)(ctx->open_handles[i],
1722                                                      NULL, NULL, NULL,
1723                                                      &ctx->iosb, bufptr, count,
1724                                                      NULL, NULL);
1725                         if (!NT_SUCCESS(status)) {
1726                                 set_errno_from_nt_status(status);
1727                                 ERROR_WITH_ERRNO("Error writing data to target "
1728                                                  "volume (status=0x%08"PRIx32")",
1729                                                  (u32)status);
1730                                 return WIMLIB_ERR_WRITE;
1731                         }
1732                         bufptr += ctx->iosb.Information;
1733                         bytes_remaining -= ctx->iosb.Information;
1734                 }
1735         }
1736
1737         /* Copy the data chunk into the buffer (if needed)  */
1738         if (ctx->data_buffer_ptr)
1739                 ctx->data_buffer_ptr = mempcpy(ctx->data_buffer_ptr,
1740                                                chunk, size);
1741         return 0;
1742 }
1743
1744 /* Called when a stream has been fully read for extraction on Windows  */
1745 static int
1746 end_extract_stream(struct wim_lookup_table_entry *stream, int status, void *_ctx)
1747 {
1748         struct win32_apply_ctx *ctx = _ctx;
1749         int ret;
1750         const struct wim_dentry *dentry;
1751
1752         close_handles(ctx);
1753
1754         if (status)
1755                 return status;
1756
1757         if (likely(!ctx->data_buffer_ptr))
1758                 return 0;
1759
1760         if (!list_empty(&ctx->reparse_dentries)) {
1761                 if (stream->size > REPARSE_DATA_MAX_SIZE) {
1762                         dentry = list_first_entry(&ctx->reparse_dentries,
1763                                                   struct wim_dentry, tmp_list);
1764                         build_extraction_path(dentry, ctx);
1765                         ERROR("Reparse data of \"%ls\" has size "
1766                               "%"PRIu64" bytes (exceeds %u bytes)",
1767                               current_path(ctx), stream->size,
1768                               REPARSE_DATA_MAX_SIZE);
1769                         return WIMLIB_ERR_INVALID_REPARSE_DATA;
1770                 }
1771                 /* In the WIM format, reparse streams are just the reparse data
1772                  * and omit the header.  But we can reconstruct the header.  */
1773                 memcpy(ctx->rpbuf.rpdata, ctx->data_buffer, stream->size);
1774                 ctx->rpbuf.rpdatalen = stream->size;
1775                 ctx->rpbuf.rpreserved = 0;
1776                 list_for_each_entry(dentry, &ctx->reparse_dentries, tmp_list) {
1777                         ctx->rpbuf.rptag = dentry->d_inode->i_reparse_tag;
1778                         ret = set_reparse_data(dentry, &ctx->rpbuf,
1779                                                stream->size + REPARSE_DATA_OFFSET,
1780                                                ctx);
1781                         if (ret)
1782                                 return ret;
1783                 }
1784         }
1785
1786         if (!list_empty(&ctx->encrypted_dentries)) {
1787                 ctx->encrypted_size = stream->size;
1788                 list_for_each_entry(dentry, &ctx->encrypted_dentries, tmp_list) {
1789                         ret = extract_encrypted_file(dentry, ctx);
1790                         if (ret)
1791                                 return ret;
1792                 }
1793         }
1794
1795         return 0;
1796 }
1797
1798 /* Attributes that can't be set directly  */
1799 #define SPECIAL_ATTRIBUTES                      \
1800         (FILE_ATTRIBUTE_REPARSE_POINT   |       \
1801          FILE_ATTRIBUTE_DIRECTORY       |       \
1802          FILE_ATTRIBUTE_ENCRYPTED       |       \
1803          FILE_ATTRIBUTE_SPARSE_FILE     |       \
1804          FILE_ATTRIBUTE_COMPRESSED)
1805
1806 /* Set the security descriptor @desc, of @desc_size bytes, on the file with open
1807  * handle @h.  */
1808 static NTSTATUS
1809 set_security_descriptor(HANDLE h, const void *desc,
1810                         size_t desc_size, struct win32_apply_ctx *ctx)
1811 {
1812         SECURITY_INFORMATION info;
1813         NTSTATUS status;
1814
1815         /* We really just want to set entire the security descriptor as-is, but
1816          * all available APIs require specifying the specific parts of the
1817          * descriptor being set.  Start out by requesting all parts be set.  If
1818          * permissions problems are encountered, fall back to omitting some
1819          * parts (first the SACL, then the DACL, then the owner), unless the
1820          * WIMLIB_EXTRACT_FLAG_STRICT_ACLS flag has been enabled.  */
1821         info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
1822                DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
1823
1824         /* Prefer NtSetSecurityObject() to SetFileSecurity().  SetFileSecurity()
1825          * itself necessarily uses NtSetSecurityObject() as the latter is the
1826          * underlying system call for setting security information, but
1827          * SetFileSecurity() opens the handle with NtCreateFile() without
1828          * FILE_OPEN_FILE_BACKUP_INTENT.  Hence, access checks are done and due
1829          * to the Windows security model, even a process running as the
1830          * Administrator can have access denied.  (Of course, this not mentioned
1831          * in the MS "documentation".)  */
1832 retry:
1833         status = (*func_NtSetSecurityObject)(h, info, (PSECURITY_DESCRIPTOR)desc);
1834         if (NT_SUCCESS(status))
1835                 return status;
1836         /* Failed to set the requested parts of the security descriptor.  If the
1837          * error was permissions-related, try to set fewer parts of the security
1838          * descriptor, unless WIMLIB_EXTRACT_FLAG_STRICT_ACLS is enabled.  */
1839         if ((status == STATUS_PRIVILEGE_NOT_HELD ||
1840              status == STATUS_ACCESS_DENIED) &&
1841             !(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
1842         {
1843                 if (info & SACL_SECURITY_INFORMATION) {
1844                         info &= ~SACL_SECURITY_INFORMATION;
1845                         ctx->partial_security_descriptors++;
1846                         goto retry;
1847                 }
1848                 if (info & DACL_SECURITY_INFORMATION) {
1849                         info &= ~DACL_SECURITY_INFORMATION;
1850                         goto retry;
1851                 }
1852                 if (info & OWNER_SECURITY_INFORMATION) {
1853                         info &= ~OWNER_SECURITY_INFORMATION;
1854                         goto retry;
1855                 }
1856                 /* Nothing left except GROUP, and if we removed it we
1857                  * wouldn't have anything at all.  */
1858         }
1859
1860         /* No part of the security descriptor could be set, or
1861          * WIMLIB_EXTRACT_FLAG_STRICT_ACLS is enabled and the full security
1862          * descriptor could not be set.  */
1863         if (!(info & SACL_SECURITY_INFORMATION))
1864                 ctx->partial_security_descriptors--;
1865         ctx->no_security_descriptors++;
1866         return status;
1867 }
1868
1869 /* Set metadata on the open file @h from the WIM inode @inode.  */
1870 static int
1871 do_apply_metadata_to_file(HANDLE h, const struct wim_inode *inode,
1872                           struct win32_apply_ctx *ctx)
1873 {
1874         FILE_BASIC_INFORMATION info;
1875         NTSTATUS status;
1876
1877         /* Set security descriptor if present and not in NO_ACLS mode  */
1878         if (inode->i_security_id >= 0 &&
1879             !(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS))
1880         {
1881                 const struct wim_security_data *sd;
1882                 const void *desc;
1883                 size_t desc_size;
1884
1885                 sd = wim_get_current_security_data(ctx->common.wim);
1886                 desc = sd->descriptors[inode->i_security_id];
1887                 desc_size = sd->sizes[inode->i_security_id];
1888
1889                 status = set_security_descriptor(h, desc, desc_size, ctx);
1890                 if (!NT_SUCCESS(status) &&
1891                     (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
1892                 {
1893                         set_errno_from_nt_status(status);
1894                         ERROR_WITH_ERRNO("Can't set security descriptor "
1895                                          "on \"%ls\" (status=0x%08"PRIx32")",
1896                                          current_path(ctx), (u32)status);
1897                         return WIMLIB_ERR_SET_SECURITY;
1898                 }
1899         }
1900
1901         /* Set attributes and timestamps  */
1902         info.CreationTime.QuadPart = inode->i_creation_time;
1903         info.LastAccessTime.QuadPart = inode->i_last_access_time;
1904         info.LastWriteTime.QuadPart = inode->i_last_write_time;
1905         info.ChangeTime.QuadPart = 0;
1906         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)
1907                 info.FileAttributes = 0;
1908         else
1909                 info.FileAttributes = inode->i_attributes & ~SPECIAL_ATTRIBUTES;
1910
1911         status = (*func_NtSetInformationFile)(h, &ctx->iosb,
1912                                               &info, sizeof(info),
1913                                               FileBasicInformation);
1914         /* On FAT volumes we get STATUS_INVALID_PARAMETER if we try to set
1915          * attributes on the root directory.  (Apparently because FAT doesn't
1916          * actually have a place to store those attributes!)  */
1917         if (!NT_SUCCESS(status)
1918             && !(status == STATUS_INVALID_PARAMETER &&
1919                  dentry_is_root(inode_first_extraction_dentry(inode))))
1920         {
1921                 set_errno_from_nt_status(status);
1922                 ERROR_WITH_ERRNO("Can't set basic metadata on \"%ls\" "
1923                                  "(status=0x%08"PRIx32")",
1924                                  current_path(ctx), (u32)status);
1925                 return WIMLIB_ERR_SET_ATTRIBUTES;
1926         }
1927
1928         return 0;
1929 }
1930
1931 static int
1932 apply_metadata_to_file(const struct wim_dentry *dentry,
1933                        struct win32_apply_ctx *ctx)
1934 {
1935         const struct wim_inode *inode = dentry->d_inode;
1936         DWORD perms;
1937         HANDLE h;
1938         NTSTATUS status;
1939         int ret;
1940
1941         perms = FILE_WRITE_ATTRIBUTES | WRITE_DAC |
1942                 WRITE_OWNER | ACCESS_SYSTEM_SECURITY;
1943
1944         build_extraction_path(dentry, ctx);
1945
1946         /* Open a handle with as many relevant permissions as possible.  */
1947         while (!NT_SUCCESS(status = do_create_file(&h, perms, NULL,
1948                                                    0, FILE_OPEN, 0, ctx)))
1949         {
1950                 if (status == STATUS_PRIVILEGE_NOT_HELD ||
1951                     status == STATUS_ACCESS_DENIED)
1952                 {
1953                         if (perms & ACCESS_SYSTEM_SECURITY) {
1954                                 perms &= ~ACCESS_SYSTEM_SECURITY;
1955                                 continue;
1956                         }
1957                         if (perms & WRITE_DAC) {
1958                                 perms &= ~WRITE_DAC;
1959                                 continue;
1960                         }
1961                         if (perms & WRITE_OWNER) {
1962                                 perms &= ~WRITE_OWNER;
1963                                 continue;
1964                         }
1965                 }
1966                 set_errno_from_nt_status(status);
1967                 ERROR_WITH_ERRNO("Can't open \"%ls\" to set metadata "
1968                                  "(status=0x%08"PRIx32")",
1969                                  current_path(ctx), (u32)status);
1970                 return WIMLIB_ERR_OPEN;
1971         }
1972
1973         ret = do_apply_metadata_to_file(h, inode, ctx);
1974
1975         (*func_NtClose)(h);
1976
1977         return ret;
1978 }
1979
1980 static int
1981 apply_metadata(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
1982 {
1983         const struct wim_dentry *dentry;
1984         int ret;
1985
1986         /* We go in reverse so that metadata is set on all a directory's
1987          * children before the directory itself.  This avoids any potential
1988          * problems with attributes, timestamps, or security descriptors.  */
1989         list_for_each_entry_reverse(dentry, dentry_list, d_extraction_list_node)
1990         {
1991                 ret = apply_metadata_to_file(dentry, ctx);
1992                 if (ret)
1993                         return ret;
1994                 ret = report_file_metadata_applied(&ctx->common);
1995                 if (ret)
1996                         return ret;
1997         }
1998         return 0;
1999 }
2000
2001 /* Issue warnings about problems during the extraction for which warnings were
2002  * not already issued (due to the high number of potential warnings if we issued
2003  * them per-file).  */
2004 static void
2005 do_warnings(const struct win32_apply_ctx *ctx)
2006 {
2007         if (ctx->partial_security_descriptors == 0 &&
2008             ctx->no_security_descriptors == 0)
2009                 return;
2010
2011         WARNING("Extraction to \"%ls\" complete, but with one or more warnings:",
2012                 ctx->common.target);
2013         if (ctx->partial_security_descriptors != 0) {
2014                 WARNING("- Could only partially set the security descriptor\n"
2015                         "            on %lu files or directories.",
2016                         ctx->partial_security_descriptors);
2017         }
2018         if (ctx->no_security_descriptors != 0) {
2019                 WARNING("- Could not set security descriptor at all\n"
2020                         "            on %lu files or directories.",
2021                         ctx->no_security_descriptors);
2022         }
2023         WARNING("To fully restore all security descriptors, run the program\n"
2024                 "          with Administrator rights.");
2025 }
2026
2027 /* Extract files from a WIM image to a directory on Windows  */
2028 static int
2029 win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
2030 {
2031         int ret;
2032         struct win32_apply_ctx *ctx = (struct win32_apply_ctx *)_ctx;
2033
2034         ret = prepare_target(dentry_list, ctx);
2035         if (ret)
2036                 goto out;
2037
2038         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
2039                 ret = start_wimboot_extraction(ctx);
2040                 if (ret)
2041                         goto out;
2042         }
2043
2044         reset_file_progress(&ctx->common);
2045
2046         ret = create_directories(dentry_list, ctx);
2047         if (ret)
2048                 goto out;
2049
2050         ret = create_nondirectories(dentry_list, ctx);
2051         if (ret)
2052                 goto out;
2053
2054         struct read_stream_list_callbacks cbs = {
2055                 .begin_stream      = begin_extract_stream,
2056                 .begin_stream_ctx  = ctx,
2057                 .consume_chunk     = extract_chunk,
2058                 .consume_chunk_ctx = ctx,
2059                 .end_stream        = end_extract_stream,
2060                 .end_stream_ctx    = ctx,
2061         };
2062         ret = extract_stream_list(&ctx->common, &cbs);
2063         if (ret)
2064                 goto out;
2065
2066         reset_file_progress(&ctx->common);
2067
2068         ret = apply_metadata(dentry_list, ctx);
2069         if (ret)
2070                 goto out;
2071
2072         do_warnings(ctx);
2073 out:
2074         if (ctx->h_target)
2075                 (*func_NtClose)(ctx->h_target);
2076         if (ctx->target_ntpath.Buffer)
2077                 HeapFree(GetProcessHeap(), 0, ctx->target_ntpath.Buffer);
2078         FREE(ctx->pathbuf.Buffer);
2079         FREE(ctx->print_buffer);
2080         if (ctx->wimboot.prepopulate_pats) {
2081                 FREE(ctx->wimboot.prepopulate_pats->strings);
2082                 FREE(ctx->wimboot.prepopulate_pats);
2083         }
2084         FREE(ctx->wimboot.mem_prepopulate_pats);
2085         FREE(ctx->data_buffer);
2086         return ret;
2087 }
2088
2089 const struct apply_operations win32_apply_ops = {
2090         .name                   = "Windows",
2091         .get_supported_features = win32_get_supported_features,
2092         .extract                = win32_extract,
2093         .context_size           = sizeof(struct win32_apply_ctx),
2094 };
2095
2096 #endif /* __WIN32__ */