X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=archival%2Fcpio.c;h=3b15507200e770176bf2212951ee092189ebb528;hb=47cfbf32fd66563f8c4e09ad6cced6abfbe2fad5;hp=e0ca7fa5cf29164b06a82b0fbdc87512379bff7c;hpb=ff0e875e02487b61dcc520b295feb6477b859065;p=oweals%2Fbusybox.git diff --git a/archival/cpio.c b/archival/cpio.c index e0ca7fa5c..3b1550720 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -4,15 +4,78 @@ * * Copyright (C) 2001 by Glenn McGrath * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Limitations: * Doesn't check CRC's * Only supports new ASCII and CRC formats - * */ #include "libbb.h" -#include "unarchive.h" +#include "common_bufsiz.h" +#include "bb_archive.h" + +//config:config CPIO +//config: bool "cpio" +//config: default y +//config: help +//config: cpio is an archival utility program used to create, modify, and +//config: extract contents from archives. +//config: cpio has 110 bytes of overheads for every stored file. +//config: +//config: This implementation of cpio can extract cpio archives created in the +//config: "newc" or "crc" format, it cannot create or modify them. +//config: +//config: Unless you have a specific application which requires cpio, you +//config: should probably say N here. +//config: +//config:config FEATURE_CPIO_O +//config: bool "Support for archive creation" +//config: default y +//config: depends on CPIO +//config: help +//config: This implementation of cpio can create cpio archives in the "newc" +//config: format only. +//config: +//config:config FEATURE_CPIO_P +//config: bool "Support for passthrough mode" +//config: default y +//config: depends on FEATURE_CPIO_O +//config: help +//config: Passthrough mode. Rarely used. + +//applet:IF_CPIO(APPLET(cpio, BB_DIR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_CPIO) += cpio.o + +//usage:#define cpio_trivial_usage +//usage: "[-dmvu] [-F FILE] [-R USER[:GRP]]" IF_FEATURE_CPIO_O(" [-H newc]") +//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") +//usage: " [EXTR_FILE]..." +//usage:#define cpio_full_usage "\n\n" +//usage: "Extract or list files from a cpio archive" +//usage: IF_FEATURE_CPIO_O(", or" +//usage: "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") +//usage: " using file list on stdin" +//usage: ) +//usage: "\n" +//usage: "\nMain operation mode:" +//usage: "\n -t List" +//usage: "\n -i Extract EXTR_FILEs (or all)" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -o Create (requires -H newc)" +//usage: ) +//usage: IF_FEATURE_CPIO_P( +//usage: "\n -p DIR Copy files to DIR" +//usage: ) +//usage: "\nOptions:" +//usage: "\n -d Make leading directories" +//usage: "\n -m Preserve mtime" +//usage: "\n -v Verbose" +//usage: "\n -u Overwrite" +//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file" +//usage: "\n -R USER[:GRP] Set owner of created files" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -H newc Archive format" +//usage: ) /* GNU cpio 2.9 --help (abridged): @@ -20,7 +83,7 @@ -t, --list List the archive -i, --extract Extract files from an archive -o, --create Create the archive - -p, --pass-through Copy-pass mode [was ist das?!] + -p, --pass-through Copy-pass mode Options valid in any mode: --block-size=SIZE I/O block size = SIZE * 512 bytes @@ -69,7 +132,7 @@ -I FILE File to use instead of standard input -L, --dereference Dereference symbolic links (copy the files that they point to instead of copying the links) - -R, --owner=[USER][:.][GROUP] Set owner of created files + -R, --owner=[USER][:.][GRP] Set owner of created files Options valid in --extract and --pass-through modes: -d, --make-directories Create leading directories where needed @@ -78,30 +141,43 @@ --sparse Write files with blocks of zeros as sparse files -u, --unconditional Replace all files unconditionally */ + enum { - CPIO_OPT_EXTRACT = (1 << 0), - CPIO_OPT_TEST = (1 << 1), - CPIO_OPT_NUL_TERMINATED = (1 << 2), - CPIO_OPT_UNCONDITIONAL = (1 << 3), - CPIO_OPT_VERBOSE = (1 << 4), - CPIO_OPT_CREATE_LEADING_DIR = (1 << 5), - CPIO_OPT_PRESERVE_MTIME = (1 << 6), - CPIO_OPT_DEREF = (1 << 7), - CPIO_OPT_FILE = (1 << 8), - OPTBIT_FILE = 8, + OPT_EXTRACT = (1 << 0), + OPT_TEST = (1 << 1), + OPT_NUL_TERMINATED = (1 << 2), + OPT_UNCONDITIONAL = (1 << 3), + OPT_VERBOSE = (1 << 4), + OPT_CREATE_LEADING_DIR = (1 << 5), + OPT_PRESERVE_MTIME = (1 << 6), + OPT_DEREF = (1 << 7), + OPT_FILE = (1 << 8), + OPT_OWNER = (1 << 9), + OPTBIT_OWNER = 9, IF_FEATURE_CPIO_O(OPTBIT_CREATE ,) IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,) IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,) IF_LONG_OPTS( OPTBIT_QUIET ,) IF_LONG_OPTS( OPTBIT_2STDOUT ,) - CPIO_OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, - CPIO_OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, - CPIO_OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, - CPIO_OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, - CPIO_OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, + OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, + OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, + OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, + OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, + OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, }; -#define OPTION_STR "it0uvdmLF:" +#define OPTION_STR "it0uvdmLF:R:" + +struct globals { + struct bb_uidgid_t owner_ugid; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +void BUG_cpio_globals_too_big(void); +#define INIT_G() do { \ + setup_common_bufsiz(); \ + G.owner_ugid.uid = -1L; \ + G.owner_ugid.gid = -1L; \ +} while (0) #if ENABLE_FEATURE_CPIO_O static off_t cpio_pad4(off_t size) @@ -119,7 +195,6 @@ static off_t cpio_pad4(off_t size) * It's ok to exit instead of return. */ static NOINLINE int cpio_o(void) { - static const char trailer[] ALIGN1 = "TRAILER!!!"; struct name_s { struct name_s *next; char name[1]; @@ -138,7 +213,7 @@ static NOINLINE int cpio_o(void) char *line; struct stat st; - line = (option_mask32 & CPIO_OPT_NUL_TERMINATED) + line = (option_mask32 & OPT_NUL_TERMINATED) ? bb_get_chunk_from_file(stdin, NULL) : xmalloc_fgetline(stdin); @@ -153,7 +228,7 @@ static NOINLINE int cpio_o(void) free(line); continue; } - if ((option_mask32 & CPIO_OPT_DEREF) + if ((option_mask32 & OPT_DEREF) ? stat(name, &st) : lstat(name, &st) ) { @@ -161,6 +236,11 @@ static NOINLINE int cpio_o(void) bb_simple_perror_msg_and_die(name); } + if (G.owner_ugid.uid != (uid_t)-1L) + st.st_uid = G.owner_ugid.uid; + if (G.owner_ugid.gid != (gid_t)-1L) + st.st_gid = G.owner_ugid.gid; + if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode))) st.st_size = 0; /* paranoia */ @@ -195,7 +275,6 @@ static NOINLINE int cpio_o(void) free(line); continue; } - } else { /* line == NULL: EOF */ next_link: if (links) { @@ -214,7 +293,7 @@ static NOINLINE int cpio_o(void) } else { /* If no (more) hardlinks to output, * output "trailer" entry */ - name = trailer; + name = cpio_TRAILER; /* st.st_size == 0 is a must, but for uniformity * in the output, we zero out everything */ memset(&st, 0, sizeof(st)); @@ -223,24 +302,24 @@ static NOINLINE int cpio_o(void) } bytes += printf("070701" - "%08X%08X%08X%08X%08X%08X%08X" - "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ + "%08X%08X%08X%08X%08X%08X%08X" + "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ /* strlen+1: */ "%08X" /* chksum: */ "00000000" /* (only for "070702" files) */ /* name,NUL: */ "%s%c", - (unsigned)(uint32_t) st.st_ino, - (unsigned)(uint32_t) st.st_mode, - (unsigned)(uint32_t) st.st_uid, - (unsigned)(uint32_t) st.st_gid, - (unsigned)(uint32_t) st.st_nlink, - (unsigned)(uint32_t) st.st_mtime, - (unsigned)(uint32_t) st.st_size, - (unsigned)(uint32_t) major(st.st_dev), - (unsigned)(uint32_t) minor(st.st_dev), - (unsigned)(uint32_t) major(st.st_rdev), - (unsigned)(uint32_t) minor(st.st_rdev), - (unsigned)(strlen(name) + 1), - name, '\0'); + (unsigned)(uint32_t) st.st_ino, + (unsigned)(uint32_t) st.st_mode, + (unsigned)(uint32_t) st.st_uid, + (unsigned)(uint32_t) st.st_gid, + (unsigned)(uint32_t) st.st_nlink, + (unsigned)(uint32_t) st.st_mtime, + (unsigned)(uint32_t) st.st_size, + (unsigned)(uint32_t) major(st.st_dev), + (unsigned)(uint32_t) minor(st.st_dev), + (unsigned)(uint32_t) major(st.st_rdev), + (unsigned)(uint32_t) minor(st.st_rdev), + (unsigned)(strlen(name) + 1), + name, '\0'); bytes = cpio_pad4(bytes); if (st.st_size) { @@ -262,7 +341,7 @@ static NOINLINE int cpio_o(void) } if (!line) { - if (name != trailer) + if (name != cpio_TRAILER) goto next_link; /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */ return EXIT_SUCCESS; @@ -278,6 +357,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) { archive_handle_t *archive_handle; char *cpio_filename; + char *cpio_owner; IF_FEATURE_CPIO_O(const char *cpio_fmt = "";) unsigned opt; @@ -292,12 +372,14 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) "pass-through\0" No_argument "p" #endif #endif + "owner\0" Required_argument "R" "verbose\0" No_argument "v" "quiet\0" No_argument "\xff" "to-stdout\0" No_argument "\xfe" ; #endif + INIT_G(); archive_handle = init_handle(); /* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */ archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER; @@ -308,28 +390,31 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) /* -L makes sense only with -o or -p */ #if !ENABLE_FEATURE_CPIO_O - /* no parameters */ - opt_complementary = "=0"; - opt = getopt32(argv, OPTION_STR, &cpio_filename); + opt = getopt32(argv, OPTION_STR, &cpio_filename, &cpio_owner); +#else + opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), + &cpio_filename, &cpio_owner, &cpio_fmt); +#endif argv += optind; - if (opt & CPIO_OPT_FILE) { /* -F */ + if (opt & OPT_OWNER) { /* -R */ + parse_chown_usergroup_or_die(&G.owner_ugid, cpio_owner); + archive_handle->cpio__owner = G.owner_ugid; + } +#if !ENABLE_FEATURE_CPIO_O + if (opt & OPT_FILE) { /* -F */ xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); } #else - /* _exactly_ one parameter for -p, thus <= 1 param if -p is allowed */ - opt_complementary = ENABLE_FEATURE_CPIO_P ? "?1" : "=0"; - opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt); - argv += optind; - if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */ + if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */ xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); } - if (opt & CPIO_OPT_PASSTHROUGH) { + if (opt & OPT_PASSTHROUGH) { pid_t pid; struct fd_pair pp; if (argv[0] == NULL) bb_show_usage(); - if (opt & CPIO_OPT_CREATE_LEADING_DIR) + if (opt & OPT_CREATE_LEADING_DIR) mkdir(argv[0], 0777); /* Crude existence check: * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); @@ -358,19 +443,20 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) goto dump; } /* parent */ + USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */ xchdir(*argv++); close(pp.wr); xmove_fd(pp.rd, STDIN_FILENO); - //opt &= ~CPIO_OPT_PASSTHROUGH; - opt |= CPIO_OPT_EXTRACT; + //opt &= ~OPT_PASSTHROUGH; + opt |= OPT_EXTRACT; goto skip; } /* -o */ - if (opt & CPIO_OPT_CREATE) { + if (opt & OPT_CREATE) { if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */ bb_show_usage(); - if (opt & CPIO_OPT_FILE) { - xmove_fd(xopen3(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666), STDOUT_FILENO); + if (opt & OPT_FILE) { + xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); } dump: return cpio_o(); @@ -379,35 +465,35 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) #endif /* One of either extract or test options must be given */ - if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { + if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) { bb_show_usage(); } - if (opt & CPIO_OPT_TEST) { + if (opt & OPT_TEST) { /* if both extract and test options are given, ignore extract option */ - opt &= ~CPIO_OPT_EXTRACT; + opt &= ~OPT_EXTRACT; archive_handle->action_header = header_list; } - if (opt & CPIO_OPT_EXTRACT) { + if (opt & OPT_EXTRACT) { archive_handle->action_data = data_extract_all; - if (opt & CPIO_OPT_2STDOUT) + if (opt & OPT_2STDOUT) archive_handle->action_data = data_extract_to_stdout; } - if (opt & CPIO_OPT_UNCONDITIONAL) { + if (opt & OPT_UNCONDITIONAL) { archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD; archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER; } - if (opt & CPIO_OPT_VERBOSE) { + if (opt & OPT_VERBOSE) { if (archive_handle->action_header == header_list) { archive_handle->action_header = header_verbose_list; } else { archive_handle->action_header = header_list; } } - if (opt & CPIO_OPT_CREATE_LEADING_DIR) { + if (opt & OPT_CREATE_LEADING_DIR) { archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS; } - if (opt & CPIO_OPT_PRESERVE_MTIME) { + if (opt & OPT_PRESERVE_MTIME) { archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; } @@ -423,7 +509,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) continue; if (archive_handle->cpio__blocks != (off_t)-1 - && !(opt & CPIO_OPT_QUIET) + && !(opt & OPT_QUIET) ) { fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); }