Rizin
unix-like reverse engineering framework and cli tools
zipmerge.c
Go to the documentation of this file.
1 /*
2  zipmerge.c -- merge zip archives
3  Copyright (C) 2004-2021 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 <ctype.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include "config.h"
42 
43 #ifndef HAVE_GETOPT
44 #include "getopt.h"
45 #endif
46 
47 #include "zip.h"
48 
49 char *progname;
50 
51 #define PROGRAM "zipmerge"
52 
53 #define USAGE "usage: %s [-DhIiSsV] target-zip zip...\n"
54 
55 char help_head[] = PROGRAM " (" PACKAGE ") by Dieter Baron and Thomas Klausner\n\n";
56 
57 char help[] = "\n\
58  -h display this help message\n\
59  -V display version number\n\
60  -D ignore directory component in file names\n\
61  -I ignore case in file names\n\
62  -i ask before overwriting files\n\
63  -S don't overwrite identical files\n\
64  -s overwrite identical files without asking\n\
65 \n\
66 Report bugs to <libzip@nih.at>.\n";
67 
68 char version_string[] = PROGRAM " (" PACKAGE " " VERSION ")\n\
69 Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n\
70 " PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n";
71 
72 #define OPTIONS "hVDiIsS"
73 
74 #define CONFIRM_ALL_YES 0x001
75 #define CONFIRM_ALL_NO 0x002
76 #define CONFIRM_SAME_YES 0x010
77 #define CONFIRM_SAME_NO 0x020
78 
79 int confirm;
81 
82 static int confirm_replace(zip_t *, const char *, zip_uint64_t, zip_t *, const char *, zip_uint64_t);
83 static zip_t *merge_zip(zip_t *, const char *, const char *);
84 
85 
86 int
87 main(int argc, char *argv[]) {
88  zip_t *za;
89  zip_t **zs;
90  int c, err;
91  unsigned int i, n;
92  char *tname;
93 
94  progname = argv[0];
95 
97  name_flags = 0;
98 
99  while ((c = getopt(argc, argv, OPTIONS)) != -1) {
100  switch (c) {
101  case 'D':
103  break;
104  case 'i':
106  break;
107  case 'I':
109  break;
110  case 's':
113  break;
114  case 'S':
117  break;
118 
119  case 'h':
120  fputs(help_head, stdout);
122  fputs(help, stdout);
123  exit(0);
124  case 'V':
125  fputs(version_string, stdout);
126  exit(0);
127 
128  default:
129  fprintf(stderr, USAGE, progname);
130  exit(2);
131  }
132  }
133 
134  if (argc < optind + 2) {
135  fprintf(stderr, USAGE, progname);
136  exit(2);
137  }
138 
139  tname = argv[optind++];
140  argv += optind;
141 
142  n = (unsigned int)(argc - optind);
143  if ((zs = (zip_t **)malloc(sizeof(zs[0]) * n)) == NULL) {
144  fprintf(stderr, "%s: out of memory\n", progname);
145  exit(1);
146  }
147 
148  if ((za = zip_open(tname, ZIP_CREATE, &err)) == NULL) {
151  fprintf(stderr, "%s: can't open zip archive '%s': %s\n", progname, tname, zip_error_strerror(&error));
153  exit(1);
154  }
155 
156  for (i = 0; i < n; i++) {
157  if ((zs[i] = merge_zip(za, tname, argv[i])) == NULL)
158  exit(1);
159  }
160 
161  if (zip_close(za) < 0) {
162  fprintf(stderr, "%s: cannot write zip archive '%s': %s\n", progname, tname, zip_strerror(za));
163  exit(1);
164  }
165 
166  for (i = 0; i < n; i++)
167  zip_close(zs[i]);
168 
169  exit(0);
170 }
171 
172 
173 static int
174 confirm_replace(zip_t *za, const char *tname, zip_uint64_t it, zip_t *zs, const char *sname, zip_uint64_t is) {
175  char line[1024];
176  struct zip_stat st, ss;
177 
178  if (confirm & CONFIRM_ALL_YES)
179  return 1;
180  else if (confirm & CONFIRM_ALL_NO)
181  return 0;
182 
183  if (zip_stat_index(za, it, ZIP_FL_UNCHANGED, &st) < 0) {
184  fprintf(stderr, "%s: cannot stat file %" PRIu64 " in '%s': %s\n", progname, it, tname, zip_strerror(za));
185  return -1;
186  }
187  if (zip_stat_index(zs, is, 0, &ss) < 0) {
188  fprintf(stderr, "%s: cannot stat file %" PRIu64 " in '%s': %s\n", progname, is, sname, zip_strerror(zs));
189  return -1;
190  }
191 
192  if (st.size == ss.size && st.crc == ss.crc) {
194  return 1;
195  else if (confirm & CONFIRM_SAME_NO)
196  return 0;
197  }
198 
199  printf("replace '%s' (%" PRIu64 " / %08x) in `%s'\n"
200  " with '%s' (%" PRIu64 " / %08x) from `%s'? ",
201  st.name, st.size, st.crc, tname, ss.name, ss.size, ss.crc, sname);
202  fflush(stdout);
203 
204  if (fgets(line, sizeof(line), stdin) == NULL) {
205  fprintf(stderr, "%s: read error from stdin: %s\n", progname, strerror(errno));
206  return -1;
207  }
208 
209  if (tolower((unsigned char)line[0]) == 'y')
210  return 1;
211 
212  return 0;
213 }
214 
215 
216 static zip_t *
217 merge_zip(zip_t *za, const char *tname, const char *sname) {
218  zip_t *zs;
220  zip_int64_t ret, idx;
221  zip_uint64_t i;
222  int err;
223  const char *fname;
224 
225  if ((zs = zip_open(sname, 0, &err)) == NULL) {
228  fprintf(stderr, "%s: can't open zip archive '%s': %s\n", progname, sname, zip_error_strerror(&error));
230  return NULL;
231  }
232 
233  ret = zip_get_num_entries(zs, 0);
234  if (ret < 0) {
235  fprintf(stderr, "%s: cannot get number of entries for '%s': %s\n", progname, sname, zip_strerror(za));
236  return NULL;
237  }
238  for (i = 0; i < (zip_uint64_t)ret; i++) {
239  fname = zip_get_name(zs, i, 0);
240 
241  if ((idx = zip_name_locate(za, fname, name_flags)) >= 0) {
242  switch (confirm_replace(za, tname, (zip_uint64_t)idx, zs, sname, i)) {
243  case 0:
244  break;
245 
246  case 1:
247  if ((source = zip_source_zip(za, zs, i, 0, 0, 0)) == NULL || zip_replace(za, (zip_uint64_t)idx, source) < 0) {
249  fprintf(stderr, "%s: cannot replace '%s' in `%s': %s\n", progname, fname, tname, zip_strerror(za));
250  zip_close(zs);
251  return NULL;
252  }
253  break;
254 
255  case -1:
256  zip_close(zs);
257  return NULL;
258 
259  default:
260  fprintf(stderr,
261  "%s: internal error: "
262  "unexpected return code from confirm (%d)\n",
263  progname, err);
264  zip_close(zs);
265  return NULL;
266  }
267  }
268  else {
269  if ((source = zip_source_zip(za, zs, i, 0, 0, 0)) == NULL || zip_add(za, fname, source) < 0) {
271  fprintf(stderr, "%s: cannot add '%s' to `%s': %s\n", progname, fname, tname, zip_strerror(za));
272  zip_close(zs);
273  return NULL;
274  }
275  }
276  }
277 
278  return zs;
279 }
lzma_index ** i
Definition: index.h:629
static bool err
Definition: armass.c:435
#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
#define NULL
Definition: cris-opc.c:27
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
#define PRIu64
Definition: macros.h:18
ZIP_EXTERN void zip_error_init_with_code(zip_error_t *_Nonnull, int)
Definition: zip_error.c:66
ZIP_EXTERN zip_int64_t zip_name_locate(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t)
#define ZIP_FL_NODIR
Definition: zip.h:77
ZIP_EXTERN zip_int64_t zip_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull)
Definition: zip_add.c:47
ZIP_EXTERN const char *_Nullable zip_get_name(zip_t *_Nonnull, zip_uint64_t, zip_flags_t)
Definition: zip_get_name.c:41
#define ZIP_CREATE
Definition: zip.h:67
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
zip_uint32_t zip_flags_t
Definition: zip.h:347
ZIP_EXTERN zip_source_t *_Nullable zip_source_zip(zip_t *_Nonnull, zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t)
ZIP_EXTERN void zip_source_free(zip_source_t *_Nullable)
ZIP_EXTERN zip_t *_Nullable zip_open(const char *_Nonnull, int, int *_Nullable)
Definition: zip_open.c:54
ZIP_EXTERN int zip_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull)
Definition: zip_replace.c:40
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)
#define ZIP_FL_UNCHANGED
Definition: zip.h:79
ZIP_EXTERN zip_int64_t zip_get_num_entries(zip_t *_Nonnull, zip_flags_t)
#define ZIP_FL_NOCASE
Definition: zip.h:76
ZIP_EXTERN const char *_Nonnull zip_strerror(zip_t *_Nonnull)
Definition: zip_strerror.c:39
void * malloc(size_t size)
Definition: malloc.c:123
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
const char * source
Definition: lz4.h:699
int n
Definition: mipsasm.c:19
line
Definition: setup.py:34
int idx
Definition: setup.py:197
#define tolower(c)
Definition: safe-ctype.h:149
static int
Definition: sfsocketcall.h:114
#define c(i)
Definition: sha256.c:43
Definition: zip.h:284
Definition: zip.h:300
const char *_Nullable name
Definition: zip.h:302
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
uint64_t zip_uint64_t
Definition: zipconf.h:39
int64_t zip_int64_t
Definition: zipconf.h:38
int confirm
Definition: zipmerge.c:79
int main(int argc, char *argv[])
Definition: zipmerge.c:87
char help[]
Definition: zipmerge.c:57
static zip_t * merge_zip(zip_t *, const char *, const char *)
Definition: zipmerge.c:217
zip_flags_t name_flags
Definition: zipmerge.c:80
#define CONFIRM_ALL_NO
Definition: zipmerge.c:75
#define USAGE
Definition: zipmerge.c:53
#define CONFIRM_SAME_NO
Definition: zipmerge.c:77
#define CONFIRM_SAME_YES
Definition: zipmerge.c:76
char version_string[]
Definition: zipmerge.c:68
#define PROGRAM
Definition: zipmerge.c:51
char help_head[]
Definition: zipmerge.c:55
#define CONFIRM_ALL_YES
Definition: zipmerge.c:74
char * progname
Definition: zipmerge.c:49
#define OPTIONS
Definition: zipmerge.c:72
static int confirm_replace(zip_t *, const char *, zip_uint64_t, zip_t *, const char *, zip_uint64_t)
Definition: zipmerge.c:174
zip_t * za
Definition: ziptool.c:79