]> wimlib.net Git - wimlib/blob - src/ntfs-3g_apply.c
avl_tree: replace 'AVL_INLINE' with 'forceinline'
[wimlib] / src / ntfs-3g_apply.c
1 /*
2  * ntfs-3g_apply.c
3  *
4  * Apply a WIM image directly to an NTFS volume using libntfs-3g.  Restore as
5  * much information as possible, including security data, file attributes, DOS
6  * names, alternate data streams, and object IDs.
7  *
8  * Note: because NTFS-3G offers inode-based interfaces, we actually don't need
9  * to deal with paths at all!  (Other than for error messages.)
10  */
11
12 /*
13  * Copyright (C) 2012-2016 Eric Biggers
14  *
15  * This file is free software; you can redistribute it and/or modify it under
16  * the terms of the GNU Lesser General Public License as published by the Free
17  * Software Foundation; either version 3 of the License, or (at your option) any
18  * later version.
19  *
20  * This file is distributed in the hope that it will be useful, but WITHOUT
21  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
23  * details.
24  *
25  * You should have received a copy of the GNU Lesser General Public License
26  * along with this file; if not, see http://www.gnu.org/licenses/.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #  include "config.h"
31 #endif
32
33 #include <errno.h>
34 #include <locale.h>
35 #include <string.h>
36
37 #include <ntfs-3g/attrib.h>
38 #include <ntfs-3g/object_id.h>
39 #include <ntfs-3g/reparse.h>
40 #include <ntfs-3g/security.h>
41
42 #include "wimlib/assert.h"
43 #include "wimlib/apply.h"
44 #include "wimlib/blob_table.h"
45 #include "wimlib/dentry.h"
46 #include "wimlib/encoding.h"
47 #include "wimlib/error.h"
48 #include "wimlib/metadata.h"
49 #include "wimlib/ntfs_3g.h"
50 #include "wimlib/object_id.h"
51 #include "wimlib/reparse.h"
52 #include "wimlib/security.h"
53
54 static int
55 ntfs_3g_get_supported_features(const char *target,
56                                struct wim_features *supported_features)
57 {
58         supported_features->readonly_files            = 1;
59         supported_features->hidden_files              = 1;
60         supported_features->system_files              = 1;
61         supported_features->archive_files             = 1;
62         supported_features->compressed_files          = 1;
63         supported_features->not_context_indexed_files = 1;
64         supported_features->named_data_streams        = 1;
65         supported_features->hard_links                = 1;
66         supported_features->reparse_points            = 1;
67         supported_features->security_descriptors      = 1;
68         supported_features->short_names               = 1;
69         supported_features->object_ids                = 1;
70         supported_features->timestamps                = 1;
71         supported_features->case_sensitive_filenames  = 1;
72         return 0;
73 }
74
75 struct ntfs_3g_apply_ctx {
76         /* Extract flags, the pointer to the WIMStruct, etc.  */
77         struct apply_ctx common;
78
79         /* Pointer to the open NTFS volume  */
80         ntfs_volume *vol;
81
82         ntfs_attr *open_attrs[MAX_OPEN_FILES];
83         unsigned num_open_attrs;
84         ntfs_inode *open_inodes[MAX_OPEN_FILES];
85         unsigned num_open_inodes;
86
87         struct reparse_buffer_disk rpbuf;
88         u8 *reparse_ptr;
89
90         /* Offset in the blob currently being read  */
91         u64 offset;
92
93         unsigned num_reparse_inodes;
94         ntfs_inode *ntfs_reparse_inodes[MAX_OPEN_FILES];
95         struct wim_inode *wim_reparse_inodes[MAX_OPEN_FILES];
96 };
97
98 static int
99 ntfs_3g_set_timestamps(ntfs_inode *ni, const struct wim_inode *inode)
100 {
101         u64 times[3] = {
102                 inode->i_creation_time,
103                 inode->i_last_write_time,
104                 inode->i_last_access_time,
105         };
106
107         if (ntfs_inode_set_times(ni, (const char *)times, sizeof(times), 0))
108                 return WIMLIB_ERR_SET_TIMESTAMPS;
109         return 0;
110 }
111
112 /* Restore the timestamps on the NTFS inode corresponding to @inode.  */
113 static int
114 ntfs_3g_restore_timestamps(ntfs_volume *vol, const struct wim_inode *inode)
115 {
116         ntfs_inode *ni;
117         int res;
118
119         ni = ntfs_inode_open(vol, inode->i_mft_no);
120         if (!ni)
121                 goto fail;
122
123         res = ntfs_3g_set_timestamps(ni, inode);
124
125         if (ntfs_inode_close(ni) || res)
126                 goto fail;
127
128         return 0;
129
130 fail:
131         ERROR_WITH_ERRNO("Failed to update timestamps of \"%s\" in NTFS volume",
132                          dentry_full_path(inode_first_extraction_dentry(inode)));
133         return WIMLIB_ERR_SET_TIMESTAMPS;
134 }
135
136 /* Restore the DOS name of the @dentry.
137  * This closes both @ni and @dir_ni.
138  * If either is NULL, then they are opened temporarily.  */
139 static int
140 ntfs_3g_restore_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
141                          struct wim_dentry *dentry, ntfs_volume *vol)
142 {
143         int ret;
144         const char *dos_name;
145         size_t dos_name_nbytes;
146
147         /* Note: ntfs_set_ntfs_dos_name() closes both inodes (even if it fails).
148          * And it takes in a multibyte string, even though it translates it to
149          * UTF-16LE internally... which is annoying because we currently have
150          * the UTF-16LE string but not the multibyte string.  */
151
152         ret = utf16le_get_tstr(dentry->d_short_name, dentry->d_short_name_nbytes,
153                                &dos_name, &dos_name_nbytes);
154         if (ret)
155                 goto out_close;
156
157         if (!dir_ni)
158                 dir_ni = ntfs_inode_open(vol, dentry->d_parent->d_inode->i_mft_no);
159         if (!ni)
160                 ni = ntfs_inode_open(vol, dentry->d_inode->i_mft_no);
161         if (dir_ni && ni) {
162                 ret = ntfs_set_ntfs_dos_name(ni, dir_ni,
163                                              dos_name, dos_name_nbytes, 0);
164                 dir_ni = NULL;
165                 ni = NULL;
166         } else {
167                 ret = -1;
168         }
169         utf16le_put_tstr(dos_name);
170         if (ret) {
171                 int err = errno;
172                 ERROR_WITH_ERRNO("Failed to set DOS name of \"%s\" in NTFS "
173                                  "volume", dentry_full_path(dentry));
174                 if (err == EILSEQ) {
175                         ERROR("This error may have been caused by a known "
176                               "bug in libntfs-3g where it is unable to set "
177                               "DOS names on files whose long names contain "
178                               "unpaired surrogate characters.  This bug "
179                               "was fixed in the development version of "
180                               "NTFS-3G in June 2016.");
181                 }
182                 ret = WIMLIB_ERR_SET_SHORT_NAME;
183                 goto out_close;
184         }
185
186         /* Unlike most other NTFS-3G functions, ntfs_set_ntfs_dos_name()
187          * changes the directory's last modification timestamp...
188          * Change it back.  */
189         return ntfs_3g_restore_timestamps(vol, dentry->d_parent->d_inode);
190
191 out_close:
192         /* ntfs_inode_close() can take a NULL argument, but it's probably best
193          * not to rely on this behavior.  */
194         if (ni)
195                 ntfs_inode_close(ni);
196         if (dir_ni)
197                 ntfs_inode_close(dir_ni);
198         return ret;
199 }
200
201 static int
202 ntfs_3g_restore_reparse_point(ntfs_inode *ni, const struct wim_inode *inode,
203                               unsigned blob_size, struct ntfs_3g_apply_ctx *ctx)
204 {
205         complete_reparse_point(&ctx->rpbuf, inode, blob_size);
206
207         if (ntfs_set_ntfs_reparse_data(ni, (const char *)&ctx->rpbuf,
208                                        REPARSE_DATA_OFFSET + blob_size, 0))
209         {
210                 int err = errno;
211                 ERROR_WITH_ERRNO("Failed to set reparse data on \"%s\"",
212                                  dentry_full_path(
213                                         inode_first_extraction_dentry(inode)));
214                 if (err == EINVAL && !(inode->i_reparse_tag & 0x80000000)) {
215                         WARNING("This reparse point had a non-Microsoft reparse "
216                                 "tag.  The preceding error may have been caused "
217                                 "by a known bug in libntfs-3g where it does not "
218                                 "correctly validate non-Microsoft reparse "
219                                 "points.  This bug was fixed in NTFS-3G version "
220                                 "2016.2.22.");
221                 }
222                 return WIMLIB_ERR_SET_REPARSE_DATA;
223         }
224
225         return 0;
226 }
227
228 static bool
229 ntfs_3g_has_empty_attributes(const struct wim_inode *inode)
230 {
231         for (unsigned i = 0; i < inode->i_num_streams; i++) {
232                 const struct wim_inode_stream *strm = &inode->i_streams[i];
233
234                 if (stream_blob_resolved(strm) == NULL &&
235                     (strm->stream_type == STREAM_TYPE_REPARSE_POINT ||
236                      stream_is_named_data_stream(strm)))
237                         return true;
238         }
239         return false;
240 }
241
242 /*
243  * Create empty attributes (named data streams and potentially a reparse point)
244  * for the specified file, if there are any.
245  *
246  * Since these won't have blob descriptors, they won't show up in the call to
247  * extract_blob_list().  Hence the need for the special case.
248  *
249  * Keep this in sync with ntfs_3g_has_empty_attributes()!
250  */
251 static int
252 ntfs_3g_create_empty_attributes(ntfs_inode *ni,
253                                 const struct wim_inode *inode,
254                                 struct ntfs_3g_apply_ctx *ctx)
255 {
256         for (unsigned i = 0; i < inode->i_num_streams; i++) {
257
258                 const struct wim_inode_stream *strm = &inode->i_streams[i];
259                 int ret;
260
261                 if (stream_blob_resolved(strm) != NULL)
262                         continue;
263
264                 if (strm->stream_type == STREAM_TYPE_REPARSE_POINT) {
265                         ret = ntfs_3g_restore_reparse_point(ni, inode, 0, ctx);
266                         if (ret)
267                                 return ret;
268                 } else if (stream_is_named_data_stream(strm)) {
269                         if (ntfs_attr_add(ni, AT_DATA, strm->stream_name,
270                                           utf16le_len_chars(strm->stream_name),
271                                           NULL, 0))
272                         {
273                                 ERROR_WITH_ERRNO("Failed to create named data "
274                                                  "stream of \"%s\"",
275                                                  dentry_full_path(
276                                         inode_first_extraction_dentry(inode)));
277                                 return WIMLIB_ERR_NTFS_3G;
278                         }
279                 }
280         }
281         return 0;
282 }
283
284 /* Set attributes, security descriptor, and timestamps on the NTFS inode @ni.
285  */
286 static int
287 ntfs_3g_set_metadata(ntfs_inode *ni, const struct wim_inode *inode,
288                      const struct ntfs_3g_apply_ctx *ctx)
289 {
290         int extract_flags;
291         const struct wim_security_data *sd;
292         struct wim_dentry *one_dentry;
293         int ret;
294
295         extract_flags = ctx->common.extract_flags;
296         sd = wim_get_current_security_data(ctx->common.wim);
297         one_dentry = inode_first_extraction_dentry(inode);
298
299         /* Object ID */
300         {
301                 u32 len;
302                 const void *object_id = inode_get_object_id(inode, &len);
303                 if (unlikely(object_id != NULL) &&
304                     ntfs_set_ntfs_object_id(ni, object_id, len, 0))
305                 {
306                         if (errno == EEXIST) {
307                                 WARNING("Duplicate object ID on file \"%s\"",
308                                         dentry_full_path(one_dentry));
309                         } else {
310                                 ERROR_WITH_ERRNO("Failed to set object ID on "
311                                                  "\"%s\" in NTFS volume",
312                                                  dentry_full_path(one_dentry));
313                                 return WIMLIB_ERR_NTFS_3G;
314                         }
315                 }
316         }
317
318         /* Attributes  */
319         if (!(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)) {
320                 u32 attrib = inode->i_attributes;
321
322                 attrib &= ~(FILE_ATTRIBUTE_SPARSE_FILE |
323                             FILE_ATTRIBUTE_ENCRYPTED);
324
325                 if (ntfs_set_ntfs_attrib(ni, (const char *)&attrib,
326                                          sizeof(attrib), 0))
327                 {
328                         ERROR_WITH_ERRNO("Failed to set attributes on \"%s\" "
329                                          "in NTFS volume",
330                                          dentry_full_path(one_dentry));
331                         return WIMLIB_ERR_SET_ATTRIBUTES;
332                 }
333         }
334
335         /* Security descriptor  */
336         if (inode_has_security_descriptor(inode)
337             && !(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS))
338         {
339                 struct SECURITY_CONTEXT sec_ctx = { ctx->vol };
340                 const void *desc;
341                 size_t desc_size;
342
343                 desc = sd->descriptors[inode->i_security_id];
344                 desc_size = sd->sizes[inode->i_security_id];
345
346                 ret = ntfs_set_ntfs_acl(&sec_ctx, ni, desc, desc_size, 0);
347
348                 if (unlikely(ret)) {
349                         int err = errno;
350                         ERROR_WITH_ERRNO("Failed to set security descriptor on "
351                                          "\"%s\" in NTFS volume",
352                                          dentry_full_path(one_dentry));
353                         if (err == EINVAL && wimlib_print_errors) {
354                                 fprintf(wimlib_error_file,
355                                         "The security descriptor is: ");
356                                 print_byte_field(desc, desc_size, wimlib_error_file);
357                                 fprintf(wimlib_error_file,
358                                         "\n\nThis error occurred because libntfs-3g thinks "
359                                         "the security descriptor is invalid.  There "
360                                         "are several known bugs with libntfs-3g's "
361                                         "security descriptor validation logic in older "
362                                         "versions.  Please upgrade to NTFS-3G version "
363                                         "2016.2.22 or later if you haven't already.\n");
364                         }
365                         return WIMLIB_ERR_SET_SECURITY;
366                 }
367         }
368
369         /* Timestamps  */
370         ret = ntfs_3g_set_timestamps(ni, inode);
371         if (ret) {
372                 ERROR_WITH_ERRNO("Failed to set timestamps on \"%s\" "
373                                  "in NTFS volume",
374                                  dentry_full_path(one_dentry));
375                 return ret;
376         }
377         return 0;
378 }
379
380 /* Recursively creates all the subdirectories of @dir, which has been created as
381  * the NTFS inode @dir_ni.  */
382 static int
383 ntfs_3g_create_dirs_recursive(ntfs_inode *dir_ni, struct wim_dentry *dir,
384                               struct ntfs_3g_apply_ctx *ctx)
385 {
386         struct wim_dentry *child;
387
388         for_dentry_child(child, dir) {
389                 ntfs_inode *ni;
390                 int ret;
391
392                 if (!(child->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
393                         continue;
394                 if (!will_extract_dentry(child))
395                         continue;
396
397                 ni = ntfs_create(dir_ni, 0, child->d_extraction_name,
398                                  child->d_extraction_name_nchars, S_IFDIR);
399                 if (!ni) {
400                         ERROR_WITH_ERRNO("Error creating \"%s\" in NTFS volume",
401                                          dentry_full_path(child));
402                         return WIMLIB_ERR_NTFS_3G;
403                 }
404
405                 child->d_inode->i_mft_no = ni->mft_no;
406
407                 ret = report_file_created(&ctx->common);
408                 if (!ret)
409                         ret = ntfs_3g_set_metadata(ni, child->d_inode, ctx);
410                 if (!ret)
411                         ret = ntfs_3g_create_dirs_recursive(ni, child, ctx);
412
413                 if (ntfs_inode_close_in_dir(ni, dir_ni) && !ret) {
414                         ERROR_WITH_ERRNO("Error closing \"%s\" in NTFS volume",
415                                          dentry_full_path(child));
416                         ret = WIMLIB_ERR_NTFS_3G;
417                 }
418                 if (ret)
419                         return ret;
420         }
421         return 0;
422 }
423
424 /* For each WIM dentry in the @root tree that represents a directory, create the
425  * corresponding directory in the NTFS volume @ctx->vol.  */
426 static int
427 ntfs_3g_create_directories(struct wim_dentry *root,
428                            struct list_head *dentry_list,
429                            struct ntfs_3g_apply_ctx *ctx)
430 {
431         ntfs_inode *root_ni;
432         int ret;
433         struct wim_dentry *dentry;
434
435         /* Create the directories using POSIX names.  */
436
437         root_ni = ntfs_inode_open(ctx->vol, FILE_root);
438         if (!root_ni) {
439                 ERROR_WITH_ERRNO("Can't open root of NTFS volume");
440                 return WIMLIB_ERR_NTFS_3G;
441         }
442
443         root->d_inode->i_mft_no = FILE_root;
444
445         ret = ntfs_3g_set_metadata(root_ni, root->d_inode, ctx);
446         if (!ret)
447                 ret = ntfs_3g_create_dirs_recursive(root_ni, root, ctx);
448
449         if (ntfs_inode_close(root_ni) && !ret) {
450                 ERROR_WITH_ERRNO("Error closing root of NTFS volume");
451                 ret = WIMLIB_ERR_NTFS_3G;
452         }
453         if (ret)
454                 return ret;
455
456         /* Set the DOS name of any directory that has one.  In addition, create
457          * empty attributes for directories that have them.  Note that creating
458          * an empty reparse point attribute must happen *after* setting the DOS
459          * name in order to work around a case where ntfs_set_ntfs_dos_name()
460          * fails with EOPNOTSUPP.  This bug was fixed in NTFS-3G version
461          * 2016.2.22.  */
462         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
463                 const struct wim_inode *inode = dentry->d_inode;
464
465                 if (!(inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
466                         continue;
467                 if (dentry_has_short_name(dentry)) {
468                         ret = ntfs_3g_restore_dos_name(NULL, NULL, dentry,
469                                                        ctx->vol);
470                         if (ret)
471                                 return ret;
472                         ret = report_file_created(&ctx->common);
473                         if (ret)
474                                 return ret;
475                 }
476                 if (ntfs_3g_has_empty_attributes(inode)) {
477                         ntfs_inode *ni;
478
479                         ret = WIMLIB_ERR_NTFS_3G;
480                         ni = ntfs_inode_open(ctx->vol, inode->i_mft_no);
481                         if (ni) {
482                                 ret = ntfs_3g_create_empty_attributes(ni, inode,
483                                                                       ctx);
484                                 if (ntfs_inode_close(ni) && !ret)
485                                         ret = WIMLIB_ERR_NTFS_3G;
486                         }
487                         if (ret) {
488                                 ERROR_WITH_ERRNO("Failed to create empty "
489                                                  "attributes of directory "
490                                                  "\"%s\" in NTFS volume",
491                                                  dentry_full_path(dentry));
492                                 return ret;
493                         }
494                 }
495         }
496         return 0;
497 }
498
499 /* When creating an inode that will have a short (DOS) name, we create it using
500  * the long name associated with the short name.  This ensures that the short
501  * name gets associated with the correct long name.  */
502 static struct wim_dentry *
503 ntfs_3g_first_extraction_alias(struct wim_inode *inode)
504 {
505         struct wim_dentry *dentry;
506
507         inode_for_each_extraction_alias(dentry, inode)
508                 if (dentry_has_short_name(dentry))
509                         return dentry;
510         return inode_first_extraction_dentry(inode);
511 }
512
513 /*
514  * Add a hard link for the NTFS inode @ni at the location corresponding to the
515  * WIM dentry @dentry.
516  *
517  * The parent directory must have already been created on the NTFS volume.
518  *
519  * Returns 0 on success; returns WIMLIB_ERR_NTFS_3G and sets errno on failure.
520  */
521 static int
522 ntfs_3g_add_link(ntfs_inode *ni, struct wim_dentry *dentry)
523 {
524         ntfs_inode *dir_ni;
525         int res;
526
527         /* Open the inode of the parent directory.  */
528         dir_ni = ntfs_inode_open(ni->vol, dentry->d_parent->d_inode->i_mft_no);
529         if (!dir_ni)
530                 goto fail;
531
532         /* Create the link.  */
533         res = ntfs_link(ni, dir_ni, dentry->d_extraction_name,
534                         dentry->d_extraction_name_nchars);
535
536         /* Close the parent directory.  */
537         if (ntfs_inode_close(dir_ni) || res)
538                 goto fail;
539
540         return 0;
541
542 fail:
543         ERROR_WITH_ERRNO("Can't create link \"%s\" in NTFS volume",
544                          dentry_full_path(dentry));
545         return WIMLIB_ERR_NTFS_3G;
546 }
547
548 static int
549 ntfs_3g_create_nondirectory(struct wim_inode *inode,
550                             struct ntfs_3g_apply_ctx *ctx)
551 {
552         struct wim_dentry *first_dentry;
553         ntfs_inode *dir_ni;
554         ntfs_inode *ni;
555         struct wim_dentry *dentry;
556         int ret;
557
558         first_dentry = ntfs_3g_first_extraction_alias(inode);
559
560         /* Create first link.  */
561
562         dir_ni = ntfs_inode_open(ctx->vol, first_dentry->d_parent->d_inode->i_mft_no);
563         if (!dir_ni) {
564                 ERROR_WITH_ERRNO("Can't open \"%s\" in NTFS volume",
565                                  dentry_full_path(first_dentry->d_parent));
566                 return WIMLIB_ERR_NTFS_3G;
567         }
568
569         ni = ntfs_create(dir_ni, 0, first_dentry->d_extraction_name,
570                          first_dentry->d_extraction_name_nchars, S_IFREG);
571
572         if (!ni) {
573                 ERROR_WITH_ERRNO("Can't create \"%s\" in NTFS volume",
574                                  dentry_full_path(first_dentry));
575                 ntfs_inode_close(dir_ni);
576                 return WIMLIB_ERR_NTFS_3G;
577         }
578
579         inode->i_mft_no = ni->mft_no;
580
581         /* Set short name if present.  */
582         if (dentry_has_short_name(first_dentry)) {
583
584                 ret = ntfs_3g_restore_dos_name(ni, dir_ni, first_dentry, ctx->vol);
585
586                 /* ntfs_3g_restore_dos_name() closed both 'ni' and 'dir_ni'.  */
587
588                 if (ret)
589                         return ret;
590
591                 /* Reopen the inode.  */
592                 ni = ntfs_inode_open(ctx->vol, inode->i_mft_no);
593                 if (!ni) {
594                         ERROR_WITH_ERRNO("Failed to reopen \"%s\" "
595                                          "in NTFS volume",
596                                          dentry_full_path(first_dentry));
597                         return WIMLIB_ERR_NTFS_3G;
598                 }
599         } else {
600                 /* Close the directory in which the first link was created.  */
601                 if (ntfs_inode_close(dir_ni)) {
602                         ERROR_WITH_ERRNO("Failed to close \"%s\" in NTFS volume",
603                                          dentry_full_path(first_dentry->d_parent));
604                         ret = WIMLIB_ERR_NTFS_3G;
605                         goto out_close_ni;
606                 }
607         }
608
609         /* Create additional links if present.  */
610         inode_for_each_extraction_alias(dentry, inode) {
611                 if (dentry != first_dentry) {
612                         ret = ntfs_3g_add_link(ni, dentry);
613                         if (ret)
614                                 goto out_close_ni;
615                 }
616         }
617
618         /* Set metadata.  */
619         ret = ntfs_3g_set_metadata(ni, inode, ctx);
620         if (ret)
621                 goto out_close_ni;
622
623         ret = ntfs_3g_create_empty_attributes(ni, inode, ctx);
624
625 out_close_ni:
626         /* Close the inode.  */
627         if (ntfs_inode_close(ni) && !ret) {
628                 ERROR_WITH_ERRNO("Error closing \"%s\" in NTFS volume",
629                                  dentry_full_path(first_dentry));
630                 ret = WIMLIB_ERR_NTFS_3G;
631         }
632         return ret;
633 }
634
635 /* For each WIM dentry in the @dentry_list that represents a nondirectory file,
636  * create the corresponding nondirectory file in the NTFS volume.
637  *
638  * Directories must have already been created.  */
639 static int
640 ntfs_3g_create_nondirectories(struct list_head *dentry_list,
641                               struct ntfs_3g_apply_ctx *ctx)
642 {
643         struct wim_dentry *dentry;
644         struct wim_inode *inode;
645         int ret;
646
647         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
648                 inode = dentry->d_inode;
649                 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
650                         continue;
651                 if (dentry == inode_first_extraction_dentry(inode)) {
652                         ret = ntfs_3g_create_nondirectory(inode, ctx);
653                         if (ret)
654                                 return ret;
655                 }
656                 ret = report_file_created(&ctx->common);
657                 if (ret)
658                         return ret;
659         }
660         return 0;
661 }
662
663 static int
664 ntfs_3g_begin_extract_blob_instance(struct blob_descriptor *blob,
665                                     ntfs_inode *ni,
666                                     struct wim_inode *inode,
667                                     const struct wim_inode_stream *strm,
668                                     struct ntfs_3g_apply_ctx *ctx)
669 {
670         struct wim_dentry *one_dentry = inode_first_extraction_dentry(inode);
671         ntfschar *stream_name;
672         size_t stream_name_nchars;
673         ntfs_attr *attr;
674
675         if (unlikely(strm->stream_type == STREAM_TYPE_REPARSE_POINT)) {
676
677                 if (blob->size > REPARSE_DATA_MAX_SIZE) {
678                         ERROR("Reparse data of \"%s\" has size "
679                               "%"PRIu64" bytes (exceeds %u bytes)",
680                               dentry_full_path(one_dentry),
681                               blob->size, REPARSE_DATA_MAX_SIZE);
682                         return WIMLIB_ERR_INVALID_REPARSE_DATA;
683                 }
684                 ctx->reparse_ptr = ctx->rpbuf.rpdata;
685                 ctx->ntfs_reparse_inodes[ctx->num_reparse_inodes] = ni;
686                 ctx->wim_reparse_inodes[ctx->num_reparse_inodes] = inode;
687                 ctx->num_reparse_inodes++;
688                 return 0;
689         }
690
691         /* It's a data stream (may be unnamed or named).  */
692         wimlib_assert(strm->stream_type == STREAM_TYPE_DATA);
693
694         if (unlikely(stream_is_named(strm))) {
695                 stream_name = strm->stream_name;
696                 stream_name_nchars = utf16le_len_chars(stream_name);
697
698                 if (ntfs_attr_add(ni, AT_DATA, stream_name,
699                                   stream_name_nchars, NULL, 0))
700                 {
701                         ERROR_WITH_ERRNO("Failed to create named data stream of \"%s\"",
702                                          dentry_full_path(one_dentry));
703                         return WIMLIB_ERR_NTFS_3G;
704                 }
705         } else {
706                 /* Don't pass an empty string other than AT_UNNAMED to
707                  * ntfs_attr_open() --- it violates assumptions made by
708                  * libntfs-3g.  */
709                 stream_name = AT_UNNAMED;
710                 stream_name_nchars = 0;
711         }
712
713         /* This should be ensured by extract_blob_list()  */
714         wimlib_assert(ctx->num_open_attrs < MAX_OPEN_FILES);
715
716         attr = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_nchars);
717         if (!attr) {
718                 ERROR_WITH_ERRNO("Failed to open data stream of \"%s\"",
719                                  dentry_full_path(one_dentry));
720                 return WIMLIB_ERR_NTFS_3G;
721         }
722         ctx->open_attrs[ctx->num_open_attrs++] = attr;
723         ntfs_attr_truncate_solid(attr, blob->size);
724         return 0;
725 }
726
727 static int
728 ntfs_3g_cleanup_blob_extract(struct ntfs_3g_apply_ctx *ctx)
729 {
730         int ret = 0;
731
732         for (unsigned i = 0; i < ctx->num_open_attrs; i++) {
733                 if (ntfs_attr_pclose(ctx->open_attrs[i]))
734                         ret = -1;
735                 ntfs_attr_close(ctx->open_attrs[i]);
736         }
737
738         ctx->num_open_attrs = 0;
739
740         for (unsigned i = 0; i < ctx->num_open_inodes; i++) {
741                 if (ntfs_inode_close(ctx->open_inodes[i]))
742                         ret = -1;
743         }
744         ctx->num_open_inodes = 0;
745
746         ctx->offset = 0;
747         ctx->reparse_ptr = NULL;
748         ctx->num_reparse_inodes = 0;
749         return ret;
750 }
751
752 static ntfs_inode *
753 ntfs_3g_open_inode(struct wim_inode *inode, struct ntfs_3g_apply_ctx *ctx)
754 {
755         ntfs_inode *ni;
756
757         /* If the same blob is being extracted to multiple streams of the same
758          * inode, then we must only open the inode once.  */
759         if (unlikely(inode->i_num_streams > 1)) {
760                 for (unsigned i = 0; i < ctx->num_open_inodes; i++) {
761                         if (ctx->open_inodes[i]->mft_no == inode->i_mft_no) {
762                                 return ctx->open_inodes[i];
763                         }
764                 }
765         }
766
767         ni = ntfs_inode_open(ctx->vol, inode->i_mft_no);
768         if (unlikely(!ni)) {
769                 ERROR_WITH_ERRNO("Can't open \"%s\" in NTFS volume",
770                                  dentry_full_path(
771                                         inode_first_extraction_dentry(inode)));
772                 return NULL;
773         }
774
775         ctx->open_inodes[ctx->num_open_inodes++] = ni;
776         return ni;
777 }
778
779 static int
780 ntfs_3g_begin_extract_blob(struct blob_descriptor *blob, void *_ctx)
781 {
782         struct ntfs_3g_apply_ctx *ctx = _ctx;
783         const struct blob_extraction_target *targets = blob_extraction_targets(blob);
784         int ret;
785         ntfs_inode *ni;
786
787         for (u32 i = 0; i < blob->out_refcnt; i++) {
788                 ret = WIMLIB_ERR_NTFS_3G;
789                 ni = ntfs_3g_open_inode(targets[i].inode, ctx);
790                 if (!ni)
791                         goto out_cleanup;
792
793                 ret = ntfs_3g_begin_extract_blob_instance(blob, ni,
794                                                           targets[i].inode,
795                                                           targets[i].stream, ctx);
796                 if (ret)
797                         goto out_cleanup;
798         }
799         ret = 0;
800         goto out;
801
802 out_cleanup:
803         ntfs_3g_cleanup_blob_extract(ctx);
804 out:
805         return ret;
806 }
807
808 /* Note: contrary to its documentation, ntfs_attr_pwrite() can return a short
809  * count in non-error cases --- specifically, when writing to a compressed
810  * attribute and the requested count exceeds the size of an NTFS "compression
811  * block".  Therefore, we must continue calling ntfs_attr_pwrite() until all
812  * bytes have been written or a real error has occurred.  */
813 static bool
814 ntfs_3g_full_pwrite(ntfs_attr *na, u64 offset, size_t size, const u8 *data)
815 {
816         while (size) {
817                 s64 res = ntfs_attr_pwrite(na, offset, size, data);
818                 if (unlikely(res <= 0))
819                         return false;
820                 wimlib_assert(res <= size);
821                 offset += res;
822                 size -= res;
823                 data += res;
824         }
825         return true;
826 }
827
828 static int
829 ntfs_3g_extract_chunk(const void *chunk, size_t size, void *_ctx)
830 {
831         struct ntfs_3g_apply_ctx *ctx = _ctx;
832
833         for (unsigned i = 0; i < ctx->num_open_attrs; i++) {
834                 if (!ntfs_3g_full_pwrite(ctx->open_attrs[i],
835                                          ctx->offset, size, chunk))
836                 {
837                         ERROR_WITH_ERRNO("Error writing data to NTFS volume");
838                         return WIMLIB_ERR_NTFS_3G;
839                 }
840         }
841         if (ctx->reparse_ptr)
842                 ctx->reparse_ptr = mempcpy(ctx->reparse_ptr, chunk, size);
843         ctx->offset += size;
844         return 0;
845 }
846
847 static int
848 ntfs_3g_end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx)
849 {
850         struct ntfs_3g_apply_ctx *ctx = _ctx;
851         int ret;
852
853         if (status) {
854                 ret = status;
855                 goto out;
856         }
857
858         for (u32 i = 0; i < ctx->num_reparse_inodes; i++) {
859                 ret = ntfs_3g_restore_reparse_point(ctx->ntfs_reparse_inodes[i],
860                                                     ctx->wim_reparse_inodes[i],
861                                                     blob->size, ctx);
862                 if (ret)
863                         goto out;
864         }
865         ret = 0;
866 out:
867         if (ntfs_3g_cleanup_blob_extract(ctx) && !ret) {
868                 ERROR_WITH_ERRNO("Error writing data to NTFS volume");
869                 ret = WIMLIB_ERR_NTFS_3G;
870         }
871         return ret;
872 }
873
874 static u64
875 ntfs_3g_count_dentries(const struct list_head *dentry_list)
876 {
877         const struct wim_dentry *dentry;
878         u64 count = 0;
879
880         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
881                 count++;
882                 if ((dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) &&
883                     dentry_has_short_name(dentry))
884                 {
885                         count++;
886                 }
887         }
888
889         return count;
890 }
891
892 static int
893 ntfs_3g_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
894 {
895         struct ntfs_3g_apply_ctx *ctx = (struct ntfs_3g_apply_ctx *)_ctx;
896         ntfs_volume *vol;
897         struct wim_dentry *root;
898         int ret;
899
900         /* For NTFS-3G extraction mode we require that the dentries to extract
901          * form a single tree.  */
902         root = list_first_entry(dentry_list, struct wim_dentry,
903                                 d_extraction_list_node);
904
905         /* Mount the NTFS volume.  */
906         vol = ntfs_mount(ctx->common.target, 0);
907         if (!vol) {
908                 ERROR_WITH_ERRNO("Failed to mount \"%s\" with NTFS-3G",
909                                  ctx->common.target);
910                 return WIMLIB_ERR_NTFS_3G;
911         }
912         ctx->vol = vol;
913
914         /* Create all inodes and aliases, including short names, and set
915          * metadata (attributes, security descriptors, and timestamps).  */
916
917         ret = start_file_structure_phase(&ctx->common,
918                                          ntfs_3g_count_dentries(dentry_list));
919         if (ret)
920                 goto out_unmount;
921
922         ret = ntfs_3g_create_directories(root, dentry_list, ctx);
923         if (ret)
924                 goto out_unmount;
925
926         ret = ntfs_3g_create_nondirectories(dentry_list, ctx);
927         if (ret)
928                 goto out_unmount;
929
930         ret = end_file_structure_phase(&ctx->common);
931         if (ret)
932                 goto out_unmount;
933
934         /* Extract blobs.  */
935         struct read_blob_callbacks cbs = {
936                 .begin_blob     = ntfs_3g_begin_extract_blob,
937                 .consume_chunk  = ntfs_3g_extract_chunk,
938                 .end_blob       = ntfs_3g_end_extract_blob,
939                 .ctx            = ctx,
940         };
941         ret = extract_blob_list(&ctx->common, &cbs);
942
943         /* We do not need a final pass to set timestamps because libntfs-3g does
944          * not update timestamps automatically (exception:
945          * ntfs_set_ntfs_dos_name() does, but we handle this elsewhere).  */
946
947 out_unmount:
948         if (ntfs_umount(ctx->vol, FALSE) && !ret) {
949                 ERROR_WITH_ERRNO("Failed to unmount \"%s\" with NTFS-3G",
950                                  ctx->common.target);
951                 ret = WIMLIB_ERR_NTFS_3G;
952         }
953         return ret;
954 }
955
956 const struct apply_operations ntfs_3g_apply_ops = {
957         .name                   = "NTFS-3G",
958         .get_supported_features = ntfs_3g_get_supported_features,
959         .extract                = ntfs_3g_extract,
960         .context_size           = sizeof(struct ntfs_3g_apply_ctx),
961         .single_tree_only       = true,
962 };