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