bsdcat
bsdcpio
bsdtar
+bsdunzip
build/autoconf/compile
build/autoconf/config.guess
build/autoconf/config.sub
libtool
stamp-h1
tar/test/list.h
+unzip/test/list.h
CMakeCache.txt
CMakeFiles/
DartConfiguration.tcl
OPTION(ENABLE_CPIO_SHARED "Enable dynamic build of cpio" FALSE)
OPTION(ENABLE_CAT "Enable cat building" ON)
OPTION(ENABLE_CAT_SHARED "Enable dynamic build of cat" FALSE)
+OPTION(ENABLE_UNZIP "Enable unzip building" ON)
+OPTION(ENABLE_UNZIP_SHARED "Enable dynamic build of unzip" FALSE)
OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
OPTION(ENABLE_ACL "Enable ACL support" ON)
OPTION(ENABLE_ICONV "Enable iconv support" ON)
"#include <fcntl.h>\n#include <unistd.h>\nint main() {char buf[10]; return readlinkat(AT_FDCWD, \"\", buf, 0);}"
HAVE_READLINKAT)
+# Check for getopt uses optreset to reset
+CHECK_SYMBOL_EXISTS(optreset "getopt.h" HAVE_GETOPT_OPTRESET)
+
# To verify major(), we need to both include the header
# of interest and verify that the result can be linked.
add_subdirectory(cat)
add_subdirectory(tar)
add_subdirectory(cpio)
+add_subdirectory(unzip)
#
lib_LTLIBRARIES= libarchive.la
noinst_LTLIBRARIES= libarchive_fe.la
-bin_PROGRAMS= $(bsdtar_programs) $(bsdcpio_programs) $(bsdcat_programs)
-man_MANS= $(libarchive_man_MANS) $(bsdtar_man_MANS) $(bsdcpio_man_MANS) $(bsdcat_man_MANS)
-BUILT_SOURCES= libarchive/test/list.h tar/test/list.h cpio/test/list.h cat/test/list.h
+bin_PROGRAMS= $(bsdtar_programs) $(bsdcpio_programs) $(bsdcat_programs) $(bsdunzip_programs)
+man_MANS= $(libarchive_man_MANS) $(bsdtar_man_MANS) $(bsdcpio_man_MANS) $(bsdcat_man_MANS) $(bsdunzip_man_MANS)
+BUILT_SOURCES= libarchive/test/list.h tar/test/list.h cpio/test/list.h cat/test/list.h unzip/test/list.h
#
# What to test: We always test libarchive, test bsdtar and bsdcpio only
# if we built them.
#
-check_PROGRAMS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs)
-TESTS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs)
-TESTS_ENVIRONMENT= $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $(bsdcpio_TESTS_ENVIRONMENT) $(bsdcat_TESTS_ENVIRONMENT)
+check_PROGRAMS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) $(bsdunzip_test_programs)
+TESTS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) $(bsdunzip_test_programs)
+TESTS_ENVIRONMENT= $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $(bsdcpio_TESTS_ENVIRONMENT) $(bsdcat_TESTS_ENVIRONMENT) $(bsdunzip_TESTS_ENVIRONMENT)
# Always build and test both bsdtar and bsdcpio as part of 'distcheck'
DISTCHECK_CONFIGURE_FLAGS = --enable-bsdtar --enable-bsdcpio
# The next line is commented out by default in shipping libarchive releases.
$(bsdcpio_EXTRA_DIST) \
$(bsdcpio_test_EXTRA_DIST) \
$(bsdcat_EXTRA_DIST) \
- $(bsdcat_test_EXTRA_DIST)
+ $(bsdcat_test_EXTRA_DIST) \
+ $(bsdunzip_EXTRA_DIST) \
+ $(bsdunzip_test_EXTRA_DIST)
# a) Clean out some unneeded files and directories
# b) Collect all documentation and format it for distribution.
libarchive/test/list.h \
tar/test/list.h \
cpio/test/list.h \
- cat/test/list.h
+ cat/test/list.h \
+ unzip/test/list.h
distclean-local:
-rm -rf .ref
-[ -f cpio/Makefile ] && cd cpio && make clean
-[ -f cpio/test/Makefile ] && cd cpio/test && make clean
-[ -f cat/Makefile ] && cd cat && make clean
- -[ -f cpio/test/Makefile ] && cd cat/test && make clean
+ -[ -f cat/test/Makefile ] && cd cat/test && make clean
+ -[ -f unzip/Makefile ] && cd unzip && make clean
+ -[ -f unzip/test/Makefile ] && cd unzip/test && make clean
#
# Libarchive headers, source, etc.
cat/test/test_expand.plain.uu \
cat/test/test_expand.xz.uu \
cat/test/CMakeLists.txt
+
+#
+#
+# bsdunzip source, docs, etc.
+#
+#
+
+bsdunzip_SOURCES= \
+ unzip/bsdunzip.c \
+ unzip/bsdunzip.h \
+ unzip/bsdunzip_platform.h
+
+if INC_WINDOWS_FILES
+bsdunzip_SOURCES+=
+endif
+
+bsdunzip_DEPENDENCIES = libarchive.la libarchive_fe.la
+
+
+if STATIC_BSDUNZIP
+bsdunzip_ldstatic= -static
+bsdunzip_ccstatic= -DLIBARCHIVE_STATIC
+else
+bsdunzip_ldstatic=
+bsdunzip_ccstatic=
+endif
+
+bsdunzip_LDADD= libarchive_fe.la libarchive.la $(LTLIBICONV)
+bsdunzip_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe $(bsdunzip_ccstatic) $(PLATFORMCPPFLAGS)
+bsdunzip_LDFLAGS= $(bsdunzip_ldstatic) $(GC_SECTIONS)
+
+bsdunzip_EXTRA_DIST= \
+ unzip/bsdunzip.1 \
+ unzip/CMakeLists.txt
+
+
+if BUILD_BSDUNZIP
+# Manpages to install
+bsdunzip_man_MANS= unzip/bsdunzip.1
+bsdunzip_programs= bsdunzip
+else
+bsdunzip_man_MANS=
+bsdunzip_programs=
+endif
+
+#
+# bsdcat_test
+#
+
+bsdunzip_test_SOURCES= \
+ $(test_utils_SOURCES) \
+ unzip/test/test.h \
+ unzip/test/test_0.c \
+ unzip/test/test_basic.c \
+ unzip/test/test_glob.c \
+ unzip/test/test_not_exist.c \
+ unzip/test/test_singlefile.c \
+ unzip/test/test_C.c \
+ unzip/test/test_p.c \
+ unzip/test/test_d.c \
+ unzip/test/test_j.c \
+ unzip/test/test_L.c \
+ unzip/test/test_n.c \
+ unzip/test/test_o.c \
+ unzip/test/test_q.c \
+ unzip/test/test_t.c \
+ unzip/test/test_t_bad.c \
+ unzip/test/test_x.c \
+ unzip/test/test_Z1.c \
+ unzip/test/test_P_encryption.c
+
+bsdunzip_test_CPPFLAGS= \
+ -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \
+ -I$(top_srcdir)/test_utils \
+ -I$(top_srcdir)/unzip -I$(top_srcdir)/unzip/test \
+ -I$(top_builddir)/unzip/test \
+ $(PLATFORMCPPFLAGS)
+bsdunzip_test_LDADD=libarchive_fe.la
+
+unzip/test/list.h: Makefile
+ cat $(top_srcdir)/unzip/test/test_*.c | grep '^DEFINE_TEST' > unzip/test/list.h
+
+if BUILD_BSDUNZIP
+bsdunzip_test_programs= bsdunzip_test
+bsdunzip_TESTS_ENVIRONMENT= BSDUNZIP=`cd $(top_builddir);/bin/pwd`/bsdunzip$(EXEEXT) BSDUNZIP_TEST_FILES=`cd $(top_srcdir);/bin/pwd`/unzip/test
+else
+bsdunzip_test_programs=
+bsdunzip_TESTS_ENVIRONMENT=
+endif
+
+bsdunzip_test_EXTRA_DIST= \
+ unzip/test/list.h \
+ unzip/test/test_basic.zip.uu \
+ unzip/test/test_encrypted.zip.uu \
+ unzip/test/CMakeLists.txt
* **tar**: the 'bsdtar' program is a full-featured 'tar' implementation built on libarchive
* **cpio**: the 'bsdcpio' program is a different interface to essentially the same functionality
* **cat**: the 'bsdcat' program is a simple replacement tool for zcat, bzcat, xzcat, and such
+* **unzip**: the 'bsdunzip' program is a simple replacement tool for Info-ZIP's unzip
* **examples**: Some small example programs that you may find useful.
* **examples/minitar**: a compact sample demonstrating use of libarchive.
* **contrib**: Various items sent to me by third parties; please contact the authors with any questions.
/* Define to 1 if you have the `getgrnam_r' function. */
#cmakedefine HAVE_GETGRNAM_R 1
+/* Define to 1 if platform uses `optreset` to reset `getopt` */
+#cmakedefine HAVE_GETOPT_OPTRESET 1
+
/* Define to 1 if you have the `getpid' function. */
#cmakedefine HAVE_GETPID 1
;;
esac
+#
+# Options for building bsdunzip.
+#
+# Default is to build bsdunzip, but allow people to override that.
+#
+AC_ARG_ENABLE([bsdunzip],
+ [AS_HELP_STRING([--enable-bsdunzip], [enable build of bsdunzip (default)])
+ AS_HELP_STRING([--enable-bsdunzip=static], [force static build of bsdunzip])
+ AS_HELP_STRING([--enable-bsdunzip=shared], [force dynamic build of bsdunzip])
+AS_HELP_STRING([--disable-bsdunzip], [disable build of bsdunzip])],
+ [], [enable_bsdunzip=yes])
+
+case "$enable_bsdunzip" in
+yes)
+ if test "$enable_static" = "no"; then
+ static_bsdunzip=no
+ else
+ static_bsdunzip=yes
+ fi
+ build_bsdunzip=yes
+ ;;
+dynamic|shared)
+ if test "$enable_shared" = "no"; then
+ AC_MSG_FAILURE([Shared linking of bsdunzip requires shared libarchive])
+ fi
+ build_bsdunzip=yes
+ static_bsdunzip=no
+ ;;
+static)
+ build_bsdunzip=yes
+ static_bsdunzip=yes
+ ;;
+no)
+ build_bsdunzip=no
+ static_bsdunzip=no
+ ;;
+*)
+ AC_MSG_FAILURE([Unsupported value for --enable-bsdunzip])
+ ;;
+esac
+
+AM_CONDITIONAL([BUILD_BSDUNZIP], [ test "$build_bsdunzip" = yes ])
+AM_CONDITIONAL([STATIC_BSDUNZIP], [ test "$static_bsdunzip" = yes ])
+
# Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_SYS_WAIT
#endif
])
+AC_CHECK_DECL([optreset],
+ [AC_DEFINE(HAVE_GETOPT_OPTRESET, 1, [Platform uses optreset to reset getopt])],
+ [],
+ [#include <getopt.h>])
+
# Check for Extended Attributes support
AC_ARG_ENABLE([xattr],
AS_HELP_STRING([--disable-xattr],
--- /dev/null
+############################################
+#
+# How to build bsdunzip
+#
+############################################
+IF(ENABLE_UNZIP)
+
+ SET(bsdunzip_SOURCES
+ bsdunzip.c
+ bsdunzip_platform.h
+ ../libarchive_fe/err.c
+ ../libarchive_fe/err.h
+ ../libarchive_fe/lafe_platform.h
+ ../libarchive_fe/passphrase.c
+ ../libarchive_fe/passphrase.h
+ )
+ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe)
+
+ # bsdunzip documentation
+ SET(bsdunzip_MANS bsdunzip.1)
+
+ # How to build bsdunzip
+ ADD_EXECUTABLE(bsdunzip ${bsdunzip_SOURCES})
+ IF(ENABLE_UNZIP_SHARED)
+ TARGET_LINK_LIBRARIES(bsdunzip archive ${ADDITIONAL_LIBS})
+ ELSE(ENABLE_UNZIP_SHARED)
+ TARGET_LINK_LIBRARIES(bsdunzip archive_static ${ADDITIONAL_LIBS})
+ SET_TARGET_PROPERTIES(bsdunzip PROPERTIES COMPILE_DEFINITIONS
+ LIBARCHIVE_STATIC)
+ ENDIF(ENABLE_UNZIP_SHARED)
+
+ # Installation rules
+ INSTALL(TARGETS bsdunzip RUNTIME DESTINATION bin)
+ INSTALL_MAN(${bsdunzip_MANS})
+ENDIF(ENABLE_UNZIP)
+
+add_subdirectory(test)
--- /dev/null
+.\"-
+.\" Copyright (c) 2007-2008 Dag-Erling Smørgrav
+.\" All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 2, 2023
+.Dt BSDUNZIP 1
+.Os
+.Sh NAME
+.Nm bsdunzip
+.Nd extract files from a ZIP archive
+.Sh SYNOPSIS
+.Nm
+.Op Fl aCcfjLlnopqtuvy
+.Op Fl d Ar dir
+.Op Fl x Ar pattern
+.Op Fl P Ar password
+.Ar zipfile
+.Op Ar member ...
+.Sh DESCRIPTION
+.\" ...
+The following options are available:
+.Bl -tag -width Fl
+.It Fl a
+When extracting a text file, convert DOS-style line endings to
+Unix-style line endings.
+.It Fl C
+Match file names case-insensitively.
+.It Fl c
+Extract to stdout/screen.
+When extracting files from the zipfile, they are written to stdout.
+This is similar to
+.Fl p ,
+but does not suppress normal output.
+.It Fl d Ar dir
+Extract files into the specified directory rather than the current
+directory.
+.It Fl f
+Update existing.
+Extract only files from the zipfile if a file with the same name
+already exists on disk and is older than the former.
+Otherwise, the file is silently skipped.
+.It Fl j
+Ignore directories stored in the zipfile; instead, extract all files
+directly into the extraction directory.
+.It Fl L
+Convert the names of the extracted files and directories to lowercase.
+.It Fl l
+List, rather than extract, the contents of the zipfile.
+.It Fl n
+No overwrite.
+When extracting a file from the zipfile, if a file with the same name
+already exists on disk, the file is silently skipped.
+.It Fl o
+Overwrite.
+When extracting a file from the zipfile, if a file with the same name
+already exists on disk, the existing file is replaced with the file
+from the zipfile.
+.It Fl p
+Extract to stdout.
+When extracting files from the zipfile, they are written to stdout.
+The normal output is suppressed as if
+.Fl q
+was specified.
+.It Fl P Ar password
+Extract encrypted files using a password.
+Putting a password on the command line using this option can be
+insecure.
+.It Fl q
+Quiet: print less information while extracting.
+.It Fl t
+Test: do not extract anything, but verify the checksum of every file
+in the archive.
+.It Fl u
+Update.
+When extracting a file from the zipfile, if a file with the same name
+already exists on disk, the existing file is replaced with the file
+from the zipfile if and only if the latter is newer than the former.
+Otherwise, the file is silently skipped.
+.It Fl v
+List verbosely, rather than extract, the contents of the zipfile.
+This differs from
+.Fl l
+by using the long listing.
+Note that most of the data is currently fake and does not reflect the
+content of the archive.
+.It Fl x Ar pattern
+Exclude files matching the pattern
+.Ar pattern .
+.It Fl y
+Print four digit years in listings instead of two.
+.It Fl Z Ar mode
+Emulate
+.Xr zipinfo 1L
+mode.
+Enabling
+.Xr zipinfo 1L
+mode changes the way in which additional arguments are parsed.
+Currently only
+.Xr zipinfo 1L
+mode 1 is supported, which lists the file names one per line.
+.It Ar [member ...]
+Optional list of members to extract from the zipfile.
+Can include patterns, e.g.
+.Ar 'memberdir/*'
+will extract all files and dirs below memberdir.
+.El
+.Pp
+Note that only one of
+.Fl n ,
+.Fl o ,
+and
+.Fl u
+may be specified.
+If specified filename is
+.Qq - ,
+then data is read from
+.Va stdin .
+.Sh ENVIRONMENT
+If the
+.Ev UNZIP_DEBUG
+environment variable is defined, the
+.Fl q
+command-line option has no effect, and additional debugging
+information will be printed to
+.Va stderr .
+.Sh COMPATIBILITY
+The
+.Nm
+utility aims to be sufficiently compatible with other implementations
+to serve as a drop-in replacement in the context of the
+.Xr ports 7
+system.
+No attempt has been made to replicate functionality which is not
+required for that purpose.
+.Pp
+For compatibility reasons, command-line options will be recognized if
+they are listed not only before but also after the name of the
+zipfile.
+.Pp
+Normally, the
+.Fl a
+option should only affect files which are marked as text files in the
+zipfile's central directory.
+Since the
+.Xr archive 3
+library does not provide access to that information, it is not available
+to the
+.Nm
+utility.
+Instead, the
+.Nm
+utility will assume that a file is a text file if no non-ASCII
+characters are present within the first block of data decompressed for
+that file.
+If non-ASCII characters appear in subsequent blocks of data, a warning
+will be issued.
+.Pp
+The
+.Nm
+utility is only able to process ZIP archives handled by
+.Xr libarchive 3 .
+Depending on the installed version of
+.Xr libarchive 3 ,
+this may or may not include self-extracting or ZIPX archives.
+.Sh SEE ALSO
+.Xr libarchive 3
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Nm
+utility and this manual page were written by
+.An Dag-Erling Sm\(/orgrav Aq Mt des@FreeBSD.org .
+It uses the
+.Xr archive 3
+library developed by
+.An Tim Kientzle Aq Mt kientzle@FreeBSD.org .
--- /dev/null
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
+ * Copyright (c) 2007-2008 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ *
+ * This file would be much shorter if we didn't care about command-line
+ * compatibility with Info-ZIP's UnZip, which requires us to duplicate
+ * parts of libarchive in order to gain more detailed control of its
+ * behaviour for the purpose of implementing the -n, -o, -L and -a
+ * options.
+ */
+
+#include "bsdunzip_platform.h"
+
+#include <sys/queue.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <fnmatch.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <archive.h>
+#include <archive_entry.h>
+#include "passphrase.h"
+#include "err.h"
+
+/* command-line options */
+static int a_opt; /* convert EOL */
+static int C_opt; /* match case-insensitively */
+static int c_opt; /* extract to stdout */
+static const char *d_arg; /* directory */
+static int f_opt; /* update existing files only */
+static int j_opt; /* junk directories */
+static int L_opt; /* lowercase names */
+static int n_opt; /* never overwrite */
+static int o_opt; /* always overwrite */
+static int p_opt; /* extract to stdout, quiet */
+static char *P_arg; /* passphrase */
+static int q_opt; /* quiet */
+static int t_opt; /* test */
+static int u_opt; /* update */
+static int v_opt; /* verbose/list */
+static const char *y_str = ""; /* 4 digit year */
+static int Z1_opt; /* zipinfo mode list files only */
+
+/* debug flag */
+static int unzip_debug;
+
+/* zipinfo mode */
+static int zipinfo_mode;
+
+/* running on tty? */
+static int tty;
+
+/* convenience macro */
+/* XXX should differentiate between ARCHIVE_{WARN,FAIL,RETRY} */
+#define ac(call) \
+ do { \
+ int acret = (call); \
+ if (acret != ARCHIVE_OK) \
+ errorx("%s", archive_error_string(a)); \
+ } while (0)
+
+/*
+ * Indicates that last info() did not end with EOL. This helps error() et
+ * al. avoid printing an error message on the same line as an incomplete
+ * informational message.
+ */
+static int noeol;
+
+/* for an interactive passphrase input */
+static char *passphrase_buf;
+
+/* fatal error message + errno */
+static void
+error(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (noeol)
+ fprintf(stdout, "\n");
+ fflush(stdout);
+ fprintf(stderr, "unzip: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, ": %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+}
+
+/* fatal error message, no errno */
+static void
+errorx(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (noeol)
+ fprintf(stdout, "\n");
+ fflush(stdout);
+ fprintf(stderr, "unzip: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(EXIT_FAILURE);
+}
+
+/* non-fatal error message + errno */
+static void
+warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (noeol)
+ fprintf(stdout, "\n");
+ fflush(stdout);
+ fprintf(stderr, "unzip: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, ": %s\n", strerror(errno));
+}
+
+/* non-fatal error message, no errno */
+static void
+warningx(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (noeol)
+ fprintf(stdout, "\n");
+ fflush(stdout);
+ fprintf(stderr, "unzip: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+/* informational message (if not -q) */
+static void
+info(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (q_opt && !unzip_debug)
+ return;
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ va_end(ap);
+ fflush(stdout);
+
+ if (*fmt == '\0')
+ noeol = 1;
+ else
+ noeol = fmt[strlen(fmt) - 1] != '\n';
+}
+
+/* debug message (if unzip_debug) */
+static void
+debug(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!unzip_debug)
+ return;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fflush(stderr);
+
+ if (*fmt == '\0')
+ noeol = 1;
+ else
+ noeol = fmt[strlen(fmt) - 1] != '\n';
+}
+
+/* duplicate a path name, possibly converting to lower case */
+static char *
+pathdup(const char *path)
+{
+ char *str;
+ size_t i, len;
+
+ if (path == NULL || path[0] == '\0')
+ return (NULL);
+
+ len = strlen(path);
+ while (len && path[len - 1] == '/')
+ len--;
+ if ((str = malloc(len + 1)) == NULL) {
+ errno = ENOMEM;
+ error("malloc()");
+ }
+ if (L_opt) {
+ for (i = 0; i < len; ++i)
+ str[i] = tolower((unsigned char)path[i]);
+ } else {
+ memcpy(str, path, len);
+ }
+ str[len] = '\0';
+
+ return (str);
+}
+
+/* concatenate two path names */
+static char *
+pathcat(const char *prefix, const char *path)
+{
+ char *str;
+ size_t prelen, len;
+
+ prelen = prefix ? strlen(prefix) + 1 : 0;
+ len = strlen(path) + 1;
+ if ((str = malloc(prelen + len)) == NULL) {
+ errno = ENOMEM;
+ error("malloc()");
+ }
+ if (prefix) {
+ memcpy(str, prefix, prelen); /* includes zero */
+ str[prelen - 1] = '/'; /* splat zero */
+ }
+ memcpy(str + prelen, path, len); /* includes zero */
+
+ return (str);
+}
+
+/*
+ * Pattern lists for include / exclude processing
+ */
+struct pattern {
+ STAILQ_ENTRY(pattern) link;
+ char pattern[];
+};
+
+STAILQ_HEAD(pattern_list, pattern);
+static struct pattern_list include = STAILQ_HEAD_INITIALIZER(include);
+static struct pattern_list exclude = STAILQ_HEAD_INITIALIZER(exclude);
+
+/*
+ * Add an entry to a pattern list
+ */
+static void
+add_pattern(struct pattern_list *list, const char *pattern)
+{
+ struct pattern *entry;
+ size_t len;
+
+ debug("adding pattern '%s'\n", pattern);
+ len = strlen(pattern);
+ if ((entry = malloc(sizeof *entry + len + 1)) == NULL) {
+ errno = ENOMEM;
+ error("malloc()");
+ }
+ memcpy(entry->pattern, pattern, len + 1);
+ STAILQ_INSERT_TAIL(list, entry, link);
+}
+
+/*
+ * Match a string against a list of patterns
+ */
+static int
+match_pattern(struct pattern_list *list, const char *str)
+{
+ struct pattern *entry;
+
+ STAILQ_FOREACH(entry, list, link) {
+ if (fnmatch(entry->pattern, str, C_opt ? FNM_CASEFOLD : 0) == 0)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Verify that a given pathname is in the include list and not in the
+ * exclude list.
+ */
+static int
+accept_pathname(const char *pathname)
+{
+
+ if (!STAILQ_EMPTY(&include) && !match_pattern(&include, pathname))
+ return (0);
+ if (!STAILQ_EMPTY(&exclude) && match_pattern(&exclude, pathname))
+ return (0);
+ return (1);
+}
+
+/*
+ * Create the specified directory with the specified mode, taking certain
+ * precautions on they way.
+ */
+static void
+make_dir(const char *path, int mode)
+{
+ struct stat sb;
+
+ if (lstat(path, &sb) == 0) {
+ if (S_ISDIR(sb.st_mode))
+ return;
+ /*
+ * Normally, we should either ask the user about removing
+ * the non-directory of the same name as a directory we
+ * wish to create, or respect the -n or -o command-line
+ * options. However, this may lead to a later failure or
+ * even compromise (if this non-directory happens to be a
+ * symlink to somewhere unsafe), so we don't.
+ */
+
+ /*
+ * Don't check unlink() result; failure will cause mkdir()
+ * to fail later, which we will catch.
+ */
+ (void)unlink(path);
+ }
+ if (mkdir(path, mode) != 0 && errno != EEXIST)
+ error("mkdir('%s')", path);
+}
+
+/*
+ * Ensure that all directories leading up to (but not including) the
+ * specified path exist.
+ *
+ * XXX inefficient + modifies the file in-place
+ */
+static void
+make_parent(char *path)
+{
+ struct stat sb;
+ char *sep;
+
+ sep = strrchr(path, '/');
+ if (sep == NULL || sep == path)
+ return;
+ *sep = '\0';
+ if (lstat(path, &sb) == 0) {
+ if (S_ISDIR(sb.st_mode)) {
+ *sep = '/';
+ return;
+ }
+ unlink(path);
+ }
+ make_parent(path);
+ mkdir(path, 0755);
+ *sep = '/';
+
+#if 0
+ for (sep = path; (sep = strchr(sep, '/')) != NULL; sep++) {
+ /* root in case of absolute d_arg */
+ if (sep == path)
+ continue;
+ *sep = '\0';
+ make_dir(path, 0755);
+ *sep = '/';
+ }
+#endif
+}
+
+/*
+ * Extract a directory.
+ */
+static void
+extract_dir(struct archive *a, struct archive_entry *e, const char *path)
+{
+ int mode;
+
+ /*
+ * Dropbox likes to create '/' directory entries, just ignore
+ * such junk.
+ */
+ if (*path == '\0')
+ return;
+
+ mode = archive_entry_mode(e) & 0777;
+ if (mode == 0)
+ mode = 0755;
+
+ /*
+ * Some zipfiles contain directories with weird permissions such
+ * as 0644 or 0444. This can cause strange issues such as being
+ * unable to extract files into the directory we just created, or
+ * the user being unable to remove the directory later without
+ * first manually changing its permissions. Therefore, we whack
+ * the permissions into shape, assuming that the user wants full
+ * access and that anyone who gets read access also gets execute
+ * access.
+ */
+ mode |= 0700;
+ if (mode & 0040)
+ mode |= 0010;
+ if (mode & 0004)
+ mode |= 0001;
+
+ info(" creating: %s/\n", path);
+ make_dir(path, mode);
+ ac(archive_read_data_skip(a));
+}
+
+static unsigned char buffer[8192];
+static char spinner[] = { '|', '/', '-', '\\' };
+
+static int
+handle_existing_file(char **path)
+{
+ size_t alen;
+ ssize_t len;
+ char buf[4];
+
+ for (;;) {
+ fprintf(stderr,
+ "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
+ *path);
+ if (fgets(buf, sizeof(buf), stdin) == NULL) {
+ clearerr(stdin);
+ printf("NULL\n(EOF or read error, "
+ "treating as \"[N]one\"...)\n");
+ n_opt = 1;
+ return -1;
+ }
+ switch (*buf) {
+ case 'A':
+ o_opt = 1;
+ /* FALLTHROUGH */
+ case 'y':
+ case 'Y':
+ (void)unlink(*path);
+ return 1;
+ case 'N':
+ n_opt = 1;
+ /* FALLTHROUGH */
+ case 'n':
+ return -1;
+ case 'r':
+ case 'R':
+ printf("New name: ");
+ fflush(stdout);
+ free(*path);
+ *path = NULL;
+ alen = 0;
+ len = getline(path, &alen, stdin);
+ if ((*path)[len - 1] == '\n')
+ (*path)[len - 1] = '\0';
+ return 0;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Detect binary files by a combination of character white list and
+ * black list. NUL bytes and other control codes without use in text files
+ * result directly in switching the file to binary mode. Otherwise, at least
+ * one white-listed byte has to be found.
+ *
+ * Black-listed: 0..6, 14..25, 28..31
+ * 0xf3ffc07f = 11110011111111111100000001111111b
+ * White-listed: 9..10, 13, >= 32
+ * 0x00002600 = 00000000000000000010011000000000b
+ *
+ * See the proginfo/txtvsbin.txt in the zip sources for a detailed discussion.
+ */
+#define BYTE_IS_BINARY(x) ((x) < 32 && (0xf3ffc07fU & (1U << (x))))
+#define BYTE_IS_TEXT(x) ((x) >= 32 || (0x00002600U & (1U << (x))))
+
+static int
+check_binary(const unsigned char *buf, size_t len)
+{
+ int rv;
+ for (rv = 1; len--; ++buf) {
+ if (BYTE_IS_BINARY(*buf))
+ return 1;
+ if (BYTE_IS_TEXT(*buf))
+ rv = 0;
+ }
+
+ return rv;
+}
+
+/*
+ * Extract to a file descriptor
+ */
+static int
+extract2fd(struct archive *a, char *pathname, int fd)
+{
+ int cr, text, warn;
+ ssize_t len;
+ unsigned char *p, *q, *end;
+
+ text = a_opt;
+ warn = 0;
+ cr = 0;
+
+ /* loop over file contents and write to fd */
+ for (int n = 0; ; n++) {
+ if (fd != STDOUT_FILENO)
+ if (tty && (n % 4) == 0)
+ info(" %c\b\b", spinner[(n / 4) % sizeof spinner]);
+
+ len = archive_read_data(a, buffer, sizeof buffer);
+
+ if (len < 0)
+ ac(len);
+
+ /* left over CR from previous buffer */
+ if (a_opt && cr) {
+ if (len == 0 || buffer[0] != '\n')
+ if (write(fd, "\r", 1) != 1)
+ error("write('%s')", pathname);
+ cr = 0;
+ }
+
+ /* EOF */
+ if (len == 0)
+ break;
+ end = buffer + len;
+
+ /*
+ * Detect whether this is a text file. The correct way to
+ * do this is to check the least significant bit of the
+ * "internal file attributes" field of the corresponding
+ * file header in the central directory, but libarchive
+ * does not provide access to this field, so we have to
+ * guess by looking for non-ASCII characters in the
+ * buffer. Hopefully we won't guess wrong. If we do
+ * guess wrong, we print a warning message later.
+ */
+ if (a_opt && n == 0) {
+ if (check_binary(buffer, len))
+ text = 0;
+ }
+
+ /* simple case */
+ if (!a_opt || !text) {
+ if (write(fd, buffer, len) != len)
+ error("write('%s')", pathname);
+ continue;
+ }
+
+ /* hard case: convert \r\n to \n (sigh...) */
+ for (p = buffer; p < end; p = q + 1) {
+ for (q = p; q < end; q++) {
+ if (!warn && BYTE_IS_BINARY(*q)) {
+ warningx("%s may be corrupted due"
+ " to weak text file detection"
+ " heuristic", pathname);
+ warn = 1;
+ }
+ if (q[0] != '\r')
+ continue;
+ if (&q[1] == end) {
+ cr = 1;
+ break;
+ }
+ if (q[1] == '\n')
+ break;
+ }
+ if (write(fd, p, q - p) != q - p)
+ error("write('%s')", pathname);
+ }
+ }
+
+ return text;
+}
+
+/*
+ * Extract a regular file.
+ */
+static void
+extract_file(struct archive *a, struct archive_entry *e, char **path)
+{
+ int mode;
+ struct timespec mtime;
+ struct stat sb;
+ struct timespec ts[2];
+ int fd, check, text;
+ const char *linkname;
+
+ mode = archive_entry_mode(e) & 0777;
+ if (mode == 0)
+ mode = 0644;
+ mtime.tv_sec = archive_entry_mtime(e);
+ mtime.tv_nsec = archive_entry_mtime_nsec(e);
+
+ /* look for existing file of same name */
+recheck:
+ if (lstat(*path, &sb) == 0) {
+ if (u_opt || f_opt) {
+ /* check if up-to-date */
+ if (S_ISREG(sb.st_mode) &&
+ (sb.st_mtim.tv_sec > mtime.tv_sec ||
+ (sb.st_mtim.tv_sec == mtime.tv_sec &&
+ sb.st_mtim.tv_nsec >= mtime.tv_nsec)))
+ return;
+ (void)unlink(*path);
+ } else if (o_opt) {
+ /* overwrite */
+ (void)unlink(*path);
+ } else if (n_opt) {
+ /* do not overwrite */
+ return;
+ } else {
+ check = handle_existing_file(path);
+ if (check == 0)
+ goto recheck;
+ if (check == -1)
+ return; /* do not overwrite */
+ }
+ } else {
+ if (f_opt)
+ return;
+ }
+
+ ts[0].tv_sec = 0;
+ ts[0].tv_nsec = UTIME_NOW;
+ ts[1] = mtime;
+
+ /* process symlinks */
+ linkname = archive_entry_symlink(e);
+ if (linkname != NULL) {
+ if (symlink(linkname, *path) != 0)
+ error("symlink('%s')", *path);
+ info(" extracting: %s -> %s\n", *path, linkname);
+ if (lchmod(*path, mode) != 0)
+ warning("Cannot set mode for '%s'", *path);
+ /* set access and modification time */
+ if (utimensat(AT_FDCWD, *path, ts, AT_SYMLINK_NOFOLLOW) != 0)
+ warning("utimensat('%s')", *path);
+ return;
+ }
+
+ if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
+ error("open('%s')", *path);
+
+ info(" extracting: %s", *path);
+
+ text = extract2fd(a, *path, fd);
+
+ if (tty)
+ info(" \b\b");
+ if (text)
+ info(" (text)");
+ info("\n");
+
+ /* set access and modification time */
+ if (futimens(fd, ts) != 0)
+ error("futimens('%s')", *path);
+ if (close(fd) != 0)
+ error("close('%s')", *path);
+}
+
+/*
+ * Extract a zipfile entry: first perform some sanity checks to ensure
+ * that it is either a directory or a regular file and that the path is
+ * not absolute and does not try to break out of the current directory;
+ * then call either extract_dir() or extract_file() as appropriate.
+ *
+ * This is complicated a bit by the various ways in which we need to
+ * manipulate the path name. Case conversion (if requested by the -L
+ * option) happens first, but the include / exclude patterns are applied
+ * to the full converted path name, before the directory part of the path
+ * is removed in accordance with the -j option. Sanity checks are
+ * intentionally done earlier than they need to be, so the user will get a
+ * warning about insecure paths even for files or directories which
+ * wouldn't be extracted anyway.
+ */
+static void
+extract(struct archive *a, struct archive_entry *e)
+{
+ char *pathname, *realpathname;
+ mode_t filetype;
+ char *p, *q;
+
+ if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) {
+ warningx("skipping empty or unreadable filename entry");
+ ac(archive_read_data_skip(a));
+ return;
+ }
+ filetype = archive_entry_filetype(e);
+
+ /* sanity checks */
+ if (pathname[0] == '/' ||
+ strncmp(pathname, "../", 3) == 0 ||
+ strstr(pathname, "/../") != NULL) {
+ warningx("skipping insecure entry '%s'", pathname);
+ ac(archive_read_data_skip(a));
+ free(pathname);
+ return;
+ }
+
+ /* I don't think this can happen in a zipfile.. */
+ if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) {
+ warningx("skipping non-regular entry '%s'", pathname);
+ ac(archive_read_data_skip(a));
+ free(pathname);
+ return;
+ }
+
+ /* skip directories in -j case */
+ if (S_ISDIR(filetype) && j_opt) {
+ ac(archive_read_data_skip(a));
+ free(pathname);
+ return;
+ }
+
+ /* apply include / exclude patterns */
+ if (!accept_pathname(pathname)) {
+ ac(archive_read_data_skip(a));
+ free(pathname);
+ return;
+ }
+
+ /* apply -j and -d */
+ if (j_opt) {
+ for (p = q = pathname; *p; ++p)
+ if (*p == '/')
+ q = p + 1;
+ realpathname = pathcat(d_arg, q);
+ } else {
+ realpathname = pathcat(d_arg, pathname);
+ }
+
+ /* ensure that parent directory exists */
+ make_parent(realpathname);
+
+ if (S_ISDIR(filetype))
+ extract_dir(a, e, realpathname);
+ else
+ extract_file(a, e, &realpathname);
+
+ free(realpathname);
+ free(pathname);
+}
+
+static void
+extract_stdout(struct archive *a, struct archive_entry *e)
+{
+ char *pathname;
+ mode_t filetype;
+
+ if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) {
+ warningx("skipping empty or unreadable filename entry");
+ ac(archive_read_data_skip(a));
+ return;
+ }
+ filetype = archive_entry_filetype(e);
+
+ /* I don't think this can happen in a zipfile.. */
+ if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) {
+ warningx("skipping non-regular entry '%s'", pathname);
+ ac(archive_read_data_skip(a));
+ free(pathname);
+ return;
+ }
+
+ /* skip directories in -j case */
+ if (S_ISDIR(filetype)) {
+ ac(archive_read_data_skip(a));
+ free(pathname);
+ return;
+ }
+
+ /* apply include / exclude patterns */
+ if (!accept_pathname(pathname)) {
+ ac(archive_read_data_skip(a));
+ free(pathname);
+ return;
+ }
+
+ if (c_opt)
+ info("x %s\n", pathname);
+
+ (void)extract2fd(a, pathname, STDOUT_FILENO);
+
+ free(pathname);
+}
+
+/*
+ * Print the name of an entry to stdout.
+ */
+static void
+list(struct archive *a, struct archive_entry *e)
+{
+ char buf[20];
+ time_t mtime;
+ struct tm *tm;
+
+ mtime = archive_entry_mtime(e);
+ tm = localtime(&mtime);
+ if (*y_str)
+ strftime(buf, sizeof(buf), "%m-%d-%G %R", tm);
+ else
+ strftime(buf, sizeof(buf), "%m-%d-%g %R", tm);
+
+ if (!zipinfo_mode) {
+ if (v_opt == 1) {
+ printf(" %8ju %s %s\n",
+ (uintmax_t)archive_entry_size(e),
+ buf, archive_entry_pathname(e));
+ } else if (v_opt == 2) {
+ printf("%8ju Stored %7ju 0%% %s %08x %s\n",
+ (uintmax_t)archive_entry_size(e),
+ (uintmax_t)archive_entry_size(e),
+ buf,
+ 0U,
+ archive_entry_pathname(e));
+ }
+ } else {
+ if (Z1_opt)
+ printf("%s\n",archive_entry_pathname(e));
+ }
+ ac(archive_read_data_skip(a));
+}
+
+/*
+ * Extract to memory to check CRC
+ */
+static int
+test(struct archive *a, struct archive_entry *e)
+{
+ ssize_t len;
+ int error_count;
+
+ error_count = 0;
+ if (S_ISDIR(archive_entry_filetype(e)))
+ return 0;
+
+ info(" testing: %s\t", archive_entry_pathname(e));
+ while ((len = archive_read_data(a, buffer, sizeof buffer)) > 0)
+ /* nothing */;
+ if (len < 0) {
+ info(" %s\n", archive_error_string(a));
+ ++error_count;
+ } else {
+ info(" OK\n");
+ }
+
+ /* shouldn't be necessary, but it doesn't hurt */
+ ac(archive_read_data_skip(a));
+
+ return error_count;
+}
+
+/*
+ * Callback function for reading passphrase.
+ * Originally from cpio.c and passphrase.c, libarchive.
+ */
+#define PPBUFF_SIZE 1024
+static const char *
+passphrase_callback(struct archive *a, void *_client_data)
+{
+ char *p;
+
+ (void)a; /* UNUSED */
+ (void)_client_data; /* UNUSED */
+
+ if (passphrase_buf == NULL) {
+ passphrase_buf = malloc(PPBUFF_SIZE);
+ if (passphrase_buf == NULL) {
+ errno = ENOMEM;
+ error("malloc()");
+ }
+ }
+
+ p = lafe_readpassphrase("\nEnter password: ", passphrase_buf,
+ PPBUFF_SIZE);
+
+ if (p == NULL && errno != EINTR)
+ error("Error reading password");
+
+ return p;
+}
+
+/*
+ * Main loop: open the zipfile, iterate over its contents and decide what
+ * to do with each entry.
+ */
+static void
+unzip(const char *fn)
+{
+ struct archive *a;
+ struct archive_entry *e;
+ int ret;
+ uintmax_t total_size, file_count, error_count;
+
+ if ((a = archive_read_new()) == NULL)
+ error("archive_read_new failed");
+
+ ac(archive_read_support_format_zip(a));
+
+ if (P_arg)
+ archive_read_add_passphrase(a, P_arg);
+ else
+ archive_read_set_passphrase_callback(a, NULL,
+ &passphrase_callback);
+
+ ac(archive_read_open_filename(a, fn, 8192));
+
+ if (!zipinfo_mode) {
+ if (!p_opt && !q_opt)
+ printf("Archive: %s\n", fn);
+ if (v_opt == 1) {
+ printf(" Length %sDate Time Name\n", y_str);
+ printf(" -------- %s---- ---- ----\n", y_str);
+ } else if (v_opt == 2) {
+ printf(" Length Method Size Ratio %sDate Time CRC-32 Name\n", y_str);
+ printf("-------- ------ ------- ----- %s---- ---- ------ ----\n", y_str);
+ }
+ }
+
+ total_size = 0;
+ file_count = 0;
+ error_count = 0;
+ for (;;) {
+ ret = archive_read_next_header(a, &e);
+ if (ret == ARCHIVE_EOF)
+ break;
+ ac(ret);
+ if (!zipinfo_mode) {
+ if (t_opt)
+ error_count += test(a, e);
+ else if (v_opt)
+ list(a, e);
+ else if (p_opt || c_opt)
+ extract_stdout(a, e);
+ else
+ extract(a, e);
+ } else {
+ if (Z1_opt)
+ list(a, e);
+ }
+
+ total_size += archive_entry_size(e);
+ ++file_count;
+ }
+
+ if (zipinfo_mode) {
+ if (v_opt == 1) {
+ printf(" -------- %s-------\n", y_str);
+ printf(" %8ju %s%ju file%s\n",
+ total_size, y_str, file_count, file_count != 1 ? "s" : "");
+ } else if (v_opt == 2) {
+ printf("-------- ------- --- %s-------\n", y_str);
+ printf("%8ju %7ju 0%% %s%ju file%s\n",
+ total_size, total_size, y_str, file_count,
+ file_count != 1 ? "s" : "");
+ }
+ }
+
+ ac(archive_read_free(a));
+
+ if (passphrase_buf != NULL) {
+ memset(passphrase_buf, 0, PPBUFF_SIZE);
+ free(passphrase_buf);
+ }
+
+ if (t_opt) {
+ if (error_count > 0) {
+ errorx("%ju checksum error(s) found.", error_count);
+ }
+ else {
+ printf("No errors detected in compressed data of %s.\n",
+ fn);
+ }
+ }
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+"Usage: unzip [-aCcfjLlnopqtuvyZ1] [-d dir] [-x pattern] [-P password] zipfile\n"
+" [member ...]\n");
+ exit(EXIT_FAILURE);
+}
+
+static int
+getopts(int argc, char *argv[])
+{
+ int opt;
+
+ optreset = optind = 1;
+ while ((opt = getopt(argc, argv, "aCcd:fjLlnopP:qtuvx:yZ1")) != -1)
+ switch (opt) {
+ case '1':
+ Z1_opt = 1;
+ break;
+ case 'a':
+ a_opt = 1;
+ break;
+ case 'C':
+ C_opt = 1;
+ break;
+ case 'c':
+ c_opt = 1;
+ break;
+ case 'd':
+ d_arg = optarg;
+ break;
+ case 'f':
+ f_opt = 1;
+ break;
+ case 'j':
+ j_opt = 1;
+ break;
+ case 'L':
+ L_opt = 1;
+ break;
+ case 'l':
+ if (v_opt == 0)
+ v_opt = 1;
+ break;
+ case 'n':
+ n_opt = 1;
+ break;
+ case 'o':
+ o_opt = 1;
+ q_opt = 1;
+ break;
+ case 'p':
+ p_opt = 1;
+ break;
+ case 'P':
+ P_arg = optarg;
+ break;
+ case 'q':
+ q_opt = 1;
+ break;
+ case 't':
+ t_opt = 1;
+ break;
+ case 'u':
+ u_opt = 1;
+ break;
+ case 'v':
+ v_opt = 2;
+ break;
+ case 'x':
+ add_pattern(&exclude, optarg);
+ break;
+ case 'y':
+ y_str = " ";
+ break;
+ case 'Z':
+ zipinfo_mode = 1;
+ break;
+ default:
+ usage();
+ }
+
+ return (optind);
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *zipfile;
+ int nopts;
+
+ if (isatty(STDOUT_FILENO))
+ tty = 1;
+
+ if (getenv("UNZIP_DEBUG") != NULL)
+ unzip_debug = 1;
+ for (int i = 0; i < argc; ++i)
+ debug("%s%c", argv[i], (i < argc - 1) ? ' ' : '\n');
+
+ /*
+ * Info-ZIP's unzip(1) expects certain options to come before the
+ * zipfile name, and others to come after - though it does not
+ * enforce this. For simplicity, we accept *all* options both
+ * before and after the zipfile name.
+ */
+ nopts = getopts(argc, argv);
+
+ /*
+ * When more of the zipinfo mode options are implemented, this
+ * will need to change.
+ */
+ if (zipinfo_mode && !Z1_opt) {
+ printf("Zipinfo mode needs additional options\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (argc <= nopts)
+ usage();
+ zipfile = argv[nopts++];
+
+ if (strcmp(zipfile, "-") == 0)
+ zipfile = NULL; /* STDIN */
+
+ while (nopts < argc && *argv[nopts] != '-')
+ add_pattern(&include, argv[nopts++]);
+
+ nopts--; /* fake argv[0] */
+ nopts += getopts(argc - nopts, argv + nopts);
+
+ if (n_opt + o_opt + u_opt > 1)
+ errorx("-n, -o and -u are contradictory");
+
+ unzip(zipfile);
+
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ * $FreeBSD: src/usr.bin/tar/bsdtar_platform.h,v 1.26 2008/12/06 07:37:14 kientzle Exp $
+ */
+
+/*
+ * This header is the first thing included in any of the bsdtar
+ * source files. As far as possible, platform-specific issues should
+ * be dealt with here and not within individual source files.
+ */
+
+#ifndef BSDUNZIP_PLATFORM_H_INCLUDED
+#define BSDUNZIP_PLATFORM_H_INCLUDED
+
+#if defined(PLATFORM_CONFIG_H)
+/* Use hand-built config.h in environments that need it. */
+#include PLATFORM_CONFIG_H
+#else
+/* Not having a config.h of some sort is a serious problem. */
+#include "config.h"
+#endif
+
+/* Get a real definition for __FBSDID if we can */
+#if HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/* If not, define it so as to avoid dangling semicolons. */
+#ifndef __FBSDID
+#define __FBSDID(a) struct _undefined_hack
+#endif
+
+#ifdef HAVE_LIBARCHIVE
+/* If we're using the platform libarchive, include system headers. */
+#include <archive.h>
+#include <archive_entry.h>
+#else
+/* Otherwise, include user headers. */
+#include "archive.h"
+#include "archive_entry.h"
+#endif
+
+#ifndef HAVE_GETOPT_OPTRESET
+/*
+ * If platform doesn't use optreset for resetting getopt, declare it so
+ * C source doesn't have to know this platform-specific difference
+ */
+int optreset;
+#endif
+
+/* How to mark functions that don't return. */
+/* This facilitates use of some newer static code analysis tools. */
+#undef __LA_DEAD
+#if defined(__GNUC__) && (__GNUC__ > 2 || \
+ (__GNUC__ == 2 && __GNUC_MINOR__ >= 5))
+#define __LA_DEAD __attribute__((__noreturn__))
+#else
+#define __LA_DEAD
+#endif
+
+#endif /* !BSDUNZIP_PLATFORM_H_INCLUDED */
--- /dev/null
+############################################
+#
+# How to build bsdunzip_test
+#
+############################################
+IF(ENABLE_UNZIP AND ENABLE_TEST)
+ SET(bsdunzip_test_SOURCES
+ ../../libarchive_fe/err.c
+ ../../test_utils/test_utils.c
+ ../../test_utils/test_main.c
+ test.h
+ test_0.c
+ test_basic.c
+ test_glob.c
+ test_singlefile.c
+ test_C.c
+ test_p.c
+ test_d.c
+ test_j.c
+ test_L.c
+ test_n.c
+ test_o.c
+ test_q.c
+ test_t.c
+ test_t_bad.c
+ test_x.c
+ test_Z1.c
+ test_P_encryption.c
+ )
+
+ #
+ # Register target
+ #
+ ADD_EXECUTABLE(bsdunzip_test ${bsdunzip_test_SOURCES})
+ SET_PROPERTY(TARGET bsdunzip_test PROPERTY COMPILE_DEFINITIONS LIST_H)
+
+ #
+ # Generate list.h by grepping DEFINE_TEST() lines out of the C sources.
+ #
+ GENERATE_LIST_H(${CMAKE_CURRENT_BINARY_DIR}/list.h
+ ${CMAKE_CURRENT_LIST_FILE} ${bsdunzip_test_SOURCES})
+ SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_BINARY_DIR})
+
+ # list.h has a line DEFINE_TEST(testname) for every
+ # test. We can use that to define the tests for cmake by
+ # defining a DEFINE_TEST macro and reading list.h in.
+ MACRO (DEFINE_TEST _testname)
+ ADD_TEST(
+ NAME bsdunzip_${_testname}
+ COMMAND bsdunzip_test -vv
+ -p $<TARGET_FILE:bsdunzip>
+ -r ${CMAKE_CURRENT_SOURCE_DIR}
+ ${_testname})
+ ENDMACRO (DEFINE_TEST _testname)
+
+ INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h)
+ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
+ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/unzip/test)
+
+ # Experimental new test handling
+ ADD_CUSTOM_TARGET(run_bsdunzip_test
+ COMMAND bsdunzip_test -p $<TARGET_FILE:bsdunzip>
+ -r ${CMAKE_CURRENT_SOURCE_DIR}
+ -vv)
+ ADD_DEPENDENCIES(run_bsdunzip_test bsdunzip)
+ ADD_DEPENDENCIES(run_all_tests run_bsdunzip_test)
+ENDIF(ENABLE_UNZIP AND ENABLE_TEST)
+
--- /dev/null
+/*
+ * Copyright (c) 2003-2017 Tim Kientzle
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ * $FreeBSD$
+ */
+
+/* Every test program should #include "test.h" as the first thing. */
+
+#define KNOWNREF "test_basic.zip.uu"
+#define ENVBASE "BSDUNZIP" /* Prefix for environment variables. */
+#define PROGRAM "bsdunzip" /* Name of program being tested. */
+#define PROGRAM_ALIAS "unzip" /* Generic alias for program */
+#undef LIBRARY /* Not testing a library. */
+#undef EXTRA_DUMP /* How to dump extra data */
+#undef EXTRA_ERRNO /* How to dump errno */
+/* How to generate extra version info. */
+#define EXTRA_VERSION (system(testprog) ? "" : "")
+
+#include "test_common.h"
--- /dev/null
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/*
+ * This first test does basic sanity checks on the environment. For
+ * most of these, we just exit on failure.
+ */
+#if !defined(_WIN32) || defined(__CYGWIN__)
+#define DEV_NULL "/dev/null"
+#else
+#define DEV_NULL "NUL"
+#endif
+
+DEFINE_TEST(test_0)
+{
+ struct stat st;
+
+ failure("File %s does not exist?!", testprog);
+ if (!assertEqualInt(0, stat(testprogfile, &st))) {
+ fprintf(stderr,
+ "\nFile %s does not exist; aborting test.\n\n",
+ testprog);
+ exit(1);
+ }
+
+ failure("%s is not executable?!", testprog);
+ if (!assert((st.st_mode & 0111) != 0)) {
+ fprintf(stderr,
+ "\nFile %s not executable; aborting test.\n\n",
+ testprog);
+ exit(1);
+ }
+
+ /* TODO: Ensure that our reference files are available. */
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test C arg - match case-insensitive */
+DEFINE_TEST(test_C)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -C %s test_basic/caps >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents CAPS\n", "test_basic/CAPS");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test L arg - make names lowercase */
+DEFINE_TEST(test_L)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -L %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents a\n", "test_basic/a");
+ assertTextFileContents("contents b\n", "test_basic/b");
+ assertTextFileContents("contents c\n", "test_basic/c");
+ assertTextFileContents("contents CAPS\n", "test_basic/caps");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test P arg - password protected */
+DEFINE_TEST(test_P)
+{
+ const char *reffile = "test_encrypted.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -P password %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("plaintext\n", "encrypted/file.txt");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test -Z1 arg - List filenames */
+DEFINE_TEST(test_Z1)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -Z1 %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertTextFileContents("test_basic/\ntest_basic/a\ntest_basic/b\ntest_basic/c\ntest_basic/CAPS\n", "test.out");
+ assertEmptyFile("test.err");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* This test just does a basic zip decompression */
+DEFINE_TEST(test_basic)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents a\n", "test_basic/a");
+ assertTextFileContents("contents b\n", "test_basic/b");
+ assertTextFileContents("contents c\n", "test_basic/c");
+ assertTextFileContents("contents CAPS\n", "test_basic/CAPS");
+}
--- /dev/null
+begin 644 test_basic.zip
+M4$L#!!0``````,J0MU8````````````````+`"``=&5S=%]B87-I8R]55`T`
+M!]PX;63U.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+`P04``@`"``)C;=6````
+M```````+````#``@`'1E<W1?8F%S:6,O8554#0`'PS)M9/HY;603.&UD=7@+
+M``$$Z`,```3H`P``2\[/*TG-*RE62.0"`%!+!PAY:C`$#0````L```!02P,$
+M%``(``@`#HVW5@``````````"P````P`(`!T97-T7V)A<VEC+V)55`T`!\TR
+M;63Z.6UD.SAM9'5X"P`!!.@#```$Z`,``$O.SRM)S2LI5DCB`@!02P<(NCD=
+M+PT````+````4$L#!!0`"``(`%*-MU8```````````L````,`"``=&5S=%]B
+M87-I8R]C550-``=,,VUDTSAM9,\X;61U>`L``03H`P``!.@#``!+SL\K2<TK
+M*59(Y@(`4$L'"/L(!C8-````"P```%!+`P04``@`"`#*D+=6```````````.
+M````#P`@`'1E<W1?8F%S:6,O0T%04U54#0`'W#AM9/HY;63<.&UD=7@+``$$
+MZ`,```3H`P``2\[/*TG-*RE6<'8,".8"`%!+!P@I4T'W$`````X```!02P$"
+M%`,4``````#*D+=6````````````````"P`@````````````[4$`````=&5S
+M=%]B87-I8R]55`T`!]PX;63U.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+`0(4
+M`Q0`"``(``F-MU9Y:C`$#0````L````,`"````````````"D@4D```!T97-T
+M7V)A<VEC+V%55`T`!\,R;63Z.6UD$SAM9'5X"P`!!.@#```$Z`,``%!+`0(4
+M`Q0`"``(``Z-MU:Z.1TO#0````L````,`"````````````"D@;````!T97-T
+M7V)A<VEC+V)55`T`!\TR;63Z.6UD.SAM9'5X"P`!!.@#```$Z`,``%!+`0(4
+M`Q0`"``(`%*-MU;["`8V#0````L````,`"````````````"D@1<!``!T97-T
+M7V)A<VEC+V-55`T`!TPS;633.&UDSSAM9'5X"P`!!.@#```$Z`,``%!+`0(4
+M`Q0`"``(`,J0MU8I4T'W$`````X````/`"````````````"D@7X!``!T97-T
+M7V)A<VEC+T-!4%-55`T`!]PX;63Z.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+
+4!08`````!0`%`,0!``#K`0``````
+`
+end
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test d arg - extract to target dir */
+DEFINE_TEST(test_d)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -d foobar %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents a\n", "foobar/test_basic/a");
+ assertTextFileContents("contents b\n", "foobar/test_basic/b");
+ assertTextFileContents("contents c\n", "foobar/test_basic/c");
+ assertTextFileContents("contents CAPS\n", "foobar/test_basic/CAPS");
+}
--- /dev/null
+begin 644 test_encrypted.zip
+M4$L#!!0``````'*1MU8````````````````*`"``96YC<GEP=&5D+U54#0`'
+M&#IM9!LZ;608.FUD=7@+``$$Z`,```3H`P``4$L#!!0`"0!C`'*1MU8`````
+M``````H````2`"L`96YC<GEP=&5D+V9I;&4N='AT550-``<8.FUD&#IM9!@Z
+M;61U>`L``03H`P``!.@#```!F0<``@!!10,(`*_-)-RYPDYFJ$Q9+L<I#-><
+M'#C?XVBR9/=H?7U\LC!A^8<6[&CO#PM02P<(`````"@````*````4$L!`A0#
+M%```````<I&W5@````````````````H`(````````````.U!`````&5N8W)Y
+M<'1E9"]55`T`!Q@Z;60;.FUD&#IM9'5X"P`!!.@#```$Z`,``%!+`0(4`Q0`
+M"0!C`'*1MU8`````*`````H````2`"L```````````"D@4@```!E;F-R>7!T
+M960O9FEL92YT>'155`T`!Q@Z;608.FUD&#IM9'5X"P`!!.@#```$Z`,```&9
+?!P`"`$%%`P@`4$L%!@`````"``(`PP```-L`````````
+`
+end
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test that the glob works */
+DEFINE_TEST(test_glob)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s %s test_*/[ab] >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents a\n", "test_basic/a");
+ assertTextFileContents("contents b\n", "test_basic/b");
+ assertFileNotExists("test_basic/c");
+ assertFileNotExists("test_basic/CAPS");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test j arg - don't make directories */
+DEFINE_TEST(test_j)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -j %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents a\n", "a");
+ assertTextFileContents("contents b\n", "b");
+ assertTextFileContents("contents c\n", "c");
+ assertTextFileContents("contents CAPS\n", "CAPS");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test n arg - don't overrite existing files */
+DEFINE_TEST(test_n)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ assertMakeDir("test_basic", 0755);
+ assertMakeFile("test_basic/a", 0644, "orig a\n");
+ assertMakeFile("test_basic/b", 0644, "orig b\n");
+
+ extract_reference_file(reffile);
+ r = systemf("%s -n %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("orig a\n", "test_basic/a");
+ assertTextFileContents("orig b\n", "test_basic/b");
+ assertTextFileContents("contents c\n", "test_basic/c");
+ assertTextFileContents("contents CAPS\n", "test_basic/CAPS");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test non existant file */
+DEFINE_TEST(test_not_exist)
+{
+ int r;
+ r = systemf("%s nonexist.zip >test.out 2>test.err", testprog);
+ assert(r != 0);
+ assertEmptyFile("test.out");
+ assertNonEmptyFile("test.err");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test o arg - overrite existing files */
+DEFINE_TEST(test_o)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ assertMakeDir("test_basic", 0755);
+ assertMakeFile("test_basic/a", 0644, "orig a\n");
+ assertMakeFile("test_basic/b", 0644, "orig b\n");
+
+ extract_reference_file(reffile);
+ r = systemf("%s -o %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents a\n", "test_basic/a");
+ assertTextFileContents("contents b\n", "test_basic/b");
+ assertTextFileContents("contents c\n", "test_basic/c");
+ assertTextFileContents("contents CAPS\n", "test_basic/CAPS");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test p arg - Print to stdout */
+DEFINE_TEST(test_p)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -p %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertTextFileContents("contents a\ncontents b\ncontents c\ncontents CAPS\n", "test.out");
+ assertEmptyFile("test.err");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test q arg - Quiet */
+DEFINE_TEST(test_q)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -q %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents a\n", "test_basic/a");
+ assertTextFileContents("contents b\n", "test_basic/b");
+ assertTextFileContents("contents c\n", "test_basic/c");
+ assertTextFileContents("contents CAPS\n", "test_basic/CAPS");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Ensure single-file zips work */
+DEFINE_TEST(test_singlefile)
+{
+ const char *reffile = "test_singlefile.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("hello\n", "file.txt");
+}
--- /dev/null
+begin 644 test_singlefile.zip
+M4$L#!!0`"``(`&"6MU8```````````8````(`"``9FEL92YT>'155`T`!U1#
+M;6140VUD5$-M9'5X"P`!!.@#```$Z`,``,M(S<G)YP(`4$L'""`P.C8(````
+M!@```%!+`0(4`Q0`"``(`&"6MU8@,#HV"`````8````(`"````````````"D
+M@0````!F:6QE+G1X=%54#0`'5$-M9%1#;6140VUD=7@+``$$Z`,```3H`P``
+64$L%!@`````!``$`5@```%X`````````
+`
+end
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test t arg - Test zip contents */
+DEFINE_TEST(test_t)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -t %s >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test t arg - Test zip contents, but fail! */
+DEFINE_TEST(test_t_bad)
+{
+ const char *reffile = "test_t_bad.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s -t %s >test.out 2>test.err", testprog, reffile);
+ assert(r != 0);
+ assertNonEmptyFile("test.out");
+ assertNonEmptyFile("test.err");
+}
--- /dev/null
+begin 644 test_t_bad.zip
+M4$L#!!0``````,J0MU8````````````````+`"``=&5S=%]B87-I8R]55`T`
+M!]PX;63U.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+`P04``@`"``)C;=6````
+M```````+````#``@`'1E<W1?8F%S:6,O85546``'PS)M9/HY;603.&UD=7@+
+M``$$Z`,```3H`P``2\[/*TG-*RE62.0"`%!+!PAY:C`$#0````L```!02P,$
+M%&$(``@`#HVW5@``````````"P````P`(`!T97-T7V)A<VEC+V)55`T`!\TR
+M;63Z.6UD.SAM9'5X"P`!!.@#```$Z`,``$O.SRM)S2LI5DCB`@!02P<(NCD=
+M+PT````+````4$L#!!0`"``(`%*-MU8```````````L````,`"``=&5S=%]B
+M87-I8R]C550-``=,,VUDTSAM9,\X;61U>`L``03H`P``!.@#``!+SL\K2<TK
+M*59(Y@(`4$L'"/L(!C8-````"P```%!+`P04``@`"`#*D+=6```````````.
+M````#P`@`'1E<W1?8F%S:6,O0T%04U54#0`'W#AM9/HY;63<.&UD=7@+``$$
+MZ`,```3H`P``2\[/*TG-*RE6<'8,".8"`%!+!P@I4T'W$`````X```!02P$"
+M%`,4``````#*D+=6````````````````"P`@````````````[4(`````=&5S
+M=%]B87-I8R]55`T`!]PX;63U.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+`0(4
+M`Q0`"``(``F-MU9Y:C`$#0````L````,`"````````````"D@4D```!T97-T
+M7V)A<VEC+V%55`T`!\,R;63Z.6UD$SAM9'5X"P`!!.@#```$Z`,``%!+`0(4
+M`Q0`"``(``Z-MU:Z.1TO#0````L````,`"````````````"D@;````!T97-T
+M7V)A<VEC+V)55`T`!\TR;63Z.6UD.SAM9'5X"P`!!.@#```$Z`,``%!+`0(4
+M`Q0`"``(`%*-MU;["`8V#0````L````,`"````````````"D@1<!``!T97-T
+M7V)A<VEC+V-55`T`!TPS;633.&UDSSAM9'5X"P`!!.@#```$Z`,``%!+`0(4
+M`Q0`"``(`,J0MU8I4T'W$`````X````/`"````````````"D@7X!``!T97-T
+M7V)A<VEC+T-!4%-55`T`!]PX;63Z.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+
+5!08`````!0`%`,0!``#K`0`````*
+`
+end
--- /dev/null
+/*
+ * Copyright (c) 2023 Adrian Vovk
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "test.h"
+
+/* Test x arg - Exclude paths */
+DEFINE_TEST(test_x)
+{
+ const char *reffile = "test_basic.zip";
+ int r;
+
+ extract_reference_file(reffile);
+ r = systemf("%s %s -x test_basic/c >test.out 2>test.err", testprog, reffile);
+ assertEqualInt(0, r);
+ assertNonEmptyFile("test.out");
+ assertEmptyFile("test.err");
+
+ assertTextFileContents("contents a\n", "test_basic/a");
+ assertTextFileContents("contents b\n", "test_basic/b");
+ assertFileNotExists("test_basic/c");
+ assertTextFileContents("contents CAPS\n", "test_basic/CAPS");
+}