Rizin
unix-like reverse engineering framework and cli tools
zipcmp.c
Go to the documentation of this file.
1 /*
2  zipcmp.c -- compare zip files
3  Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner
4 
5  This file is part of libzip, a library to manipulate ZIP archives.
6  The authors can be contacted at <libzip@nih.at>
7 
8  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.
32 */
33 
34 
35 #include "config.h"
36 
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_STRINGS_H
43 #include <strings.h>
44 #endif
45 #ifdef HAVE_FTS_H
46 #include <fts.h>
47 #endif
48 #include <zlib.h>
49 
50 #ifndef HAVE_GETOPT
51 #include "getopt.h"
52 #endif
53 
54 #include "zip.h"
55 
56 #include "compat.h"
57 
58 #include "diff_output.h"
59 
60 struct archive {
61  const char *name;
64  struct entry *entry;
65  const char *comment;
67 };
68 
69 struct ef {
70  const char *name;
74  const zip_uint8_t *data;
75 };
76 
77 struct entry {
78  char *name;
82  struct ef *extra_fields;
84  const char *comment;
86 };
87 
88 
89 typedef struct {
91  const char * const name;
92 } enum_map_t;
93 
95  { 0, "Stored (no compression)" },
96  { 1, "Shrunk" },
97  { 2, "Reduced with compression factor 1" },
98  { 3, "Reduced with compression factor 2" },
99  { 4, "Reduced with compression factor 3" },
100  { 5, "Reduced with compression factor 4" },
101  { 6, "Imploded" },
102  { 7, "Reserved for Tokenizing compression algorithm" },
103  { 8, "Deflated" },
104  { 9, "Enhanced Deflating using Deflate64(tm)" },
105  { 10, "PKWARE Data Compression Library Imploding (old IBM TERSE)" },
106  { 11, "11 (Reserved by PKWARE)" },
107  { 12, "BZIP2" },
108  { 13, "13 (Reserved by PKWARE)" },
109  { 14, "LZMA (EFS)" },
110  { 15, "15 (Reserved by PKWARE)" },
111  { 16, "16 (Reserved by PKWARE)" },
112  { 17, "17 (Reserved by PKWARE)" },
113  { 18, "IBM TERSE (new)" },
114  { 19, "IBM LZ77 z Architecture (PFS)" },
115  { 20, "Zstandard compressed data (obsolete)" },
116  { 93, "Zstandard compressed data" },
117  { 95, "XZ compressed data" },
118  { 97, "WavPack compressed data" },
119  { 98, "PPMd version I, Rev 1" },
120  { 99, "WinZIP AES Encryption" },
121  { UINT32_MAX, NULL }
122 };
123 
125  /* PKWARE defined */
126  { 0x0001, "Zip64 extended information" },
127  { 0x0007, "AV Info" },
128  { 0x0008, "Reserved for extended language encoding data (PFS)" },
129  { 0x0009, "OS/2" },
130  { 0x000a, "NTFS" },
131  { 0x000c, "OpenVMS" },
132  { 0x000d, "UNIX" },
133  { 0x000e, "Reserved for file stream and fork descriptors" },
134  { 0x000f, "Patch Descriptor" },
135  { 0x0014, "PKCS#7 Store for X.509 Certificates" },
136  { 0x0015, "X.509 Certificate ID and Signature for individual file" },
137  { 0x0016, "X.509 Certificate ID for Central Directory" },
138  { 0x0017, "Strong Encryption Header" },
139  { 0x0018, "Record Management Controls" },
140  { 0x0019, "PKCS#7 Encryption Recipient Certificate List" },
141  { 0x0065, "IBM S/390 (Z390), AS/400 (I400) attributes - uncompressed" },
142  { 0x0066, "Reserved for IBM S/390 (Z390), AS/400 (I400) attributes - compressed" },
143  { 0x4690, "POSZIP 4690 (reserved)" },
144 
145  /* Third-Party defined; see InfoZIP unzip sources proginfo/extrafld.txt */
146  { 0x07c8, "Info-ZIP Macintosh (old)" },
147  { 0x2605, "ZipIt Macintosh (first version)" },
148  { 0x2705, "ZipIt Macintosh 1.3.5+ (w/o full filename)" },
149  { 0x2805, "ZipIt Macintosh 1.3.5+" },
150  { 0x334d, "Info-ZIP Macintosh (new)" },
151  { 0x4154, "Tandem NSK" },
152  { 0x4341, "Acorn/SparkFS" },
153  { 0x4453, "Windows NT security descriptor" },
154  { 0x4704, "VM/CMS" },
155  { 0x470f, "MVS" },
156  { 0x4854, "Theos, old unofficial port" },
157  { 0x4b46, "FWKCS MD5" },
158  { 0x4c41, "OS/2 access control list (text ACL)" },
159  { 0x4d49, "Info-ZIP OpenVMS (obsolete)" },
160  { 0x4d63, "Macintosh SmartZIP" },
161  { 0x4f4c, "Xceed original location extra field" },
162  { 0x5356, "AOS/VS (ACL)" },
163  { 0x5455, "extended timestamp" },
164  { 0x554e, "Xceed unicode extra field" },
165  { 0x5855, "Info-ZIP UNIX (original)" },
166  { 0x6375, "Info-ZIP UTF-8 comment field" },
167  { 0x6542, "BeOS (BeBox, PowerMac, etc.)" },
168  { 0x6854, "Theos" },
169  { 0x7075, "Info-ZIP UTF-8 name field" },
170  { 0x7441, "AtheOS (AtheOS/Syllable attributes)" },
171  { 0x756e, "ASi UNIX" },
172  { 0x7855, "Info-ZIP UNIX" },
173  { 0x7875, "Info-ZIP UNIX 3rd generation" },
174  { 0x9901, "WinZIP AES encryption" },
175  { 0xa220, "Microsoft Open Packaging Growth Hint" },
176  { 0xcafe, "executable Java JAR file" },
177  { 0xfb4a, "SMS/QDOS" }, /* per InfoZIP extrafld.txt */
178  { 0xfd4a, "SMS/QDOS" }, /* per appnote.txt */
179  { UINT32_MAX, NULL }
180 };
181 
182 
183 const char *progname;
184 
185 #define PROGRAM "zipcmp"
186 
187 #define USAGE "usage: %s [-hipqtVv] archive1 archive2\n"
188 
189 char help_head[] = PROGRAM " (" PACKAGE ") by Dieter Baron and Thomas Klausner\n\n";
190 
191 char help[] = "\n\
192  -h display this help message\n\
193  -C check archive consistencies\n\
194  -i compare names ignoring case distinctions\n\
195  -p compare as many details as possible\n\
196  -q be quiet\n\
197  -s print a summary\n\
198  -t test zip files (compare file contents to checksum)\n\
199  -V display version number\n\
200  -v be verbose (print differences, default)\n\
201 \n\
202 Report bugs to <libzip@nih.at>.\n";
203 
204 char version_string[] = PROGRAM " (" PACKAGE " " VERSION ")\n\
205 Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n\
206 " PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n";
207 
208 #define OPTIONS "hVCipqstv"
209 
210 
211 #define BOTH_ARE_ZIPS(a) (a[0].za && a[1].za)
212 
213 static int comment_compare(const char *c1, size_t l1, const char *c2, size_t l2);
214 static int compare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int (*cmp)(const void *a, const void *b), int (*ignore)(const void *list, int last, const void *other), int (*check)(char *const name[2], const void *a, const void *b), void (*print)(char side, const void *element), void (*start_file)(const void *element));
215 static int compare_zip(char *const zn[]);
216 static int ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2);
217 static int ef_order(const void *a, const void *b);
218 static void ef_print(char side, const void *p);
219 static int ef_read(zip_t *za, zip_uint64_t idx, struct entry *e);
220 static int entry_cmp(const void *p1, const void *p2);
221 static int entry_ignore(const void *p1, int last, const void *o);
222 static int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2);
223 static void entry_print(char side, const void *p);
224 static void entry_start_file(const void *p);
225 static const char *map_enum(const enum_map_t *map, uint32_t value);
226 
227 static int is_directory(const char *name);
228 #ifdef HAVE_FTS_H
229 static int list_directory(const char *name, struct archive *a);
230 #endif
231 static int list_zip(const char *name, struct archive *a);
232 static int test_file(zip_t *za, zip_uint64_t idx, const char *zipname, const char *filename, zip_uint64_t size, zip_uint32_t crc);
233 
235 int plus_count = 0, minus_count = 0;
236 
238 
239 
240 int
241 main(int argc, char *const argv[]) {
242  int c;
243 
244  progname = argv[0];
245 
246  ignore_case = 0;
247  test_files = 0;
248  check_consistency = 0;
249  paranoid = 0;
250  have_directory = 0;
251  verbose = 1;
252  summary = 0;
253 
254  while ((c = getopt(argc, argv, OPTIONS)) != -1) {
255  switch (c) {
256  case 'C':
257  check_consistency = 1;
258  break;
259  case 'i':
260  ignore_case = 1;
261  break;
262  case 'p':
263  paranoid = 1;
264  break;
265  case 'q':
266  verbose = 0;
267  break;
268  case 's':
269  summary = 1;
270  break;
271  case 't':
272  test_files = 1;
273  break;
274  case 'v':
275  verbose = 1;
276  break;
277 
278  case 'h':
279  fputs(help_head, stdout);
281  fputs(help, stdout);
282  exit(0);
283  case 'V':
284  fputs(version_string, stdout);
285  exit(0);
286 
287  default:
288  fprintf(stderr, USAGE, progname);
289  exit(2);
290  }
291  }
292 
293  if (argc != optind + 2) {
294  fprintf(stderr, USAGE, progname);
295  exit(2);
296  }
297 
298  exit((compare_zip(argv + optind) == 0) ? 0 : 1);
299 }
300 
301 
302 static int
303 compare_zip(char *const zn[]) {
304  struct archive a[2];
305  struct entry *e[2];
306  zip_uint64_t n[2];
307  int i;
308  int res;
309 
310  for (i = 0; i < 2; i++) {
311  a[i].name = zn[i];
312  a[i].entry = NULL;
313  a[i].nentry = 0;
314  a[i].za = NULL;
315  a[i].comment = NULL;
316  a[i].comment_length = 0;
317 
318  if (is_directory(zn[i])) {
319 #ifndef HAVE_FTS_H
320  fprintf(stderr, "%s: reading directories not supported\n", progname);
321  exit(2);
322 #else
323  if (list_directory(zn[i], a + i) < 0)
324  exit(2);
325  have_directory = 1;
326  paranoid = 0; /* paranoid checks make no sense for directories, since they compare zip metadata */
327 #endif
328  }
329  else {
330  if (list_zip(zn[i], a + i) < 0)
331  exit(2);
332  }
333  if (a[i].nentry > 0)
334  qsort(a[i].entry, a[i].nentry, sizeof(a[i].entry[0]), entry_cmp);
335  }
336 
338 
339  e[0] = a[0].entry;
340  e[1] = a[1].entry;
341  n[0] = a[0].nentry;
342  n[1] = a[1].nentry;
344 
345  if (paranoid) {
346  if (comment_compare(a[0].comment, a[0].comment_length, a[1].comment, a[1].comment_length) != 0) {
347  if (a[0].comment_length > 0) {
348  diff_output_data(&output, '-', (const zip_uint8_t *)a[0].comment, a[0].comment_length, "archive comment");
349  minus_count++;
350  }
351  if (a[1].comment_length > 0) {
352  diff_output_data(&output, '+', (const zip_uint8_t *)a[1].comment, a[1].comment_length, "archive comment");
353  plus_count++;
354  }
355  res = 1;
356  }
357  }
358 
359  for (i = 0; i < 2; i++) {
360  zip_uint64_t j;
361 
362  if (a[i].za) {
363  zip_close(a[i].za);
364  }
365  for (j = 0; j < a[i].nentry; j++) {
366  free(a[i].entry[j].name);
367  }
368  free(a[i].entry);
369  }
370 
371  if (summary) {
372  printf("%d files removed, %d files added\n", minus_count, plus_count);
373  }
374 
375  switch (res) {
376  case 0:
377  exit(0);
378 
379  case 1:
380  exit(1);
381 
382  default:
383  exit(2);
384  }
385 }
386 
387 #ifdef HAVE_FTS_H
388 static zip_int64_t
389 compute_crc(const char *fname) {
390  FILE *f;
391  uLong crc = crc32(0L, Z_NULL, 0);
392  size_t n;
393  Bytef buffer[8192];
394 
395 
396  if ((f = fopen(fname, "rb")) == NULL) {
397  fprintf(stderr, "%s: can't open %s: %s\n", progname, fname, strerror(errno));
398  return -1;
399  }
400 
401  while ((n = fread(buffer, 1, sizeof(buffer), f)) > 0) {
402  crc = crc32(crc, buffer, (unsigned int)n);
403  }
404 
405  if (ferror(f)) {
406  fprintf(stderr, "%s: read error on %s: %s\n", progname, fname, strerror(errno));
407  fclose(f);
408  return -1;
409  }
410 
411  fclose(f);
412 
413  return (zip_int64_t)crc;
414 }
415 #endif
416 
417 
418 static int
419 is_directory(const char *name) {
420  struct stat st;
421 
422  if (stat(name, &st) < 0)
423  return 0;
424 
425  return S_ISDIR(st.st_mode);
426 }
427 
428 
429 #ifdef HAVE_FTS_H
430 static int
431 list_directory(const char *name, struct archive *a) {
432  FTS *fts;
433  FTSENT *ent;
434  zip_uint64_t nalloc;
435  size_t prefix_length;
436 
437  char *const names[2] = {(char *)name, NULL};
438 
439 
440  if ((fts = fts_open(names, FTS_NOCHDIR | FTS_LOGICAL, NULL)) == NULL) {
441  fprintf(stderr, "%s: can't open directory '%s': %s\n", progname, name, strerror(errno));
442  return -1;
443  }
444  prefix_length = strlen(name) + 1;
445 
446  nalloc = 0;
447 
448  while ((ent = fts_read(fts))) {
449  zip_int64_t crc;
450 
451  switch (ent->fts_info) {
452  case FTS_DOT:
453  case FTS_DP:
454  case FTS_DEFAULT:
455  case FTS_SL:
456  case FTS_NSOK:
457  break;
458 
459  case FTS_DC:
460  case FTS_DNR:
461  case FTS_ERR:
462  case FTS_NS:
463  case FTS_SLNONE:
464  /* TODO: error */
465  fts_close(fts);
466  return -1;
467 
468  case FTS_D:
469  case FTS_F:
470  if (a->nentry >= nalloc) {
471  nalloc += 16;
472  if (nalloc > SIZE_MAX / sizeof(a->entry[0])) {
473  fprintf(stderr, "%s: malloc failure\n", progname);
474  exit(1);
475  }
476  a->entry = realloc(a->entry, sizeof(a->entry[0]) * nalloc);
477  if (a->entry == NULL) {
478  fprintf(stderr, "%s: malloc failure\n", progname);
479  exit(1);
480  }
481  }
482 
483  if (ent->fts_info == FTS_D) {
484  char *dir_name;
485 
486  if (ent->fts_path[prefix_length - 1] == '\0') {
487  break;
488  }
489 
490  dir_name = malloc(strlen(ent->fts_path + prefix_length) + 2);
491  if (dir_name == NULL) {
492  fprintf(stderr, "%s: malloc failure\n", progname);
493  exit(1);
494  }
495  sprintf(dir_name, "%s/", ent->fts_path + prefix_length);
496  a->entry[a->nentry].name = dir_name;
497  a->entry[a->nentry].size = 0;
498  a->entry[a->nentry].crc = 0;
499  }
500  else {
501  a->entry[a->nentry].name = strdup(ent->fts_path + prefix_length);
502  a->entry[a->nentry].size = (zip_uint64_t)ent->fts_statp->st_size;
503  if ((crc = compute_crc(ent->fts_accpath)) < 0) {
504  fts_close(fts);
505  return -1;
506  }
507 
508  a->entry[a->nentry].crc = (zip_uint32_t)crc;
509  }
510  a->nentry++;
511  break;
512  }
513  }
514 
515  if (fts_close(fts)) {
516  fprintf(stderr, "%s: error closing directory '%s': %s\n", progname, a->name, strerror(errno));
517  return -1;
518  }
519 
520  return 0;
521 }
522 #endif
523 
524 
525 static int
526 list_zip(const char *name, struct archive *a) {
527  zip_t *za;
528  int err;
529  struct zip_stat st;
530  unsigned int i;
531 
532  if ((za = zip_open(name, check_consistency ? ZIP_CHECKCONS : 0, &err)) == NULL) {
535  fprintf(stderr, "%s: cannot open zip archive '%s': %s\n", progname, name, zip_error_strerror(&error));
537  return -1;
538  }
539 
540  a->za = za;
541  a->nentry = (zip_uint64_t)zip_get_num_entries(za, 0);
542 
543  if (a->nentry == 0)
544  a->entry = NULL;
545  else {
546  if ((a->nentry > SIZE_MAX / sizeof(a->entry[0])) || (a->entry = (struct entry *)malloc(sizeof(a->entry[0]) * a->nentry)) == NULL) {
547  fprintf(stderr, "%s: malloc failure\n", progname);
548  exit(1);
549  }
550 
551  for (i = 0; i < a->nentry; i++) {
552  zip_stat_index(za, i, 0, &st);
553  a->entry[i].name = strdup(st.name);
554  a->entry[i].size = st.size;
555  a->entry[i].crc = st.crc;
556  if (test_files)
557  test_file(za, i, name, st.name, st.size, st.crc);
558  if (paranoid) {
559  a->entry[i].comp_method = st.comp_method;
560  ef_read(za, i, a->entry + i);
561  a->entry[i].comment = zip_file_get_comment(za, i, &a->entry[i].comment_length, 0);
562  }
563  else {
564  a->entry[i].comp_method = 0;
565  a->entry[i].n_extra_fields = 0;
566  }
567  }
568 
569  if (paranoid) {
570  int length;
571  a->comment = zip_get_archive_comment(za, &length, 0);
572  a->comment_length = (size_t)length;
573  }
574  else {
575  a->comment = NULL;
576  a->comment_length = 0;
577  }
578  }
579 
580  return 0;
581 }
582 
583 
584 static int
585 comment_compare(const char *c1, size_t l1, const char *c2, size_t l2) {
586  if (l1 != l2)
587  return 1;
588 
589  if (l1 == 0)
590  return 0;
591 
592  if (c1 == NULL || c2 == NULL)
593  return c1 == c2;
594 
595  return memcmp(c1, c2, (size_t)l2);
596 }
597 
598 
599 static int compare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int (*cmp)(const void *a, const void *b), int (*ignore)(const void *list, int last, const void *other), int (*check)(char *const name[2], const void *a, const void *b), void (*print)(char side, const void *element), void (*start_file)(const void *element)) {
600  unsigned int i[2];
601  int j;
602  int diff;
603 
604 #define INC(k) (i[k]++, list[k] = ((const char *)list[k]) + element_size)
605 #define PRINT(k) \
606  do { \
607  if (ignore && ignore(list[k], i[k] >= list_length[k] - 1, i[1-k] < list_length[1-k] ? list[1-k] : NULL)) { \
608  break; \
609  } \
610  print((k) ? '+' : '-', list[k]); \
611  (k) ? plus_count++ : minus_count++; \
612  diff = 1; \
613  } while (0)
614 
615  i[0] = i[1] = 0;
616  diff = 0;
617  while (i[0] < list_length[0] && i[1] < list_length[1]) {
618  int c = cmp(list[0], list[1]);
619 
620  if (c == 0) {
621  if (check) {
622  if (start_file) {
623  start_file(list[0]);
624  }
625  diff |= check(name, list[0], list[1]);
626  if (start_file) {
628  }
629  }
630  INC(0);
631  INC(1);
632  }
633  else if (c < 0) {
634  PRINT(0);
635  INC(0);
636  }
637  else {
638  PRINT(1);
639  INC(1);
640  }
641  }
642 
643  for (j = 0; j < 2; j++) {
644  while (i[j] < list_length[j]) {
645  PRINT(j);
646  INC(j);
647  }
648  }
649 
650  return diff;
651 }
652 
653 
654 static int
656  zip_int16_t n_local, n_central;
657  zip_uint16_t i;
658 
659  if ((n_local = zip_file_extra_fields_count(za, idx, ZIP_FL_LOCAL)) < 0 || (n_central = zip_file_extra_fields_count(za, idx, ZIP_FL_CENTRAL)) < 0) {
660  return -1;
661  }
662 
663  e->n_extra_fields = (zip_uint16_t)(n_local + n_central);
664 
665  if ((e->extra_fields = (struct ef *)malloc(sizeof(e->extra_fields[0]) * e->n_extra_fields)) == NULL)
666  return -1;
667 
668  for (i = 0; i < n_local; i++) {
669  e->extra_fields[i].name = e->name;
670  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);
671  if (e->extra_fields[i].data == NULL)
672  return -1;
673  e->extra_fields[i].flags = ZIP_FL_LOCAL;
674  }
675  for (; i < e->n_extra_fields; i++) {
676  e->extra_fields[i].name = e->name;
677  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);
678  if (e->extra_fields[i].data == NULL)
679  return -1;
680  e->extra_fields[i].flags = ZIP_FL_CENTRAL;
681  }
682 
683  qsort(e->extra_fields, e->n_extra_fields, sizeof(e->extra_fields[0]), ef_order);
684 
685  return 0;
686 }
687 
688 
689 static int
690 ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2) {
691  struct ef *ef[2];
692  zip_uint64_t n[2];
693 
694  ef[0] = e1->extra_fields;
695  ef[1] = e2->extra_fields;
696  n[0] = e1->n_extra_fields;
697  n[1] = e2->n_extra_fields;
698 
699  return compare_list(name, (const void **)ef, n, sizeof(struct ef), ef_order, NULL, NULL, ef_print, NULL);
700 }
701 
702 
703 static int
704 ef_order(const void *ap, const void *bp) {
705  const struct ef *a, *b;
706 
707  a = (struct ef *)ap;
708  b = (struct ef *)bp;
709 
710  if (a->flags != b->flags)
711  return a->flags - b->flags;
712  if (a->id != b->id)
713  return a->id - b->id;
714  if (a->size != b->size)
715  return a->size - b->size;
716  return memcmp(a->data, b->data, a->size);
717 }
718 
719 
720 static void
721 ef_print(char side, const void *p) {
722  const struct ef *ef = (struct ef *)p;
723 
724  diff_output_data(&output, side, ef->data, ef->size, " %s extra field %s", ef->flags == ZIP_FL_LOCAL ? "local" : "central", map_enum(extra_fields, ef->id));
725 }
726 
727 
728 static int
729 entry_cmp(const void *p1, const void *p2) {
730  const struct entry *e1, *e2;
731  int c;
732 
733  e1 = (struct entry *)p1;
734  e2 = (struct entry *)p2;
735 
736  if ((c = (ignore_case ? strcasecmp : strcmp)(e1->name, e2->name)) != 0)
737  return c;
738  if (e1->size != e2->size) {
739  if (e1->size > e2->size)
740  return 1;
741  else
742  return -1;
743  }
744  if (e1->crc != e2->crc)
745  return (int)e1->crc - (int)e2->crc;
746 
747  return 0;
748 }
749 
750 
751 static int
752 entry_ignore(const void *p, int last, const void *o) {
753  const struct entry *e = (const struct entry *)p;
754  const struct entry *other = (const struct entry *)o;
755 
756  size_t length = strlen(e[0].name);
757 
758  if (length == 0 || e[0].name[length - 1] != '/') {
759  /* not a directory */
760  return 0;
761  }
762 
763  if (other != NULL && strlen(other->name) > length && strncmp(other->name, e[0].name, length) == 0) {
764  /* not empty in other archive */
765  return 1;
766  }
767 
768  if (last || (strlen(e[1].name) < length || strncmp(e[0].name, e[1].name, length) != 0)) {
769  /* empty in this archive */
770  return 0;
771  }
772 
773  /* not empty in this archive */
774  return 1;
775 }
776 
777 
778 static int
779 entry_paranoia_checks(char *const name[2], const void *p1, const void *p2) {
780  const struct entry *e1, *e2;
781  int ret;
782 
783  e1 = (struct entry *)p1;
784  e2 = (struct entry *)p2;
785 
786  ret = 0;
787 
788  if (e1->comp_method != e2->comp_method) {
789  diff_output(&output, '-', " compression method %s", map_enum(comp_methods, e1->comp_method));
790  diff_output(&output, '+', " compression method %s", map_enum(comp_methods, e2->comp_method));
791  ret = 1;
792  }
793 
794  if (ef_compare(name, e1, e2) != 0) {
795  ret = 1;
796  }
797 
798  if (comment_compare(e1->comment, e1->comment_length, e2->comment, e2->comment_length) != 0) {
799  diff_output_data(&output, '-', (const zip_uint8_t *)e1->comment, e1->comment_length, " comment");
800  diff_output_data(&output, '+', (const zip_uint8_t *)e2->comment, e2->comment_length, " comment");
801  ret = 1;
802  }
803 
804  return ret;
805 }
806 
807 
808 static void entry_print(char side, const void *p) {
809  const struct entry *e = (struct entry *)p;
810 
811  diff_output_file(&output, side, e->name, e->size, e->crc);
812 }
813 
814 
815 static void entry_start_file(const void *p) {
816  const struct entry *e = (struct entry *)p;
817 
818  diff_output_start_file(&output, e->name, e->size, e->crc);
819 }
820 
821 
822 static int
823 test_file(zip_t *za, zip_uint64_t idx, const char *zipname, const char *filename, zip_uint64_t size, zip_uint32_t crc) {
824  zip_file_t *zf;
825  char buf[8192];
826  zip_uint64_t nsize;
827  zip_int64_t n;
828  zip_uint32_t ncrc;
829 
830  if ((zf = zip_fopen_index(za, idx, 0)) == NULL) {
831  fprintf(stderr, "%s: %s: cannot open file %s (index %" PRIu64 "): %s\n", progname, zipname, filename, idx, zip_strerror(za));
832  return -1;
833  }
834 
835  ncrc = (zip_uint32_t)crc32(0, NULL, 0);
836  nsize = 0;
837 
838  while ((n = zip_fread(zf, buf, sizeof(buf))) > 0) {
839  nsize += (zip_uint64_t)n;
840  ncrc = (zip_uint32_t)crc32(ncrc, (const Bytef *)buf, (unsigned int)n);
841  }
842 
843  if (n < 0) {
844  fprintf(stderr, "%s: %s: error reading file %s (index %" PRIu64 "): %s\n", progname, zipname, filename, idx, zip_file_strerror(zf));
845  zip_fclose(zf);
846  return -1;
847  }
848 
849  zip_fclose(zf);
850 
851  if (nsize != size) {
852  fprintf(stderr, "%s: %s: file %s (index %" PRIu64 "): unexpected length %" PRId64 " (should be %" PRId64 ")\n", progname, zipname, filename, idx, nsize, size);
853  return -2;
854  }
855  if (ncrc != crc) {
856  fprintf(stderr, "%s: %s: file %s (index %" PRIu64 "): unexpected length %x (should be %x)\n", progname, zipname, filename, idx, ncrc, crc);
857  return -2;
858  }
859 
860  return 0;
861 }
862 
863 
864 static const char *map_enum(const enum_map_t *map, uint32_t value) {
865  static char unknown[16];
866  size_t i = 0;
867 
868  while (map[i].value < UINT32_MAX) {
869  if (map[i].value == value) {
870  return map[i].name;
871  }
872  i++;
873  }
874 
875  snprintf(unknown, sizeof(unknown), "unknown (%u)", value);
876  unknown[sizeof(unknown) - 1] = '\0';
877 
878  return unknown;
879 }
#define e(frag)
lzma_index ** i
Definition: index.h:629
static RzILOpEffect * cmp(cs_insn *insn, bool is_thumb)
Definition: arm_il32.c:942
static bool err
Definition: armass.c:435
lsl lsr asr ror lsl lsr asr ror lsl lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror c1
lsl lsr asr ror lsl lsr asr ror lsl lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror c2
#define VERSION
Definition: config.h:54
#define PACKAGE
Definition: config.h:59
int getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.h:20
int optind
Definition: getopt.h:6
static int value
Definition: cmd_api.c:93
#define S_ISDIR(mode)
Definition: compat.h:187
lzma_check check
Definition: container.h:292
#define NULL
Definition: cris-opc.c:27
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
void diff_output_file(diff_output_t *output, char side, const char *name, zip_uint64_t size, zip_uint32_t crc)
Definition: diff_output.c:59
void diff_output_data(diff_output_t *output, int side, const zip_uint8_t *data, zip_uint64_t data_length, const char *fmt,...)
Definition: diff_output.c:75
void diff_output(diff_output_t *output, int side, const char *fmt,...)
Definition: diff_output.c:38
void diff_output_end_file(diff_output_t *output)
Definition: diff_output.c:34
void diff_output_start_file(diff_output_t *output, const char *name, zip_uint64_t size, zip_uint32_t crc)
Definition: diff_output.c:28
void diff_output_init(diff_output_t *output, int verbose, char *const archive_names[])
Definition: diff_output.c:19
size_t map(int syms, int left, int len)
Definition: enough.c:237
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
const char * filename
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
sprintf
Definition: kernel.h:365
void * p
Definition: libc.cpp:67
#define PRIu64
Definition: macros.h:18
#define PRId64
Definition: macros.h:17
static void list(RzEgg *egg)
Definition: rz-gg.c:52
ZIP_EXTERN const zip_uint8_t *_Nullable zip_file_extra_field_get(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_uint16_t *_Nullable, zip_flags_t)
ZIP_EXTERN void zip_error_init_with_code(zip_error_t *_Nonnull, int)
Definition: zip_error.c:66
ZIP_EXTERN int zip_fclose(zip_file_t *_Nonnull)
Definition: zip_fclose.c:41
ZIP_EXTERN const char *_Nonnull zip_file_strerror(zip_file_t *_Nonnull)
#define ZIP_CHECKCONS
Definition: zip.h:69
ZIP_EXTERN zip_int16_t zip_file_extra_fields_count(zip_t *_Nonnull, zip_uint64_t, zip_flags_t)
ZIP_EXTERN const char *_Nullable zip_get_archive_comment(zip_t *_Nonnull, int *_Nullable, zip_flags_t)
#define ZIP_FL_LOCAL
Definition: zip.h:85
ZIP_EXTERN const char *_Nullable zip_file_get_comment(zip_t *_Nonnull, zip_uint64_t, zip_uint32_t *_Nullable, zip_flags_t)
ZIP_EXTERN zip_int64_t zip_fread(zip_file_t *_Nonnull, void *_Nonnull, zip_uint64_t)
Definition: zip_fread.c:39
ZIP_EXTERN int zip_close(zip_t *_Nonnull)
Definition: zip_close.c:52
ZIP_EXTERN void zip_error_fini(zip_error_t *_Nonnull)
Definition: zip_error.c:52
#define ZIP_FL_CENTRAL
Definition: zip.h:86
ZIP_EXTERN zip_t *_Nullable zip_open(const char *_Nonnull, int, int *_Nullable)
Definition: zip_open.c:54
ZIP_EXTERN int zip_stat_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_stat_t *_Nonnull)
ZIP_EXTERN const char *_Nonnull zip_error_strerror(zip_error_t *_Nonnull)
ZIP_EXTERN zip_int64_t zip_get_num_entries(zip_t *_Nonnull, zip_flags_t)
ZIP_EXTERN zip_file_t *_Nullable zip_fopen_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t)
ZIP_EXTERN const char *_Nonnull zip_strerror(zip_t *_Nonnull)
Definition: zip_strerror.c:39
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
static stat
Definition: sflib.h:131
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
int n
Definition: mipsasm.c:19
string FILE
Definition: benchmark.py:21
int idx
Definition: setup.py:197
void qsort(void *a, size_t n, size_t es, int(*cmp)(const void *, const void *))
Definition: qsort.h:130
static int
Definition: sfsocketcall.h:114
int size_t
Definition: sftypes.h:40
unsigned int uint32_t
Definition: sftypes.h:29
#define b(i)
Definition: sha256.c:42
#define f(i)
Definition: sha256.c:46
#define c(i)
Definition: sha256.c:43
#define a(i)
Definition: sha256.c:41
#define SIZE_MAX
#define UINT32_MAX
Definition: zipcmp.c:60
zip_t * za
Definition: zipcmp.c:62
const char * comment
Definition: zipcmp.c:65
size_t comment_length
Definition: zipcmp.c:66
const char * name
Definition: zipcmp.c:61
struct entry * entry
Definition: zipcmp.c:64
zip_uint64_t nentry
Definition: zipcmp.c:63
Definition: buffer.h:15
Definition: zipcmp.c:69
zip_uint16_t size
Definition: zipcmp.c:73
const char * name
Definition: zipcmp.c:70
zip_uint16_t id
Definition: zipcmp.c:72
const zip_uint8_t * data
Definition: zipcmp.c:74
zip_uint16_t flags
Definition: zipcmp.c:71
Definition: zipcmp.c:77
zip_uint32_t comp_method
Definition: zipcmp.c:81
zip_uint64_t size
Definition: zipcmp.c:79
struct ef * extra_fields
Definition: zipcmp.c:82
zip_uint16_t n_extra_fields
Definition: zipcmp.c:83
const char * comment
Definition: zipcmp.c:84
zip_uint32_t crc
Definition: zipcmp.c:80
zip_uint32_t comment_length
Definition: zipcmp.c:85
char * name
Definition: zipcmp.c:78
uint32_t value
Definition: zipcmp.c:90
const char *const name
Definition: zipcmp.c:91
Definition: z80asm.h:102
Definition: names.h:123
Definition: sftypes.h:80
Definition: zip.h:284
Definition: zip.h:300
const char *_Nullable name
Definition: zip.h:302
zip_uint16_t comp_method
Definition: zip.h:308
zip_uint32_t crc
Definition: zip.h:307
zip_uint64_t size
Definition: zip.h:304
Definition: zipint.h:278
void error(const char *msg)
Definition: untgz.c:593
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
unsigned long uLong
Definition: zconf.h:394
Byte FAR Bytef
Definition: zconf.h:400
#define L
Definition: zip_err_str.c:7
diff_output_t output
Definition: zipcmp.c:237
int ignore_case
Definition: zipcmp.c:234
int verbose
Definition: zipcmp.c:234
static void entry_print(char side, const void *p)
Definition: zipcmp.c:808
static int entry_ignore(const void *p1, int last, const void *o)
Definition: zipcmp.c:752
static const char * map_enum(const enum_map_t *map, uint32_t value)
Definition: zipcmp.c:864
char help[]
Definition: zipcmp.c:191
static void ef_print(char side, const void *p)
Definition: zipcmp.c:721
int plus_count
Definition: zipcmp.c:235
static int is_directory(const char *name)
Definition: zipcmp.c:419
static int compare_zip(char *const zn[])
Definition: zipcmp.c:303
const enum_map_t extra_fields[]
Definition: zipcmp.c:124
static int entry_cmp(const void *p1, const void *p2)
Definition: zipcmp.c:729
#define USAGE
Definition: zipcmp.c:187
#define PRINT(k)
static int test_file(zip_t *za, zip_uint64_t idx, const char *zipname, const char *filename, zip_uint64_t size, zip_uint32_t crc)
Definition: zipcmp.c:823
char version_string[]
Definition: zipcmp.c:204
static int ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2)
Definition: zipcmp.c:690
int have_directory
Definition: zipcmp.c:234
static int compare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int(*cmp)(const void *a, const void *b), int(*ignore)(const void *list, int last, const void *other), int(*check)(char *const name[2], const void *a, const void *b), void(*print)(char side, const void *element), void(*start_file)(const void *element))
Definition: zipcmp.c:599
static void entry_start_file(const void *p)
Definition: zipcmp.c:815
const enum_map_t comp_methods[]
Definition: zipcmp.c:94
#define PROGRAM
Definition: zipcmp.c:185
char help_head[]
Definition: zipcmp.c:189
int test_files
Definition: zipcmp.c:234
static int comment_compare(const char *c1, size_t l1, const char *c2, size_t l2)
Definition: zipcmp.c:585
static int ef_order(const void *a, const void *b)
Definition: zipcmp.c:704
int minus_count
Definition: zipcmp.c:235
static int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2)
Definition: zipcmp.c:779
static int ef_read(zip_t *za, zip_uint64_t idx, struct entry *e)
Definition: zipcmp.c:655
int paranoid
Definition: zipcmp.c:234
static int list_zip(const char *name, struct archive *a)
Definition: zipcmp.c:526
int check_consistency
Definition: zipcmp.c:234
const char * progname
Definition: zipcmp.c:183
int summary
Definition: zipcmp.c:234
#define OPTIONS
Definition: zipcmp.c:208
int main(int argc, char *const argv[])
Definition: zipcmp.c:241
#define INC(k)
int16_t zip_int16_t
Definition: zipconf.h:34
uint64_t zip_uint64_t
Definition: zipconf.h:39
uint32_t zip_uint32_t
Definition: zipconf.h:37
uint8_t zip_uint8_t
Definition: zipconf.h:33
uint16_t zip_uint16_t
Definition: zipconf.h:35
int64_t zip_int64_t
Definition: zipconf.h:38
zip_t * za
Definition: ziptool.c:79
unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, uInt len)
Definition: crc32.c:1063
#define Z_NULL
Definition: zlib.h:212