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