1303 files changed, 32187 insertions, 57138 deletions
diff --git a/archival/tar.c b/archival/tar.c index cdc6067..8e315c6 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -146,25 +146,23 @@ #include <fnmatch.h> #include "libbb.h" +#include "common_bufsiz.h" #include "bb_archive.h" /* FIXME: Stop using this non-standard feature */ #ifndef FNM_LEADING_DIR # define FNM_LEADING_DIR 0 #endif - -//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) -#define DBG(...) ((void)0) +#if 0 +# define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) +#else +# define DBG(...) ((void)0) +#endif +#define DBG_OPTION_PARSING 0 #define block_buf bb_common_bufsiz1 - - -#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2 -/* Do not pass gzip flag to writeTarFile() */ -#define writeTarFile(tar_fd, verboseFlag, optFlags, recurseFlags, include, exclude, gzip) \ - writeTarFile(tar_fd, verboseFlag, optFlags, recurseFlags, include, exclude) -#endif +#define INIT_G() do { setup_common_bufsiz(); } while (0) #if ENABLE_FEATURE_TAR_CREATE @@ -187,8 +185,6 @@ typedef struct TarBallInfo { int tarFd; /* Open-for-write file descriptor * for the tarball */ int verboseFlag; /* Whether to print extra stuff or not */ - unsigned optFlags; /* all command line flags */ - 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 */ @@ -212,7 +208,6 @@ enum { CONTTYPE = '7', /* reserved */ GNULONGLINK = 'K', /* GNU long (>100 chars) link name */ GNULONGNAME = 'L', /* GNU long (>100 chars) file name */ - EXTTYPE = 'x', /* ext metadata for next file, store selinux_context */ }; /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ @@ -354,34 +349,6 @@ static void writeLongname(int fd, int type, const char *name, int dir) } #endif -#if ENABLE_FEATURE_TAR_SELINUX -# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" -/* Write 2 blocks : extended file header + selinux context */ -static int writeSeHeader(int fd, const char *con, struct tar_header_t *header) -{ - char block[TAR_BLOCK_SIZE]; - struct tar_header_t hd; - - int sz = sizeof(SELINUX_CONTEXT_KEYWORD) + 4 + strlen(con); - if (sz >= 100) sz++; /* another ascii digit for size */ - if (sz > TAR_BLOCK_SIZE) - return FALSE; - - memset(&block, 0, TAR_BLOCK_SIZE); - sprintf(block, "%d %s=%s\n", sz, SELINUX_CONTEXT_KEYWORD, con); - - /* write duplicated file entry */ - memcpy(&hd, header, sizeof(hd)); - hd.typeflag = EXTTYPE; - PUT_OCTAL(hd.size, sz); - chksum_and_xwrite(fd, &hd); - - /* write selinux context */ - xwrite(fd, &block, TAR_BLOCK_SIZE); - return TRUE; -} -#endif - /* Write out a tar header for the specified file/directory/whatever */ static int writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name, const char *fileName, struct stat *statbuf) @@ -397,7 +364,8 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, PUT_OCTAL(header.uid, statbuf->st_uid); PUT_OCTAL(header.gid, statbuf->st_gid); memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */ - PUT_OCTAL(header.mtime, statbuf->st_mtime); + /* users report that files with negative st_mtime cause trouble, so: */ + PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0); /* Enter the user and group names */ safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname)); @@ -481,7 +449,7 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, *p8 |= 0x80; } else { bb_error_msg_and_die("can't store file '%s' " - "of size %"FILESIZE_FMT"u, aborting", + "of size %"OFF_FMT"u, aborting", fileName, statbuf->st_size); } header.typeflag = REGTYPE; @@ -498,18 +466,6 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, header_name, S_ISDIR(statbuf->st_mode)); #endif -#if ENABLE_FEATURE_TAR_SELINUX - if (is_selinux_enabled() && (tbInfo->optFlags & ARCHIVE_STORE_SELINUX)) { - security_context_t sid; - lgetfilecon(fileName, &sid); - if (sid) { - // optional extended block - writeSeHeader(tbInfo->tarFd, sid, &header); - freecon(sid); - } - } -#endif - /* Now write the header out to disk */ chksum_and_xwrite(tbInfo->tarFd, &header); @@ -663,21 +619,12 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb return TRUE; } -#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 -# if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2) -# define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd) -# endif +#if SEAMLESS_COMPRESSION /* Don't inline: vfork scares gcc and pessimizes code */ -static void NOINLINE vfork_compressor(int tar_fd, int gzip) +static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) { pid_t gzipPid; -# if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2 - const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; -# elif ENABLE_FEATURE_SEAMLESS_GZ - const char *zip_exec = "gzip"; -# else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */ - const char *zip_exec = "bzip2"; -# endif + // On Linux, vfork never unpauses parent early, although standard // allows for that. Do we want to waste bytes checking for it? # define WAIT_FOR_CHILD 0 @@ -691,11 +638,6 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ -# if defined(__GNUC__) && __GNUC__ - /* Avoid vfork clobbering */ - (void) &zip_exec; -# endif - gzipPid = xvfork(); if (gzipPid == 0) { @@ -711,7 +653,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) xmove_fd(gzipDataPipe.rd, 0); xmove_fd(tar_fd, 1); /* exec gzip/bzip2 program/applet */ - BB_EXECLP(zip_exec, zip_exec, "-f", (char *)0); + BB_EXECLP(gzip, gzip, "-f", (char *)0); vfork_exec_errno = errno; _exit(EXIT_FAILURE); } @@ -734,17 +676,21 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) # endif if (vfork_exec_errno) { errno = vfork_exec_errno; - bb_perror_msg_and_die("can't execute '%s'", zip_exec); + bb_perror_msg_and_die("can't execute '%s'", gzip); } } -#endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */ +#endif /* SEAMLESS_COMPRESSION */ +#if !SEAMLESS_COMPRESSION +/* Do not pass gzip flag to writeTarFile() */ +#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \ + writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude) +#endif /* gcc 4.2.1 inlines it, making code bigger */ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, - unsigned optFlags, int recurseFlags, const llist_t *include, - const llist_t *exclude, int gzip) + const llist_t *exclude, const char *gzip) { int errorFlag = FALSE; struct TarBallInfo tbInfo; @@ -752,13 +698,12 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, tbInfo.hlInfoHead = NULL; tbInfo.tarFd = tar_fd; tbInfo.verboseFlag = verboseFlag; - tbInfo.optFlags = optFlags; /* Store the stat info for the tarball's file, so * can avoid including the tarball into itself.... */ xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file"); -#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 +#if SEAMLESS_COMPRESSION if (gzip) vfork_compressor(tbInfo.tarFd, gzip); #endif @@ -793,7 +738,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, if (errorFlag) bb_error_msg("error exit delayed from previous errors"); -#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 +#if SEAMLESS_COMPRESSION if (gzip) { int status; if (safe_waitpid(-1, &status, 0) == -1) @@ -805,12 +750,9 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, #endif return errorFlag; } -#else -int writeTarFile(int tar_fd, int verboseFlag, - unsigned optFlags, - int recurseFlags, const llist_t *include, - const llist_t *exclude, int gzip); -#endif /* FEATURE_TAR_CREATE */ +#else /* !FEATURE_TAR_CREATE */ +# define writeTarFile(...) 0 +#endif #if ENABLE_FEATURE_TAR_FROM static llist_t *append_file_list_to_list(llist_t *list) @@ -843,7 +785,6 @@ static llist_t *append_file_list_to_list(llist_t *list) //usage: IF_FEATURE_SEAMLESS_LZMA("a") //usage: IF_FEATURE_TAR_CREATE("h") //usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") -//usage: IF_FEATURE_TAR_SELINUX("p") //usage: "vO] " //usage: IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ") //usage: "[-f TARFILE] [-C DIR] [FILE]..." @@ -889,9 +830,6 @@ static llist_t *append_file_list_to_list(llist_t *list) //usage: "\n X File with names to exclude" //usage: "\n T File with names to include" //usage: ) -//usage: IF_FEATURE_TAR_SELINUX( -//usage: "\n p Store SELinux contexts" -//usage: ) //usage: //usage:#define tar_example_usage //usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" @@ -922,6 +860,7 @@ enum { IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) #if ENABLE_FEATURE_TAR_LONG_OPTIONS + OPTBIT_STRIP_COMPONENTS, OPTBIT_NORECURSION, IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,) OPTBIT_NUMERIC_OWNER, @@ -946,12 +885,13 @@ enum { OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z OPT_XZ = IF_FEATURE_SEAMLESS_XZ( (1 << OPTBIT_XZ )) + 0, // J OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z - OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m - OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0, // no-recursion - OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command - OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner - OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions - OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite + OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m + OPT_STRIP_COMPONENTS = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_STRIP_COMPONENTS)) + 0, // strip-components + OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0, // no-recursion + OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command + OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner + OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions + OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS), }; @@ -995,6 +935,7 @@ static const char tar_longopts[] ALIGN1 = # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME "touch\0" No_argument "m" # endif + "strip-components\0" Required_argument "\xf9" "no-recursion\0" No_argument "\xfa" # if ENABLE_FEATURE_TAR_TO_COMMAND "to-command\0" Required_argument "\xfb" @@ -1024,6 +965,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM llist_t *excludes = NULL; #endif + INIT_G(); /* Initialise default values */ tar_handle = init_handle(); @@ -1038,17 +980,29 @@ int tar_main(int argc UNUSED_PARAM, char **argv) /* Prepend '-' to the first argument if required */ opt_complementary = "--:" // first arg is options "tt:vv:" // count -t,-v - IF_FEATURE_TAR_FROM("X::T::") // cumulative lists #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM - "\xff::" // cumulative lists for --exclude + "\xff::" // --exclude=PATTERN is a list #endif IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive - IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive + IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + ":\xf9+" // --strip-components=NUM +#endif + ; #if ENABLE_FEATURE_TAR_LONG_OPTIONS applet_long_options = tar_longopts; #endif #if ENABLE_DESKTOP + /* Lie to buildroot when it starts asking stupid questions. */ + if (argv[1] && strcmp(argv[1], "--version") == 0) { + // Output of 'tar --version' examples: + // tar (GNU tar) 1.15.1 + // tar (GNU tar) 1.25 + // bsdtar 2.8.3 - libarchive 2.8.3 + puts("tar (busybox) " BB_VER); + return 0; + } if (argv[1] && argv[1][0] != '-') { /* Compat: * 1st argument without dash handles options with parameters @@ -1077,18 +1031,22 @@ int tar_main(int argc UNUSED_PARAM, char **argv) #endif opt = getopt32(argv, "txC:f:Oopvk" - IF_FEATURE_TAR_CREATE( "ch" ) - IF_FEATURE_SEAMLESS_BZ2( "j" ) - IF_FEATURE_SEAMLESS_LZMA("a" ) - IF_FEATURE_TAR_FROM( "T:X:") - IF_FEATURE_SEAMLESS_GZ( "z" ) - IF_FEATURE_SEAMLESS_XZ( "J" ) - IF_FEATURE_SEAMLESS_Z( "Z" ) + IF_FEATURE_TAR_CREATE( "ch" ) + IF_FEATURE_SEAMLESS_BZ2( "j" ) + IF_FEATURE_SEAMLESS_LZMA("a" ) + IF_FEATURE_TAR_FROM( "T:*X:*") + IF_FEATURE_SEAMLESS_GZ( "z" ) + IF_FEATURE_SEAMLESS_XZ( "J" ) + IF_FEATURE_SEAMLESS_Z( "Z" ) IF_FEATURE_TAR_NOPRESERVE_TIME("m") + IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components , &base_dir // -C dir , &tar_filename // -f filename IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + , &tar_handle->tar__strip_components // --strip-components +#endif IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM , &excludes // --exclude @@ -1096,11 +1054,49 @@ int tar_main(int argc UNUSED_PARAM, char **argv) , &verboseFlag // combined count for -t and -v , &verboseFlag // combined count for -t and -v ); - //bb_error_msg("opt:%08x", opt); +#if DBG_OPTION_PARSING + bb_error_msg("opt: 0x%08x", opt); +# define showopt(o) bb_error_msg("opt & %s(%x): %x", #o, o, opt & o); + showopt(OPT_TEST ); + showopt(OPT_EXTRACT ); + showopt(OPT_BASEDIR ); + showopt(OPT_TARNAME ); + showopt(OPT_2STDOUT ); + showopt(OPT_NOPRESERVE_OWNER); + showopt(OPT_P ); + showopt(OPT_VERBOSE ); + showopt(OPT_KEEP_OLD ); + showopt(OPT_CREATE ); + showopt(OPT_DEREFERENCE ); + showopt(OPT_BZIP2 ); + showopt(OPT_LZMA ); + showopt(OPT_INCLUDE_FROM ); + showopt(OPT_EXCLUDE_FROM ); + showopt(OPT_GZIP ); + showopt(OPT_XZ ); + showopt(OPT_COMPRESS ); + showopt(OPT_NOPRESERVE_TIME ); + showopt(OPT_STRIP_COMPONENTS); + showopt(OPT_NORECURSION ); + showopt(OPT_2COMMAND ); + showopt(OPT_NUMERIC_OWNER ); + showopt(OPT_NOPRESERVE_PERM ); + showopt(OPT_OVERWRITE ); + showopt(OPT_ANY_COMPRESS ); + bb_error_msg("base_dir:'%s'", base_dir); + bb_error_msg("tar_filename:'%s'", tar_filename); + bb_error_msg("verboseFlag:%d", verboseFlag); + bb_error_msg("tar_handle->tar__to_command:'%s'", tar_handle->tar__to_command); + bb_error_msg("tar_handle->tar__strip_components:%u", tar_handle->tar__strip_components); + return 0; +# undef showopt +#endif argv += optind; - if (verboseFlag) tar_handle->action_header = header_verbose_list; - if (verboseFlag == 1) tar_handle->action_header = header_list; + if (verboseFlag) + tar_handle->action_header = header_verbose_list; + if (verboseFlag == 1) + tar_handle->action_header = header_list; if (opt & OPT_EXTRACT) tar_handle->action_data = data_extract_all; @@ -1127,11 +1123,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_NOPRESERVE_PERM) tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; -#if ENABLE_FEATURE_TAR_SELINUX - if (opt & OPT_P) - tar_handle->ah_flags |= ARCHIVE_STORE_SELINUX; -#endif - if (opt & OPT_OVERWRITE) { tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD; tar_handle->ah_flags |= ARCHIVE_O_TRUNC; @@ -1203,30 +1194,37 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (base_dir) xchdir(base_dir); - //if (SEAMLESS_COMPRESSION || OPT_COMPRESS) + //if (SEAMLESS_COMPRESSION) // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ // signal(SIGCHLD, check_errors_in_children); +#if ENABLE_FEATURE_TAR_CREATE /* Create an archive */ if (opt & OPT_CREATE) { -#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 - int zipMode = 0; - if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP)) - zipMode = 1; - if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2)) - zipMode = 2; -#endif +# if SEAMLESS_COMPRESSION + const char *zipMode = NULL; + if (opt & OPT_COMPRESS) + zipMode = "compress"; + if (opt & OPT_GZIP) + zipMode = "gzip"; + if (opt & OPT_BZIP2) + zipMode = "bzip2"; + if (opt & OPT_LZMA) + zipMode = "lzma"; + if (opt & OPT_XZ) + zipMode = "xz"; +# endif /* NB: writeTarFile() closes tar_handle->src_fd */ return writeTarFile(tar_handle->src_fd, verboseFlag, - tar_handle->ah_flags, (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0) | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE), tar_handle->accept, tar_handle->reject, zipMode); } +#endif if (opt & OPT_ANY_COMPRESS) { - USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);) USE_FOR_NOMMU(const char *xformer_prog;) if (opt & OPT_COMPRESS) @@ -1245,7 +1243,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) USE_FOR_MMU(xformer = unpack_xz_stream;) USE_FOR_NOMMU(xformer_prog = "unxz";) - open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog); + fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog); /* Can't lseek over pipes */ tar_handle->seek = seek_by_read; /*tar_handle->offset = 0; - already is */ |