]> wimlib.net Git - wimlib/blob - src/unix_apply.c
c4f5318b23b0694c0e6737c19128e0dab9cc6798
[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, 2013, 2014 Eric Biggers
7  *
8  * This file is part of wimlib, a library for working with WIM files.
9  *
10  * wimlib is free software; you can redistribute it and/or modify it under the
11  * terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 3 of the License, or (at your option)
13  * any later version.
14  *
15  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17  * A PARTICULAR PURPOSE. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with wimlib; if not, see http://www.gnu.org/licenses/.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "wimlib/apply.h"
29 #include "wimlib/dentry.h"
30 #include "wimlib/error.h"
31 #include "wimlib/file_io.h"
32 #include "wimlib/reparse.h"
33 #include "wimlib/timestamp.h"
34
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 #include <sys/stat.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <unistd.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->hard_links = 1;
58         supported_features->symlink_reparse_points = 1;
59         supported_features->unix_data = 1;
60         supported_features->timestamps = 1;
61         supported_features->case_sensitive_filenames = 1;
62         return 0;
63 }
64
65 #define NUM_PATHBUFS 2  /* We need 2 when creating hard links  */
66 #define MAX_OPEN_FDS 1024 /* TODO: Add special case for when the number of
67                              identical streams exceeds this number.  */
68
69 struct unix_apply_ctx {
70         /* Extract flags, the pointer to the WIMStruct, etc.  */
71         struct apply_ctx common;
72
73         /* Buffers for building extraction paths (allocated).  */
74         char *pathbufs[NUM_PATHBUFS];
75
76         /* Index of next pathbuf to use  */
77         unsigned which_pathbuf;
78
79         /* Currently open file descriptors for extraction  */
80         struct filedes open_fds[MAX_OPEN_FDS];
81
82         /* Number of currently open file descriptors in open_fds, starting from
83          * the beginning of the array.  */
84         unsigned num_open_fds;
85
86         /* Buffer for reading reparse data streams into memory  */
87         u8 reparse_data[REPARSE_DATA_MAX_SIZE];
88
89         /* Pointer to the next byte in @reparse_data to fill  */
90         u8 *reparse_ptr;
91
92         /* Absolute path to the target directory (allocated buffer).  Only set
93          * if needed for absolute symbolic link fixups.  */
94         char *target_abspath;
95
96         /* Number of characters in target_abspath.  */
97         size_t target_abspath_nchars;
98 };
99
100 /* Returns the number of characters needed to represent the path to the
101  * specified @dentry when extracted, not including the null terminator or the
102  * path to the target directory itself.  */
103 static size_t
104 unix_dentry_path_length(const struct wim_dentry *dentry)
105 {
106         size_t len = 0;
107         const struct wim_dentry *d;
108
109         d = dentry;
110         do {
111                 len += d->d_extraction_name_nchars + 1;
112                 d = d->parent;
113         } while (!dentry_is_root(d) && will_extract_dentry(d));
114
115         return len;
116 }
117
118 /* Returns the maximum number of characters needed to represent the path to any
119  * dentry in @dentry_list when extracted, including the null terminator and the
120  * path to the target directory itself.  */
121 static size_t
122 unix_compute_path_max(const struct list_head *dentry_list,
123                       const struct unix_apply_ctx *ctx)
124 {
125         size_t max = 0;
126         size_t len;
127         const struct wim_dentry *dentry;
128
129         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
130                 len = unix_dentry_path_length(dentry);
131                 if (len > max)
132                         max = len;
133         }
134
135         /* Account for target and null terminator.  */
136         return ctx->common.target_nchars + max + 1;
137 }
138
139 /* Builds and returns the filesystem path to which to extract @dentry.
140  * This cycles through NUM_PATHBUFS different buffers.  */
141 static const char *
142 unix_build_extraction_path(const struct wim_dentry *dentry,
143                            struct unix_apply_ctx *ctx)
144 {
145         char *pathbuf;
146         char *p;
147         const struct wim_dentry *d;
148
149         pathbuf = ctx->pathbufs[ctx->which_pathbuf];
150         ctx->which_pathbuf = (ctx->which_pathbuf + 1) % NUM_PATHBUFS;
151
152         p = &pathbuf[ctx->common.target_nchars +
153                      unix_dentry_path_length(dentry)];
154         *p = '\0';
155         d = dentry;
156         do {
157                 p -= d->d_extraction_name_nchars;
158                 memcpy(p, d->d_extraction_name, d->d_extraction_name_nchars);
159                 *--p = '/';
160                 d = d->parent;
161         } while (!dentry_is_root(d) && will_extract_dentry(d));
162
163         return pathbuf;
164 }
165
166 /* This causes the next call to unix_build_extraction_path() to use the same
167  * path buffer as the previous call.  */
168 static void
169 unix_reuse_pathbuf(struct unix_apply_ctx *ctx)
170 {
171         ctx->which_pathbuf = (ctx->which_pathbuf - 1) % NUM_PATHBUFS;
172 }
173
174 /* Builds and returns the filesystem path to which to extract an unspecified
175  * alias of the @inode.  This cycles through NUM_PATHBUFS different buffers.  */
176 static const char *
177 unix_build_inode_extraction_path(const struct wim_inode *inode,
178                                  struct unix_apply_ctx *ctx)
179 {
180         return unix_build_extraction_path(inode_first_extraction_dentry(inode), ctx);
181 }
182
183 /* Sets the timestamps on a file being extracted.
184  *
185  * Either @fd or @path must be specified (not -1 and not NULL, respectively).
186  */
187 static int
188 unix_set_timestamps(int fd, const char *path, u64 atime, u64 mtime)
189 {
190         {
191                 struct timespec times[2];
192
193                 times[0] = wim_timestamp_to_timespec(atime);
194                 times[1] = wim_timestamp_to_timespec(mtime);
195
196                 errno = ENOSYS;
197 #ifdef HAVE_FUTIMENS
198                 if (fd >= 0 && !futimens(fd, times))
199                         return 0;
200 #endif
201 #ifdef HAVE_UTIMENSAT
202                 if (fd < 0 && !utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW))
203                         return 0;
204 #endif
205                 if (errno != ENOSYS)
206                         return WIMLIB_ERR_SET_TIMESTAMPS;
207         }
208         {
209                 struct timeval times[2];
210
211                 times[0] = wim_timestamp_to_timeval(atime);
212                 times[1] = wim_timestamp_to_timeval(mtime);
213
214                 if (fd >= 0 && !futimes(fd, times))
215                         return 0;
216                 if (fd < 0 && !lutimes(path, times))
217                         return 0;
218                 return WIMLIB_ERR_SET_TIMESTAMPS;
219         }
220 }
221
222 /*
223  * Set metadata on an extracted file.
224  *
225  * @fd is an open file descriptor to the extracted file, or -1.  @path is the
226  * path to the extracted file, or NULL.  If valid, this function uses @fd.
227  * Otherwise, if valid, it uses @path.  Otherwise, it calculates the path to one
228  * alias of the extracted file and uses it.
229  */
230 static int
231 unix_set_metadata(int fd, const struct wim_inode *inode,
232                   const char *path, struct unix_apply_ctx *ctx)
233 {
234         int ret;
235
236         if (fd < 0 && !path)
237                 path = unix_build_inode_extraction_path(inode, ctx);
238
239         ret = unix_set_timestamps(fd, path,
240                                   inode->i_last_access_time,
241                                   inode->i_last_write_time);
242         if (ret) {
243                 if (!path)
244                         path = unix_build_inode_extraction_path(inode, ctx);
245                 if (ctx->common.extract_flags &
246                     WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS)
247                 {
248                         ERROR_WITH_ERRNO("Can't set timestamps on \"%s\"", path);
249                         return ret;
250                 } else {
251                         WARNING_WITH_ERRNO("Can't set timestamps on \"%s\"", path);
252                 }
253         }
254         return 0;
255 }
256
257 /* Extract all needed aliases of the @inode, where one alias, corresponding to
258  * @first_dentry, has already been extracted to @first_path.  */
259 static int
260 unix_create_hardlinks(const struct wim_inode *inode,
261                       const struct wim_dentry *first_dentry,
262                       const char *first_path, struct unix_apply_ctx *ctx)
263 {
264         const struct wim_dentry *dentry;
265         const char *newpath;
266
267         list_for_each_entry(dentry, &inode->i_extraction_aliases,
268                             d_extraction_alias_node)
269         {
270                 if (dentry == first_dentry)
271                         continue;
272
273                 newpath = unix_build_extraction_path(dentry, ctx);
274         retry_link:
275                 if (link(first_path, newpath)) {
276                         if (errno == EEXIST && !unlink(newpath))
277                                 goto retry_link;
278                         ERROR_WITH_ERRNO("Can't create hard link "
279                                          "\"%s\" => \"%s\"", newpath, first_path);
280                         return WIMLIB_ERR_LINK;
281                 }
282                 unix_reuse_pathbuf(ctx);
283         }
284         return 0;
285 }
286
287 /* If @dentry represents a directory, create it.  */
288 static int
289 unix_create_if_directory(const struct wim_dentry *dentry,
290                          struct unix_apply_ctx *ctx)
291 {
292         const char *path;
293         struct stat stbuf;
294
295         if (!dentry_is_directory(dentry))
296                 return 0;
297
298         path = unix_build_extraction_path(dentry, ctx);
299         if (mkdir(path, 0755) &&
300             /* It's okay if the path already exists, as long as it's a
301              * directory.  */
302             !(errno == EEXIST && !lstat(path, &stbuf) && S_ISDIR(stbuf.st_mode)))
303         {
304                 ERROR_WITH_ERRNO("Can't create directory \"%s\"", path);
305                 return WIMLIB_ERR_MKDIR;
306         }
307         return 0;
308 }
309
310 /* If @dentry represents an empty regular file, create it, set its metadata, and
311  * create any needed hard links.  */
312 static int
313 unix_extract_if_empty_file(const struct wim_dentry *dentry,
314                            struct unix_apply_ctx *ctx)
315 {
316         const struct wim_inode *inode;
317         const char *path;
318         int fd;
319         int ret;
320
321         inode = dentry->d_inode;
322
323         /* Extract all aliases only when the "first" comes up.  */
324         if (dentry != inode_first_extraction_dentry(inode))
325                 return 0;
326
327         /* Not an empty regular file?  */
328         if (inode_is_directory(inode) || inode_is_symlink(inode) ||
329             inode_unnamed_lte_resolved(inode))
330                 return 0;
331
332         path = unix_build_extraction_path(dentry, ctx);
333 retry_create:
334         fd = open(path, O_TRUNC | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644);
335         if (fd < 0) {
336                 if (errno == EEXIST && !unlink(path))
337                         goto retry_create;
338                 ERROR_WITH_ERRNO("Can't create regular file \"%s\"", path);
339                 return WIMLIB_ERR_OPEN;
340         }
341         /* On empty files, we can set timestamps immediately because we don't
342          * need to write any data to them.  */
343         ret = unix_set_metadata(fd, inode, path, ctx);
344         if (close(fd) && !ret) {
345                 ERROR_WITH_ERRNO("Error closing \"%s\"", path);
346                 ret = WIMLIB_ERR_WRITE;
347         }
348         if (ret)
349                 return ret;
350
351         return unix_create_hardlinks(inode, dentry, path, ctx);
352 }
353
354 static int
355 unix_create_dirs_and_empty_files(const struct list_head *dentry_list,
356                                  struct unix_apply_ctx *ctx)
357 {
358         const struct wim_dentry *dentry;
359         int ret;
360
361         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
362                 ret = unix_create_if_directory(dentry, ctx);
363                 if (ret)
364                         return ret;
365         }
366         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
367                 ret = unix_extract_if_empty_file(dentry, ctx);
368                 if (ret)
369                         return ret;
370         }
371         return 0;
372 }
373
374 static int
375 unix_create_symlink(const struct wim_inode *inode, const char *path,
376                     const u8 *rpdata, u16 rpdatalen, bool rpfix,
377                     const char *apply_dir, size_t apply_dir_nchars)
378 {
379         char link_target[REPARSE_DATA_MAX_SIZE];
380         int ret;
381         struct wim_lookup_table_entry lte_override;
382
383         lte_override.resource_location = RESOURCE_IN_ATTACHED_BUFFER;
384         lte_override.attached_buffer = (void *)rpdata;
385         lte_override.size = rpdatalen;
386
387         ret = wim_inode_readlink(inode, link_target,
388                                  sizeof(link_target) - 1, &lte_override);
389         if (ret < 0) {
390                 errno = -ret;
391                 return WIMLIB_ERR_READLINK;
392         }
393
394         link_target[ret] = 0;
395
396         if (rpfix && link_target[0] == '/') {
397
398                 /* "Fix" the absolute symbolic link by prepending the absolute
399                  * path to the target directory.  */
400
401                 if (sizeof(link_target) - (ret + 1) < apply_dir_nchars) {
402                         errno = ENAMETOOLONG;
403                         return WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED;
404                 }
405                 memmove(link_target + apply_dir_nchars, link_target,
406                         ret + 1);
407                 memcpy(link_target, apply_dir, apply_dir_nchars);
408         }
409 retry_symlink:
410         if (symlink(link_target, path)) {
411                 if (errno == EEXIST && !unlink(path))
412                         goto retry_symlink;
413                 return WIMLIB_ERR_LINK;
414         }
415         return 0;
416 }
417
418 static void
419 unix_cleanup_open_fds(struct unix_apply_ctx *ctx, unsigned offset)
420 {
421         for (unsigned i = offset; i < ctx->num_open_fds; i++)
422                 filedes_close(&ctx->open_fds[i]);
423         ctx->num_open_fds = 0;
424 }
425
426 static int
427 unix_begin_extract_stream_instance(const struct wim_lookup_table_entry *stream,
428                                    const struct wim_inode *inode,
429                                    struct unix_apply_ctx *ctx)
430 {
431         const struct wim_dentry *first_dentry;
432         const char *first_path;
433         int fd;
434
435         if (inode_is_symlink(inode)) {
436                 /* On UNIX, symbolic links must be created with symlink(), which
437                  * requires that the full link target be available.  */
438                 if (stream->size > REPARSE_DATA_MAX_SIZE) {
439                         ERROR_WITH_ERRNO("Reparse data of \"%s\" has size "
440                                          "%"PRIu64" bytes (exceeds %u bytes)",
441                                          inode_first_full_path(inode),
442                                          stream->size, REPARSE_DATA_MAX_SIZE);
443                         return WIMLIB_ERR_INVALID_REPARSE_DATA;
444                 }
445                 ctx->reparse_ptr = ctx->reparse_data;
446                 return 0;
447         }
448
449         first_dentry = inode_first_extraction_dentry(inode);
450         first_path = unix_build_extraction_path(first_dentry, ctx);
451 retry_create:
452         fd = open(first_path, O_TRUNC | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644);
453         if (fd < 0) {
454                 if (errno == EEXIST && !unlink(first_path))
455                         goto retry_create;
456                 ERROR_WITH_ERRNO("Can't create regular file \"%s\"", first_path);
457                 return WIMLIB_ERR_OPEN;
458         }
459         filedes_init(&ctx->open_fds[ctx->num_open_fds++], fd);
460         return unix_create_hardlinks(inode, first_dentry, first_path, ctx);
461 }
462
463 /* Called when starting to read a single-instance stream for extraction  */
464 static int
465 unix_begin_extract_stream(struct wim_lookup_table_entry *stream,
466                           u32 flags, void *_ctx)
467 {
468         struct unix_apply_ctx *ctx = _ctx;
469         const struct stream_owner *owners = stream_owners(stream);
470         int ret;
471
472         for (u32 i = 0; i < stream->out_refcnt; i++) {
473                 const struct wim_inode *inode = owners[i].inode;
474
475                 ret = unix_begin_extract_stream_instance(stream, inode, ctx);
476                 if (ret) {
477                         ctx->reparse_ptr = NULL;
478                         unix_cleanup_open_fds(ctx, 0);
479                         return ret;
480                 }
481         }
482         return 0;
483 }
484
485 /* Called when the next chunk of a single-instance stream has been read for
486  * extraction  */
487 static int
488 unix_extract_chunk(const void *chunk, size_t size, void *_ctx)
489 {
490         struct unix_apply_ctx *ctx = _ctx;
491         int ret;
492
493         for (unsigned i = 0; i < ctx->num_open_fds; i++) {
494                 ret = full_write(&ctx->open_fds[i], chunk, size);
495                 if (ret) {
496                         ERROR_WITH_ERRNO("Error writing data to filesystem");
497                         return ret;
498                 }
499         }
500         if (ctx->reparse_ptr)
501                 ctx->reparse_ptr = mempcpy(ctx->reparse_ptr, chunk, size);
502         return 0;
503 }
504
505 /* Called when a single-instance stream has been fully read for extraction  */
506 static int
507 unix_end_extract_stream(struct wim_lookup_table_entry *stream, int status,
508                         void *_ctx)
509 {
510         struct unix_apply_ctx *ctx = _ctx;
511         int ret;
512         unsigned j;
513         const struct stream_owner *owners = stream_owners(stream);
514
515         ctx->reparse_ptr = NULL;
516
517         if (status) {
518                 unix_cleanup_open_fds(ctx, 0);
519                 return status;
520         }
521
522         j = 0;
523         ret = 0;
524         for (u32 i = 0; i < stream->out_refcnt; i++) {
525                 struct wim_inode *inode = owners[i].inode;
526
527                 if (inode_is_symlink(inode)) {
528                         /* We finally have the symlink data, so we can create
529                          * the symlink.  */
530                         const char *path;
531
532                         path = unix_build_inode_extraction_path(inode, ctx);
533                         ret = unix_create_symlink(inode, path,
534                                                   ctx->reparse_data,
535                                                   stream->size,
536                                                   (ctx->common.extract_flags &
537                                                    WIMLIB_EXTRACT_FLAG_RPFIX),
538                                                   ctx->target_abspath,
539                                                   ctx->target_abspath_nchars);
540                         if (ret) {
541                                 ERROR_WITH_ERRNO("Can't create symbolic link "
542                                                  "\"%s\"", path);
543                                 break;
544                         }
545                         ret = unix_set_metadata(-1, inode, path, ctx);
546                         if (ret)
547                                 break;
548                 } else {
549                         /* Set metadata on regular file just before closing it.
550                          */
551                         struct filedes *fd = &ctx->open_fds[j];
552
553                         ret = unix_set_metadata(fd->fd, inode, NULL, ctx);
554                         if (ret)
555                                 break;
556
557                         if (filedes_close(fd)) {
558                                 ERROR_WITH_ERRNO("Error closing \"%s\"",
559                                                  unix_build_inode_extraction_path(inode, ctx));
560                                 ret = WIMLIB_ERR_WRITE;
561                                 break;
562                         }
563                         j++;
564                 }
565         }
566         unix_cleanup_open_fds(ctx, j);
567         return ret;
568 }
569
570 static int
571 unix_set_dir_metadata(struct list_head *dentry_list, struct unix_apply_ctx *ctx)
572 {
573         const struct wim_dentry *dentry;
574         int ret;
575
576         list_for_each_entry_reverse(dentry, dentry_list, d_extraction_list_node) {
577                 if (dentry_is_directory(dentry)) {
578                         ret = unix_set_metadata(-1, dentry->d_inode, NULL, ctx);
579                         if (ret)
580                                 return ret;
581                 }
582         }
583         return 0;
584 }
585
586 static int
587 unix_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
588 {
589         int ret;
590         struct unix_apply_ctx *ctx = (struct unix_apply_ctx *)_ctx;
591         size_t path_max;
592
593         /* Compute the maximum path length that will be needed, then allocate
594          * some path buffers.  */
595         path_max = unix_compute_path_max(dentry_list, ctx);
596
597         for (unsigned i = 0; i < NUM_PATHBUFS; i++) {
598                 ctx->pathbufs[i] = MALLOC(path_max);
599                 if (!ctx->pathbufs[i]) {
600                         ret = WIMLIB_ERR_NOMEM;
601                         goto out;
602                 }
603                 /* Pre-fill the target in each path buffer.  We'll just append
604                  * the rest of the paths after this.  */
605                 memcpy(ctx->pathbufs[i],
606                        ctx->common.target, ctx->common.target_nchars);
607         }
608
609         /* Extract directories and empty regular files.  Directories are needed
610          * because we can't extract any other files until their directories
611          * exist.  Empty files are needed because they don't have
612          * representatives in the stream list.  */
613         ret = unix_create_dirs_and_empty_files(dentry_list, ctx);
614         if (ret)
615                 goto out;
616
617         /* Get full path to target if needed for absolute symlink fixups.  */
618         if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX) &&
619             ctx->common.required_features.symlink_reparse_points)
620         {
621                 ctx->target_abspath = realpath(ctx->common.target, NULL);
622                 if (!ctx->target_abspath) {
623                         ret = WIMLIB_ERR_NOMEM;
624                         goto out;
625                 }
626                 ctx->target_abspath_nchars = strlen(ctx->target_abspath);
627         }
628
629         /* Extract nonempty regular files and symbolic links.  */
630
631         struct read_stream_list_callbacks cbs = {
632                 .begin_stream      = unix_begin_extract_stream,
633                 .begin_stream_ctx  = ctx,
634                 .consume_chunk     = unix_extract_chunk,
635                 .consume_chunk_ctx = ctx,
636                 .end_stream        = unix_end_extract_stream,
637                 .end_stream_ctx    = ctx,
638         };
639         ret = extract_stream_list(&ctx->common, &cbs);
640         if (ret)
641                 goto out;
642
643         /* Set directory metadata.  We do this last so that we get the right
644          * directory timestamps.  */
645         ret = unix_set_dir_metadata(dentry_list, ctx);
646 out:
647         for (unsigned i = 0; i < NUM_PATHBUFS; i++)
648                 FREE(ctx->pathbufs[i]);
649         FREE(ctx->target_abspath);
650         return ret;
651 }
652
653 const struct apply_operations unix_apply_ops = {
654         .name                   = "UNIX",
655         .get_supported_features = unix_get_supported_features,
656         .extract                = unix_extract,
657         .context_size           = sizeof(struct unix_apply_ctx),
658 };