From b6cb6076444c1b3006d0064be4b6098b8fa92b6c Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Sat, 8 May 2010 16:47:33 +0000 Subject: [PATCH] bsdcpio 2.8.3 --- usr.bin/cpio/Makefile | 4 +- usr.bin/cpio/bsdcpio.1 | 31 +- usr.bin/cpio/cmdline.c | 42 +-- usr.bin/cpio/config_freebsd.h | 67 +--- usr.bin/cpio/cpio.c | 576 +++++++++++++--------------------- usr.bin/cpio/cpio.h | 23 +- usr.bin/cpio/cpio_platform.h | 43 +-- usr.bin/cpio/err.c | 17 +- usr.bin/cpio/err.h | 43 +++ usr.bin/cpio/line_reader.c | 171 ++++++++++ usr.bin/cpio/line_reader.h | 37 +++ usr.bin/cpio/matching.c | 163 ++++++---- usr.bin/cpio/matching.h | 18 +- usr.bin/cpio/pathmatch.c | 14 +- usr.bin/cpio/pathmatch.h | 6 +- 15 files changed, 684 insertions(+), 571 deletions(-) create mode 100644 usr.bin/cpio/err.h create mode 100644 usr.bin/cpio/line_reader.c create mode 100644 usr.bin/cpio/line_reader.h diff --git a/usr.bin/cpio/Makefile b/usr.bin/cpio/Makefile index 499b173f64d6..80cf1fa55ef6 100644 --- a/usr.bin/cpio/Makefile +++ b/usr.bin/cpio/Makefile @@ -3,8 +3,8 @@ .include PROG= bsdcpio -BSDCPIO_VERSION_STRING=2.7.0 -SRCS= cpio.c cmdline.c err.c matching.c pathmatch.c +BSDCPIO_VERSION_STRING=2.8.3 +SRCS= cpio.c cmdline.c err.c line_reader.c matching.c pathmatch.c CFLAGS+= -DBSDCPIO_VERSION_STRING=\"${BSDCPIO_VERSION_STRING}\" CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\" .ifdef RELEASE_CRUNCH diff --git a/usr.bin/cpio/bsdcpio.1 b/usr.bin/cpio/bsdcpio.1 index 6017bc5b465c..79b6997ef4a8 100644 --- a/usr.bin/cpio/bsdcpio.1 +++ b/usr.bin/cpio/bsdcpio.1 @@ -80,6 +80,9 @@ specified directory. Unless specifically stated otherwise, options are applicable in all operating modes. .Bl -tag -width indent +.It Fl 0 +Read filenames separated by NUL characters instead of newlines. +This is necessary if any of the filenames being read might contain newlines. .It Fl A (o mode only) Append to the specified archive. @@ -142,6 +145,11 @@ for more complete information about the formats currently supported by the underlying .Xr libarchive 3 library. +.It Fl H Ar format +Synonym for +.Fl -format . +.It Fl h , Fl -help +Print usage information. .It Fl I Ar file Read archive from .Ar file . @@ -154,6 +162,14 @@ Disable security checks during extraction or copying. This allows extraction via symbolic links and path names containing .Sq .. in the name. +.It Fl J +(o mode only) +Compress the file with xz-compatible compression before writing it. +In input mode, this option is ignored; xz compression is recognized +automatically on input. +.It Fl j +Synonym for +.Fl y . .It Fl L (o and p modes) All symbolic links will be followed. @@ -163,6 +179,11 @@ With this option, the target of the link will be archived or copied instead. (p mode only) Create links from the target directory to the original files, instead of copying. +.It Fl lzma +(o mode only) +Compress the file with lzma-compatible compression before writing it. +In input mode, this option is ignored; lzma compression is recognized +automatically on input. .It Fl m (i and p modes) Set file modification time on created files to match @@ -176,6 +197,10 @@ By default, displays the user and group names when they are provided in the archive, or looks up the user and group names in the system password database. +.It Fl no-preserve-owner +(i mode only) +Do not attempt to restore file ownership. +This is the default when run by non-root users. .It Fl O Ar file Write archive to .Ar file . @@ -185,6 +210,10 @@ See above for description. .It Fl p Pass-through mode. See above for description. +.It Fl preserve-owner +(i mode only) +Restore file ownership. +This is the default when run by the root user. .It Fl -quiet Suppress unnecessary messages. .It Fl R Oo user Oc Ns Oo : Oc Ns Oo group Oc @@ -266,7 +295,7 @@ for more information. .Sh EXAMPLES The .Nm -command is traditionally used to copy file hierarchies in conjunction +command is traditionally used to copy file heirarchies in conjunction with the .Xr find 1 command. diff --git a/usr.bin/cpio/cmdline.c b/usr.bin/cpio/cmdline.c index b6a56bed485d..ca50ed2c7597 100644 --- a/usr.bin/cpio/cmdline.c +++ b/usr.bin/cpio/cmdline.c @@ -46,11 +46,12 @@ __FBSDID("$FreeBSD$"); #endif #include "cpio.h" +#include "err.h" /* * Short options for cpio. Please keep this sorted. */ -static const char *short_options = "0AaBC:F:O:cdE:f:H:hijLlmnopR:rtuvVW:yZz"; +static const char *short_options = "0AaBC:cdE:F:f:H:hI:iJjLlmnO:opR:rtuvW:yZz"; /* * Long options for cpio. Please keep this sorted. @@ -61,7 +62,6 @@ static const struct option { int equivalent; /* Equivalent short option. */ } cpio_longopts[] = { { "create", 0, 'o' }, - { "dot", 0, 'V' }, { "extract", 0, 'i' }, { "file", 1, 'F' }, { "format", 1, 'H' }, @@ -69,6 +69,7 @@ static const struct option { { "insecure", 0, OPTION_INSECURE }, { "link", 0, 'l' }, { "list", 0, 't' }, + { "lzma", 0, OPTION_LZMA }, { "make-directories", 0, 'd' }, { "no-preserve-owner", 0, OPTION_NO_PRESERVE_OWNER }, { "null", 0, '0' }, @@ -76,10 +77,12 @@ static const struct option { { "owner", 1, 'R' }, { "pass-through", 0, 'p' }, { "preserve-modification-time", 0, 'm' }, + { "preserve-owner", 0, OPTION_PRESERVE_OWNER }, { "quiet", 0, OPTION_QUIET }, { "unconditional", 0, 'u' }, { "verbose", 0, 'v' }, { "version", 0, OPTION_VERSION }, + { "xz", 0, 'J' }, { NULL, 0, 0 } }; @@ -172,7 +175,7 @@ cpio_getopt(struct cpio *cpio) /* Otherwise, pick up the next word. */ opt_word = *cpio->argv; if (opt_word == NULL) { - cpio_warnc(0, + warnc(0, "Option -%c requires an argument", opt); return ('?'); @@ -223,13 +226,13 @@ cpio_getopt(struct cpio *cpio) /* Fail if there wasn't a unique match. */ if (match == NULL) { - cpio_warnc(0, + warnc(0, "Option %s%s is not supported", long_prefix, opt_word); return ('?'); } if (match2 != NULL) { - cpio_warnc(0, + warnc(0, "Ambiguous option %s%s (matches --%s and --%s)", long_prefix, opt_word, match->name, match2->name); return ('?'); @@ -241,7 +244,7 @@ cpio_getopt(struct cpio *cpio) if (cpio->optarg == NULL) { cpio->optarg = *cpio->argv; if (cpio->optarg == NULL) { - cpio_warnc(0, + warnc(0, "Option %s%s requires an argument", long_prefix, match->name); return ('?'); @@ -252,7 +255,7 @@ cpio_getopt(struct cpio *cpio) } else { /* Argument forbidden: fail if there is one. */ if (cpio->optarg != NULL) { - cpio_warnc(0, + warnc(0, "Option %s%s does not allow an argument", long_prefix, match->name); return ('?'); @@ -283,17 +286,20 @@ cpio_getopt(struct cpio *cpio) * * Sets uid/gid return as appropriate, -1 indicates uid/gid not specified. * + * Returns NULL if no error, otherwise returns error string for display. + * */ -int +const char * owner_parse(const char *spec, int *uid, int *gid) { + static char errbuff[128]; const char *u, *ue, *g; *uid = -1; *gid = -1; if (spec[0] == '\0') - return (1); + return ("Invalid empty user/group spec"); /* * Split spec into [user][:.][group] @@ -321,10 +327,8 @@ owner_parse(const char *spec, int *uid, int *gid) struct passwd *pwent; user = (char *)malloc(ue - u + 1); - if (user == NULL) { - cpio_warnc(errno, "Couldn't allocate memory"); - return (1); - } + if (user == NULL) + return ("Couldn't allocate memory"); memcpy(user, u, ue - u); user[ue - u] = '\0'; if ((pwent = getpwnam(user)) != NULL) { @@ -336,9 +340,10 @@ owner_parse(const char *spec, int *uid, int *gid) errno = 0; *uid = strtoul(user, &end, 10); if (errno || *end != '\0') { - cpio_warnc(errno, + snprintf(errbuff, sizeof(errbuff), "Couldn't lookup user ``%s''", user); - return (1); + errbuff[sizeof(errbuff) - 1] = '\0'; + return (errbuff); } } free(user); @@ -353,11 +358,12 @@ owner_parse(const char *spec, int *uid, int *gid) errno = 0; *gid = strtoul(g, &end, 10); if (errno || *end != '\0') { - cpio_warnc(errno, + snprintf(errbuff, sizeof(errbuff), "Couldn't lookup group ``%s''", g); - return (1); + errbuff[sizeof(errbuff) - 1] = '\0'; + return (errbuff); } } } - return (0); + return (NULL); } diff --git a/usr.bin/cpio/config_freebsd.h b/usr.bin/cpio/config_freebsd.h index df376ff2d30a..ec4e4416e37f 100644 --- a/usr.bin/cpio/config_freebsd.h +++ b/usr.bin/cpio/config_freebsd.h @@ -25,83 +25,32 @@ * $FreeBSD$ */ -/* A default configuration for FreeBSD, used if there is no config.h. */ +/* A hand-tooled configuration for FreeBSD. */ #include /* __FreeBSD_version */ -#if __FreeBSD__ > 4 -#define HAVE_ACL_GET_PERM 0 -#define HAVE_ACL_GET_PERM_NP 1 -#define HAVE_ACL_PERMSET_T 1 -#define HAVE_ACL_USER 1 -#endif -#undef HAVE_ATTR_XATTR_H -#define HAVE_BZLIB_H 1 -#define HAVE_CHFLAGS 1 -#define HAVE_DECL_OPTARG 1 -#define HAVE_DECL_OPTIND 1 -#define HAVE_DIRENT_D_NAMLEN 1 #define HAVE_DIRENT_H 1 -#define HAVE_D_MD_ORDER 1 #define HAVE_ERRNO_H 1 -#undef HAVE_EXT2FS_EXT2_FS_H -#define HAVE_FCHDIR 1 #define HAVE_FCNTL_H 1 -#define HAVE_FNMATCH 1 -#define HAVE_FNMATCH_H 1 -#define HAVE_FNM_LEADING_DIR 1 -#define HAVE_FTRUNCATE 1 #define HAVE_FUTIMES 1 -#undef HAVE_GETXATTR #define HAVE_GRP_H 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_LANGINFO_H 1 -#undef HAVE_LGETXATTR -#undef HAVE_LIBACL #define HAVE_LIBARCHIVE 1 -#define HAVE_LIBBZ2 1 -#define HAVE_LIBZ 1 -#define HAVE_LIMITS_H 1 -#undef HAVE_LINUX_EXT2_FS_H -#undef HAVE_LINUX_FS_H -#undef HAVE_LISTXATTR -#undef HAVE_LLISTXATTR -#define HAVE_LOCALE_H 1 +#define HAVE_LINK 1 +#define HAVE_LSTAT 1 #define HAVE_LUTIMES 1 -#define HAVE_MALLOC 1 -#define HAVE_MEMMOVE 1 -#define HAVE_MEMORY_H 1 -#define HAVE_MEMSET 1 -#if __FreeBSD_version >= 450002 /* nl_langinfo introduced */ -#define HAVE_NL_LANGINFO 1 -#endif -#define HAVE_PATHS_H 1 #define HAVE_PWD_H 1 -#define HAVE_SETLOCALE 1 +#define HAVE_READLINK 1 #define HAVE_STDARG_H 1 -#define HAVE_STDINT_H 1 #define HAVE_STDLIB_H 1 -#define HAVE_STRCHR 1 -#define HAVE_STRDUP 1 -#define HAVE_STRERROR 1 -#define HAVE_STRFTIME 1 -#define HAVE_STRINGS_H 1 #define HAVE_STRING_H 1 -#define HAVE_STRRCHR 1 -#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC -#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 -#define HAVE_SYS_ACL_H 1 -#define HAVE_SYS_IOCTL_H 1 -#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYMLINK 1 +#define HAVE_SYS_CDEFS_H 1 #define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 #define HAVE_TIME_H 1 -#define HAVE_SYS_TYPES_H 1 #define HAVE_UINTMAX_T 1 #define HAVE_UNISTD_H 1 #define HAVE_UNSIGNED_LONG_LONG 1 +#define HAVE_UTIME_H 1 #define HAVE_UTIMES 1 -#define HAVE_VPRINTF 1 -#define HAVE_ZLIB_H 1 -#undef MAJOR_IN_MKDEV -#define STDC_HEADERS 1 diff --git a/usr.bin/cpio/cpio.c b/usr.bin/cpio/cpio.c index 53195aa95af2..9b76fe8c9fa9 100644 --- a/usr.bin/cpio/cpio.c +++ b/usr.bin/cpio/cpio.c @@ -56,6 +56,9 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_STDARG_H #include #endif +#ifdef HAVE_STDINT_H +#include +#endif #include #ifdef HAVE_STDLIB_H #include @@ -74,11 +77,17 @@ __FBSDID("$FreeBSD$"); #endif #include "cpio.h" +#include "err.h" +#include "line_reader.h" #include "matching.h" /* Fixed size of uname/gname caches. */ #define name_cache_size 101 +#ifndef O_BINARY +#define O_BINARY 0 +#endif + struct name_cache { int probes; int hits; @@ -89,7 +98,8 @@ struct name_cache { } cache[name_cache_size]; }; -static int copy_data(struct archive *, struct archive *); +static int extract_data(struct archive *, struct archive *); +const char * cpio_i64toa(int64_t); static const char *cpio_rename(const char *name); static int entry_to_archive(struct cpio *, struct archive_entry *); static int file_to_archive(struct cpio *, const char *); @@ -117,6 +127,7 @@ main(int argc, char *argv[]) static char buff[16384]; struct cpio _cpio; /* Allocated on stack. */ struct cpio *cpio; + const char *errmsg; int uid, gid; int opt; @@ -124,33 +135,26 @@ main(int argc, char *argv[]) memset(cpio, 0, sizeof(*cpio)); cpio->buff = buff; cpio->buff_size = sizeof(buff); -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure open() function will be used with a binary mode. */ - /* on cygwin, we need something similar, but instead link against */ - /* a special startup object, binmode.o */ - _set_fmode(_O_BINARY); -#endif - /* Need cpio_progname before calling cpio_warnc. */ + /* Need progname before calling warnc. */ if (*argv == NULL) - cpio_progname = "bsdcpio"; + progname = "bsdcpio"; else { #if defined(_WIN32) && !defined(__CYGWIN__) - cpio_progname = strrchr(*argv, '\\'); + progname = strrchr(*argv, '\\'); #else - cpio_progname = strrchr(*argv, '/'); + progname = strrchr(*argv, '/'); #endif - if (cpio_progname != NULL) - cpio_progname++; + if (progname != NULL) + progname++; else - cpio_progname = *argv; + progname = *argv; } cpio->uid_override = -1; cpio->gid_override = -1; cpio->argv = argv; cpio->argc = argc; - cpio->line_separator = '\n'; cpio->mode = '\0'; cpio->verbose = 0; cpio->compress = '\0'; @@ -161,19 +165,17 @@ main(int argc, char *argv[]) cpio->extract_flags |= ARCHIVE_EXTRACT_PERM; cpio->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; cpio->extract_flags |= ARCHIVE_EXTRACT_ACL; -#if defined(_WIN32) || defined(__CYGWIN__) - if (bsdcpio_is_privileged()) -#else +#if !defined(_WIN32) && !defined(__CYGWIN__) if (geteuid() == 0) -#endif cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; +#endif cpio->bytes_per_block = 512; cpio->filename = NULL; while ((opt = cpio_getopt(cpio)) != -1) { switch (opt) { case '0': /* GNU convention: --null, -0 */ - cpio->line_separator = '\0'; + cpio->option_null = 1; break; case 'A': /* NetBSD/OpenBSD */ cpio->option_append = 1; @@ -187,7 +189,7 @@ main(int argc, char *argv[]) case 'C': /* NetBSD/OpenBSD */ cpio->bytes_per_block = atoi(cpio->optarg); if (cpio->bytes_per_block <= 0) - cpio_errc(1, 0, "Invalid blocksize %s", cpio->optarg); + errc(1, 0, "Invalid blocksize %s", cpio->optarg); break; case 'c': /* POSIX 1997 */ cpio->format = "odc"; @@ -196,13 +198,14 @@ main(int argc, char *argv[]) cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_AUTODIR; break; case 'E': /* NetBSD/OpenBSD */ - include_from_file(cpio, cpio->optarg); + include_from_file(&cpio->matching, + cpio->optarg, cpio->option_null); break; case 'F': /* NetBSD/OpenBSD/GNU cpio */ cpio->filename = cpio->optarg; break; case 'f': /* POSIX 1997 */ - exclude(cpio, cpio->optarg); + exclude(&cpio->matching, cpio->optarg); break; case 'H': /* GNU cpio (also --format) */ cpio->format = cpio->optarg; @@ -215,10 +218,16 @@ main(int argc, char *argv[]) break; case 'i': /* POSIX 1997 */ if (cpio->mode != '\0') - cpio_errc(1, 0, + errc(1, 0, "Cannot use both -i and -%c", cpio->mode); cpio->mode = opt; break; + case 'J': /* GNU tar, others */ + cpio->compress = opt; + break; + case 'j': /* GNU tar, others */ + cpio->compress = opt; + break; case OPTION_INSECURE: cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_SYMLINKS; cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; @@ -229,6 +238,9 @@ main(int argc, char *argv[]) case 'l': /* POSIX 1997 */ cpio->option_link = 1; break; + case OPTION_LZMA: /* GNU tar, others */ + cpio->compress = opt; + break; case 'm': /* POSIX 1997 */ cpio->extract_flags |= ARCHIVE_EXTRACT_TIME; break; @@ -243,23 +255,29 @@ main(int argc, char *argv[]) break; case 'o': /* POSIX 1997 */ if (cpio->mode != '\0') - cpio_errc(1, 0, + errc(1, 0, "Cannot use both -o and -%c", cpio->mode); cpio->mode = opt; break; case 'p': /* POSIX 1997 */ if (cpio->mode != '\0') - cpio_errc(1, 0, + errc(1, 0, "Cannot use both -p and -%c", cpio->mode); cpio->mode = opt; cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; break; + case OPTION_PRESERVE_OWNER: + cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; + break; case OPTION_QUIET: /* GNU cpio */ cpio->quiet = 1; break; case 'R': /* GNU cpio, also --owner */ - if (owner_parse(cpio->optarg, &uid, &gid)) + errmsg = owner_parse(cpio->optarg, &uid, &gid); + if (errmsg) { + warnc(-1, "%s", errmsg); usage(); + } if (uid != -1) cpio->uid_override = uid; if (gid != -1) @@ -278,9 +296,6 @@ main(int argc, char *argv[]) case 'v': /* POSIX 1997 */ cpio->verbose++; break; - case 'V': /* GNU cpio */ - cpio->dot++; - break; case OPTION_VERSION: /* GNU convention */ version(); break; @@ -293,23 +308,13 @@ main(int argc, char *argv[]) break; #endif case 'y': /* tar convention */ -#if HAVE_LIBBZ2 cpio->compress = opt; -#else - cpio_warnc(0, "bzip2 compression not supported by " - "this version of bsdcpio"); -#endif break; case 'Z': /* tar convention */ cpio->compress = opt; break; case 'z': /* tar convention */ -#if HAVE_LIBZ cpio->compress = opt; -#else - cpio_warnc(0, "gzip compression not supported by " - "this version of bsdcpio"); -#endif break; default: usage(); @@ -324,19 +329,16 @@ main(int argc, char *argv[]) cpio->mode = 'i'; /* -t requires -i */ if (cpio->option_list && cpio->mode != 'i') - cpio_errc(1, 0, "Option -t requires -i", cpio->mode); + errc(1, 0, "Option -t requires -i"); /* -n requires -it */ if (cpio->option_numeric_uid_gid && !cpio->option_list) - cpio_errc(1, 0, "Option -n requires -it"); + errc(1, 0, "Option -n requires -it"); /* Can only specify format when writing */ if (cpio->format != NULL && cpio->mode != 'o') - cpio_errc(1, 0, "Option --format requires -o"); + errc(1, 0, "Option --format requires -o"); /* -l requires -p */ if (cpio->option_link && cpio->mode != 'p') - cpio_errc(1, 0, "Option -l requires -p"); - /* -v overrides -V */ - if (cpio->dot && cpio->verbose) - cpio->dot = 0; + errc(1, 0, "Option -l requires -p"); /* TODO: Flag other nonsensical combinations. */ switch (cpio->mode) { @@ -350,7 +352,7 @@ main(int argc, char *argv[]) break; case 'i': while (*cpio->argv != NULL) { - include(cpio, *cpio->argv); + include(&cpio->matching, *cpio->argv); --cpio->argc; ++cpio->argv; } @@ -361,26 +363,26 @@ main(int argc, char *argv[]) break; case 'p': if (*cpio->argv == NULL || **cpio->argv == '\0') - cpio_errc(1, 0, + errc(1, 0, "-p mode requires a target directory"); mode_pass(cpio, *cpio->argv); break; default: - cpio_errc(1, 0, + errc(1, 0, "Must specify at least one of -i, -o, or -p"); } free_cache(cpio->gname_cache); free_cache(cpio->uname_cache); - return (0); + return (cpio->return_value); } -void +static void usage(void) { const char *p; - p = cpio_progname; + p = progname; fprintf(stderr, "Brief Usage:\n"); fprintf(stderr, " List: %s -it < archive\n", p); @@ -394,14 +396,9 @@ static const char *long_help_msg = "First option must be a mode specifier:\n" " -i Input -o Output -p Pass\n" "Common Options:\n" - " -v Verbose filenames -V one dot per file\n" + " -v Verbose\n" "Create: %p -o [options] < [list of files] > [archive]\n" -#ifdef HAVE_BZLIB_H - " -y Compress archive with bzip2\n" -#endif -#ifdef HAVE_ZLIB_H - " -z Compress archive with gzip\n" -#endif + " -J,-y,-z,--lzma Compress archive with xz/bzip2/gzip/lzma\n" " --format {odc|newc|ustar} Select archive format\n" "List: %p -it < [archive]\n" "Extract: %p -i [options] < [archive]\n"; @@ -423,7 +420,7 @@ long_help(void) const char *prog; const char *p; - prog = cpio_progname; + prog = progname; fflush(stderr); @@ -455,19 +452,33 @@ version(void) static void mode_out(struct cpio *cpio) { - unsigned long blocks; struct archive_entry *entry, *spare; struct line_reader *lr; const char *p; int r; if (cpio->option_append) - cpio_errc(1, 0, "Append mode not yet supported."); + errc(1, 0, "Append mode not yet supported."); + + cpio->archive_read_disk = archive_read_disk_new(); + if (cpio->archive_read_disk == NULL) + errc(1, 0, "Failed to allocate archive object"); + if (cpio->option_follow_links) + archive_read_disk_set_symlink_logical(cpio->archive_read_disk); + else + archive_read_disk_set_symlink_physical(cpio->archive_read_disk); + archive_read_disk_set_standard_lookup(cpio->archive_read_disk); + cpio->archive = archive_write_new(); if (cpio->archive == NULL) - cpio_errc(1, 0, "Failed to allocate archive object"); + errc(1, 0, "Failed to allocate archive object"); switch (cpio->compress) { -#ifndef SMALLER + case 'J': + r = archive_write_set_compression_xz(cpio->archive); + break; + case OPTION_LZMA: + r = archive_write_set_compression_lzma(cpio->archive); + break; case 'j': case 'y': r = archive_write_set_compression_bzip2(cpio->archive); break; @@ -477,41 +488,30 @@ mode_out(struct cpio *cpio) case 'Z': r = archive_write_set_compression_compress(cpio->archive); break; -#endif - case '\0': + default: r = archive_write_set_compression_none(cpio->archive); break; - default: - cpio_errc(1, 0, "Unrecognized compression option"); } - if (r != ARCHIVE_OK) - cpio_errc(1, 0, "Unsupported compression format"); -#ifdef SMALLER - if (strcmp(cpio->format, "cpio")) - r = archive_write_set_format_cpio(cpio->archive); - else if (strcmp(cpio->format, "odc")) - r = archive_write_set_format_cpio(cpio->archive); - else if (strcmp(cpio->format, "newc")) - r = archive_write_set_format_cpio(cpio->archive); - else if (strcmp(cpio->format, "ustar")) - r = archive_write_set_format_cpio(cpio->archive); -#else + if (r < ARCHIVE_WARN) + errc(1, 0, "Requested compression not available"); r = archive_write_set_format_by_name(cpio->archive, cpio->format); -#endif if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(cpio->archive)); + errc(1, 0, "%s", archive_error_string(cpio->archive)); archive_write_set_bytes_per_block(cpio->archive, cpio->bytes_per_block); cpio->linkresolver = archive_entry_linkresolver_new(); archive_entry_linkresolver_set_strategy(cpio->linkresolver, archive_format(cpio->archive)); + /* + * The main loop: Copy each file into the output archive. + */ r = archive_write_open_file(cpio->archive, cpio->filename); if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(cpio->archive)); - lr = process_lines_init("-", cpio->line_separator); - while ((p = process_lines_next(lr)) != NULL) + errc(1, 0, "%s", archive_error_string(cpio->archive)); + lr = line_reader("-", cpio->option_null); + while ((p = line_reader_next(lr)) != NULL) file_to_archive(cpio, p); - process_lines_free(lr); + line_reader_free(lr); /* * The hardlink detection may have queued up a couple of entries @@ -527,15 +527,14 @@ mode_out(struct cpio *cpio) } r = archive_write_close(cpio->archive); - if (cpio->dot) - fprintf(stderr, "\n"); if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(cpio->archive)); + errc(1, 0, "%s", archive_error_string(cpio->archive)); if (!cpio->quiet) { - blocks = (archive_position_uncompressed(cpio->archive) + 511) - / 512; - fprintf(stderr, "%lu %s\n", blocks, + int64_t blocks = + (archive_position_uncompressed(cpio->archive) + 511) + / 512; + fprintf(stderr, "%lu %s\n", (unsigned long)blocks, blocks == 1 ? "block" : "blocks"); } archive_write_finish(cpio->archive); @@ -549,57 +548,37 @@ mode_out(struct cpio *cpio) static int file_to_archive(struct cpio *cpio, const char *srcpath) { - struct stat st; const char *destpath; struct archive_entry *entry, *spare; size_t len; const char *p; -#if !defined(_WIN32) || defined(__CYGWIN__) - int lnklen; -#endif int r; /* * Create an archive_entry describing the source file. * - * XXX TODO: rework to use archive_read_disk_entry_from_file() */ entry = archive_entry_new(); if (entry == NULL) - cpio_errc(1, 0, "Couldn't allocate entry"); + errc(1, 0, "Couldn't allocate entry"); archive_entry_copy_sourcepath(entry, srcpath); - - /* Get stat information. */ - if (cpio->option_follow_links) - r = stat(srcpath, &st); - else - r = lstat(srcpath, &st); - if (r != 0) { - cpio_warnc(errno, "Couldn't stat \"%s\"", srcpath); - archive_entry_free(entry); - return (0); + r = archive_read_disk_entry_from_file(cpio->archive_read_disk, + entry, -1, NULL); + if (r < ARCHIVE_FAILED) + errc(1, 0, "%s", + archive_error_string(cpio->archive_read_disk)); + if (r < ARCHIVE_OK) + warnc(0, "%s", + archive_error_string(cpio->archive_read_disk)); + if (r <= ARCHIVE_FAILED) { + cpio->return_value = 1; + return (r); } if (cpio->uid_override >= 0) - st.st_uid = cpio->uid_override; + archive_entry_set_uid(entry, cpio->uid_override); if (cpio->gid_override >= 0) - st.st_gid = cpio->gid_override; - archive_entry_copy_stat(entry, &st); - -#if !defined(_WIN32) || defined(__CYGWIN__) - /* If its a symlink, pull the target. */ - if (S_ISLNK(st.st_mode)) { - lnklen = readlink(srcpath, cpio->buff, cpio->buff_size); - if (lnklen < 0) { - cpio_warnc(errno, - "%s: Couldn't read symbolic link", srcpath); - archive_entry_free(entry); - return (0); - } - cpio->buff[lnklen] = 0; - archive_entry_set_symlink(entry, cpio->buff); - } -#endif + archive_entry_set_gid(entry, cpio->gid_override); /* * Generate a destination path for this entry. @@ -618,7 +597,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath) free(cpio->pass_destpath); cpio->pass_destpath = malloc(cpio->pass_destpath_alloc); if (cpio->pass_destpath == NULL) - cpio_errc(1, ENOMEM, + errc(1, ENOMEM, "Can't allocate path buffer"); } strcpy(cpio->pass_destpath, cpio->destdir); @@ -639,18 +618,18 @@ file_to_archive(struct cpio *cpio, const char *srcpath) */ spare = NULL; if (cpio->linkresolver != NULL - && !S_ISDIR(st.st_mode)) { + && archive_entry_filetype(entry) != AE_IFDIR) { archive_entry_linkify(cpio->linkresolver, &entry, &spare); } if (entry != NULL) { r = entry_to_archive(cpio, entry); archive_entry_free(entry); - } - if (spare != NULL) { - if (r == 0) - r = entry_to_archive(cpio, spare); - archive_entry_free(spare); + if (spare != NULL) { + if (r == 0) + r = entry_to_archive(cpio, spare); + archive_entry_free(spare); + } } return (r); } @@ -667,8 +646,6 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) /* Print out the destination name to the user. */ if (cpio->verbose) fprintf(stderr,"%s", destpath); - if (cpio->dot) - fprintf(stderr, "."); /* * Option_link only makes sense in pass mode and for @@ -686,7 +663,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) /* Save the original entry in case we need it later. */ t = archive_entry_clone(entry); if (t == NULL) - cpio_errc(1, ENOMEM, "Can't create link"); + errc(1, ENOMEM, "Can't create link"); /* Note: link(2) doesn't create parent directories, * so we use archive_write_header() instead as a * convenience. */ @@ -696,15 +673,15 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) r = archive_write_header(cpio->archive, t); archive_entry_free(t); if (r != ARCHIVE_OK) - cpio_warnc(archive_errno(cpio->archive), - archive_error_string(cpio->archive)); + warnc(archive_errno(cpio->archive), + "%s", archive_error_string(cpio->archive)); if (r == ARCHIVE_FATAL) exit(1); #ifdef EXDEV if (r != ARCHIVE_OK && archive_errno(cpio->archive) == EXDEV) { /* Cross-device link: Just fall through and use * the original entry to copy the file over. */ - cpio_warnc(0, "Copying file instead"); + warnc(0, "Copying file instead"); } else #endif return (0); @@ -716,9 +693,9 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) */ if (archive_entry_filetype(entry) == AE_IFREG) { if (archive_entry_size(entry) > 0) { - fd = open(srcpath, O_RDONLY); + fd = open(srcpath, O_RDONLY | O_BINARY); if (fd < 0) { - cpio_warnc(errno, + warnc(errno, "%s: could not open file", srcpath); goto cleanup; } @@ -730,7 +707,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) r = archive_write_header(cpio->archive, entry); if (r != ARCHIVE_OK) - cpio_warnc(archive_errno(cpio->archive), + warnc(archive_errno(cpio->archive), "%s: %s", srcpath, archive_error_string(cpio->archive)); @@ -744,10 +721,10 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) r = archive_write_data(cpio->archive, cpio->buff, bytes_read); if (r < 0) - cpio_errc(1, archive_errno(cpio->archive), - archive_error_string(cpio->archive)); + errc(1, archive_errno(cpio->archive), + "%s", archive_error_string(cpio->archive)); if (r < bytes_read) { - cpio_warnc(0, + warnc(0, "Truncated write; file may have grown while being archived."); } bytes_read = read(fd, cpio->buff, cpio->buff_size); @@ -776,7 +753,7 @@ restore_time(struct cpio *cpio, struct archive_entry *entry, (void)name; /* UNUSED */ if (!warned) - cpio_warnc(0, "Can't restore access times on this platform"); + warnc(0, "Can't restore access times on this platform"); warned = 1; return (fd); #else @@ -795,7 +772,7 @@ restore_time(struct cpio *cpio, struct archive_entry *entry, times[0].tv_sec = archive_entry_atime(entry); times[0].tv_usec = archive_entry_atime_nsec(entry) / 1000; -#ifdef HAVE_FUTIMES +#if defined(HAVE_FUTIMES) && !defined(__CYGWIN__) if (fd >= 0 && futimes(fd, times) == 0) return (fd); #endif @@ -811,9 +788,10 @@ restore_time(struct cpio *cpio, struct archive_entry *entry, #ifdef HAVE_LUTIMES if (lutimes(name, times) != 0) #else - if (!S_ISLNK(archive_entry_mode(entry)) && utimes(name, times) != 0) + if ((AE_IFLNK != archive_entry_filetype(entry)) + && utimes(name, times) != 0) #endif - cpio_warnc(errno, "Can't update time for %s", name); + warnc(errno, "Can't update time for %s", name); #endif return (fd); } @@ -826,38 +804,32 @@ mode_in(struct cpio *cpio) struct archive_entry *entry; struct archive *ext; const char *destpath; - unsigned long blocks; int r; ext = archive_write_disk_new(); if (ext == NULL) - cpio_errc(1, 0, "Couldn't allocate restore object"); + errc(1, 0, "Couldn't allocate restore object"); r = archive_write_disk_set_options(ext, cpio->extract_flags); if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(ext)); + errc(1, 0, "%s", archive_error_string(ext)); a = archive_read_new(); if (a == NULL) - cpio_errc(1, 0, "Couldn't allocate archive object"); -#ifdef SMALLER - archive_read_support_format_cpio(a); - archive_read_support_format_tar(a); -#else + errc(1, 0, "Couldn't allocate archive object"); archive_read_support_compression_all(a); archive_read_support_format_all(a); -#endif if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block)) - cpio_errc(1, archive_errno(a), - archive_error_string(a)); + errc(1, archive_errno(a), + "%s", archive_error_string(a)); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { - cpio_errc(1, archive_errno(a), - archive_error_string(a)); + errc(1, archive_errno(a), + "%s", archive_error_string(a)); } - if (excluded(cpio, archive_entry_pathname(entry))) + if (excluded(cpio->matching, archive_entry_pathname(entry))) continue; if (cpio->option_rename) { destpath = cpio_rename(archive_entry_pathname(entry)); @@ -867,9 +839,7 @@ mode_in(struct cpio *cpio) if (destpath == NULL) continue; if (cpio->verbose) - fprintf(stderr, "%s\n", destpath); - if (cpio->dot) - fprintf(stderr, "."); + fprintf(stdout, "%s\n", destpath); if (cpio->uid_override >= 0) archive_entry_set_uid(entry, cpio->uid_override); if (cpio->gid_override >= 0) @@ -880,30 +850,34 @@ mode_in(struct cpio *cpio) archive_entry_pathname(entry), archive_error_string(ext)); } else if (archive_entry_size(entry) > 0) { - r = copy_data(a, ext); + r = extract_data(a, ext); + if (r != ARCHIVE_OK) + cpio->return_value = 1; } } r = archive_read_close(a); - if (cpio->dot) - fprintf(stderr, "\n"); if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(a)); + errc(1, 0, "%s", archive_error_string(a)); r = archive_write_close(ext); if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(ext)); + errc(1, 0, "%s", archive_error_string(ext)); if (!cpio->quiet) { - blocks = (archive_position_uncompressed(a) + 511) + int64_t blocks = (archive_position_uncompressed(a) + 511) / 512; - fprintf(stderr, "%lu %s\n", blocks, + fprintf(stderr, "%lu %s\n", (unsigned long)blocks, blocks == 1 ? "block" : "blocks"); } archive_read_finish(a); archive_write_finish(ext); - exit(0); + exit(cpio->return_value); } +/* + * Exits if there's a fatal error. Returns ARCHIVE_OK + * if everything is kosher. + */ static int -copy_data(struct archive *ar, struct archive *aw) +extract_data(struct archive *ar, struct archive *aw) { int r; size_t size; @@ -915,14 +889,14 @@ copy_data(struct archive *ar, struct archive *aw) if (r == ARCHIVE_EOF) return (ARCHIVE_OK); if (r != ARCHIVE_OK) { - cpio_warnc(archive_errno(ar), + warnc(archive_errno(ar), "%s", archive_error_string(ar)); - return (r); + exit(1); } r = archive_write_data_block(aw, block, size, offset); if (r != ARCHIVE_OK) { - cpio_warnc(archive_errno(aw), - archive_error_string(aw)); + warnc(archive_errno(aw), + "%s", archive_error_string(aw)); return (r); } } @@ -933,32 +907,26 @@ mode_list(struct cpio *cpio) { struct archive *a; struct archive_entry *entry; - unsigned long blocks; int r; a = archive_read_new(); if (a == NULL) - cpio_errc(1, 0, "Couldn't allocate archive object"); -#ifdef SMALLER - archive_read_support_format_cpio(a); - archive_read_support_format_tar(a); -#else + errc(1, 0, "Couldn't allocate archive object"); archive_read_support_compression_all(a); archive_read_support_format_all(a); -#endif if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block)) - cpio_errc(1, archive_errno(a), - archive_error_string(a)); + errc(1, archive_errno(a), + "%s", archive_error_string(a)); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { - cpio_errc(1, archive_errno(a), - archive_error_string(a)); + errc(1, archive_errno(a), + "%s", archive_error_string(a)); } - if (excluded(cpio, archive_entry_pathname(entry))) + if (excluded(cpio->matching, archive_entry_pathname(entry))) continue; if (cpio->verbose) list_item_verbose(cpio, entry); @@ -967,11 +935,11 @@ mode_list(struct cpio *cpio) } r = archive_read_close(a); if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(a)); + errc(1, 0, "%s", archive_error_string(a)); if (!cpio->quiet) { - blocks = (archive_position_uncompressed(a) + 511) + int64_t blocks = (archive_position_uncompressed(a) + 511) / 512; - fprintf(stderr, "%lu %s\n", blocks, + fprintf(stderr, "%lu %s\n", (unsigned long)blocks, blocks == 1 ? "block" : "blocks"); } archive_read_finish(a); @@ -994,23 +962,18 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry) char uids[16], gids[16]; const char *uname, *gname; FILE *out = stdout; - const struct stat *st; const char *fmt; - time_t tim; + time_t mtime; static time_t now; - st = archive_entry_stat(entry); - if (!now) time(&now); if (cpio->option_numeric_uid_gid) { /* Format numeric uid/gid for display. */ - snprintf(uids, sizeof(uids), "%jd", - (intmax_t)archive_entry_uid(entry)); + strcpy(uids, cpio_i64toa(archive_entry_uid(entry))); uname = uids; - snprintf(gids, sizeof(gids), "%jd", - (intmax_t)archive_entry_gid(entry)); + strcpy(gids, cpio_i64toa(archive_entry_gid(entry))); gname = gids; } else { /* Use uname if it's present, else lookup name from uid. */ @@ -1024,30 +987,31 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry) } /* Print device number or file size. */ - if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { + if (archive_entry_filetype(entry) == AE_IFCHR + || archive_entry_filetype(entry) == AE_IFBLK) { snprintf(size, sizeof(size), "%lu,%lu", - (unsigned long)major(st->st_rdev), - (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */ + (unsigned long)archive_entry_rdevmajor(entry), + (unsigned long)archive_entry_rdevminor(entry)); } else { - snprintf(size, sizeof(size), CPIO_FILESIZE_PRINTF, - (CPIO_FILESIZE_TYPE)st->st_size); + strcpy(size, cpio_i64toa(archive_entry_size(entry))); } /* Format the time using 'ls -l' conventions. */ - tim = (time_t)st->st_mtime; + mtime = archive_entry_mtime(entry); #if defined(_WIN32) && !defined(__CYGWIN__) /* Windows' strftime function does not support %e format. */ - if (abs(tim - now) > (365/2)*86400) + if (mtime - now > 365*86400/2 + || mtime - now < -365*86400/2) fmt = cpio->day_first ? "%d %b %Y" : "%b %d %Y"; else fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M"; #else - if (abs(tim - now) > (365/2)*86400) + if (abs(mtime - now) > (365/2)*86400) fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y"; else fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M"; #endif - strftime(date, sizeof(date), fmt, localtime(&tim)); + strftime(date, sizeof(date), fmt, localtime(&mtime)); fprintf(out, "%s%3d %-8s %-8s %8s %12s %s", archive_entry_strmode(entry), @@ -1066,7 +1030,6 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry) static void mode_pass(struct cpio *cpio, const char *destdir) { - unsigned long blocks; struct line_reader *lr; const char *p; int r; @@ -1079,28 +1042,37 @@ mode_pass(struct cpio *cpio, const char *destdir) cpio->archive = archive_write_disk_new(); if (cpio->archive == NULL) - cpio_errc(1, 0, "Failed to allocate archive object"); + errc(1, 0, "Failed to allocate archive object"); r = archive_write_disk_set_options(cpio->archive, cpio->extract_flags); if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(cpio->archive)); + errc(1, 0, "%s", archive_error_string(cpio->archive)); cpio->linkresolver = archive_entry_linkresolver_new(); archive_write_disk_set_standard_lookup(cpio->archive); - lr = process_lines_init("-", cpio->line_separator); - while ((p = process_lines_next(lr)) != NULL) + + cpio->archive_read_disk = archive_read_disk_new(); + if (cpio->archive_read_disk == NULL) + errc(1, 0, "Failed to allocate archive object"); + if (cpio->option_follow_links) + archive_read_disk_set_symlink_logical(cpio->archive_read_disk); + else + archive_read_disk_set_symlink_physical(cpio->archive_read_disk); + archive_read_disk_set_standard_lookup(cpio->archive_read_disk); + + lr = line_reader("-", cpio->option_null); + while ((p = line_reader_next(lr)) != NULL) file_to_archive(cpio, p); - process_lines_free(lr); + line_reader_free(lr); archive_entry_linkresolver_free(cpio->linkresolver); r = archive_write_close(cpio->archive); - if (cpio->dot) - fprintf(stderr, "\n"); if (r != ARCHIVE_OK) - cpio_errc(1, 0, archive_error_string(cpio->archive)); + errc(1, 0, "%s", archive_error_string(cpio->archive)); if (!cpio->quiet) { - blocks = (archive_position_uncompressed(cpio->archive) + 511) - / 512; - fprintf(stderr, "%lu %s\n", blocks, + int64_t blocks = + (archive_position_uncompressed(cpio->archive) + 511) + / 512; + fprintf(stderr, "%lu %s\n", (unsigned long)blocks, blocks == 1 ? "block" : "blocks"); } @@ -1150,130 +1122,6 @@ cpio_rename(const char *name) return (ret); } - -/* - * Read lines from file and do something with each one. If option_null - * is set, lines are terminated with zero bytes; otherwise, they're - * terminated with newlines. - * - * This uses a self-sizing buffer to handle arbitrarily-long lines. - */ -struct line_reader { - FILE *f; - char *buff, *buff_end, *line_start, *line_end, *p; - char *pathname; - size_t buff_length; - int separator; - int ret; -}; - -struct line_reader * -process_lines_init(const char *pathname, char separator) -{ - struct line_reader *lr; - - lr = calloc(1, sizeof(*lr)); - if (lr == NULL) - cpio_errc(1, ENOMEM, "Can't open %s", pathname); - - lr->separator = separator; - lr->pathname = strdup(pathname); - - if (strcmp(pathname, "-") == 0) - lr->f = stdin; - else - lr->f = fopen(pathname, "r"); - if (lr->f == NULL) - cpio_errc(1, errno, "Couldn't open %s", pathname); - lr->buff_length = 8192; - lr->buff = malloc(lr->buff_length); - if (lr->buff == NULL) - cpio_errc(1, ENOMEM, "Can't read %s", pathname); - lr->line_start = lr->line_end = lr->buff_end = lr->buff; - - return (lr); -} - -const char * -process_lines_next(struct line_reader *lr) -{ - size_t bytes_wanted, bytes_read, new_buff_size; - char *line_start, *p; - - for (;;) { - /* If there's a line in the buffer, return it immediately. */ - while (lr->line_end < lr->buff_end) { - if (*lr->line_end == lr->separator) { - *lr->line_end = '\0'; - line_start = lr->line_start; - lr->line_start = lr->line_end + 1; - lr->line_end = lr->line_start; - return (line_start); - } else - lr->line_end++; - } - - /* If we're at end-of-file, process the final data. */ - if (lr->f == NULL) { - /* If there's more text, return one last line. */ - if (lr->line_end > lr->line_start) { - *lr->line_end = '\0'; - line_start = lr->line_start; - lr->line_start = lr->line_end + 1; - lr->line_end = lr->line_start; - return (line_start); - } - /* Otherwise, we're done. */ - return (NULL); - } - - /* Buffer only has part of a line. */ - if (lr->line_start > lr->buff) { - /* Move a leftover fractional line to the beginning. */ - memmove(lr->buff, lr->line_start, - lr->buff_end - lr->line_start); - lr->buff_end -= lr->line_start - lr->buff; - lr->line_end -= lr->line_start - lr->buff; - lr->line_start = lr->buff; - } else { - /* Line is too big; enlarge the buffer. */ - new_buff_size = lr->buff_length * 2; - if (new_buff_size <= lr->buff_length) - cpio_errc(1, ENOMEM, - "Line too long in %s", lr->pathname); - lr->buff_length = new_buff_size; - p = realloc(lr->buff, new_buff_size); - if (p == NULL) - cpio_errc(1, ENOMEM, - "Line too long in %s", lr->pathname); - lr->buff_end = p + (lr->buff_end - lr->buff); - lr->line_end = p + (lr->line_end - lr->buff); - lr->line_start = lr->buff = p; - } - - /* Get some more data into the buffer. */ - bytes_wanted = lr->buff + lr->buff_length - lr->buff_end; - bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f); - lr->buff_end += bytes_read; - - if (ferror(lr->f)) - cpio_errc(1, errno, "Can't read %s", lr->pathname); - if (feof(lr->f)) { - if (lr->f != stdin) - fclose(lr->f); - lr->f = NULL; - } - } -} - -void -process_lines_free(struct line_reader *lr) -{ - free(lr->buff); - free(lr->pathname); - free(lr); -} - static void free_cache(struct name_cache *cache) { @@ -1302,7 +1150,7 @@ lookup_name(struct cpio *cpio, struct name_cache **name_cache_variable, if (*name_cache_variable == NULL) { *name_cache_variable = malloc(sizeof(struct name_cache)); if (*name_cache_variable == NULL) - cpio_errc(1, ENOMEM, "No more memory"); + errc(1, ENOMEM, "No more memory"); memset(*name_cache_variable, 0, sizeof(struct name_cache)); (*name_cache_variable)->size = name_cache_size; } @@ -1358,8 +1206,8 @@ lookup_uname_helper(struct cpio *cpio, const char **name, id_t id) pwent = getpwuid((uid_t)id); if (pwent == NULL) { *name = NULL; - if (errno != 0) - cpio_warnc(errno, "getpwuid(%d) failed", id); + if (errno != 0 && errno != ENOENT) + warnc(errno, "getpwuid(%d) failed", id); return (errno); } @@ -1386,10 +1234,34 @@ lookup_gname_helper(struct cpio *cpio, const char **name, id_t id) if (grent == NULL) { *name = NULL; if (errno != 0) - cpio_warnc(errno, "getgrgid(%d) failed", id); + warnc(errno, "getgrgid(%d) failed", id); return (errno); } *name = grent->gr_name; return (0); } + +/* + * It would be nice to just use printf() for formatting large numbers, + * but the compatibility problems are a big headache. Hence the + * following simple utility function. + */ +const char * +cpio_i64toa(int64_t n0) +{ + // 2^64 =~ 1.8 * 10^19, so 20 decimal digits suffice. + // We also need 1 byte for '-' and 1 for '\0'. + static char buff[22]; + int64_t n = n0 < 0 ? -n0 : n0; + char *p = buff + sizeof(buff); + + *--p = '\0'; + do { + *--p = '0' + (int)(n % 10); + n /= 10; + } while (n > 0); + if (n0 < 0) + *--p = '-'; + return p; +} diff --git a/usr.bin/cpio/cpio.h b/usr.bin/cpio/cpio.h index 8c1873725138..36dab55bc26f 100644 --- a/usr.bin/cpio/cpio.h +++ b/usr.bin/cpio/cpio.h @@ -31,7 +31,7 @@ #include "cpio_platform.h" #include -#define DEFAULT_BYTES_PER_BLOCK (20*512) +#include "matching.h" /* * The internal state for the "cpio" program. @@ -52,17 +52,16 @@ struct cpio { const char *format; /* -H format */ int bytes_per_block; /* -b block_size */ int verbose; /* -v */ - int dot; /* -V */ int quiet; /* --quiet */ int extract_flags; /* Flags for extract operation */ char symlink_mode; /* H or L, per BSD conventions */ const char *compress_program; - char line_separator; /* --null ? '\0' : '\n' */ int option_append; /* -A, only relevant for -o */ int option_atime_restore; /* -a */ int option_follow_links; /* -L */ int option_link; /* -l */ int option_list; /* -t */ + char option_null; /* --null */ int option_numeric_uid_gid; /* -n */ int option_rename; /* -r */ char *destdir; @@ -77,6 +76,7 @@ struct cpio { /* Miscellaneous state information */ struct archive *archive; + struct archive *archive_read_disk; int argc; char **argv; int return_value; /* Value returned by main() */ @@ -91,30 +91,19 @@ struct cpio { size_t buff_size; }; -/* Name of this program; used in error reporting, initialized in main(). */ -const char *cpio_progname; - -void cpio_errc(int _eval, int _code, const char *fmt, ...) __LA_DEAD; -void cpio_warnc(int _code, const char *fmt, ...); - -int owner_parse(const char *, int *, int *); +const char *owner_parse(const char *, int *, int *); /* Fake short equivalents for long options that otherwise lack them. */ enum { OPTION_INSECURE = 1, + OPTION_LZMA, OPTION_NO_PRESERVE_OWNER, + OPTION_PRESERVE_OWNER, OPTION_QUIET, OPTION_VERSION }; -struct line_reader; - -struct line_reader *process_lines_init(const char *, char separator); -const char *process_lines_next(struct line_reader *); -void process_lines_free(struct line_reader *); - int cpio_getopt(struct cpio *cpio); -int include_from_file(struct cpio *, const char *); #endif diff --git a/usr.bin/cpio/cpio_platform.h b/usr.bin/cpio/cpio_platform.h index 037376a8c6d8..3043828db2af 100644 --- a/usr.bin/cpio/cpio_platform.h +++ b/usr.bin/cpio/cpio_platform.h @@ -37,19 +37,18 @@ #if defined(PLATFORM_CONFIG_H) /* Use hand-built config.h in environments that need it. */ #include PLATFORM_CONFIG_H -#elif defined(HAVE_CONFIG_H) -/* Most POSIX platforms use the 'configure' script to build config.h */ -#include "config.h" #else -/* Warn if cpio hasn't been (automatically or manually) configured. */ -#error Oops: No config.h and no built-in configuration in cpio_platform.h. -#endif /* !HAVE_CONFIG_H */ +/* Read config.h or die trying. */ +#include "config.h" +#endif -/* No non-FreeBSD platform will have __FBSDID, so just define it here. */ -#ifdef __FreeBSD__ -#include /* For __FBSDID */ -#elif !defined(__FBSDID) -/* Just leaving this macro replacement empty leads to a dangling semicolon. */ +/* Get a real definition for __FBSDID if we can */ +#if HAVE_SYS_CDEFS_H +#include +#endif + +/* If not, define it so as to avoid dangling semicolons. */ +#ifndef __FBSDID #define __FBSDID(a) struct _undefined_hack #endif @@ -63,24 +62,6 @@ #include "archive_entry.h" #endif -/* - * We need to be able to display a filesize using printf(). The type - * and format string here must be compatible with one another and - * large enough for any file. - */ -#if HAVE_UINTMAX_T -#define CPIO_FILESIZE_TYPE uintmax_t -#define CPIO_FILESIZE_PRINTF "%ju" -#else -#if HAVE_UNSIGNED_LONG_LONG -#define CPIO_FILESIZE_TYPE unsigned long long -#define CPIO_FILESIZE_PRINTF "%llu" -#else -#define CPIO_FILESIZE_TYPE unsigned long -#define CPIO_FILESIZE_PRINTF "%lu" -#endif -#endif - /* How to mark functions that don't return. */ #if defined(__GNUC__) && (__GNUC__ > 2 || \ (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) @@ -89,9 +70,7 @@ #define __LA_DEAD #endif -#if defined(__CYGWIN__) -#include "cpio_cygwin.h" -#elif defined(_WIN32) /* && !__CYGWIN__ */ +#if defined(_WIN32) && !defined(__CYGWIN__) #include "cpio_windows.h" #endif diff --git a/usr.bin/cpio/err.c b/usr.bin/cpio/err.c index ad9c0e193e17..c74e097d4439 100644 --- a/usr.bin/cpio/err.c +++ b/usr.bin/cpio/err.c @@ -24,7 +24,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include "cpio_platform.h" __FBSDID("$FreeBSD$"); @@ -39,12 +38,14 @@ __FBSDID("$FreeBSD$"); #include #endif -#include "cpio.h" +#include "err.h" + +const char *progname; static void -cpio_vwarnc(int code, const char *fmt, va_list ap) +vwarnc(int code, const char *fmt, va_list ap) { - fprintf(stderr, "%s: ", cpio_progname); + fprintf(stderr, "%s: ", progname); vfprintf(stderr, fmt, ap); if (code != 0) fprintf(stderr, ": %s", strerror(code)); @@ -52,22 +53,22 @@ cpio_vwarnc(int code, const char *fmt, va_list ap) } void -cpio_warnc(int code, const char *fmt, ...) +warnc(int code, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - cpio_vwarnc(code, fmt, ap); + vwarnc(code, fmt, ap); va_end(ap); } void -cpio_errc(int eval, int code, const char *fmt, ...) +errc(int eval, int code, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - cpio_vwarnc(code, fmt, ap); + vwarnc(code, fmt, ap); va_end(ap); exit(eval); } diff --git a/usr.bin/cpio/err.h b/usr.bin/cpio/err.h new file mode 100644 index 000000000000..fe96c7012442 --- /dev/null +++ b/usr.bin/cpio/err.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2009 Joerg Sonnenberger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef LAFE_ERR_H +#define LAFE_ERR_H + +#if defined(__GNUC__) && (__GNUC__ > 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) +#define __LA_DEAD __attribute__((__noreturn__)) +#else +#define __LA_DEAD +#endif + +extern const char *progname; + +void warnc(int code, const char *fmt, ...); +void errc(int eval, int code, const char *fmt, ...) __LA_DEAD; + +#endif diff --git a/usr.bin/cpio/line_reader.c b/usr.bin/cpio/line_reader.c new file mode 100644 index 000000000000..846194131ecd --- /dev/null +++ b/usr.bin/cpio/line_reader.c @@ -0,0 +1,171 @@ +/*- + * Copyright (c) 2008 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpio_platform.h" +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include "err.h" +#include "line_reader.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) +#define strdup _strdup +#endif + +/* + * Read lines from file and do something with each one. If option_null + * is set, lines are terminated with zero bytes; otherwise, they're + * terminated with newlines. + * + * This uses a self-sizing buffer to handle arbitrarily-long lines. + */ +struct line_reader { + FILE *f; + char *buff, *buff_end, *line_start, *line_end, *p; + char *pathname; + size_t buff_length; + int nullSeparator; /* Lines separated by null, not CR/CRLF/etc. */ + int ret; +}; + +struct line_reader * +line_reader(const char *pathname, int nullSeparator) +{ + struct line_reader *lr; + + lr = calloc(1, sizeof(*lr)); + if (lr == NULL) + errc(1, ENOMEM, "Can't open %s", pathname); + + lr->nullSeparator = nullSeparator; + lr->pathname = strdup(pathname); + + if (strcmp(pathname, "-") == 0) + lr->f = stdin; + else + lr->f = fopen(pathname, "r"); + if (lr->f == NULL) + errc(1, errno, "Couldn't open %s", pathname); + lr->buff_length = 8192; + lr->buff = malloc(lr->buff_length); + if (lr->buff == NULL) + errc(1, ENOMEM, "Can't read %s", pathname); + lr->line_start = lr->line_end = lr->buff_end = lr->buff; + + return (lr); +} + +const char * +line_reader_next(struct line_reader *lr) +{ + size_t bytes_wanted, bytes_read, new_buff_size; + char *line_start, *p; + + for (;;) { + /* If there's a line in the buffer, return it immediately. */ + while (lr->line_end < lr->buff_end) { + if (lr->nullSeparator) { + if (*lr->line_end == '\0') { + line_start = lr->line_start; + lr->line_start = lr->line_end + 1; + lr->line_end = lr->line_start; + return (line_start); + } + } else if (*lr->line_end == '\x0a' || *lr->line_end == '\x0d') { + *lr->line_end = '\0'; + line_start = lr->line_start; + lr->line_start = lr->line_end + 1; + lr->line_end = lr->line_start; + if (line_start[0] != '\0') + return (line_start); + } + lr->line_end++; + } + + /* If we're at end-of-file, process the final data. */ + if (lr->f == NULL) { + /* If there's more text, return one last line. */ + if (lr->line_end > lr->line_start) { + *lr->line_end = '\0'; + line_start = lr->line_start; + lr->line_start = lr->line_end + 1; + lr->line_end = lr->line_start; + return (line_start); + } + /* Otherwise, we're done. */ + return (NULL); + } + + /* Buffer only has part of a line. */ + if (lr->line_start > lr->buff) { + /* Move a leftover fractional line to the beginning. */ + memmove(lr->buff, lr->line_start, + lr->buff_end - lr->line_start); + lr->buff_end -= lr->line_start - lr->buff; + lr->line_end -= lr->line_start - lr->buff; + lr->line_start = lr->buff; + } else { + /* Line is too big; enlarge the buffer. */ + new_buff_size = lr->buff_length * 2; + if (new_buff_size <= lr->buff_length) + errc(1, ENOMEM, + "Line too long in %s", lr->pathname); + lr->buff_length = new_buff_size; + p = realloc(lr->buff, new_buff_size); + if (p == NULL) + errc(1, ENOMEM, + "Line too long in %s", lr->pathname); + lr->buff_end = p + (lr->buff_end - lr->buff); + lr->line_end = p + (lr->line_end - lr->buff); + lr->line_start = lr->buff = p; + } + + /* Get some more data into the buffer. */ + bytes_wanted = lr->buff + lr->buff_length - lr->buff_end; + bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f); + lr->buff_end += bytes_read; + + if (ferror(lr->f)) + errc(1, errno, "Can't read %s", lr->pathname); + if (feof(lr->f)) { + if (lr->f != stdin) + fclose(lr->f); + lr->f = NULL; + } + } +} + +void +line_reader_free(struct line_reader *lr) +{ + free(lr->buff); + free(lr->pathname); + free(lr); +} diff --git a/usr.bin/cpio/line_reader.h b/usr.bin/cpio/line_reader.h new file mode 100644 index 000000000000..4f5dd6afaf0a --- /dev/null +++ b/usr.bin/cpio/line_reader.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2009 Joerg Sonnenberger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef LAFE_LINE_READER_H +#define LAFE_LINE_READER_H + +struct line_reader; + +struct line_reader *line_reader(const char *, int nullSeparator); +const char *line_reader_next(struct line_reader *); +void line_reader_free(struct line_reader *); + +#endif diff --git a/usr.bin/cpio/matching.c b/usr.bin/cpio/matching.c index 8d1798fd50ff..0fd2b6a90d11 100644 --- a/usr.bin/cpio/matching.c +++ b/usr.bin/cpio/matching.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include #endif +#include "err.h" +#include "line_reader.h" #include "matching.h" #include "pathmatch.h" @@ -54,7 +56,7 @@ struct matching { }; static void add_pattern(struct match **list, const char *pattern); -static void initialize_matching(struct cpio *); +static void initialize_matching(struct matching **); static int match_exclusion(struct match *, const char *pathname); static int match_inclusion(struct match *, const char *pathname); @@ -70,52 +72,58 @@ static int match_inclusion(struct match *, const char *pathname); */ int -exclude(struct cpio *cpio, const char *pattern) +exclude(struct matching **matching, const char *pattern) { - struct matching *matching; - if (cpio->matching == NULL) - initialize_matching(cpio); - matching = cpio->matching; - add_pattern(&(matching->exclusions), pattern); - matching->exclusions_count++; - return (0); -} - -#if 0 -int -exclude_from_file(struct cpio *cpio, const char *pathname) -{ - return (process_lines(cpio, pathname, &exclude)); -} -#endif - -int -include(struct cpio *cpio, const char *pattern) -{ - struct matching *matching; - - if (cpio->matching == NULL) - initialize_matching(cpio); - matching = cpio->matching; - add_pattern(&(matching->inclusions), pattern); - matching->inclusions_count++; - matching->inclusions_unmatched_count++; + if (*matching == NULL) + initialize_matching(matching); + add_pattern(&((*matching)->exclusions), pattern); + (*matching)->exclusions_count++; return (0); } int -include_from_file(struct cpio *cpio, const char *pathname) +exclude_from_file(struct matching **matching, const char *pathname) { struct line_reader *lr; const char *p; int ret = 0; - lr = process_lines_init(pathname, '\n'); - while ((p = process_lines_next(lr)) != NULL) - if (include(cpio, p) != 0) + lr = line_reader(pathname, 0); + while ((p = line_reader_next(lr)) != NULL) { + if (exclude(matching, p) != 0) ret = -1; - process_lines_free(lr); + } + line_reader_free(lr); + return (ret); +} + +int +include(struct matching **matching, const char *pattern) +{ + + if (*matching == NULL) + initialize_matching(matching); + add_pattern(&((*matching)->inclusions), pattern); + (*matching)->inclusions_count++; + (*matching)->inclusions_unmatched_count++; + return (0); +} + +int +include_from_file(struct matching **matching, const char *pathname, + int nullSeparator) +{ + struct line_reader *lr; + const char *p; + int ret = 0; + + lr = line_reader(pathname, nullSeparator); + while ((p = line_reader_next(lr)) != NULL) { + if (include(matching, p) != 0) + ret = -1; + } + line_reader_free(lr); return (ret); } @@ -123,15 +131,15 @@ static void add_pattern(struct match **list, const char *pattern) { struct match *match; + size_t len; - match = malloc(sizeof(*match) + strlen(pattern) + 1); + len = strlen(pattern); + match = malloc(sizeof(*match) + len + 1); if (match == NULL) - cpio_errc(1, errno, "Out of memory"); - if (pattern[0] == '/') - pattern++; + errc(1, errno, "Out of memory"); strcpy(match->pattern, pattern); /* Both "foo/" and "foo" should match "foo/bar". */ - if (match->pattern[strlen(match->pattern)-1] == '/') + if (len && match->pattern[len - 1] == '/') match->pattern[strlen(match->pattern)-1] = '\0'; match->next = *list; *list = match; @@ -140,13 +148,11 @@ add_pattern(struct match **list, const char *pattern) int -excluded(struct cpio *cpio, const char *pathname) +excluded(struct matching *matching, const char *pathname) { - struct matching *matching; struct match *match; struct match *matched; - matching = cpio->matching; if (matching == NULL) return (0); @@ -166,7 +172,7 @@ excluded(struct cpio *cpio, const char *pathname) */ if (match->matches == 0) { match->matches++; - matching->inclusions_unmatched_count++; + matching->inclusions_unmatched_count--; return (0); } /* @@ -198,7 +204,7 @@ excluded(struct cpio *cpio, const char *pathname) * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' * */ -int +static int match_exclusion(struct match *match, const char *pathname) { return (pathmatch(match->pattern, @@ -210,50 +216,69 @@ match_exclusion(struct match *match, const char *pathname) * Again, mimic gtar: inclusions are always anchored (have to match * the beginning of the path) even though exclusions are not anchored. */ -int +static int match_inclusion(struct match *match, const char *pathname) { +#if 0 return (pathmatch(match->pattern, pathname, 0)); +#else + return (pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END)); +#endif } void -cleanup_exclusions(struct cpio *cpio) +cleanup_exclusions(struct matching **matching) { struct match *p, *q; - if (cpio->matching) { - p = cpio->matching->inclusions; - while (p != NULL) { - q = p; - p = p->next; - free(q); - } - p = cpio->matching->exclusions; - while (p != NULL) { - q = p; - p = p->next; - free(q); - } - free(cpio->matching); + if (*matching == NULL) + return; + + for (p = (*matching)->inclusions; p != NULL; ) { + q = p; + p = p->next; + free(q); } + + for (p = (*matching)->exclusions; p != NULL; ) { + q = p; + p = p->next; + free(q); + } + + free(*matching); + *matching = NULL; } static void -initialize_matching(struct cpio *cpio) +initialize_matching(struct matching **matching) { - cpio->matching = malloc(sizeof(*cpio->matching)); - if (cpio->matching == NULL) - cpio_errc(1, errno, "No memory"); - memset(cpio->matching, 0, sizeof(*cpio->matching)); + *matching = calloc(sizeof(**matching), 1); + if (*matching == NULL) + errc(1, errno, "No memory"); } int -unmatched_inclusions(struct cpio *cpio) +unmatched_inclusions(struct matching *matching) { - struct matching *matching; - matching = cpio->matching; if (matching == NULL) return (0); return (matching->inclusions_unmatched_count); } + +int +unmatched_inclusions_warn(struct matching *matching, const char *msg) +{ + struct match *p; + + if (matching == NULL) + return (0); + + for (p = matching->inclusions; p != NULL; p = p->next) { + if (p->matches == 0) + warnc(0, "%s: %s", p->pattern, msg); + } + + return (matching->inclusions_unmatched_count); +} diff --git a/usr.bin/cpio/matching.h b/usr.bin/cpio/matching.h index a66bc86bc73d..e98e82e9c025 100644 --- a/usr.bin/cpio/matching.h +++ b/usr.bin/cpio/matching.h @@ -29,12 +29,18 @@ #ifndef MATCHING_H #define MATCHING_H -#include "cpio.h" +struct matching; -int exclude(struct cpio *, const char *pattern); -int include(struct cpio *, const char *pattern); -int excluded(struct cpio *cpio, const char *pathname); -void cleanup_exclusions(struct cpio *cpio); -int unmatched_inclusions(struct cpio *cpio); +int exclude(struct matching **matching, const char *pattern); +int exclude_from_file(struct matching **matching, + const char *pathname); +int include(struct matching **matching, const char *pattern); +int include_from_file(struct matching **matching, + const char *pathname, int nullSeparator); + +int excluded(struct matching *, const char *pathname); +void cleanup_exclusions(struct matching **); +int unmatched_inclusions(struct matching *); +int unmatched_inclusions_warn(struct matching *, const char *msg); #endif diff --git a/usr.bin/cpio/pathmatch.c b/usr.bin/cpio/pathmatch.c index 40fa836041b0..75f9095af014 100644 --- a/usr.bin/cpio/pathmatch.c +++ b/usr.bin/cpio/pathmatch.c @@ -131,7 +131,6 @@ pm(const char *p, const char *s, int flags) s = pm_slashskip(s); } return (*s == '\0'); - break; case '?': /* ? always succeds, unless we hit end of 's' */ if (*s == '\0') @@ -150,7 +149,6 @@ pm(const char *p, const char *s, int flags) ++s; } return (0); - break; case '[': /* * Find the end of the [...] character class, @@ -229,9 +227,17 @@ pathmatch(const char *p, const char *s, int flags) flags &= ~PATHMATCH_NO_ANCHOR_START; } - /* Certain patterns anchor implicitly. */ - if (*p == '*' || *p == '/') + if (*p == '/' && *s != '/') + return (0); + + /* Certain patterns and file names anchor implicitly. */ + if (*p == '*' || *p == '/' || *p == '/') { + while (*p == '/') + ++p; + while (*s == '/') + ++s; return (pm(p, s, flags)); + } /* If start is unanchored, try to match start of each path element. */ if (flags & PATHMATCH_NO_ANCHOR_START) { diff --git a/usr.bin/cpio/pathmatch.h b/usr.bin/cpio/pathmatch.h index fd2c2575cc0a..3e82830b4561 100644 --- a/usr.bin/cpio/pathmatch.h +++ b/usr.bin/cpio/pathmatch.h @@ -26,13 +26,13 @@ * $FreeBSD$ */ -#ifndef PATHMATCH_H -#define PATHMATCH_H +#ifndef LAFE_PATHMATCH_H +#define LAFE_PATHMATCH_H /* Don't anchor at beginning unless the pattern starts with "^" */ #define PATHMATCH_NO_ANCHOR_START 1 /* Don't anchor at end unless the pattern ends with "$" */ -#define PATHMATCH_NO_ANCHOR_END 2 +#define PATHMATCH_NO_ANCHOR_END 2 /* Note that "^" and "$" are not special unless you set the corresponding * flag above. */