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