commit ce9e9e8012c8b61d5c8f5d58009b3b329b2aada4 Author: Martin Matuska Date: Mon Jul 31 13:54:58 2023 +0200 unzip: swtich to bsdunzip from libarchive Unzip from FreeBSD has been ported to libarchive. Change usr.bin/unzip to use bsdunzip from libarchive. diff --git a/contrib/libarchive/unzip/bsdunzip.h b/contrib/libarchive/unzip/bsdunzip.h index 12b65cefb466..3853178189c7 100644 --- a/contrib/libarchive/unzip/bsdunzip.h +++ b/contrib/libarchive/unzip/bsdunzip.h @@ -1,63 +1,65 @@ /*- * Copyright (c) 2023, Martin Matuska * 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. */ #ifndef BSDUNZIP_H_INCLUDED #define BSDUNZIP_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 #include #include struct bsdunzip { /* Option parser state */ int getopt_state; char *getopt_word; /* Miscellaneous state information */ int argc; char **argv; const char *argument; }; struct bsdunzip_getopt_ret { int index; int opt; }; enum { OPTION_NONE, OPTION_VERSION }; int bsdunzip_getopt(struct bsdunzip *); +extern int bsdunzip_optind; + #endif diff --git a/contrib/libarchive/unzip/cmdline.c b/contrib/libarchive/unzip/cmdline.c index 95d4f99b8242..76eb423de116 100644 --- a/contrib/libarchive/unzip/cmdline.c +++ b/contrib/libarchive/unzip/cmdline.c @@ -1,250 +1,248 @@ /*- * Copyright (c) 2003-2008 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. */ /* * Command line parser for bsdunzip. */ #include "bsdunzip_platform.h" __FBSDID("$FreeBSD$"); #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "bsdunzip.h" #include "err.h" -extern int bsdunzip_optind; - /* * Short options for bsdunzip. Please keep this sorted. */ static const char *short_options = "aCcd:fI:jLlnO:opP:qtuvx:yZ:"; /* * Long options for bsdunzip. Please keep this list sorted. * * The symbolic names for options that lack a short equivalent are * defined in bsdunzip.h. Also note that so far I've found no need * to support optional arguments to long options. That would be * a small change to the code below. */ static const struct bsdunzip_option { const char *name; int required; /* 1 if this option requires an argument. */ int equivalent; /* Equivalent short option. */ } bsdunzip_longopts[] = { { "version", 0, OPTION_VERSION }, { NULL, 0, 0 } }; /* * This getopt implementation has two key features that common * getopt_long() implementations lack. Apart from those, it's a * straightforward option parser, considerably simplified by not * needing to support the wealth of exotic getopt_long() features. It * has, of course, been shamelessly tailored for bsdunzip. (If you're * looking for a generic getopt_long() implementation for your * project, I recommend Gregory Pietsch's public domain getopt_long() * implementation.) The two additional features are: */ int bsdunzip_getopt(struct bsdunzip *bsdunzip) { enum { state_start = 0, state_next_word, state_short, state_long }; const struct bsdunzip_option *popt, *match = NULL, *match2 = NULL; const char *p, *long_prefix = "--"; size_t optlength; int opt = OPTION_NONE; int required = 0; bsdunzip->argument = NULL; /* First time through, initialize everything. */ if (bsdunzip->getopt_state == state_start) { /* Skip program name. */ ++bsdunzip->argv; --bsdunzip->argc; if (*bsdunzip->argv == NULL) return (-1); bsdunzip->getopt_state = state_next_word; } /* * We're ready to look at the next word in argv. */ if (bsdunzip->getopt_state == state_next_word) { /* No more arguments, so no more options. */ if (bsdunzip->argv[0] == NULL) return (-1); /* Doesn't start with '-', so no more options. */ if (bsdunzip->argv[0][0] != '-') return (-1); /* "--" marks end of options; consume it and return. */ if (strcmp(bsdunzip->argv[0], "--") == 0) { ++bsdunzip->argv; --bsdunzip->argc; return (-1); } /* Get next word for parsing. */ bsdunzip->getopt_word = *bsdunzip->argv++; --bsdunzip->argc; bsdunzip_optind++; if (bsdunzip->getopt_word[1] == '-') { /* Set up long option parser. */ bsdunzip->getopt_state = state_long; bsdunzip->getopt_word += 2; /* Skip leading '--' */ } else { /* Set up short option parser. */ bsdunzip->getopt_state = state_short; ++bsdunzip->getopt_word; /* Skip leading '-' */ } } /* * We're parsing a group of POSIX-style single-character options. */ if (bsdunzip->getopt_state == state_short) { /* Peel next option off of a group of short options. */ opt = *bsdunzip->getopt_word++; if (opt == '\0') { /* End of this group; recurse to get next option. */ bsdunzip->getopt_state = state_next_word; return bsdunzip_getopt(bsdunzip); } /* Does this option take an argument? */ p = strchr(short_options, opt); if (p == NULL) return ('?'); if (p[1] == ':') required = 1; /* If it takes an argument, parse that. */ if (required) { /* If arg is run-in, bsdunzip->getopt_word already points to it. */ if (bsdunzip->getopt_word[0] == '\0') { /* Otherwise, pick up the next word. */ bsdunzip->getopt_word = *bsdunzip->argv; if (bsdunzip->getopt_word == NULL) { lafe_warnc(0, "Option -%c requires an argument", opt); return ('?'); } ++bsdunzip->argv; --bsdunzip->argc; bsdunzip_optind++; } bsdunzip->getopt_state = state_next_word; bsdunzip->argument = bsdunzip->getopt_word; } } /* We're reading a long option */ if (bsdunzip->getopt_state == state_long) { /* After this long option, we'll be starting a new word. */ bsdunzip->getopt_state = state_next_word; /* Option name ends at '=' if there is one. */ p = strchr(bsdunzip->getopt_word, '='); if (p != NULL) { optlength = (size_t)(p - bsdunzip->getopt_word); bsdunzip->argument = (char *)(uintptr_t)(p + 1); } else { optlength = strlen(bsdunzip->getopt_word); } /* Search the table for an unambiguous match. */ for (popt = bsdunzip_longopts; popt->name != NULL; popt++) { /* Short-circuit if first chars don't match. */ if (popt->name[0] != bsdunzip->getopt_word[0]) continue; /* If option is a prefix of name in table, record it.*/ if (strncmp(bsdunzip->getopt_word, popt->name, optlength) == 0) { match2 = match; /* Record up to two matches. */ match = popt; /* If it's an exact match, we're done. */ if (strlen(popt->name) == optlength) { match2 = NULL; /* Forget the others. */ break; } } } /* Fail if there wasn't a unique match. */ if (match == NULL) { lafe_warnc(0, "Option %s%s is not supported", long_prefix, bsdunzip->getopt_word); return ('?'); } if (match2 != NULL) { lafe_warnc(0, "Ambiguous option %s%s (matches --%s and --%s)", long_prefix, bsdunzip->getopt_word, match->name, match2->name); return ('?'); } /* We've found a unique match; does it need an argument? */ if (match->required) { /* Argument required: get next word if necessary. */ if (bsdunzip->argument == NULL) { bsdunzip->argument = *bsdunzip->argv; if (bsdunzip->argument == NULL) { lafe_warnc(0, "Option %s%s requires an argument", long_prefix, match->name); return ('?'); } ++bsdunzip->argv; --bsdunzip->argc; bsdunzip_optind++; } } else { /* Argument forbidden: fail if there is one. */ if (bsdunzip->argument != NULL) { lafe_warnc(0, "Option %s%s does not allow an argument", long_prefix, match->name); return ('?'); } } return (match->equivalent); } return (opt); } diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 9312a6c2980b..943924c56bae 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -1,1184 +1,1186 @@ # $FreeBSD$ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 tags=package=tests . bin cat .. chflags .. chmod .. cp .. date .. dd .. echo .. expr .. ln .. ls .. mkdir .. mv .. pax .. pkill .. pwait .. rm .. rmdir .. sh builtins .. errors .. execution .. expansion .. invocation .. parameters .. parser .. set-e .. .. sleep .. test .. timeout .. .. cddl lib .. sbin .. usr.bin ctfconvert .. ztest .. .. usr.sbin dtrace common aggs .. arithmetic .. arrays .. assocs .. begin .. bitfields .. buffering .. builtinvar .. cg .. clauses .. cpc .. decls .. drops .. dtraceUtil .. end .. env .. enum .. error .. exit .. fbtprovider .. funcs .. grammar .. include .. inline .. io .. ip .. java_api .. json .. kinst .. lexer .. llquantize .. mdb .. mib .. misc .. multiaggs .. offsetof .. operators .. pid .. plockstat .. pointers .. pragma .. predicates .. preprocessor .. print .. printa .. printf .. privs .. probes .. proc .. profile-n .. providers .. raise .. rates .. safety .. scalars .. sched .. scripting .. sdt .. sizeof .. speculation .. stability .. stack .. stackdepth .. stop .. strlen .. strtoll .. struct .. sugar .. syscall .. sysevent .. tick-n .. trace .. tracemem .. translators .. typedef .. types .. uctf .. union .. usdt .. ustack .. vars .. version .. .. i386 arrays .. funcs .. pid .. ustack .. .. amd64 arrays .. .. .. zfsd .. .. .. etc rc.d .. .. examples .. games .. gnu lib .. usr.bin diff .. .. .. lib atf libatf-c detail .. .. libatf-c++ detail .. .. test-programs .. .. csu dynamic .. dynamiclib .. static .. .. googletest gmock .. gmock_main .. gtest .. gtest_main .. .. libarchive .. libbe .. libc c063 .. db .. gen execve .. posix_spawn .. .. hash data .. .. iconv .. inet .. locale .. net getaddrinfo data .. .. .. nss .. regex data .. .. resolv .. rpc .. ssp .. setjmp .. stdio .. stdlib .. string .. sys .. time .. tls dso .. .. termios .. ttyio .. .. libcam .. libcasper services cap_dns .. cap_grp .. cap_pwd .. cap_sysctl .. .. .. libcrypt .. libdevdctl .. libexecinfo .. libkvm .. libmp .. libnv .. libproc .. libregex data .. .. librt .. libsbuf .. libsysdecode .. libthr dlopen .. .. libutil .. libxo .. msun .. .. libexec atf atf-check .. atf-pytest-wrapper .. atf-sh .. .. rc .. rtld-elf .. tftpd .. .. sbin bectl .. dhclient .. devd .. growfs .. ifconfig .. ipfw .. md5 .. mdconfig .. newfs_msdos .. nvmecontrol .. pfctl files .. .. ping .. route .. sysctl .. .. secure lib .. libexec .. usr.bin .. usr.sbin .. .. share examples tests atf .. googletest .. plain .. tap .. .. .. zoneinfo .. .. sys acl .. aio .. audit .. auditpipe .. capsicum .. cddl zfs bin .. include .. tests acl cifs .. nontrivial .. trivial .. .. atime .. bootfs .. cache .. cachefile .. clean_mirror .. cli_root zfs_upgrade .. zfs_promote .. zfs_clone .. zfs_property .. zfs_destroy .. zpool_create .. zpool_history .. zpool_expand .. zpool_remove .. zfs_mount .. zfs_unshare .. zdb .. zpool_online .. zpool_get .. zpool_export .. zfs_copies .. zfs_get .. zfs .. zpool_clear .. zpool_import blockfiles .. .. zpool .. zpool_offline .. zpool_replace .. zfs_rollback .. zpool_set .. zfs_send .. zfs_set .. zpool_detach .. zfs_diff .. zpool_scrub .. zfs_inherit .. zfs_snapshot .. zfs_share .. zpool_destroy .. zpool_status .. zfs_unmount .. zfs_receive .. zfs_create .. zpool_upgrade blockfiles .. .. zpool_add .. zfs_rename .. zpool_attach .. zfs_reservation .. .. cli_user misc .. zfs_list .. zpool_iostat .. zpool_list .. .. compression .. ctime .. delegate .. devices .. exec .. grow_pool .. grow_replicas .. history .. hotplug .. hotspare .. inheritance .. interop .. inuse .. iscsi .. large_files .. largest_pool .. link_count .. migration .. mmap .. mount .. mv_files .. nestedfs .. no_space .. online_offline .. pool_names .. poolversion .. quota .. redundancy .. refquota .. refreserv .. rename_dirs .. replacement .. reservation .. rootpool .. rsend .. scrub_mirror .. slog .. snapshot .. snapused .. sparse .. threadsappend .. truncate .. txg_integrity .. userquota .. utils_test .. write_dirs .. xattr .. zfsd .. zil .. zinject .. zones .. zvol zvol_ENOSPC .. zvol_cli .. zvol_misc .. zvol_swap .. .. zvol_thrash .. .. .. .. compat32 .. devrandom .. dtrace .. fifo .. file .. fs fusefs .. tarfs .. tmpfs .. .. geom class concat .. eli .. gate .. gpt .. mirror .. multipath .. nop .. part .. raid3 .. shsec .. stripe .. uzip etalon .. .. .. .. kern acct .. execve .. pipe .. .. kqueue libkqueue .. .. mac bsdextended .. ipacl .. portacl .. .. mqueue .. net if_ovpn .. routing .. .. netgraph .. netinet .. netinet6 frag6 .. .. netipsec tunnel .. .. netlink .. netmap .. netpfil common .. ipfw .. pf ioctl .. .. .. opencrypto .. pjdfstest chflags .. chmod .. chown .. ftruncate .. granular .. link .. mkdir .. mkfifo .. mknod .. open .. rename .. rmdir .. symlink .. truncate .. unlink .. utimensat .. .. posixshm .. sys .. vfs .. vm .. vmm .. .. usr.bin apply .. asa .. awk bugs-fixed .. netbsd .. .. basename .. bintrans .. bmake archives fmt_44bsd .. fmt_44bsd_mod .. fmt_oldbsd .. .. basic t0 .. t1 .. t2 .. t3 .. .. execution ellipsis .. empty .. joberr .. plus .. .. shell builtin .. meta .. path .. path_select .. replace .. select .. .. suffixes basic .. src_wild1 .. src_wild2 .. .. syntax directive-t0 .. enl .. funny-targets .. semi .. .. sysmk t0 2 1 .. .. mk .. .. t1 2 1 .. .. mk .. .. t2 2 1 .. .. mk .. .. .. variables modifier_M .. modifier_t .. opt_V .. t0 .. .. .. bsdcat .. calendar .. cmp .. compress .. cpio .. col .. comm .. csplit .. cut .. dc .. diff .. diff3 .. dirname .. du .. factor .. file2c .. file .. find .. fold .. getconf .. gh-bc .. grep .. gzip .. head .. hexdump .. ident .. indent .. join .. jot .. lastcomm .. limits .. locale .. m4 .. mkimg .. mktemp .. ncal .. opensm .. patch .. pr .. printf .. procstat .. renice .. rs .. sdiff .. sed regress.multitest.out .. .. seq .. soelim .. sort .. split .. stat .. tail .. tar .. tftp .. tr .. truncate .. tsort .. units .. unifdef .. uniq .. + unzip + .. vmstat .. wc .. xargs .. xinstall .. xo .. yacc yacc .. .. .. usr.sbin chown .. daemon .. etcupdate .. extattr .. fstyp .. jail .. makefs .. mixer .. newsyslog .. nmtree .. praudit .. pw .. rpcbind .. sa .. .. .. # vim: set expandtab ts=4 sw=4: diff --git a/lib/libarchive/config_freebsd.h b/lib/libarchive/config_freebsd.h index 408bd1f12dbc..5211513610f3 100644 --- a/lib/libarchive/config_freebsd.h +++ b/lib/libarchive/config_freebsd.h @@ -1,267 +1,272 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * 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$ */ #define __LIBARCHIVE_CONFIG_H_INCLUDED 1 #include /* FreeBSD 5.0 and later has ACL and extattr support. */ #if __FreeBSD__ > 4 #define ARCHIVE_ACL_FREEBSD 1 #define ARCHIVE_XATTR_FREEBSD 1 #define HAVE_ACL_GET_PERM_NP 1 #define HAVE_ARC4RANDOM_BUF 1 #define HAVE_STRUCT_XVFSCONF 1 #define HAVE_SYS_ACL_H 1 #define HAVE_SYS_EXTATTR_H 1 #if __FreeBSD__ > 7 /* FreeBSD 8.0 and later has NFSv4 ACL support */ #define ARCHIVE_ACL_FREEBSD_NFS4 1 #define HAVE_ACL_GET_LINK_NP 1 #define HAVE_ACL_IS_TRIVIAL_NP 1 #define HAVE_ACL_SET_LINK_NP 1 #endif /* __FreeBSD__ > 7 */ #endif /* __FreeBSD__ > 4 */ #ifdef WITH_OPENSSL #define HAVE_LIBCRYPTO 1 #define HAVE_OPENSSL_EVP_H 1 #define HAVE_OPENSSL_MD5_H 1 #define HAVE_OPENSSL_RIPEMD_H 1 #define HAVE_OPENSSL_SHA_H 1 #define HAVE_OPENSSL_SHA256_INIT 1 #define HAVE_OPENSSL_SHA384_INIT 1 #define HAVE_OPENSSL_SHA512_INIT 1 #define HAVE_PKCS5_PBKDF2_HMAC_SHA1 1 #define HAVE_SHA256 1 #define HAVE_SHA384 1 #define HAVE_SHA512 1 #else #define HAVE_LIBMD 1 #define HAVE_MD5_H 1 #define HAVE_MD5INIT 1 #define HAVE_RIPEMD_H 1 #define HAVE_SHA_H 1 #define HAVE_SHA1 1 #define HAVE_SHA1_INIT 1 #define HAVE_SHA256 1 #define HAVE_SHA256_H 1 #define HAVE_SHA256_INIT 1 #define HAVE_SHA512 1 #define HAVE_SHA512_H 1 #define HAVE_SHA512_INIT 1 #endif #define HAVE_BSDXML_H 1 #define HAVE_BZLIB_H 1 #define HAVE_CHFLAGS 1 #define HAVE_CHOWN 1 #define HAVE_CHROOT 1 #define HAVE_CTIME_R 1 #define HAVE_CTYPE_H 1 #define HAVE_DECL_EXTATTR_NAMESPACE_USER 1 #define HAVE_DECL_INT32_MAX 1 #define HAVE_DECL_INT32_MIN 1 #define HAVE_DECL_INT64_MAX 1 #define HAVE_DECL_INT64_MIN 1 #define HAVE_DECL_INTMAX_MAX 1 #define HAVE_DECL_INTMAX_MIN 1 #define HAVE_DECL_SIZE_MAX 1 #define HAVE_DECL_SSIZE_MAX 1 #define HAVE_DECL_STRERROR_R 1 #define HAVE_DECL_UINT32_MAX 1 #define HAVE_DECL_UINT64_MAX 1 #define HAVE_DECL_UINTMAX_MAX 1 #define HAVE_DIRENT_H 1 #define HAVE_DIRFD 1 #define HAVE_DLFCN_H 1 #ifndef __linux__ #define HAVE_D_MD_ORDER 1 #endif #define HAVE_EFTYPE 1 #define HAVE_EILSEQ 1 #define HAVE_ERRNO_H 1 #define HAVE_FCHDIR 1 #define HAVE_FCHFLAGS 1 #define HAVE_FCHMOD 1 #define HAVE_FCHOWN 1 #define HAVE_FCNTL 1 #define HAVE_FCNTL_H 1 #define HAVE_FDOPENDIR 1 +#define HAVE_FNMATCH 1 +#define HAVE_FNMATCH_H 1 #define HAVE_FORK 1 #define HAVE_FSEEKO 1 #define HAVE_FSTAT 1 #define HAVE_FSTATAT 1 #define HAVE_FSTATFS 1 #define HAVE_FSTATVFS 1 #define HAVE_FTRUNCATE 1 #define HAVE_FUTIMES 1 #define HAVE_FUTIMESAT 1 #define HAVE_GETEUID 1 #define HAVE_GETGRGID_R 1 #define HAVE_GETGRNAM_R 1 +#define HAVE_GETLINE 1 +#define HAVE_GETOPT_OPTRESET 1 #define HAVE_GETPID 1 #define HAVE_GETPWNAM_R 1 #define HAVE_GETPWUID_R 1 #define HAVE_GETVFSBYNAME 1 #define HAVE_GMTIME_R 1 #define HAVE_GRP_H 1 #define HAVE_INTMAX_T 1 #define HAVE_INTTYPES_H 1 #define HAVE_LANGINFO_H 1 #define HAVE_LCHFLAGS 1 #define HAVE_LCHMOD 1 #define HAVE_LCHOWN 1 #define HAVE_LIBZ 1 #define HAVE_LIMITS_H 1 #define HAVE_LINK 1 #define HAVE_LINKAT 1 #define HAVE_LOCALE_H 1 #define HAVE_LOCALTIME_R 1 #define HAVE_LONG_LONG_INT 1 #define HAVE_LSTAT 1 #define HAVE_LUTIMES 1 #define HAVE_MBRTOWC 1 #define HAVE_MEMMOVE 1 #define HAVE_MEMORY_H 1 #define HAVE_MEMSET 1 #define HAVE_MKDIR 1 #define HAVE_MKFIFO 1 #define HAVE_MKNOD 1 #define HAVE_MKSTEMP 1 #define HAVE_NL_LANGINFO 1 #define HAVE_OPENAT 1 #define HAVE_PATHS_H 1 #define HAVE_PIPE 1 #define HAVE_POLL 1 #define HAVE_POLL_H 1 #define HAVE_POSIX_SPAWNP 1 #define HAVE_PTHREAD_H 1 #define HAVE_PWD_H 1 #define HAVE_READDIR_R 1 #define HAVE_READLINK 1 #define HAVE_READLINKAT 1 #ifndef __linux__ #define HAVE_READPASSPHRASE 1 #define HAVE_READPASSPHRASE_H 1 #endif #define HAVE_REGEX_H 1 #define HAVE_SELECT 1 #define HAVE_SETENV 1 #define HAVE_SETLOCALE 1 #define HAVE_SIGACTION 1 #define HAVE_SIGNAL_H 1 #define HAVE_SPAWN_H 1 #define HAVE_STATFS 1 #define HAVE_STATVFS 1 #define HAVE_STDARG_H 1 #define HAVE_STDINT_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRCHR 1 #define HAVE_STRDUP 1 #define HAVE_STRERROR 1 #define HAVE_STRERROR_R 1 #define HAVE_STRFTIME 1 #define HAVE_STRINGS_H 1 #define HAVE_STRING_H 1 #define HAVE_STRNLEN 1 #define HAVE_STRRCHR 1 #define HAVE_STRUCT_STATFS_F_NAMEMAX 1 #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 #define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 #define HAVE_STRUCT_STAT_ST_FLAGS 1 #define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 #define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 #define HAVE_STRUCT_TM_TM_GMTOFF 1 #define HAVE_SYMLINK 1 #define HAVE_SYS_CDEFS_H 1 #define HAVE_SYS_IOCTL_H 1 #define HAVE_SYS_MOUNT_H 1 #define HAVE_SYS_PARAM_H 1 #define HAVE_SYS_POLL_H 1 +#define HAVE_SYS_QUEUE_H 1 #define HAVE_SYS_SELECT_H 1 #define HAVE_SYS_STATVFS_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_UTSNAME_H 1 #define HAVE_SYS_WAIT_H 1 #define HAVE_TIMEGM 1 #define HAVE_TIME_H 1 #define HAVE_TZSET 1 #define HAVE_UINTMAX_T 1 #define HAVE_UNISTD_H 1 #define HAVE_UNLINKAT 1 #define HAVE_UNSETENV 1 #define HAVE_UNSIGNED_LONG_LONG 1 #define HAVE_UNSIGNED_LONG_LONG_INT 1 #define HAVE_UTIME 1 #define HAVE_UTIMES 1 #define HAVE_UTIME_H 1 #define HAVE_VFORK 1 #define HAVE_VPRINTF 1 #define HAVE_WCHAR_H 1 #define HAVE_WCHAR_T 1 #define HAVE_WCRTOMB 1 #define HAVE_WCSCMP 1 #define HAVE_WCSCPY 1 #define HAVE_WCSLEN 1 #define HAVE_WCTOMB 1 #define HAVE_WCTYPE_H 1 #define HAVE_WMEMCMP 1 #define HAVE_WMEMCPY 1 #define HAVE_WMEMMOVE 1 #define HAVE_ZLIB_H 1 #define TIME_WITH_SYS_TIME 1 #if __FreeBSD_version >= 1100056 #define HAVE_FUTIMENS 1 #define HAVE_UTIMENSAT 1 #endif /* FreeBSD 4 and earlier lack intmax_t/uintmax_t */ #if __FreeBSD__ < 5 #define intmax_t int64_t #define uintmax_t uint64_t #endif /* FreeBSD defines for archive_hash.h */ #ifdef WITH_OPENSSL #define ARCHIVE_CRYPTO_MD5_OPENSSL 1 #define ARCHIVE_CRYPTO_RMD160_OPENSSL 1 #define ARCHIVE_CRYPTO_SHA1_OPENSSL #define ARCHIVE_CRYPTO_SHA256_OPENSSL 1 #define ARCHIVE_CRYPTO_SHA384_OPENSSL 1 #define ARCHIVE_CRYPTO_SHA512_OPENSSL 1 #else #define ARCHIVE_CRYPTO_MD5_LIBMD 1 #define ARCHIVE_CRYPTO_SHA1_LIBMD 1 #define ARCHIVE_CRYPTO_SHA256_LIBMD 1 #define ARCHIVE_CRYPTO_SHA512_LIBMD 1 #endif diff --git a/usr.bin/unzip/Makefile b/usr.bin/unzip/Makefile index c1713e95222b..e0b5ac74246d 100644 --- a/usr.bin/unzip/Makefile +++ b/usr.bin/unzip/Makefile @@ -1,6 +1,32 @@ # $FreeBSD$ -PROG = unzip +.include + +_LIBARCHIVEDIR= ${SRCTOP}/contrib/libarchive +_LIBARCHIVECONFDIR= ${SRCTOP}/lib/libarchive + +PROG= bsdunzip + +BSDUNZIP_VERSION_STRING!= sed -n '/define.*ARCHIVE_VERSION_ONLY_STRING/{s,[^0-9.],,gp;q;}' \ + ${_LIBARCHIVEDIR}/libarchive/archive.h + +.PATH: ${_LIBARCHIVEDIR}/unzip +SRCS= bsdunzip.c + +.PATH: ${_LIBARCHIVEDIR}/libarchive_fe +SRCS+= cmdline.c err.c passphrase.c + +CFLAGS+= -DBSDUNZIP_VERSION_STRING=\"${BSDUNZIP_VERSION_STRING}\" +CFLAGS+= -DPLATFORM_CONFIG_H=\"${_LIBARCHIVECONFDIR}/config_freebsd.h\" +CFLAGS+= -I${_LIBARCHIVEDIR}/unzip -I${_LIBARCHIVEDIR}/libarchive_fe + LIBADD= archive +SYMLINKS=bsdunzip ${BINDIR}/unzip +MLINKS= bsdunzip.1 unzip.1 + +HAS_TESTS= +SUBDIR.${MK_TESTS}+= tests + .include +# DO NOT DELETE diff --git a/usr.bin/unzip/tests/Makefile b/usr.bin/unzip/tests/Makefile new file mode 100644 index 000000000000..577c0936a151 --- /dev/null +++ b/usr.bin/unzip/tests/Makefile @@ -0,0 +1,74 @@ +# $FreeBSD$ + +PACKAGE= tests + +_LIBARCHIVEDIR= ${SRCTOP}/contrib/libarchive + +ATF_TESTS_SH+= functional_test + +BINDIR= ${TESTSDIR} + +PROGS+= bsdunzip_test + +CFLAGS+= -DPLATFORM_CONFIG_H=\"${SRCTOP}/lib/libarchive/config_freebsd.h\" +CFLAGS+= -I${SRCTOP}/lib/libarchive -I${.OBJDIR} + +CFLAGS+= -I${.OBJDIR} +CFLAGS+= -I${_LIBARCHIVEDIR}/unzip -I${_LIBARCHIVEDIR}/unzip/test +CFLAGS+= -I${_LIBARCHIVEDIR}/libarchive +CFLAGS+= -I${_LIBARCHIVEDIR}/libarchive_fe -I${_LIBARCHIVEDIR}/test_utils + +# Uncomment to link against dmalloc +#LDADD+= -L/usr/local/lib -ldmalloc +#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC + +CFLAGS.test_utils.c+= -Wno-cast-align + +.PATH: ${_LIBARCHIVEDIR}/libarchive_fe +UNZIP_SRCS+= err.c + +.PATH: ${_LIBARCHIVEDIR}/unzip/test +TESTS_SRCS= \ + test_0.c \ + test_C.c \ + test_L.c \ + test_P_encryption.c \ + test_Z1.c \ + test_basic.c \ + test_d.c \ + test_glob.c \ + test_j.c \ + test_n.c \ + test_not_exist.c \ + test_o.c \ + test_p.c \ + test_q.c \ + test_singlefile.c \ + test_t.c \ + test_t_bad.c \ + test_version.c \ + test_x.c + +SRCS.bsdunzip_test= list.h \ + ${UNZIP_SRCS} \ + ${TESTS_SRCS} + +.PATH: ${_LIBARCHIVEDIR}/test_utils +SRCS.bsdunzip_test+= test_main.c \ + test_utils.c + +LIBADD.bsdunzip_test= archive + +list.h: ${TESTS_SRCS} Makefile + @(cd ${_LIBARCHIVEDIR}/unzip/test && \ + grep -h DEFINE_TEST ${.ALLSRC:N*Makefile}) > ${.TARGET}.tmp + @mv ${.TARGET}.tmp ${.TARGET} + +CLEANFILES+= list.h list.h.tmp + +${PACKAGE}FILES+= test_basic.zip.uu +${PACKAGE}FILES+= test_encrypted.zip.uu +${PACKAGE}FILES+= test_singlefile.zip.uu +${PACKAGE}FILES+= test_t_bad.zip.uu + +.include diff --git a/usr.bin/unzip/tests/Makefile.depend b/usr.bin/unzip/tests/Makefile.depend new file mode 100644 index 000000000000..138ae4120671 --- /dev/null +++ b/usr.bin/unzip/tests/Makefile.depend @@ -0,0 +1,24 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libarchive \ + lib/libbz2 \ + lib/libc \ + lib/libcompiler_rt \ + lib/libexpat \ + lib/liblzma \ + lib/libthr \ + lib/libz \ + secure/lib/libcrypto \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.bin/unzip/tests/functional_test.sh b/usr.bin/unzip/tests/functional_test.sh new file mode 100755 index 000000000000..1b39e057d538 --- /dev/null +++ b/usr.bin/unzip/tests/functional_test.sh @@ -0,0 +1,56 @@ +# +# Copyright 2015 EMC Corp. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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 COPYRIGHT HOLDERS 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 COPYRIGHT +# OWNER 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$ + +SRCDIR=$(atf_get_srcdir) +TESTER="${SRCDIR}/bsdunzip_test" +export BSDUNZIP=$(which bsdunzip) + +check() +{ + local testcase=${1}; shift + + # For some odd reason /bin/sh spuriously writes + # "write error on stdout" with some of the testcases + # + # Probably an issue with how they're written as it calls system(3) to + # clean up directories.. + atf_check -e ignore -o ignore -s exit:0 ${TESTER} -d -r "${SRCDIR}" -v "${testcase}" +} + +atf_init_test_cases() +{ + # Redirect stderr to stdout for the usage message because if you don't + # kyua list/kyua test will break: + # https://github.com/jmmv/kyua/issues/149 + testcases=$(${TESTER} -h 2>&1 | awk 'p != 0 && $1 ~ /^[0-9]+:/ { print $NF } /Available tests:/ { p=1 }') + for testcase in ${testcases}; do + atf_test_case ${testcase} + eval "${testcase}_body() { check ${testcase}; }" + atf_add_test_case ${testcase} + done +} diff --git a/usr.bin/unzip/unzip.1 b/usr.bin/unzip/unzip.1 deleted file mode 100644 index fd826fbe1c05..000000000000 --- a/usr.bin/unzip/unzip.1 +++ /dev/null @@ -1,207 +0,0 @@ -.\"- -.\" 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 June 27, 2023 -.Dt UNZIP 1 -.Os -.Sh NAME -.Nm unzip -.Nd extract files from a ZIP archive -.Sh SYNOPSIS -.Nm -.Op Fl aCcfjLlnopqtuvy -.Op { Fl O | Fl I No } Ar encoding -.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 I Ar encoding -.It Fl O Ar encoding -Convert filenames from the specified encoding. -.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 . diff --git a/usr.bin/unzip/unzip.c b/usr.bin/unzip/unzip.c deleted file mode 100644 index 1200aa53e7e3..000000000000 --- a/usr.bin/unzip/unzip.c +++ /dev/null @@ -1,1141 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2009, 2010 Joerg Sonnenberger - * 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* 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 char *O_arg; /* encoding */ -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 = readpassphrase("\nEnter password: ", passphrase_buf, - PPBUFF_SIZE, RPP_ECHO_OFF); - - 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 (O_arg) - ac(archive_read_set_format_option(a, "zip", "hdrcharset", O_arg)); - - 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_s(passphrase_buf, PPBUFF_SIZE, 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] [{-O|-I} encoding] [-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:fI:jLlnO:opP: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 'I': - case 'O': - O_arg = optarg; - 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); -}