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