diff options
Diffstat (limited to 'archival')
-rw-r--r-- | archival/tar.c | 334 |
1 files changed, 146 insertions, 188 deletions
diff --git a/archival/tar.c b/archival/tar.c index 4363d35..4f02e90 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -21,20 +21,7 @@ * Copyright (C) 1995 Bruce Perens * This is free software under the GNU General Public License. * - * 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 GPL v2 (or later), see file LICENSE in this tarball. */ #include <fcntl.h> @@ -94,22 +81,22 @@ typedef struct TarHeader TarHeader; typedef struct HardLinkInfo HardLinkInfo; struct HardLinkInfo { HardLinkInfo *next; /* Next entry in list */ - dev_t dev; /* Device number */ - ino_t ino; /* Inode number */ + dev_t dev; /* Device number */ + ino_t ino; /* Inode number */ short linkCount; /* (Hard) Link Count */ char name[1]; /* Start of filename (must be last) */ }; /* Some info to be carried along when creating a new tarball */ struct TarBallInfo { - char *fileName; /* File name of the tarball */ - int tarFd; /* Open-for-write file descriptor - for the tarball */ + char *fileName; /* File name of the tarball */ + int tarFd; /* Open-for-write file descriptor + for the tarball */ struct stat statBuf; /* Stat info for the tarball, letting us know the inode and device that the tarball lives, so we can avoid trying to include the tarball into itself */ - int verboseFlag; /* Whether to print extra stuff or not */ + int verboseFlag; /* Whether to print extra stuff or not */ const llist_t *excludeList; /* List of files to not include */ HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ @@ -213,9 +200,7 @@ static int putOctal(char *cp, int len, long value) /* Write out a tar header for the specified file/directory/whatever */ static inline int writeTarHeader(struct TarBallInfo *tbInfo, - const char *header_name, - const char *real_name, - struct stat *statbuf) + const char *header_name, const char *real_name, struct stat *statbuf) { long chksum = 0; struct TarHeader header; @@ -393,11 +378,10 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, if (header_name[0] == '\0') return TRUE; -# ifdef CONFIG_FEATURE_TAR_FROM - if (exclude_file(tbInfo->excludeList, header_name)) { + if (ENABLE_FEATURE_TAR_FROM && + exclude_file(tbInfo->excludeList, header_name)) { return SKIP; } -# endif /* CONFIG_FEATURE_TAR_FROM */ if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) { return (FALSE); @@ -419,9 +403,9 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, readSize = bb_copyfd_eof(inputFileFd, tbInfo->tarFd); /* Pad the file up to the tar block size */ - for (; (readSize % TAR_BLOCK_SIZE) != 0; readSize++) { + for (; (readSize % TAR_BLOCK_SIZE) != 0; readSize++) write(tbInfo->tarFd, "\0", 1); - } + close(inputFileFd); } @@ -456,9 +440,8 @@ static inline int writeTarFile(const int tar_fd, const int verboseFlag, char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; - if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0) { - bb_perror_msg_and_die("Failed to create pipe"); - } + if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0) + bb_perror_msg_and_die("create pipe"); signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ @@ -504,26 +487,23 @@ static inline int writeTarFile(const int tar_fd, const int verboseFlag, close(gzipStatusPipe[0]); tbInfo.tarFd = gzipDataPipe[1]; - } else { - bb_perror_msg_and_die("Failed to vfork gzip process"); - } + } else bb_perror_msg_and_die("vfork gzip"); } tbInfo.excludeList = exclude; /* Read the directory/files and iterate over them one at a time */ while (include) { - if (!recursive_action(include->data, TRUE, dereferenceFlag, FALSE, - writeFileToTarball, writeFileToTarball, - (void *) &tbInfo)) { + if (!recursive_action(include->data, TRUE, dereferenceFlag, + FALSE, writeFileToTarball, writeFileToTarball, &tbInfo)) + { errorFlag = TRUE; } include = include->link; } /* Write two empty blocks to the end of the archive */ - for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++) { + for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++) write(tbInfo.tarFd, "\0", 1); - } /* To be pedantically correct, we would check if the tarball * is smaller than 20 tar blocks, and pad it if it was smaller, @@ -531,19 +511,23 @@ static inline int writeTarFile(const int tar_fd, const int verboseFlag, * so is considered a waste of space */ /* Hang up the tools, close up shop, head home */ - close(tbInfo.tarFd); + if (ENABLE_FEATURE_CLEAN_UP) { + close(tbInfo.tarFd); + freeHardLinkInfo(&tbInfo.hlInfoHead); + } + if (errorFlag) bb_error_msg("Error exit delayed from previous errors"); - freeHardLinkInfo(&tbInfo.hlInfoHead); - - if (gzipPid) { - if (waitpid(gzipPid, NULL, 0) == -1) - printf("Couldnt wait ?"); - } + if (gzipPid && waitpid(gzipPid, NULL, 0)==-1) + bb_error_msg("Couldnt wait"); return !errorFlag; } +#else +int writeTarFile(const int tar_fd, const int verboseFlag, + const unsigned long dereferenceFlag, const llist_t *include, + const llist_t *exclude, const int gzip); #endif /* tar_create */ #ifdef CONFIG_FEATURE_TAR_FROM @@ -555,18 +539,19 @@ static llist_t *append_file_list_to_list(llist_t *list) char *line; llist_t *newlist = NULL; - while(cur) { + while (cur) { src_stream = bb_xfopen(cur->data, "r"); tmp = cur; cur = cur->link; free(tmp); - while((line = bb_get_chomped_line_from_file(src_stream)) != NULL) { - newlist = llist_add_to(newlist, line); - } - fclose(src_stream); + while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) + newlist = llist_add_to(newlist, line); + fclose(src_stream); } return newlist; } +#else +#define append_file_list_to_list(x) 0 #endif #ifdef CONFIG_FEATURE_TAR_COMPRESS @@ -576,7 +561,9 @@ static char get_header_tar_Z(archive_handle_t *archive_handle) archive_handle->seek = seek_by_char; /* do the decompression, and cleanup */ - if ((bb_xread_char(archive_handle->src_fd) != 0x1f) || (bb_xread_char(archive_handle->src_fd) != 0x9d)) { + if (bb_xread_char(archive_handle->src_fd) != 0x1f || + bb_xread_char(archive_handle->src_fd) != 0x9d) + { bb_error_msg_and_die("Invalid magic"); } @@ -587,58 +574,59 @@ static char get_header_tar_Z(archive_handle_t *archive_handle) /* Can only do one file at a time */ return(EXIT_FAILURE); } +#else +#define get_header_tar_Z 0 #endif -#define CTX_TEST (1 << 0) -#define CTX_EXTRACT (1 << 1) -#define TAR_OPT_BASEDIR (1 << 2) -#define TAR_OPT_TARNAME (1 << 3) -#define TAR_OPT_2STDOUT (1 << 4) -#define TAR_OPT_P (1 << 5) -#define TAR_OPT_VERBOSE (1 << 6) -#define TAR_OPT_KEEP_OLD (1 << 7) - +#define CTX_TEST (1 << 0) +#define CTX_EXTRACT (1 << 1) +#define TAR_OPT_BASEDIR (1 << 2) +#define TAR_OPT_TARNAME (1 << 3) +#define TAR_OPT_2STDOUT (1 << 4) +#define TAR_OPT_P (1 << 5) +#define TAR_OPT_VERBOSE (1 << 6) +#define TAR_OPT_KEEP_OLD (1 << 7) + +# define CTX_CREATE (1 << 8) +# define TAR_OPT_DEREFERNCE (1 << 9) #ifdef CONFIG_FEATURE_TAR_CREATE -# define CTX_CREATE (1 << 8) -# define TAR_OPT_DEREFERNCE (1 << 9) -# define TAR_OPT_STR_CREATE "ch" +# define TAR_OPT_STR_CREATE "ch" # define TAR_OPT_FLAG_CREATE 2 #else -# define CTX_CREATE 0 -# define TAR_OPT_STR_CREATE "" +# define TAR_OPT_STR_CREATE "" # define TAR_OPT_FLAG_CREATE 0 #endif +# define TAR_OPT_BZIP2 (1 << (8 + TAR_OPT_FLAG_CREATE)) #ifdef CONFIG_FEATURE_TAR_BZIP2 -# define TAR_OPT_BZIP2 (1 << (8 + TAR_OPT_FLAG_CREATE)) -# define TAR_OPT_STR_BZIP2 "j" -# define TAR_OPT_FLAG_BZIP2 1 +# define TAR_OPT_STR_BZIP2 "j" +# define TAR_OPT_FLAG_BZIP2 1 #else -# define TAR_OPT_STR_BZIP2 "" -# define TAR_OPT_FLAG_BZIP2 0 +# define TAR_OPT_STR_BZIP2 "" +# define TAR_OPT_FLAG_BZIP2 0 #endif -#ifdef CONFIG_FEATURE_TAR_FROM # define TAR_OPT_INCLUDE_FROM (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2)) # define TAR_OPT_EXCLUDE_FROM (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2 + 1)) -# define TAR_OPT_STR_FROM "T:X:" -# define TAR_OPT_FLAG_FROM 2 +#ifdef CONFIG_FEATURE_TAR_FROM +# define TAR_OPT_STR_FROM "T:X:" +# define TAR_OPT_FLAG_FROM 2 #else -# define TAR_OPT_STR_FROM "" -# define TAR_OPT_FLAG_FROM 0 +# define TAR_OPT_STR_FROM "" +# define TAR_OPT_FLAG_FROM 0 #endif +# define TAR_OPT_GZIP (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2 + TAR_OPT_FLAG_FROM)) #ifdef CONFIG_FEATURE_TAR_GZIP -# define TAR_OPT_GZIP (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2 + TAR_OPT_FLAG_FROM)) -# define TAR_OPT_STR_GZIP "z" -# define TAR_OPT_FLAG_GZIP 1 +# define TAR_OPT_STR_GZIP "z" +# define TAR_OPT_FLAG_GZIP 1 #else -# define TAR_OPT_STR_GZIP "" -# define TAR_OPT_FLAG_GZIP 0 +# define TAR_OPT_STR_GZIP "" +# define TAR_OPT_FLAG_GZIP 0 #endif +# define TAR_OPT_UNCOMPRESS (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2 + TAR_OPT_FLAG_FROM + TAR_OPT_FLAG_GZIP)) #ifdef CONFIG_FEATURE_TAR_COMPRESS -# define TAR_OPT_UNCOMPRESS (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2 + TAR_OPT_FLAG_FROM + TAR_OPT_FLAG_GZIP)) # define TAR_OPT_STR_COMPRESS "Z" #else # define TAR_OPT_STR_COMPRESS "" @@ -653,34 +641,36 @@ static const char tar_options[]="txC:f:Opvk" \ #ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS static const struct option tar_long_options[] = { - { "list", 0, NULL, 't' }, - { "extract", 0, NULL, 'x' }, - { "directory", 1, NULL, 'C' }, - { "file", 1, NULL, 'f' }, - { "to-stdout", 0, NULL, 'O' }, + { "list", 0, NULL, 't' }, + { "extract", 0, NULL, 'x' }, + { "directory", 1, NULL, 'C' }, + { "file", 1, NULL, 'f' }, + { "to-stdout", 0, NULL, 'O' }, { "same-permissions", 0, NULL, 'p' }, - { "verbose", 0, NULL, 'v' }, - { "keep-old", 0, NULL, 'k' }, + { "verbose", 0, NULL, 'v' }, + { "keep-old", 0, NULL, 'k' }, # ifdef CONFIG_FEATURE_TAR_CREATE - { "create", 0, NULL, 'c' }, - { "dereference", 0, NULL, 'h' }, + { "create", 0, NULL, 'c' }, + { "dereference", 0, NULL, 'h' }, # endif # ifdef CONFIG_FEATURE_TAR_BZIP2 - { "bzip2", 0, NULL, 'j' }, + { "bzip2", 0, NULL, 'j' }, # endif # ifdef CONFIG_FEATURE_TAR_FROM - { "files-from", 1, NULL, 'T' }, - { "exclude-from", 1, NULL, 'X' }, - { "exclude", 1, NULL, '\n' }, + { "files-from", 1, NULL, 'T' }, + { "exclude-from", 1, NULL, 'X' }, + { "exclude", 1, NULL, '\n' }, # endif # ifdef CONFIG_FEATURE_TAR_GZIP - { "gzip", 0, NULL, 'z' }, + { "gzip", 0, NULL, 'z' }, # endif # ifdef CONFIG_FEATURE_TAR_COMPRESS - { "compress", 0, NULL, 'Z' }, + { "compress", 0, NULL, 'Z' }, # endif { 0, 0, 0, 0 } }; +#else +#define tar_long_options 0 #endif int tar_main(int argc, char **argv) @@ -690,24 +680,18 @@ int tar_main(int argc, char **argv) char *base_dir = NULL; const char *tar_filename = "-"; unsigned long opt; - -#if defined(CONFIG_FEATURE_TAR_FROM) llist_t *excludes = NULL; -#endif /* Initialise default values */ tar_handle = init_handle(); tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL; /* Prepend '-' to the first argument if required */ -#ifdef CONFIG_FEATURE_TAR_CREATE - bb_opt_complementally = "--:-1:X::T::\n::c:t:x:?:c--tx:t--cx:x--ct"; -#else - bb_opt_complementally = "--:-1:X::T::\n::t:x:?:t--x:x--t"; -#endif -#ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS - bb_applet_long_options = tar_long_options; -#endif + bb_opt_complementally = ENABLE_FEATURE_TAR_CREATE ? + "--:-1:X::T::\n::c:t:x:?:c--tx:t--cx:x--ct" : + "--:-1:X::T::\n::t:x:?:t--x:x--t"; + if (ENABLE_FEATURE_TAR_LONG_OPTIONS) + bb_applet_long_options = tar_long_options; opt = bb_getopt_ulflags(argc, argv, tar_options, &base_dir, /* Change to dir <optarg> */ &tar_filename /* archive filename */ @@ -717,62 +701,52 @@ int tar_main(int argc, char **argv) &excludes #endif ); - - if(opt & CTX_TEST) { + + if (opt & CTX_TEST) { if ((tar_handle->action_header == header_list) || - (tar_handle->action_header == header_verbose_list)) { - tar_handle->action_header = header_verbose_list; - } else { - tar_handle->action_header = header_list; - } - } - if(opt & CTX_EXTRACT) { - if (tar_handle->action_data != data_extract_to_stdout) - tar_handle->action_data = data_extract_all; + (tar_handle->action_header == header_verbose_list)) + { + tar_handle->action_header = header_verbose_list; + } else tar_handle->action_header = header_list; } - if(opt & TAR_OPT_2STDOUT) { - /* To stdout */ + if((opt & CTX_EXTRACT) && tar_handle->action_data != data_extract_to_stdout) + tar_handle->action_data = data_extract_all; + + if (opt & TAR_OPT_2STDOUT) tar_handle->action_data = data_extract_to_stdout; - } - if(opt & TAR_OPT_VERBOSE) { + + if (opt & TAR_OPT_VERBOSE) { if ((tar_handle->action_header == header_list) || (tar_handle->action_header == header_verbose_list)) { tar_handle->action_header = header_verbose_list; - } else { + } else tar_handle->action_header = header_list; - } } - if (opt & TAR_OPT_KEEP_OLD) { + if (opt & TAR_OPT_KEEP_OLD) tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL; - } -#ifdef CONFIG_FEATURE_TAR_GZIP - if(opt & TAR_OPT_GZIP) { + + if (ENABLE_FEATURE_TAR_GZIP && (opt & TAR_OPT_GZIP)) get_header_ptr = get_header_tar_gz; - } -#endif -#ifdef CONFIG_FEATURE_TAR_BZIP2 - if(opt & TAR_OPT_BZIP2) { + + if (ENABLE_FEATURE_TAR_BZIP2 && (opt & TAR_OPT_BZIP2)) get_header_ptr = get_header_tar_bz2; - } -#endif -#ifdef CONFIG_FEATURE_TAR_COMPRESS - if(opt & TAR_OPT_UNCOMPRESS) { + + if (ENABLE_FEATURE_TAR_COMPRESS && (opt & TAR_OPT_UNCOMPRESS)) get_header_ptr = get_header_tar_Z; + + if (ENABLE_FEATURE_TAR_FROM) { + tar_handle->reject = append_file_list_to_list(tar_handle->reject); + /* Append excludes to reject */ + while (excludes) { + llist_t *temp = excludes->link; + excludes->link = tar_handle->reject; + tar_handle->reject = excludes; + excludes = temp; + } + tar_handle->accept = append_file_list_to_list(tar_handle->accept); } -#endif -#ifdef CONFIG_FEATURE_TAR_FROM - tar_handle->reject = append_file_list_to_list(tar_handle->reject); - /* Append excludes to reject */ - while(excludes) { - llist_t *temp = excludes->link; - excludes->link = tar_handle->reject; - tar_handle->reject = excludes; - excludes = temp; - } - tar_handle->accept = append_file_list_to_list(tar_handle->accept); -#endif /* Check if we are reading from stdin */ if (argv[optind] && *argv[optind] == '-') { @@ -784,34 +758,30 @@ int tar_main(int argc, char **argv) /* TODO: This is the same as in ar, separate function ? */ while (optind < argc) { char *filename_ptr = last_char_is(argv[optind], '/'); - if (filename_ptr > argv[optind]) { + if (filename_ptr > argv[optind]) *filename_ptr = '\0'; - } + tar_handle->accept = llist_add_to(tar_handle->accept, argv[optind]); optind++; } - if ((tar_handle->accept) || (tar_handle->reject)) { + if ((tar_handle->accept) || (tar_handle->reject)) tar_handle->filter = filter_accept_reject_list; - } /* Open the tar file */ { FILE *tar_stream; int flags; -#ifdef CONFIG_FEATURE_TAR_CREATE - if (opt & CTX_CREATE) { + if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) { /* Make sure there is at least one file to tar up. */ - if (tar_handle->accept == NULL) { - bb_error_msg_and_die("Cowardly refusing to create an empty archive"); - } + if (tar_handle->accept == NULL) + bb_error_msg_and_die("empty archive"); + tar_stream = stdout; flags = O_WRONLY | O_CREAT | O_EXCL; unlink(tar_filename); - } else -#endif - { + } else { tar_stream = stdin; flags = O_RDONLY; } @@ -824,54 +794,42 @@ int tar_main(int argc, char **argv) } } - if ((base_dir) && (chdir(base_dir))) { + if ((base_dir) && (chdir(base_dir))) bb_perror_msg_and_die("Couldnt chdir to %s", base_dir); - } -#ifdef CONFIG_FEATURE_TAR_CREATE /* create an archive */ - if (opt & CTX_CREATE) { + if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) { int verboseFlag = FALSE; int zipMode = 0; -# ifdef CONFIG_FEATURE_TAR_GZIP - if (get_header_ptr == get_header_tar_gz) { - zipMode = 1; - } -# endif /* CONFIG_FEATURE_TAR_GZIP */ -# ifdef CONFIG_FEATURE_TAR_BZIP2 - if (get_header_ptr == get_header_tar_bz2) { - zipMode = 2; - } -# endif /* CONFIG_FEATURE_TAR_BZIP2 */ + if (ENABLE_FEATURE_TAR_GZIP && get_header_ptr == get_header_tar_gz) + zipMode = 1; + if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2) + zipMode = 2; if ((tar_handle->action_header == header_list) || - (tar_handle->action_header == header_verbose_list)) { + (tar_handle->action_header == header_verbose_list)) + { verboseFlag = TRUE; } writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERNCE, tar_handle->accept, tar_handle->reject, zipMode); - } else -#endif /* CONFIG_FEATURE_TAR_CREATE */ - { + } else { while (get_header_ptr(tar_handle) == EXIT_SUCCESS); - /* Ckeck that every file that should have been extracted was */ + /* Check that every file that should have been extracted was */ while (tar_handle->accept) { - if (find_list_entry(tar_handle->reject, tar_handle->accept->data) == NULL) { - if (find_list_entry(tar_handle->passed, tar_handle->accept->data) == NULL) { - bb_error_msg_and_die("%s: Not found in archive", tar_handle->accept->data); - } + if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) + && !find_list_entry(tar_handle->passed, tar_handle->accept->data)) + { + bb_error_msg_and_die("%s: Not found in archive", tar_handle->accept->data); } tar_handle->accept = tar_handle->accept->link; } } -#ifdef CONFIG_FEATURE_CLEAN_UP - if (tar_handle->src_fd != STDIN_FILENO) { + if (ENABLE_FEATURE_CLEAN_UP && tar_handle->src_fd != STDIN_FILENO) close(tar_handle->src_fd); - } -#endif /* CONFIG_FEATURE_CLEAN_UP */ return(EXIT_SUCCESS); } |