blob: 48c4ed4a2587eaf037c93436ea7ace6fa3bacb4f [file] [log] [blame]
Dieter Baron392787a2003-03-14 14:53:29 +00001/*
Dieter Baronb2ed74d2004-04-14 14:01:31 +00002 zipcmp.c -- compare zip files
Thomas Klausnerdf77dc62016-12-31 13:40:32 +01003 Copyright (C) 2003-2016 Dieter Baron and Thomas Klausner
Dieter Baron392787a2003-03-14 14:53:29 +00004
Dieter Barondd9afca2003-10-02 14:13:37 +00005 This file is part of libzip, a library to manipulate ZIP archives.
Dieter Baron40a21972007-11-07 00:11:26 +01006 The authors can be contacted at <libzip@nih.at>
Dieter Baron392787a2003-03-14 14:53:29 +00007
Dieter Barondd9afca2003-10-02 14:13:37 +00008 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in
15 the documentation and/or other materials provided with the
16 distribution.
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
19 written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Dieter Baron392787a2003-03-14 14:53:29 +000032*/
33
Dieter Baron392787a2003-03-14 14:53:29 +000034
Dieter Barona6192cf2011-02-04 16:25:01 +010035#include "config.h"
36
Thomas Klausnera191f7b2014-01-29 15:14:37 +010037#include <sys/stat.h>
Dieter Barone3f91ef2003-10-06 02:50:14 +000038#include <errno.h>
Dieter Baron392787a2003-03-14 14:53:29 +000039#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
Dieter Baronc0866112012-08-08 16:54:19 +020042#ifdef HAVE_STRINGS_H
43#include <strings.h>
44#endif
Thomas Klausner30b32ec2010-02-03 15:34:38 +010045#ifdef HAVE_UNISTD_H
Thomas Klausnerf29a6ba2006-05-09 16:34:18 +000046#include <unistd.h>
Thomas Klausner30b32ec2010-02-03 15:34:38 +010047#endif
Thomas Klausnerde610c32014-05-08 12:19:28 +020048#ifdef HAVE_FTS_H
49#include <fts.h>
50#endif
Thomas Klausner24a722b2004-11-30 21:51:30 +000051#include <zlib.h>
Dieter Baron392787a2003-03-14 14:53:29 +000052
Thomas Klausner81e94332011-03-08 14:10:27 +010053#ifndef HAVE_GETOPT
54#include "getopt.h"
55#endif
56
Dieter Baronb5a0e3f2012-08-31 18:18:36 +020057#include "compat.h"
Thomas Klausner069aee62017-06-21 10:11:01 +020058#include "zip.h"
Dieter Baron392787a2003-03-14 14:53:29 +000059
Thomas Klausnera191f7b2014-01-29 15:14:37 +010060struct archive {
61 const char *name;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020062 zip_t *za;
Thomas Klausnera191f7b2014-01-29 15:14:37 +010063 zip_uint64_t nentry;
64 struct entry *entry;
65 const char *comment;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020066 size_t comment_length;
Thomas Klausnera191f7b2014-01-29 15:14:37 +010067};
68
Dieter Baron0e5eeab2012-04-24 18:47:12 +020069struct ef {
70 const char *name;
71 zip_uint16_t flags;
72 zip_uint16_t id;
73 zip_uint16_t size;
74 const zip_uint8_t *data;
75};
76
Dieter Baron392787a2003-03-14 14:53:29 +000077struct entry {
78 char *name;
Dieter Baron0e5eeab2012-04-24 18:47:12 +020079 zip_uint64_t size;
80 zip_uint32_t crc;
81 zip_uint32_t comp_method;
Dieter Baron0e5eeab2012-04-24 18:47:12 +020082 struct ef *extra_fields;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020083 zip_uint16_t n_extra_fields;
Dieter Baron3efab992012-05-04 09:29:29 +020084 const char *comment;
Thomas Klausner216701e2013-03-14 11:47:39 +010085 zip_uint32_t comment_length;
Dieter Baron392787a2003-03-14 14:53:29 +000086};
87
Dieter Baron392787a2003-03-14 14:53:29 +000088
Thomas Klausneref9a02f2004-11-18 15:06:20 +000089const char *prg;
Dieter Baron392787a2003-03-14 14:53:29 +000090
Thomas Klausner28cc4ce2012-03-28 21:41:30 +020091#define PROGRAM "zipcmp"
Dieter Baron80d9ff32004-12-22 17:31:32 +000092
Thomas Klausner199a91f2014-03-10 16:17:10 +010093#define USAGE "usage: %s [-hipqtVv] archive1 archive2\n"
Dieter Baron392787a2003-03-14 14:53:29 +000094
Dieter Baron80d9ff32004-12-22 17:31:32 +000095char help_head[] =
96 PROGRAM " (" PACKAGE ") by Dieter Baron and Thomas Klausner\n\n";
Dieter Baron392787a2003-03-14 14:53:29 +000097
98char help[] = "\n\
99 -h display this help message\n\
Dieter Baron3014e882003-10-03 23:54:32 +0000100 -i compare names ignoring case distinctions\n\
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200101 -p compare as many details as possible\n\
Dieter Baron392787a2003-03-14 14:53:29 +0000102 -q be quiet\n\
Thomas Klausneraf2c40e2014-08-06 00:02:25 +0200103 -t test zip files (compare file contents to checksum)\n\
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100104 -V display version number\n\
Dieter Baron392787a2003-03-14 14:53:29 +0000105 -v be verbose (print differences, default)\n\
106\n\
Dieter Baron40a21972007-11-07 00:11:26 +0100107Report bugs to <libzip@nih.at>.\n";
Dieter Baron392787a2003-03-14 14:53:29 +0000108
Dieter Baron80d9ff32004-12-22 17:31:32 +0000109char version_string[] = PROGRAM " (" PACKAGE " " VERSION ")\n\
Thomas Klausnerdf77dc62016-12-31 13:40:32 +0100110Copyright (C) 2003-2016 Dieter Baron and Thomas Klausner\n\
Dieter Baron79aca392007-11-08 16:00:37 +0100111" PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n";
Dieter Baron392787a2003-03-14 14:53:29 +0000112
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200113#define OPTIONS "hVipqtv"
Dieter Baron392787a2003-03-14 14:53:29 +0000114
Dieter Baron392787a2003-03-14 14:53:29 +0000115
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100116#define BOTH_ARE_ZIPS(a) (a[0].za && a[1].za)
117
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200118static int comment_compare(const char *c1, size_t l1, const char *c2, size_t l2);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200119static int compare_list(char * const name[],
Dieter Barona1f8e2c2013-05-14 22:21:34 +0200120 const void *l[], const zip_uint64_t n[], int size,
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200121 int (*cmp)(const void *, const void *),
122 int (*checks)(char *const name[2], const void *, const void *),
123 void (*print)(const void *));
124static int compare_zip(char * const zn[]);
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100125static int ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2);
126static int ef_order(const void *a, const void *b);
127static void ef_print(const void *p);
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200128static int ef_read(zip_t *za, zip_uint64_t idx, struct entry *e);
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100129static int entry_cmp(const void *p1, const void *p2);
130static int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2);
131static void entry_print(const void *p);
132static int is_directory(const char *name);
Thomas Klausnerde610c32014-05-08 12:19:28 +0200133#ifdef HAVE_FTS_H
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100134static int list_directory(const char *name, struct archive *a);
Thomas Klausnerde610c32014-05-08 12:19:28 +0200135#endif
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100136static int list_zip(const char *name, struct archive *a);
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200137static int test_file(zip_t *za, zip_uint64_t idx, zip_uint64_t size, zip_uint32_t crc);
Dieter Baron392787a2003-03-14 14:53:29 +0000138
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200139int ignore_case, test_files, paranoid, verbose;
140int header_done;
Dieter Baron3014e882003-10-03 23:54:32 +0000141
Dieter Baron392787a2003-03-14 14:53:29 +0000142
143int
Thomas Klausnerf9b991b2004-12-22 18:12:03 +0000144main(int argc, char * const argv[])
Dieter Baron392787a2003-03-14 14:53:29 +0000145{
Dieter Baron392787a2003-03-14 14:53:29 +0000146 int c;
147
148 prg = argv[0];
149
Dieter Baron3014e882003-10-03 23:54:32 +0000150 ignore_case = 0;
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000151 test_files = 0;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200152 paranoid = 0;
Dieter Baron392787a2003-03-14 14:53:29 +0000153 verbose = 1;
154
155 while ((c=getopt(argc, argv, OPTIONS)) != -1) {
156 switch (c) {
Dieter Baron3014e882003-10-03 23:54:32 +0000157 case 'i':
158 ignore_case = 1;
159 break;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200160 case 'p':
161 paranoid = 1;
162 break;
Dieter Baron392787a2003-03-14 14:53:29 +0000163 case 'q':
164 verbose = 0;
165 break;
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000166 case 't':
167 test_files = 1;
168 break;
Dieter Baron392787a2003-03-14 14:53:29 +0000169 case 'v':
170 verbose = 1;
171 break;
172
173 case 'h':
174 fputs(help_head, stdout);
Thomas Klausner199a91f2014-03-10 16:17:10 +0100175 printf(USAGE, prg);
Dieter Baron392787a2003-03-14 14:53:29 +0000176 fputs(help, stdout);
177 exit(0);
178 case 'V':
179 fputs(version_string, stdout);
180 exit(0);
181
182 default:
Thomas Klausner199a91f2014-03-10 16:17:10 +0100183 fprintf(stderr, USAGE, prg);
Dieter Baron9afd7bd2003-10-01 18:27:46 +0000184 exit(2);
Dieter Baron392787a2003-03-14 14:53:29 +0000185 }
186 }
187
188 if (argc != optind+2) {
Thomas Klausner199a91f2014-03-10 16:17:10 +0100189 fprintf(stderr, USAGE, prg);
Dieter Baron9afd7bd2003-10-01 18:27:46 +0000190 exit(2);
Dieter Baron392787a2003-03-14 14:53:29 +0000191 }
192
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200193 exit((compare_zip(argv+optind) == 0) ? 0 : 1);
Dieter Baron392787a2003-03-14 14:53:29 +0000194}
195
Dieter Baron392787a2003-03-14 14:53:29 +0000196
197static int
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200198compare_zip(char * const zn[])
Dieter Baron392787a2003-03-14 14:53:29 +0000199{
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100200 struct archive a[2];
Dieter Baron392787a2003-03-14 14:53:29 +0000201 struct entry *e[2];
Dieter Barona1f8e2c2013-05-14 22:21:34 +0200202 zip_uint64_t n[2];
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100203 int i;
Dieter Baron3efab992012-05-04 09:29:29 +0200204 int res;
205
Dieter Baron392787a2003-03-14 14:53:29 +0000206 for (i=0; i<2; i++) {
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100207 a[i].name = zn[i];
208 a[i].entry = NULL;
209 a[i].nentry = 0;
210 a[i].za = NULL;
211 a[i].comment = NULL;
212 a[i].comment_length =0;
213
214 if (is_directory(zn[i])) {
Thomas Klausnerde610c32014-05-08 12:19:28 +0200215#ifndef HAVE_FTS_H
216 fprintf(stderr, "%s: reading directories not supported\n", prg);
217 exit(2);
218#else
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100219 if (list_directory(zn[i], a+i) < 0)
220 exit(2);
221 paranoid = 0; /* paranoid checks make no sense for directories, since they compare zip metadata */
Thomas Klausnerde610c32014-05-08 12:19:28 +0200222#endif
Dieter Baron392787a2003-03-14 14:53:29 +0000223 }
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100224 else {
225 if (list_zip(zn[i], a+i) < 0)
226 exit(2);
227 }
Thomas Klausner95e0f982016-10-19 00:36:57 +0200228 if (a[i].nentry > 0)
229 qsort(a[i].entry, a[i].nentry, sizeof(a[i].entry[0]), entry_cmp);
Dieter Baron392787a2003-03-14 14:53:29 +0000230 }
231
Dieter Baron3efab992012-05-04 09:29:29 +0200232 header_done = 0;
233
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100234 e[0] = a[0].entry;
235 e[1] = a[1].entry;
236 n[0] = a[0].nentry;
237 n[1] = a[1].nentry;
238 res = compare_list(zn, (const void **)e, n, sizeof(e[i][0]), entry_cmp, paranoid ? entry_paranoia_checks : NULL, entry_print);
Dieter Baron3efab992012-05-04 09:29:29 +0200239
240 if (paranoid) {
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100241 if (comment_compare(a[0].comment, a[0].comment_length, a[1].comment, a[1].comment_length) != 0) {
Dieter Baron3efab992012-05-04 09:29:29 +0200242 if (verbose) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200243 printf("--- archive comment (%zd)\n", a[0].comment_length);
244 printf("+++ archive comment (%zd)\n", a[1].comment_length);
Dieter Baron3efab992012-05-04 09:29:29 +0200245 }
246 res = 1;
247 }
248 }
249
250 for (i=0; i<2; i++)
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100251 if (a[i].za)
252 zip_close(a[i].za);
Dieter Baron3efab992012-05-04 09:29:29 +0200253
254 switch (res) {
Dieter Baron9afd7bd2003-10-01 18:27:46 +0000255 case 0:
256 exit(0);
257
258 case 1:
259 exit(1);
260
261 default:
262 exit(2);
263 }
Dieter Baron3efab992012-05-04 09:29:29 +0200264}
Thomas Klausner3a2ce0e2005-05-20 21:56:54 +0000265
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200266#ifdef HAVE_FTS_H
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100267static zip_int64_t
268compute_crc(const char *fname)
269{
270 FILE *f;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200271 uLong crc = crc32(0L, Z_NULL, 0);
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100272 size_t n;
273 Bytef buffer[8192];
274
275
276 if ((f=fopen(fname, "r")) == NULL) {
Thomas Klausnerde610c32014-05-08 12:19:28 +0200277 fprintf(stderr, "%s: can't open %s: %s\n", prg, fname, strerror(errno));
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100278 return -1;
279 }
280
281 while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200282 crc = crc32(crc, buffer, (unsigned int)n);
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100283 }
284
285 if (ferror(f)) {
Thomas Klausnerde610c32014-05-08 12:19:28 +0200286 fprintf(stderr, "%s: read error on %s: %s\n", prg, fname, strerror(errno));
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100287 fclose(f);
288 return -1;
289 }
290
291 fclose(f);
292
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200293 return (zip_int64_t)crc;
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100294}
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200295#endif
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100296
297
298static int
299is_directory(const char *name)
300{
301 struct stat st;
302
303 if (stat(name, &st) < 0)
304 return 0;
305
306 return S_ISDIR(st.st_mode);
307}
308
309
Thomas Klausnerde610c32014-05-08 12:19:28 +0200310#ifdef HAVE_FTS_H
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100311static int
312list_directory(const char *name, struct archive *a)
313{
Thomas Klausnerde610c32014-05-08 12:19:28 +0200314 FTS *fts;
315 FTSENT *ent;
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100316 zip_uint64_t nalloc;
Thomas Klausnerdceead52017-02-26 11:01:57 +0100317 size_t prefix_length;
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100318
Thomas Klausnerde610c32014-05-08 12:19:28 +0200319 char * const names[2] = { (char *)name, NULL };
320
321
322 if ((fts = fts_open(names, FTS_NOCHDIR|FTS_LOGICAL, NULL)) == NULL) {
323 fprintf(stderr, "%s: can't open directory '%s': %s\n", prg, name, strerror(errno));
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100324 return -1;
325 }
Thomas Klausnerdceead52017-02-26 11:01:57 +0100326 prefix_length = strlen(name)+1;
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100327
328 nalloc = 0;
Thomas Klausnerde610c32014-05-08 12:19:28 +0200329
330 while ((ent = fts_read(fts))) {
Thomas Klausner90918402014-03-08 22:13:47 +0100331 zip_int64_t crc;
332
Thomas Klausnerde610c32014-05-08 12:19:28 +0200333 switch (ent->fts_info) {
334 case FTS_D:
335 case FTS_DOT:
336 case FTS_DP:
337 case FTS_DEFAULT:
338 case FTS_SL:
339 case FTS_NSOK:
340 break;
Thomas Klausner90918402014-03-08 22:13:47 +0100341
Thomas Klausnerde610c32014-05-08 12:19:28 +0200342 case FTS_DC:
343 case FTS_DNR:
344 case FTS_ERR:
345 case FTS_NS:
346 case FTS_SLNONE:
347 /* TODO: error */
348 fts_close(fts);
349 return -1;
350
351 case FTS_F:
Thomas Klausner90918402014-03-08 22:13:47 +0100352 if (a->nentry >= nalloc) {
353 nalloc += 16;
Thomas Klausner2b5ddb22015-04-22 11:18:49 +0200354 if (nalloc > SIZE_MAX/sizeof(a->entry[0])) {
355 fprintf(stderr, "%s: malloc failure\n", prg);
356 exit(1);
357 }
Thomas Klausner90918402014-03-08 22:13:47 +0100358 a->entry = realloc(a->entry, sizeof(a->entry[0])*nalloc);
359 if (a->entry == NULL) {
Thomas Klausnerde610c32014-05-08 12:19:28 +0200360 fprintf(stderr, "%s: malloc failure\n", prg);
Thomas Klausner90918402014-03-08 22:13:47 +0100361 exit(1);
362 }
363 }
Thomas Klausnerde610c32014-05-08 12:19:28 +0200364
365 a->entry[a->nentry].name = strdup(ent->fts_path+prefix_length);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200366 a->entry[a->nentry].size = (zip_uint64_t)ent->fts_statp->st_size;
Thomas Klausnerde610c32014-05-08 12:19:28 +0200367 if ((crc = compute_crc(ent->fts_accpath)) < 0) {
368 fts_close(fts);
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100369 return -1;
Thomas Klausner90918402014-03-08 22:13:47 +0100370 }
Thomas Klausnerde610c32014-05-08 12:19:28 +0200371
Thomas Klausner90918402014-03-08 22:13:47 +0100372 a->entry[a->nentry].crc = (zip_uint32_t)crc;
373 a->nentry++;
Thomas Klausnerde610c32014-05-08 12:19:28 +0200374 break;
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100375 }
376 }
377
Thomas Klausnerde610c32014-05-08 12:19:28 +0200378 if (fts_close(fts)) {
379 fprintf(stderr, "%s: error closing directory '%s': %s\n", prg, a->name, strerror(errno));
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100380 return -1;
381 }
382
383 return 0;
384}
Thomas Klausnerde610c32014-05-08 12:19:28 +0200385#endif
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100386
387
388static int
389list_zip(const char *name, struct archive *a)
390{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200391 zip_t *za;
Thomas Klausner199a91f2014-03-10 16:17:10 +0100392 int err;
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100393 struct zip_stat st;
Thomas Klausner199a91f2014-03-10 16:17:10 +0100394 unsigned int i;
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100395
396 if ((za=zip_open(name, paranoid ? ZIP_CHECKCONS : 0, &err)) == NULL) {
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100397 zip_error_t error;
398 zip_error_init_with_code(&error, err);
399 fprintf(stderr, "%s: cannot open zip archive '%s': %s\n", prg, name, zip_error_strerror(&error));
400 zip_error_fini(&error);
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100401 return -1;
402 }
403
404 a->za = za;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200405 a->nentry = (zip_uint64_t)zip_get_num_entries(za, 0);
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100406
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100407 if (a->nentry == 0)
408 a->entry = NULL;
409 else {
Thomas Klausner2402de92015-04-22 11:13:52 +0200410 if ((a->nentry > SIZE_MAX/sizeof(a->entry[0])) || (a->entry=(struct entry *)malloc(sizeof(a->entry[0]) * a->nentry)) == NULL) {
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100411 fprintf(stderr, "%s: malloc failure\n", prg);
412 exit(1);
413 }
414
415 for (i=0; i<a->nentry; i++) {
416 zip_stat_index(za, i, 0, &st);
417 a->entry[i].name = strdup(st.name);
418 a->entry[i].size = st.size;
419 a->entry[i].crc = st.crc;
420 if (test_files)
421 test_file(za, i, st.size, st.crc);
422 if (paranoid) {
423 a->entry[i].comp_method = st.comp_method;
424 ef_read(za, i, a->entry+i);
425 a->entry[i].comment = zip_file_get_comment(za, i, &a->entry[i].comment_length, 0);
426 }
427 else {
428 a->entry[i].comp_method = 0;
429 a->entry[i].n_extra_fields = 0;
430 }
431 }
432
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200433 if (paranoid) {
434 int length;
435 a->comment = zip_get_archive_comment(za, &length, 0);
436 a->comment_length = (size_t)length;
437 }
Thomas Klausnera191f7b2014-01-29 15:14:37 +0100438 else {
439 a->comment = NULL;
440 a->comment_length = 0;
441 }
442 }
443
444 return 0;
445}
446
Dieter Baron3efab992012-05-04 09:29:29 +0200447
448static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200449comment_compare(const char *c1, size_t l1, const char *c2, size_t l2) {
Dieter Baron3efab992012-05-04 09:29:29 +0200450 if (l1 != l2)
451 return 1;
452
453 if (l1 == 0)
454 return 0;
455
Dieter Barona205a4d2012-08-08 16:52:57 +0200456 if (c1 == NULL || c2 == NULL)
457 return c1 == c2;
458
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200459 return memcmp(c1, c2, (size_t)l2);
Dieter Baron392787a2003-03-14 14:53:29 +0000460}
461
Dieter Baron392787a2003-03-14 14:53:29 +0000462
463static int
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200464compare_list(char * const name[2],
Dieter Barona1f8e2c2013-05-14 22:21:34 +0200465 const void *l[2], const zip_uint64_t n[2], int size,
Dieter Baron392787a2003-03-14 14:53:29 +0000466 int (*cmp)(const void *, const void *),
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200467 int (*check)(char *const name[2], const void *, const void *),
468 void (*print)(const void *))
Dieter Baron392787a2003-03-14 14:53:29 +0000469{
Thomas Klausner199a91f2014-03-10 16:17:10 +0100470 unsigned int i[2];
471 int j, c;
Dieter Baron392787a2003-03-14 14:53:29 +0000472 int diff;
473
Dieter Baronab97dc32005-05-19 18:42:09 +0000474#define INC(k) (i[k]++, l[k]=((const char *)l[k])+size)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200475#define PRINT(k) do { \
476 if (header_done==0 && verbose) { \
Dieter Baronab97dc32005-05-19 18:42:09 +0000477 printf("--- %s\n+++ %s\n", name[0], name[1]); \
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200478 header_done = 1; \
479 } \
480 if (verbose) { \
481 printf("%c ", (k)?'+':'-'); \
482 print(l[k]); \
483 } \
484 diff = 1; \
Dieter Baronab97dc32005-05-19 18:42:09 +0000485 } while (0)
Dieter Baron392787a2003-03-14 14:53:29 +0000486
487 i[0] = i[1] = 0;
488 diff = 0;
489 while (i[0]<n[0] && i[1]<n[1]) {
490 c = cmp(l[0], l[1]);
491
492 if (c == 0) {
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200493 if (check)
494 diff |= check(name, l[0], l[1]);
Dieter Baron392787a2003-03-14 14:53:29 +0000495 INC(0);
496 INC(1);
497 }
498 else if (c < 0) {
499 PRINT(0);
500 INC(0);
501 }
502 else {
503 PRINT(1);
504 INC(1);
505 }
506 }
507
508 for (j=0; j<2; j++) {
509 while (i[j]<n[j]) {
510 PRINT(j);
511 INC(j);
512 }
513 }
514
515 return diff;
516}
517
Dieter Baron392787a2003-03-14 14:53:29 +0000518
519static int
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200520ef_read(zip_t *za, zip_uint64_t idx, struct entry *e)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200521{
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200522 zip_int16_t n_local, n_central;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200523 zip_uint16_t i;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200524
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200525 if ((n_local = zip_file_extra_fields_count(za, idx, ZIP_FL_LOCAL)) < 0
526 || (n_central = zip_file_extra_fields_count(za, idx, ZIP_FL_CENTRAL)) < 0) {
527 return -1;
528 }
529
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200530 e->n_extra_fields = (zip_uint16_t)(n_local + n_central);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200531
Thomas Klausnerf5d96cb2013-03-20 00:31:18 +0100532 if ((e->extra_fields=(struct ef *)malloc(sizeof(e->extra_fields[0])*e->n_extra_fields)) == NULL)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200533 return -1;
534
535 for (i=0; i<n_local; i++) {
536 e->extra_fields[i].name = e->name;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200537 e->extra_fields[i].data = zip_file_extra_field_get(za, idx, i, &e->extra_fields[i].id, &e->extra_fields[i].size, ZIP_FL_LOCAL);
538 if (e->extra_fields[i].data == NULL)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200539 return -1;
540 e->extra_fields[i].flags = ZIP_FL_LOCAL;
541 }
542 for (; i<e->n_extra_fields; i++) {
543 e->extra_fields[i].name = e->name;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200544 e->extra_fields[i].data=zip_file_extra_field_get(za, idx, (zip_uint16_t)(i-n_local), &e->extra_fields[i].id, &e->extra_fields[i].size, ZIP_FL_CENTRAL);
545 if (e->extra_fields[i].data == NULL)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200546 return -1;
547 e->extra_fields[i].flags = ZIP_FL_CENTRAL;
548 }
549
550 qsort(e->extra_fields, e->n_extra_fields, sizeof(e->extra_fields[0]), ef_order);
551
552 return 0;
553}
554
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200555
556static int
557ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2)
558{
559 struct ef *ef[2];
Dieter Barona1f8e2c2013-05-14 22:21:34 +0200560 zip_uint64_t n[2];
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200561
562 ef[0] = e1->extra_fields;
563 ef[1] = e2->extra_fields;
564 n[0] = e1->n_extra_fields;
565 n[1] = e2->n_extra_fields;
566
Thomas Klausnerf5d96cb2013-03-20 00:31:18 +0100567 return compare_list(name, (const void **)ef, n, sizeof(struct ef), ef_order, NULL, ef_print);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200568}
569
570
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200571
572static int
573ef_order(const void *ap, const void *bp) {
574 const struct ef *a, *b;
575
Thomas Klausnerf5d96cb2013-03-20 00:31:18 +0100576 a = (struct ef *)ap;
577 b = (struct ef *)bp;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200578
579 if (a->flags != b->flags)
580 return a->flags - b->flags;
581 if (a->id != b->id)
582 return a->id - b->id;
583 if (a->size != b->size)
584 return a->size - b->size;
585 return memcmp(a->data, b->data, a->size);
586}
587
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200588
589static void
590ef_print(const void *p)
591{
Thomas Klausnerf5d96cb2013-03-20 00:31:18 +0100592 const struct ef *ef = (struct ef *)p;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200593 int i;
594
595 printf(" %s ", ef->name);
Dieter Baronff40b572012-07-15 15:19:32 +0200596 printf("%04x %c <", ef->id, ef->flags == ZIP_FL_LOCAL ? 'l' : 'c');
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200597 for (i=0; i<ef->size; i++)
598 printf("%s%02x", i ? " " : "", ef->data[i]);
599 printf(">\n");
600}
601
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200602
603static int
Dieter Baron392787a2003-03-14 14:53:29 +0000604entry_cmp(const void *p1, const void *p2)
605{
606 const struct entry *e1, *e2;
607 int c;
608
Thomas Klausnerf5d96cb2013-03-20 00:31:18 +0100609 e1 = (struct entry *)p1;
610 e2 = (struct entry *)p2;
Dieter Baron392787a2003-03-14 14:53:29 +0000611
Dieter Baron3014e882003-10-03 23:54:32 +0000612 if ((c=(ignore_case ? strcasecmp : strcmp)(e1->name, e2->name)) != 0)
Dieter Baron392787a2003-03-14 14:53:29 +0000613 return c;
Dieter Barona205a4d2012-08-08 16:52:57 +0200614 if (e1->size != e2->size) {
615 if (e1->size > e2->size)
616 return 1;
617 else
618 return -1;
619 }
Dieter Baron392787a2003-03-14 14:53:29 +0000620 if (e1->crc != e2->crc)
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200621 return (int)e1->crc - (int)e2->crc;
Dieter Baron392787a2003-03-14 14:53:29 +0000622
623 return 0;
624}
625
Dieter Baron392787a2003-03-14 14:53:29 +0000626
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200627static int
628entry_paranoia_checks(char *const name[2], const void *p1, const void *p2) {
629 const struct entry *e1, *e2;
Dieter Baron3efab992012-05-04 09:29:29 +0200630 int ret;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200631
Thomas Klausnerf5d96cb2013-03-20 00:31:18 +0100632 e1 = (struct entry *)p1;
633 e2 = (struct entry *)p2;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200634
Dieter Baron3efab992012-05-04 09:29:29 +0200635 ret = 0;
636
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200637 if (ef_compare(name, e1, e2) != 0)
Dieter Baron3efab992012-05-04 09:29:29 +0200638 ret = 1;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200639
Thomas Klausner563e6f52012-04-24 19:08:41 +0200640 if (e1->comp_method != e2->comp_method) {
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200641 if (verbose) {
642 if (header_done==0) {
643 printf("--- %s\n+++ %s\n", name[0], name[1]);
644 header_done = 1;
645 }
646 printf("--- %s ", e1->name);
Dieter Baronae694b72013-02-26 11:17:51 +0100647 printf("method %u\n", e1->comp_method);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200648 printf("+++ %s ", e1->name);
Dieter Baronae694b72013-02-26 11:17:51 +0100649 printf("method %u\n", e2->comp_method);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200650 }
Dieter Baron3efab992012-05-04 09:29:29 +0200651 ret = 1;
652 }
653 if (comment_compare(e1->comment, e1->comment_length, e2->comment, e2->comment_length) != 0) {
654 if (verbose) {
655 if (header_done==0) {
656 printf("--- %s\n+++ %s\n", name[0], name[1]);
657 header_done = 1;
658 }
659 printf("--- %s ", e1->name);
660 printf("comment %d\n", e1->comment_length);
661 printf("+++ %s ", e1->name);
662 printf("comment %d\n", e2->comment_length);
663 }
664 ret = 1;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200665 }
666
Dieter Baron3efab992012-05-04 09:29:29 +0200667 return ret;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200668}
669
670
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200671
Dieter Baron392787a2003-03-14 14:53:29 +0000672static void
673entry_print(const void *p)
674{
675 const struct entry *e;
676
Thomas Klausnerf5d96cb2013-03-20 00:31:18 +0100677 e = (struct entry *)p;
Dieter Baron392787a2003-03-14 14:53:29 +0000678
Thomas Klausnerb52bda02013-11-28 18:01:40 +0100679 /* TODO PRId64 */
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200680 printf("%10lu %08x %s\n", (unsigned long)e->size, e->crc, e->name);
Dieter Baron392787a2003-03-14 14:53:29 +0000681}
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000682
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000683
684static int
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200685test_file(zip_t *za, zip_uint64_t idx, zip_uint64_t size, zip_uint32_t crc)
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000686{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200687 zip_file_t *zf;
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000688 char buf[8192];
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200689 zip_uint64_t nsize;
690 zip_int64_t n;
Dieter Barona205a4d2012-08-08 16:52:57 +0200691 zip_uint32_t ncrc;
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000692
Thomas Klausner6be59812004-11-18 17:11:24 +0000693 if ((zf=zip_fopen_index(za, idx, 0)) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200694 fprintf(stderr, "%s: cannot open file %" PRIu64 " in archive: %s\n", prg, idx, zip_strerror(za));
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000695 return -1;
696 }
697
Dieter Barona205a4d2012-08-08 16:52:57 +0200698 ncrc = (zip_uint32_t)crc32(0, NULL, 0);
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000699 nsize = 0;
700
Thomas Klausner6be59812004-11-18 17:11:24 +0000701 while ((n=zip_fread(zf, buf, sizeof(buf))) > 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200702 nsize += (zip_uint64_t)n;
Dieter Barona205a4d2012-08-08 16:52:57 +0200703 ncrc = (zip_uint32_t)crc32(ncrc, (const Bytef *)buf, (unsigned int)n);
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000704 }
705
706 if (n < 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200707 fprintf(stderr, "%s: error reading file %" PRIu64 " in archive: %s\n", prg, idx, zip_file_strerror(zf));
Thomas Klausner6be59812004-11-18 17:11:24 +0000708 zip_fclose(zf);
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000709 return -1;
710 }
711
Thomas Klausner6be59812004-11-18 17:11:24 +0000712 zip_fclose(zf);
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000713
714 if (nsize != size) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200715 fprintf(stderr, "%s: file %" PRIu64 ": unexpected length %" PRId64 " (should be %" PRId64 ")\n", prg, idx, nsize, size);
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000716 return -2;
717 }
718 if (ncrc != crc) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200719 fprintf(stderr, "%s: file %" PRIu64 ": unexpected length %x (should be %x)\n", prg, idx, ncrc, crc);
Dieter Baronb2ed74d2004-04-14 14:01:31 +0000720 return -2;
721 }
722
723 return 0;
724}