]> wimlib.net Git - wimlib/blob - src/unix_apply.c
unix_apply.c: separate creation, data extraction, and metadata passes
[wimlib] / src / unix_apply.c
1 /*
2  * unix_apply.c - Code to apply files from a WIM image on UNIX.
3  */
4
5 /*
6  * Copyright (C) 2012-2016 Eric Biggers
7  *
8  * This file is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the Free
10  * Software Foundation; either version 3 of the License, or (at your option) any
11  * later version.
12  *
13  * This file is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this file; if not, see http://www.gnu.org/licenses/.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <sys/stat.h>
30 #include <sys/time.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33
34 #include "wimlib/apply.h"
35 #include "wimlib/assert.h"
36 #include "wimlib/blob_table.h"
37 #include "wimlib/dentry.h"
38 #include "wimlib/error.h"
39 #include "wimlib/file_io.h"
40 #include "wimlib/reparse.h"
41 #include "wimlib/timestamp.h"
42 #include "wimlib/unix_data.h"
43
44 /* We don't require O_NOFOLLOW, but the advantage of having it is that if we
45  * need to extract a file to a location at which there exists a symbolic link,
46  * open(..., O_NOFOLLOW | ...) recognizes the symbolic link rather than
47  * following it and creating the file somewhere else.  (Equivalent to
48  * FILE_OPEN_REPARSE_POINT on Windows.)  */
49 #ifndef O_NOFOLLOW
50 #  define O_NOFOLLOW 0
51 #endif
52
53 static int
54 unix_get_supported_features(const char *target,
55                             struct wim_features *supported_features)
56 {
57         supported_features->sparse_files = 1;
58         supported_features->hard_links = 1;
59         supported_features->symlink_reparse_points = 1;
60         supported_features->unix_data = 1;
61         supported_features->timestamps = 1;
62         supported_features->case_sensitive_filenames = 1;
63         return 0;
64 }
65
66 #define NUM_PATHBUFS 2  /* We need 2 when creating hard links  */
67
68 struct unix_apply_ctx {
69         /* Extract flags, the pointer to the WIMStruct, etc.  */
70         struct apply_ctx common;
71
72         /* Buffers for building extraction paths (allocated).  */
73         char *pathbufs[NUM_PATHBUFS];
74
75         /* Index of next pathbuf to use  */
76         unsigned which_pathbuf;
77
78         /* Currently open file descriptors for extraction  */
79         struct filedes open_fds[MAX_OPEN_FILES];
80
81         /* Number of currently open file descriptors in open_fds, starting from
82          * the beginning of the array.  */
83         unsigned num_open_fds;
84
85         /* For each currently open file, whether we're writing to it in "sparse"
86          * mode or not.  */
87         bool is_sparse_file[MAX_OPEN_FILES];
88
89         /* Whether is_sparse_file[] is true for any currently open file  */
90         bool any_sparse_files;
91
92         /* Buffer for reading reparse point data into memory  */
93         u8 reparse_data[REPARSE_DATA_MAX_SIZE];
94
95         /* Pointer to the next byte in @reparse_data to fill  */
96         u8 *reparse_ptr;
97
98         /* Absolute path to the target directory (allocated buffer).  Only set
99          * if needed for absolute symbolic link fixups.  */
100         char *target_abspath;
101
102         /* Number of characters in target_abspath.  */
103         size_t target_abspath_nchars;
104
105         /* Number of special files we couldn't create due to EPERM  */
106         unsigned long num_special_files_ignored;
107 };
108
109 /* Returns the number of characters needed to represent the path to the
110  * specified @dentry when extracted, not including the null terminator or the
111  * path to the target directory itself.  */
112 static size_t
113 unix_dentry_path_length(const struct wim_dentry *dentry)
114 {
115         size_t len = 0;
116         const struct wim_dentry *d;
117
118         d = dentry;
119         do {
120                 len += d->d_extraction_name_nchars + 1;
121                 d = d->d_parent;
122         } while (!dentry_is_root(d) && will_extract_dentry(d));
123
124         return len;
125 }
126
127 /* Returns the maximum number of characters needed to represent the path to any
128  * dentry in @dentry_list when extracted, including the null terminator and the
129  * path to the target directory itself.  */
130 static size_t
131 unix_compute_path_max(const struct list_head *dentry_list,
132                       const struct unix_apply_ctx *ctx)
133 {
134         size_t max = 0;
135         size_t len;
136         const struct wim_dentry *dentry;
137
138         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
139                 len = unix_dentry_path_length(dentry);
140                 if (len > max)
141                         max = len;
142         }
143
144         /* Account for target and null terminator.  */
145         return ctx->common.target_nchars + max + 1;
146 }
147
148 /* Builds and returns the filesystem path to which to extract @dentry.
149  * This cycles through NUM_PATHBUFS different buffers.  */
150 static const char *
151 unix_build_extraction_path(const struct wim_dentry *dentry,
152                            struct unix_apply_ctx *ctx)
153 {
154         char *pathbuf;
155         char *p;
156         const struct wim_dentry *d;
157
158         pathbuf = ctx->pathbufs[ctx->which_pathbuf];
159         ctx->which_pathbuf = (ctx->which_pathbuf + 1) % NUM_PATHBUFS;
160
161         p = &pathbuf[ctx->common.target_nchars +
162                      unix_dentry_path_length(dentry)];
163         *p = '\0';
164         d = dentry;
165         do {
166                 p -= d->d_extraction_name_nchars;
167                 if (d->d_extraction_name_nchars)
168                         memcpy(p, d->d_extraction_name,
169                                d->d_extraction_name_nchars);
170                 *--p = '/';
171                 d = d->d_parent;
172         } while (!dentry_is_root(d) && will_extract_dentry(d));
173
174         return pathbuf;
175 }
176
177 /* This causes the next call to unix_build_extraction_path() to use the same
178  * path buffer as the previous call.  */
179 static void
180 unix_reuse_pathbuf(struct unix_apply_ctx *ctx)
181 {
182         ctx->which_pathbuf = (ctx->which_pathbuf - 1) % NUM_PATHBUFS;
183 }
184
185 /* Builds and returns the filesystem path to which to extract an unspecified
186  * alias of the @inode.  This cycles through NUM_PATHBUFS different buffers.  */
187 static const char *
188 unix_build_inode_extraction_path(const struct wim_inode *inode,
189                                  struct unix_apply_ctx *ctx)
190 {
191         return unix_build_extraction_path(inode_first_extraction_dentry(inode), ctx);
192 }
193
194 /* Should the specified file be extracted as a directory on UNIX?  We extract
195  * the file as a directory if FILE_ATTRIBUTE_DIRECTORY is set and the file does
196  * not have a symlink or junction reparse point.  It *may* have a different type
197  * of reparse point.  */
198 static inline bool
199 should_extract_as_directory(const struct wim_inode *inode)
200 {
201         return (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) &&
202                 !inode_is_symlink(inode);
203 }
204
205 /* Sets the timestamps on a file being extracted. */
206 static int
207 unix_set_timestamps(const char *path, u64 atime, u64 mtime)
208 {
209 #ifdef HAVE_UTIMENSAT
210         {
211                 struct timespec times[2];
212
213                 times[0] = wim_timestamp_to_timespec(atime);
214                 times[1] = wim_timestamp_to_timespec(mtime);
215
216                 if (utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW) == 0)
217                         return 0;
218                 if (errno != ENOSYS)
219                         return -1;
220         }
221 #endif
222         {
223                 struct timeval times[2];
224
225                 times[0] = wim_timestamp_to_timeval(atime);
226                 times[1] = wim_timestamp_to_timeval(mtime);
227
228                 return lutimes(path, times);
229         }
230 }
231
232 /* Set metadata on an extracted file. */
233 static int
234 unix_set_metadata(const struct wim_inode *inode, struct unix_apply_ctx *ctx)
235 {
236         const char *path = unix_build_inode_extraction_path(inode, ctx);
237         struct wimlib_unix_data unix_data;
238
239         if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA)
240             && inode_get_unix_data(inode, &unix_data))
241         {
242                 u32 uid = unix_data.uid;
243                 u32 gid = unix_data.gid;
244                 u32 mode = unix_data.mode;
245
246                 if (lchown(path, uid, gid) != 0) {
247                         if (ctx->common.extract_flags &
248                             WIMLIB_EXTRACT_FLAG_STRICT_ACLS)
249                         {
250                                 ERROR_WITH_ERRNO("Can't set uid=%"PRIu32" and "
251                                                  "gid=%"PRIu32" on \"%s\"",
252                                                  uid, gid, path);
253                                 return WIMLIB_ERR_SET_SECURITY;
254                         }
255                         WARNING_WITH_ERRNO("Can't set uid=%"PRIu32" and "
256                                            "gid=%"PRIu32" on \"%s\"",
257                                            uid, gid, path);
258                 }
259
260                 if (!inode_is_symlink(inode) && chmod(path, mode) != 0) {
261                         if (ctx->common.extract_flags &
262                             WIMLIB_EXTRACT_FLAG_STRICT_ACLS)
263                         {
264                                 ERROR_WITH_ERRNO("Can't set mode=0%"PRIo32" "
265                                                  "on \"%s\"", mode, path);
266                                 return WIMLIB_ERR_SET_SECURITY;
267                         }
268                         WARNING_WITH_ERRNO("Can't set mode=0%"PRIo32" "
269                                            "on \"%s\"", mode, path);
270                 }
271         }
272
273         if (unix_set_timestamps(path, inode->i_last_access_time,
274                                 inode->i_last_write_time) != 0)
275         {
276                 if (ctx->common.extract_flags &
277                     WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS)
278                 {
279                         ERROR_WITH_ERRNO("Can't set timestamps on \"%s\"", path);
280                         return WIMLIB_ERR_SET_TIMESTAMPS;
281                 }
282                 WARNING_WITH_ERRNO("Can't set timestamps on \"%s\"", path);
283         }
284         return 0;
285 }
286
287 /*
288  * Extract all needed aliases of the specified @inode, where the first alias has
289  * already been extracted to @first_path.
290  */
291 static int
292 unix_create_hardlinks(const struct wim_inode *inode,
293                       const char *first_path, struct unix_apply_ctx *ctx)
294 {
295         const struct wim_dentry *dentry;
296         const char *newpath;
297
298         inode_for_each_extraction_alias(dentry, inode) {
299                 if (dentry == inode_first_extraction_dentry(inode))
300                         continue;
301                 newpath = unix_build_extraction_path(dentry, ctx);
302         retry_link:
303                 if (link(first_path, newpath)) {
304                         if (errno == EEXIST && !unlink(newpath))
305                                 goto retry_link;
306                         ERROR_WITH_ERRNO("Can't create hard link "
307                                          "\"%s\" => \"%s\"", newpath, first_path);
308                         return WIMLIB_ERR_LINK;
309                 }
310                 unix_reuse_pathbuf(ctx);
311         }
312         return 0;
313 }
314
315 static int
316 unix_create_directory(const struct wim_dentry *dentry,
317                       struct unix_apply_ctx *ctx)
318 {
319         const char *path = unix_build_extraction_path(dentry, ctx);
320         struct stat stbuf;
321
322         if (mkdir(path, 0755) &&
323             /* It's okay if the path already exists, as long as it's a
324              * directory.  */
325             !(errno == EEXIST && !lstat(path, &stbuf) && S_ISDIR(stbuf.st_mode)))
326         {
327                 ERROR_WITH_ERRNO("Can't create directory \"%s\"", path);
328                 return WIMLIB_ERR_MKDIR;
329         }
330
331         return 0;
332 }
333
334 static int
335 unix_create_nondirectory(const struct wim_inode *inode,
336                          struct unix_apply_ctx *ctx)
337 {
338         const char *path = unix_build_inode_extraction_path(inode, ctx);
339         struct wimlib_unix_data unix_data;
340
341         /* Recognize special files in UNIX_DATA mode  */
342         if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) &&
343             inode_get_unix_data(inode, &unix_data) &&
344             !S_ISREG(unix_data.mode))
345         {
346         retry_mknod:
347                 if (mknod(path, unix_data.mode, unix_data.rdev)) {
348                         if (errno == EPERM) {
349                                 WARNING_WITH_ERRNO("Can't create special "
350                                                    "file \"%s\"", path);
351                                 ctx->num_special_files_ignored++;
352                                 return 0;
353                         }
354                         if (errno == EEXIST && !unlink(path))
355                                 goto retry_mknod;
356                         ERROR_WITH_ERRNO("Can't create special file \"%s\"",
357                                          path);
358                         return WIMLIB_ERR_MKNOD;
359                 }
360         } else {
361                 int fd;
362
363         retry_create:
364                 fd = open(path, O_EXCL | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644);
365                 if (fd < 0) {
366                         if (errno == EEXIST && !unlink(path))
367                                 goto retry_create;
368                         ERROR_WITH_ERRNO("Can't create regular file \"%s\"", path);
369                         return WIMLIB_ERR_OPEN;
370                 }
371                 if (close(fd)) {
372                         ERROR_WITH_ERRNO("Error closing \"%s\"", path);
373                         return WIMLIB_ERR_WRITE;
374                 }
375         }
376
377         return unix_create_hardlinks(inode, path, ctx);
378 }
379
380 /* Create all files (and directories) except for symlinks. */
381 static int
382 unix_create_file_structure(const struct list_head *dentry_list,
383                            struct unix_apply_ctx *ctx)
384 {
385         const struct wim_dentry *dentry;
386         const struct wim_inode *inode;
387         int ret;
388
389         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
390                 inode = dentry->d_inode;
391                 if (!should_extract_as_directory(inode))
392                         continue;
393                 ret = unix_create_directory(dentry, ctx);
394                 if (!ret)
395                         ret = report_file_created(&ctx->common);
396                 if (ret)
397                         return ret;
398         }
399         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
400                 inode = dentry->d_inode;
401                 if (should_extract_as_directory(inode) ||
402                     inode_is_symlink(inode) ||
403                     dentry != inode_first_extraction_dentry(inode))
404                         continue;
405                 ret = unix_create_nondirectory(inode, ctx);
406                 if (!ret)
407                         ret = report_file_created(&ctx->common);
408                 if (ret)
409                         return ret;
410         }
411         return 0;
412 }
413
414 static void
415 unix_count_inodes(const struct list_head *dentry_list,
416                   u64 *full_count, u64 *symlink_count)
417 {
418         const struct wim_dentry *dentry;
419
420         *full_count = 0;
421         *symlink_count = 0;
422
423         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
424                 if (dentry != inode_first_extraction_dentry(dentry->d_inode))
425                         continue;
426                 ++*full_count;
427                 if (inode_is_symlink(dentry->d_inode))
428                         ++*symlink_count;
429         }
430 }
431
432 static int
433 unix_create_symlink(const struct wim_inode *inode, const char *path,
434                     size_t rpdatalen, struct unix_apply_ctx *ctx)
435 {
436         char target[REPARSE_POINT_MAX_SIZE];
437         struct blob_descriptor blob_override;
438         int ret;
439
440         blob_set_is_located_in_attached_buffer(&blob_override,
441                                                ctx->reparse_data, rpdatalen);
442
443         ret = wim_inode_readlink(inode, target, sizeof(target) - 1,
444                                  &blob_override,
445                                  ctx->target_abspath,
446                                  ctx->target_abspath_nchars);
447         if (unlikely(ret < 0)) {
448                 errno = -ret;
449                 return WIMLIB_ERR_READLINK;
450         }
451         target[ret] = '\0';
452
453 retry_symlink:
454         if (symlink(target, path)) {
455                 if (errno == EEXIST && !unlink(path))
456                         goto retry_symlink;
457                 return WIMLIB_ERR_LINK;
458         }
459         return 0;
460 }
461
462 static void
463 unix_cleanup_open_fds(struct unix_apply_ctx *ctx, unsigned offset)
464 {
465         for (unsigned i = offset; i < ctx->num_open_fds; i++)
466                 filedes_close(&ctx->open_fds[i]);
467         ctx->num_open_fds = 0;
468         ctx->any_sparse_files = false;
469 }
470
471 static int
472 unix_begin_extract_blob_instance(const struct blob_descriptor *blob,
473                                  const struct wim_inode *inode,
474                                  const struct wim_inode_stream *strm,
475                                  struct unix_apply_ctx *ctx)
476 {
477         const char *path = unix_build_inode_extraction_path(inode, ctx);
478         int fd;
479
480         if (unlikely(strm->stream_type == STREAM_TYPE_REPARSE_POINT)) {
481                 /* On UNIX, symbolic links must be created with symlink(), which
482                  * requires that the full link target be available.  */
483                 if (blob->size > REPARSE_DATA_MAX_SIZE) {
484                         ERROR_WITH_ERRNO("Reparse data of \"%s\" has size "
485                                          "%"PRIu64" bytes (exceeds %u bytes)",
486                                          path,
487                                          blob->size, REPARSE_DATA_MAX_SIZE);
488                         return WIMLIB_ERR_INVALID_REPARSE_DATA;
489                 }
490                 ctx->reparse_ptr = ctx->reparse_data;
491                 return 0;
492         }
493
494         wimlib_assert(stream_is_unnamed_data_stream(strm));
495
496         /* Unnamed data stream of "regular" file  */
497
498         /* This should be ensured by extract_blob_list()  */
499         wimlib_assert(ctx->num_open_fds < MAX_OPEN_FILES);
500
501         fd = open(path, O_WRONLY | O_NOFOLLOW);
502         if (fd < 0) {
503                 ERROR_WITH_ERRNO("Can't open regular file \"%s\"", path);
504                 return WIMLIB_ERR_OPEN;
505         }
506         if (inode->i_attributes & FILE_ATTRIBUTE_SPARSE_FILE) {
507                 ctx->is_sparse_file[ctx->num_open_fds] = true;
508                 ctx->any_sparse_files = true;
509         } else {
510                 ctx->is_sparse_file[ctx->num_open_fds] = false;
511 #ifdef HAVE_POSIX_FALLOCATE
512                 posix_fallocate(fd, 0, blob->size);
513 #endif
514         }
515         filedes_init(&ctx->open_fds[ctx->num_open_fds++], fd);
516         return 0;
517 }
518
519 /* Called when starting to read a blob for extraction  */
520 static int
521 unix_begin_extract_blob(struct blob_descriptor *blob, void *_ctx)
522 {
523         struct unix_apply_ctx *ctx = _ctx;
524         const struct blob_extraction_target *targets = blob_extraction_targets(blob);
525
526         for (u32 i = 0; i < blob->out_refcnt; i++) {
527                 int ret = unix_begin_extract_blob_instance(blob,
528                                                            targets[i].inode,
529                                                            targets[i].stream,
530                                                            ctx);
531                 if (ret) {
532                         ctx->reparse_ptr = NULL;
533                         unix_cleanup_open_fds(ctx, 0);
534                         return ret;
535                 }
536         }
537         return 0;
538 }
539
540 /* Called when the next chunk of a blob has been read for extraction  */
541 static int
542 unix_extract_chunk(const struct blob_descriptor *blob, u64 offset,
543                    const void *chunk, size_t size, void *_ctx)
544 {
545         struct unix_apply_ctx *ctx = _ctx;
546         const void * const end = chunk + size;
547         const void *p;
548         bool zeroes;
549         size_t len;
550         unsigned i;
551         int ret;
552
553         /*
554          * For sparse files, only write nonzero regions.  This lets the
555          * filesystem use holes to represent zero regions.
556          */
557         for (p = chunk; p != end; p += len, offset += len) {
558                 zeroes = maybe_detect_sparse_region(p, end - p, &len,
559                                                     ctx->any_sparse_files);
560                 for (i = 0; i < ctx->num_open_fds; i++) {
561                         if (!zeroes || !ctx->is_sparse_file[i]) {
562                                 ret = full_pwrite(&ctx->open_fds[i],
563                                                   p, len, offset);
564                                 if (ret)
565                                         goto err;
566                         }
567                 }
568         }
569
570         if (ctx->reparse_ptr)
571                 ctx->reparse_ptr = mempcpy(ctx->reparse_ptr, chunk, size);
572         return 0;
573
574 err:
575         ERROR_WITH_ERRNO("Error writing data to filesystem");
576         return ret;
577 }
578
579 /* Called when a blob has been fully read for extraction  */
580 static int
581 unix_end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx)
582 {
583         struct unix_apply_ctx *ctx = _ctx;
584         int ret;
585         unsigned j;
586         const struct blob_extraction_target *targets = blob_extraction_targets(blob);
587
588         ctx->reparse_ptr = NULL;
589
590         if (status) {
591                 unix_cleanup_open_fds(ctx, 0);
592                 return status;
593         }
594
595         j = 0;
596         ret = 0;
597         for (u32 i = 0; i < blob->out_refcnt; i++) {
598                 struct wim_inode *inode = targets[i].inode;
599
600                 if (inode_is_symlink(inode)) {
601                         /* We finally have the symlink data, so we can create
602                          * the symlink.  */
603                         const char *path;
604
605                         path = unix_build_inode_extraction_path(inode, ctx);
606                         ret = unix_create_symlink(inode, path, blob->size, ctx);
607                         if (ret) {
608                                 ERROR_WITH_ERRNO("Can't create symbolic link "
609                                                  "\"%s\"", path);
610                                 break;
611                         }
612                 } else {
613                         struct filedes *fd = &ctx->open_fds[j];
614
615                         /* If the file is sparse, extend it to its final size. */
616                         if (ctx->is_sparse_file[j] && ftruncate(fd->fd, blob->size)) {
617                                 ERROR_WITH_ERRNO("Error extending \"%s\" to final size",
618                                                  unix_build_inode_extraction_path(inode, ctx));
619                                 ret = WIMLIB_ERR_WRITE;
620                                 break;
621                         }
622
623                         if (filedes_close(fd)) {
624                                 ERROR_WITH_ERRNO("Error closing \"%s\"",
625                                                  unix_build_inode_extraction_path(inode, ctx));
626                                 ret = WIMLIB_ERR_WRITE;
627                                 break;
628                         }
629                         j++;
630                 }
631         }
632         unix_cleanup_open_fds(ctx, j);
633         return ret;
634 }
635
636 /* Apply metadata to all extracted files (and directories). */
637 static int
638 unix_apply_metadata(struct list_head *dentry_list, struct unix_apply_ctx *ctx)
639 {
640         const struct wim_dentry *dentry;
641         const struct wim_inode *inode;
642         int ret;
643
644         list_for_each_entry_reverse(dentry, dentry_list, d_extraction_list_node)
645         {
646                 inode = dentry->d_inode;
647                 if (dentry != inode_first_extraction_dentry(inode))
648                         continue;
649                 ret = unix_set_metadata(inode, ctx);
650                 if (!ret)
651                         ret = report_file_metadata_applied(&ctx->common);
652                 if (ret)
653                         return ret;
654         }
655         return 0;
656 }
657
658 static int
659 unix_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
660 {
661         int ret;
662         struct unix_apply_ctx *ctx = (struct unix_apply_ctx *)_ctx;
663         size_t path_max;
664         u64 full_count;
665         u64 symlink_count;
666
667         /* Compute the maximum path length that will be needed, then allocate
668          * some path buffers.  */
669         path_max = unix_compute_path_max(dentry_list, ctx);
670
671         for (unsigned i = 0; i < NUM_PATHBUFS; i++) {
672                 ctx->pathbufs[i] = MALLOC(path_max);
673                 if (!ctx->pathbufs[i]) {
674                         ret = WIMLIB_ERR_NOMEM;
675                         goto out;
676                 }
677                 /* Pre-fill the target in each path buffer.  We'll just append
678                  * the rest of the paths after this.  */
679                 memcpy(ctx->pathbufs[i],
680                        ctx->common.target, ctx->common.target_nchars);
681         }
682
683         /*
684          * We do the extraction in three phases:
685          *
686          *      1. Create all directories and files except for symlinks
687          *      2. Extract streams
688          *      3. Apply metadata
689          *
690          * In phase (2), the streams which may be extracted include unnamed data
691          * streams (regular file contents), reparse streams (translated to
692          * symlink targets), and extended attribute (xattr) streams.  These may
693          * come up for extraction in any order.  Therefore, at least when xattr
694          * streams are present, all files must be created earlier, in phase (1).
695          *
696          * Symlinks are an exception: they cannot be created until the reparse
697          * stream comes up for extraction.  Currently we hack around this by
698          * caching the xattrs of symlinks in memory until they can be applied
699          * between phases (2) and (3).
700          *
701          * Note that phase (3) must happen after all data all xattr extraction
702          * because it might set the file mode's to readonly (which precludes
703          * setxattr), and it also will set timestamps including the last
704          * modification time (which precludes write).
705          */
706
707         unix_count_inodes(dentry_list, &full_count, &symlink_count);
708
709         ret = start_file_structure_phase(&ctx->common,
710                                          full_count - symlink_count);
711         if (ret)
712                 goto out;
713
714         ret = unix_create_file_structure(dentry_list, ctx);
715         if (ret)
716                 goto out;
717
718         ret = end_file_structure_phase(&ctx->common);
719         if (ret)
720                 goto out;
721
722         /* Get full path to target if needed for absolute symlink fixups.  */
723         if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX) &&
724             ctx->common.required_features.symlink_reparse_points)
725         {
726                 ctx->target_abspath = realpath(ctx->common.target, NULL);
727                 if (!ctx->target_abspath) {
728                         ret = WIMLIB_ERR_NOMEM;
729                         goto out;
730                 }
731                 ctx->target_abspath_nchars = strlen(ctx->target_abspath);
732         }
733
734         struct read_blob_callbacks cbs = {
735                 .begin_blob     = unix_begin_extract_blob,
736                 .continue_blob  = unix_extract_chunk,
737                 .end_blob       = unix_end_extract_blob,
738                 .ctx            = ctx,
739         };
740         ret = extract_blob_list(&ctx->common, &cbs);
741         if (ret)
742                 goto out;
743
744         ret = start_file_metadata_phase(&ctx->common, full_count);
745         if (ret)
746                 goto out;
747
748         ret = unix_apply_metadata(dentry_list, ctx);
749         if (ret)
750                 goto out;
751
752         ret = end_file_metadata_phase(&ctx->common);
753         if (ret)
754                 goto out;
755
756         if (ctx->num_special_files_ignored) {
757                 WARNING("%lu special files were not extracted due to EPERM!",
758                         ctx->num_special_files_ignored);
759         }
760 out:
761         for (unsigned i = 0; i < NUM_PATHBUFS; i++)
762                 FREE(ctx->pathbufs[i]);
763         FREE(ctx->target_abspath);
764         return ret;
765 }
766
767 const struct apply_operations unix_apply_ops = {
768         .name                   = "UNIX",
769         .get_supported_features = unix_get_supported_features,
770         .extract                = unix_extract,
771         .context_size           = sizeof(struct unix_apply_ctx),
772 };