archivetest.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*-
  2. * Copyright (c) 2019 Martin Matuska
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. /*
  26. * Archivetest verifies reading archives with libarchive
  27. *
  28. * It may be used to reproduce failures in testcases discovered by OSS-Fuzz
  29. * https://github.com/google/oss-fuzz/blob/master/projects/libarchive
  30. */
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <stdarg.h>
  34. #include <ctype.h>
  35. #include <archive.h>
  36. #include <archive_entry.h>
  37. #if defined __MINGW32__
  38. #include <getopt.h>
  39. #endif
  40. static const char *errnostr(int e)
  41. {
  42. char *estr;
  43. switch(e) {
  44. case ARCHIVE_EOF:
  45. estr = "ARCHIVE_EOF";
  46. break;
  47. case ARCHIVE_OK:
  48. estr = "ARCHIVE_OK";
  49. break;
  50. case ARCHIVE_WARN:
  51. estr = "ARCHIVE_WARN";
  52. break;
  53. case ARCHIVE_RETRY:
  54. estr = "ARCHIVE_RETRY";
  55. break;
  56. case ARCHIVE_FAILED:
  57. estr = "ARCHIVE_FAILED";
  58. break;
  59. case ARCHIVE_FATAL:
  60. estr = "ARCHIVE_FATAL";
  61. break;
  62. default:
  63. estr = "Unknown";
  64. break;
  65. }
  66. return (estr);
  67. }
  68. static void usage(const char *prog)
  69. {
  70. fprintf(stderr, "Usage: %s [-f filename] [-h] [-q] [-s]\n", prog);
  71. }
  72. static void printhelp()
  73. {
  74. fprintf(stdout, "archivetest: verify reading archives with "
  75. "libarchive\n\n"
  76. "Options:\n"
  77. " -f filename Filename to verify\n"
  78. " -h Show this help\n"
  79. " -q Quiet mode\n"
  80. " -s Verify only headers (skip data)\n\n"
  81. "If no filename is specified, data is read from standard input.\n"
  82. "\n%s\n", archive_version_details());
  83. }
  84. static int v_print(int verbose, const char *format, ...)
  85. {
  86. int r = 0;
  87. if (verbose) {
  88. va_list args;
  89. va_start(args, format);
  90. r = vfprintf(stdout, format, args);
  91. va_end(args);
  92. }
  93. return (r);
  94. }
  95. int main(int argc, char *argv[])
  96. {
  97. struct archive *a;
  98. struct archive_entry *entry;
  99. char *filename;
  100. const char *p;
  101. char buffer[4096];
  102. int c;
  103. int v, skip_data;
  104. int r = ARCHIVE_OK;
  105. int format_printed;
  106. filename = NULL;
  107. skip_data = 0;
  108. v = 1;
  109. while ((c = getopt (argc, argv, "f:hqs")) != -1) {
  110. switch (c) {
  111. case 'f':
  112. filename = optarg;
  113. break;
  114. case 'h':
  115. printhelp();
  116. exit(0);
  117. case 'q':
  118. v = 0;
  119. break;
  120. case 's':
  121. skip_data = 1;
  122. break;
  123. case '?':
  124. if (optopt == 'f')
  125. fprintf(stderr, "Option -%c requires "
  126. "an argument.\n", optopt);
  127. else if (isprint(optopt))
  128. fprintf(stderr, "Unknown option '-%c'"
  129. ".\n", optopt);
  130. else
  131. fprintf(stderr, "Unknown option "
  132. "character '\\x%x'.\n", optopt);
  133. usage(argv[0]);
  134. exit(1);
  135. break;
  136. default:
  137. exit(1);
  138. }
  139. }
  140. a = archive_read_new();
  141. archive_read_support_filter_all(a);
  142. archive_read_support_format_all(a);
  143. v_print(v, "Data source: ");
  144. if (filename == NULL) {
  145. v_print(v, "standard input\n");
  146. r = archive_read_open_fd(a, STDIN_FILENO, 4096);
  147. } else {
  148. v_print(v, "filename: %s\n", filename);
  149. r = archive_read_open_filename(a, filename, 4096);
  150. }
  151. if (r != ARCHIVE_OK) {
  152. archive_read_free(a);
  153. fprintf(stderr, "Invalid or unsupported data source\n");
  154. exit(1);
  155. }
  156. format_printed = 0;
  157. c = 1;
  158. while (1) {
  159. r = archive_read_next_header(a, &entry);
  160. if (r == ARCHIVE_FATAL) {
  161. v_print(v, "Entry %d: fatal error reading "
  162. "header\n", c);
  163. break;
  164. }
  165. if (!format_printed) {
  166. v_print(v, "Filter: %s\nFormat: %s\n",
  167. archive_filter_name(a, 0), archive_format_name(a));
  168. format_printed = 1;
  169. }
  170. if (r == ARCHIVE_RETRY)
  171. continue;
  172. if (r == ARCHIVE_EOF)
  173. break;
  174. p = archive_entry_pathname(entry);
  175. v_print(v, "Entry %d: %s, pathname", c, errnostr(r));
  176. if (p == NULL || p[0] == '\0')
  177. v_print(v, " unreadable");
  178. else
  179. v_print(v, ": %s", p);
  180. v_print(v, ", data: ");
  181. if (skip_data) {
  182. v_print(v, "skipping");
  183. } else {
  184. while ((r = archive_read_data(a, buffer, 4096) > 0))
  185. ;
  186. if (r == ARCHIVE_FATAL) {
  187. v_print(v, "ERROR\nError string: %s\n",
  188. archive_error_string(a));
  189. break;
  190. }
  191. v_print(v, "OK");
  192. }
  193. v_print(v, "\n");
  194. c++;
  195. }
  196. v_print(v, "Last return code: %s (%d)\n", errnostr(r), r);
  197. if (r == ARCHIVE_EOF || r == ARCHIVE_OK) {
  198. archive_read_free(a);
  199. exit(0);
  200. }
  201. v_print(v, "Error string: %s\n", archive_error_string(a));
  202. archive_read_free(a);
  203. exit(2);
  204. }