From 4aca87515a5083ae0e31ce3177189fd43b6d05ac Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 3 Jan 2015 13:58:15 +0100 Subject: patch to Vanilla Tomato 1.28 --- .../archival/libunarchive/data_extract_all.c | 174 +++++++++++++-------- 1 file changed, 111 insertions(+), 63 deletions(-) (limited to 'release/src/router/busybox/archival/libunarchive/data_extract_all.c') diff --git a/release/src/router/busybox/archival/libunarchive/data_extract_all.c b/release/src/router/busybox/archival/libunarchive/data_extract_all.c index bd264dd7..8b1ee2a6 100644 --- a/release/src/router/busybox/archival/libunarchive/data_extract_all.c +++ b/release/src/router/busybox/archival/libunarchive/data_extract_all.c @@ -1,100 +1,148 @@ +/* vi: set sw=4 ts=4: */ /* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include - -#include -#include -#include -#include -#include -#include -#include - #include "libbb.h" #include "unarchive.h" -extern void data_extract_all(archive_handle_t *archive_handle) +void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; - if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) { - char *name = bb_xstrdup(file_header->name); - bb_make_directory (dirname(name), 0777, FILEUTILS_RECUR); + if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { + char *name = xstrdup(file_header->name); + bb_make_directory(dirname(name), -1, FILEUTILS_RECUR); free(name); - } + } - /* Create the filesystem entry */ - switch(file_header->mode & S_IFMT) { - case S_IFREG: { -#ifdef CONFIG_CPIO - if (file_header->link_name && file_header->size == 0) { - /* hard link */ - res = link(file_header->link_name, file_header->name); - if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { - bb_perror_msg("Couldnt create hard link"); - } - } else -#endif - { - /* Regular file */ - unlink(file_header->name); - dst_fd = bb_xopen(file_header->name, O_WRONLY | O_CREAT | O_EXCL); - archive_copy_file(archive_handle, dst_fd); - close(dst_fd); + /* Check if the file already exists */ + if (archive_handle->ah_flags & ARCHIVE_EXTRACT_UNCONDITIONAL) { + /* Remove the entry if it exists */ + if (((file_header->mode & S_IFMT) != S_IFDIR) + && (unlink(file_header->name) == -1) + && (errno != ENOENT) + ) { + bb_perror_msg_and_die("cannot remove old file %s", + file_header->name); + } + } + else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { + /* Remove the existing entry if its older than the extracted entry */ + struct stat statbuf; + if (lstat(file_header->name, &statbuf) == -1) { + if (errno != ENOENT) { + bb_perror_msg_and_die("cannot stat old file"); + } + } + else if (statbuf.st_mtime <= file_header->mtime) { + if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { + bb_error_msg("%s not created: newer or " + "same age file exists", file_header->name); } + data_skip(archive_handle); + return; + } + else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { + bb_perror_msg_and_die("cannot remove old file %s", + file_header->name); + } + } + + /* Handle hard links separately + * We identified hard links as regular files of size 0 with a symlink */ + if (S_ISREG(file_header->mode) && (file_header->link_target) + && (file_header->size == 0) + ) { + /* hard link */ + res = link(file_header->link_target, file_header->name); + if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { + bb_perror_msg("cannot create %slink " + "from %s to %s", "hard", + file_header->name, + file_header->link_target); + } + } else { + /* Create the filesystem entry */ + switch (file_header->mode & S_IFMT) { + case S_IFREG: { + /* Regular file */ + dst_fd = xopen3(file_header->name, O_WRONLY | O_CREAT | O_EXCL, + file_header->mode); + bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); + close(dst_fd); break; } case S_IFDIR: - unlink(file_header->name); res = mkdir(file_header->name, file_header->mode); - if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { - bb_perror_msg("extract_archive: %s", file_header->name); + if ((res == -1) + && (errno != EISDIR) /* btw, Linux doesn't return this */ + && (errno != EEXIST) + && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) + ) { + bb_perror_msg("cannot make dir %s", file_header->name); } break; case S_IFLNK: /* Symlink */ - unlink(file_header->name); - res = symlink(file_header->link_name, file_header->name); - if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { - bb_perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name); + res = symlink(file_header->link_target, file_header->name); + if ((res == -1) + && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) + ) { + bb_perror_msg("cannot create %slink " + "from %s to %s", "sym", + file_header->name, + file_header->link_target); } break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: - unlink(file_header->name); res = mknod(file_header->name, file_header->mode, file_header->device); - if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { - bb_perror_msg("Cannot create node %s", file_header->name); + if ((res == -1) + && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) + ) { + bb_perror_msg("cannot create node %s", file_header->name); } break; default: - bb_error_msg_and_die("Unrecognised file type"); + bb_error_msg_and_die("unrecognized file type"); + } } - chmod(file_header->name, file_header->mode); - chown(file_header->name, file_header->uid, file_header->gid); + if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_OWN)) { +#if ENABLE_FEATURE_TAR_UNAME_GNAME + uid_t uid = file_header->uid; + gid_t gid = file_header->gid; - if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) { - struct utimbuf t; - t.actime = t.modtime = file_header->mtime; - utime(file_header->name, &t); + if (file_header->uname) { + struct passwd *pwd = getpwnam(file_header->uname); + if (pwd) uid = pwd->pw_uid; + } + if (file_header->gname) { + struct group *grp = getgrnam(file_header->gname); + if (grp) gid = grp->gr_gid; + } + lchown(file_header->name, uid, gid); +#else + lchown(file_header->name, file_header->uid, file_header->gid); +#endif + } + if ((file_header->mode & S_IFMT) != S_IFLNK) { + /* uclibc has no lchmod, glibc is even stranger - + * it has lchmod which seems to do nothing! + * so we use chmod... */ + if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_PERM)) { + chmod(file_header->name, file_header->mode); + } + /* same for utime */ + if (archive_handle->ah_flags & ARCHIVE_PRESERVE_DATE) { + struct utimbuf t; + t.actime = t.modtime = file_header->mtime; + utime(file_header->name, &t); + } } } -- cgit v1.2.3-54-g00ecf