]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/archivetest.c
Update vendor/libarchive/dist to git 614110e76d9dbb9ed3e159a71cbd75fa3b23efe3
[FreeBSD/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 const char *errnostr(int errno)
41 {
42         char *estr;
43         switch(errno) {
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
69 void usage(const char *prog)
70 {
71         fprintf(stderr, "Usage: %s [-f filename] [-h] [-q] [-s]\n", prog);
72 }
73
74 void printhelp()
75 {
76         fprintf(stdout, "archivetest: verify reading archives with "
77             "libarchive\n\n"
78             "Options:\n"
79             "  -f filename      Filename to verify\n"
80             "  -h               Show this help\n"
81             "  -q               Quiet mode\n"
82             "  -s               Verify only headers (skip data)\n\n"
83             "If no filename is specified, data is read from standard input.\n"
84             "\n%s\n", archive_version_details());
85 }
86
87 int v_print(int verbose, const char *format, ...)
88 {
89         int r = 0;
90
91         if (verbose) {
92                 va_list args;
93
94                 va_start(args, format);
95                 r = vfprintf(stdout, format, args);
96                 va_end(args);
97         }
98         return (r);
99 }
100
101 int main(int argc, char *argv[])
102 {
103         struct archive *a;
104         struct archive_entry *entry;
105         char *filename;
106         const char *p;
107         char buffer[4096];
108         int c;
109         int v, skip_data;
110         int r = ARCHIVE_OK;
111         int format_printed;
112
113         filename = NULL;
114         skip_data = 0;
115         v = 1;
116
117         while ((c = getopt (argc, argv, "f:hqs")) != -1) {
118                 switch (c) {
119                         case 'f':
120                                 filename = optarg;
121                                 break;
122                         case 'h':
123                                 printhelp();
124                                 exit(0);
125                         case 'q':
126                                 v = 0;
127                                 break;
128                         case 's':
129                                 skip_data = 1;
130                                 break;
131                         case '?':
132                                 if (optopt == 'f')
133                                         fprintf(stderr, "Option -%c requires "
134                                             "an argument.\n", optopt);
135                                 else if (isprint(optopt))
136                                         fprintf(stderr, "Unknown option '-%c'"
137                                             ".\n", optopt);
138                                 else
139                                         fprintf(stderr, "Unknown option "
140                                             "character '\\x%x'.\n", optopt);
141                                 usage(argv[0]);
142                         default:
143                                 exit(1);
144                 }
145         }
146
147         a = archive_read_new();
148
149         archive_read_support_filter_all(a);
150         archive_read_support_format_all(a);
151
152         v_print(v, "Data source: ");
153
154         if (filename == NULL) {
155                 v_print(v, "standard input\n");
156                 r = archive_read_open_fd(a, STDIN_FILENO, 4096);
157         } else {
158                 v_print(v, "filename: %s\n", filename);
159                 r = archive_read_open_filename(a, filename, 4096);
160         }
161
162         if (r != ARCHIVE_OK) {
163                 archive_read_free(a);
164                 fprintf(stderr, "Invalid or unsupported data source\n");
165                 exit(1);
166         }
167
168         format_printed = 0;
169         c = 1;
170
171         while (1) {
172                 r = archive_read_next_header(a, &entry);
173                 if (r == ARCHIVE_FATAL) {
174                         v_print(v, "Entry %d: fatal error reading "
175                             "header\n", c);
176                         break;
177                 }
178                 if (!format_printed) {
179                         v_print(v, "Filter: %s\nFormat: %s\n",
180                             archive_filter_name(a, 0), archive_format_name(a));
181                         format_printed = 1;
182                 }
183                 if (r == ARCHIVE_RETRY)
184                         continue;
185                 if (r == ARCHIVE_EOF)
186                         break;
187                 p = archive_entry_pathname(entry);
188                 v_print(v, "Entry %d: %s, pathname", c, errnostr(r));
189                 if (p == NULL || p[0] == '\0')
190                         v_print(v, " unreadable");
191                 else
192                         v_print(v, ": %s", p);
193                 v_print(v, ", data: ");
194                 if (skip_data) {
195                         v_print(v, "skipping");
196                 } else {
197                         while ((r = archive_read_data(a, buffer, 4096) > 0))
198                         ;
199                         if (r == ARCHIVE_FATAL) {
200                                 v_print(v, "ERROR\nError string: %s\n",
201                                     archive_error_string(a));
202                                 break;
203                         }
204                         v_print(v, "OK");
205                 }
206                 v_print(v, "\n");
207                 c++;
208         }
209
210         v_print(v, "Last return code: %s (%d)\n", errnostr(r), r);
211         if (r == ARCHIVE_EOF || r == ARCHIVE_OK) {
212                 archive_read_free(a);
213                 exit(0);
214         }
215         v_print(v, "Error string: %s\n", archive_error_string(a));
216         archive_read_free(a);
217         exit(2);
218 }