diff options
Diffstat (limited to 'contrib/archivetest.c')
-rw-r--r-- | contrib/archivetest.c | 125 |
1 files changed, 101 insertions, 24 deletions
diff --git a/contrib/archivetest.c b/contrib/archivetest.c index 2d81d3ee..f4a469b4 100644 --- a/contrib/archivetest.c +++ b/contrib/archivetest.c @@ -24,7 +24,7 @@ */ /* - * This utility tests parsing files by libarchive + * Archivetest verifies reading archives with libarchive * * It may be used to reproduce failures in testcases discovered by OSS-Fuzz * https://github.com/google/oss-fuzz/blob/master/projects/libarchive @@ -32,6 +32,8 @@ #include <stdio.h> #include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> #include <archive.h> #include <archive_entry.h> @@ -64,6 +66,38 @@ const char *errnostr(int errno) return (estr); } +void usage(const char *prog) +{ + fprintf(stderr, "Usage: %s [-f filename] [-h] [-q] [-s]\n", prog); +} + +void printhelp() +{ + fprintf(stdout, "archivetest: verify reading archives with " + "libarchive\n\n" + "Options:\n" + " -f filename Filename to verify\n" + " -h Show this help\n" + " -q Quiet mode\n" + " -s Verify only headers (skip data)\n\n" + "If no filename is specified, data is read from standard input.\n" + "\n%s\n", archive_version_details()); +} + +int v_print(int verbose, const char *format, ...) +{ + int r = 0; + + if (verbose) { + va_list args; + + va_start(args, format); + r = vfprintf(stdout, format, args); + va_end(args); + } + return (r); +} + int main(int argc, char *argv[]) { struct archive *a; @@ -72,39 +106,77 @@ int main(int argc, char *argv[]) const char *p; char buffer[4096]; int c; + int v, skip_data; int r = ARCHIVE_OK; int format_printed; - if (argc != 2) { - fprintf(stderr, "Usage: %s filename\n", argv[0]); - exit(1); - } + filename = NULL; + skip_data = 0; + v = 1; - filename = argv[1]; + while ((c = getopt (argc, argv, "f:hqs")) != -1) { + switch (c) { + case 'f': + filename = optarg; + break; + case 'h': + printhelp(); + exit(0); + case 'q': + v = 0; + break; + case 's': + skip_data = 1; + break; + case '?': + if (optopt == 'f') + fprintf(stderr, "Option -%c requires " + "an argument.\n", optopt); + else if (isprint(optopt)) + fprintf(stderr, "Unknown option '-%c'" + ".\n", optopt); + else + fprintf(stderr, "Unknown option " + "character '\\x%x'.\n", optopt); + usage(argv[0]); + default: + exit(1); + } + } a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); - r = archive_read_open_filename(a, filename, 4096); + v_print(v, "Data source: "); + + if (filename == NULL) { + v_print(v, "standard input\n"); + r = archive_read_open_fd(a, STDIN_FILENO, 4096); + } else { + v_print(v, "filename: %s\n", filename); + r = archive_read_open_filename(a, filename, 4096); + } + if (r != ARCHIVE_OK) { archive_read_free(a); - fprintf(stderr, "Error opening filename: %s\n", filename); - exit(ARCHIVE_FATAL); + fprintf(stderr, "Invalid or unsupported data source\n"); + exit(1); } format_printed = 0; c = 1; + while (1) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_FATAL) { - fprintf(stdout, - "Entry %d: fatal error reding header\n", c); + v_print(v, "Entry %d: fatal error reading " + "header\n", c); break; } if (!format_printed) { - fprintf(stdout, "Filter: %s\nFormat: %s\n", + v_print(v, "Filter: %s\nFormat: %s\n", archive_filter_name(a, 0), archive_format_name(a)); format_printed = 1; } @@ -113,25 +185,30 @@ int main(int argc, char *argv[]) if (r == ARCHIVE_EOF) break; p = archive_entry_pathname(entry); + v_print(v, "Entry %d: %s, pathname", c, errnostr(r)); if (p == NULL || p[0] == '\0') - fprintf(stdout, "Entry %d: %s, ureadable pathname\n", - c, errnostr(r)); + v_print(v, " unreadable"); else - fprintf(stdout, "Entry %d: %s, pathname: %s\n", c, - errnostr(r), p); - while ((r = archive_read_data(a, buffer, 4096) > 0)) - ; - if (r == ARCHIVE_FATAL) { - fprintf(stderr, "Entry %d: fatal error reading data\n", - c); - break; + v_print(v, ": %s", p); + v_print(v, ", data: "); + if (skip_data) { + v_print(v, "skipping"); + } else { + while ((r = archive_read_data(a, buffer, 4096) > 0)) + ; + if (r == ARCHIVE_FATAL) { + v_print(v, "ERROR\n"); + break; + } + v_print(v, "OK"); } + v_print(v, "\n"); c++; } archive_read_free(a); - fprintf(stdout, "Last return code: %s (%d)\n", errnostr(r), r); + v_print(v, "Last return code: %s (%d)\n", errnostr(r), r); if (r == ARCHIVE_EOF || r == ARCHIVE_OK) exit(0); - exit(1); + exit(2); } |