diff options
Diffstat (limited to 'dep/libzip/src/zipmerge.c')
-rw-r--r-- | dep/libzip/src/zipmerge.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/dep/libzip/src/zipmerge.c b/dep/libzip/src/zipmerge.c new file mode 100644 index 00000000000..03af58ade86 --- /dev/null +++ b/dep/libzip/src/zipmerge.c @@ -0,0 +1,291 @@ +/* + zipmerge.c -- merge zip archives + Copyright (C) 2004-2008 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at <libzip@nih.at> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "config.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "zip.h" + + + +char *prg; + +#define PROGRAM "zipmerge" + +char *usage = "usage: %s [-DhIiSsV] target-zip zip...\n"; + +char help_head[] = + PROGRAM " (" PACKAGE ") by Dieter Baron and Thomas Klausner\n\n"; + +char help[] = "\n\ + -h display this help message\n\ + -V display version number\n\ + -D ignore directory component in file names\n\ + -I ignore case in file names\n\ + -i ask before overwriting files\n\ + -S don't overwrite identical files\n\ + -s overwrite identical files without asking\n\ +\n\ +Report bugs to <libizp@nih.at>.\n"; + +char version_string[] = PROGRAM " (" PACKAGE " " VERSION ")\n\ +Copyright (C) 2008 Dieter Baron and Thomas Klausner\n\ +" PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n"; + +#define OPTIONS "hVDiIsS" + +#define CONFIRM_ALL_YES 0x001 +#define CONFIRM_ALL_NO 0x002 +#define CONFIRM_SAME_YES 0x010 +#define CONFIRM_SAME_NO 0x020 + +int confirm; +int name_flags; + +static int confirm_replace(struct zip *, const char *, int, + struct zip *, const char *, int); +static int merge_zip(struct zip *za, const char *, const char *, struct zip **); + + + +int +main(int argc, char *argv[]) +{ + struct zip *za; + struct zip **zs; + int c, err, i; + char errstr[1024], *tname; + + prg = argv[0]; + + confirm = CONFIRM_ALL_YES; + name_flags = 0; + + while ((c=getopt(argc, argv, OPTIONS)) != -1) { + switch (c) { + case 'D': + name_flags |= ZIP_FL_NODIR; + break; + case 'i': + confirm &= ~CONFIRM_ALL_YES; + break; + case 'I': + name_flags |= ZIP_FL_NOCASE; + break; + case 's': + confirm &= ~CONFIRM_SAME_NO; + confirm |= CONFIRM_SAME_YES; + break; + case 'S': + confirm &= ~CONFIRM_SAME_YES; + confirm |= CONFIRM_SAME_NO; + break; + + case 'h': + fputs(help_head, stdout); + printf(usage, prg); + fputs(help, stdout); + exit(0); + case 'V': + fputs(version_string, stdout); + exit(0); + + default: + fprintf(stderr, usage, prg); + exit(2); + } + } + + if (argc < optind+2) { + fprintf(stderr, usage, prg); + exit(2); + } + + tname = argv[optind++]; + + if ((zs=malloc(sizeof(zs[0])*(argc-optind))) == NULL) { + fprintf(stderr, "%s: out of memory\n", prg); + exit(1); + } + + if ((za=zip_open(tname, ZIP_CREATE, &err)) == NULL) { + zip_error_to_str(errstr, sizeof(errstr), err, errno); + fprintf(stderr, "%s: cannot open zip archive `%s': %s\n", + prg, tname, errstr); + exit(1); + } + + for (i=0; i<argc-optind; i++) { + if (merge_zip(za, tname, argv[optind+i], zs+i) < 0) + exit(1); + } + + if (zip_close(za) < 0) { + fprintf(stderr, "%s: cannot write zip archive `%s': %s\n", + prg, tname, zip_strerror(za)); + exit(1); + } + + for (i=0; i<argc-optind; i++) + zip_close(zs[i]); + + exit(0); +} + + + +static int +confirm_replace(struct zip *za, const char *tname, int it, + struct zip *zs, const char *sname, int is) +{ + char line[1024]; + struct zip_stat st, ss; + + if (confirm & CONFIRM_ALL_YES) + return 1; + else if (confirm & CONFIRM_ALL_NO) + return 0; + + if (zip_stat_index(za, it, ZIP_FL_UNCHANGED, &st) < 0) { + fprintf(stderr, "%s: cannot stat file %d in `%s': %s\n", + prg, it, tname, zip_strerror(za)); + return -1; + } + if (zip_stat_index(zs, is, 0, &ss) < 0) { + fprintf(stderr, "%s: cannot stat file %d in `%s': %s\n", + prg, is, sname, zip_strerror(zs)); + return -1; + } + + if (st.size == ss.size && st.crc == ss.crc) { + if (confirm & CONFIRM_SAME_YES) + return 1; + else if (confirm & CONFIRM_SAME_NO) + return 0; + } + + printf("replace `%s' (%llu / %08x) in `%s'\n" + " with `%s' (%llu / %08x) from `%s'? ", + st.name, st.size, st.crc, tname, + ss.name, ss.size, ss.crc, sname); + fflush(stdout); + + if (fgets(line, sizeof(line), stdin) == NULL) { + fprintf(stderr, "%s: read error from stdin: %s\n", + prg, strerror(errno)); + return -1; + } + + if (tolower((unsigned char)line[0]) == 'y') + return 1; + + return 0; +} + + + +static int +merge_zip(struct zip *za, const char *tname, const char *sname, + struct zip **zsp) +{ + struct zip *zs; + struct zip_source *source; + int i, idx, err; + char errstr[1024]; + const char *fname; + + if ((zs=zip_open(sname, 0, &err)) == NULL) { + zip_error_to_str(errstr, sizeof(errstr), err, errno); + fprintf(stderr, "%s: cannot open zip archive `%s': %s\n", + prg, sname, errstr); + return -1; + } + + for (i=0; i<zip_get_num_files(zs); i++) { + fname = zip_get_name(zs, i, 0); + + if ((idx=zip_name_locate(za, fname, name_flags)) != -1) { + switch (confirm_replace(za, tname, idx, zs, sname, i)) { + case 0: + break; + + case 1: + if ((source=zip_source_zip(za, zs, i, 0, 0, 0)) == NULL + || zip_replace(za, idx, source) < 0) { + zip_source_free(source); + fprintf(stderr, + "%s: cannot replace `%s' in `%s': %s\n", + prg, fname, tname, zip_strerror(za)); + return -1; + } + break; + + case -1: + zip_close(zs); + return -1; + + default: + fprintf(stderr, "%s: internal error: " + "unexpected return code from confirm (%d)\n", + prg, err); + zip_close(zs); + return -1; + } + } + else { + if ((source=zip_source_zip(za, zs, i, 0, 0, 0)) == NULL + || zip_add(za, fname, source) < 0) { + zip_source_free(source); + fprintf(stderr, + "%s: cannot add `%s' to `%s': %s\n", + prg, fname, tname, zip_strerror(za)); + zip_close(zs); + return -1; + } + } + } + + *zsp = zs; + return 0; +} |