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