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