Update vendor/libarchive/dist to b2c3ee7e2907511533eeb2a0f2ceecc1faa73185
[freebsd.git] / contrib / archivetest.c
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 /*
27  * Archivetest verifies reading archives with libarchive
28  *
29  * It may be used to reproduce failures in testcases discovered by OSS-Fuzz
30  * https://github.com/google/oss-fuzz/blob/master/projects/libarchive
31  */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <ctype.h>
37 #include <archive.h>
38 #include <archive_entry.h>
39
40 #if defined __MINGW32__
41 #include <getopt.h>
42 #endif
43
44 static const char *errnostr(int e)
45 {
46         char *estr;
47         switch(e) {
48                 case ARCHIVE_EOF:
49                         estr = "ARCHIVE_EOF";
50                 break;
51                 case ARCHIVE_OK:
52                         estr = "ARCHIVE_OK";
53                 break;
54                 case ARCHIVE_WARN:
55                         estr = "ARCHIVE_WARN";
56                 break;
57                 case ARCHIVE_RETRY:
58                         estr = "ARCHIVE_RETRY";
59                 break;
60                 case ARCHIVE_FAILED:
61                         estr = "ARCHIVE_FAILED";
62                 break;
63                 case ARCHIVE_FATAL:
64                         estr = "ARCHIVE_FATAL";
65                 break;
66                 default:
67                         estr = "Unknown";
68                 break;
69         }
70         return (estr);
71 }
72
73 static void usage(const char *prog)
74 {
75         fprintf(stderr, "Usage: %s [-f filename] [-h] [-q] [-s]\n", prog);
76 }
77
78 static void printhelp()
79 {
80         fprintf(stdout, "archivetest: verify reading archives with "
81             "libarchive\n\n"
82             "Options:\n"
83             "  -f filename      Filename to verify\n"
84             "  -h               Show this help\n"
85             "  -q               Quiet mode\n"
86             "  -s               Verify only headers (skip data)\n\n"
87             "If no filename is specified, data is read from standard input.\n"
88             "\n%s\n", archive_version_details());
89 }
90
91 static int v_print(int verbose, const char *format, ...)
92 {
93         int r = 0;
94
95         if (verbose) {
96                 va_list args;
97
98                 va_start(args, format);
99                 r = vfprintf(stdout, format, args);
100                 va_end(args);
101         }
102         return (r);
103 }
104
105 int main(int argc, char *argv[])
106 {
107         struct archive *a;
108         struct archive_entry *entry;
109         char *filename;
110         const char *p;
111         char buffer[4096];
112         int c;
113         int v, skip_data;
114         int r = ARCHIVE_OK;
115         int format_printed;
116
117         filename = NULL;
118         skip_data = 0;
119         v = 1;
120
121         while ((c = getopt (argc, argv, "f:hqs")) != -1) {
122                 switch (c) {
123                         case 'f':
124                                 filename = optarg;
125                                 break;
126                         case 'h':
127                                 printhelp();
128                                 exit(0);
129                         case 'q':
130                                 v = 0;
131                                 break;
132                         case 's':
133                                 skip_data = 1;
134                                 break;
135                         case '?':
136                                 if (optopt == 'f')
137                                         fprintf(stderr, "Option -%c requires "
138                                             "an argument.\n", optopt);
139                                 else if (isprint(optopt))
140                                         fprintf(stderr, "Unknown option '-%c'"
141                                             ".\n", optopt);
142                                 else
143                                         fprintf(stderr, "Unknown option "
144                                             "character '\\x%x'.\n", optopt);
145                                 usage(argv[0]);
146                                 exit(1);
147                                 break;
148                         default:
149                                 exit(1);
150                 }
151         }
152
153         a = archive_read_new();
154
155         archive_read_support_filter_all(a);
156         archive_read_support_format_all(a);
157
158         v_print(v, "Data source: ");
159
160         if (filename == NULL) {
161                 v_print(v, "standard input\n");
162                 r = archive_read_open_fd(a, STDIN_FILENO, 4096);
163         } else {
164                 v_print(v, "filename: %s\n", filename);
165                 r = archive_read_open_filename(a, filename, 4096);
166         }
167
168         if (r != ARCHIVE_OK) {
169                 archive_read_free(a);
170                 fprintf(stderr, "Invalid or unsupported data source\n");
171                 exit(1);
172         }
173
174         format_printed = 0;
175         c = 1;
176
177         while (1) {
178                 r = archive_read_next_header(a, &entry);
179                 if (r == ARCHIVE_FATAL) {
180                         v_print(v, "Entry %d: fatal error reading "
181                             "header\n", c);
182                         break;
183                 }
184                 if (!format_printed) {
185                         v_print(v, "Filter: %s\nFormat: %s\n",
186                             archive_filter_name(a, 0), archive_format_name(a));
187                         format_printed = 1;
188                 }
189                 if (r == ARCHIVE_RETRY)
190                         continue;
191                 if (r == ARCHIVE_EOF)
192                         break;
193                 p = archive_entry_pathname(entry);
194                 v_print(v, "Entry %d: %s, pathname", c, errnostr(r));
195                 if (p == NULL || p[0] == '\0')
196                         v_print(v, " unreadable");
197                 else
198                         v_print(v, ": %s", p);
199                 v_print(v, ", data: ");
200                 if (skip_data) {
201                         v_print(v, "skipping");
202                 } else {
203                         while ((r = archive_read_data(a, buffer, 4096) > 0))
204                         ;
205                         if (r == ARCHIVE_FATAL) {
206                                 v_print(v, "ERROR\nError string: %s\n",
207                                     archive_error_string(a));
208                                 break;
209                         }
210                         v_print(v, "OK");
211                 }
212                 v_print(v, "\n");
213                 c++;
214         }
215
216         v_print(v, "Last return code: %s (%d)\n", errnostr(r), r);
217         if (r == ARCHIVE_EOF || r == ARCHIVE_OK) {
218                 archive_read_free(a);
219                 exit(0);
220         }
221         v_print(v, "Error string: %s\n", archive_error_string(a));
222         archive_read_free(a);
223         exit(2);
224 }