[1770] | 1 | /* vi: set sw=4 ts=4: */
|
---|
[821] | 2 | /*
|
---|
[1770] | 3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
|
---|
[821] | 4 | */
|
---|
| 5 |
|
---|
| 6 | #include "libbb.h"
|
---|
| 7 | #include "unarchive.h"
|
---|
| 8 |
|
---|
| 9 | void data_extract_all(archive_handle_t *archive_handle)
|
---|
| 10 | {
|
---|
| 11 | file_header_t *file_header = archive_handle->file_header;
|
---|
| 12 | int dst_fd;
|
---|
| 13 | int res;
|
---|
| 14 |
|
---|
| 15 | if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) {
|
---|
[1770] | 16 | char *name = xstrdup(file_header->name);
|
---|
| 17 | bb_make_directory(dirname(name), -1, FILEUTILS_RECUR);
|
---|
[821] | 18 | free(name);
|
---|
| 19 | }
|
---|
| 20 |
|
---|
| 21 | /* Check if the file already exists */
|
---|
| 22 | if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
|
---|
| 23 | /* Remove the existing entry if it exists */
|
---|
[1770] | 24 | if (((file_header->mode & S_IFMT) != S_IFDIR)
|
---|
| 25 | && (unlink(file_header->name) == -1)
|
---|
| 26 | && (errno != ENOENT)
|
---|
| 27 | ) {
|
---|
| 28 | bb_perror_msg_and_die("cannot remove old file %s",
|
---|
| 29 | file_header->name);
|
---|
[821] | 30 | }
|
---|
| 31 | }
|
---|
| 32 | else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) {
|
---|
| 33 | /* Remove the existing entry if its older than the extracted entry */
|
---|
| 34 | struct stat statbuf;
|
---|
| 35 | if (lstat(file_header->name, &statbuf) == -1) {
|
---|
| 36 | if (errno != ENOENT) {
|
---|
[1770] | 37 | bb_perror_msg_and_die("cannot stat old file");
|
---|
[821] | 38 | }
|
---|
| 39 | }
|
---|
| 40 | else if (statbuf.st_mtime <= file_header->mtime) {
|
---|
| 41 | if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
|
---|
[1770] | 42 | bb_error_msg("%s not created: newer or "
|
---|
| 43 | "same age file exists", file_header->name);
|
---|
[821] | 44 | }
|
---|
| 45 | data_skip(archive_handle);
|
---|
| 46 | return;
|
---|
| 47 | }
|
---|
| 48 | else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
|
---|
[1770] | 49 | bb_perror_msg_and_die("cannot remove old file %s",
|
---|
| 50 | file_header->name);
|
---|
[821] | 51 | }
|
---|
| 52 | }
|
---|
| 53 |
|
---|
| 54 | /* Handle hard links separately
|
---|
| 55 | * We identified hard links as regular files of size 0 with a symlink */
|
---|
[1770] | 56 | if (S_ISREG(file_header->mode) && (file_header->link_target)
|
---|
| 57 | && (file_header->size == 0)
|
---|
| 58 | ) {
|
---|
[821] | 59 | /* hard link */
|
---|
[1770] | 60 | res = link(file_header->link_target, file_header->name);
|
---|
[821] | 61 | if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
|
---|
[1770] | 62 | bb_perror_msg("cannot create %slink "
|
---|
| 63 | "from %s to %s", "hard",
|
---|
| 64 | file_header->name,
|
---|
| 65 | file_header->link_target);
|
---|
[821] | 66 | }
|
---|
| 67 | } else {
|
---|
| 68 | /* Create the filesystem entry */
|
---|
[1770] | 69 | switch (file_header->mode & S_IFMT) {
|
---|
| 70 | case S_IFREG: {
|
---|
| 71 | /* Regular file */
|
---|
| 72 | dst_fd = xopen3(file_header->name, O_WRONLY | O_CREAT | O_EXCL,
|
---|
| 73 | file_header->mode);
|
---|
| 74 | bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
|
---|
| 75 | close(dst_fd);
|
---|
| 76 | break;
|
---|
[821] | 77 | }
|
---|
[1770] | 78 | case S_IFDIR:
|
---|
| 79 | res = mkdir(file_header->name, file_header->mode);
|
---|
| 80 | if ((res == -1) && (errno != EISDIR)
|
---|
| 81 | && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
|
---|
| 82 | ) {
|
---|
| 83 | bb_perror_msg("cannot make dir %s", file_header->name);
|
---|
| 84 | }
|
---|
| 85 | break;
|
---|
| 86 | case S_IFLNK:
|
---|
| 87 | /* Symlink */
|
---|
| 88 | res = symlink(file_header->link_target, file_header->name);
|
---|
| 89 | if ((res == -1)
|
---|
| 90 | && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
|
---|
| 91 | ) {
|
---|
| 92 | bb_perror_msg("cannot create %slink "
|
---|
| 93 | "from %s to %s", "sym",
|
---|
| 94 | file_header->name,
|
---|
| 95 | file_header->link_target);
|
---|
| 96 | }
|
---|
| 97 | break;
|
---|
| 98 | case S_IFSOCK:
|
---|
| 99 | case S_IFBLK:
|
---|
| 100 | case S_IFCHR:
|
---|
| 101 | case S_IFIFO:
|
---|
| 102 | res = mknod(file_header->name, file_header->mode, file_header->device);
|
---|
| 103 | if ((res == -1)
|
---|
| 104 | && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
|
---|
| 105 | ) {
|
---|
| 106 | bb_perror_msg("cannot create node %s", file_header->name);
|
---|
| 107 | }
|
---|
| 108 | break;
|
---|
| 109 | default:
|
---|
| 110 | bb_error_msg_and_die("unrecognized file type");
|
---|
| 111 | }
|
---|
[821] | 112 | }
|
---|
| 113 |
|
---|
| 114 | if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) {
|
---|
| 115 | lchown(file_header->name, file_header->uid, file_header->gid);
|
---|
| 116 | }
|
---|
[1770] | 117 | if ((file_header->mode & S_IFMT) != S_IFLNK) {
|
---|
| 118 | /* uclibc has no lchmod, glibc is even stranger -
|
---|
| 119 | * it has lchmod which seems to do nothing!
|
---|
| 120 | * so we use chmod... */
|
---|
| 121 | if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM)) {
|
---|
| 122 | chmod(file_header->name, file_header->mode);
|
---|
| 123 | }
|
---|
| 124 | /* same for utime */
|
---|
| 125 | if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) {
|
---|
| 126 | struct utimbuf t;
|
---|
| 127 | t.actime = t.modtime = file_header->mtime;
|
---|
| 128 | utime(file_header->name, &t);
|
---|
| 129 | }
|
---|
[821] | 130 | }
|
---|
| 131 | }
|
---|