1/* vi: set sw=4 ts=4: */ 2/* 3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 4 */ 5 6#include "libbb.h" 7#include "unarchive.h" 8 9void 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) { 16 char *name = xstrdup(file_header->name); 17 bb_make_directory(dirname(name), -1, FILEUTILS_RECUR); 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 */ 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); 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) { 37 bb_perror_msg_and_die("cannot stat old file"); 38 } 39 } 40 else if (statbuf.st_mtime <= file_header->mtime) { 41 if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { 42 bb_error_msg("%s not created: newer or " 43 "same age file exists", file_header->name); 44 } 45 data_skip(archive_handle); 46 return; 47 } 48 else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { 49 bb_perror_msg_and_die("cannot remove old file %s", 50 file_header->name); 51 } 52 } 53 54 /* Handle hard links separately 55 * We identified hard links as regular files of size 0 with a symlink */ 56 if (S_ISREG(file_header->mode) && (file_header->link_target) 57 && (file_header->size == 0) 58 ) { 59 /* hard link */ 60 res = link(file_header->link_target, file_header->name); 61 if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { 62 bb_perror_msg("cannot create %slink " 63 "from %s to %s", "hard", 64 file_header->name, 65 file_header->link_target); 66 } 67 } else { 68 /* Create the filesystem entry */ 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; 77 } 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 } 112 } 113 114 if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) { 115 lchown(file_header->name, file_header->uid, file_header->gid); 116 } 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 } 130 } 131} 132