]> wimlib.net Git - wimlib/blob - src/ntfs-3g_apply.c
ntfs-3g_apply.c: add message about another known libntfs-3g bug
[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 (unlikely(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                 if (err == EINVAL) {
183                         utf16lechar c =
184                                 dentry->d_name[dentry->d_name_nbytes / 2 - 1];
185                         if (c == cpu_to_le16('.') || c == cpu_to_le16(' ')) {
186                                 ERROR("This error was probably caused by a "
187                                       "known bug in libntfs-3g where it is "
188                                       "unable to set DOS names on files whose "
189                                       "long names end with a dot or space "
190                                       "character.  See "
191                                       "https://wimlib.net/forums/viewtopic.php?f=1&t=294 "
192                                       "for more information.");
193                         }
194                 }
195                 ret = WIMLIB_ERR_SET_SHORT_NAME;
196                 goto out_close;
197         }
198
199         /* Unlike most other NTFS-3G functions, ntfs_set_ntfs_dos_name()
200          * changes the directory's last modification timestamp...
201          * Change it back.  */
202         return ntfs_3g_restore_timestamps(vol, dentry->d_parent->d_inode);
203
204 out_close:
205         /* ntfs_inode_close() can take a NULL argument, but it's probably best
206          * not to rely on this behavior.  */
207         if (ni)
208                 ntfs_inode_close(ni);
209         if (dir_ni)
210                 ntfs_inode_close(dir_ni);
211         return ret;
212 }
213
214 static int
215 ntfs_3g_restore_reparse_point(ntfs_inode *ni, const struct wim_inode *inode,
216                               unsigned blob_size, struct ntfs_3g_apply_ctx *ctx)
217 {
218         complete_reparse_point(&ctx->rpbuf, inode, blob_size);
219
220         if (ntfs_set_ntfs_reparse_data(ni, (const char *)&ctx->rpbuf,
221                                        REPARSE_DATA_OFFSET + blob_size, 0))
222         {
223                 int err = errno;
224                 ERROR_WITH_ERRNO("Failed to set reparse data on \"%s\"",
225                                  dentry_full_path(
226                                         inode_first_extraction_dentry(inode)));
227                 if (err == EINVAL && !(inode->i_reparse_tag & 0x80000000)) {
228                         WARNING("This reparse point had a non-Microsoft reparse "
229                                 "tag.  The preceding error may have been caused "
230                                 "by a known bug in libntfs-3g where it does not "
231                                 "correctly validate non-Microsoft reparse "
232                                 "points.  This bug was fixed in NTFS-3G version "
233                                 "2016.2.22.");
234                 }
235                 return WIMLIB_ERR_SET_REPARSE_DATA;
236         }
237
238         return 0;
239 }
240
241 static bool
242 ntfs_3g_has_empty_attributes(const struct wim_inode *inode)
243 {
244         for (unsigned i = 0; i < inode->i_num_streams; i++) {
245                 const struct wim_inode_stream *strm = &inode->i_streams[i];
246
247                 if (stream_blob_resolved(strm) == NULL &&
248                     (strm->stream_type == STREAM_TYPE_REPARSE_POINT ||
249                      stream_is_named_data_stream(strm)))
250                         return true;
251         }
252         return false;
253 }
254
255 /*
256  * Create empty attributes (named data streams and potentially a reparse point)
257  * for the specified file, if there are any.
258  *
259  * Since these won't have blob descriptors, they won't show up in the call to
260  * extract_blob_list().  Hence the need for the special case.
261  *
262  * Keep this in sync with ntfs_3g_has_empty_attributes()!
263  */
264 static int
265 ntfs_3g_create_empty_attributes(ntfs_inode *ni,
266                                 const struct wim_inode *inode,
267                                 struct ntfs_3g_apply_ctx *ctx)
268 {
269         for (unsigned i = 0; i < inode->i_num_streams; i++) {
270
271                 const struct wim_inode_stream *strm = &inode->i_streams[i];
272                 int ret;
273
274                 if (stream_blob_resolved(strm) != NULL)
275                         continue;
276
277                 if (strm->stream_type == STREAM_TYPE_REPARSE_POINT) {
278                         ret = ntfs_3g_restore_reparse_point(ni, inode, 0, ctx);
279                         if (ret)
280                                 return ret;
281                 } else if (stream_is_named_data_stream(strm)) {
282                         if (ntfs_attr_add(ni, AT_DATA, strm->stream_name,
283                                           utf16le_len_chars(strm->stream_name),
284                                           NULL, 0))
285                         {
286                                 ERROR_WITH_ERRNO("Failed to create named data "
287                                                  "stream of \"%s\"",
288                                                  dentry_full_path(
289                                         inode_first_extraction_dentry(inode)));
290                                 return WIMLIB_ERR_NTFS_3G;
291                         }
292                 }
293         }
294         return 0;
295 }
296
297 /* Set attributes, security descriptor, and timestamps on the NTFS inode @ni.
298  */
299 static int
300 ntfs_3g_set_metadata(ntfs_inode *ni, const struct wim_inode *inode,
301                      const struct ntfs_3g_apply_ctx *ctx)
302 {
303         int extract_flags;
304         const struct wim_security_data *sd;
305         struct wim_dentry *one_dentry;
306         int ret;
307
308         extract_flags = ctx->common.extract_flags;
309         sd = wim_get_current_security_data(ctx->common.wim);
310         one_dentry = inode_first_extraction_dentry(inode);
311
312         /* Object ID */
313         {
314                 u32 len;
315                 const void *object_id = inode_get_object_id(inode, &len);
316                 if (unlikely(object_id != NULL) &&
317                     ntfs_set_ntfs_object_id(ni, object_id, len, 0))
318                 {
319                         if (errno == EEXIST) {
320                                 WARNING("Duplicate object ID on file \"%s\"",
321                                         dentry_full_path(one_dentry));
322                         } else {
323                                 ERROR_WITH_ERRNO("Failed to set object ID on "
324                                                  "\"%s\" in NTFS volume",
325                                                  dentry_full_path(one_dentry));
326                                 return WIMLIB_ERR_NTFS_3G;
327                         }
328                 }
329         }
330
331         /* Attributes  */
332         if (!(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)) {
333                 u32 attrib = inode->i_attributes;
334
335                 attrib &= ~(FILE_ATTRIBUTE_SPARSE_FILE |
336                             FILE_ATTRIBUTE_ENCRYPTED);
337
338                 if (ntfs_set_ntfs_attrib(ni, (const char *)&attrib,
339                                          sizeof(attrib), 0))
340                 {
341                         ERROR_WITH_ERRNO("Failed to set attributes on \"%s\" "
342                                          "in NTFS volume",
343                                          dentry_full_path(one_dentry));
344                         return WIMLIB_ERR_SET_ATTRIBUTES;
345                 }
346         }
347
348         /* Security descriptor  */
349         if (inode_has_security_descriptor(inode)
350             && !(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS))
351         {
352                 struct SECURITY_CONTEXT sec_ctx = { ctx->vol };
353                 const void *desc;
354                 size_t desc_size;
355
356                 desc = sd->descriptors[inode->i_security_id];
357                 desc_size = sd->sizes[inode->i_security_id];
358
359                 ret = ntfs_set_ntfs_acl(&sec_ctx, ni, desc, desc_size, 0);
360
361                 if (unlikely(ret)) {
362                         int err = errno;
363                         ERROR_WITH_ERRNO("Failed to set security descriptor on "
364                                          "\"%s\" in NTFS volume",
365                                          dentry_full_path(one_dentry));
366                         if (err == EINVAL && wimlib_print_errors) {
367                                 fprintf(wimlib_error_file,
368                                         "The security descriptor is: ");
369                                 print_byte_field(desc, desc_size, wimlib_error_file);
370                                 fprintf(wimlib_error_file,
371                                         "\n\nThis error occurred because libntfs-3g thinks "
372                                         "the security descriptor is invalid.  There "
373                                         "are several known bugs with libntfs-3g's "
374                                         "security descriptor validation logic in older "
375                                         "versions.  Please upgrade to NTFS-3G version "
376                                         "2016.2.22 or later if you haven't already.\n");
377                         }
378                         return WIMLIB_ERR_SET_SECURITY;
379                 }
380         }
381
382         /* Timestamps  */
383         ret = ntfs_3g_set_timestamps(ni, inode);
384         if (ret) {
385                 ERROR_WITH_ERRNO("Failed to set timestamps on \"%s\" "
386                                  "in NTFS volume",
387                                  dentry_full_path(one_dentry));
388                 return ret;
389         }
390         return 0;
391 }
392
393 /* Recursively creates all the subdirectories of @dir, which has been created as
394  * the NTFS inode @dir_ni.  */
395 static int
396 ntfs_3g_create_dirs_recursive(ntfs_inode *dir_ni, struct wim_dentry *dir,
397                               struct ntfs_3g_apply_ctx *ctx)
398 {
399         struct wim_dentry *child;
400
401         for_dentry_child(child, dir) {
402                 ntfs_inode *ni;
403                 int ret;
404
405                 if (!(child->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
406                         continue;
407                 if (!will_extract_dentry(child))
408                         continue;
409
410                 ni = ntfs_create(dir_ni, 0, child->d_extraction_name,
411                                  child->d_extraction_name_nchars, S_IFDIR);
412                 if (!ni) {
413                         ERROR_WITH_ERRNO("Error creating \"%s\" in NTFS volume",
414                                          dentry_full_path(child));
415                         return WIMLIB_ERR_NTFS_3G;
416                 }
417
418                 child->d_inode->i_mft_no = ni->mft_no;
419
420                 ret = report_file_created(&ctx->common);
421                 if (!ret)
422                         ret = ntfs_3g_set_metadata(ni, child->d_inode, ctx);
423                 if (!ret)
424                         ret = ntfs_3g_create_dirs_recursive(ni, child, ctx);
425
426                 if (ntfs_inode_close_in_dir(ni, dir_ni) && !ret) {
427                         ERROR_WITH_ERRNO("Error closing \"%s\" in NTFS volume",
428                                          dentry_full_path(child));
429                         ret = WIMLIB_ERR_NTFS_3G;
430                 }
431                 if (ret)
432                         return ret;
433         }
434         return 0;
435 }
436
437 /* For each WIM dentry in the @root tree that represents a directory, create the
438  * corresponding directory in the NTFS volume @ctx->vol.  */
439 static int
440 ntfs_3g_create_directories(struct wim_dentry *root,
441                            struct list_head *dentry_list,
442                            struct ntfs_3g_apply_ctx *ctx)
443 {
444         ntfs_inode *root_ni;
445         int ret;
446         struct wim_dentry *dentry;
447
448         /* Create the directories using POSIX names.  */
449
450         root_ni = ntfs_inode_open(ctx->vol, FILE_root);
451         if (!root_ni) {
452                 ERROR_WITH_ERRNO("Can't open root of NTFS volume");
453                 return WIMLIB_ERR_NTFS_3G;
454         }
455
456         root->d_inode->i_mft_no = FILE_root;
457
458         ret = ntfs_3g_set_metadata(root_ni, root->d_inode, ctx);
459         if (!ret)
460                 ret = ntfs_3g_create_dirs_recursive(root_ni, root, ctx);
461
462         if (ntfs_inode_close(root_ni) && !ret) {
463                 ERROR_WITH_ERRNO("Error closing root of NTFS volume");
464                 ret = WIMLIB_ERR_NTFS_3G;
465         }
466         if (ret)
467                 return ret;
468
469         /* Set the DOS name of any directory that has one.  In addition, create
470          * empty attributes for directories that have them.  Note that creating
471          * an empty reparse point attribute must happen *after* setting the DOS
472          * name in order to work around a case where ntfs_set_ntfs_dos_name()
473          * fails with EOPNOTSUPP.  This bug was fixed in NTFS-3G version
474          * 2016.2.22.  */
475         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
476                 const struct wim_inode *inode = dentry->d_inode;
477
478                 if (!(inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
479                         continue;
480                 if (dentry_has_short_name(dentry)) {
481                         ret = ntfs_3g_restore_dos_name(NULL, NULL, dentry,
482                                                        ctx->vol);
483                         if (ret)
484                                 return ret;
485                         ret = report_file_created(&ctx->common);
486                         if (ret)
487                                 return ret;
488                 }
489                 if (ntfs_3g_has_empty_attributes(inode)) {
490                         ntfs_inode *ni;
491
492                         ret = WIMLIB_ERR_NTFS_3G;
493                         ni = ntfs_inode_open(ctx->vol, inode->i_mft_no);
494                         if (ni) {
495                                 ret = ntfs_3g_create_empty_attributes(ni, inode,
496                                                                       ctx);
497                                 if (ntfs_inode_close(ni) && !ret)
498                                         ret = WIMLIB_ERR_NTFS_3G;
499                         }
500                         if (ret) {
501                                 ERROR_WITH_ERRNO("Failed to create empty "
502                                                  "attributes of directory "
503                                                  "\"%s\" in NTFS volume",
504                                                  dentry_full_path(dentry));
505                                 return ret;
506                         }
507                 }
508         }
509         return 0;
510 }
511
512 /* When creating an inode that will have a short (DOS) name, we create it using
513  * the long name associated with the short name.  This ensures that the short
514  * name gets associated with the correct long name.  */
515 static struct wim_dentry *
516 ntfs_3g_first_extraction_alias(struct wim_inode *inode)
517 {
518         struct wim_dentry *dentry;
519
520         inode_for_each_extraction_alias(dentry, inode)
521                 if (dentry_has_short_name(dentry))
522                         return dentry;
523         return inode_first_extraction_dentry(inode);
524 }
525
526 /*
527  * Add a hard link for the NTFS inode @ni at the location corresponding to the
528  * WIM dentry @dentry.
529  *
530  * The parent directory must have already been created on the NTFS volume.
531  *
532  * Returns 0 on success; returns WIMLIB_ERR_NTFS_3G and sets errno on failure.
533  */
534 static int
535 ntfs_3g_add_link(ntfs_inode *ni, struct wim_dentry *dentry)
536 {
537         ntfs_inode *dir_ni;
538         int res;
539
540         /* Open the inode of the parent directory.  */
541         dir_ni = ntfs_inode_open(ni->vol, dentry->d_parent->d_inode->i_mft_no);
542         if (!dir_ni)
543                 goto fail;
544
545         /* Create the link.  */
546         res = ntfs_link(ni, dir_ni, dentry->d_extraction_name,
547                         dentry->d_extraction_name_nchars);
548
549         /* Close the parent directory.  */
550         if (ntfs_inode_close(dir_ni) || res)
551                 goto fail;
552
553         return 0;
554
555 fail:
556         ERROR_WITH_ERRNO("Can't create link \"%s\" in NTFS volume",
557                          dentry_full_path(dentry));
558         return WIMLIB_ERR_NTFS_3G;
559 }
560
561 static int
562 ntfs_3g_create_nondirectory(struct wim_inode *inode,
563                             struct ntfs_3g_apply_ctx *ctx)
564 {
565         struct wim_dentry *first_dentry;
566         ntfs_inode *dir_ni;
567         ntfs_inode *ni;
568         struct wim_dentry *dentry;
569         int ret;
570
571         first_dentry = ntfs_3g_first_extraction_alias(inode);
572
573         /* Create first link.  */
574
575         dir_ni = ntfs_inode_open(ctx->vol, first_dentry->d_parent->d_inode->i_mft_no);
576         if (!dir_ni) {
577                 ERROR_WITH_ERRNO("Can't open \"%s\" in NTFS volume",
578                                  dentry_full_path(first_dentry->d_parent));
579                 return WIMLIB_ERR_NTFS_3G;
580         }
581
582         ni = ntfs_create(dir_ni, 0, first_dentry->d_extraction_name,
583                          first_dentry->d_extraction_name_nchars, S_IFREG);
584
585         if (!ni) {
586                 ERROR_WITH_ERRNO("Can't create \"%s\" in NTFS volume",
587                                  dentry_full_path(first_dentry));
588                 ntfs_inode_close(dir_ni);
589                 return WIMLIB_ERR_NTFS_3G;
590         }
591
592         inode->i_mft_no = ni->mft_no;
593
594         /* Set short name if present.  */
595         if (dentry_has_short_name(first_dentry)) {
596
597                 ret = ntfs_3g_restore_dos_name(ni, dir_ni, first_dentry, ctx->vol);
598
599                 /* ntfs_3g_restore_dos_name() closed both 'ni' and 'dir_ni'.  */
600
601                 if (ret)
602                         return ret;
603
604                 /* Reopen the inode.  */
605                 ni = ntfs_inode_open(ctx->vol, inode->i_mft_no);
606                 if (!ni) {
607                         ERROR_WITH_ERRNO("Failed to reopen \"%s\" "
608                                          "in NTFS volume",
609                                          dentry_full_path(first_dentry));
610                         return WIMLIB_ERR_NTFS_3G;
611                 }
612         } else {
613                 /* Close the directory in which the first link was created.  */
614                 if (ntfs_inode_close(dir_ni)) {
615                         ERROR_WITH_ERRNO("Failed to close \"%s\" in NTFS volume",
616                                          dentry_full_path(first_dentry->d_parent));
617                         ret = WIMLIB_ERR_NTFS_3G;
618                         goto out_close_ni;
619                 }
620         }
621
622         /* Create additional links if present.  */
623         inode_for_each_extraction_alias(dentry, inode) {
624                 if (dentry != first_dentry) {
625                         ret = ntfs_3g_add_link(ni, dentry);
626                         if (ret)
627                                 goto out_close_ni;
628                 }
629         }
630
631         /* Set metadata.  */
632         ret = ntfs_3g_set_metadata(ni, inode, ctx);
633         if (ret)
634                 goto out_close_ni;
635
636         ret = ntfs_3g_create_empty_attributes(ni, inode, ctx);
637
638 out_close_ni:
639         /* Close the inode.  */
640         if (ntfs_inode_close(ni) && !ret) {
641                 ERROR_WITH_ERRNO("Error closing \"%s\" in NTFS volume",
642                                  dentry_full_path(first_dentry));
643                 ret = WIMLIB_ERR_NTFS_3G;
644         }
645         return ret;
646 }
647
648 /* For each WIM dentry in the @dentry_list that represents a nondirectory file,
649  * create the corresponding nondirectory file in the NTFS volume.
650  *
651  * Directories must have already been created.  */
652 static int
653 ntfs_3g_create_nondirectories(struct list_head *dentry_list,
654                               struct ntfs_3g_apply_ctx *ctx)
655 {
656         struct wim_dentry *dentry;
657         struct wim_inode *inode;
658         int ret;
659
660         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
661                 inode = dentry->d_inode;
662                 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
663                         continue;
664                 if (dentry == inode_first_extraction_dentry(inode)) {
665                         ret = ntfs_3g_create_nondirectory(inode, ctx);
666                         if (ret)
667                                 return ret;
668                 }
669                 ret = report_file_created(&ctx->common);
670                 if (ret)
671                         return ret;
672         }
673         return 0;
674 }
675
676 static int
677 ntfs_3g_begin_extract_blob_instance(struct blob_descriptor *blob,
678                                     ntfs_inode *ni,
679                                     struct wim_inode *inode,
680                                     const struct wim_inode_stream *strm,
681                                     struct ntfs_3g_apply_ctx *ctx)
682 {
683         struct wim_dentry *one_dentry = inode_first_extraction_dentry(inode);
684         ntfschar *stream_name;
685         size_t stream_name_nchars;
686         ntfs_attr *attr;
687
688         if (unlikely(strm->stream_type == STREAM_TYPE_REPARSE_POINT)) {
689
690                 if (blob->size > REPARSE_DATA_MAX_SIZE) {
691                         ERROR("Reparse data of \"%s\" has size "
692                               "%"PRIu64" bytes (exceeds %u bytes)",
693                               dentry_full_path(one_dentry),
694                               blob->size, REPARSE_DATA_MAX_SIZE);
695                         return WIMLIB_ERR_INVALID_REPARSE_DATA;
696                 }
697                 ctx->reparse_ptr = ctx->rpbuf.rpdata;
698                 ctx->ntfs_reparse_inodes[ctx->num_reparse_inodes] = ni;
699                 ctx->wim_reparse_inodes[ctx->num_reparse_inodes] = inode;
700                 ctx->num_reparse_inodes++;
701                 return 0;
702         }
703
704         /* It's a data stream (may be unnamed or named).  */
705         wimlib_assert(strm->stream_type == STREAM_TYPE_DATA);
706
707         if (unlikely(stream_is_named(strm))) {
708                 stream_name = strm->stream_name;
709                 stream_name_nchars = utf16le_len_chars(stream_name);
710
711                 if (ntfs_attr_add(ni, AT_DATA, stream_name,
712                                   stream_name_nchars, NULL, 0))
713                 {
714                         ERROR_WITH_ERRNO("Failed to create named data stream of \"%s\"",
715                                          dentry_full_path(one_dentry));
716                         return WIMLIB_ERR_NTFS_3G;
717                 }
718         } else {
719                 /* Don't pass an empty string other than AT_UNNAMED to
720                  * ntfs_attr_open() --- it violates assumptions made by
721                  * libntfs-3g.  */
722                 stream_name = AT_UNNAMED;
723                 stream_name_nchars = 0;
724         }
725
726         /* This should be ensured by extract_blob_list()  */
727         wimlib_assert(ctx->num_open_attrs < MAX_OPEN_FILES);
728
729         attr = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_nchars);
730         if (!attr) {
731                 ERROR_WITH_ERRNO("Failed to open data stream of \"%s\"",
732                                  dentry_full_path(one_dentry));
733                 return WIMLIB_ERR_NTFS_3G;
734         }
735         ctx->open_attrs[ctx->num_open_attrs++] = attr;
736         ntfs_attr_truncate_solid(attr, blob->size);
737         return 0;
738 }
739
740 static int
741 ntfs_3g_cleanup_blob_extract(struct ntfs_3g_apply_ctx *ctx)
742 {
743         int ret = 0;
744
745         for (unsigned i = 0; i < ctx->num_open_attrs; i++) {
746                 if (ntfs_attr_pclose(ctx->open_attrs[i]))
747                         ret = -1;
748                 ntfs_attr_close(ctx->open_attrs[i]);
749         }
750
751         ctx->num_open_attrs = 0;
752
753         for (unsigned i = 0; i < ctx->num_open_inodes; i++) {
754                 if (ntfs_inode_close(ctx->open_inodes[i]))
755                         ret = -1;
756         }
757         ctx->num_open_inodes = 0;
758
759         ctx->offset = 0;
760         ctx->reparse_ptr = NULL;
761         ctx->num_reparse_inodes = 0;
762         return ret;
763 }
764
765 static ntfs_inode *
766 ntfs_3g_open_inode(struct wim_inode *inode, struct ntfs_3g_apply_ctx *ctx)
767 {
768         ntfs_inode *ni;
769
770         /* If the same blob is being extracted to multiple streams of the same
771          * inode, then we must only open the inode once.  */
772         if (unlikely(inode->i_num_streams > 1)) {
773                 for (unsigned i = 0; i < ctx->num_open_inodes; i++) {
774                         if (ctx->open_inodes[i]->mft_no == inode->i_mft_no) {
775                                 return ctx->open_inodes[i];
776                         }
777                 }
778         }
779
780         ni = ntfs_inode_open(ctx->vol, inode->i_mft_no);
781         if (unlikely(!ni)) {
782                 ERROR_WITH_ERRNO("Can't open \"%s\" in NTFS volume",
783                                  dentry_full_path(
784                                         inode_first_extraction_dentry(inode)));
785                 return NULL;
786         }
787
788         ctx->open_inodes[ctx->num_open_inodes++] = ni;
789         return ni;
790 }
791
792 static int
793 ntfs_3g_begin_extract_blob(struct blob_descriptor *blob, void *_ctx)
794 {
795         struct ntfs_3g_apply_ctx *ctx = _ctx;
796         const struct blob_extraction_target *targets = blob_extraction_targets(blob);
797         int ret;
798         ntfs_inode *ni;
799
800         for (u32 i = 0; i < blob->out_refcnt; i++) {
801                 ret = WIMLIB_ERR_NTFS_3G;
802                 ni = ntfs_3g_open_inode(targets[i].inode, ctx);
803                 if (!ni)
804                         goto out_cleanup;
805
806                 ret = ntfs_3g_begin_extract_blob_instance(blob, ni,
807                                                           targets[i].inode,
808                                                           targets[i].stream, ctx);
809                 if (ret)
810                         goto out_cleanup;
811         }
812         ret = 0;
813         goto out;
814
815 out_cleanup:
816         ntfs_3g_cleanup_blob_extract(ctx);
817 out:
818         return ret;
819 }
820
821 /*
822  * Note: prior to NTFS-3G version 2016.2.22, ntfs_attr_pwrite() could return a
823  * short count in non-error cases, contrary to its documentation.  Specifically,
824  * a short count could be returned when writing to a compressed attribute and
825  * the requested count exceeded the size of an NTFS "compression block".
826  * Therefore, we must continue calling ntfs_attr_pwrite() until all bytes have
827  * been written or a real error has occurred.
828  */
829 static bool
830 ntfs_3g_full_pwrite(ntfs_attr *na, u64 offset, size_t size, const u8 *data)
831 {
832         while (size) {
833                 s64 res = ntfs_attr_pwrite(na, offset, size, data);
834                 if (unlikely(res <= 0))
835                         return false;
836                 wimlib_assert(res <= size);
837                 offset += res;
838                 size -= res;
839                 data += res;
840         }
841         return true;
842 }
843
844 static int
845 ntfs_3g_extract_chunk(const void *chunk, size_t size, void *_ctx)
846 {
847         struct ntfs_3g_apply_ctx *ctx = _ctx;
848
849         for (unsigned i = 0; i < ctx->num_open_attrs; i++) {
850                 if (!ntfs_3g_full_pwrite(ctx->open_attrs[i],
851                                          ctx->offset, size, chunk))
852                 {
853                         ERROR_WITH_ERRNO("Error writing data to NTFS volume");
854                         return WIMLIB_ERR_NTFS_3G;
855                 }
856         }
857         if (ctx->reparse_ptr)
858                 ctx->reparse_ptr = mempcpy(ctx->reparse_ptr, chunk, size);
859         ctx->offset += size;
860         return 0;
861 }
862
863 static int
864 ntfs_3g_end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx)
865 {
866         struct ntfs_3g_apply_ctx *ctx = _ctx;
867         int ret;
868
869         if (status) {
870                 ret = status;
871                 goto out;
872         }
873
874         for (u32 i = 0; i < ctx->num_reparse_inodes; i++) {
875                 ret = ntfs_3g_restore_reparse_point(ctx->ntfs_reparse_inodes[i],
876                                                     ctx->wim_reparse_inodes[i],
877                                                     blob->size, ctx);
878                 if (ret)
879                         goto out;
880         }
881         ret = 0;
882 out:
883         if (ntfs_3g_cleanup_blob_extract(ctx) && !ret) {
884                 ERROR_WITH_ERRNO("Error writing data to NTFS volume");
885                 ret = WIMLIB_ERR_NTFS_3G;
886         }
887         return ret;
888 }
889
890 static u64
891 ntfs_3g_count_dentries(const struct list_head *dentry_list)
892 {
893         const struct wim_dentry *dentry;
894         u64 count = 0;
895
896         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
897                 count++;
898                 if ((dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) &&
899                     dentry_has_short_name(dentry))
900                 {
901                         count++;
902                 }
903         }
904
905         return count;
906 }
907
908 static int
909 ntfs_3g_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
910 {
911         struct ntfs_3g_apply_ctx *ctx = (struct ntfs_3g_apply_ctx *)_ctx;
912         ntfs_volume *vol;
913         struct wim_dentry *root;
914         int ret;
915
916         /* For NTFS-3G extraction mode we require that the dentries to extract
917          * form a single tree.  */
918         root = list_first_entry(dentry_list, struct wim_dentry,
919                                 d_extraction_list_node);
920
921         /* Mount the NTFS volume.  */
922         vol = ntfs_mount(ctx->common.target, 0);
923         if (!vol) {
924                 ERROR_WITH_ERRNO("Failed to mount \"%s\" with NTFS-3G",
925                                  ctx->common.target);
926                 return WIMLIB_ERR_NTFS_3G;
927         }
928         ctx->vol = vol;
929
930         /* Opening $Secure is required to set security descriptors in NTFS v3.0
931          * format, where security descriptors are stored in a per-volume index
932          * rather than being fully specified for each file.  */
933         if (ntfs_open_secure(vol) && vol->major_ver >= 3) {
934                 ERROR_WITH_ERRNO("Unable to open security descriptor index of "
935                                  "NTFS volume \"%s\"", ctx->common.target);
936                 ret = WIMLIB_ERR_NTFS_3G;
937                 goto out_unmount;
938         }
939
940         /* Create all inodes and aliases, including short names, and set
941          * metadata (attributes, security descriptors, and timestamps).  */
942
943         ret = start_file_structure_phase(&ctx->common,
944                                          ntfs_3g_count_dentries(dentry_list));
945         if (ret)
946                 goto out_unmount;
947
948         ret = ntfs_3g_create_directories(root, dentry_list, ctx);
949         if (ret)
950                 goto out_unmount;
951
952         ret = ntfs_3g_create_nondirectories(dentry_list, ctx);
953         if (ret)
954                 goto out_unmount;
955
956         ret = end_file_structure_phase(&ctx->common);
957         if (ret)
958                 goto out_unmount;
959
960         /* Extract blobs.  */
961         struct read_blob_callbacks cbs = {
962                 .begin_blob     = ntfs_3g_begin_extract_blob,
963                 .consume_chunk  = ntfs_3g_extract_chunk,
964                 .end_blob       = ntfs_3g_end_extract_blob,
965                 .ctx            = ctx,
966         };
967         ret = extract_blob_list(&ctx->common, &cbs);
968
969         /* We do not need a final pass to set timestamps because libntfs-3g does
970          * not update timestamps automatically (exception:
971          * ntfs_set_ntfs_dos_name() does, but we handle this elsewhere).  */
972
973 out_unmount:
974         if (vol->secure_ni) {
975                 ntfs_index_ctx_put(vol->secure_xsii);
976                 ntfs_index_ctx_put(vol->secure_xsdh);
977                 if (ntfs_inode_close(vol->secure_ni) && !ret) {
978                         ERROR_WITH_ERRNO("Failed to close security descriptor "
979                                          "index of NTFS volume \"%s\"",
980                                          ctx->common.target);
981                         ret = WIMLIB_ERR_NTFS_3G;
982                 }
983                 vol->secure_ni = NULL;
984         }
985         if (ntfs_umount(ctx->vol, FALSE) && !ret) {
986                 ERROR_WITH_ERRNO("Failed to unmount \"%s\" with NTFS-3G",
987                                  ctx->common.target);
988                 ret = WIMLIB_ERR_NTFS_3G;
989         }
990         return ret;
991 }
992
993 const struct apply_operations ntfs_3g_apply_ops = {
994         .name                   = "NTFS-3G",
995         .get_supported_features = ntfs_3g_get_supported_features,
996         .extract                = ntfs_3g_extract,
997         .context_size           = sizeof(struct ntfs_3g_apply_ctx),
998         .single_tree_only       = true,
999 };