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