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