diff options
Diffstat (limited to 'test/ar/plugin/ardiff.c')
-rw-r--r-- | test/ar/plugin/ardiff.c | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/test/ar/plugin/ardiff.c b/test/ar/plugin/ardiff.c new file mode 100644 index 0000000000000..e54f6a9f6cdc0 --- /dev/null +++ b/test/ar/plugin/ardiff.c @@ -0,0 +1,254 @@ +/* Selectively compare two ar archives. + * Usage: + * ardiff [-ni] [-t name] ar1 ar2 + * Options: + * -c compare member content. (This implies -s) + * -n compare member name. + * -i compare member mtime. + * -l compare archive length (member count). + * -s compare member size. + * -t specify the test name. + * + * By default, it compares nothing and consider the test "not ok" + * iff it encounters errors while reading archive. + * + * $Id: ardiff.c 2142 2011-11-10 15:29:59Z jkoshy $ + */ + +#include <archive.h> +#include <archive_entry.h> +#include <err.h> +#include <errno.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define COUNTER "/tmp/bsdar-test-total" +#define PASSED "/tmp/bsdar-test-passed" + +static void usage(void); +static void filediff(const char *tc, const char *msg, const char *e); +static void filesame(const char *tc); +static void incct(const char *pathname); + +int +main(int argc, char **argv) +{ + struct archive *a1; + struct archive *a2; + struct archive_entry *e1; + struct archive_entry *e2; + const char *tc; + char *buf1; + char *buf2; + char checkcont; + char checklen; + char checkname; + char checksize; + char checktime; + char a1end; + ssize_t size1; + ssize_t size2; + char opt; + int r; + + /* + * Parse command line options. + */ + checkcont = 0; + checklen = 0; + checkname = 0; + checksize = 0; + checktime = 0; + tc = NULL; + while ((opt = getopt(argc, argv, "cilnst:")) != -1) { + switch(opt) { + case 'c': + checkcont = 1; + break; + case 'i': + checktime = 1; + break; + case 'l': + checklen = 1; + break; + case 'n': + checkname = 1; + break; + case 's': + checksize = 1; + case 't': + tc = optarg; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc != 2) + usage(); + + /* Open file 1 */ + a1 = archive_read_new(); + archive_read_support_compression_none(a1); + archive_read_support_format_ar(a1); + if (archive_read_open_file(a1, argv[0], + 1024*10)) { + warnx("%s", archive_error_string(a1)); + filediff(tc, "archive open failed", NULL); + } + + /* Open file 2 */ + a2 = archive_read_new(); + archive_read_support_compression_none(a2); + archive_read_support_format_ar(a2); + if (archive_read_open_file(a2, argv[1], + 1024*10)) { + warnx("%s", archive_error_string(a2)); + filediff(tc, "archive open failed", NULL); + } + + /* Main loop */ + a1end = 0; + size1 = 0; + size2 = 0; + for (;;) { + /* + * Read header from each archive, compare length. + */ + r = archive_read_next_header(a1, &e1); + if (r == ARCHIVE_EOF) + a1end = 1; + if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || + r == ARCHIVE_FATAL) { + warnx("%s", archive_error_string(a1)); + filediff(tc, "archive data error", NULL); + } + r = archive_read_next_header(a2, &e2); + if (r == ARCHIVE_EOF) { + if (a1end > 0) + break; + else { + if (checklen) + filediff(tc, "length differ", NULL); + break; + } + } + if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || + r == ARCHIVE_FATAL) { + warnx("%s", archive_error_string(a2)); + filediff(tc, "archive data error", NULL); + } + if (a1end > 0) { + if (checklen) + filediff(tc, "length differ", NULL); + break; + } + + /* + * Check member name if required. + */ + if (checkname) { + if (strcmp(archive_entry_pathname(e1), + archive_entry_pathname(e2)) != 0) + filediff(tc, "member name differ", + archive_entry_pathname(e1)); + } + + /* + * Compare time if required. + */ + if (checktime) { + if (archive_entry_mtime(e1) != + archive_entry_mtime(e2)) + filediff(tc, "member mtime differ", + archive_entry_pathname(e1)); + } + + /* + * Compare member size if required. + */ + if (checksize || checkcont) { + size1 = archive_entry_size(e1); + size2 = archive_entry_size(e2); + if (size1 != size2) + filediff(tc, "member size differ", + archive_entry_pathname(e1)); + } + + /* + * Compare member content if required. + */ + if (checkcont) { + if ((buf1 = malloc(size1)) == NULL) + filediff(tc, "not enough memory", NULL); + if ((buf2 = malloc(size2)) == NULL) + filediff(tc, "not enough memory", NULL); + if (archive_read_data(a1, buf1, size1) != size1) + filediff(tc, "archive_read_data failed", + archive_entry_pathname(e1)); + if (archive_read_data(a2, buf2, size2) != size2) + filediff(tc, "archive_read_data failed", + archive_entry_pathname(e1)); + if (memcmp(buf1, buf2, size1) != 0) + filediff(tc, "member content differ", + archive_entry_pathname(e1)); + free(buf1); + free(buf2); + } + + /* Proceed to next header. */ + } + + /* Passed! */ + filesame(tc); + exit(EXIT_SUCCESS); +} + +static void +filediff(const char *tc, const char *msg, const char *e) +{ + if (e != NULL) + fprintf(stdout, "%s - archive diff not ok (%s (entry: %s))\n", + tc, msg, e); + else + fprintf(stdout, "%s - archive diff not ok (%s)\n", tc, msg); + + incct(COUNTER); + exit(EXIT_SUCCESS); +} + +static void +filesame(const char *tc) +{ + fprintf(stdout, "%s - archive diff ok\n", tc); + incct(COUNTER); + incct(PASSED); +} + +static void +incct(const char *pathname) +{ + FILE *fp; + char buf[10], *_buf; + + if ((fp = fopen(pathname, "r")) != NULL) { + _buf = fgets(buf, 10, fp); + snprintf(buf, 10, "%d\n", atoi(buf) + 1); + fclose(fp); + } + if ((fp = fopen(pathname, "w")) != NULL) { + fputs(buf, fp); + fclose(fp); + } +} + +static void +usage(void) +{ + fprintf(stderr, "usage: ardiff archive1 archive2\n"); + exit(EXIT_FAILURE); +} |