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