merge
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3869050..bf6e557 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -48,16 +48,13 @@ CHECK_SYMBOL_EXISTS(MoveFileExA windows.h HAVE_MOVEFILEEXA) +CHECK_INCLUDE_FILES(fts.h HAVE_FTS_H) CHECK_INCLUDE_FILES(strings.h HAVE_STRINGS_H) CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H) CHECK_INCLUDE_FILES(inttypes.h HAVE_INTTYPES_H_LIBZIP) CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H_LIBZIP) CHECK_INCLUDE_FILES(sys/types.h HAVE_SYS_TYPES_H_LIBZIP) -CHECK_INCLUDE_FILES(dirent.h HAVE_DIRENT_H) -CHECK_INCLUDE_FILES(ndir.h HAVE_NDIR_H) -CHECK_INCLUDE_FILES(sys/dir.h HAVE_SYS_DIR_H) -CHECK_INCLUDE_FILES(sys/ndir.h HAVE_SYS_NDIR_H) CHECK_TYPE_SIZE(__int8 __INT8_LIBZIP) CHECK_TYPE_SIZE(int8_t INT8_T_LIBZIP)
diff --git a/TODO b/TODO index b9a4c26..b49df63 100644 --- a/TODO +++ b/TODO
@@ -25,11 +25,11 @@ Features ======== -! test and if necessary fix zipcmp on Windows * progress callback for zip_close (called after each file written completely) * function to copy file from one archive to another * do not compress if storing is smaller * set O_CLOEXEC flag after fopen and mkstemp +* switch to new perl test framework ! W test extra fields api . set @@ -56,7 +56,6 @@ Bugs ==== -! invalidate zip_source_zip when source archive is closed * embed stripped down old zlib for torrentzip ! ensure that nentries is small enough not to cause overflow (size_t for entry, uint64 for CD on disk) * Xcode 32bit build uses 64bit config.h
diff --git a/configure.ac b/configure.ac index afc5f7f..4e63629 100644 --- a/configure.ac +++ b/configure.ac
@@ -63,8 +63,7 @@ [Define to 1 if you have the `MoveFileExA' function.])], [AC_MSG_RESULT([no])]) -AC_CHECK_HEADERS([unistd.h strings.h]) -AC_HEADER_DIRENT +AC_CHECK_HEADERS([fts.h strings.h unistd.h]) AC_CHECK_TYPES([int8_t]) AC_CHECK_TYPES([int16_t])
diff --git a/lib/zip_close.c b/lib/zip_close.c index 1ad796d..577e921 100644 --- a/lib/zip_close.c +++ b/lib/zip_close.c
@@ -88,8 +88,16 @@ /* don't create zip files with no entries */ if (survivors == 0) { if (za->zn && ((za->open_flags & ZIP_TRUNCATE) || (changed && za->zp))) { + int reopen = 0; + if (za->zp) { + reopen = 1; + fclose(za->zp); + za->zp = NULL; + } if (remove(za->zn) != 0) { _zip_error_set(&za->error, ZIP_ER_REMOVE, errno); + if (reopen) + za->zp = fopen(za->zn, "rb"); return -1; } }
diff --git a/lib/zip_discard.c b/lib/zip_discard.c index 051fd72..3fc6d8f 100644 --- a/lib/zip_discard.c +++ b/lib/zip_discard.c
@@ -1,6 +1,6 @@ /* zip_discard.c -- discard and free struct zip - Copyright (C) 1999-2012 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2014 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> @@ -65,15 +65,12 @@ free(za->entry); } - for (i=0; i<za->nfile; i++) { - if (za->file[i]->error.zip_err == ZIP_ER_OK) { - _zip_error_set(&za->file[i]->error, ZIP_ER_ZIPCLOSED, 0); - za->file[i]->za = NULL; - } + for (i=0; i<za->nsource; i++) { + _zip_source_filep_invalidate(za->source[i]); } _zip_error_fini(&za->error); - free(za->file); + free(za->source); free(za);
diff --git a/lib/zip_fclose.c b/lib/zip_fclose.c index a7dfdf3..c336c31 100644 --- a/lib/zip_fclose.c +++ b/lib/zip_fclose.c
@@ -1,6 +1,6 @@ /* zip_fclose.c -- close file in zip archive - Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2014 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> @@ -46,16 +46,6 @@ if (zf->src) zip_source_free(zf->src); - if (zf->za) { - for (i=0; i<zf->za->nfile; i++) { - if (zf->za->file[i] == zf) { - zf->za->file[i] = zf->za->file[zf->za->nfile-1]; - zf->za->nfile--; - break; - } - } - } - ret = 0; if (zf->error.zip_err) ret = zf->error.zip_err;
diff --git a/lib/zip_fopen_index_encrypted.c b/lib/zip_fopen_index_encrypted.c index e429f6c..7aaf894 100644 --- a/lib/zip_fopen_index_encrypted.c +++ b/lib/zip_fopen_index_encrypted.c
@@ -1,6 +1,6 @@ /* zip_fopen_index_encrypted.c -- open file for reading by index w/ password - Copyright (C) 1999-2013 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2014 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> @@ -77,22 +77,6 @@ _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } - - if (za->nfile+1 >= za->nfile_alloc) { - unsigned int n; - n = za->nfile_alloc + 10; - file = (struct zip_file **)realloc(za->file, - n*sizeof(struct zip_file *)); - if (file == NULL) { - _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - free(zf); - return NULL; - } - za->nfile_alloc = n; - za->file = file; - } - - za->file[za->nfile++] = zf; zf->za = za; _zip_error_init(&zf->error);
diff --git a/lib/zip_new.c b/lib/zip_new.c index 7acc84e..db64be3 100644 --- a/lib/zip_new.c +++ b/lib/zip_new.c
@@ -1,6 +1,6 @@ /* zip_new.c -- create and init struct zip - Copyright (C) 1999-2012 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2014 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> @@ -62,8 +62,8 @@ za->comment_changed = 0; za->nentry = za->nentry_alloc = 0; za->entry = NULL; - za->nfile = za->nfile_alloc = 0; - za->file = NULL; + za->nsource = za->nsource_alloc = 0; + za->source = NULL; za->tempdir = NULL; return za;
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c index 48f1878..5c1a7ab 100644 --- a/lib/zip_source_filep.c +++ b/lib/zip_source_filep.c
@@ -1,6 +1,6 @@ /* zip_source_filep.c -- create data source from FILE * - Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2014 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> @@ -50,10 +50,13 @@ zip_int64_t len; /* length of data to copy */ zip_int64_t remain; /* bytes remaining to be copied */ int e[2]; /* error codes */ + int source_closed; /* set if source archive is closed */ + struct zip *source_archive; /* zip archive we're reading from, NULL if not from archive */ }; -static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, - enum zip_source_cmd cmd); +static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, enum zip_source_cmd cmd); +static void _zip_deregister_source(struct zip *za, void *ud); +static int _zip_register_source(struct zip *za, struct zip_source *src); ZIP_EXTERN struct zip_source * @@ -102,6 +105,8 @@ f->off = start; f->len = (len ? len : -1); f->closep = f->fname ? 1 : closep; + f->source_closed = 0; + f->source_archive = NULL; if (st) memcpy(&f->st, st, sizeof(f->st)); else @@ -116,6 +121,31 @@ } +int +_zip_source_filep_set_source_archive(struct zip_source *src, struct zip *za) +{ + struct read_file *z = (struct read_file *)src->ud; + + z->source_archive = za; + return _zip_register_source(za, src); +} + + +/* called by zip_discard to avoid operating on file from closed archive */ +void +_zip_source_filep_invalidate(struct zip_source *src) +{ + struct read_file *z = (struct read_file *)src->ud; + + z->source_closed = 1; + z->f = NULL; + if (z->e[0] == ZIP_ER_OK) { + z->e[0] = ZIP_ER_ZIPCLOSED; + z->e[1] = 0; + } +} + + static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, enum zip_source_cmd cmd) { @@ -129,6 +159,9 @@ switch (cmd) { case ZIP_SOURCE_OPEN: + if (z->source_closed) + return -1; + if (z->fname) { if ((z->f=fopen(z->fname, "rb")) == NULL) { z->e[0] = ZIP_ER_OPEN; @@ -148,6 +181,9 @@ return 0; case ZIP_SOURCE_READ: + if (z->source_closed) + return -1; + if (z->remain != -1) n = len > (zip_uint64_t)z->remain ? (zip_uint64_t)z->remain : len; else @@ -179,6 +215,9 @@ return (zip_int64_t)i; case ZIP_SOURCE_CLOSE: + if (z->source_closed) + return -1; + if (z->fname) { fclose(z->f); z->f = NULL; @@ -186,6 +225,9 @@ return 0; case ZIP_SOURCE_STAT: + if (z->source_closed) + return -1; + { if (len < sizeof(z->st)) return -1; @@ -233,6 +275,9 @@ return sizeof(int)*2; case ZIP_SOURCE_FREE: + if (z->source_archive && !z->source_closed) { + _zip_deregister_source(z->source_archive, state); + } free(z->fname); if (z->closep && z->f) fclose(z->f); @@ -245,3 +290,41 @@ return -1; } + + +static void +_zip_deregister_source(struct zip *za, void *ud) +{ + int i; + + for (i=0; i<za->nsource; i++) { + if (za->source[i]->ud == ud) { + za->source[i] = za->source[za->nsource-1]; + za->nsource--; + break; + } + } +} + + +static int +_zip_register_source(struct zip *za, struct zip_source *src) +{ + struct zip_source **source; + + if (za->nsource+1 >= za->nsource_alloc) { + unsigned int n; + n = za->nsource_alloc + 10; + source = (struct zip_source **)realloc(za->source, n*sizeof(struct zip_source *)); + if (source == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + za->nsource_alloc = n; + za->source = source; + } + + za->source[za->nsource++] = src; + + return 0; +}
diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c index 70ac4e8..3f4fbd2 100644 --- a/lib/zip_source_zip_new.c +++ b/lib/zip_source_zip_new.c
@@ -1,6 +1,6 @@ /* zip_source_zip_new.c -- prepare data structures for zip_fopen/zip_source_zip - Copyright (C) 2012 Dieter Baron and Thomas Klausner + Copyright (C) 2012-2014 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> @@ -129,6 +129,11 @@ return NULL; } + if (_zip_source_filep_set_source_archive(src, srcza) < 0) { + zip_source_free(src); + return NULL; + } + if (enc_impl) { if ((s2=enc_impl(za, src, st.encryption_method, 0, password)) == NULL) { zip_source_free(src);
diff --git a/lib/zipint.h b/lib/zipint.h index c3852b5..6f13361 100644 --- a/lib/zipint.h +++ b/lib/zipint.h
@@ -3,7 +3,7 @@ /* zipint.h -- internal declarations. - Copyright (C) 1999-2013 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2014 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> @@ -284,9 +284,9 @@ zip_uint64_t nentry_alloc; /* number of entries allocated */ struct zip_entry *entry; /* entries */ - unsigned int nfile; /* number of opened files within archive */ - unsigned int nfile_alloc; /* number of files allocated */ - struct zip_file **file; /* opened files within archive */ + unsigned int nsource; /* number of open sources using archive */ + unsigned int nsource_alloc; /* number of sources allocated */ + struct zip_source **source; /* open sources using archive */ char *tempdir; /* custom temp dir (needed e.g. for OS X sandboxing) */ }; @@ -458,19 +458,17 @@ struct zip_dirent *_zip_get_dirent(struct zip *, zip_uint64_t, zip_flags_t, struct zip_error *); enum zip_encoding_type _zip_guess_encoding(struct zip_string *, enum zip_encoding_type); -zip_uint8_t *_zip_cp437_to_utf8(const zip_uint8_t * const, zip_uint32_t, - zip_uint32_t *, struct zip_error *error); +zip_uint8_t *_zip_cp437_to_utf8(const zip_uint8_t * const, zip_uint32_t, zip_uint32_t *, struct zip_error *); struct zip *_zip_open(const char *, FILE *, unsigned int, int *); int _zip_read_local_ef(struct zip *, zip_uint64_t); -struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *, - zip_uint64_t, zip_int64_t, int, - const struct zip_stat *); +struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *, zip_uint64_t, zip_int64_t, int, const struct zip_stat *); +void _zip_source_filep_invalidate(struct zip_source *); +int _zip_source_filep_set_source_archive(struct zip_source *, struct zip *); struct zip_source *_zip_source_new(struct zip *); -struct zip_source *_zip_source_zip_new(struct zip *, struct zip *, zip_uint64_t, zip_flags_t, - zip_uint64_t, zip_uint64_t, const char *); +struct zip_source *_zip_source_zip_new(struct zip *, struct zip *, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_uint64_t, const char *); int _zip_string_equal(const struct zip_string *, const struct zip_string *); void _zip_string_free(struct zip_string *);
diff --git a/regress/Makefile.am b/regress/Makefile.am index 29e2b5b..3630c53 100644 --- a/regress/Makefile.am +++ b/regress/Makefile.am
@@ -20,6 +20,7 @@ runtest \ ${TESTS} \ bigzero-zip.zip \ + bogus.zip \ broken.zip \ encrypt.zip \ encrypt_plus_extra.zip \ @@ -113,6 +114,7 @@ add_from_file_twice_duplicate.test \ add_from_filep.test \ add_from_stdin.test \ + add_from_zip_closed.test \ add_from_zip_deflated.test \ add_from_zip_partial_deflated.test \ add_from_zip_partial_stored.test \
diff --git a/regress/add_from_zip_closed.test b/regress/add_from_zip_closed.test new file mode 100644 index 0000000..25507d9 --- /dev/null +++ b/regress/add_from_zip_closed.test
@@ -0,0 +1,6 @@ +# add deflated file from zip to zip, but close the source before it can be read +program modify +return 1 +args -- testfile.zip add_from_zip abac-repeat.txt testdeflated.zzip 0 0 -1 zin_close +file testdeflated.zzip testdeflated.zip testdeflated.zip +stderr can't close zip archive 'testfile.zip': Containing zip archive was closed
diff --git a/regress/modify.c b/regress/modify.c index 9a70bca..5a0b0d2 100644 --- a/regress/modify.c +++ b/regress/modify.c
@@ -72,6 +72,7 @@ "\tset_extra index extra_id extra_index flags value\n" "\tset_file_comment index comment\n" "\tset_file_compression index method flags\n" + "\tzin_close\n" "\nThe index is zero-based.\n"; static zip_flags_t @@ -193,10 +194,18 @@ arg += 2; } else if (strcmp(argv[arg], "add_file") == 0 && arg+4 < argc) { /* add */ - if ((zs=zip_source_file(za, argv[arg+2], atoi(argv[arg+3]), atoi(argv[arg+4]))) == NULL) { - fprintf(stderr, "can't create zip_source from file: %s\n", zip_strerror(za)); - err = 1; - break; + if (strcmp(argv[arg+2], "/dev/stdin") == 0) { + if ((zs=zip_source_filep(za, stdin, atoi(argv[arg+3]), atoi(argv[arg+4]))) == NULL) { + fprintf(stderr, "can't create zip_source from stdin: %s\n", zip_strerror(za)); + err = 1; + break; + } + } else { + if ((zs=zip_source_file(za, argv[arg+2], atoi(argv[arg+3]), atoi(argv[arg+4]))) == NULL) { + fprintf(stderr, "can't create zip_source from file: %s\n", zip_strerror(za)); + err = 1; + break; + } } if (zip_add(za, argv[arg+1], zs) == -1) { @@ -399,6 +408,13 @@ break; } arg += 4; + } else if (strcmp(argv[arg], "zin_close") == 0) { + if (zip_close(z_in) < 0) { + fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in)); + err = 1; + break; + } + arg += 1; } else { fprintf(stderr, "unrecognized command '%s', or not enough arguments\n", argv[arg]); err = 1;
diff --git a/src/Makefile.am b/src/Makefile.am index 58d53ec..d1ca9b9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am
@@ -1,6 +1,6 @@ bin_PROGRAMS=zipcmp zipmerge ziptorrent -zipcmp_SOURCES=zipcmp.c dir.c parray.c parray_push.c parray_pop.c +zipcmp_SOURCES=zipcmp.c zipcmp_CPPFLAGS=-I${top_srcdir}/lib -I../lib zipcmp_LDADD=${top_builddir}/lib/libzip.la @@ -9,4 +9,4 @@ ziptorrent_CPPFLAGS=-I${top_srcdir}/lib -I../lib ziptorrent_LDADD=${top_builddir}/lib/libzip.la -EXTRA_DIST= CMakeLists.txt getopt.c getopt.h compat.h dir.h parray.h +EXTRA_DIST= CMakeLists.txt getopt.c getopt.h compat.h
diff --git a/src/dir.c b/src/dir.c deleted file mode 100644 index 0437de5..0000000 --- a/src/dir.c +++ /dev/null
@@ -1,197 +0,0 @@ -/* - dir.h -- reading a directory - Copyright (C) 2005-2014 Dieter Baron and Thomas Klausner - - This file is part of ckmame, a program to check rom sets for MAME. - The authors can be contacted at <ckmame@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 name of the author 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 <sys/stat.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -/* copied from autoconf manual (AC_HEADER_DIRENT) */ - -#include "config.h" - -#ifdef HAVE_DIRENT_H -# include <dirent.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif -# ifdef HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# ifdef HAVE_NDIR_H -# include <ndir.h> -# endif -#endif - -#include "dir.h" - -struct dir_one { - DIR *dir; - char *name; - int len; -}; - -typedef struct dir_one dir_one_t; - -static int dir_one_free(dir_one_t *); -static dir_one_t *dir_one_new(const char *); - - -int -dir_close(dir_t *dir) -{ - dir_one_t *d; - int ret; - - ret = 0; - while ((d=parray_pop(dir->stack)) != NULL) - ret |= dir_one_free(d); - - parray_free(dir->stack, (void (*)())dir_one_free); - free(dir); - - return ret; -} - - -dir_status_t -dir_next(dir_t *dir, char *name, int len) -{ - struct dirent *de; - dir_one_t *d; - int l; - struct stat st; - - d = parray_get_last(dir->stack); - for (;;) { - if ((de=readdir(d->dir)) == NULL) { - dir_one_free(d); - parray_pop(dir->stack); - if ((d=parray_get_last(dir->stack)) == NULL) - return DIR_EOD; - continue; - } - - l = NAMLEN(de); - - if ((l == 1 && strncmp(de->d_name, ".", 1) == 0) - || (l == 2 && strncmp(de->d_name, "..", 2) == 0)) - continue; - - if (d->len + l + 2 > len) { - errno = ENAMETOOLONG; - return DIR_ERROR; - } - - sprintf(name, "%s/%*s", d->name, l, de->d_name); - - if (dir->flags & DIR_RECURSE) { - - if (stat(name, &st) < 0) - return DIR_ERROR; - - if ((st.st_mode & S_IFMT) == S_IFDIR) { - if ((d=dir_one_new(name)) == NULL) - return DIR_ERROR; - - parray_push(dir->stack, d); - continue; - } - } - return DIR_OK; - } -} - - -dir_t * -dir_open(const char *name, int flags) -{ - dir_one_t *d; - dir_t *dir; - - if ((d=dir_one_new(name)) == NULL) - return NULL; - - if ((dir=(dir_t *)malloc(sizeof(*dir))) == NULL) - return NULL; - - dir->stack = parray_new(); - parray_push(dir->stack, d); - dir->flags = flags; - - return dir; -} - - -static int -dir_one_free(dir_one_t *d) -{ - int ret; - - if (d == NULL) - return 0; - - ret = closedir(d->dir); - free(d->name); - free(d); - - return ret; -} - - -static dir_one_t * -dir_one_new(const char *name) -{ - DIR *dir; - dir_one_t *d; - - if ((dir=opendir(name)) == NULL) - return NULL; - - if ((d=(dir_one_t *)malloc(sizeof(*d))) == NULL) - return NULL; - d->dir = dir; - if ((d->name=strdup(name)) == NULL) { - free(d); - return NULL; - } - - d->len = strlen(name); - - return d; -}
diff --git a/src/dir.h b/src/dir.h deleted file mode 100644 index ae2fbe2..0000000 --- a/src/dir.h +++ /dev/null
@@ -1,61 +0,0 @@ -#ifndef HAD_DIR_H -#define HAD_DIR_H - -/* - dir.h -- reading a directory - Copyright (C) 2005-2014 Dieter Baron and Thomas Klausner - - This file is part of ckmame, a program to check rom sets for MAME. - The authors can be contacted at <ckmame@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 name of the author 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 "parray.h" - -#define DIR_RECURSE 1 - -struct dir { - int flags; - parray_t *stack; -}; - -typedef struct dir dir_t; - -enum dir_status { - DIR_ERROR = -1, - DIR_OK, - DIR_EOD -}; - -typedef enum dir_status dir_status_t; - -int dir_close(dir_t *); -dir_status_t dir_next(dir_t *, char *, int); -dir_t *dir_open(const char *, int); - -#endif /* dir.h */
diff --git a/src/parray.c b/src/parray.c deleted file mode 100644 index ac132eb..0000000 --- a/src/parray.c +++ /dev/null
@@ -1,76 +0,0 @@ -/* - parray.c -- create / free array of pointers - Copyright (C) 2005-2014 Dieter Baron and Thomas Klausner - - This file is part of ckmame, a program to check rom sets for MAME. - The authors can be contacted at <ckmame@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 name of the author 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 <stdlib.h> - -#include "parray.h" - -void -parray_free(parray_t *pa, void (*fn)(void *)) -{ - int i; - - if (pa == NULL) - return; - - if (fn) { - for (i=0; i<parray_length(pa); i++) - fn(parray_get(pa, i)); - } - - free(pa->entry); - free(pa); -} - -parray_t * -parray_new_sized(int n) -{ - parray_t *pa; - - if (n<0) - n = 0; - - if ((pa=malloc(sizeof(*pa))) == NULL) - exit(1); - - if (n == 0) - pa->entry = 0; - else { - if ((pa->entry=malloc(n*sizeof(pa->entry[0]))) == NULL) - exit(1); - } - pa->nentry = 0; - pa->alloc_len = n; - - return pa; -}
diff --git a/src/parray.h b/src/parray.h deleted file mode 100644 index d0e26f1..0000000 --- a/src/parray.h +++ /dev/null
@@ -1,57 +0,0 @@ -#ifndef _HAD_PARRAY_H -#define _HAD_PARRAY_H - -/* - parray.h -- array of pointers - Copyright (C) 2005-2014 Dieter Baron and Thomas Klausner - - This file is part of ckmame, a program to check rom sets for MAME. - The authors can be contacted at <ckmame@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 name of the author 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. -*/ - -struct parray { - void **entry; - int nentry; - int alloc_len; -}; - -typedef struct parray parray_t; - -#define parray_get(a, i) ((a)->entry[i]) -#define parray_get_last(a) \ - (parray_length(a) ? parray_get((a), parray_length(a)-1) : NULL) -#define parray_length(a) ((a)->nentry) -#define parray_new() (parray_new_sized(0)) - -/* function arguments not specified to avoid lots of casts */ -void parray_free(parray_t *, void (*)(/* void * */)); -parray_t *parray_new_sized(int); -void *parray_pop(parray_t *); -void parray_push(parray_t *, void *); - -#endif /* parray.h */
diff --git a/src/parray_pop.c b/src/parray_pop.c deleted file mode 100644 index 108b693..0000000 --- a/src/parray_pop.c +++ /dev/null
@@ -1,45 +0,0 @@ -/* - parray_pop.c -- delete element from array of pointers and return it - Copyright (C) 2005-2014 Dieter Baron and Thomas Klausner - - This file is part of ckmame, a program to check rom sets for MAME. - The authors can be contacted at <ckmame@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 name of the author 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 <string.h> - -#include "parray.h" - -void * -parray_pop(parray_t *pa) -{ - if (parray_length(pa) == 0) - return NULL; - - return (parray_get(pa, --pa->nentry)); -}
diff --git a/src/parray_push.c b/src/parray_push.c deleted file mode 100644 index fb47e28..0000000 --- a/src/parray_push.c +++ /dev/null
@@ -1,53 +0,0 @@ -/* - parray_push.c -- append element to end of array of pointers - Copyright (C) 2005-2014 Dieter Baron and Thomas Klausner - - This file is part of ckmame, a program to check rom sets for MAME. - The authors can be contacted at <ckmame@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 name of the author 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 <stdlib.h> - -#include "parray.h" - -void -parray_push(parray_t *pa, void *e) -{ - if (pa->nentry >= pa->alloc_len) { - void **tmp; - if (pa->alloc_len == 0) - pa->alloc_len = 1; - else - pa->alloc_len *= 2; - if ((tmp=realloc(pa->entry, sizeof(pa->entry[0])*pa->alloc_len)) == NULL) - exit(1); - pa->entry = tmp; - } - - pa->entry[pa->nentry++] = e; -}
diff --git a/src/zipcmp.c b/src/zipcmp.c index 2411e4d..ead0abd 100644 --- a/src/zipcmp.c +++ b/src/zipcmp.c
@@ -45,6 +45,9 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_FTS_H +#include <fts.h> +#endif #include <zlib.h> #ifndef HAVE_GETOPT @@ -56,8 +59,6 @@ #include "zip.h" #include "compat.h" -#include "dir.h" - struct archive { const char *name; struct zip *za; @@ -131,7 +132,9 @@ static int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2); static void entry_print(const void *p); static int is_directory(const char *name); +#ifdef HAVE_FTS_H static int list_directory(const char *name, struct archive *a); +#endif static int list_zip(const char *name, struct archive *a); static int test_file(struct zip *za, int idx, zip_int64_t size, unsigned int crc); @@ -211,9 +214,14 @@ a[i].comment_length =0; if (is_directory(zn[i])) { +#ifndef HAVE_FTS_H + fprintf(stderr, "%s: reading directories not supported\n", prg); + exit(2); +#else if (list_directory(zn[i], a+i) < 0) exit(2); paranoid = 0; /* paranoid checks make no sense for directories, since they compare zip metadata */ +#endif } else { if (list_zip(zn[i], a+i) < 0) @@ -267,7 +275,7 @@ if ((f=fopen(fname, "r")) == NULL) { - fprintf(stderr, "%s: can't open %s: %s", prg, fname, strerror(errno)); + fprintf(stderr, "%s: can't open %s: %s\n", prg, fname, strerror(errno)); return -1; } @@ -276,7 +284,7 @@ } if (ferror(f)) { - fprintf(stderr, "%s: read error on %s: %s", prg, fname, strerror(errno)); + fprintf(stderr, "%s: read error on %s: %s\n", prg, fname, strerror(errno)); fclose(f); return -1; } @@ -299,64 +307,77 @@ } +#ifdef HAVE_FTS_H static int list_directory(const char *name, struct archive *a) { - char namebuf[8192]; - dir_t *dir; - dir_status_t status; + FTS *fts; + FTSENT *ent; zip_uint64_t nalloc; - if ((dir=dir_open(name, DIR_RECURSE)) == NULL) { - fprintf(stderr, "%s: can't open directory '%s': %s", prg, name, strerror(errno)); + char * const names[2] = { (char *)name, NULL }; + + + if ((fts = fts_open(names, FTS_NOCHDIR|FTS_LOGICAL, NULL)) == NULL) { + fprintf(stderr, "%s: can't open directory '%s': %s\n", prg, name, strerror(errno)); return -1; } + size_t prefix_length = strlen(name)+1; nalloc = 0; - while ((status=dir_next(dir, namebuf, sizeof(namebuf))) == DIR_OK) { - struct stat sb; + + while ((ent = fts_read(fts))) { zip_int64_t crc; - if (stat(namebuf, &sb) < 0) { - fprintf(stderr, "%s: can't stat '%s': %s", prg, namebuf, strerror(errno)); - dir_close(dir); - return -1; - } + switch (ent->fts_info) { + case FTS_D: + case FTS_DOT: + case FTS_DP: + case FTS_DEFAULT: + case FTS_SL: + case FTS_NSOK: + break; - if (S_ISREG(sb.st_mode)) { + case FTS_DC: + case FTS_DNR: + case FTS_ERR: + case FTS_NS: + case FTS_SLNONE: + /* TODO: error */ + fts_close(fts); + return -1; + + case FTS_F: if (a->nentry >= nalloc) { nalloc += 16; a->entry = realloc(a->entry, sizeof(a->entry[0])*nalloc); if (a->entry == NULL) { - fprintf(stderr, "%s: malloc failure", prg); + fprintf(stderr, "%s: malloc failure\n", prg); exit(1); } } - - a->entry[a->nentry].name = strdup(namebuf+strlen(a->name)+1); - a->entry[a->nentry].size = sb.st_size; - if ((crc = compute_crc(namebuf)) < 0) { - dir_close(dir); + + a->entry[a->nentry].name = strdup(ent->fts_path+prefix_length); + a->entry[a->nentry].size = ent->fts_statp->st_size; + if ((crc = compute_crc(ent->fts_accpath)) < 0) { + fts_close(fts); return -1; } - + a->entry[a->nentry].crc = (zip_uint32_t)crc; a->nentry++; + break; } } - if (status != DIR_EOD) { - fprintf(stderr, "%s: error reading directory '%s': %s", prg, a->name, strerror(errno)); - dir_close(dir); - return -1; - } - if (dir_close(dir) < 0) { - fprintf(stderr, "%s: error closing directory '%s': %s", prg, a->name, strerror(errno)); + if (fts_close(fts)) { + fprintf(stderr, "%s: error closing directory '%s': %s\n", prg, a->name, strerror(errno)); return -1; } return 0; } +#endif static int