]> wimlib.net Git - wimlib/blob - src/win32_apply.c
96d9df6f578842eea91fc7b5308066b9a0df5715
[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-2016 Eric Biggers
7  *
8  * This file is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the Free
10  * Software Foundation; either version 3 of the License, or (at your option) any
11  * later version.
12  *
13  * This file is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this file; if not, see http://www.gnu.org/licenses/.
20  */
21
22 #ifdef __WIN32__
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "wimlib/win32_common.h"
29
30 #include "wimlib/apply.h"
31 #include "wimlib/assert.h"
32 #include "wimlib/blob_table.h"
33 #include "wimlib/dentry.h"
34 #include "wimlib/encoding.h"
35 #include "wimlib/error.h"
36 #include "wimlib/metadata.h"
37 #include "wimlib/object_id.h"
38 #include "wimlib/paths.h"
39 #include "wimlib/pattern.h"
40 #include "wimlib/reparse.h"
41 #include "wimlib/scan.h" /* for mangle_pat() and match_pattern_list()  */
42 #include "wimlib/textfile.h"
43 #include "wimlib/xml.h"
44 #include "wimlib/wimboot.h"
45 #include "wimlib/wof.h"
46
47 struct win32_apply_ctx {
48
49         /* Extract flags, the pointer to the WIMStruct, etc.  */
50         struct apply_ctx common;
51
52         /* WIMBoot information, only filled in if WIMLIB_EXTRACT_FLAG_WIMBOOT
53          * was provided  */
54         struct {
55                 /* This array contains the WIM files registered with WOF on the
56                  * target volume for this extraction operation.  All WIMStructs
57                  * in this array are distinct and have ->filename != NULL.  */
58                 struct wimboot_wim {
59                         WIMStruct *wim;
60                         u64 data_source_id;
61                         u8 blob_table_hash[SHA1_HASH_SIZE];
62                 } *wims;
63                 size_t num_wims;
64                 bool wof_running;
65                 bool have_wrong_version_wims;
66                 bool have_uncompressed_wims;
67                 bool have_unsupported_compressed_resources;
68                 bool have_huge_resources;
69         } wimboot;
70
71         /* External backing information  */
72         struct string_list *prepopulate_pats;
73         void *mem_prepopulate_pats;
74         bool tried_to_load_prepopulate_list;
75
76         /* Open handle to the target directory  */
77         HANDLE h_target;
78
79         /* NT namespace path to the target directory (buffer allocated)  */
80         UNICODE_STRING target_ntpath;
81
82         /* Temporary buffer for building paths (buffer allocated)  */
83         UNICODE_STRING pathbuf;
84
85         /* Object attributes to reuse for opening files in the target directory.
86          * (attr.ObjectName == &pathbuf) and (attr.RootDirectory == h_target).
87          */
88         OBJECT_ATTRIBUTES attr;
89
90         /* Temporary I/O status block for system calls  */
91         IO_STATUS_BLOCK iosb;
92
93         /* Allocated buffer for creating "printable" paths from our
94          * target-relative NT paths  */
95         wchar_t *print_buffer;
96
97         /* Allocated buffer for reading blob data when it cannot be extracted
98          * directly  */
99         u8 *data_buffer;
100
101         /* Pointer to the next byte in @data_buffer to fill  */
102         u8 *data_buffer_ptr;
103
104         /* Size allocated in @data_buffer  */
105         size_t data_buffer_size;
106
107         /* Current offset in the raw encrypted file being written  */
108         size_t encrypted_offset;
109
110         /* Current size of the raw encrypted file being written  */
111         size_t encrypted_size;
112
113         /* Temporary buffer for reparse data  */
114         struct reparse_buffer_disk rpbuf;
115
116         /* Temporary buffer for reparse data of "fixed" absolute symbolic links
117          * and junctions  */
118         struct reparse_buffer_disk rpfixbuf;
119
120         /* Array of open handles to filesystem streams currently being written
121          */
122         HANDLE open_handles[MAX_OPEN_FILES];
123
124         /* Number of handles in @open_handles currently open (filled in from the
125          * beginning of the array)  */
126         unsigned num_open_handles;
127
128         /* For each currently open stream, whether we're writing to it in
129          * "sparse" mode or not.  */
130         bool is_sparse_stream[MAX_OPEN_FILES];
131
132         /* Whether is_sparse_stream[] is true for any currently open stream  */
133         bool any_sparse_streams;
134
135         /* List of dentries, joined by @d_tmp_list, that need to have reparse
136          * data extracted as soon as the whole blob has been read into
137          * @data_buffer.  */
138         struct list_head reparse_dentries;
139
140         /* List of dentries, joined by @d_tmp_list, that need to have raw
141          * encrypted data extracted as soon as the whole blob has been read into
142          * @data_buffer.  */
143         struct list_head encrypted_dentries;
144
145         /* Number of files for which we didn't have permission to set the full
146          * security descriptor.  */
147         unsigned long partial_security_descriptors;
148
149         /* Number of files for which we didn't have permission to set any part
150          * of the security descriptor.  */
151         unsigned long no_security_descriptors;
152
153         /* Number of files for which we couldn't set the short name.  */
154         unsigned long num_set_short_name_failures;
155
156         /* Number of files for which we couldn't remove the short name.  */
157         unsigned long num_remove_short_name_failures;
158
159         /* Number of files on which we couldn't set System Compression.  */
160         unsigned long num_system_compression_failures;
161
162         /* The number of files which, for compatibility with the Windows
163          * bootloader, were not compressed using the requested system
164          * compression format.  This includes matches with the hardcoded pattern
165          * list only; it does not include matches with patterns in
166          * [PrepopulateList].  */
167         unsigned long num_system_compression_exclusions;
168
169         /* Number of files for which we couldn't set the object ID.  */
170         unsigned long num_object_id_failures;
171
172         /* The Windows build number of the image being applied, or 0 if unknown.
173          */
174         u64 windows_build_number;
175
176         /* Have we tried to enable short name support on the target volume yet?
177          */
178         bool tried_to_enable_short_names;
179 };
180
181 /* Get the drive letter from a Windows path, or return the null character if the
182  * path is relative.  */
183 static wchar_t
184 get_drive_letter(const wchar_t *path)
185 {
186         /* Skip \\?\ prefix  */
187         if (!wcsncmp(path, L"\\\\?\\", 4))
188                 path += 4;
189
190         /* Return drive letter if valid  */
191         if (((path[0] >= L'a' && path[0] <= L'z') ||
192              (path[0] >= L'A' && path[0] <= L'Z')) && path[1] == L':')
193                 return path[0];
194
195         return L'\0';
196 }
197
198 static void
199 get_vol_flags(const wchar_t *target, DWORD *vol_flags_ret,
200               bool *short_names_supported_ret)
201 {
202         wchar_t filesystem_name[MAX_PATH + 1];
203         wchar_t drive[4];
204         wchar_t *volume = NULL;
205
206         *vol_flags_ret = 0;
207         *short_names_supported_ret = false;
208
209         drive[0] = get_drive_letter(target);
210         if (drive[0]) {
211                 drive[1] = L':';
212                 drive[2] = L'\\';
213                 drive[3] = L'\0';
214                 volume = drive;
215         }
216
217         if (!GetVolumeInformation(volume, NULL, 0, NULL, NULL,
218                                   vol_flags_ret, filesystem_name,
219                                   ARRAY_LEN(filesystem_name)))
220         {
221                 win32_warning(GetLastError(),
222                               L"Failed to get volume information for \"%ls\"",
223                               target);
224                 return;
225         }
226
227         if (wcsstr(filesystem_name, L"NTFS")) {
228                 /* FILE_SUPPORTS_HARD_LINKS is only supported on Windows 7 and
229                  * later.  Force it on anyway if filesystem is NTFS.  */
230                 *vol_flags_ret |= FILE_SUPPORTS_HARD_LINKS;
231
232                 /* There's no volume flag for short names, but according to the
233                  * MS documentation they are only user-settable on NTFS.  */
234                 *short_names_supported_ret = true;
235         }
236 }
237
238 /* Is the image being extracted an OS image for Windows 10 or later?  */
239 static bool
240 is_image_windows_10_or_later(struct win32_apply_ctx *ctx)
241 {
242         /* Note: if no build number is available, this returns false.  */
243         return ctx->windows_build_number >= 10240;
244 }
245
246 static const wchar_t *
247 current_path(struct win32_apply_ctx *ctx);
248
249 static void
250 build_extraction_path(const struct wim_dentry *dentry,
251                       struct win32_apply_ctx *ctx);
252
253 static int
254 report_dentry_apply_error(const struct wim_dentry *dentry,
255                           struct win32_apply_ctx *ctx, int ret)
256 {
257         build_extraction_path(dentry, ctx);
258         return report_apply_error(&ctx->common, ret, current_path(ctx));
259 }
260
261 static inline int
262 check_apply_error(const struct wim_dentry *dentry,
263                   struct win32_apply_ctx *ctx, int ret)
264 {
265         if (unlikely(ret))
266                 ret = report_dentry_apply_error(dentry, ctx, ret);
267         return ret;
268 }
269
270 static int
271 win32_get_supported_features(const wchar_t *target,
272                              struct wim_features *supported_features)
273 {
274         DWORD vol_flags;
275         bool short_names_supported;
276
277         /* Query the features of the target volume.  */
278
279         get_vol_flags(target, &vol_flags, &short_names_supported);
280
281         supported_features->readonly_files = 1;
282         supported_features->hidden_files = 1;
283         supported_features->system_files = 1;
284         supported_features->archive_files = 1;
285
286         if (vol_flags & FILE_FILE_COMPRESSION)
287                 supported_features->compressed_files = 1;
288
289         if (vol_flags & FILE_SUPPORTS_ENCRYPTION) {
290                 supported_features->encrypted_files = 1;
291                 supported_features->encrypted_directories = 1;
292         }
293
294         supported_features->not_context_indexed_files = 1;
295
296         if (vol_flags & FILE_SUPPORTS_SPARSE_FILES)
297                 supported_features->sparse_files = 1;
298
299         if (vol_flags & FILE_NAMED_STREAMS)
300                 supported_features->named_data_streams = 1;
301
302         if (vol_flags & FILE_SUPPORTS_HARD_LINKS)
303                 supported_features->hard_links = 1;
304
305         if (vol_flags & FILE_SUPPORTS_REPARSE_POINTS)
306                 supported_features->reparse_points = 1;
307
308         if (vol_flags & FILE_PERSISTENT_ACLS)
309                 supported_features->security_descriptors = 1;
310
311         if (short_names_supported)
312                 supported_features->short_names = 1;
313
314         if (vol_flags & FILE_SUPPORTS_OBJECT_IDS)
315                 supported_features->object_ids = 1;
316
317         supported_features->timestamps = 1;
318
319         if (vol_flags & FILE_CASE_SENSITIVE_SEARCH) {
320                 /*
321                  * The filesystem supports case-sensitive filenames.  But does
322                  * the operating system as well?  This normally requires the
323                  * registry setting ObCaseInsensitive=0.  We can test it
324                  * indirectly by attempting to open the "\SystemRoot" symbolic
325                  * link using a name with the wrong case.  If we get
326                  * STATUS_OBJECT_NAME_NOT_FOUND instead of STATUS_ACCESS_DENIED,
327                  * then case-sensitive names must be enabled.
328                  */
329                 UNICODE_STRING path;
330                 OBJECT_ATTRIBUTES attr;
331                 HANDLE h;
332                 NTSTATUS status;
333
334                 RtlInitUnicodeString(&path, L"\\systemroot");
335                 InitializeObjectAttributes(&attr, &path, 0, NULL, NULL);
336
337                 status = NtOpenSymbolicLinkObject(&h, 0, &attr);
338                 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
339                         supported_features->case_sensitive_filenames = 1;
340         }
341
342         return 0;
343 }
344
345 #define COMPACT_FLAGS   (WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS4K |         \
346                          WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS8K |         \
347                          WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS16K |        \
348                          WIMLIB_EXTRACT_FLAG_COMPACT_LZX)
349
350
351
352 /*
353  * If not done already, load the patterns from the [PrepopulateList] section of
354  * WimBootCompress.ini in the WIM image being extracted.
355  *
356  * Note: WimBootCompress.ini applies to both types of "external backing":
357  *
358  *      - WIM backing ("WIMBoot" - Windows 8.1 and later)
359  *      - File backing ("System Compression" - Windows 10 and later)
360  */
361 static int
362 load_prepopulate_pats(struct win32_apply_ctx *ctx)
363 {
364         const wchar_t *path = L"\\Windows\\System32\\WimBootCompress.ini";
365         struct wim_dentry *dentry;
366         const struct blob_descriptor *blob;
367         int ret;
368         void *buf;
369         struct string_list *strings;
370         void *mem;
371         struct text_file_section sec;
372
373         if (ctx->tried_to_load_prepopulate_list)
374                 return 0;
375
376         ctx->tried_to_load_prepopulate_list = true;
377
378         dentry = get_dentry(ctx->common.wim, path, WIMLIB_CASE_INSENSITIVE);
379         if (!dentry ||
380             (dentry->d_inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
381                                               FILE_ATTRIBUTE_REPARSE_POINT |
382                                               FILE_ATTRIBUTE_ENCRYPTED)) ||
383             !(blob = inode_get_blob_for_unnamed_data_stream(dentry->d_inode,
384                                                             ctx->common.wim->blob_table)))
385         {
386                 WARNING("%ls does not exist in the WIM image.\n"
387                         "          The default configuration will be used instead; it assumes that all\n"
388                         "          files are valid for external backing regardless of path, equivalent\n"
389                         "          to an empty [PrepopulateList] section.", path);
390                 return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
391         }
392
393         ret = read_blob_into_alloc_buf(blob, &buf);
394         if (ret)
395                 return ret;
396
397         strings = CALLOC(1, sizeof(struct string_list));
398         if (!strings) {
399                 FREE(buf);
400                 return WIMLIB_ERR_NOMEM;
401         }
402
403         sec.name = T("PrepopulateList");
404         sec.strings = strings;
405
406         ret = do_load_text_file(path, buf, blob->size, &mem, &sec, 1,
407                                 LOAD_TEXT_FILE_REMOVE_QUOTES |
408                                         LOAD_TEXT_FILE_NO_WARNINGS,
409                                 mangle_pat);
410         STATIC_ASSERT(OS_PREFERRED_PATH_SEPARATOR == WIM_PATH_SEPARATOR);
411         FREE(buf);
412         if (ret) {
413                 FREE(strings);
414                 return ret;
415         }
416         ctx->prepopulate_pats = strings;
417         ctx->mem_prepopulate_pats = mem;
418         return 0;
419 }
420
421 /* Returns %true if the specified absolute path to a file in the WIM image can
422  * be subject to external backing when extracted.  Otherwise returns %false.  */
423 static bool
424 can_externally_back_path(const wchar_t *path, const struct win32_apply_ctx *ctx)
425 {
426         /* Does the path match a pattern given in the [PrepopulateList] section
427          * of WimBootCompress.ini?  */
428         if (ctx->prepopulate_pats && match_pattern_list(path, ctx->prepopulate_pats))
429                 return false;
430
431         /* Since we attempt to modify the SYSTEM registry after it's extracted
432          * (see end_wimboot_extraction()), it can't be extracted as externally
433          * backed.  This extends to associated files such as SYSTEM.LOG that
434          * also must be writable in order to write to the registry.  Normally,
435          * SYSTEM is in [PrepopulateList], and the SYSTEM.* files match patterns
436          * in [ExclusionList] and therefore are not captured in the WIM at all.
437          * However, a WIM that wasn't specifically captured in "WIMBoot mode"
438          * may contain SYSTEM.* files.  So to make things "just work", hard-code
439          * the pattern.  */
440         if (match_path(path, L"\\Windows\\System32\\config\\SYSTEM*", false))
441                 return false;
442
443         return true;
444 }
445
446 /* Can the specified WIM resource be used as the source of an external backing
447  * for the wof.sys WIM provider?  */
448 static bool
449 is_resource_valid_for_external_backing(const struct wim_resource_descriptor *rdesc,
450                                        struct win32_apply_ctx *ctx)
451 {
452         /* Must be the original WIM file format.  This check excludes pipable
453          * resources and solid resources.  It also excludes other resources
454          * contained in such files even if they would be otherwise compatible.
455          */
456         if (rdesc->wim->hdr.magic != WIM_MAGIC ||
457             rdesc->wim->hdr.wim_version != WIM_VERSION_DEFAULT)
458         {
459                 ctx->wimboot.have_wrong_version_wims = true;
460                 return false;
461         }
462
463         /*
464          * Whitelist of compression types and chunk sizes supported by
465          * Microsoft's WOF driver.
466          *
467          * Notes:
468          *    - Uncompressed WIMs result in BSOD.  However, this only applies to
469          *      the WIM file itself, not to uncompressed resources in a WIM file
470          *      that is otherwise compressed.
471          *    - XPRESS 64K sometimes appears to work, but sometimes it causes
472          *      reads to fail with STATUS_UNSUCCESSFUL.
473          */
474         switch (rdesc->compression_type) {
475         case WIMLIB_COMPRESSION_TYPE_NONE:
476                 if (rdesc->wim->compression_type == WIMLIB_COMPRESSION_TYPE_NONE) {
477                         ctx->wimboot.have_uncompressed_wims = true;
478                         return false;
479                 }
480                 break;
481         case WIMLIB_COMPRESSION_TYPE_XPRESS:
482                 switch (rdesc->chunk_size) {
483                 case 4096:
484                 case 8192:
485                 case 16384:
486                 case 32768:
487                         break;
488                 default:
489                         ctx->wimboot.have_unsupported_compressed_resources = true;
490                         return false;
491                 }
492                 break;
493         case WIMLIB_COMPRESSION_TYPE_LZX:
494                 switch (rdesc->chunk_size) {
495                 case 32768:
496                         break;
497                 default:
498                         ctx->wimboot.have_unsupported_compressed_resources = true;
499                         return false;
500                 }
501                 break;
502         default:
503                 ctx->wimboot.have_unsupported_compressed_resources = true;
504                 return false;
505         }
506
507         /* Microsoft's WoF driver errors out if it tries to satisfy a read with
508          * ending offset >= 4 GiB from an externally backed file.  */
509         if (rdesc->uncompressed_size > 4200000000) {
510                 ctx->wimboot.have_huge_resources = true;
511                 return false;
512         }
513
514         return true;
515 }
516
517 #define EXTERNAL_BACKING_NOT_ENABLED            -1
518 #define EXTERNAL_BACKING_NOT_POSSIBLE           -2
519 #define EXTERNAL_BACKING_EXCLUDED               -3
520
521 /*
522  * Determines whether the specified file will be externally backed.  Returns a
523  * negative status code if no, 0 if yes, or a positive wimlib error code on
524  * error.  If the file is excluded from external backing based on its path, then
525  * *excluded_dentry_ret is set to the dentry for the path that matched the
526  * exclusion rule.
527  *
528  * Note that this logic applies to both types of "external backing":
529  *
530  *      - WIM backing ("WIMBoot" - Windows 8.1 and later)
531  *      - File backing ("System Compression" - Windows 10 and later)
532  *
533  * However, in the case of WIM backing we also need to validate that the WIM
534  * resource that would be the source of the backing is supported by the wof.sys
535  * WIM provider.
536  */
537 static int
538 will_externally_back_inode(struct wim_inode *inode, struct win32_apply_ctx *ctx,
539                            const struct wim_dentry **excluded_dentry_ret,
540                            bool wimboot_mode)
541 {
542         struct wim_dentry *dentry;
543         struct blob_descriptor *blob;
544         int ret;
545
546         if (load_prepopulate_pats(ctx) == WIMLIB_ERR_NOMEM)
547                 return WIMLIB_ERR_NOMEM;
548
549         if (inode->i_can_externally_back)
550                 return 0;
551
552         /* This may do redundant checks because the cached value
553          * i_can_externally_back is 2-state (as opposed to 3-state:
554          * unknown/no/yes).  But most files can be externally backed, so this
555          * way is fine.  */
556
557         if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
558                                    FILE_ATTRIBUTE_REPARSE_POINT |
559                                    FILE_ATTRIBUTE_ENCRYPTED))
560                 return EXTERNAL_BACKING_NOT_POSSIBLE;
561
562         blob = inode_get_blob_for_unnamed_data_stream_resolved(inode);
563
564         if (!blob)
565                 return EXTERNAL_BACKING_NOT_POSSIBLE;
566
567         if (wimboot_mode &&
568             (blob->blob_location != BLOB_IN_WIM ||
569              !is_resource_valid_for_external_backing(blob->rdesc, ctx)))
570                 return EXTERNAL_BACKING_NOT_POSSIBLE;
571
572         /*
573          * We need to check the patterns in [PrepopulateList] against every name
574          * of the inode, in case any of them match.
575          */
576
577         inode_for_each_extraction_alias(dentry, inode) {
578
579                 ret = calculate_dentry_full_path(dentry);
580                 if (ret)
581                         return ret;
582
583                 if (!can_externally_back_path(dentry->d_full_path, ctx)) {
584                         if (excluded_dentry_ret)
585                                 *excluded_dentry_ret = dentry;
586                         return EXTERNAL_BACKING_EXCLUDED;
587                 }
588         }
589
590         inode->i_can_externally_back = 1;
591         return 0;
592 }
593
594 /*
595  * Determines if the unnamed data stream of a file will be created as a WIM
596  * external backing (a "WIMBoot pointer file"), as opposed to a standard
597  * extraction.
598  */
599 static int
600 win32_will_back_from_wim(struct wim_dentry *dentry, struct apply_ctx *_ctx)
601 {
602         struct win32_apply_ctx *ctx = (struct win32_apply_ctx *)_ctx;
603
604         if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT))
605                 return EXTERNAL_BACKING_NOT_ENABLED;
606
607         return will_externally_back_inode(dentry->d_inode, ctx, NULL, true);
608 }
609
610 /* Find the WOF registration information for the specified WIM file.  */
611 static struct wimboot_wim *
612 find_wimboot_wim(WIMStruct *wim_to_find, struct win32_apply_ctx *ctx)
613 {
614         for (size_t i = 0; i < ctx->wimboot.num_wims; i++)
615                 if (wim_to_find == ctx->wimboot.wims[i].wim)
616                         return &ctx->wimboot.wims[i];
617
618         wimlib_assert(0);
619         return NULL;
620 }
621
622 static int
623 set_backed_from_wim(HANDLE h, struct wim_inode *inode, struct win32_apply_ctx *ctx)
624 {
625         int ret;
626         const struct wim_dentry *excluded_dentry;
627         const struct blob_descriptor *blob;
628         const struct wimboot_wim *wimboot_wim;
629
630         ret = will_externally_back_inode(inode, ctx, &excluded_dentry, true);
631         if (ret > 0) /* Error.  */
632                 return ret;
633
634         if (ret < 0 && ret != EXTERNAL_BACKING_EXCLUDED)
635                 return 0; /* Not externally backing, other than due to exclusion.  */
636
637         if (unlikely(ret == EXTERNAL_BACKING_EXCLUDED)) {
638                 /* Not externally backing due to exclusion.  */
639                 union wimlib_progress_info info;
640
641                 build_extraction_path(excluded_dentry, ctx);
642
643                 info.wimboot_exclude.path_in_wim = excluded_dentry->d_full_path;
644                 info.wimboot_exclude.extraction_path = current_path(ctx);
645
646                 return call_progress(ctx->common.progfunc,
647                                      WIMLIB_PROGRESS_MSG_WIMBOOT_EXCLUDE,
648                                      &info, ctx->common.progctx);
649         }
650
651         /* Externally backing.  */
652
653         blob = inode_get_blob_for_unnamed_data_stream_resolved(inode);
654         wimboot_wim = find_wimboot_wim(blob->rdesc->wim, ctx);
655
656         if (unlikely(!wimboot_set_pointer(h,
657                                           blob,
658                                           wimboot_wim->data_source_id,
659                                           wimboot_wim->blob_table_hash,
660                                           ctx->wimboot.wof_running)))
661         {
662                 const DWORD err = GetLastError();
663
664                 build_extraction_path(inode_first_extraction_dentry(inode), ctx);
665                 win32_error(err, L"\"%ls\": Couldn't set WIMBoot pointer data",
666                             current_path(ctx));
667                 return WIMLIB_ERR_WIMBOOT;
668         }
669         return 0;
670 }
671
672 /* Calculates the SHA-1 message digest of the WIM's blob table.  */
673 static int
674 hash_blob_table(WIMStruct *wim, u8 hash[SHA1_HASH_SIZE])
675 {
676         return wim_reshdr_to_hash(&wim->hdr.blob_table_reshdr, wim, hash);
677 }
678
679 static int
680 register_wim_with_wof(WIMStruct *wim, struct win32_apply_ctx *ctx)
681 {
682         struct wimboot_wim *p;
683         int ret;
684
685         /* Check if already registered  */
686         for (size_t i = 0; i < ctx->wimboot.num_wims; i++)
687                 if (wim == ctx->wimboot.wims[i].wim)
688                         return 0;
689
690         /* Not yet registered  */
691
692         p = REALLOC(ctx->wimboot.wims,
693                     (ctx->wimboot.num_wims + 1) * sizeof(ctx->wimboot.wims[0]));
694         if (!p)
695                 return WIMLIB_ERR_NOMEM;
696         ctx->wimboot.wims = p;
697
698         ctx->wimboot.wims[ctx->wimboot.num_wims].wim = wim;
699
700         ret = hash_blob_table(wim, ctx->wimboot.wims[ctx->wimboot.num_wims].blob_table_hash);
701         if (ret)
702                 return ret;
703
704         ret = wimboot_alloc_data_source_id(wim->filename,
705                                            wim->hdr.guid,
706                                            ctx->common.wim->current_image,
707                                            ctx->common.target,
708                                            &ctx->wimboot.wims[ctx->wimboot.num_wims].data_source_id,
709                                            &ctx->wimboot.wof_running);
710         if (ret)
711                 return ret;
712
713         ctx->wimboot.num_wims++;
714         return 0;
715 }
716
717 /* Prepare for doing a "WIMBoot" extraction by registering each source WIM file
718  * with WOF on the target volume.  */
719 static int
720 start_wimboot_extraction(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
721 {
722         int ret;
723         struct wim_dentry *dentry;
724
725         if (!xml_get_wimboot(ctx->common.wim->xml_info,
726                              ctx->common.wim->current_image))
727                 WARNING("The WIM image is not marked as WIMBoot compatible.  This usually\n"
728                         "          means it is not intended to be used to back a Windows operating\n"
729                         "          system.  Proceeding anyway.");
730
731         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
732                 struct blob_descriptor *blob;
733
734                 ret = win32_will_back_from_wim(dentry, &ctx->common);
735                 if (ret > 0) /* Error */
736                         return ret;
737                 if (ret < 0) /* Won't externally back */
738                         continue;
739
740                 blob = inode_get_blob_for_unnamed_data_stream_resolved(dentry->d_inode);
741                 ret = register_wim_with_wof(blob->rdesc->wim, ctx);
742                 if (ret)
743                         return ret;
744         }
745
746         if (ctx->wimboot.have_wrong_version_wims) {
747   WARNING("At least one of the source WIM files uses a version of the WIM\n"
748 "          file format that not supported by Microsoft's wof.sys driver.\n"
749 "          Files whose data is contained in one of these WIM files will be\n"
750 "          extracted as full files rather than externally backed.");
751         }
752
753         if (ctx->wimboot.have_uncompressed_wims) {
754   WARNING("At least one of the source WIM files is uncompressed.  Files whose\n"
755 "          data is contained in an uncompressed WIM file will be extracted as\n"
756 "          full files rather than externally backed, since uncompressed WIM\n"
757 "          files are not supported by Microsoft's wof.sys driver.");
758         }
759
760         if (ctx->wimboot.have_unsupported_compressed_resources) {
761   WARNING("At least one of the source WIM files uses a compression format that\n"
762 "          is not supported by Microsoft's wof.sys driver.  Files whose data is\n"
763 "          contained in a compressed resource in one of these WIM files will be\n"
764 "          extracted as full files rather than externally backed.  (The\n"
765 "          compression formats supported by wof.sys are: XPRESS 4K, XPRESS 8K,\n"
766 "          XPRESS 16K, XPRESS 32K, and LZX 32K.)");
767         }
768
769         if (ctx->wimboot.have_huge_resources) {
770   WARNING("Some files exceeded 4.2 GB in size.  Such files will be extracted\n"
771 "          as full files rather than externally backed, since very large files\n"
772 "          are not supported by Microsoft's wof.sys driver.");
773         }
774
775         return 0;
776 }
777
778 static void
779 build_win32_extraction_path(const struct wim_dentry *dentry,
780                             struct win32_apply_ctx *ctx);
781
782 /* Sets WimBoot=1 in the extracted SYSTEM registry hive.
783  *
784  * WIMGAPI does this, and it's possible that it's important.
785  * But I don't know exactly what this value means to Windows.  */
786 static int
787 end_wimboot_extraction(struct win32_apply_ctx *ctx)
788 {
789         struct wim_dentry *dentry;
790         wchar_t subkeyname[32];
791         LONG res;
792         LONG res2;
793         HKEY key;
794         DWORD value;
795
796         dentry = get_dentry(ctx->common.wim, L"\\Windows\\System32\\config\\SYSTEM",
797                             WIMLIB_CASE_INSENSITIVE);
798
799         if (!dentry || !will_extract_dentry(dentry))
800                 goto out;
801
802         if (!will_extract_dentry(wim_get_current_root_dentry(ctx->common.wim)))
803                 goto out;
804
805         /* Not bothering to use the native routines (e.g. NtLoadKey()) for this.
806          * If this doesn't work, you probably also have many other problems.  */
807
808         build_win32_extraction_path(dentry, ctx);
809
810         get_random_alnum_chars(subkeyname, 20);
811         subkeyname[20] = L'\0';
812
813         res = RegLoadKey(HKEY_LOCAL_MACHINE, subkeyname, ctx->pathbuf.Buffer);
814         if (res)
815                 goto out_check_res;
816
817         wcscpy(&subkeyname[20], L"\\Setup");
818
819         res = RegCreateKeyEx(HKEY_LOCAL_MACHINE, subkeyname, 0, NULL,
820                              REG_OPTION_BACKUP_RESTORE, 0, NULL, &key, NULL);
821         if (res)
822                 goto out_unload_key;
823
824         value = 1;
825
826         res = RegSetValueEx(key, L"WimBoot", 0, REG_DWORD,
827                             (const BYTE *)&value, sizeof(DWORD));
828         if (res)
829                 goto out_close_key;
830
831         res = RegFlushKey(key);
832
833 out_close_key:
834         res2 = RegCloseKey(key);
835         if (!res)
836                 res = res2;
837 out_unload_key:
838         subkeyname[20] = L'\0';
839         RegUnLoadKey(HKEY_LOCAL_MACHINE, subkeyname);
840 out_check_res:
841         if (res) {
842                 /* Warning only.  */
843                 win32_warning(res, L"Failed to set \\Setup: dword \"WimBoot\"=1 "
844                               "value in registry hive \"%ls\"",
845                               ctx->pathbuf.Buffer);
846         }
847 out:
848         return 0;
849 }
850
851 /* Returns the number of wide characters needed to represent the path to the
852  * specified @dentry, relative to the target directory, when extracted.
853  *
854  * Does not include null terminator (not needed for NtCreateFile).  */
855 static size_t
856 dentry_extraction_path_length(const struct wim_dentry *dentry)
857 {
858         size_t len = 0;
859         const struct wim_dentry *d;
860
861         d = dentry;
862         do {
863                 len += d->d_extraction_name_nchars + 1;
864                 d = d->d_parent;
865         } while (!dentry_is_root(d) && will_extract_dentry(d));
866
867         return --len;  /* No leading slash  */
868 }
869
870 /* Returns the length of the longest string that might need to be appended to
871  * the path to an alias of an inode to open or create a named data stream.
872  *
873  * If the inode has no named data streams, this will be 0.  Otherwise, this will
874  * be 1 plus the length of the longest-named data stream, since the data stream
875  * name must be separated from the path by the ':' character.  */
876 static size_t
877 inode_longest_named_data_stream_spec(const struct wim_inode *inode)
878 {
879         size_t max = 0;
880         for (unsigned i = 0; i < inode->i_num_streams; i++) {
881                 const struct wim_inode_stream *strm = &inode->i_streams[i];
882                 if (!stream_is_named_data_stream(strm))
883                         continue;
884                 size_t len = utf16le_len_chars(strm->stream_name);
885                 if (len > max)
886                         max = len;
887         }
888         if (max)
889                 max += 1;
890         return max;
891 }
892
893 /* Find the length, in wide characters, of the longest path needed for
894  * extraction of any file in @dentry_list relative to the target directory.
895  *
896  * Accounts for named data streams, but does not include null terminator (not
897  * needed for NtCreateFile).  */
898 static size_t
899 compute_path_max(struct list_head *dentry_list)
900 {
901         size_t max = 0;
902         const struct wim_dentry *dentry;
903
904         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
905                 size_t len;
906
907                 len = dentry_extraction_path_length(dentry);
908
909                 /* Account for named data streams  */
910                 len += inode_longest_named_data_stream_spec(dentry->d_inode);
911
912                 if (len > max)
913                         max = len;
914         }
915
916         return max;
917 }
918
919 /* Build the path at which to extract the @dentry, relative to the target
920  * directory.
921  *
922  * The path is saved in ctx->pathbuf.  */
923 static void
924 build_extraction_path(const struct wim_dentry *dentry,
925                       struct win32_apply_ctx *ctx)
926 {
927         size_t len;
928         wchar_t *p;
929         const struct wim_dentry *d;
930
931         len = dentry_extraction_path_length(dentry);
932
933         ctx->pathbuf.Length = len * sizeof(wchar_t);
934         p = ctx->pathbuf.Buffer + len;
935         for (d = dentry;
936              !dentry_is_root(d->d_parent) && will_extract_dentry(d->d_parent);
937              d = d->d_parent)
938         {
939                 p -= d->d_extraction_name_nchars;
940                 if (d->d_extraction_name_nchars)
941                         wmemcpy(p, d->d_extraction_name,
942                                 d->d_extraction_name_nchars);
943                 *--p = '\\';
944         }
945         /* No leading slash  */
946         p -= d->d_extraction_name_nchars;
947         wmemcpy(p, d->d_extraction_name, d->d_extraction_name_nchars);
948 }
949
950 /* Build the path at which to extract the @dentry, relative to the target
951  * directory, adding the suffix for a named data stream.
952  *
953  * The path is saved in ctx->pathbuf.  */
954 static void
955 build_extraction_path_with_ads(const struct wim_dentry *dentry,
956                                struct win32_apply_ctx *ctx,
957                                const wchar_t *stream_name,
958                                size_t stream_name_nchars)
959 {
960         wchar_t *p;
961
962         build_extraction_path(dentry, ctx);
963
964         /* Add :NAME for named data stream  */
965         p = ctx->pathbuf.Buffer + (ctx->pathbuf.Length / sizeof(wchar_t));
966         *p++ = L':';
967         wmemcpy(p, stream_name, stream_name_nchars);
968         ctx->pathbuf.Length += (1 + stream_name_nchars) * sizeof(wchar_t);
969 }
970
971 /* Build the Win32 namespace path to the specified @dentry when extracted.
972  *
973  * The path is saved in ctx->pathbuf and will be null terminated.
974  *
975  * XXX: We could get rid of this if it wasn't needed for the file encryption
976  * APIs, and the registry manipulation in WIMBoot mode.  */
977 static void
978 build_win32_extraction_path(const struct wim_dentry *dentry,
979                             struct win32_apply_ctx *ctx)
980 {
981         build_extraction_path(dentry, ctx);
982
983         /* Prepend target_ntpath to our relative path, then change \??\ into \\?\  */
984
985         memmove(ctx->pathbuf.Buffer +
986                         (ctx->target_ntpath.Length / sizeof(wchar_t)) + 1,
987                 ctx->pathbuf.Buffer, ctx->pathbuf.Length);
988         memcpy(ctx->pathbuf.Buffer, ctx->target_ntpath.Buffer,
989                 ctx->target_ntpath.Length);
990         ctx->pathbuf.Buffer[ctx->target_ntpath.Length / sizeof(wchar_t)] = L'\\';
991         ctx->pathbuf.Length += ctx->target_ntpath.Length + sizeof(wchar_t);
992         ctx->pathbuf.Buffer[ctx->pathbuf.Length / sizeof(wchar_t)] = L'\0';
993
994         wimlib_assert(ctx->pathbuf.Length >= 4 * sizeof(wchar_t) &&
995                       !wmemcmp(ctx->pathbuf.Buffer, L"\\??\\", 4));
996
997         ctx->pathbuf.Buffer[1] = L'\\';
998
999 }
1000
1001 /* Returns a "printable" representation of the last relative NT path that was
1002  * constructed with build_extraction_path() or build_extraction_path_with_ads().
1003  *
1004  * This will be overwritten by the next call to this function.  */
1005 static const wchar_t *
1006 current_path(struct win32_apply_ctx *ctx)
1007 {
1008         wchar_t *p = ctx->print_buffer;
1009
1010         p = wmempcpy(p, ctx->common.target, ctx->common.target_nchars);
1011         *p++ = L'\\';
1012         p = wmempcpy(p, ctx->pathbuf.Buffer, ctx->pathbuf.Length / sizeof(wchar_t));
1013         *p = L'\0';
1014         return ctx->print_buffer;
1015 }
1016
1017 /* Open handle to the target directory if it is not already open.  If the target
1018  * directory does not exist, this creates it.  */
1019 static int
1020 open_target_directory(struct win32_apply_ctx *ctx)
1021 {
1022         NTSTATUS status;
1023
1024         if (ctx->h_target)
1025                 return 0;
1026
1027         ctx->attr.Length = sizeof(ctx->attr);
1028         ctx->attr.RootDirectory = NULL;
1029         ctx->attr.ObjectName = &ctx->target_ntpath;
1030
1031         /* Don't use FILE_OPEN_REPARSE_POINT here; we want the extraction to
1032          * happen at the directory "pointed to" by the reparse point. */
1033         status = NtCreateFile(&ctx->h_target,
1034                               FILE_TRAVERSE,
1035                               &ctx->attr,
1036                               &ctx->iosb,
1037                               NULL,
1038                               0,
1039                               FILE_SHARE_VALID_FLAGS,
1040                               FILE_OPEN_IF,
1041                               FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT,
1042                               NULL,
1043                               0);
1044         if (!NT_SUCCESS(status)) {
1045                 winnt_error(status, L"Can't open or create directory \"%ls\"",
1046                             ctx->common.target);
1047                 return WIMLIB_ERR_OPENDIR;
1048         }
1049         ctx->attr.RootDirectory = ctx->h_target;
1050         ctx->attr.ObjectName = &ctx->pathbuf;
1051         return 0;
1052 }
1053
1054 static void
1055 close_target_directory(struct win32_apply_ctx *ctx)
1056 {
1057         if (ctx->h_target) {
1058                 NtClose(ctx->h_target);
1059                 ctx->h_target = NULL;
1060                 ctx->attr.RootDirectory = NULL;
1061         }
1062 }
1063
1064 /*
1065  * Ensures the target directory exists and opens a handle to it, in preparation
1066  * of using paths relative to it.
1067  */
1068 static int
1069 prepare_target(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
1070 {
1071         int ret;
1072         size_t path_max;
1073
1074         ret = win32_path_to_nt_path(ctx->common.target, &ctx->target_ntpath);
1075         if (ret)
1076                 return ret;
1077
1078         ret = open_target_directory(ctx);
1079         if (ret)
1080                 return ret;
1081
1082         path_max = compute_path_max(dentry_list);
1083         /* Add some extra for building Win32 paths for the file encryption APIs,
1084          * and ensure we have at least enough to potentially use a 8.3 name for
1085          * the last component.  */
1086         path_max += max(2 + (ctx->target_ntpath.Length / sizeof(wchar_t)),
1087                         8 + 1 + 3);
1088
1089         ctx->pathbuf.MaximumLength = path_max * sizeof(wchar_t);
1090         ctx->pathbuf.Buffer = MALLOC(ctx->pathbuf.MaximumLength);
1091         if (!ctx->pathbuf.Buffer)
1092                 return WIMLIB_ERR_NOMEM;
1093
1094         ctx->print_buffer = MALLOC((ctx->common.target_nchars + 1 + path_max + 1) *
1095                                    sizeof(wchar_t));
1096         if (!ctx->print_buffer)
1097                 return WIMLIB_ERR_NOMEM;
1098
1099         return 0;
1100 }
1101
1102 /* When creating an inode that will have a short (DOS) name, we create it using
1103  * the long name associated with the short name.  This ensures that the short
1104  * name gets associated with the correct long name.  */
1105 static struct wim_dentry *
1106 first_extraction_alias(const struct wim_inode *inode)
1107 {
1108         struct wim_dentry *dentry;
1109
1110         inode_for_each_extraction_alias(dentry, inode)
1111                 if (dentry_has_short_name(dentry))
1112                         return dentry;
1113         return inode_first_extraction_dentry(inode);
1114 }
1115
1116 /*
1117  * Set or clear FILE_ATTRIBUTE_COMPRESSED if the inherited value is different
1118  * from the desired value.
1119  *
1120  * Note that you can NOT override the inherited value of
1121  * FILE_ATTRIBUTE_COMPRESSED directly with NtCreateFile().
1122  */
1123 static int
1124 adjust_compression_attribute(HANDLE h, const struct wim_dentry *dentry,
1125                              struct win32_apply_ctx *ctx)
1126 {
1127         const bool compressed = (dentry->d_inode->i_attributes &
1128                                  FILE_ATTRIBUTE_COMPRESSED);
1129         FILE_BASIC_INFORMATION info;
1130         USHORT compression_state;
1131         NTSTATUS status;
1132
1133         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)
1134                 return 0;
1135
1136         if (!ctx->common.supported_features.compressed_files)
1137                 return 0;
1138
1139
1140         /* Get current attributes  */
1141         status = NtQueryInformationFile(h, &ctx->iosb, &info, sizeof(info),
1142                                         FileBasicInformation);
1143         if (NT_SUCCESS(status) &&
1144             compressed == !!(info.FileAttributes & FILE_ATTRIBUTE_COMPRESSED))
1145         {
1146                 /* Nothing needs to be done.  */
1147                 return 0;
1148         }
1149
1150         /* Set the new compression state  */
1151
1152         if (compressed)
1153                 compression_state = COMPRESSION_FORMAT_DEFAULT;
1154         else
1155                 compression_state = COMPRESSION_FORMAT_NONE;
1156
1157         status = winnt_fsctl(h, FSCTL_SET_COMPRESSION,
1158                              &compression_state, sizeof(USHORT), NULL, 0, NULL);
1159         if (NT_SUCCESS(status))
1160                 return 0;
1161
1162         winnt_error(status, L"Can't %s compression attribute on \"%ls\"",
1163                     (compressed ? "set" : "clear"), current_path(ctx));
1164         return WIMLIB_ERR_SET_ATTRIBUTES;
1165 }
1166
1167 static bool
1168 need_sparse_flag(const struct wim_inode *inode,
1169                  const struct win32_apply_ctx *ctx)
1170 {
1171         return (inode->i_attributes & FILE_ATTRIBUTE_SPARSE_FILE) &&
1172                 ctx->common.supported_features.sparse_files;
1173 }
1174
1175 static int
1176 set_sparse_flag(HANDLE h, struct win32_apply_ctx *ctx)
1177 {
1178         NTSTATUS status;
1179
1180         status = winnt_fsctl(h, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, NULL);
1181         if (NT_SUCCESS(status))
1182                 return 0;
1183
1184         winnt_error(status, L"Can't set sparse flag on \"%ls\"",
1185                     current_path(ctx));
1186         return WIMLIB_ERR_SET_ATTRIBUTES;
1187 }
1188
1189 /* Try to enable short name support on the target volume.  If successful, return
1190  * true.  If unsuccessful, issue a warning and return false.  */
1191 static bool
1192 try_to_enable_short_names(const wchar_t *volume)
1193 {
1194         HANDLE h;
1195         FILE_FS_PERSISTENT_VOLUME_INFORMATION info;
1196         BOOL bret;
1197         DWORD bytesReturned;
1198
1199         h = CreateFile(volume, GENERIC_WRITE,
1200                        FILE_SHARE_VALID_FLAGS, NULL, OPEN_EXISTING,
1201                        FILE_FLAG_BACKUP_SEMANTICS, NULL);
1202         if (h == INVALID_HANDLE_VALUE)
1203                 goto fail;
1204
1205         info.VolumeFlags = 0;
1206         info.FlagMask = PERSISTENT_VOLUME_STATE_SHORT_NAME_CREATION_DISABLED;
1207         info.Version = 1;
1208         info.Reserved = 0;
1209
1210         bret = DeviceIoControl(h, FSCTL_SET_PERSISTENT_VOLUME_STATE,
1211                                &info, sizeof(info), NULL, 0,
1212                                &bytesReturned, NULL);
1213
1214         CloseHandle(h);
1215
1216         if (!bret)
1217                 goto fail;
1218         return true;
1219
1220 fail:
1221         win32_warning(GetLastError(),
1222                       L"Failed to enable short name support on %ls",
1223                       volume + 4);
1224         return false;
1225 }
1226
1227 static NTSTATUS
1228 remove_conflicting_short_name(const struct wim_dentry *dentry, struct win32_apply_ctx *ctx)
1229 {
1230         wchar_t *name;
1231         wchar_t *end;
1232         NTSTATUS status;
1233         HANDLE h;
1234         size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) +
1235                          (13 * sizeof(wchar_t));
1236         u8 buf[bufsize] _aligned_attribute(8);
1237         bool retried = false;
1238         FILE_NAME_INFORMATION *info = (FILE_NAME_INFORMATION *)buf;
1239
1240         memset(buf, 0, bufsize);
1241
1242         /* Build the path with the short name.  */
1243         name = &ctx->pathbuf.Buffer[ctx->pathbuf.Length / sizeof(wchar_t)];
1244         while (name != ctx->pathbuf.Buffer && *(name - 1) != L'\\')
1245                 name--;
1246         end = mempcpy(name, dentry->d_short_name, dentry->d_short_name_nbytes);
1247         ctx->pathbuf.Length = ((u8 *)end - (u8 *)ctx->pathbuf.Buffer);
1248
1249         /* Open the conflicting file (by short name).  */
1250         status = NtOpenFile(&h, GENERIC_WRITE | DELETE,
1251                             &ctx->attr, &ctx->iosb,
1252                             FILE_SHARE_VALID_FLAGS,
1253                             FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT);
1254         if (!NT_SUCCESS(status)) {
1255                 winnt_warning(status, L"Can't open \"%ls\"", current_path(ctx));
1256                 goto out;
1257         }
1258
1259 #if 0
1260         WARNING("Overriding conflicting short name; path=\"%ls\"",
1261                 current_path(ctx));
1262 #endif
1263
1264         /* Try to remove the short name on the conflicting file.  */
1265
1266 retry:
1267         status = NtSetInformationFile(h, &ctx->iosb, info, bufsize,
1268                                       FileShortNameInformation);
1269
1270         if (status == STATUS_INVALID_PARAMETER && !retried) {
1271                 /* Microsoft forgot to make it possible to remove short names
1272                  * until Windows 7.  Oops.  Use a random short name instead.  */
1273                 get_random_alnum_chars(info->FileName, 8);
1274                 wcscpy(&info->FileName[8], L".WLB");
1275                 info->FileNameLength = 12 * sizeof(wchar_t);
1276                 retried = true;
1277                 goto retry;
1278         }
1279         NtClose(h);
1280 out:
1281         build_extraction_path(dentry, ctx);
1282         return status;
1283 }
1284
1285 /* Set the short name on the open file @h which has been created at the location
1286  * indicated by @dentry.
1287  *
1288  * Note that this may add, change, or remove the short name.
1289  *
1290  * @h must be opened with DELETE access.
1291  *
1292  * Returns 0 or WIMLIB_ERR_SET_SHORT_NAME.  The latter only happens in
1293  * STRICT_SHORT_NAMES mode.
1294  */
1295 static int
1296 set_short_name(HANDLE h, const struct wim_dentry *dentry,
1297                struct win32_apply_ctx *ctx)
1298 {
1299
1300         if (!ctx->common.supported_features.short_names)
1301                 return 0;
1302
1303         /*
1304          * Note: The size of the FILE_NAME_INFORMATION buffer must be such that
1305          * FileName contains at least 2 wide characters (4 bytes).  Otherwise,
1306          * NtSetInformationFile() will return STATUS_INFO_LENGTH_MISMATCH.  This
1307          * is despite the fact that FileNameLength can validly be 0 or 2 bytes,
1308          * with the former case being removing the existing short name if
1309          * present, rather than setting one.
1310          *
1311          * The null terminator is seemingly optional, but to be safe we include
1312          * space for it and zero all unused space.
1313          */
1314
1315         size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) +
1316                          max(dentry->d_short_name_nbytes, sizeof(wchar_t)) +
1317                          sizeof(wchar_t);
1318         u8 buf[bufsize] _aligned_attribute(8);
1319         FILE_NAME_INFORMATION *info = (FILE_NAME_INFORMATION *)buf;
1320         NTSTATUS status;
1321         bool tried_to_remove_existing = false;
1322
1323         memset(buf, 0, bufsize);
1324
1325         info->FileNameLength = dentry->d_short_name_nbytes;
1326         memcpy(info->FileName, dentry->d_short_name, dentry->d_short_name_nbytes);
1327
1328 retry:
1329         status = NtSetInformationFile(h, &ctx->iosb, info, bufsize,
1330                                       FileShortNameInformation);
1331         if (NT_SUCCESS(status))
1332                 return 0;
1333
1334         if (status == STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME) {
1335                 if (dentry->d_short_name_nbytes == 0)
1336                         return 0;
1337                 if (!ctx->tried_to_enable_short_names) {
1338                         wchar_t volume[7];
1339                         int ret;
1340
1341                         ctx->tried_to_enable_short_names = true;
1342
1343                         ret = win32_get_drive_path(ctx->common.target,
1344                                                    volume);
1345                         if (ret)
1346                                 return ret;
1347                         if (try_to_enable_short_names(volume))
1348                                 goto retry;
1349                 }
1350         }
1351
1352         /*
1353          * Short names can conflict in several cases:
1354          *
1355          * - a file being extracted has a short name conflicting with an
1356          *   existing file
1357          *
1358          * - a file being extracted has a short name conflicting with another
1359          *   file being extracted (possible, but shouldn't happen)
1360          *
1361          * - a file being extracted has a short name that conflicts with the
1362          *   automatically generated short name of a file we previously
1363          *   extracted, but failed to set the short name for.  Sounds unlikely,
1364          *   but this actually does happen fairly often on versions of Windows
1365          *   prior to Windows 7 because they do not support removing short names
1366          *   from files.
1367          */
1368         if (unlikely(status == STATUS_OBJECT_NAME_COLLISION) &&
1369             dentry->d_short_name_nbytes && !tried_to_remove_existing)
1370         {
1371                 tried_to_remove_existing = true;
1372                 status = remove_conflicting_short_name(dentry, ctx);
1373                 if (NT_SUCCESS(status))
1374                         goto retry;
1375         }
1376
1377         /* By default, failure to set short names is not an error (since short
1378          * names aren't too important anymore...).  */
1379         if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES)) {
1380                 if (dentry->d_short_name_nbytes)
1381                         ctx->num_set_short_name_failures++;
1382                 else
1383                         ctx->num_remove_short_name_failures++;
1384                 return 0;
1385         }
1386
1387         winnt_error(status, L"Can't set short name on \"%ls\"", current_path(ctx));
1388         return WIMLIB_ERR_SET_SHORT_NAME;
1389 }
1390
1391 /*
1392  * A wrapper around NtCreateFile() to make it slightly more usable...
1393  * This uses the path currently constructed in ctx->pathbuf.
1394  *
1395  * Also, we always specify SYNCHRONIZE access, FILE_OPEN_FOR_BACKUP_INTENT, and
1396  * FILE_OPEN_REPARSE_POINT.
1397  */
1398 static NTSTATUS
1399 do_create_file(PHANDLE FileHandle,
1400                ACCESS_MASK DesiredAccess,
1401                PLARGE_INTEGER AllocationSize,
1402                ULONG FileAttributes,
1403                ULONG CreateDisposition,
1404                ULONG CreateOptions,
1405                struct win32_apply_ctx *ctx)
1406 {
1407         return NtCreateFile(FileHandle,
1408                             DesiredAccess | SYNCHRONIZE,
1409                             &ctx->attr,
1410                             &ctx->iosb,
1411                             AllocationSize,
1412                             FileAttributes,
1413                             FILE_SHARE_VALID_FLAGS,
1414                             CreateDisposition,
1415                             CreateOptions |
1416                                 FILE_OPEN_FOR_BACKUP_INTENT |
1417                                 FILE_OPEN_REPARSE_POINT,
1418                             NULL,
1419                             0);
1420 }
1421
1422 /* Like do_create_file(), but builds the extraction path of the @dentry first.
1423  */
1424 static NTSTATUS
1425 create_file(PHANDLE FileHandle,
1426             ACCESS_MASK DesiredAccess,
1427             PLARGE_INTEGER AllocationSize,
1428             ULONG FileAttributes,
1429             ULONG CreateDisposition,
1430             ULONG CreateOptions,
1431             const struct wim_dentry *dentry,
1432             struct win32_apply_ctx *ctx)
1433 {
1434         build_extraction_path(dentry, ctx);
1435         return do_create_file(FileHandle,
1436                               DesiredAccess,
1437                               AllocationSize,
1438                               FileAttributes,
1439                               CreateDisposition,
1440                               CreateOptions,
1441                               ctx);
1442 }
1443
1444 static int
1445 delete_file_or_stream(struct win32_apply_ctx *ctx)
1446 {
1447         NTSTATUS status;
1448         HANDLE h;
1449         ULONG perms = DELETE;
1450         ULONG flags = FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE;
1451
1452         /* First try opening the file with FILE_DELETE_ON_CLOSE.  In most cases,
1453          * all we have to do is that plus close the file handle.  */
1454 retry:
1455         status = do_create_file(&h, perms, NULL, 0, FILE_OPEN, flags, ctx);
1456
1457         if (unlikely(status == STATUS_CANNOT_DELETE)) {
1458                 /* This error occurs for files with FILE_ATTRIBUTE_READONLY set.
1459                  * Try an alternate approach: first open the file without
1460                  * FILE_DELETE_ON_CLOSE, then reset the file attributes, then
1461                  * set the "delete" disposition on the handle.  */
1462                 if (flags & FILE_DELETE_ON_CLOSE) {
1463                         flags &= ~FILE_DELETE_ON_CLOSE;
1464                         perms |= FILE_WRITE_ATTRIBUTES;
1465                         goto retry;
1466                 }
1467         }
1468
1469         if (unlikely(!NT_SUCCESS(status))) {
1470                 winnt_error(status, L"Can't open \"%ls\" for deletion "
1471                             "(perms=%x, flags=%x)",
1472                             current_path(ctx), perms, flags);
1473                 return WIMLIB_ERR_OPEN;
1474         }
1475
1476         if (unlikely(!(flags & FILE_DELETE_ON_CLOSE))) {
1477
1478                 FILE_BASIC_INFORMATION basic_info =
1479                         { .FileAttributes = FILE_ATTRIBUTE_NORMAL };
1480                 status = NtSetInformationFile(h, &ctx->iosb, &basic_info,
1481                                               sizeof(basic_info),
1482                                               FileBasicInformation);
1483
1484                 if (!NT_SUCCESS(status)) {
1485                         winnt_error(status, L"Can't reset attributes of \"%ls\" "
1486                                     "to prepare for deletion", current_path(ctx));
1487                         NtClose(h);
1488                         return WIMLIB_ERR_SET_ATTRIBUTES;
1489                 }
1490
1491                 FILE_DISPOSITION_INFORMATION disp_info =
1492                         { .DoDeleteFile = TRUE };
1493                 status = NtSetInformationFile(h, &ctx->iosb, &disp_info,
1494                                               sizeof(disp_info),
1495                                               FileDispositionInformation);
1496                 if (!NT_SUCCESS(status)) {
1497                         winnt_error(status, L"Can't set delete-on-close "
1498                                     "disposition on \"%ls\"", current_path(ctx));
1499                         NtClose(h);
1500                         return WIMLIB_ERR_SET_ATTRIBUTES;
1501                 }
1502         }
1503
1504         status = NtClose(h);
1505         if (unlikely(!NT_SUCCESS(status))) {
1506                 winnt_error(status, L"Error closing \"%ls\" after setting "
1507                             "delete-on-close disposition", current_path(ctx));
1508                 return WIMLIB_ERR_OPEN;
1509         }
1510
1511         return 0;
1512 }
1513
1514 /*
1515  * Create a nondirectory file or named data stream at the current path,
1516  * superseding any that already exists at that path.  If successful, return an
1517  * open handle to the file or named data stream with the requested permissions.
1518  */
1519 static int
1520 supersede_file_or_stream(struct win32_apply_ctx *ctx, DWORD perms,
1521                          HANDLE *h_ret)
1522 {
1523         NTSTATUS status;
1524         bool retried = false;
1525
1526         /* FILE_ATTRIBUTE_SYSTEM is needed to ensure that
1527          * FILE_ATTRIBUTE_ENCRYPTED doesn't get set before we want it to be.  */
1528 retry:
1529         status = do_create_file(h_ret,
1530                                 perms,
1531                                 NULL,
1532                                 FILE_ATTRIBUTE_SYSTEM,
1533                                 FILE_CREATE,
1534                                 FILE_NON_DIRECTORY_FILE,
1535                                 ctx);
1536         if (likely(NT_SUCCESS(status)))
1537                 return 0;
1538
1539         /* STATUS_OBJECT_NAME_COLLISION means that the file or stream already
1540          * exists.  Delete the existing file or stream, then try again.
1541          *
1542          * Note: we don't use FILE_OVERWRITE_IF or FILE_SUPERSEDE because of
1543          * problems with certain file attributes, especially
1544          * FILE_ATTRIBUTE_ENCRYPTED.  FILE_SUPERSEDE is also broken in the
1545          * Windows PE ramdisk.  */
1546         if (status == STATUS_OBJECT_NAME_COLLISION && !retried) {
1547                 int ret = delete_file_or_stream(ctx);
1548                 if (ret)
1549                         return ret;
1550                 retried = true;
1551                 goto retry;
1552         }
1553         winnt_error(status, L"Can't create \"%ls\"", current_path(ctx));
1554         return WIMLIB_ERR_OPEN;
1555 }
1556
1557 /* Set the reparse point @rpbuf of length @rpbuflen on the extracted file
1558  * corresponding to the WIM dentry @dentry.  */
1559 static int
1560 do_set_reparse_point(const struct wim_dentry *dentry,
1561                      const struct reparse_buffer_disk *rpbuf, u16 rpbuflen,
1562                      struct win32_apply_ctx *ctx)
1563 {
1564         NTSTATUS status;
1565         HANDLE h;
1566
1567         status = create_file(&h, GENERIC_WRITE, NULL,
1568                              0, FILE_OPEN, 0, dentry, ctx);
1569         if (!NT_SUCCESS(status))
1570                 goto fail;
1571
1572         status = winnt_fsctl(h, FSCTL_SET_REPARSE_POINT,
1573                              rpbuf, rpbuflen, NULL, 0, NULL);
1574         NtClose(h);
1575
1576         if (NT_SUCCESS(status))
1577                 return 0;
1578
1579         /* On Windows, by default only the Administrator can create symbolic
1580          * links for some reason.  By default we just issue a warning if this
1581          * appears to be the problem.  Use WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS
1582          * to get a hard error.  */
1583         if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS)
1584             && (status == STATUS_PRIVILEGE_NOT_HELD ||
1585                 status == STATUS_ACCESS_DENIED)
1586             && (dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
1587                 dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT))
1588         {
1589                 WARNING("Can't create symbolic link \"%ls\"!              \n"
1590                         "          (Need Administrator rights, or at least "
1591                         "the\n"
1592                         "          SeCreateSymbolicLink privilege.)",
1593                         current_path(ctx));
1594                 return 0;
1595         }
1596
1597 fail:
1598         winnt_error(status, L"Can't set reparse data on \"%ls\"",
1599                     current_path(ctx));
1600         return WIMLIB_ERR_SET_REPARSE_DATA;
1601 }
1602
1603 /*
1604  * Create empty named data streams and potentially a reparse point for the
1605  * specified file, if any.
1606  *
1607  * Since these won't have blob descriptors, they won't show up in the call to
1608  * extract_blob_list().  Hence the need for the special case.
1609  */
1610 static int
1611 create_empty_streams(const struct wim_dentry *dentry,
1612                      struct win32_apply_ctx *ctx)
1613 {
1614         const struct wim_inode *inode = dentry->d_inode;
1615         int ret;
1616
1617         for (unsigned i = 0; i < inode->i_num_streams; i++) {
1618                 const struct wim_inode_stream *strm = &inode->i_streams[i];
1619
1620                 if (stream_blob_resolved(strm) != NULL)
1621                         continue;
1622
1623                 if (strm->stream_type == STREAM_TYPE_REPARSE_POINT &&
1624                     ctx->common.supported_features.reparse_points)
1625                 {
1626                         u8 buf[REPARSE_DATA_OFFSET] _aligned_attribute(8);
1627                         struct reparse_buffer_disk *rpbuf =
1628                                 (struct reparse_buffer_disk *)buf;
1629                         complete_reparse_point(rpbuf, inode, 0);
1630                         ret = do_set_reparse_point(dentry, rpbuf,
1631                                                    REPARSE_DATA_OFFSET, ctx);
1632                         if (ret)
1633                                 return ret;
1634                 } else if (stream_is_named_data_stream(strm) &&
1635                            ctx->common.supported_features.named_data_streams)
1636                 {
1637                         HANDLE h;
1638
1639                         build_extraction_path_with_ads(dentry, ctx,
1640                                                        strm->stream_name,
1641                                                        utf16le_len_chars(strm->stream_name));
1642                         /*
1643                          * Note: do not request any permissions on the handle.
1644                          * Otherwise, we may encounter a Windows bug where the
1645                          * parent directory DACL denies read access to the new
1646                          * named data stream, even when using backup semantics!
1647                          */
1648                         ret = supersede_file_or_stream(ctx, 0, &h);
1649
1650                         build_extraction_path(dentry, ctx);
1651
1652                         if (ret)
1653                                 return ret;
1654                         NtClose(h);
1655                 }
1656         }
1657
1658         return 0;
1659 }
1660
1661 /*
1662  * Creates the directory named by @dentry, or uses an existing directory at that
1663  * location.  If necessary, sets the short name and/or fixes compression and
1664  * encryption attributes.
1665  *
1666  * Returns 0, WIMLIB_ERR_MKDIR, or WIMLIB_ERR_SET_SHORT_NAME.
1667  */
1668 static int
1669 create_directory(const struct wim_dentry *dentry, struct win32_apply_ctx *ctx)
1670 {
1671         DWORD perms;
1672         NTSTATUS status;
1673         HANDLE h;
1674         int ret;
1675
1676         /* DELETE is needed for set_short_name(); GENERIC_READ and GENERIC_WRITE
1677          * are needed for adjust_compression_attribute().  */
1678         perms = GENERIC_READ | GENERIC_WRITE;
1679         if (!dentry_is_root(dentry))
1680                 perms |= DELETE;
1681
1682         /* FILE_ATTRIBUTE_SYSTEM is needed to ensure that
1683          * FILE_ATTRIBUTE_ENCRYPTED doesn't get set before we want it to be.  */
1684         status = create_file(&h, perms, NULL, FILE_ATTRIBUTE_SYSTEM,
1685                              FILE_OPEN_IF, FILE_DIRECTORY_FILE, dentry, ctx);
1686         if (unlikely(!NT_SUCCESS(status))) {
1687                 const wchar_t *path = current_path(ctx);
1688                 winnt_error(status, L"Can't create directory \"%ls\"", path);
1689
1690                 /* Check for known issue with WindowsApps directory.  */
1691                 if (status == STATUS_ACCESS_DENIED &&
1692                     (wcsstr(path, L"\\WindowsApps\\") ||
1693                      wcsstr(path, L"\\InfusedApps\\"))) {
1694                         ERROR(
1695 "You seem to be trying to extract files to the WindowsApps directory.\n"
1696 "        Windows 8.1 and later use new file permissions in this directory that\n"
1697 "        cannot be overridden, even by backup/restore programs.  To extract your\n"
1698 "        files anyway, you need to choose a different target directory, delete\n"
1699 "        the WindowsApps directory entirely, reformat the volume, do the\n"
1700 "        extraction from a non-broken operating system such as Windows 7 or\n"
1701 "        Linux, or wait for Microsoft to fix the design flaw in their operating\n"
1702 "        system.  This is *not* a bug in wimlib.  See this thread for more\n"
1703 "        information: https://wimlib.net/forums/viewtopic.php?f=1&t=261");
1704                 }
1705                 return WIMLIB_ERR_MKDIR;
1706         }
1707
1708         if (ctx->iosb.Information == FILE_OPENED) {
1709                 /* If we opened an existing directory, try to clear its file
1710                  * attributes.  As far as I know, this only actually makes a
1711                  * difference in the case where a FILE_ATTRIBUTE_READONLY
1712                  * directory has a named data stream which needs to be
1713                  * extracted.  You cannot create a named data stream of such a
1714                  * directory, even though this contradicts Microsoft's
1715                  * documentation for FILE_ATTRIBUTE_READONLY which states it is
1716                  * not honored for directories!  */
1717                 if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)) {
1718                         FILE_BASIC_INFORMATION basic_info =
1719                                 { .FileAttributes = FILE_ATTRIBUTE_NORMAL };
1720                         NtSetInformationFile(h, &ctx->iosb, &basic_info,
1721                                              sizeof(basic_info),
1722                                              FileBasicInformation);
1723                 }
1724         }
1725
1726         if (!dentry_is_root(dentry)) {
1727                 ret = set_short_name(h, dentry, ctx);
1728                 if (ret)
1729                         goto out;
1730         }
1731
1732         ret = adjust_compression_attribute(h, dentry, ctx);
1733 out:
1734         NtClose(h);
1735         return ret;
1736 }
1737
1738 /*
1739  * Create all the directories being extracted, other than the target directory
1740  * itself.
1741  *
1742  * Note: we don't honor directory hard links.  However, we don't allow them to
1743  * exist in WIM images anyway (see inode_fixup.c).
1744  */
1745 static int
1746 create_directories(struct list_head *dentry_list,
1747                    struct win32_apply_ctx *ctx)
1748 {
1749         const struct wim_dentry *dentry;
1750         int ret;
1751
1752         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1753
1754                 if (!(dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
1755                         continue;
1756
1757                 /* Note: Here we include files with
1758                  * FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT, but we
1759                  * wait until later to actually set the reparse data.  */
1760
1761                 ret = create_directory(dentry, ctx);
1762
1763                 if (!ret)
1764                         ret = create_empty_streams(dentry, ctx);
1765
1766                 ret = check_apply_error(dentry, ctx, ret);
1767                 if (ret)
1768                         return ret;
1769
1770                 ret = report_file_created(&ctx->common);
1771                 if (ret)
1772                         return ret;
1773         }
1774         return 0;
1775 }
1776
1777 /*
1778  * Creates the nondirectory file named by @dentry.
1779  *
1780  * On success, returns an open handle to the file in @h_ret, with GENERIC_READ,
1781  * GENERIC_WRITE, and DELETE access.  Also, the path to the file will be saved
1782  * in ctx->pathbuf.  On failure, returns an error code.
1783  */
1784 static int
1785 create_nondirectory_inode(HANDLE *h_ret, const struct wim_dentry *dentry,
1786                           struct win32_apply_ctx *ctx)
1787 {
1788         int ret;
1789         HANDLE h;
1790
1791         build_extraction_path(dentry, ctx);
1792
1793         ret = supersede_file_or_stream(ctx,
1794                                        GENERIC_READ | GENERIC_WRITE | DELETE,
1795                                        &h);
1796         if (ret)
1797                 goto out;
1798
1799         ret = adjust_compression_attribute(h, dentry, ctx);
1800         if (ret)
1801                 goto out_close;
1802
1803         if (need_sparse_flag(dentry->d_inode, ctx)) {
1804                 ret = set_sparse_flag(h, ctx);
1805                 if (ret)
1806                         goto out_close;
1807         }
1808
1809         ret = create_empty_streams(dentry, ctx);
1810         if (ret)
1811                 goto out_close;
1812
1813         *h_ret = h;
1814         return 0;
1815
1816 out_close:
1817         NtClose(h);
1818 out:
1819         return ret;
1820 }
1821
1822 /* Creates a hard link at the location named by @dentry to the file represented
1823  * by the open handle @h.  Or, if the target volume does not support hard links,
1824  * create a separate file instead.  */
1825 static int
1826 create_link(HANDLE h, const struct wim_dentry *dentry,
1827             struct win32_apply_ctx *ctx)
1828 {
1829         if (ctx->common.supported_features.hard_links) {
1830
1831                 build_extraction_path(dentry, ctx);
1832
1833                 size_t bufsize = offsetof(FILE_LINK_INFORMATION, FileName) +
1834                                  ctx->pathbuf.Length + sizeof(wchar_t);
1835                 u8 buf[bufsize] _aligned_attribute(8);
1836                 FILE_LINK_INFORMATION *info = (FILE_LINK_INFORMATION *)buf;
1837                 NTSTATUS status;
1838
1839                 info->ReplaceIfExists = TRUE;
1840                 info->RootDirectory = ctx->attr.RootDirectory;
1841                 info->FileNameLength = ctx->pathbuf.Length;
1842                 memcpy(info->FileName, ctx->pathbuf.Buffer, ctx->pathbuf.Length);
1843                 info->FileName[info->FileNameLength / 2] = L'\0';
1844
1845                 /* Note: the null terminator isn't actually necessary,
1846                  * but if you don't add the extra character, you get
1847                  * STATUS_INFO_LENGTH_MISMATCH when FileNameLength
1848                  * happens to be 2  */
1849
1850                 status = NtSetInformationFile(h, &ctx->iosb, info, bufsize,
1851                                               FileLinkInformation);
1852                 if (NT_SUCCESS(status))
1853                         return 0;
1854                 winnt_error(status, L"Failed to create link \"%ls\"",
1855                             current_path(ctx));
1856                 return WIMLIB_ERR_LINK;
1857         } else {
1858                 HANDLE h2;
1859                 int ret;
1860
1861                 ret = create_nondirectory_inode(&h2, dentry, ctx);
1862                 if (ret)
1863                         return ret;
1864
1865                 NtClose(h2);
1866                 return 0;
1867         }
1868 }
1869
1870 /* Given an inode (represented by the open handle @h) for which one link has
1871  * been created (named by @first_dentry), create the other links.
1872  *
1873  * Or, if the target volume does not support hard links, create separate files.
1874  *
1875  * Note: This uses ctx->pathbuf and does not reset it.
1876  */
1877 static int
1878 create_links(HANDLE h, const struct wim_dentry *first_dentry,
1879              struct win32_apply_ctx *ctx)
1880 {
1881         const struct wim_inode *inode = first_dentry->d_inode;
1882         const struct wim_dentry *dentry;
1883         int ret;
1884
1885         inode_for_each_extraction_alias(dentry, inode) {
1886                 if (dentry != first_dentry) {
1887                         ret = create_link(h, dentry, ctx);
1888                         if (ret)
1889                                 return ret;
1890                 }
1891         }
1892         return 0;
1893 }
1894
1895 /* Create a nondirectory file, including all links.  */
1896 static int
1897 create_nondirectory(struct wim_inode *inode, struct win32_apply_ctx *ctx)
1898 {
1899         struct wim_dentry *first_dentry;
1900         HANDLE h;
1901         int ret;
1902
1903         first_dentry = first_extraction_alias(inode);
1904
1905         /* Create first link.  */
1906         ret = create_nondirectory_inode(&h, first_dentry, ctx);
1907         if (ret)
1908                 return ret;
1909
1910         /* Set short name.  */
1911         ret = set_short_name(h, first_dentry, ctx);
1912
1913         /* Create additional links, OR if hard links are not supported just
1914          * create more files.  */
1915         if (!ret)
1916                 ret = create_links(h, first_dentry, ctx);
1917
1918         /* "WIMBoot" extraction: set external backing by the WIM file if needed.  */
1919         if (!ret && unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT))
1920                 ret = set_backed_from_wim(h, inode, ctx);
1921
1922         NtClose(h);
1923         return ret;
1924 }
1925
1926 /* Create all the nondirectory files being extracted, including all aliases
1927  * (hard links).  */
1928 static int
1929 create_nondirectories(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
1930 {
1931         struct wim_dentry *dentry;
1932         struct wim_inode *inode;
1933         int ret;
1934
1935         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1936                 inode = dentry->d_inode;
1937                 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
1938                         continue;
1939                 /* Call create_nondirectory() only once per inode  */
1940                 if (dentry == inode_first_extraction_dentry(inode)) {
1941                         ret = create_nondirectory(inode, ctx);
1942                         ret = check_apply_error(dentry, ctx, ret);
1943                         if (ret)
1944                                 return ret;
1945                 }
1946                 ret = report_file_created(&ctx->common);
1947                 if (ret)
1948                         return ret;
1949         }
1950         return 0;
1951 }
1952
1953 static void
1954 close_handles(struct win32_apply_ctx *ctx)
1955 {
1956         for (unsigned i = 0; i < ctx->num_open_handles; i++)
1957                 NtClose(ctx->open_handles[i]);
1958 }
1959
1960 /* Prepare to read the next blob, which has size @blob_size, into an in-memory
1961  * buffer.  */
1962 static bool
1963 prepare_data_buffer(struct win32_apply_ctx *ctx, u64 blob_size)
1964 {
1965         if (blob_size > ctx->data_buffer_size) {
1966                 /* Larger buffer needed.  */
1967                 void *new_buffer;
1968                 if ((size_t)blob_size != blob_size)
1969                         return false;
1970                 new_buffer = REALLOC(ctx->data_buffer, blob_size);
1971                 if (!new_buffer)
1972                         return false;
1973                 ctx->data_buffer = new_buffer;
1974                 ctx->data_buffer_size = blob_size;
1975         }
1976         /* On the first call this changes data_buffer_ptr from NULL, which tells
1977          * extract_chunk() that the data buffer needs to be filled while reading
1978          * the stream data.  */
1979         ctx->data_buffer_ptr = ctx->data_buffer;
1980         return true;
1981 }
1982
1983 static int
1984 begin_extract_blob_instance(const struct blob_descriptor *blob,
1985                             struct wim_dentry *dentry,
1986                             const struct wim_inode_stream *strm,
1987                             struct win32_apply_ctx *ctx)
1988 {
1989         HANDLE h;
1990         NTSTATUS status;
1991
1992         if (unlikely(strm->stream_type == STREAM_TYPE_REPARSE_POINT)) {
1993                 /* We can't write the reparse point stream directly; we must set
1994                  * it with FSCTL_SET_REPARSE_POINT, which requires that all the
1995                  * data be available.  So, stage the data in a buffer.  */
1996                 if (!prepare_data_buffer(ctx, blob->size))
1997                         return WIMLIB_ERR_NOMEM;
1998                 list_add_tail(&dentry->d_tmp_list, &ctx->reparse_dentries);
1999                 return 0;
2000         }
2001
2002         if (unlikely(strm->stream_type == STREAM_TYPE_EFSRPC_RAW_DATA)) {
2003                 /* We can't write encrypted files directly; we must use
2004                  * WriteEncryptedFileRaw(), which requires providing the data
2005                  * through a callback function.  This can't easily be combined
2006                  * with our own callback-based approach.
2007                  *
2008                  * The current workaround is to simply read the blob into memory
2009                  * and write the encrypted file from that.
2010                  *
2011                  * TODO: This isn't sufficient for extremely large encrypted
2012                  * files.  Perhaps we should create an extra thread to write
2013                  * such files...  */
2014                 if (!prepare_data_buffer(ctx, blob->size))
2015                         return WIMLIB_ERR_NOMEM;
2016                 list_add_tail(&dentry->d_tmp_list, &ctx->encrypted_dentries);
2017                 return 0;
2018         }
2019
2020         /* It's a data stream (may be unnamed or named).  */
2021         wimlib_assert(strm->stream_type == STREAM_TYPE_DATA);
2022
2023         if (ctx->num_open_handles == MAX_OPEN_FILES) {
2024                 /* XXX: Fix this.  But because of the checks in
2025                  * extract_blob_list(), this can now only happen on a filesystem
2026                  * that does not support hard links.  */
2027                 ERROR("Can't extract data: too many open files!");
2028                 return WIMLIB_ERR_UNSUPPORTED;
2029         }
2030
2031
2032         if (unlikely(stream_is_named(strm))) {
2033                 build_extraction_path_with_ads(dentry, ctx,
2034                                                strm->stream_name,
2035                                                utf16le_len_chars(strm->stream_name));
2036         } else {
2037                 build_extraction_path(dentry, ctx);
2038         }
2039
2040
2041         /* Open a new handle  */
2042         status = do_create_file(&h,
2043                                 FILE_WRITE_DATA | SYNCHRONIZE,
2044                                 NULL, 0, FILE_OPEN_IF,
2045                                 FILE_SEQUENTIAL_ONLY |
2046                                         FILE_SYNCHRONOUS_IO_NONALERT,
2047                                 ctx);
2048         if (!NT_SUCCESS(status)) {
2049                 winnt_error(status, L"Can't open \"%ls\" for writing",
2050                             current_path(ctx));
2051                 return WIMLIB_ERR_OPEN;
2052         }
2053
2054         ctx->is_sparse_stream[ctx->num_open_handles] = false;
2055         if (need_sparse_flag(dentry->d_inode, ctx)) {
2056                 /* If the stream is unnamed, then the sparse flag was already
2057                  * set when the file was created.  But if the stream is named,
2058                  * then we need to set the sparse flag here. */
2059                 if (unlikely(stream_is_named(strm))) {
2060                         int ret = set_sparse_flag(h, ctx);
2061                         if (ret) {
2062                                 NtClose(h);
2063                                 return ret;
2064                         }
2065                 }
2066                 ctx->is_sparse_stream[ctx->num_open_handles] = true;
2067                 ctx->any_sparse_streams = true;
2068         } else {
2069                 /* Allocate space for the data.  */
2070                 FILE_ALLOCATION_INFORMATION info =
2071                         { .AllocationSize = { .QuadPart = blob->size }};
2072                 NtSetInformationFile(h, &ctx->iosb, &info, sizeof(info),
2073                                      FileAllocationInformation);
2074         }
2075         ctx->open_handles[ctx->num_open_handles++] = h;
2076         return 0;
2077 }
2078
2079 /* Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a
2080  * pointer to the suffix of the path that begins with the device directly, such
2081  * as e:\Windows\System32.  */
2082 static const wchar_t *
2083 skip_nt_toplevel_component(const wchar_t *path, size_t path_nchars)
2084 {
2085         static const wchar_t * const dirs[] = {
2086                 L"\\??\\",
2087                 L"\\DosDevices\\",
2088                 L"\\Device\\",
2089         };
2090         const wchar_t * const end = path + path_nchars;
2091
2092         for (size_t i = 0; i < ARRAY_LEN(dirs); i++) {
2093                 size_t len = wcslen(dirs[i]);
2094                 if (len <= (end - path) && !wmemcmp(path, dirs[i], len)) {
2095                         path += len;
2096                         while (path != end && *path == L'\\')
2097                                 path++;
2098                         return path;
2099                 }
2100         }
2101         return path;
2102 }
2103
2104 /*
2105  * Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a
2106  * pointer to the suffix of the path that is device-relative but possibly with
2107  * leading slashes, such as \Windows\System32.
2108  *
2109  * The path has an explicit length and is not necessarily null terminated.
2110  */
2111 static const wchar_t *
2112 get_device_relative_path(const wchar_t *path, size_t path_nchars)
2113 {
2114         const wchar_t * const orig_path = path;
2115         const wchar_t * const end = path + path_nchars;
2116
2117         path = skip_nt_toplevel_component(path, path_nchars);
2118         if (path == orig_path)
2119                 return orig_path;
2120
2121         while (path != end && *path != L'\\')
2122                 path++;
2123
2124         return path;
2125 }
2126
2127 /*
2128  * Given a reparse point buffer for an inode for which the absolute link target
2129  * was relativized when it was archived, de-relative the link target to be
2130  * consistent with the actual extraction location.
2131  */
2132 static void
2133 try_rpfix(struct reparse_buffer_disk *rpbuf, u16 *rpbuflen_p,
2134           struct win32_apply_ctx *ctx)
2135 {
2136         struct link_reparse_point link;
2137         size_t orig_subst_name_nchars;
2138         const wchar_t *relpath;
2139         size_t relpath_nchars;
2140         size_t target_ntpath_nchars;
2141         size_t fixed_subst_name_nchars;
2142         const wchar_t *fixed_print_name;
2143         size_t fixed_print_name_nchars;
2144
2145         /* Do nothing if the reparse data is invalid.  */
2146         if (parse_link_reparse_point(rpbuf, *rpbuflen_p, &link))
2147                 return;
2148
2149         /* Do nothing if the reparse point is a relative symbolic link.  */
2150         if (link_is_relative_symlink(&link))
2151                 return;
2152
2153         /* Build the new substitute name from the NT namespace path to the
2154          * target directory, then a path separator, then the "device relative"
2155          * part of the old substitute name.  */
2156
2157         orig_subst_name_nchars = link.substitute_name_nbytes / sizeof(wchar_t);
2158
2159         relpath = get_device_relative_path(link.substitute_name,
2160                                            orig_subst_name_nchars);
2161         relpath_nchars = orig_subst_name_nchars -
2162                          (relpath - link.substitute_name);
2163
2164         target_ntpath_nchars = ctx->target_ntpath.Length / sizeof(wchar_t);
2165
2166         /* If the target directory is a filesystem root, such as \??\C:\, then
2167          * it already will have a trailing slash.  Don't include this slash if
2168          * we are already adding slashes via 'relpath'.  This prevents an extra
2169          * slash from being generated each time the link is extracted.  And
2170          * unlike on UNIX, the number of slashes in paths on Windows can be
2171          * significant; Windows won't understand the link target if it contains
2172          * too many slashes.  */
2173         if (target_ntpath_nchars > 0 && relpath_nchars > 0 &&
2174             ctx->target_ntpath.Buffer[target_ntpath_nchars - 1] == L'\\')
2175                 target_ntpath_nchars--;
2176
2177         /* Also remove extra slashes from the beginning of 'relpath'.  Normally
2178          * this isn't needed, but this is here to make the extra slash(es) added
2179          * by wimlib pre-v1.9.1 get removed automatically.  */
2180         while (relpath_nchars >= 2 &&
2181                relpath[0] == L'\\' && relpath[1] == L'\\') {
2182                 relpath++;
2183                 relpath_nchars--;
2184         }
2185
2186         fixed_subst_name_nchars = target_ntpath_nchars + relpath_nchars;
2187
2188         wchar_t fixed_subst_name[fixed_subst_name_nchars];
2189
2190         wmemcpy(fixed_subst_name, ctx->target_ntpath.Buffer, target_ntpath_nchars);
2191         wmemcpy(&fixed_subst_name[target_ntpath_nchars], relpath, relpath_nchars);
2192         /* Doesn't need to be null-terminated.  */
2193
2194         /* Print name should be Win32, but not all NT names can even be
2195          * translated to Win32 names.  But we can at least delete the top-level
2196          * directory, such as \??\, and this will have the expected result in
2197          * the usual case.  */
2198         fixed_print_name = skip_nt_toplevel_component(fixed_subst_name,
2199                                                       fixed_subst_name_nchars);
2200         fixed_print_name_nchars = fixed_subst_name_nchars - (fixed_print_name -
2201                                                              fixed_subst_name);
2202
2203         link.substitute_name = fixed_subst_name;
2204         link.substitute_name_nbytes = fixed_subst_name_nchars * sizeof(wchar_t);
2205         link.print_name = (wchar_t *)fixed_print_name;
2206         link.print_name_nbytes = fixed_print_name_nchars * sizeof(wchar_t);
2207         make_link_reparse_point(&link, rpbuf, rpbuflen_p);
2208 }
2209
2210 /* Sets the reparse point on the specified file.  This handles "fixing" the
2211  * targets of absolute symbolic links and junctions if WIMLIB_EXTRACT_FLAG_RPFIX
2212  * was specified.  */
2213 static int
2214 set_reparse_point(const struct wim_dentry *dentry,
2215                   const struct reparse_buffer_disk *rpbuf, u16 rpbuflen,
2216                   struct win32_apply_ctx *ctx)
2217 {
2218         if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX)
2219             && !(dentry->d_inode->i_rp_flags & WIM_RP_FLAG_NOT_FIXED))
2220         {
2221                 memcpy(&ctx->rpfixbuf, rpbuf, rpbuflen);
2222                 try_rpfix(&ctx->rpfixbuf, &rpbuflen, ctx);
2223                 rpbuf = &ctx->rpfixbuf;
2224         }
2225         return do_set_reparse_point(dentry, rpbuf, rpbuflen, ctx);
2226
2227 }
2228
2229 /* Import the next block of raw encrypted data  */
2230 static DWORD WINAPI
2231 import_encrypted_data(PBYTE pbData, PVOID pvCallbackContext, PULONG Length)
2232 {
2233         struct win32_apply_ctx *ctx = pvCallbackContext;
2234         ULONG copy_len;
2235
2236         copy_len = min(ctx->encrypted_size - ctx->encrypted_offset, *Length);
2237         memcpy(pbData, &ctx->data_buffer[ctx->encrypted_offset], copy_len);
2238         ctx->encrypted_offset += copy_len;
2239         *Length = copy_len;
2240         return ERROR_SUCCESS;
2241 }
2242
2243 /*
2244  * Write the raw encrypted data to the already-created file (or directory)
2245  * corresponding to @dentry.
2246  *
2247  * The raw encrypted data is provided in ctx->data_buffer, and its size is
2248  * ctx->encrypted_size.
2249  *
2250  * This function may close the target directory, in which case the caller needs
2251  * to re-open it if needed.
2252  */
2253 static int
2254 extract_encrypted_file(const struct wim_dentry *dentry,
2255                        struct win32_apply_ctx *ctx)
2256 {
2257         void *rawctx;
2258         DWORD err;
2259         ULONG flags;
2260         bool retried;
2261
2262         /* Temporarily build a Win32 path for OpenEncryptedFileRaw()  */
2263         build_win32_extraction_path(dentry, ctx);
2264
2265         flags = CREATE_FOR_IMPORT | OVERWRITE_HIDDEN;
2266         if (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
2267                 flags |= CREATE_FOR_DIR;
2268
2269         retried = false;
2270 retry:
2271         err = OpenEncryptedFileRaw(ctx->pathbuf.Buffer, flags, &rawctx);
2272         if (err == ERROR_SHARING_VIOLATION && !retried) {
2273                 /* This can be caused by the handle we have open to the target
2274                  * directory.  Try closing it temporarily.  */
2275                 close_target_directory(ctx);
2276                 retried = true;
2277                 goto retry;
2278         }
2279
2280         /* Restore the NT namespace path  */
2281         build_extraction_path(dentry, ctx);
2282
2283         if (err != ERROR_SUCCESS) {
2284                 win32_error(err, L"Can't open \"%ls\" for encrypted import",
2285                             current_path(ctx));
2286                 return WIMLIB_ERR_OPEN;
2287         }
2288
2289         ctx->encrypted_offset = 0;
2290
2291         err = WriteEncryptedFileRaw(import_encrypted_data, ctx, rawctx);
2292
2293         CloseEncryptedFileRaw(rawctx);
2294
2295         if (err != ERROR_SUCCESS) {
2296                 win32_error(err, L"Can't import encrypted file \"%ls\"",
2297                             current_path(ctx));
2298                 return WIMLIB_ERR_WRITE;
2299         }
2300
2301         return 0;
2302 }
2303
2304 /* Called when starting to read a blob for extraction */
2305 static int
2306 win32_begin_extract_blob(struct blob_descriptor *blob, void *_ctx)
2307 {
2308         struct win32_apply_ctx *ctx = _ctx;
2309         const struct blob_extraction_target *targets = blob_extraction_targets(blob);
2310         int ret;
2311
2312         ctx->num_open_handles = 0;
2313         ctx->data_buffer_ptr = NULL;
2314         ctx->any_sparse_streams = false;
2315         INIT_LIST_HEAD(&ctx->reparse_dentries);
2316         INIT_LIST_HEAD(&ctx->encrypted_dentries);
2317
2318         for (u32 i = 0; i < blob->out_refcnt; i++) {
2319                 const struct wim_inode *inode = targets[i].inode;
2320                 const struct wim_inode_stream *strm = targets[i].stream;
2321                 struct wim_dentry *dentry;
2322
2323                 /* A copy of the blob needs to be extracted to @inode.  */
2324
2325                 if (ctx->common.supported_features.hard_links) {
2326                         dentry = inode_first_extraction_dentry(inode);
2327                         ret = begin_extract_blob_instance(blob, dentry, strm, ctx);
2328                         ret = check_apply_error(dentry, ctx, ret);
2329                         if (ret)
2330                                 goto fail;
2331                 } else {
2332                         /* Hard links not supported.  Extract the blob
2333                          * separately to each alias of the inode.  */
2334                         inode_for_each_extraction_alias(dentry, inode) {
2335                                 ret = begin_extract_blob_instance(blob, dentry, strm, ctx);
2336                                 ret = check_apply_error(dentry, ctx, ret);
2337                                 if (ret)
2338                                         goto fail;
2339                         }
2340                 }
2341         }
2342
2343         return 0;
2344
2345 fail:
2346         close_handles(ctx);
2347         return ret;
2348 }
2349
2350 static int
2351 pwrite_to_handle(HANDLE h, const void *data, size_t size, u64 offset)
2352 {
2353         const void * const end = data + size;
2354         const void *p;
2355         IO_STATUS_BLOCK iosb;
2356         NTSTATUS status;
2357
2358         for (p = data; p != end; p += iosb.Information,
2359                                  offset += iosb.Information)
2360         {
2361                 LARGE_INTEGER offs = { .QuadPart = offset };
2362
2363                 status = NtWriteFile(h, NULL, NULL, NULL, &iosb,
2364                                      (void *)p, min(INT32_MAX, end - p),
2365                                      &offs, NULL);
2366                 if (!NT_SUCCESS(status)) {
2367                         winnt_error(status,
2368                                     L"Error writing data to target volume");
2369                         return WIMLIB_ERR_WRITE;
2370                 }
2371         }
2372         return 0;
2373 }
2374
2375 /* Called when the next chunk of a blob has been read for extraction */
2376 static int
2377 win32_extract_chunk(const struct blob_descriptor *blob, u64 offset,
2378                     const void *chunk, size_t size, void *_ctx)
2379 {
2380         struct win32_apply_ctx *ctx = _ctx;
2381         const void * const end = chunk + size;
2382         const void *p;
2383         bool zeroes;
2384         size_t len;
2385         unsigned i;
2386         int ret;
2387
2388         /*
2389          * For sparse streams, only write nonzero regions.  This lets the
2390          * filesystem use holes to represent zero regions.
2391          */
2392         for (p = chunk; p != end; p += len, offset += len) {
2393                 zeroes = maybe_detect_sparse_region(p, end - p, &len,
2394                                                     ctx->any_sparse_streams);
2395                 for (i = 0; i < ctx->num_open_handles; i++) {
2396                         if (!zeroes || !ctx->is_sparse_stream[i]) {
2397                                 ret = pwrite_to_handle(ctx->open_handles[i],
2398                                                        p, len, offset);
2399                                 if (ret)
2400                                         return ret;
2401                         }
2402                 }
2403         }
2404
2405         /* Copy the data chunk into the buffer (if needed)  */
2406         if (ctx->data_buffer_ptr)
2407                 ctx->data_buffer_ptr = mempcpy(ctx->data_buffer_ptr,
2408                                                chunk, size);
2409         return 0;
2410 }
2411
2412 static int
2413 get_system_compression_format(int extract_flags)
2414 {
2415         if (extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS4K)
2416                 return FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K;
2417
2418         if (extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS8K)
2419                 return FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS8K;
2420
2421         if (extract_flags & WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS16K)
2422                 return FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS16K;
2423
2424         return FILE_PROVIDER_COMPRESSION_FORMAT_LZX;
2425 }
2426
2427
2428 static const wchar_t *
2429 get_system_compression_format_string(int format)
2430 {
2431         switch (format) {
2432         case FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K:
2433                 return L"XPRESS4K";
2434         case FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS8K:
2435                 return L"XPRESS8K";
2436         case FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS16K:
2437                 return L"XPRESS16K";
2438         default:
2439                 return L"LZX";
2440         }
2441 }
2442
2443 static NTSTATUS
2444 set_system_compression(HANDLE h, int format)
2445 {
2446         NTSTATUS status;
2447         struct {
2448                 struct wof_external_info wof_info;
2449                 struct file_provider_external_info file_info;
2450         } in = {
2451                 .wof_info = {
2452                         .version = WOF_CURRENT_VERSION,
2453                         .provider = WOF_PROVIDER_FILE,
2454                 },
2455                 .file_info = {
2456                         .version = FILE_PROVIDER_CURRENT_VERSION,
2457                         .compression_format = format,
2458                 },
2459         };
2460
2461         /* We intentionally use NtFsControlFile() rather than DeviceIoControl()
2462          * here because the "compressing this object would not save space"
2463          * status code does not map to a valid Win32 error code on older
2464          * versions of Windows (before Windows 10?).  This can be a problem if
2465          * the WOFADK driver is being used rather than the regular WOF, since
2466          * WOFADK can be used on older versions of Windows.  */
2467         status = winnt_fsctl(h, FSCTL_SET_EXTERNAL_BACKING,
2468                              &in, sizeof(in), NULL, 0, NULL);
2469
2470         if (status == 0xC000046F) /* "Compressing this object would not save space."  */
2471                 return STATUS_SUCCESS;
2472
2473         return status;
2474 }
2475
2476 /* Hard-coded list of files which the Windows bootloader may need to access
2477  * before the WOF driver has been loaded.  */
2478 static const wchar_t * const bootloader_pattern_strings[] = {
2479         L"*winload.*",
2480         L"*winresume.*",
2481         L"\\Windows\\AppPatch\\drvmain.sdb",
2482         L"\\Windows\\Boot\\DVD\\*",
2483         L"\\Windows\\Boot\\EFI\\*",
2484         L"\\Windows\\bootstat.dat",
2485         L"\\Windows\\Fonts\\vgaoem.fon",
2486         L"\\Windows\\Fonts\\vgasys.fon",
2487         L"\\Windows\\INF\\errata.inf",
2488         L"\\Windows\\System32\\config\\*",
2489         L"\\Windows\\System32\\ntkrnlpa.exe",
2490         L"\\Windows\\System32\\ntoskrnl.exe",
2491         L"\\Windows\\System32\\bootvid.dll",
2492         L"\\Windows\\System32\\ci.dll",
2493         L"\\Windows\\System32\\hal*.dll",
2494         L"\\Windows\\System32\\mcupdate_AuthenticAMD.dll",
2495         L"\\Windows\\System32\\mcupdate_GenuineIntel.dll",
2496         L"\\Windows\\System32\\pshed.dll",
2497         L"\\Windows\\System32\\apisetschema.dll",
2498         L"\\Windows\\System32\\api-ms-win*.dll",
2499         L"\\Windows\\System32\\ext-ms-win*.dll",
2500         L"\\Windows\\System32\\KernelBase.dll",
2501         L"\\Windows\\System32\\drivers\\*.sys",
2502         L"\\Windows\\System32\\*.nls",
2503         L"\\Windows\\System32\\kbd*.dll",
2504         L"\\Windows\\System32\\kd*.dll",
2505         L"\\Windows\\System32\\clfs.sys",
2506         L"\\Windows\\System32\\CodeIntegrity\\driver.stl",
2507 };
2508
2509 static const struct string_list bootloader_patterns = {
2510         .strings = (wchar_t **)bootloader_pattern_strings,
2511         .num_strings = ARRAY_LEN(bootloader_pattern_strings),
2512 };
2513
2514 static NTSTATUS
2515 set_system_compression_on_inode(struct wim_inode *inode, int format,
2516                                 struct win32_apply_ctx *ctx)
2517 {
2518         bool retried = false;
2519         NTSTATUS status;
2520         HANDLE h;
2521
2522         /* If it may be needed for compatibility with the Windows bootloader,
2523          * force this file to XPRESS4K or uncompressed format.  The bootloader
2524          * of Windows 10 supports XPRESS4K only; older versions don't support
2525          * system compression at all.  */
2526         if (!is_image_windows_10_or_later(ctx) ||
2527             format != FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K)
2528         {
2529                 /* We need to check the patterns against every name of the
2530                  * inode, in case any of them match.  */
2531                 struct wim_dentry *dentry;
2532                 inode_for_each_extraction_alias(dentry, inode) {
2533                         bool incompatible;
2534                         bool warned;
2535
2536                         if (calculate_dentry_full_path(dentry)) {
2537                                 ERROR("Unable to compute file path!");
2538                                 return STATUS_NO_MEMORY;
2539                         }
2540
2541                         incompatible = match_pattern_list(dentry->d_full_path,
2542                                                           &bootloader_patterns);
2543                         FREE(dentry->d_full_path);
2544                         dentry->d_full_path = NULL;
2545
2546                         if (!incompatible)
2547                                 continue;
2548
2549                         warned = (ctx->num_system_compression_exclusions++ > 0);
2550
2551                         if (is_image_windows_10_or_later(ctx)) {
2552                                 /* Force to XPRESS4K  */
2553                                 if (!warned) {
2554                                         WARNING("For compatibility with the "
2555                                                 "Windows bootloader, some "
2556                                                 "files are being\n"
2557                                                 "          compacted "
2558                                                 "using the XPRESS4K format "
2559                                                 "instead of the %"TS" format\n"
2560                                                 "          you requested.",
2561                                                 get_system_compression_format_string(format));
2562                                 }
2563                                 format = FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K;
2564                                 break;
2565                         } else {
2566                                 /* Force to uncompressed  */
2567                                 if (!warned) {
2568                                         WARNING("For compatibility with the "
2569                                                 "Windows bootloader, some "
2570                                                 "files will not\n"
2571                                                 "          be compressed with"
2572                                                 " system compression "
2573                                                 "(\"compacted\").");
2574                                 }
2575                                 return STATUS_SUCCESS;
2576                         }
2577
2578                 }
2579         }
2580
2581         /* Open the extracted file.  */
2582         status = create_file(&h, GENERIC_READ | GENERIC_WRITE, NULL,
2583                              0, FILE_OPEN, 0,
2584                              inode_first_extraction_dentry(inode), ctx);
2585
2586         if (!NT_SUCCESS(status))
2587                 return status;
2588 retry:
2589         /* Compress the file.  If the attempt fails with "invalid device
2590          * request", then attach wof.sys (or wofadk.sys) and retry.  */
2591         status = set_system_compression(h, format);
2592         if (unlikely(status == STATUS_INVALID_DEVICE_REQUEST && !retried)) {
2593                 wchar_t drive_path[7];
2594                 if (!win32_get_drive_path(ctx->common.target, drive_path) &&
2595                     win32_try_to_attach_wof(drive_path + 4)) {
2596                         retried = true;
2597                         goto retry;
2598                 }
2599         }
2600
2601         NtClose(h);
2602         return status;
2603 }
2604
2605 /*
2606  * This function is called when doing a "compact-mode" extraction and we just
2607  * finished extracting a blob to one or more locations.  For each location that
2608  * was the unnamed data stream of a file, this function compresses the
2609  * corresponding file using System Compression, if allowed.
2610  *
2611  * Note: we're doing the compression immediately after extracting the data
2612  * rather than during a separate compression pass.  This way should be faster
2613  * since the operating system should still have the file's data cached.
2614  *
2615  * Note: we're having the operating system do the compression, which is not
2616  * ideal because wimlib could create the compressed data faster and more
2617  * efficiently (the compressed data format is identical to a WIM resource).  But
2618  * we seemingly don't have a choice because WOF prevents applications from
2619  * creating its reparse points.
2620  */
2621 static void
2622 handle_system_compression(struct blob_descriptor *blob, struct win32_apply_ctx *ctx)
2623 {
2624         const struct blob_extraction_target *targets = blob_extraction_targets(blob);
2625
2626         const int format = get_system_compression_format(ctx->common.extract_flags);
2627
2628         for (u32 i = 0; i < blob->out_refcnt; i++) {
2629                 struct wim_inode *inode = targets[i].inode;
2630                 struct wim_inode_stream *strm = targets[i].stream;
2631                 NTSTATUS status;
2632
2633                 if (!stream_is_unnamed_data_stream(strm))
2634                         continue;
2635
2636                 if (will_externally_back_inode(inode, ctx, NULL, false) != 0)
2637                         continue;
2638
2639                 status = set_system_compression_on_inode(inode, format, ctx);
2640                 if (likely(NT_SUCCESS(status)))
2641                         continue;
2642
2643                 if (status == STATUS_INVALID_DEVICE_REQUEST) {
2644                         WARNING(
2645           "The request to compress the extracted files using System Compression\n"
2646 "          will not be honored because the operating system or target volume\n"
2647 "          does not support it.  System Compression is only supported on\n"
2648 "          Windows 10 and later, and only on NTFS volumes.");
2649                         ctx->common.extract_flags &= ~COMPACT_FLAGS;
2650                         return;
2651                 }
2652
2653                 ctx->num_system_compression_failures++;
2654                 if (ctx->num_system_compression_failures < 10) {
2655                         winnt_warning(status, L"\"%ls\": Failed to compress "
2656                                       "extracted file using System Compression",
2657                                       current_path(ctx));
2658                 } else if (ctx->num_system_compression_failures == 10) {
2659                         WARNING("Suppressing further warnings about "
2660                                 "System Compression failures.");
2661                 }
2662         }
2663 }
2664
2665 /* Called when a blob has been fully read for extraction */
2666 static int
2667 win32_end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx)
2668 {
2669         struct win32_apply_ctx *ctx = _ctx;
2670         int ret;
2671         const struct wim_dentry *dentry;
2672
2673         /* Extend sparse streams to their final size. */
2674         if (ctx->any_sparse_streams && !status) {
2675                 for (unsigned i = 0; i < ctx->num_open_handles; i++) {
2676                         FILE_END_OF_FILE_INFORMATION info =
2677                                 { .EndOfFile = { .QuadPart = blob->size } };
2678                         NTSTATUS ntstatus;
2679
2680                         if (!ctx->is_sparse_stream[i])
2681                                 continue;
2682
2683                         ntstatus = NtSetInformationFile(ctx->open_handles[i],
2684                                                         &ctx->iosb,
2685                                                         &info, sizeof(info),
2686                                                         FileEndOfFileInformation);
2687                         if (!NT_SUCCESS(ntstatus)) {
2688                                 winnt_error(ntstatus, L"Error writing data to "
2689                                             "target volume (while extending)");
2690                                 status = WIMLIB_ERR_WRITE;
2691                                 break;
2692                         }
2693                 }
2694         }
2695
2696         close_handles(ctx);
2697
2698         if (status)
2699                 return status;
2700
2701         if (unlikely(ctx->common.extract_flags & COMPACT_FLAGS))
2702                 handle_system_compression(blob, ctx);
2703
2704         if (likely(!ctx->data_buffer_ptr))
2705                 return 0;
2706
2707         if (!list_empty(&ctx->reparse_dentries)) {
2708                 if (blob->size > REPARSE_DATA_MAX_SIZE) {
2709                         dentry = list_first_entry(&ctx->reparse_dentries,
2710                                                   struct wim_dentry, d_tmp_list);
2711                         build_extraction_path(dentry, ctx);
2712                         ERROR("Reparse data of \"%ls\" has size "
2713                               "%"PRIu64" bytes (exceeds %u bytes)",
2714                               current_path(ctx), blob->size,
2715                               REPARSE_DATA_MAX_SIZE);
2716                         ret = WIMLIB_ERR_INVALID_REPARSE_DATA;
2717                         return check_apply_error(dentry, ctx, ret);
2718                 }
2719                 /* Reparse data  */
2720                 memcpy(ctx->rpbuf.rpdata, ctx->data_buffer, blob->size);
2721
2722                 list_for_each_entry(dentry, &ctx->reparse_dentries, d_tmp_list) {
2723
2724                         /* Reparse point header  */
2725                         complete_reparse_point(&ctx->rpbuf, dentry->d_inode,
2726                                                blob->size);
2727
2728                         ret = set_reparse_point(dentry, &ctx->rpbuf,
2729                                                 REPARSE_DATA_OFFSET + blob->size,
2730                                                 ctx);
2731                         ret = check_apply_error(dentry, ctx, ret);
2732                         if (ret)
2733                                 return ret;
2734                 }
2735         }
2736
2737         if (!list_empty(&ctx->encrypted_dentries)) {
2738                 ctx->encrypted_size = blob->size;
2739                 list_for_each_entry(dentry, &ctx->encrypted_dentries, d_tmp_list) {
2740                         ret = extract_encrypted_file(dentry, ctx);
2741                         ret = check_apply_error(dentry, ctx, ret);
2742                         if (ret)
2743                                 return ret;
2744                         /* Re-open the target directory if needed.  */
2745                         ret = open_target_directory(ctx);
2746                         if (ret)
2747                                 return ret;
2748                 }
2749         }
2750
2751         return 0;
2752 }
2753
2754 /* Attributes that can't be set directly  */
2755 #define SPECIAL_ATTRIBUTES                      \
2756         (FILE_ATTRIBUTE_REPARSE_POINT   |       \
2757          FILE_ATTRIBUTE_DIRECTORY       |       \
2758          FILE_ATTRIBUTE_ENCRYPTED       |       \
2759          FILE_ATTRIBUTE_SPARSE_FILE     |       \
2760          FILE_ATTRIBUTE_COMPRESSED)
2761
2762 static void
2763 set_object_id(HANDLE h, const struct wim_inode *inode,
2764               struct win32_apply_ctx *ctx)
2765 {
2766         const void *object_id;
2767         u32 len;
2768         NTSTATUS status;
2769
2770         if (!ctx->common.supported_features.object_ids)
2771                 return;
2772
2773         object_id = inode_get_object_id(inode, &len);
2774         if (likely(object_id == NULL))  /* No object ID?  */
2775                 return;
2776
2777         status = winnt_fsctl(h, FSCTL_SET_OBJECT_ID,
2778                              object_id, len, NULL, 0, NULL);
2779         if (NT_SUCCESS(status))
2780                 return;
2781
2782         /* Object IDs must be unique within the filesystem.  A duplicate might
2783          * occur if an image containing object IDs is applied twice to the same
2784          * filesystem.  Arguably, the user should be warned in this case; but
2785          * the reality seems to be that nothing important cares about object IDs
2786          * except the Distributed Link Tracking Service... so for now these
2787          * failures are just ignored.  */
2788         if (status == STATUS_DUPLICATE_NAME ||
2789             status == STATUS_OBJECT_NAME_COLLISION)
2790                 return;
2791
2792         ctx->num_object_id_failures++;
2793         if (ctx->num_object_id_failures < 10) {
2794                 winnt_warning(status, L"Can't set object ID on \"%ls\"",
2795                               current_path(ctx));
2796         } else if (ctx->num_object_id_failures == 10) {
2797                 WARNING("Suppressing further warnings about failure to set "
2798                         "object IDs.");
2799         }
2800 }
2801
2802 /* Set the security descriptor @desc, of @desc_size bytes, on the file with open
2803  * handle @h.  */
2804 static NTSTATUS
2805 set_security_descriptor(HANDLE h, const void *_desc,
2806                         size_t desc_size, struct win32_apply_ctx *ctx)
2807 {
2808         SECURITY_INFORMATION info;
2809         NTSTATUS status;
2810         SECURITY_DESCRIPTOR_RELATIVE *desc;
2811
2812         /*
2813          * Ideally, we would just pass in the security descriptor buffer as-is.
2814          * But it turns out that Windows can mess up the security descriptor
2815          * even when using the low-level NtSetSecurityObject() function:
2816          *
2817          * - Windows will clear SE_DACL_AUTO_INHERITED if it is set in the
2818          *   passed buffer.  To actually get Windows to set
2819          *   SE_DACL_AUTO_INHERITED, the application must set the non-persistent
2820          *   flag SE_DACL_AUTO_INHERIT_REQ.  As usual, Microsoft didn't bother
2821          *   to properly document either of these flags.  It's unclear how
2822          *   important SE_DACL_AUTO_INHERITED actually is, but to be safe we use
2823          *   the SE_DACL_AUTO_INHERIT_REQ workaround to set it if needed.
2824          *
2825          * - The above also applies to the equivalent SACL flags,
2826          *   SE_SACL_AUTO_INHERITED and SE_SACL_AUTO_INHERIT_REQ.
2827          *
2828          * - If the application says that it's setting
2829          *   DACL_SECURITY_INFORMATION, then Windows sets SE_DACL_PRESENT in the
2830          *   resulting security descriptor, even if the security descriptor the
2831          *   application provided did not have a DACL.  This seems to be
2832          *   unavoidable, since omitting DACL_SECURITY_INFORMATION would cause a
2833          *   default DACL to remain.  Fortunately, this behavior seems harmless,
2834          *   since the resulting DACL will still be "null" --- but it will be
2835          *   "the other representation of null".
2836          *
2837          * - The above also applies to SACL_SECURITY_INFORMATION and
2838          *   SE_SACL_PRESENT.  Again, it's seemingly unavoidable but "harmless"
2839          *   that Windows changes the representation of a "null SACL".
2840          */
2841         if (likely(desc_size <= STACK_MAX)) {
2842                 desc = alloca(desc_size);
2843         } else {
2844                 desc = MALLOC(desc_size);
2845                 if (!desc)
2846                         return STATUS_NO_MEMORY;
2847         }
2848
2849         memcpy(desc, _desc, desc_size);
2850
2851         if (likely(desc_size >= 4)) {
2852
2853                 if (desc->Control & SE_DACL_AUTO_INHERITED)
2854                         desc->Control |= SE_DACL_AUTO_INHERIT_REQ;
2855
2856                 if (desc->Control & SE_SACL_AUTO_INHERITED)
2857                         desc->Control |= SE_SACL_AUTO_INHERIT_REQ;
2858         }
2859
2860         /*
2861          * More API insanity.  We want to set the entire security descriptor
2862          * as-is.  But all available APIs require specifying the specific parts
2863          * of the security descriptor being set.  Especially annoying is that
2864          * mandatory integrity labels are part of the SACL, but they aren't set
2865          * with SACL_SECURITY_INFORMATION.  Instead, applications must also
2866          * specify LABEL_SECURITY_INFORMATION (Windows Vista, Windows 7) or
2867          * BACKUP_SECURITY_INFORMATION (Windows 8).  But at least older versions
2868          * of Windows don't error out if you provide these newer flags...
2869          *
2870          * Also, if the process isn't running as Administrator, then it probably
2871          * doesn't have SE_RESTORE_PRIVILEGE.  In this case, it will always get
2872          * the STATUS_PRIVILEGE_NOT_HELD error by trying to set the SACL, even
2873          * if the security descriptor it provided did not have a SACL.  By
2874          * default, in this case we try to recover and set as much of the
2875          * security descriptor as possible --- potentially excluding the DACL, and
2876          * even the owner, as well as the SACL.
2877          */
2878
2879         info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
2880                DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION |
2881                LABEL_SECURITY_INFORMATION | BACKUP_SECURITY_INFORMATION;
2882
2883
2884         /*
2885          * It's also worth noting that SetFileSecurity() is unusable because it
2886          * doesn't request "backup semantics" when it opens the file internally.
2887          * NtSetSecurityObject() seems to be the best function to use in backup
2888          * applications.  (SetSecurityInfo() should also work, but it's harder
2889          * to use and must call NtSetSecurityObject() internally anyway.
2890          * BackupWrite() is theoretically usable as well, but it's inflexible
2891          * and poorly documented.)
2892          */
2893
2894 retry:
2895         status = NtSetSecurityObject(h, info, desc);
2896         if (NT_SUCCESS(status))
2897                 goto out_maybe_free_desc;
2898
2899         /* Failed to set the requested parts of the security descriptor.  If the
2900          * error was permissions-related, try to set fewer parts of the security
2901          * descriptor, unless WIMLIB_EXTRACT_FLAG_STRICT_ACLS is enabled.  */
2902         if ((status == STATUS_PRIVILEGE_NOT_HELD ||
2903              status == STATUS_ACCESS_DENIED) &&
2904             !(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
2905         {
2906                 if (info & SACL_SECURITY_INFORMATION) {
2907                         info &= ~(SACL_SECURITY_INFORMATION |
2908                                   LABEL_SECURITY_INFORMATION |
2909                                   BACKUP_SECURITY_INFORMATION);
2910                         ctx->partial_security_descriptors++;
2911                         goto retry;
2912                 }
2913                 if (info & DACL_SECURITY_INFORMATION) {
2914                         info &= ~DACL_SECURITY_INFORMATION;
2915                         goto retry;
2916                 }
2917                 if (info & OWNER_SECURITY_INFORMATION) {
2918                         info &= ~OWNER_SECURITY_INFORMATION;
2919                         goto retry;
2920                 }
2921                 /* Nothing left except GROUP, and if we removed it we
2922                  * wouldn't have anything at all.  */
2923         }
2924
2925         /* No part of the security descriptor could be set, or
2926          * WIMLIB_EXTRACT_FLAG_STRICT_ACLS is enabled and the full security
2927          * descriptor could not be set.  */
2928         if (!(info & SACL_SECURITY_INFORMATION))
2929                 ctx->partial_security_descriptors--;
2930         ctx->no_security_descriptors++;
2931
2932 out_maybe_free_desc:
2933         if (unlikely(desc_size > STACK_MAX))
2934                 FREE(desc);
2935         return status;
2936 }
2937
2938 /* Set metadata on the open file @h from the WIM inode @inode.  */
2939 static int
2940 do_apply_metadata_to_file(HANDLE h, const struct wim_inode *inode,
2941                           struct win32_apply_ctx *ctx)
2942 {
2943         FILE_BASIC_INFORMATION info;
2944         NTSTATUS status;
2945
2946         /* Set the file's object ID if present and object IDs are supported by
2947          * the filesystem.  */
2948         set_object_id(h, inode, ctx);
2949
2950         /* Set the file's security descriptor if present and we're not in
2951          * NO_ACLS mode  */
2952         if (inode_has_security_descriptor(inode) &&
2953             !(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS))
2954         {
2955                 const struct wim_security_data *sd;
2956                 const void *desc;
2957                 size_t desc_size;
2958
2959                 sd = wim_get_current_security_data(ctx->common.wim);
2960                 desc = sd->descriptors[inode->i_security_id];
2961                 desc_size = sd->sizes[inode->i_security_id];
2962
2963                 status = set_security_descriptor(h, desc, desc_size, ctx);
2964                 if (!NT_SUCCESS(status) &&
2965                     (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
2966                 {
2967                         winnt_error(status,
2968                                     L"Can't set security descriptor on \"%ls\"",
2969                                     current_path(ctx));
2970                         return WIMLIB_ERR_SET_SECURITY;
2971                 }
2972         }
2973
2974         /* Set attributes and timestamps  */
2975         info.CreationTime.QuadPart = inode->i_creation_time;
2976         info.LastAccessTime.QuadPart = inode->i_last_access_time;
2977         info.LastWriteTime.QuadPart = inode->i_last_write_time;
2978         info.ChangeTime.QuadPart = 0;
2979         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES) {
2980                 info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2981         } else {
2982                 info.FileAttributes = inode->i_attributes & ~SPECIAL_ATTRIBUTES;
2983                 if (info.FileAttributes == 0)
2984                         info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2985         }
2986
2987         status = NtSetInformationFile(h, &ctx->iosb, &info, sizeof(info),
2988                                       FileBasicInformation);
2989         /* On FAT volumes we get STATUS_INVALID_PARAMETER if we try to set
2990          * attributes on the root directory.  (Apparently because FAT doesn't
2991          * actually have a place to store those attributes!)  */
2992         if (!NT_SUCCESS(status)
2993             && !(status == STATUS_INVALID_PARAMETER &&
2994                  dentry_is_root(inode_first_extraction_dentry(inode))))
2995         {
2996                 winnt_error(status, L"Can't set basic metadata on \"%ls\"",
2997                             current_path(ctx));
2998                 return WIMLIB_ERR_SET_ATTRIBUTES;
2999         }
3000
3001         return 0;
3002 }
3003
3004 static int
3005 apply_metadata_to_file(const struct wim_dentry *dentry,
3006                        struct win32_apply_ctx *ctx)
3007 {
3008         const struct wim_inode *inode = dentry->d_inode;
3009         DWORD perms;
3010         HANDLE h;
3011         NTSTATUS status;
3012         int ret;
3013
3014         perms = FILE_WRITE_ATTRIBUTES | WRITE_DAC |
3015                 WRITE_OWNER | ACCESS_SYSTEM_SECURITY;
3016
3017         build_extraction_path(dentry, ctx);
3018
3019         /* Open a handle with as many relevant permissions as possible.  */
3020         while (!NT_SUCCESS(status = do_create_file(&h, perms, NULL,
3021                                                    0, FILE_OPEN, 0, ctx)))
3022         {
3023                 if (status == STATUS_PRIVILEGE_NOT_HELD ||
3024                     status == STATUS_ACCESS_DENIED)
3025                 {
3026                         if (perms & ACCESS_SYSTEM_SECURITY) {
3027                                 perms &= ~ACCESS_SYSTEM_SECURITY;
3028                                 continue;
3029                         }
3030                         if (perms & WRITE_DAC) {
3031                                 perms &= ~WRITE_DAC;
3032                                 continue;
3033                         }
3034                         if (perms & WRITE_OWNER) {
3035                                 perms &= ~WRITE_OWNER;
3036                                 continue;
3037                         }
3038                 }
3039                 winnt_error(status, L"Can't open \"%ls\" to set metadata",
3040                             current_path(ctx));
3041                 return WIMLIB_ERR_OPEN;
3042         }
3043
3044         ret = do_apply_metadata_to_file(h, inode, ctx);
3045
3046         NtClose(h);
3047
3048         return ret;
3049 }
3050
3051 static int
3052 apply_metadata(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
3053 {
3054         const struct wim_dentry *dentry;
3055         int ret;
3056
3057         /* We go in reverse so that metadata is set on all a directory's
3058          * children before the directory itself.  This avoids any potential
3059          * problems with attributes, timestamps, or security descriptors.  */
3060         list_for_each_entry_reverse(dentry, dentry_list, d_extraction_list_node)
3061         {
3062                 ret = apply_metadata_to_file(dentry, ctx);
3063                 ret = check_apply_error(dentry, ctx, ret);
3064                 if (ret)
3065                         return ret;
3066                 ret = report_file_metadata_applied(&ctx->common);
3067                 if (ret)
3068                         return ret;
3069         }
3070         return 0;
3071 }
3072
3073 /* Issue warnings about problems during the extraction for which warnings were
3074  * not already issued (due to the high number of potential warnings if we issued
3075  * them per-file).  */
3076 static void
3077 do_warnings(const struct win32_apply_ctx *ctx)
3078 {
3079         if (ctx->partial_security_descriptors == 0
3080             && ctx->no_security_descriptors == 0
3081             && ctx->num_set_short_name_failures == 0
3082         #if 0
3083             && ctx->num_remove_short_name_failures == 0
3084         #endif
3085             )
3086                 return;
3087
3088         WARNING("Extraction to \"%ls\" complete, but with one or more warnings:",
3089                 ctx->common.target);
3090         if (ctx->num_set_short_name_failures) {
3091                 WARNING("- Could not set short names on %lu files or directories",
3092                         ctx->num_set_short_name_failures);
3093         }
3094 #if 0
3095         if (ctx->num_remove_short_name_failures) {
3096                 WARNING("- Could not remove short names on %lu files or directories"
3097                         "          (This is expected on Vista and earlier)",
3098                         ctx->num_remove_short_name_failures);
3099         }
3100 #endif
3101         if (ctx->partial_security_descriptors) {
3102                 WARNING("- Could only partially set the security descriptor\n"
3103                         "            on %lu files or directories.",
3104                         ctx->partial_security_descriptors);
3105         }
3106         if (ctx->no_security_descriptors) {
3107                 WARNING("- Could not set security descriptor at all\n"
3108                         "            on %lu files or directories.",
3109                         ctx->no_security_descriptors);
3110         }
3111         if (ctx->partial_security_descriptors || ctx->no_security_descriptors) {
3112                 WARNING("To fully restore all security descriptors, run the program\n"
3113                         "          with Administrator rights.");
3114         }
3115 }
3116
3117 static u64
3118 count_dentries(const struct list_head *dentry_list)
3119 {
3120         const struct list_head *cur;
3121         u64 count = 0;
3122
3123         list_for_each(cur, dentry_list)
3124                 count++;
3125
3126         return count;
3127 }
3128
3129 /* Extract files from a WIM image to a directory on Windows  */
3130 static int
3131 win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
3132 {
3133         int ret;
3134         struct win32_apply_ctx *ctx = (struct win32_apply_ctx *)_ctx;
3135         u64 dentry_count;
3136
3137         ret = prepare_target(dentry_list, ctx);
3138         if (ret)
3139                 goto out;
3140
3141         if (unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT)) {
3142                 ret = start_wimboot_extraction(dentry_list, ctx);
3143                 if (ret)
3144                         goto out;
3145         }
3146
3147         ctx->windows_build_number = xml_get_windows_build_number(ctx->common.wim->xml_info,
3148                                                                  ctx->common.wim->current_image);
3149
3150         dentry_count = count_dentries(dentry_list);
3151
3152         ret = start_file_structure_phase(&ctx->common, dentry_count);
3153         if (ret)
3154                 goto out;
3155
3156         ret = create_directories(dentry_list, ctx);
3157         if (ret)
3158                 goto out;
3159
3160         ret = create_nondirectories(dentry_list, ctx);
3161         if (ret)
3162                 goto out;
3163
3164         ret = end_file_structure_phase(&ctx->common);
3165         if (ret)
3166                 goto out;
3167
3168         struct read_blob_callbacks cbs = {
3169                 .begin_blob     = win32_begin_extract_blob,
3170                 .continue_blob  = win32_extract_chunk,
3171                 .end_blob       = win32_end_extract_blob,
3172                 .ctx            = ctx,
3173         };
3174         ret = extract_blob_list(&ctx->common, &cbs);
3175         if (ret)
3176                 goto out;
3177
3178         ret = start_file_metadata_phase(&ctx->common, dentry_count);
3179         if (ret)
3180                 goto out;
3181
3182         ret = apply_metadata(dentry_list, ctx);
3183         if (ret)
3184                 goto out;
3185
3186         ret = end_file_metadata_phase(&ctx->common);
3187         if (ret)
3188                 goto out;
3189
3190         if (unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT)) {
3191                 ret = end_wimboot_extraction(ctx);
3192                 if (ret)
3193                         goto out;
3194         }
3195
3196         do_warnings(ctx);
3197 out:
3198         close_target_directory(ctx);
3199         if (ctx->target_ntpath.Buffer)
3200                 HeapFree(GetProcessHeap(), 0, ctx->target_ntpath.Buffer);
3201         FREE(ctx->pathbuf.Buffer);
3202         FREE(ctx->print_buffer);
3203         FREE(ctx->wimboot.wims);
3204         if (ctx->prepopulate_pats) {
3205                 FREE(ctx->prepopulate_pats->strings);
3206                 FREE(ctx->prepopulate_pats);
3207         }
3208         FREE(ctx->mem_prepopulate_pats);
3209         FREE(ctx->data_buffer);
3210         return ret;
3211 }
3212
3213 const struct apply_operations win32_apply_ops = {
3214         .name                   = "Windows",
3215         .get_supported_features = win32_get_supported_features,
3216         .extract                = win32_extract,
3217         .will_back_from_wim     = win32_will_back_from_wim,
3218         .context_size           = sizeof(struct win32_apply_ctx),
3219 };
3220
3221 #endif /* __WIN32__ */