Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/archival/cpio.c


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/archival/cpio.c

    r1765 r2725  
    55 * Copyright (C) 2001 by Glenn McGrath
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 *
    99 * Limitations:
    10  *      Doesn't check CRC's
    11  *      Only supports new ASCII and CRC formats
     10 * Doesn't check CRC's
     11 * Only supports new ASCII and CRC formats
    1212 *
    1313 */
    1414#include "libbb.h"
    15 #include "unarchive.h"
    16 
    17 #define CPIO_OPT_EXTRACT                0x01
    18 #define CPIO_OPT_TEST                   0x02
    19 #define CPIO_OPT_UNCONDITIONAL          0x04
    20 #define CPIO_OPT_VERBOSE                0x08
    21 #define CPIO_OPT_FILE                   0x10
    22 #define CPIO_OPT_CREATE_LEADING_DIR     0x20
    23 #define CPIO_OPT_PRESERVE_MTIME         0x40
    24 
    25 int cpio_main(int argc, char **argv);
    26 int cpio_main(int argc, char **argv)
     15#include "archive.h"
     16
     17/* GNU cpio 2.9 --help (abridged):
     18
     19 Modes:
     20  -t, --list                 List the archive
     21  -i, --extract              Extract files from an archive
     22  -o, --create               Create the archive
     23  -p, --pass-through         Copy-pass mode [was ist das?!]
     24
     25 Options valid in any mode:
     26      --block-size=SIZE      I/O block size = SIZE * 512 bytes
     27  -B                         I/O block size = 5120 bytes
     28  -c                         Use the old portable (ASCII) archive format
     29  -C, --io-size=NUMBER       I/O block size in bytes
     30  -f, --nonmatching          Only copy files that do not match given pattern
     31  -F, --file=FILE            Use FILE instead of standard input or output
     32  -H, --format=FORMAT        Use given archive FORMAT
     33  -M, --message=STRING       Print STRING when the end of a volume of the
     34                             backup media is reached
     35  -n, --numeric-uid-gid      If -v, show numeric UID and GID
     36      --quiet                Do not print the number of blocks copied
     37      --rsh-command=COMMAND  Use remote COMMAND instead of rsh
     38  -v, --verbose              Verbosely list the files processed
     39  -V, --dot                  Print a "." for each file processed
     40  -W, --warning=FLAG         Control warning display: 'none','truncate','all';
     41                             multiple options accumulate
     42
     43 Options valid only in --extract mode:
     44  -b, --swap                 Swap both halfwords of words and bytes of
     45                             halfwords in the data (equivalent to -sS)
     46  -r, --rename               Interactively rename files
     47  -s, --swap-bytes           Swap the bytes of each halfword in the files
     48  -S, --swap-halfwords       Swap the halfwords of each word (4 bytes)
     49      --to-stdout            Extract files to standard output
     50  -E, --pattern-file=FILE    Read additional patterns specifying filenames to
     51                             extract or list from FILE
     52      --only-verify-crc      Verify CRC's, don't actually extract the files
     53
     54 Options valid only in --create mode:
     55  -A, --append               Append to an existing archive
     56  -O FILE                    File to use instead of standard output
     57
     58 Options valid only in --pass-through mode:
     59  -l, --link                 Link files instead of copying them, when possible
     60
     61 Options valid in --extract and --create modes:
     62      --absolute-filenames   Do not strip file system prefix components from
     63                             the file names
     64      --no-absolute-filenames Create all files relative to the current dir
     65
     66 Options valid in --create and --pass-through modes:
     67  -0, --null                 A list of filenames is terminated by a NUL
     68  -a, --reset-access-time    Reset the access times of files after reading them
     69  -I FILE                    File to use instead of standard input
     70  -L, --dereference          Dereference symbolic links (copy the files
     71                             that they point to instead of copying the links)
     72  -R, --owner=[USER][:.][GROUP] Set owner of created files
     73
     74 Options valid in --extract and --pass-through modes:
     75  -d, --make-directories     Create leading directories where needed
     76  -m, --preserve-modification-time  Retain mtime when creating files
     77      --no-preserve-owner    Do not change the ownership of the files
     78      --sparse               Write files with blocks of zeros as sparse files
     79  -u, --unconditional        Replace all files unconditionally
     80 */
     81enum {
     82    CPIO_OPT_EXTRACT            = (1 << 0),
     83    CPIO_OPT_TEST               = (1 << 1),
     84    CPIO_OPT_NUL_TERMINATED     = (1 << 2),
     85    CPIO_OPT_UNCONDITIONAL      = (1 << 3),
     86    CPIO_OPT_VERBOSE            = (1 << 4),
     87    CPIO_OPT_CREATE_LEADING_DIR = (1 << 5),
     88    CPIO_OPT_PRESERVE_MTIME     = (1 << 6),
     89    CPIO_OPT_DEREF              = (1 << 7),
     90    CPIO_OPT_FILE               = (1 << 8),
     91    OPTBIT_FILE = 8,
     92    IF_FEATURE_CPIO_O(OPTBIT_CREATE     ,)
     93    IF_FEATURE_CPIO_O(OPTBIT_FORMAT     ,)
     94    IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
     95    IF_LONG_OPTS(     OPTBIT_QUIET      ,)
     96    IF_LONG_OPTS(     OPTBIT_2STDOUT    ,)
     97    CPIO_OPT_CREATE             = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE     )) + 0,
     98    CPIO_OPT_FORMAT             = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT     )) + 0,
     99    CPIO_OPT_PASSTHROUGH        = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
     100    CPIO_OPT_QUIET              = IF_LONG_OPTS(     (1 << OPTBIT_QUIET      )) + 0,
     101    CPIO_OPT_2STDOUT            = IF_LONG_OPTS(     (1 << OPTBIT_2STDOUT    )) + 0,
     102};
     103
     104#define OPTION_STR "it0uvdmLF:"
     105
     106#if ENABLE_FEATURE_CPIO_O
     107static off_t cpio_pad4(off_t size)
     108{
     109    int i;
     110
     111    i = (- size) & 3;
     112    size += i;
     113    while (--i >= 0)
     114        bb_putchar('\0');
     115    return size;
     116}
     117
     118/* Return value will become exit code.
     119 * It's ok to exit instead of return. */
     120static NOINLINE int cpio_o(void)
     121{
     122    static const char trailer[] ALIGN1 = "TRAILER!!!";
     123    struct name_s {
     124        struct name_s *next;
     125        char name[1];
     126    };
     127    struct inodes_s {
     128        struct inodes_s *next;
     129        struct name_s *names;
     130        struct stat st;
     131    };
     132
     133    struct inodes_s *links = NULL;
     134    off_t bytes = 0; /* output bytes count */
     135
     136    while (1) {
     137        const char *name;
     138        char *line;
     139        struct stat st;
     140
     141        line = (option_mask32 & CPIO_OPT_NUL_TERMINATED)
     142                ? bb_get_chunk_from_file(stdin, NULL)
     143                : xmalloc_fgetline(stdin);
     144
     145        if (line) {
     146            /* Strip leading "./[./]..." from the filename */
     147            name = line;
     148            while (name[0] == '.' && name[1] == '/') {
     149                while (*++name == '/')
     150                    continue;
     151            }
     152            if (!*name) { /* line is empty */
     153                free(line);
     154                continue;
     155            }
     156            if ((option_mask32 & CPIO_OPT_DEREF)
     157                    ? stat(name, &st)
     158                    : lstat(name, &st)
     159            ) {
     160 abort_cpio_o:
     161                bb_simple_perror_msg_and_die(name);
     162            }
     163
     164            if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
     165                st.st_size = 0; /* paranoia */
     166
     167            /* Store hardlinks for later processing, dont output them */
     168            if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
     169                struct name_s *n;
     170                struct inodes_s *l;
     171
     172                /* Do we have this hardlink remembered? */
     173                l = links;
     174                while (1) {
     175                    if (l == NULL) {
     176                        /* Not found: add new item to "links" list */
     177                        l = xzalloc(sizeof(*l));
     178                        l->st = st;
     179                        l->next = links;
     180                        links = l;
     181                        break;
     182                    }
     183                    if (l->st.st_ino == st.st_ino) {
     184                        /* found */
     185                        break;
     186                    }
     187                    l = l->next;
     188                }
     189                /* Add new name to "l->names" list */
     190                n = xmalloc(sizeof(*n) + strlen(name));
     191                strcpy(n->name, name);
     192                n->next = l->names;
     193                l->names = n;
     194
     195                free(line);
     196                continue;
     197            }
     198
     199        } else { /* line == NULL: EOF */
     200 next_link:
     201            if (links) {
     202                /* Output hardlink's data */
     203                st = links->st;
     204                name = links->names->name;
     205                links->names = links->names->next;
     206                /* GNU cpio is reported to emit file data
     207                 * only for the last instance. Mimic that. */
     208                if (links->names == NULL)
     209                    links = links->next;
     210                else
     211                    st.st_size = 0;
     212                /* NB: we leak links->names and/or links,
     213                 * this is intended (we exit soon anyway) */
     214            } else {
     215                /* If no (more) hardlinks to output,
     216                 * output "trailer" entry */
     217                name = trailer;
     218                /* st.st_size == 0 is a must, but for uniformity
     219                 * in the output, we zero out everything */
     220                memset(&st, 0, sizeof(st));
     221                /* st.st_nlink = 1; - GNU cpio does this */
     222            }
     223        }
     224
     225        bytes += printf("070701"
     226                        "%08X%08X%08X%08X%08X%08X%08X"
     227                        "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
     228                /* strlen+1: */ "%08X"
     229                /* chksum: */   "00000000" /* (only for "070702" files) */
     230                /* name,NUL: */ "%s%c",
     231                        (unsigned)(uint32_t) st.st_ino,
     232                        (unsigned)(uint32_t) st.st_mode,
     233                        (unsigned)(uint32_t) st.st_uid,
     234                        (unsigned)(uint32_t) st.st_gid,
     235                        (unsigned)(uint32_t) st.st_nlink,
     236                        (unsigned)(uint32_t) st.st_mtime,
     237                        (unsigned)(uint32_t) st.st_size,
     238                        (unsigned)(uint32_t) major(st.st_dev),
     239                        (unsigned)(uint32_t) minor(st.st_dev),
     240                        (unsigned)(uint32_t) major(st.st_rdev),
     241                        (unsigned)(uint32_t) minor(st.st_rdev),
     242                        (unsigned)(strlen(name) + 1),
     243                        name, '\0');
     244        bytes = cpio_pad4(bytes);
     245
     246        if (st.st_size) {
     247            if (S_ISLNK(st.st_mode)) {
     248                char *lpath = xmalloc_readlink_or_warn(name);
     249                if (!lpath)
     250                    goto abort_cpio_o;
     251                bytes += printf("%s", lpath);
     252                free(lpath);
     253            } else { /* S_ISREG */
     254                int fd = xopen(name, O_RDONLY);
     255                fflush_all();
     256                /* We must abort if file got shorter too! */
     257                bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
     258                bytes += st.st_size;
     259                close(fd);
     260            }
     261            bytes = cpio_pad4(bytes);
     262        }
     263
     264        if (!line) {
     265            if (name != trailer)
     266                goto next_link;
     267            /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
     268            return EXIT_SUCCESS;
     269        }
     270
     271        free(line);
     272    } /* end of "while (1)" */
     273}
     274#endif
     275
     276int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     277int cpio_main(int argc UNUSED_PARAM, char **argv)
    27278{
    28279    archive_handle_t *archive_handle;
    29     char *cpio_filename = NULL;
     280    char *cpio_filename;
     281    IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
    30282    unsigned opt;
    31283
    32     /* Initialise */
     284#if ENABLE_LONG_OPTS
     285    applet_long_options =
     286        "extract\0"      No_argument       "i"
     287        "list\0"         No_argument       "t"
     288#if ENABLE_FEATURE_CPIO_O
     289        "create\0"       No_argument       "o"
     290        "format\0"       Required_argument "H"
     291#if ENABLE_FEATURE_CPIO_P
     292        "pass-through\0" No_argument       "p"
     293#endif
     294#endif
     295        "verbose\0"      No_argument       "v"
     296        "quiet\0"        No_argument       "\xff"
     297        "to-stdout\0"    No_argument       "\xfe"
     298        ;
     299#endif
     300
    33301    archive_handle = init_handle();
    34     archive_handle->src_fd = STDIN_FILENO;
    35     archive_handle->seek = seek_by_read;
    36     archive_handle->flags = ARCHIVE_EXTRACT_NEWER | ARCHIVE_PRESERVE_DATE;
    37 
    38     opt = getopt32(argv, "ituvF:dm", &cpio_filename);
     302    /* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */
     303    archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
     304
     305    /* As of now we do not enforce this: */
     306    /* -i,-t,-o,-p are mutually exclusive */
     307    /* -u,-d,-m make sense only with -i or -p */
     308    /* -L makes sense only with -o or -p */
     309
     310#if !ENABLE_FEATURE_CPIO_O
     311    opt = getopt32(argv, OPTION_STR, &cpio_filename);
     312    argv += optind;
     313    if (opt & CPIO_OPT_FILE) { /* -F */
     314        xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
     315    }
     316#else
     317    opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
     318    argv += optind;
     319    if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */
     320        xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
     321    }
     322    if (opt & CPIO_OPT_PASSTHROUGH) {
     323        pid_t pid;
     324        struct fd_pair pp;
     325
     326        if (argv[0] == NULL)
     327            bb_show_usage();
     328        if (opt & CPIO_OPT_CREATE_LEADING_DIR)
     329            mkdir(argv[0], 0777);
     330        /* Crude existence check:
     331         * close(xopen(argv[0], O_RDONLY | O_DIRECTORY));
     332         * We can also xopen, fstat, IS_DIR, later fchdir.
     333         * This would check for existence earlier and cleaner.
     334         * As it stands now, if we fail xchdir later,
     335         * child dies on EPIPE, unless it caught
     336         * a diffrerent problem earlier.
     337         * This is good enough for now.
     338         */
     339#if !BB_MMU
     340        pp.rd = 3;
     341        pp.wr = 4;
     342        if (!re_execed) {
     343            close(3);
     344            close(4);
     345            xpiped_pair(pp);
     346        }
     347#else
     348        xpiped_pair(pp);
     349#endif
     350        pid = fork_or_rexec(argv - optind);
     351        if (pid == 0) { /* child */
     352            close(pp.rd);
     353            xmove_fd(pp.wr, STDOUT_FILENO);
     354            goto dump;
     355        }
     356        /* parent */
     357        xchdir(*argv++);
     358        close(pp.wr);
     359        xmove_fd(pp.rd, STDIN_FILENO);
     360        //opt &= ~CPIO_OPT_PASSTHROUGH;
     361        opt |= CPIO_OPT_EXTRACT;
     362        goto skip;
     363    }
     364    /* -o */
     365    if (opt & CPIO_OPT_CREATE) {
     366        if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */
     367            bb_show_usage();
     368        if (opt & CPIO_OPT_FILE) {
     369            xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
     370        }
     371 dump:
     372        return cpio_o();
     373    }
     374 skip:
     375#endif
    39376
    40377    /* One of either extract or test options must be given */
     
    45382    if (opt & CPIO_OPT_TEST) {
    46383        /* if both extract and test options are given, ignore extract option */
    47         if (opt & CPIO_OPT_EXTRACT) {
    48             opt &= ~CPIO_OPT_EXTRACT;
    49         }
     384        opt &= ~CPIO_OPT_EXTRACT;
    50385        archive_handle->action_header = header_list;
    51386    }
    52387    if (opt & CPIO_OPT_EXTRACT) {
    53388        archive_handle->action_data = data_extract_all;
     389        if (opt & CPIO_OPT_2STDOUT)
     390            archive_handle->action_data = data_extract_to_stdout;
    54391    }
    55392    if (opt & CPIO_OPT_UNCONDITIONAL) {
    56         archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
    57         archive_handle->flags &= ~ARCHIVE_EXTRACT_NEWER;
     393        archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
     394        archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
    58395    }
    59396    if (opt & CPIO_OPT_VERBOSE) {
     
    64401        }
    65402    }
    66     if (cpio_filename) { /* CPIO_OPT_FILE */
    67         archive_handle->src_fd = xopen(cpio_filename, O_RDONLY);
    68         archive_handle->seek = seek_by_jump;
    69     }
    70403    if (opt & CPIO_OPT_CREATE_LEADING_DIR) {
    71         archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
    72     }
    73 
    74     while (optind < argc) {
     404        archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
     405    }
     406    if (opt & CPIO_OPT_PRESERVE_MTIME) {
     407        archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
     408    }
     409
     410    while (*argv) {
    75411        archive_handle->filter = filter_accept_list;
    76         llist_add_to(&(archive_handle->accept), argv[optind]);
    77         optind++;
    78     }
    79 
    80     while (get_header_cpio(archive_handle) == EXIT_SUCCESS);
     412        llist_add_to(&archive_handle->accept, *argv);
     413        argv++;
     414    }
     415
     416    /* see get_header_cpio */
     417    archive_handle->cpio__blocks = (off_t)-1;
     418    while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
     419        continue;
     420
     421    if (archive_handle->cpio__blocks != (off_t)-1
     422     && !(opt & CPIO_OPT_QUIET)
     423    ) {
     424        fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
     425    }
    81426
    82427    return EXIT_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.