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