improve overwrite confirmation prompt. add option to (not) overwrite identical (by size and crc) files --HG-- branch : HEAD
diff --git a/src/zipmerge.c b/src/zipmerge.c index fccc725..708804f 100644 --- a/src/zipmerge.c +++ b/src/zipmerge.c
@@ -1,5 +1,5 @@ /* - $NiH$ + $NiH: zipmerge.c,v 1.1 2004/05/15 23:56:55 dillo Exp $ zipmerge.c -- merge zip archives Copyright (C) 2004 Dieter Baron and Thomas Klausner @@ -49,7 +49,7 @@ char *prg; -char *usage = "usage: %s [-hVDiI] target-zip zip...\n"; +char *usage = "usage: %s [-hVDiIsS] target-zip zip...\n"; char help_head[] = PACKAGE " by Dieter Baron and Thomas Klausner\n\n"; @@ -59,6 +59,8 @@ -D ignore directory component in file names\n\ -i ask before overwriting files\n\ -I ignore case in file names\n\ + -s overwrite identical files without asking\n\ + -S don't overwrite identical files\n\ \n\ Report bugs to <nih@giga.or.at>.\n"; @@ -69,12 +71,18 @@ " PACKAGE " under the terms of the GNU General Public License.\n\ For more information about these matters, see the files named COPYING.\n"; -#define OPTIONS "hVDiI" +#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(const char *, const char *, const char *); +static int confirm_replace(struct zip *, const char *, int, + struct zip *, const char *, int); static int merge_zip(struct zip *zt, const char *, const char *); @@ -88,7 +96,7 @@ prg = argv[0]; - confirm = 0; + confirm = CONFIRM_ALL_YES; name_flags = 0; while ((c=getopt(argc, argv, OPTIONS)) != -1) { @@ -97,11 +105,19 @@ name_flags |= ZIP_FL_NODIR; break; case 'i': - confirm = 1; + 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); @@ -148,16 +164,46 @@ static int -confirm_replace(const char *tname, const char *sname, const char *fname) +confirm_replace(struct zip *zt, const char *tname, int it, + struct zip *zs, const char *sname, int is) { char line[1024]; + struct zip_stat st, ss; - printf("replace `%s' in `%s' from `%s'? ", - fname, tname, sname); + if (confirm & CONFIRM_ALL_YES) + return 1; + else if (confirm & CONFIRM_ALL_NO) + return 0; + + if (zip_stat_index(zt, it, ZIP_FL_UNCHANGED, &st) < 0) { + fprintf(stderr, "%s: cannot stat file %d in `%s': %s\n", + prg, it, tname, zip_strerror(zt)); + 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' (%qu / %08x) in `%s'\n" + " with `%s' (%qu / %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) - return 0; + if (fgets(line, sizeof(line), stdin) == NULL) { + fprintf(stderr, "%s: read error from stdin: %s\n", + prg, strerror(errno)); + return -1; + } if (tolower(line[0]) == 'y') return 1; @@ -186,13 +232,27 @@ fname = zip_get_name(zs, i); if ((idx=zip_name_locate(zt, fname, name_flags)) != -1) { - if (!confirm || confirm_replace(tname, sname, fname)) { - if (zip_replace_zip(zt, idx, zs, i, 0, 0, 0) < 0) { + switch (confirm_replace(zt, tname, idx, zs, sname, i)) { + case 0: + break; + + case 1: + if ((err=zip_replace_zip(zt, idx, zs, i, 0, 0, 0) < 0)) { fprintf(stderr, "%s: cannot replace `%s' in `%s': %s\n", prg, fname, tname, zip_strerror(zt)); return -1; } + break; + + case -1: + return -1; + + default: + fprintf(stderr, "%s: internal error: " + "unexpected return code from confirm (%d)\n", + prg, err); + return -1; } } else {