diff options
Diffstat (limited to 'archivers/libarchive/files/cpio')
-rw-r--r-- | archivers/libarchive/files/cpio/cmdline.c | 13 | ||||
-rw-r--r-- | archivers/libarchive/files/cpio/cpio.c | 206 | ||||
-rw-r--r-- | archivers/libarchive/files/cpio/cpio.h | 12 | ||||
-rw-r--r-- | archivers/libarchive/files/cpio/matching.c | 13 | ||||
-rw-r--r-- | archivers/libarchive/files/cpio/test/main.c | 53 | ||||
-rw-r--r-- | archivers/libarchive/files/cpio/test/test.h | 39 |
6 files changed, 243 insertions, 93 deletions
diff --git a/archivers/libarchive/files/cpio/cmdline.c b/archivers/libarchive/files/cpio/cmdline.c index 4b337279271..a602e39c179 100644 --- a/archivers/libarchive/files/cpio/cmdline.c +++ b/archivers/libarchive/files/cpio/cmdline.c @@ -26,7 +26,7 @@ #include "cpio_platform.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/cmdline.c,v 1.3 2008/06/21 02:20:20 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include <errno.h> @@ -66,7 +66,7 @@ struct option { */ -static const char *cpio_opts = "AaBC:F:O:cdE:f:H:hijLlmopR:rtuvW:yZz"; +static const char *cpio_opts = "0AaBC:F:O:cdE:f:H:hijLlmopR:rtuvW:yZz"; /* * On systems that lack getopt_long, long options can be specified @@ -82,12 +82,21 @@ static const char *cpio_opts = "AaBC:F:O:cdE:f:H:hijLlmopR:rtuvW:yZz"; * sorted, as the -W logic below relies on it. */ static const struct option cpio_longopts[] = { + { "create", no_argument, NULL, 'o' }, + { "extract", no_argument, NULL, 'i' }, { "file", required_argument, NULL, 'F' }, { "format", required_argument, NULL, 'H' }, { "help", no_argument, NULL, 'h' }, { "insecure", no_argument, NULL, OPTION_INSECURE }, + { "link", no_argument, NULL, 'l' }, + { "list", no_argument, NULL, 't' }, + { "make-directories", no_argument, NULL, 'd' }, + { "null", no_argument, NULL, '0' }, { "owner", required_argument, NULL, 'R' }, + { "pass-through", no_argument, NULL, 'p' }, + { "preserve-modification-time", no_argument, NULL, 'm' }, { "quiet", no_argument, NULL, OPTION_QUIET }, + { "unconditional", no_argument, NULL, 'u' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, OPTION_VERSION }, { NULL, 0, NULL, 0 } diff --git a/archivers/libarchive/files/cpio/cpio.c b/archivers/libarchive/files/cpio/cpio.c index 1d78ce1266f..76a91cf7152 100644 --- a/archivers/libarchive/files/cpio/cpio.c +++ b/archivers/libarchive/files/cpio/cpio.c @@ -26,7 +26,7 @@ #include "cpio_platform.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.4 2008/06/24 15:18:40 kientzle Exp $"); #include <sys/types.h> #include <archive.h> @@ -101,6 +101,7 @@ main(int argc, char *argv[]) cpio->gid_override = -1; cpio->argv = argv; cpio->argc = argc; + cpio->line_separator = '\n'; cpio->mode = '\0'; cpio->verbose = 0; cpio->compress = '\0'; @@ -116,6 +117,9 @@ main(int argc, char *argv[]) while ((opt = cpio_getopt(cpio)) != -1) { switch (opt) { + case '0': /* GNU convention: --null, -0 */ + cpio->line_separator = '\0'; + break; case 'A': /* NetBSD/OpenBSD */ cpio->option_append = 1; break; @@ -178,6 +182,7 @@ main(int argc, char *argv[]) break; case 'p': /* POSIX 1997 */ cpio->mode = opt; + cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; break; case OPTION_QUIET: /* GNU cpio */ cpio->quiet = 1; @@ -341,8 +346,10 @@ version(void) static void mode_out(struct cpio *cpio) { - struct archive_entry *entry, *spare; unsigned long blocks; + struct archive_entry *entry, *spare; + struct line_reader *lr; + const char *p; int r; if (cpio->option_append) @@ -375,7 +382,10 @@ mode_out(struct cpio *cpio) r = archive_write_open_file(cpio->archive, cpio->filename); if (r != ARCHIVE_OK) cpio_errc(1, 0, archive_error_string(cpio->archive)); - process_lines(cpio, "-", file_to_archive); + lr = process_lines_init("-", cpio->line_separator); + while ((p = process_lines_next(lr)) != NULL) + file_to_archive(cpio, p); + process_lines_free(lr); /* * The hardlink detection may have queued up a couple of entries @@ -525,17 +535,42 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) fprintf(stderr,"%s", destpath); /* - * Obviously, this only gets invoked in pass mode. + * Option_link only makes sense in pass mode and for + * regular files. Also note: if a link operation fails + * because of cross-device restrictions, we'll fall back + * to copy mode for that entry. + * + * TODO: Test other cpio implementations to see if they + * hard-link anything other than regular files here. */ - if (cpio->option_link) { - /* Note: link(2) doesn't create parent directories. */ - archive_entry_set_hardlink(entry, srcpath); - r = archive_write_header(cpio->archive, entry); + if (cpio->option_link + && archive_entry_filetype(entry) == AE_IFREG) + { + struct archive_entry *t; + /* 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"); + /* Note: link(2) doesn't create parent directories, + * so we use archive_write_header() instead as a + * convenience. */ + archive_entry_set_hardlink(t, srcpath); + /* This is a straight link that carries no data. */ + archive_entry_set_size(t, 0); + 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)); 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"); + } else +#endif return (0); } @@ -793,6 +828,8 @@ mode_list(struct cpio *cpio) static void mode_pass(struct cpio *cpio, const char *destdir) { + struct line_reader *lr; + const char *p; int r; /* Ensure target dir has a trailing '/' to simplify path surgery. */ @@ -809,7 +846,10 @@ mode_pass(struct cpio *cpio, const char *destdir) cpio_errc(1, 0, archive_error_string(cpio->archive)); cpio->linkresolver = archive_entry_linkresolver_new(); archive_write_disk_set_standard_lookup(cpio->archive); - process_lines(cpio, "-", file_to_archive); + lr = process_lines_init("-", cpio->line_separator); + while ((p = process_lines_next(lr)) != NULL) + file_to_archive(cpio, p); + process_lines_free(lr); archive_entry_linkresolver_free(cpio->linkresolver); r = archive_write_close(cpio->archive); @@ -868,79 +908,119 @@ cpio_rename(const char *name) * terminated with newlines. * * This uses a self-sizing buffer to handle arbitrarily-long lines. - * If the "process" function returns non-zero for any line, this - * function will return non-zero after attempting to process all - * remaining lines. */ -int -process_lines(struct cpio *cpio, const char *pathname, - int (*process)(struct cpio *, const char *)) -{ +struct line_reader { FILE *f; char *buff, *buff_end, *line_start, *line_end, *p; - size_t buff_length, bytes_read, bytes_wanted; + 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); - separator = cpio->option_null ? '\0' : '\n'; - ret = 0; + lr->separator = separator; + lr->pathname = strdup(pathname); if (strcmp(pathname, "-") == 0) - f = stdin; + lr->f = stdin; else - f = fopen(pathname, "r"); - if (f == NULL) + lr->f = fopen(pathname, "r"); + if (lr->f == NULL) cpio_errc(1, errno, "Couldn't open %s", pathname); - buff_length = 8192; - buff = malloc(buff_length); - if (buff == NULL) + lr->buff_length = 8192; + lr->buff = malloc(lr->buff_length); + if (lr->buff == NULL) cpio_errc(1, ENOMEM, "Can't read %s", pathname); - line_start = line_end = buff_end = buff; + 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 (;;) { - /* Get some more data into the buffer. */ - bytes_wanted = buff + buff_length - buff_end; - bytes_read = fread(buff_end, 1, bytes_wanted, f); - buff_end += bytes_read; - /* Process all complete lines in the buffer. */ - while (line_end < buff_end) { - if (*line_end == separator) { - *line_end = '\0'; - if ((*process)(cpio, line_start) != 0) - ret = -1; - line_start = line_end + 1; - line_end = line_start; + /* 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 - line_end++; + lr->line_end++; } - if (feof(f)) - break; - if (ferror(f)) - cpio_errc(1, errno, "Can't read %s", pathname); - if (line_start > buff) { + + /* 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(buff, line_start, buff_end - line_start); - buff_end -= line_start - buff; - line_end -= line_start - buff; - line_start = buff; + 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. */ - p = realloc(buff, buff_length *= 2); + 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", pathname); - buff_end = p + (buff_end - buff); - line_end = p + (line_end - buff); - line_start = buff = p; + "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; } } - /* At end-of-file, handle the final line. */ - if (line_end > line_start) { - *line_end = '\0'; - if ((*process)(cpio, line_start) != 0) - ret = -1; - } - free(buff); - if (f != stdin) - fclose(f); - return (ret); +} + +void +process_lines_free(struct line_reader *lr) +{ + free(lr->buff); + free(lr->pathname); + free(lr); } diff --git a/archivers/libarchive/files/cpio/cpio.h b/archivers/libarchive/files/cpio/cpio.h index ecec2eeec8e..3afd9520309 100644 --- a/archivers/libarchive/files/cpio/cpio.h +++ b/archivers/libarchive/files/cpio/cpio.h @@ -22,7 +22,7 @@ * (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$ + * $FreeBSD: src/usr.bin/cpio/cpio.h,v 1.2 2008/06/21 02:20:20 kientzle Exp $ */ #ifndef CPIO_H_INCLUDED @@ -53,12 +53,12 @@ struct cpio { 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 */ - int option_null; /* -0 --null */ int option_rename; /* -r */ char *destdir; size_t pass_destpath_alloc; @@ -98,9 +98,13 @@ enum { 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 process_lines(struct cpio *cpio, const char *pathname, - int (*process)(struct cpio *, const char *)); int include_from_file(struct cpio *, const char *); #endif diff --git a/archivers/libarchive/files/cpio/matching.c b/archivers/libarchive/files/cpio/matching.c index f98421e2df4..3e4ddc3bfdb 100644 --- a/archivers/libarchive/files/cpio/matching.c +++ b/archivers/libarchive/files/cpio/matching.c @@ -24,7 +24,7 @@ */ #include "cpio_platform.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/matching.c,v 1.2 2008/06/21 02:20:20 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include <errno.h> @@ -107,7 +107,16 @@ include(struct cpio *cpio, const char *pattern) int include_from_file(struct cpio *cpio, const char *pathname) { - return (process_lines(cpio, pathname, &include)); + 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) + ret = -1; + process_lines_free(lr); + return (ret); } static void diff --git a/archivers/libarchive/files/cpio/test/main.c b/archivers/libarchive/files/cpio/test/main.c index c88dd2ac341..e0f8c2e1175 100644 --- a/archivers/libarchive/files/cpio/test/main.c +++ b/archivers/libarchive/files/cpio/test/main.c @@ -27,13 +27,13 @@ * Various utility routines useful for test programs. * Each test program is linked against this file. */ +#include "test.h" + #include <errno.h> #include <locale.h> #include <stdarg.h> #include <time.h> -#include "test.h" - /* * This same file is used pretty much verbatim for all test harnesses. * @@ -44,7 +44,7 @@ #undef EXTRA_DUMP /* How to dump extra data */ /* How to generate extra version info. */ #define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.2 2008/06/21 02:17:18 kientzle Exp $"); /* * "list.h" is simply created by "grep DEFINE_TEST"; it has @@ -541,6 +541,48 @@ test_assert_equal_file(const char *f1, const char *f2pattern, ...) return (0); } +int +test_assert_file_exists(const char *fpattern, ...) +{ + char f[1024]; + va_list ap; + + va_start(ap, fpattern); + vsprintf(f, fpattern, ap); + va_end(ap); + + if (!access(f, F_OK)) + return (1); + if (!previous_failures(test_filename, test_line)) { + fprintf(stderr, "%s:%d: File doesn't exist\n", + test_filename, test_line); + fprintf(stderr, " file=\"%s\"\n", f); + report_failure(test_extra); + } + return (0); +} + +int +test_assert_file_not_exists(const char *fpattern, ...) +{ + char f[1024]; + va_list ap; + + va_start(ap, fpattern); + vsprintf(f, fpattern, ap); + va_end(ap); + + if (access(f, F_OK)) + return (1); + if (!previous_failures(test_filename, test_line)) { + fprintf(stderr, "%s:%d: File exists and shouldn't\n", + test_filename, test_line); + fprintf(stderr, " file=\"%s\"\n", f); + report_failure(test_extra); + } + return (0); +} + /* assertFileContents() asserts the contents of a file. */ int test_assert_file_contents(const void *buff, int s, const char *fpattern, ...) @@ -670,8 +712,11 @@ static int test_run(int i, const char *tmpdir) { int failures_before = failures; - if (!quiet_flag) + if (!quiet_flag) { printf("%d: %s\n", i, tests[i].name); + fflush(stdout); + } + /* * Always explicitly chdir() in case the last test moved us to * a strange place. diff --git a/archivers/libarchive/files/cpio/test/test.h b/archivers/libarchive/files/cpio/test/test.h index 06e6d903fc8..431d5d7c4d5 100644 --- a/archivers/libarchive/files/cpio/test/test.h +++ b/archivers/libarchive/files/cpio/test/test.h @@ -22,7 +22,7 @@ * (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$ + * $FreeBSD: src/usr.bin/cpio/test/test.h,v 1.2 2008/06/21 02:17:18 kientzle Exp $ */ /* Every test program should #include "test.h" as the first thing. */ @@ -31,8 +31,18 @@ * The goal of this file (and the matching test.c) is to * simplify the very repetitive test-*.c test programs. */ -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 +#if defined(HAVE_CONFIG_H) +/* Most POSIX platforms use the 'configure' script to build config.h */ +#include "../../config.h" +#elif defined(__FreeBSD__) +/* Building as part of FreeBSD system requires a pre-built config.h. */ +#include "../config_freebsd.h" +#elif defined(_WIN32) +/* Win32 can't run the 'configure' script. */ +#include "../config_windows.h" +#else +/* Warn if the library hasn't been (automatically or manually) configured. */ +#error Oops: No config.h and no pre-built configuration in test.h. #endif #include <dirent.h> @@ -51,20 +61,6 @@ #include <dmalloc.h> #endif -#if defined(HAVE_CONFIG_H) -/* Most POSIX platforms use the 'configure' script to build config.h */ -#include "../../config.h" -#elif defined(__FreeBSD__) -/* Building as part of FreeBSD system requires a pre-built config.h. */ -#include "../config_freebsd.h" -#elif defined(_WIN32) -/* Win32 can't run the 'configure' script. */ -#include "../config_windows.h" -#else -/* Warn if the library hasn't been (automatically or manually) configured. */ -#error Oops: No config.h and no pre-built configuration in test.h. -#endif - /* No non-FreeBSD platform will have __FBSDID, so just define it here. */ #ifdef __FreeBSD__ #include <sys/cdefs.h> /* For __FBSDID */ @@ -102,6 +98,12 @@ /* Assert that a file is empty; supports printf-style arguments. */ #define assertEmptyFile \ test_setup(__FILE__, __LINE__);test_assert_empty_file +/* Assert that a file exists; supports printf-style arguments. */ +#define assertFileExists \ + test_setup(__FILE__, __LINE__);test_assert_file_exists +/* Assert that a file exists; supports printf-style arguments. */ +#define assertFileNotExists \ + test_setup(__FILE__, __LINE__);test_assert_file_not_exists /* Assert that file contents match a string; supports printf-style arguments. */ #define assertFileContents \ test_setup(__FILE__, __LINE__);test_assert_file_contents @@ -127,6 +129,8 @@ int test_assert_equal_string(const char *, int, const char *v1, const char *, co int test_assert_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); int test_assert_equal_mem(const char *, int, const char *, const char *, const char *, const char *, size_t, const char *, void *); int test_assert_file_contents(const void *, int, const char *, ...); +int test_assert_file_exists(const char *, ...); +int test_assert_file_not_exists(const char *, ...); /* Like sprintf, then system() */ int systemf(const char * fmt, ...); @@ -144,4 +148,3 @@ void extract_reference_file(const char *); /* Pathname of exe to be tested. */ char *testprog; - |