Browse Source

add a cpio implementation to tools directory

cpio utility is a mess in point of portability.
For example NetBSD cpio implementation does not support
userid and groupid changes for the archive. This
feature is required for initramfs filesystem targets.
This cpio is from the Heirloom project.

Fix needed rebuild of tools, when changing targets.
Waldemar Brodkorb 14 years ago
parent
commit
fd6481d82f
72 changed files with 18300 additions and 62 deletions
  1. 9 6
      mk/image.mk
  2. 1 4
      mk/tools.mk
  3. 0 29
      scripts/cpio
  4. 1 2
      tools/Makefile
  5. 33 0
      tools/cpio/Makefile
  6. 27 0
      tools/cpio/src/_alloca.h
  7. 26 0
      tools/cpio/src/_malloc.h
  8. 89 0
      tools/cpio/src/_utmpx.h
  9. 59 0
      tools/cpio/src/asciitype.c
  10. 60 0
      tools/cpio/src/asciitype.h
  11. 8 0
      tools/cpio/src/atoll.h
  12. 38 0
      tools/cpio/src/blank.h
  13. 449 0
      tools/cpio/src/blast.c
  14. 76 0
      tools/cpio/src/blast.h
  15. 943 0
      tools/cpio/src/cpio.1
  16. 7185 0
      tools/cpio/src/cpio.c
  17. 232 0
      tools/cpio/src/cpio.h
  18. 115 0
      tools/cpio/src/crc32.c
  19. 193 0
      tools/cpio/src/expand.c
  20. 1138 0
      tools/cpio/src/explode.c
  21. 257 0
      tools/cpio/src/flags.c
  22. 197 0
      tools/cpio/src/getdir.c
  23. 33 0
      tools/cpio/src/getdir.h
  24. 141 0
      tools/cpio/src/getopt.c
  25. 136 0
      tools/cpio/src/gmatch.c
  26. 61 0
      tools/cpio/src/ib_alloc.c
  27. 36 0
      tools/cpio/src/ib_close.c
  28. 33 0
      tools/cpio/src/ib_free.c
  29. 78 0
      tools/cpio/src/ib_getlin.c
  30. 81 0
      tools/cpio/src/ib_getw.c
  31. 48 0
      tools/cpio/src/ib_open.c
  32. 87 0
      tools/cpio/src/ib_popen.c
  33. 51 0
      tools/cpio/src/ib_read.c
  34. 53 0
      tools/cpio/src/ib_seek.c
  35. 135 0
      tools/cpio/src/iblok.h
  36. 991 0
      tools/cpio/src/inflate.c
  37. 22 0
      tools/cpio/src/mbtowi.h
  38. 51 0
      tools/cpio/src/memalign.c
  39. 35 0
      tools/cpio/src/memalign.h
  40. 30 0
      tools/cpio/src/msgselect.h
  41. 55 0
      tools/cpio/src/nonpax.c
  42. 260 0
      tools/cpio/src/oblok.c
  43. 96 0
      tools/cpio/src/oblok.h
  44. 51 0
      tools/cpio/src/pathconf.c
  45. 29 0
      tools/cpio/src/pathconf.h
  46. 919 0
      tools/cpio/src/pax.1
  47. 757 0
      tools/cpio/src/pax.c
  48. 39 0
      tools/cpio/src/pfmt.c
  49. 46 0
      tools/cpio/src/pfmt.h
  50. 1 0
      tools/cpio/src/pfmt_label.c
  51. 1211 0
      tools/cpio/src/regexp.h
  52. 90 0
      tools/cpio/src/regexpr.c
  53. 53 0
      tools/cpio/src/regexpr.h
  54. 40 0
      tools/cpio/src/setlabel.c
  55. 47 0
      tools/cpio/src/setuxlabel.c
  56. 99 0
      tools/cpio/src/sfile.c
  57. 40 0
      tools/cpio/src/sfile.h
  58. 41 0
      tools/cpio/src/sighold.c
  59. 45 0
      tools/cpio/src/sigignore.c
  60. 45 0
      tools/cpio/src/signal.c
  61. 48 0
      tools/cpio/src/sigpause.c
  62. 41 0
      tools/cpio/src/sigrelse.c
  63. 55 0
      tools/cpio/src/sigset.c
  64. 38 0
      tools/cpio/src/sigset.h
  65. 117 0
      tools/cpio/src/strtol.c
  66. 307 0
      tools/cpio/src/unshrink.c
  67. 121 0
      tools/cpio/src/unzip.h
  68. 252 0
      tools/cpio/src/utmpx.c
  69. 26 0
      tools/cpio/src/version.c
  70. 90 0
      tools/cpio/src/vpfmt.c
  71. 3 14
      tools/mkcrypt/Makefile
  72. 0 7
      tools/rules.mk

+ 9 - 6
mk/image.mk

@@ -49,18 +49,21 @@ ${BIN_DIR}/${ROOTFSUSERTARBALL}: ${TARGET_DIR}
 		| gzip -n9 >$@
 
 ${BIN_DIR}/${INITRAMFS}: ${TARGET_DIR}
-	cd ${TARGET_DIR}; find . | sed -n '/^\.\//s///p' | sort | \
-	    cpio -o r -C512 -Hnewc | ${ADK_COMPRESSION_TOOL} >$@
+	cd ${TARGET_DIR}; find . | sed -n '/^\.\//s///p' | \
+		sed "s#\(.*\)#:0:0::::::\1#" | sort | \
+	    ${STAGING_TOOLS}/bin/cpio -o -C512 -Hnewc -P | \
+		${ADK_COMPRESSION_TOOL} >$@ 2>/dev/null
 
 ${BUILD_DIR}/${INITRAMFS_PIGGYBACK}: ${TARGET_DIR}
 	$(SED) 's#^CONFIG_INITRAMFS_SOURCE.*#CONFIG_INITRAMFS_SOURCE="${BUILD_DIR}/${INITRAMFS_PIGGYBACK}"#' \
 		$(LINUX_DIR)/.config
-	cd ${TARGET_DIR}; find . | sed -n '/^\.\//s///p' | sort | \
-	    cpio -o r -C512 -Hnewc >$@
+	cd ${TARGET_DIR}; find . | sed -n '/^\.\//s///p' | \
+		sed "s#\(.*\)#:0:0::::::\1#" | sort | \
+	    ${STAGING_TOOLS}/bin/cpio -o -C512 -Hnewc -P >$@ 2>/dev/null
 
 ${BIN_DIR}/${ROOTFSSQUASHFS}: ${TARGET_DIR}
-	PATH='${TARGET_PATH}' \
-	mksquashfs ${TARGET_DIR} ${BUILD_DIR}/root.squashfs \
+	${STAGING_TOOLS}/bin/mksquashfs ${TARGET_DIR} \
+		${BUILD_DIR}/root.squashfs \
 		-nopad -noappend -root-owned $(MAKE_TRACE)
 	cat ${BIN_DIR}/${ADK_TARGET}-${FS}-kernel \
 		${BUILD_DIR}/root.squashfs > \

+ 1 - 4
mk/tools.mk

@@ -1,6 +1,3 @@
-prepare: ${WRKDIST}/.prepared
-configure: ${WRKBUILD}/.configure_done
-compile: $(WRKBUILD)/.compiled
-install: $(WRKBUILD)/.installed
+compile:
 clean:
 	rm -rf $(WRKDIR)

+ 0 - 29
scripts/cpio

@@ -1,29 +0,0 @@
-#!/usr/bin/env bash
-# This file is part of the OpenADK project. OpenADK is copyrighted
-# material, please see the LICENCE file in the top-level directory.
-
-opt=
-user="-R 0:0"
-os=$(uname)
-case $os in
-	NetBSD|MirBSD|OpenBSD)
-		cmd="$@"
-		;;
-	FreeBSD|Darwin)
-		user="-R root:"
-		cmd=$(echo "$@"|sed -e "s#-Hnewc#--format newc#")
-		cmd="--quiet $cmd"
-		;;
-	*)
-		cmd="--quiet $@"
-		;;
-esac
-if [ "$2" = "r" ];then
-	opt="$user"
-fi
-cmd=$(echo "$cmd"|sed -e "s# r # #")
-if [ -x /usr/bin/cpio ];then
-	/usr/bin/cpio $opt $cmd
-else
-	/bin/cpio $opt $cmd
-fi

+ 1 - 2
tools/Makefile

@@ -3,12 +3,11 @@
 
 include $(TOPDIR)/rules.mk
 
-TARGETS:=mkcrypt
+TARGETS:=mkcrypt cpio
 TARGETS_INSTALL:=$(patsubst %,%-install,$(TARGETS))
 TARGETS_CLEAN:=$(patsubst %,%-clean,$(TARGETS))
 
 all: install
-prepare:
 compile:
 install: $(TARGETS_INSTALL)
 clean: $(TARGETS_CLEAN)

+ 33 - 0
tools/cpio/Makefile

@@ -0,0 +1,33 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include $(TOPDIR)/rules.mk
+
+SRCS+=		\
+		src/ib_open.c \
+		src/ib_close.c \
+		src/ib_read.c \
+		src/ib_alloc.c \
+		src/ib_free.c \
+		src/ib_getlin.c \
+		src/sfile.c \
+		src/gmatch.c
+
+SRCS+=		\
+		src/version.c \
+		src/blast.c \
+		src/crc32.c \
+		src/expand.c \
+		src/explode.c \
+		src/flags.c \
+		src/inflate.c \
+		src/unshrink.c \
+		src/nonpax.c \
+		src/cpio.c
+
+${STAGING_TOOLS}/bin/cpio: ${SRCS}
+	${HOSTCC} ${HOSTCFLAGS} -D_GNU_SOURCE -Isrc -o $@ $^
+
+install: ${STAGING_TOOLS}/bin/cpio
+
+include $(TOPDIR)/mk/tools.mk

+ 27 - 0
tools/cpio/src/_alloca.h

@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)_alloca.h	1.5 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \
+	defined (__DragonFly__) || defined (__APPLE__)
+#include <stdlib.h>
+#endif	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */

+ 26 - 0
tools/cpio/src/_malloc.h

@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)_malloc.h	1.2 (gritter) 5/1/04	*/
+
+#include	<stdlib.h>
+
+extern void	*memalign(size_t, size_t);

+ 89 - 0
tools/cpio/src/_utmpx.h

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)_utmpx.h	1.9 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__UCLIBC__) || defined (__OpenBSD__) || \
+	defined (__DragonFly__) || defined (__APPLE__)
+#include <sys/types.h>
+#include <sys/time.h>
+#include <utmp.h>
+
+#ifndef	__dietlibc__
+struct utmpx {
+	char	ut_user[UT_NAMESIZE];
+	char	ut_id[UT_LINESIZE];
+	char	ut_line[UT_LINESIZE];
+	char	ut_host[UT_HOSTSIZE];
+	pid_t	ut_pid;
+	short	ut_type;
+	struct timeval	ut_tv;
+	struct {
+		int	e_termination;
+		int	e_exit;
+	} ut_exit;
+};
+
+#ifndef EMPTY
+#define	EMPTY		0
+#endif
+#ifndef BOOT_TIME
+#define	BOOT_TIME	1
+#endif
+#ifndef OLD_TIME
+#define	OLD_TIME	2
+#endif
+#ifndef NEW_TIME
+#define	NEW_TIME	3
+#endif
+#ifndef USER_PROCESS
+#define	USER_PROCESS	4
+#endif
+#ifndef INIT_PROCESS
+#define	INIT_PROCESS	5
+#endif
+#ifndef LOGIN_PROCESS
+#define	LOGIN_PROCESS	6
+#endif
+#ifndef DEAD_PROCESS
+#define	DEAD_PROCESS	7
+#endif
+#ifndef RUN_LVL
+#define	RUN_LVL		8
+#endif
+#ifndef ACCOUNTING
+#define	ACCOUNTING	9
+#endif
+#else	/* __dietlibc__ */
+#define	utmpx	utmp
+#endif	/* __dietlibc__ */
+
+extern void		endutxent(void);
+extern struct utmpx	*getutxent(void);
+extern struct utmpx	*getutxid(const struct utmpx *);
+extern struct utmpx	*getutxline(const struct utmpx *);
+extern struct utmpx	*pututxline(const struct utmpx *);
+extern void		setutxent(void);
+extern int		utmpxname(const char *);
+extern void		updwtmpx(const char *, const struct utmpx *);
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __UCLIBC__ ||
+	 	__OpenBSD__ || __DragonFly__ || __APPLE__ */

+ 59 - 0
tools/cpio/src/asciitype.c

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)asciitype.c	1.4 (gritter) 4/17/03	*/
+
+#include "asciitype.h"
+
+const unsigned char class_char[] = {
+/*	000 nul	001 soh	002 stx	003 etx	004 eot	005 enq	006 ack	007 bel	*/
+	C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
+/*	010 bs 	011 ht 	012 nl 	013 vt 	014 np 	015 cr 	016 so 	017 si 	*/
+	C_CNTRL,C_BLANK,C_WHITE,C_SPACE,C_SPACE,C_SPACE,C_CNTRL,C_CNTRL,
+/*	020 dle	021 dc1	022 dc2	023 dc3	024 dc4	025 nak	026 syn	027 etb	*/
+	C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
+/*	030 can	031 em 	032 sub	033 esc	034 fs 	035 gs 	036 rs 	037 us 	*/
+	C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
+/*	040 sp 	041  ! 	042  " 	043  # 	044  $ 	045  % 	046  & 	047  ' 	*/
+	C_BLANK,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
+/*	050  ( 	051  ) 	052  * 	053  + 	054  , 	055  - 	056  . 	057  / 	*/
+	C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
+/*	060  0 	061  1 	062  2 	063  3 	064  4 	065  5 	066  6 	067  7 	*/
+	C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,
+/*	070  8 	071  9 	072  : 	073  ; 	074  < 	075  = 	076  > 	077  ? 	*/
+	C_DIGIT,C_DIGIT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
+/*	100  @ 	101  A 	102  B 	103  C 	104  D 	105  E 	106  F 	107  G 	*/
+	C_PUNCT,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
+/*	110  H 	111  I 	112  J 	113  K 	114  L 	115  M 	116  N 	117  O 	*/
+	C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
+/*	120  P 	121  Q 	122  R 	123  S 	124  T 	125  U 	126  V 	127  W 	*/
+	C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
+/*	130  X 	131  Y 	132  Z 	133  [ 	134  \ 	135  ] 	136  ^ 	137  _ 	*/
+	C_UPPER,C_UPPER,C_UPPER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
+/*	140  ` 	141  a 	142  b 	143  c 	144  d 	145  e 	146  f 	147  g 	*/
+	C_PUNCT,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
+/*	150  h 	151  i 	152  j 	153  k 	154  l 	155  m 	156  n 	157  o 	*/
+	C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
+/*	160  p 	161  q 	162  r 	163  s 	164  t 	165  u 	166  v 	167  w 	*/
+	C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
+/*	170  x 	171  y 	172  z 	173  { 	174  | 	175  } 	176  ~ 	177 del	*/
+	C_LOWER,C_LOWER,C_LOWER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_CNTRL
+};

+ 60 - 0
tools/cpio/src/asciitype.h

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)asciitype.h	1.6 (gritter) 9/9/05	*/
+
+/*
+ * Locale-independent character classes.
+ */
+enum {
+	C_CNTRL	= 0000,
+	C_BLANK	= 0001,
+	C_WHITE = 0002,
+	C_SPACE	= 0004,
+	C_PUNCT	= 0010,
+	C_OCTAL	= 0020,
+	C_DIGIT	= 0040,
+	C_UPPER	= 0100,
+	C_LOWER	= 0200
+};
+
+extern const unsigned char	class_char[];
+
+#define	asciichar(c) ((unsigned)(c) <= 0177)
+#define	alnumchar(c) (asciichar(c)&&(class_char[c]&\
+			(C_DIGIT|C_OCTAL|C_UPPER|C_LOWER)))
+#define	alphachar(c) (asciichar(c)&&(class_char[c]&(C_UPPER|C_LOWER)))
+#define	blankchar(c) (asciichar(c)&&(class_char[c]&(C_BLANK)))
+#define	cntrlchar(c) (asciichar(c)&&(class_char[c]==C_CNTRL)
+#define	digitchar(c) (asciichar(c)&&(class_char[c]&(C_DIGIT|C_OCTAL)))
+#define	lowerchar(c) (asciichar(c)&&(class_char[c]&(C_LOWER)))
+#define	punctchar(c) (asciichar(c)&&(class_char[c]&(C_PUNCT)))
+#define	spacechar(c) (asciichar(c)&&(class_char[c]&(C_BLANK|C_SPACE|C_WHITE)))
+#define	upperchar(c) (asciichar(c)&&(class_char[c]&(C_UPPER)))
+#define	whitechar(c) (asciichar(c)&&(class_char[c]&(C_BLANK|C_WHITE)))
+#define	octalchar(c) (asciichar(c)&&(class_char[c]&(C_OCTAL)))
+#define	graphchar(c) (asciichar(c)&&(class_char[c]&\
+			(C_UPPER|C_LOWER|C_DIGIT|C_OCTAL|C_PUNCT)))
+#define	printchar(c) ((c)==' ' || asciichar(c)&&(class_char[c]&\
+			(C_UPPER|C_LOWER|C_DIGIT|C_OCTAL|C_PUNCT)))
+
+#define	upperconv(c) (lowerchar(c) ? (c)-'a'+'A' : (c))
+#define	lowerconv(c) (upperchar(c) ? (c)-'A'+'a' : (c))

+ 8 - 0
tools/cpio/src/atoll.h

@@ -0,0 +1,8 @@
+/*	Sccsid @(#)atoll.h	1.4 (gritter) 7/18/04	*/
+
+#if defined (__hpux) || defined (_AIX) || \
+	defined (__FreeBSD__) && (__FreeBSD__) < 5
+extern long long strtoll(const char *nptr, char **endptr, int base);
+extern unsigned long long strtoull(const char *nptr, char **endptr, int base);
+extern long long atoll(const char *nptr);
+#endif	/* __hpux || _AIX || __FreeBSD__ < 5 */

+ 38 - 0
tools/cpio/src/blank.h

@@ -0,0 +1,38 @@
+/*
+ * isblank() and iswblank() are not available with many pre-XSH6
+ * systems. Check whether isblank was defined, and assume it is
+ * not available if not.
+ */
+/*	Sccsid @(#)blank.h	1.3 (gritter) 5/1/04	*/
+
+#ifndef	__dietlibc__
+#ifndef	LIBCOMMON_BLANK_H
+#define	LIBCOMMON_BLANK_H	1
+
+#include <ctype.h>
+#include <wctype.h>
+
+#ifndef	isblank
+
+static
+#ifdef	__GNUC__
+__inline__
+#endif	/* __GNUC__ */
+int
+my_isblank(int c)
+{
+	return c == ' ' || c == '\t';
+}
+#define	isblank(c)	my_isblank(c)
+
+static int
+my_iswblank(wint_t c)
+{
+	return c == L' ' || c == L'\t';
+}
+#undef	iswblank
+#define	iswblank(c)	my_iswblank(c)
+
+#endif	/* !isblank */
+#endif	/* !LIBCOMMON_BLANK_H */
+#endif	/* !__dietlibc__ */

+ 449 - 0
tools/cpio/src/blast.c

@@ -0,0 +1,449 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, February 2004.
+ *
+ * Sccsid @(#)blast.c	1.2 (gritter) 2/17/04
+ */
+/* blast.c
+ * Copyright (C) 2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in blast.h
+ * version 1.1, 16 Feb 2003
+ *
+ * blast.c decompresses data compressed by the PKWare Compression Library.
+ * This function provides functionality similar to the explode() function of
+ * the PKWare library, hence the name "blast".
+ *
+ * This decompressor is based on the excellent format description provided by
+ * Ben Rudiak-Gould in comp.compression on August 13, 2001.  Interestingly, the
+ * example Ben provided in the post is incorrect.  The distance 110001 should
+ * instead be 111000.  When corrected, the example byte stream becomes:
+ *
+ *    00 04 82 24 25 8f 80 7f
+ *
+ * which decompresses to "AIAIAIAIAIAIA" (without the quotes).
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0  12 Feb 2003     - First version
+ * 1.1  16 Feb 2003     - Fixed distance check for > 4 GB uncompressed data
+ */
+
+#include <setjmp.h>             /* for setjmp(), longjmp(), and jmp_buf */
+#include "blast.h"              /* prototype for blast() */
+
+#define local static            /* for local function definitions */
+#define MAXBITS 13              /* maximum code length */
+#define MAXWIN 4096             /* maximum window size */
+
+/* input and output state */
+struct state {
+    /* input state */
+    blast_in infun;             /* input function provided by user */
+    void *inhow;                /* opaque information passed to infun() */
+    unsigned char *in;          /* next input location */
+    unsigned left;              /* available input at in */
+    int bitbuf;                 /* bit buffer */
+    int bitcnt;                 /* number of bits in bit buffer */
+
+    /* input limit error return state for bits() and decode() */
+    jmp_buf env;
+
+    /* output state */
+    blast_out outfun;           /* output function provided by user */
+    void *outhow;               /* opaque information passed to outfun() */
+    unsigned next;              /* index of next write location in out[] */
+    int first;                  /* true to check distances (for first 4K) */
+    unsigned char out[MAXWIN];  /* output buffer and sliding window */
+};
+
+/*
+ * Return need bits from the input stream.  This always leaves less than
+ * eight bits in the buffer.  bits() works properly for need == 0.
+ *
+ * Format notes:
+ *
+ * - Bits are stored in bytes from the least significant bit to the most
+ *   significant bit.  Therefore bits are dropped from the bottom of the bit
+ *   buffer, using shift right, and new bytes are appended to the top of the
+ *   bit buffer, using shift left.
+ */
+local int bits(struct state *s, int need)
+{
+    int val;            /* bit accumulator */
+
+    /* load at least need bits into val */
+    val = s->bitbuf;
+    while (s->bitcnt < need) {
+        if (s->left == 0) {
+            s->left = s->infun(s->inhow, &(s->in));
+            if (s->left == 0) longjmp(s->env, 1);       /* out of input */
+        }
+        val |= (int)(*(s->in)++) << s->bitcnt;          /* load eight bits */
+        s->left--;
+        s->bitcnt += 8;
+    }
+
+    /* drop need bits and update buffer, always zero to seven bits left */
+    s->bitbuf = val >> need;
+    s->bitcnt -= need;
+
+    /* return need bits, zeroing the bits above that */
+    return val & ((1 << need) - 1);
+}
+
+/*
+ * Huffman code decoding tables.  count[1..MAXBITS] is the number of symbols of
+ * each length, which for a canonical code are stepped through in order.
+ * symbol[] are the symbol values in canonical order, where the number of
+ * entries is the sum of the counts in count[].  The decoding process can be
+ * seen in the function decode() below.
+ */
+struct huffman {
+    short *count;       /* number of symbols of each length */
+    short *symbol;      /* canonically ordered symbols */
+};
+
+/*
+ * Decode a code from the stream s using huffman table h.  Return the symbol or
+ * a negative value if there is an error.  If all of the lengths are zero, i.e.
+ * an empty code, or if the code is incomplete and an invalid code is received,
+ * then -9 is returned after reading MAXBITS bits.
+ *
+ * Format notes:
+ *
+ * - The codes as stored in the compressed data are bit-reversed relative to
+ *   a simple integer ordering of codes of the same lengths.  Hence below the
+ *   bits are pulled from the compressed data one at a time and used to
+ *   build the code value reversed from what is in the stream in order to
+ *   permit simple integer comparisons for decoding.
+ *
+ * - The first code for the shortest length is all ones.  Subsequent codes of
+ *   the same length are simply integer decrements of the previous code.  When
+ *   moving up a length, a one bit is appended to the code.  For a complete
+ *   code, the last code of the longest length will be all zeros.  To support
+ *   this ordering, the bits pulled during decoding are inverted to apply the
+ *   more "natural" ordering starting with all zeros and incrementing.
+ */
+local int decode(struct state *s, struct huffman *h)
+{
+    int len;            /* current number of bits in code */
+    int code;           /* len bits being decoded */
+    int first;          /* first code of length len */
+    int count;          /* number of codes of length len */
+    int index;          /* index of first code of length len in symbol table */
+    int bitbuf;         /* bits from stream */
+    int left;           /* bits left in next or left to process */
+    short *next;        /* next number of codes */
+
+    bitbuf = s->bitbuf;
+    left = s->bitcnt;
+    code = first = index = 0;
+    len = 1;
+    next = h->count + 1;
+    while (1) {
+        while (left--) {
+            code |= (bitbuf & 1) ^ 1;   /* invert code */
+            bitbuf >>= 1;
+            count = *next++;
+            if (code < first + count) { /* if length len, return symbol */
+                s->bitbuf = bitbuf;
+                s->bitcnt = (s->bitcnt - len) & 7;
+                return h->symbol[index + (code - first)];
+            }
+            index += count;             /* else update for next length */
+            first += count;
+            first <<= 1;
+            code <<= 1;
+            len++;
+        }
+        left = (MAXBITS+1) - len;
+        if (left == 0) break;
+        if (s->left == 0) {
+            s->left = s->infun(s->inhow, &(s->in));
+            if (s->left == 0) longjmp(s->env, 1);       /* out of input */
+        }
+        bitbuf = *(s->in)++;
+        s->left--;
+        if (left > 8) left = 8;
+    }
+    return -9;                          /* ran out of codes */
+}
+
+/*
+ * Given a list of repeated code lengths rep[0..n-1], where each byte is a
+ * count (high four bits + 1) and a code length (low four bits), generate the
+ * list of code lengths.  This compaction reduces the size of the object code.
+ * Then given the list of code lengths length[0..n-1] representing a canonical
+ * Huffman code for n symbols, construct the tables required to decode those
+ * codes.  Those tables are the number of codes of each length, and the symbols
+ * sorted by length, retaining their original order within each length.  The
+ * return value is zero for a complete code set, negative for an over-
+ * subscribed code set, and positive for an incomplete code set.  The tables
+ * can be used if the return value is zero or positive, but they cannot be used
+ * if the return value is negative.  If the return value is zero, it is not
+ * possible for decode() using that table to return an error--any stream of
+ * enough bits will resolve to a symbol.  If the return value is positive, then
+ * it is possible for decode() using that table to return an error for received
+ * codes past the end of the incomplete lengths.
+ */
+local int construct(struct huffman *h, const unsigned char *rep, int n)
+{
+    int symbol;         /* current symbol when stepping through length[] */
+    int len;            /* current length when stepping through h->count[] */
+    int left;           /* number of possible codes left of current length */
+    short offs[MAXBITS+1];      /* offsets in symbol table for each length */
+    short length[256];  /* code lengths */
+
+    /* convert compact repeat counts into symbol bit length list */
+    symbol = 0;
+    do {
+        len = *rep++;
+        left = (len >> 4) + 1;
+        len &= 15;
+        do {
+            length[symbol++] = len;
+        } while (--left);
+    } while (--n);
+    n = symbol;
+
+    /* count number of codes of each length */
+    for (len = 0; len <= MAXBITS; len++)
+        h->count[len] = 0;
+    for (symbol = 0; symbol < n; symbol++)
+        (h->count[length[symbol]])++;   /* assumes lengths are within bounds */
+    if (h->count[0] == n)               /* no codes! */
+        return 0;                       /* complete, but decode() will fail */
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;                           /* one possible code of zero length */
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;                     /* one more bit, double codes left */
+        left -= h->count[len];          /* deduct count from possible codes */
+        if (left < 0) return left;      /* over-subscribed--return negative */
+    }                                   /* left > 0 means incomplete */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + h->count[len];
+
+    /*
+     * put symbols in table sorted by length, by symbol order within each
+     * length
+     */
+    for (symbol = 0; symbol < n; symbol++)
+        if (length[symbol] != 0)
+            h->symbol[offs[length[symbol]]++] = symbol;
+
+    /* return zero for complete set, positive for incomplete set */
+    return left;
+}
+
+/*
+ * Decode PKWare Compression Library stream.
+ *
+ * Format notes:
+ *
+ * - First byte is 0 if literals are uncoded or 1 if they are coded.  Second
+ *   byte is 4, 5, or 6 for the number of extra bits in the distance code.
+ *   This is the base-2 logarithm of the dictionary size minus six.
+ *
+ * - Compressed data is a combination of literals and length/distance pairs
+ *   terminated by an end code.  Literals are either Huffman coded or
+ *   uncoded bytes.  A length/distance pair is a coded length followed by a
+ *   coded distance to represent a string that occurs earlier in the
+ *   uncompressed data that occurs again at the current location.
+ *
+ * - A bit preceding a literal or length/distance pair indicates which comes
+ *   next, 0 for literals, 1 for length/distance.
+ *
+ * - If literals are uncoded, then the next eight bits are the literal, in the
+ *   normal bit order in th stream, i.e. no bit-reversal is needed. Similarly,
+ *   no bit reversal is needed for either the length extra bits or the distance
+ *   extra bits.
+ *
+ * - Literal bytes are simply written to the output.  A length/distance pair is
+ *   an instruction to copy previously uncompressed bytes to the output.  The
+ *   copy is from distance bytes back in the output stream, copying for length
+ *   bytes.
+ *
+ * - Distances pointing before the beginning of the output data are not
+ *   permitted.
+ *
+ * - Overlapped copies, where the length is greater than the distance, are
+ *   allowed and common.  For example, a distance of one and a length of 518
+ *   simply copies the last byte 518 times.  A distance of four and a length of
+ *   twelve copies the last four bytes three times.  A simple forward copy
+ *   ignoring whether the length is greater than the distance or not implements
+ *   this correctly.
+ */
+local int decomp(struct state *s)
+{
+    int lit;            /* true if literals are coded */
+    int dict;           /* log2(dictionary size) - 6 */
+    int symbol;         /* decoded symbol, extra bits for distance */
+    int len;            /* length for copy */
+    int dist;           /* distance for copy */
+    int copy;           /* copy counter */
+    unsigned char *from, *to;   /* copy pointers */
+    static int virgin = 1;                              /* build tables once */
+    static short litcnt[MAXBITS+1], litsym[256];        /* litcode memory */
+    static short lencnt[MAXBITS+1], lensym[16];         /* lencode memory */
+    static short distcnt[MAXBITS+1], distsym[64];       /* distcode memory */
+    static struct huffman litcode = {litcnt, litsym};   /* length code */
+    static struct huffman lencode = {lencnt, lensym};   /* length code */
+    static struct huffman distcode = {distcnt, distsym};/* distance code */
+        /* bit lengths of literal codes */
+    static const unsigned char litlen[] = {
+        11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8,
+        9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
+        7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
+        8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
+        44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45,
+        44, 173};
+        /* bit lengths of length codes 0..15 */
+    static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23};
+        /* bit lengths of distance codes 0..63 */
+    static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248};
+    static const short base[16] = {     /* base for length codes */
+        3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264};
+    static const char extra[16] = {     /* extra bits for length codes */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};
+
+    /* set up decoding tables (once--might not be thread-safe) */
+    if (virgin) {
+        construct(&litcode, litlen, sizeof(litlen));
+        construct(&lencode, lenlen, sizeof(lenlen));
+        construct(&distcode, distlen, sizeof(distlen));
+        virgin = 0;
+    }
+
+    /* read header */
+    lit = bits(s, 8);
+    if (lit > 1) return -1;
+    dict = bits(s, 8);
+    if (dict < 4 || dict > 6) return -2;
+
+    /* decode literals and length/distance pairs */
+    do {
+        if (bits(s, 1)) {
+            /* get length */
+            symbol = decode(s, &lencode);
+            len = base[symbol] + bits(s, extra[symbol]);
+            if (len == 519) break;              /* end code */
+
+            /* get distance */
+            symbol = len == 2 ? 2 : dict;
+            dist = decode(s, &distcode) << symbol;
+            dist += bits(s, symbol);
+            dist++;
+            if (s->first && dist > s->next)
+                return -3;              /* distance too far back */
+
+            /* copy length bytes from distance bytes back */
+            do {
+                to = s->out + s->next;
+                from = to - dist;
+                copy = MAXWIN;
+                if (s->next < dist) {
+                    from += copy;
+                    copy = dist;
+                }
+                copy -= s->next;
+                if (copy > len) copy = len;
+                len -= copy;
+                s->next += copy;
+                do {
+                    *to++ = *from++;
+                } while (--copy);
+                if (s->next == MAXWIN) {
+                    if (s->outfun(s->outhow, s->out, s->next)) return 1;
+                    s->next = 0;
+                    s->first = 0;
+                }
+            } while (len != 0);
+        }
+        else {
+            /* get literal and write it */
+            symbol = lit ? decode(s, &litcode) : bits(s, 8);
+            s->out[s->next++] = symbol;
+            if (s->next == MAXWIN) {
+                if (s->outfun(s->outhow, s->out, s->next)) return 1;
+                s->next = 0;
+                s->first = 0;
+            }
+        }
+    } while (1);
+    return 0;
+}
+
+/* See comments in blast.h */
+int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow)
+{
+    struct state s;             /* input/output state */
+    int err;                    /* return value */
+
+    /* initialize input state */
+    s.infun = infun;
+    s.inhow = inhow;
+    s.left = 0;
+    s.bitbuf = 0;
+    s.bitcnt = 0;
+
+    /* initialize output state */
+    s.outfun = outfun;
+    s.outhow = outhow;
+    s.next = 0;
+    s.first = 1;
+
+    /* return if bits() or decode() tries to read past available input */
+    if (setjmp(s.env) != 0)             /* if came back here via longjmp(), */
+        err = 2;                        /*  then skip decomp(), return error */
+    else
+        err = decomp(&s);               /* decompress */
+
+    /* write any leftover output and update the error code if needed */
+    if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0)
+        err = 1;
+    return err;
+}
+
+#ifdef TEST
+/* Example of how to use blast() */
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CHUNK 16384
+
+local unsigned inf(void *how, unsigned char **buf)
+{
+    static unsigned char hold[CHUNK];
+
+    *buf = hold;
+    return fread(hold, 1, CHUNK, (FILE *)how);
+}
+
+local int outf(void *how, unsigned char *buf, unsigned len)
+{
+    return fwrite(buf, 1, len, (FILE *)how) != len;
+}
+
+/* Decompress a PKWare Compression Library stream from stdin to stdout */
+int main(void)
+{
+    int ret, n;
+
+    /* decompress to stdout */
+    ret = blast(inf, stdin, outf, stdout);
+    if (ret != 0) fprintf(stderr, "blast error: %d\n", ret);
+
+    /* see if there are any leftover bytes */
+    n = 0;
+    while (getchar() != EOF) n++;
+    if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n);
+
+    /* return blast() error code */
+    return ret;
+}
+#endif

+ 76 - 0
tools/cpio/src/blast.h

@@ -0,0 +1,76 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, February 2004.
+ *
+ * Sccsid @(#)blast.h	1.2 (gritter) 2/17/04
+ */
+/* blast.h -- interface for blast.c
+  Copyright (C) 2003 Mark Adler
+  version 1.1, 16 Feb 2003
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the author be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Mark Adler    madler@alumni.caltech.edu
+ */
+
+
+/*
+ * blast() decompresses the PKWare Data Compression Library (DCL) compressed
+ * format.  It provides the same functionality as the explode() function in
+ * that library.  (Note: PKWare overused the "implode" verb, and the format
+ * used by their library implode() function is completely different and
+ * incompatible with the implode compression method supported by PKZIP.)
+ */
+
+
+typedef unsigned (*blast_in)(void *how, unsigned char **buf);
+typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len);
+/* Definitions for input/output functions passed to blast().  See below for
+ * what the provided functions need to do.
+ */
+
+
+int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow);
+/* Decompress input to output using the provided infun() and outfun() calls.
+ * On success, the return value of blast() is zero.  If there is an error in
+ * the source data, i.e. it is not in the proper format, then a negative value
+ * is returned.  If there is not enough input available or there is not enough
+ * output space, then a positive error is returned.
+ *
+ * The input function is invoked: len = infun(how, &buf), where buf is set by
+ * infun() to point to the input buffer, and infun() returns the number of
+ * available bytes there.  If infun() returns zero, then blast() returns with
+ * an input error.  (blast() only asks for input if it needs it.)  inhow is for
+ * use by the application to pass an input descriptor to infun(), if desired.
+ *
+ * The output function is invoked: err = outfun(how, buf, len), where the bytes
+ * to be written are buf[0..len-1].  If err is not zero, then blast() returns
+ * with an output error.  outfun() is always called with len <= 4096.  outhow
+ * is for use by the application to pass an output descriptor to outfun(), if
+ * desired.
+ *
+ * The return codes are:
+ *
+ *   2:  ran out of input before completing decompression
+ *   1:  output error before completing decompression
+ *   0:  successful decompression
+ *  -1:  literal flag not zero or one
+ *  -2:  dictionary size not in 4..6
+ *  -3:  distance is too far back
+ *
+ * At the bottom of blast.c is an example program that uses blast() that can be
+ * compiled to produce a command-line decompression filter by defining TEST.
+ */

+ 943 - 0
tools/cpio/src/cpio.1

@@ -0,0 +1,943 @@
+'\" t
+.\" Copyright (c) 2003 Gunnar Ritter
+.\"
+.\" This software is provided 'as-is', without any express or implied
+.\" warranty. In no event will the authors be held liable for any damages
+.\" arising from the use of this software.
+.\"
+.\" Permission is granted to anyone to use this software for any purpose,
+.\" including commercial applications, and to alter it and redistribute
+.\" it freely, subject to the following restrictions:
+.\"
+.\" 1. The origin of this software must not be misrepresented; you must not
+.\"    claim that you wrote the original software. If you use this software
+.\"    in a product, an acknowledgment in the product documentation would be
+.\"    appreciated but is not required.
+.\"
+.\" 2. Altered source versions must be plainly marked as such, and must not be
+.\"    misrepresented as being the original software.
+.\"
+.\" 3. This notice may not be removed or altered from any source distribution.
+.\" Sccsid @(#)cpio.1	1.92 (gritter) 3/26/07
+.TH CPIO 1 "3/26/07" "Heirloom Toolchest" "User Commands"
+.SH NAME
+cpio \- copy file archives in and out
+.SH SYNOPSIS
+.PD 0
+.HP
+.nh
+.ad l
+\fBcpio\fR \fB\-i\fR[\fBbcdfkmrstuvBSV6\fR] [\fB\-C\fI\ size\fR]
+[\fB\-E\fI\ file\fR] [\fB\-H\fI\ hdr\fR] [[\fB\-I\fI\ file\fR]
+[\fB\-M\fI\ msg\fR]] [\fB\-R\fI\ id\fR] [\fIpatterns\fR]
+.HP
+.ad l
+\fBcpio\fR \fB\-o\fR[\fBacvABLPV\fR] [\fB\-C\fI\ size\fR]
+[\fB\-H\fI\ hdr\fR] [[\fB\-M\fI\ msg\fR] [\fB\-O\fI\ file\fR]]
+.HP
+.ad l
+\fBcpio\fR \fB\-p\fR[\fBadlmPuvLV\fR] [\fB\-R\fI\ id\fR] \fIdirectory\fR
+.br
+.PD
+.ad b
+.hy 1
+.SH DESCRIPTION
+.I Cpio
+creates and extracts file archives and copies files.
+.PP
+With the
+.B \-i
+option,
+.I cpio
+works in
+.RI ` copy-in '
+mode and extracts files from a file archive.
+By default,
+the archive is read from standard input.
+Optional arguments are interpreted as
+.I patterns
+and restrict the set of extracted files
+to those matching any of the
+.IR patterns .
+A
+.RB ` !\& '
+at the beginning of the
+.I pattern
+selects all files that do not match this
+.IR pattern .
+The syntax is otherwise identical to that described in
+.IR glob (7),
+except that the slash character
+.RB ` / '
+is matched by
+meta-character constructs with
+.RB ` * ',
+.RB ` ? '
+and
+.RB ` [ '.
+Care must be taken to quote meta-characters appropriately from the shell.
+File permissions are set to those in the archive;
+if the caller is the super-user,
+ownerships are restored as well.
+.I Cpio
+will not create directories,
+preserve modification times
+or overwrite more recently modified target files
+unless the appropriate
+.IR \-d ,
+.I \-m
+or
+.I \-u
+options are specified.
+Archives compressed with
+.IR bzip2 (1),
+.IR compress (1),
+.IR gzip (1),
+or
+.IR rpm (1)
+are transparently de\%compressed on input.
+.PP
+With
+.BR \-o ,
+.I cpio
+works in
+.RI ` copy-out '
+mode,
+creates archives
+and writes them to standard output per default.
+A list of filenames to be included in the archive is
+read from standard input;
+if the name of a directory appears,
+it is included in the archive,
+but
+.I cpio
+will not include any of its members
+unless they are explicitly given in addition.
+The
+.IR find (1)
+utility is useful to generate a list of files
+(see also its
+.I \-cpio
+and
+.I \-ncpio
+operators).
+When producing a filename list for
+.IR cpio ,
+find should always be invoked with
+.I \-depth
+since this makes it possible to extract write-protected directories
+for users other than the super-user.
+.PP
+The
+.B \-p
+option selects
+.RI ` pass '
+mode;
+a list of files is read from standard input as described for
+.IR \-o ;
+files are copied to the specified
+.IR directory ,
+preserving attributes as described for
+.IR \-i .
+Special files are re-created in the target hierarchy,
+and hard links between copied files are preserved.
+.PP
+When a premature end-of-file is detected with
+.I \-i
+and
+.I \-o
+and the archive is a block or character special file,
+the user is prompted for new media.
+.PP
+The following options alter the behavior of
+.IR cpio :
+.TP
+.B \-a
+Resets the access times of files
+that were included in the archive with
+.I \-o
+or copied with
+.IR \-p .
+.TP
+.B \-A
+Append files to the archive.
+The archive must be seekable,
+such as a regular file or a block device,
+or a tape device capable of writing between filemarks.
+.TP
+.B \-b
+Swap bytes within each half word
+and half words within each word
+of input file data.
+.TP
+.B \-B
+Blocks input and output archives at 5120 byte records.
+The default blocking size is device dependent.
+.TP
+.B \-c
+Specifies that archive headers are in SVR4 ASCII cpio format.
+This option is ignored with
+.I \-i
+unless the
+.I \-k
+option is also present.
+.TP
+\fB\-C\fI size\fR
+Blocks input and output archives at
+.I size
+byte records.
+.TP
+.B \-d
+Creates missing parent directories
+for each file extracted from the archive
+and allows the extraction of directories.
+.TP
+\fB\-E\fI file\fR
+Each line read from
+.I file
+is taken as a pattern in addition
+to those specified on the command line.
+.TP
+.B \-f
+Reverses the sense of patterns
+such that a file that does not match any of the patterns
+is selected.
+.TP
+\fB\-H\fI header\fR
+Specifies the archive header format to be one of:
+.sp
+.in +6
+.TS
+lfB l.
+\fBcrc\fR	SVR4 ASCII cpio format with checksum;\ 
+\fBsco\fR	T{
+SCO UnixWare 7.1 ASCII cpio format;
+T}
+\fBscocrc\fR	T{
+SCO UnixWare 7.1 ASCII cpio format with checksum;
+T}
+\fBodc\fR	T{
+traditional ASCII cpio format, as standardized in IEEE Std. 1003.1, 1996;
+T}
+\fBbbs\fR	byte-swapped binary cpio format;
+\fBsgi\fR	T{
+SGI IRIX extended binary cpio format;
+T}
+\fBcray\fR	T{
+Cray UNICOS 9 cpio format;
+T}
+\fBcray5\fR	T{
+Cray UNICOS 5 cpio format;
+T}
+\fBdec\fR	T{
+Digital UNIX extended cpio format;
+T}
+\fBtar\fR	tar format;
+\fBotar\fR	old tar format;
+\fBustar\fR	T{
+IEEE Std. 1003.1, 1996 tar format;
+T}
+.T&
+l s.
+\fBpax\fR[\fB:\fIoption\fB,\fR[\fIoption\fB,\fR\|...]]
+.T&
+l l.
+\&	T{
+IEEE Std. 1003.1, 2001 pax format.
+Format-specific \fIoptions\fR are:
+.in +2n
+.ti 0
+.br
+\fBlinkdata\fR
+.br
+For a regular file which has multiple hard links,
+the file data is stored once for each link in the archive,
+instead of being stored for the first entry only.
+This option must be used with care
+since many implementations are unable
+to read the resulting archive.
+.ti 0
+.br
+\fBtimes\fR
+.br
+Causes the times of last access and last modification
+of each archived file
+to be stored in an extended \fIpax\fR header.
+This in particular allows the time of last access
+to be restored when the archive is read.
+.br
+.in -2n
+T}
+\fBsun\fR	T{
+Sun Solaris 7 extended tar format;
+T}
+\fBgnu\fR	T{
+GNU tar format;
+T}
+\fBbar\fR	T{
+SunOS 4 bar format;
+T}
+\fBzip\fR[\fB:\fIcc\fR]	T{
+zip format with optional compression method.
+If \fIcc\fR is one of
+\fBen\fR (normal, default),
+\fBex\fR (extra),
+\fBef\fR (fast),
+or
+\fBes\fR (super fast),
+the standard \fIdeflate\fR compression is used.
+\fBe0\fR selects no compression,
+and
+\fBbz2\fR selects \fIbzip2\fR compression.
+T}
+.TE
+.in -6
+.sp
+This option is ignored with
+.I \-i
+unless the
+.I \-k
+option is also present.
+The default for
+.I \-o
+is binary cpio format.
+.TP
+\fB\-I\fI\ file\fR
+Selects a
+.I file
+that is read with the
+.I \-i
+option instead of standard input.
+.TP
+.B \-k
+Try to continue operation on read errors and invalid headers.
+If an archive contains another archive,
+files from either archive may be chosen.
+.TP
+.B \-l
+Link files instead of copying them with
+.I \-p
+if possible.
+.TP
+.B \-L
+Follow symbolic links when reading files with
+.I \-o
+or
+.IR \-p .
+.TP
+.B \-m
+Restore modification times of extracted files
+to those given in the archive.
+.TP
+\fB\-M\fI message\fR
+The given
+.I message
+is printed instead of the standard one
+with
+.I \-I
+or
+.I \-O
+when changing media.
+.TP
+\fB\-O\fI file\fR
+Selects an archive
+.I file
+that is written instead of standard output
+with the
+.I \-o
+option.
+.TP
+.B \-P
+In copy-out or pass mode,
+interpret the data read from standard input
+as prototype lines
+of colon-separated fields
+of the form
+.in +3m
+.sp
+\fItype\fB:\fIuser\fB:\fIgroup\fB:\fImode\fB:\fIatime\fB:\fImtime\fB:\fImajor\fB:\fIminor\fB:\fIpath\fR
+.sp
+.in -3m
+For each non-empty field,
+the corresponding attribute of the input file is overridden.
+With this option,
+an unprivileged user can create
+an archive that contains files
+with arbitrary attributes.
+The meanings of the individual fields are:
+.RS
+.TP 6
+.PD 0
+.I type
+File type, one of:
+\fBb\fR (block device),
+\fBc\fR (character device),
+\fBd\fR (directory),
+\fBf\fR (plain file),
+\fBp\fR (named pipe),
+or
+\fBs\fR (symbolic link).
+.TP
+.I user
+The owner of the file,
+which can be a numeric user ID or a user name.
+.TP
+.I group
+The group owner of the file,
+which can be a numeric group ID or a group name.
+.TP
+.I mode
+The octal mode of the file.
+.TP
+.I atime
+The time the file was last accessed.
+Note that most archive formats cannot store this attribute,
+in which case it is ignored.
+The format is the same as that of the
+.I mtime
+field.
+.TP
+.I mtime
+The time the file was last modified.
+This is either a decimal integer
+specifying the seconds past the epoch,
+or an ISO\ 8601 date and time field
+of the format \fIYYYYMMDD\fBT\fIHHMMSS\fR,
+e.g. 20070326T190511,
+the latter being relative to the current time zone
+and with all digits past the \fBT\fR being optional.
+.TP
+.I major minor
+Major and minor device numbers as with
+.IR mknod (1M).
+These fields are only allowed for block and character devices.
+.TP
+.I path
+The name of the file to be archived.
+If the file is not a symbolic link,
+and the specification is otherwise sufficient,
+the file needs not exist
+at the time the archive is created.
+A non-existent regular file will be empty in the archive.
+.PD
+.RE
+.IP
+This option is an extension.
+.TP
+.B \-r
+Rename files interactively.
+Before a file is extracted from the archive,
+its file name is printed on standard error
+and the user is prompted to specify a substitute file name.
+If the line read from the terminal is empty,
+the file is skipped;
+if the line consists of a single dot,
+the name is retained;
+otherwise,
+the line forms the new file name.
+.TP
+\fB\-R\fI user\fR
+Set the ownership of extracted files
+to the user and group ids of
+.I user
+instead of those specified in the archive.
+Valid only for the super-user.
+.TP
+.B \-s
+Swap bytes within each half word
+of input file data.
+.TP
+.B \-S
+Swap half words within each word
+of input file data.
+.TP
+.B \-t
+When combined with the
+.I \-o
+option,
+a list of files in the archive is written to standard output;
+no files are extracted.
+.TP
+.B \-u
+.I Cpio
+will overwrite existing target files
+that were modified more recently than the file in the archive
+when this option is given.
+.TP
+.B \-v
+Prints the file names of archived or extracted files with
+.I \-i
+and
+.I \-o
+and a verbose output format with
+.IR \-t .
+If given twice
+.RB ( \-vv )
+in combination with
+.I \-t
+when reading a
+.I zip
+archive,
+information about compression level and method is printed.
+.TP
+.B \-V
+Prints a dot for each archived or extracted file.
+.TP
+.B \-6
+Selects Unix 6th Edition archive format
+(only in copy-in mode).
+.PP
+.ne 37
+Characteristics of archive formats are as follows:
+.sp
+.TS
+allbox;
+l r r r l
+l1fB r2 n2 r2 c.
+	T{
+.ad l
+maximum user/\%group id
+T}	T{
+.ad l
+maximum file size
+T}	T{
+.ad l
+maximum pathname length
+T}	T{
+.ad l
+bits in dev_t (major/minor)
+T}
+binary	65535	2 GB\ 	256	\ 16
+\-H\ sgi	65535	9 EB\ 	256	\ 14/18
+\-H\ odc	262143	8 GB\ 	256	\ 18
+\-H\ dec	262143	8 GB\ 	256	\ 24/24
+T{
+\-c, \-H\ crc
+T}	4.3e9	4 GB\ 	1024	\ 32/32
+T{
+\-H\ sco, \-H\ scocrc
+T}	4.3e9	9 EB\ 	1024	\ 32/32
+T{
+\-H\ cray, \-H\ cray5
+T}	1.8e19	9 EB\ 	65535	\ 64
+\-H\ otar	2097151	8 GB\ 	99	\ n/a
+T{
+\-H\ tar,
+\-H\ ustar
+T}	2097151	8 GB\ 	256 (99)	\ 21/21
+\-H\ pax	1.8e19	9 EB\ 	65535	\ 21/21
+\-H\ sun	1.8e19	9 EB\ 	65535	\ 63/63
+\-H\ gnu	1.8e19	9 EB\ 	65535	\ 63/63
+\-H\ bar	2097151	8 GB\ 	427	\ 21
+\-H\ zip	4.3e9	9 EB\ 	60000	\ 32
+.TE
+.sp
+.PP
+By default,
+.B binary
+cpio archives are written.
+The byte order of such archives
+depends on the machine
+on which the archive is created.
+Unlike some other implementations,
+.I cpio
+fully supports
+archives of either byte order.
+.I \-H\ bbs
+can be used to create an archive
+with the byte order opposed to that of the current machine.
+.PP
+The
+.B sgi
+format extends the binary format
+to handle larger files and more device bits.
+If an archive does not contain any entries
+that actually need the extensions,
+it is identical to a binary archive.
+.I \-H\ sgi
+archives are always created in MSB order.
+.PP
+The
+.B odc
+format was introduced with System\ III
+and standardized with IEEE Std. 1003.1.
+All known
+.I cpio
+implementations since around 1980 can read this format.
+.PP
+The
+.B dec
+format extends the
+.I odc
+format
+to support more device bits.
+Archives in this format are generally incompatible with
+.I odc
+archives
+and need special implementation support to be read.
+.PP
+The
+.B \-c
+format was introduced with System\ V Release\ 4.
+Except for the file size,
+it imposes no practical limitations
+on files archived.
+The original SVR4 implementation
+stores the contents of hard linked files
+only once and with the last archived link.
+This
+.I cpio
+ensures compatibility with SVR4.
+With archives created by implementations that employ other methods
+for storing hard linked files,
+each file is extracted as a single link,
+and some of these files may be empty.
+Implementations that expect methods other than the original SVR4 one
+may extract no data for hard linked files at all.
+.PP
+The
+.B crc
+format is essentially the same as the
+.I \-c
+format
+but adds a simple checksum (not a CRC, despite its name)
+for the data of regular files.
+The checksum requires the implementation to read each file twice,
+which can considerably increase running time and system overhead.
+As not all implementations claiming to support this format
+handle the checksum correctly,
+it is of limited use.
+.PP
+The
+.B sco
+and
+.B scocrc
+formats are variants of the
+.I \-c
+and
+.I \-H\ crc
+formats, respectively,
+with extensions to support larger files.
+The extensions result in a different archive format
+only if files larger than slightly below 2\ GB occur.
+.PP
+The
+.B cray
+format extends all header fields to 64 bits.
+It thus imposes no practical limitations of any kind
+on archived files,
+but requires special implementation support
+to be read.
+Although it is originally a binary format,
+the byte order is always MSB as on Cray machines.
+The
+.B cray5
+format is an older variant
+that was used with UNICOS 5 and earlier.
+.PP
+The
+.B otar
+format was introduced with the Unix 7th Edition
+.I tar
+utility.
+Archives in this format
+can be read on all Unix systems since about 1980.
+It can only hold regular files
+(and, on more recent systems, symbolic links).
+For file names that contain characters with the most significant bit set
+(non-ASCII characters),
+implementations differ in the interpretation of the header checksum.
+.PP
+The
+.B ustar
+format was introduced with IEEE Std. 1003.1.
+It extends the old
+.I tar
+format
+with support for directories, device files,
+and longer file names.
+Pathnames of single-linked files can consist of up to 256 characters,
+dependent on the position of slashes.
+Files with multiple links can only be archived
+if the first link encountered is no longer than 100 characters.
+Due to implementation errors,
+file names longer than 99 characters
+can not considered to be generally portable.
+Another addition of the
+.I ustar
+format
+are fields for the symbolic user and group IDs.
+These fields are created by
+.IR cpio ,
+but ignored when reading such archives.
+.PP
+With
+.BR "\-H tar" ,
+a variant of the
+.I ustar
+format is selected
+which stores file type bits in the mode field
+to work around common implementation problems.
+These bits are ignored by
+.I cpio
+when reading archives.
+.PP
+The
+.B pax
+format is an extension to the
+.I ustar
+format.
+If attributes cannot be archived with
+.IR ustar ,
+an extended header is written.
+Unless the size of an entry is greater than 8\ GB,
+a
+.I pax
+archive should be readable by any implementation
+capable of reading
+.I ustar
+archives,
+although files may be extracted under wrong names
+and extended headers may be extracted as separate files.
+If a file name contains non-UTF-8 characters,
+it may not be archived or extracted correctly
+because of a problem of the
+.I pax
+format specification.
+.PP
+The
+.B sun
+format extends the
+.I ustar
+format similar as the
+.I pax
+format does.
+The extended headers in
+.I sun
+format archives are not understood
+by implementations that support only the
+.I pax
+format and vice-versa.
+The
+.I sun
+format has also problems with non-UTF-8 characters in file names.
+.PP
+The
+.B GNU
+.I tar
+format is mostly compatible with the other
+.I tar
+formats,
+unless an archive entry actually uses its extended features.
+There are no practical limitations on files archived with this format.
+The implementation of
+.I cpio
+is limited to expanded numerical fields
+and long file names;
+in particular,
+there is no support for sparse files or incremental backups.
+If
+.I cpio
+creates a multi-volume
+.I GNU
+archive,
+it just splits a single-volume archive in multiple parts,
+as with the other formats;
+.I GNU
+multi-volume archives are not supported.
+.PP
+The
+.B bar
+format is similar to the
+.I tar
+format, but can store longer file names.
+It requires special implementation support to be read.
+.PP
+The
+.B zip
+format can be read in many non-Unix environments.
+There are several restrictions on archives
+intended for data exchange:
+only regular files should be stored;
+file times, permissions and ownerships
+might be ignored by other implementations;
+there should be no more than 65536 files in the archive;
+the total archive size should not exceed 2 GB;
+only
+.I deflate
+compression should be used.
+Otherwise,
+.I cpio
+stores all information available with other archive formats
+in extended
+.I zip
+file headers,
+so if archive portability is of no concern,
+the
+.I zip
+implementation in
+.I cpio
+can archive complete Unix file hierarchies.
+.I Cpio
+supports the
+.I zip64
+format extension for large files;
+it automatically writes
+.I zip64
+entries if necessary.
+.I Cpio
+can extract all known
+.I zip
+format compression codes.
+It does not support
+.I zip
+encryption.
+Multi-volume
+.I zip
+archives are created as splitted single-volume archives,
+as with the other formats written by
+.IR cpio ;
+generic multi-volume
+.I zip
+archives are not supported.
+.SH EXAMPLES
+Extract all files named
+.I Makefile
+or
+.I makefile
+from the archive stored on
+.IR /dev/rmt/c0s0 ,
+overwriting recent files:
+.RS 2
+.sp
+cpio \-idmu \-I /dev/rmt/c0s0 \'[Mm]akefile\' \'*/[Mm]akefile\'
+.RE
+.PP
+List the files contained in a software distribution archive:
+.RS 2
+.sp
+cpio \-itv \-I distribution.tar.gz
+.RE
+.PP
+Write a
+.IR gzip (1)
+compressed
+.I ustar
+archive containing all files below the directory
+.I \%project
+to the file
+.IR \%project.tar.gz ,
+excluding all directories named
+.I CVS
+or
+.I SCCS
+and their contents:
+.RS 2
+.sp
+find project \-depth \-print | egrep \-v \'/(CVS|SCCS)(/|$)\' |
+.br
+      cpio \-o \-H ustar | gzip \-c > project.tar.gz
+.RE
+.PP
+Copy the directory
+.I work
+and its contents
+to the directory
+.IR \%savedfiles :
+.RS 2
+.sp
+find work \-depth \-print | cpio \-pdm savedfiles
+.RE
+.PP
+Self-extracting zip archives are not automatically recognized,
+but can normally be read using the
+.I \-k
+option, as with
+.RS 2
+.sp
+cpio \-itvk \-H zip \-I archive.exe
+.sp
+.RE
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.BR LANG ", " LC_ALL
+See
+.IR locale (7).
+.TP
+.B LC_CTYPE
+Selects the mapping of bytes to characters
+used for matching patterns.
+.TP
+.B LC_TIME
+Sets the month names printed with
+.IR \-tv .
+.TP
+.B SYSV3
+If this variable is set,
+the
+.I \-c
+option has the same effect as \fI\-H odc\fR;
+\fB\-H newc\fR can be used
+to select SVR4 ASCII format.
+The output format of
+.I \-tv
+is changed, as well as the text of diagnostic messages.
+.SH "SEE ALSO"
+find(1),
+pax(1),
+tar(1)
+.SH DIAGNOSTICS
+.I Cpio
+exits with
+.sp
+.TS
+l8fB l.
+0	after successful operation;
+1	on usage errors;
+2	when operation was continued after minor errors;
+3	on fatal error conditions.
+.TE
+.SH NOTES
+Device and inode numbers
+are used for hard link recognition
+with the various cpio formats.
+Since the header space cannot hold
+large numbers present in current file systems,
+devices and inode numbers are set on a per-archive basis.
+This enables hard link recognition with all cpio formats,
+but the link connection to files appended with
+.I \-A
+is not preserved.
+.PP
+If a numeric user or group id does not fit
+within the size of the header field in the selected format,
+files are stored with the user id (or group id, respectively)
+set to 60001.
+.PP
+Use of the
+.I \-A
+option with a
+.I zip
+format archive may cause data loss
+if the archive was not previously created by
+.I cpio
+itself.
+.PP
+.I Cpio
+cannot store file names that contain newline characters;
+see the
+.I NOTES
+section of
+.IR find (1)
+for more information.
+.PP
+If the file names passed to
+.I "cpio \-o"
+begin with a slash character,
+absolute path names are stored in the archive
+and will be extracted to these path names later
+regardless of the current working directory.
+This is normally not advisable,
+and relative path names should be passed to
+.I cpio
+only.

+ 7185 - 0
tools/cpio/src/cpio.c

@@ -0,0 +1,7185 @@
+/*
+ * cpio - copy file archives in and out
+ *
+ * Gunnar Ritter, Freiburg i. Br., Germany, April 2003.
+ */
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+/*
+ * Sccsid @(#)cpio.c	1.304 (gritter) 2/14/09
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef	__linux__
+#if !defined (__UCLIBC__) && !defined (__dietlibc__)
+#include <linux/fs.h>
+#endif	/* !__UCLIBC__, !__dietlibc__ */
+#include <linux/fd.h>
+#undef	WNOHANG
+#undef	WUNTRACED
+#undef	P_ALL
+#undef	P_PID
+#undef	P_PGID
+#ifdef	__dietlibc__
+#undef	NR_OPEN
+#undef	PATH_MAX
+#endif	/* __dietlibc__ */
+#endif	/* __linux__ */
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include "sigset.h"
+#include <time.h>
+#include <utime.h>
+#include <pwd.h>
+#include <grp.h>
+#include <limits.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <locale.h>
+#include <ctype.h>
+#include "memalign.h"
+
+int	sysv3;
+
+#if USE_ZLIB
+#include <zlib.h>
+#endif	/* USE_ZLIB */
+
+#if USE_BZLIB
+#include <bzlib.h>
+#endif	/* USE_BZLIB */
+
+#include <sys/ioctl.h>
+
+#if defined (__linux__) || defined (__sun) || defined (__FreeBSD__) || \
+	defined (__hpux) || defined (_AIX) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+#include <sys/mtio.h>
+#else	/* SVR4.2MP */
+#include <sys/scsi.h>
+#include <sys/st01.h>
+#endif	/* SVR4.2MP */
+
+#include <iblok.h>
+#include <sfile.h>
+#include <atoll.h>
+
+#ifdef	_AIX
+#include <sys/sysmacros.h>
+#endif	/* _AIX */
+
+#ifndef	major
+#include <sys/mkdev.h>
+#endif	/* !major */
+
+#include "cpio.h"
+#include "blast.h"
+
+#ifdef	__GLIBC__
+#ifdef	_IO_putc_unlocked
+#undef	putc
+#define	putc(c, f)	_IO_putc_unlocked(c, f)
+#undef	putchar
+#define	putchar(c)	_IO_putc_unlocked(c, stdout)
+#endif	/* _IO_putc_unlocked */
+#endif	/* __GLIBC__ */
+
+/*
+ * The cpio code assumes that all following S_IFMT bits are the same as
+ * those of the mode fields in cpio headers. The only real Unix system
+ * known to deviate from this de facto standard is UNICOS which uses
+ * 0130000 for S_IFLNK. But this software does not run on UNICOS for
+ * a variety of other reasons anyway, so this should not be of much
+ * concern.
+ */
+#if	S_IFIFO	!= 0010000 || \
+	S_IFCHR	!= 0020000 || \
+	S_IFDIR	!= 0040000 || \
+	S_IFBLK	!= 0060000 || \
+	S_IFREG	!= 0100000 || \
+	S_IFLNK	!= 0120000 || \
+	S_IFSOCK!= 0140000 || \
+	S_IFMT	!= 0170000
+#error non-standard S_IFMT bits
+#endif
+
+/*
+ * File types that are not present on all systems but that we want to
+ * recognize nevertheless.
+ */
+#ifndef	S_IFDOOR
+#define	S_IFDOOR	0150000		/* Solaris door */
+#endif
+#ifndef	S_IFNAM
+#define	S_IFNAM		0050000		/* XENIX special named file */
+#endif
+#ifndef	S_INSEM
+#define	S_INSEM		0x1		/* XENIX semaphore subtype of IFNAM */
+#endif
+#ifndef	S_INSHD
+#define	S_INSHD		0x2		/* XENIX shared data subtype of IFNAM */
+#endif
+#ifndef	S_IFNWK
+#define	S_IFNWK		0110000		/* HP-UX network special file */
+#endif
+
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \
+	defined (__DragonFly__) || defined (__APPLE__)
+/*
+ * For whatever reason, FreeBSD casts the return values of major() and
+ * minor() to signed values so that normal limit comparisons will fail.
+ */
+static unsigned long
+mymajor(long dev)
+{
+	return major(dev) & 0xFFFFFFFFUL;
+}
+#undef	major
+#define	major(a)	mymajor(a)
+static unsigned long
+myminor(long dev)
+{
+	return minor(dev) & 0xFFFFFFFFUL;
+}
+#undef	minor
+#define	minor(a)	myminor(a)
+#endif	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+
+/*
+ * Device and inode counts in cpio formats are too small to store the
+ * information used to detect hard links on today's systems. Keep track
+ * of all devices and inodes and store fake counts in the archive.
+ */
+struct ilink {
+	struct ilink	*l_nxt;	/* next link to same i-node */
+	char		*l_nam;	/* link name */
+	size_t		l_siz;	/* link name size */
+};
+
+struct islot {
+	struct islot	*i_lln;	/* left link */
+	struct islot 	*i_rln;	/* right link */
+	struct ilink	*i_lnk;	/* links list */
+	struct stat	*i_st;	/* stat information */
+	char		*i_name;/* name of first link encountered */
+	ino_t		i_ino;	/* real inode number */
+	uint32_t	i_fino;	/* fake inode number */
+	nlink_t		i_nlk;	/* number of remaining links */
+};
+
+struct dslot {
+	struct dslot	*d_nxt;	/* next device */
+	struct islot	*d_isl;	/* inode slots */
+	uint32_t	d_cnt;	/* used inode number count */
+	uint32_t	d_fake;	/* faked device id */
+	dev_t		d_dev;	/* real device id */
+};
+
+union types2 {
+	uint8_t		byte[2];
+	uint16_t	sword;
+};
+
+union types4 {
+	uint8_t		byte[4];
+	uint16_t	sword[2];
+	uint32_t	lword;
+};
+
+/*
+ * Store and retrieve integers in a defined endian order.
+ */
+static uint16_t
+ple16(const char *cp)
+{
+	return (uint16_t)(cp[0]&0377) +
+		((uint16_t)(cp[1]&0377) << 8);
+}
+
+static uint16_t
+pbe16(const char *cp)
+{
+	return (uint16_t)(cp[1]&0377) +
+		((uint16_t)(cp[0]&0377) << 8);
+}
+
+static uint32_t
+ple32(const char *cp)
+{
+	return (uint32_t)(cp[0]&0377) +
+		((uint32_t)(cp[1]&0377) << 8) +
+		((uint32_t)(cp[2]&0377) << 16) +
+		((uint32_t)(cp[3]&0377) << 24);
+}
+
+static uint32_t
+pbe32(const char *cp)
+{
+	return (uint32_t)(cp[3]&0377) +
+		((uint32_t)(cp[2]&0377) << 8) +
+		((uint32_t)(cp[1]&0377) << 16) +
+		((uint32_t)(cp[0]&0377) << 24);
+}
+
+static uint32_t
+pme32(const char *cp)
+{
+	return (uint32_t)(cp[2]&0377) +
+		((uint32_t)(cp[3]&0377) << 8) +
+		((uint32_t)(cp[0]&0377) << 16) +
+		((uint32_t)(cp[1]&0377) << 24);
+}
+
+static uint64_t
+ple64(const char *cp)
+{
+	return (uint64_t)(cp[0]&0377) +
+		((uint64_t)(cp[1]&0377) << 8) +
+		((uint64_t)(cp[2]&0377) << 16) +
+		((uint64_t)(cp[3]&0377) << 24) +
+		((uint64_t)(cp[4]&0377) << 32) +
+		((uint64_t)(cp[5]&0377) << 40) +
+		((uint64_t)(cp[6]&0377) << 48) +
+		((uint64_t)(cp[7]&0377) << 56);
+}
+
+static uint64_t
+pbe64(const char *cp)
+{
+	return (uint64_t)(cp[7]&0377) +
+		((uint64_t)(cp[6]&0377) << 8) +
+		((uint64_t)(cp[5]&0377) << 16) +
+		((uint64_t)(cp[4]&0377) << 24) +
+		((uint64_t)(cp[3]&0377) << 32) +
+		((uint64_t)(cp[2]&0377) << 40) +
+		((uint64_t)(cp[1]&0377) << 48) +
+		((uint64_t)(cp[0]&0377) << 56);
+}
+
+static void
+le16p(uint16_t n, char *cp)
+{
+	cp[0] = (n&0x00ff);
+	cp[1] = (n&0xff00) >> 8;
+}
+
+static void
+be16p(uint16_t n, char *cp)
+{
+	cp[1] = (n&0x00ff);
+	cp[0] = (n&0xff00) >> 8;
+}
+
+static void
+le32p(uint32_t n, char *cp)
+{
+	cp[0] = (n&0x000000ff);
+	cp[1] = (n&0x0000ff00) >> 8;
+	cp[2] = (n&0x00ff0000) >> 16;
+	cp[3] = (n&0xff000000) >> 24;
+}
+
+static void
+be32p(uint32_t n, char *cp)
+{
+	cp[3] = (n&0x000000ff);
+	cp[2] = (n&0x0000ff00) >> 8;
+	cp[1] = (n&0x00ff0000) >> 16;
+	cp[0] = (n&0xff000000) >> 24;
+}
+
+static void
+me32p(uint32_t n, char *cp)
+{
+	cp[2] = (n&0x000000ff);
+	cp[3] = (n&0x0000ff00) >> 8;
+	cp[0] = (n&0x00ff0000) >> 16;
+	cp[1] = (n&0xff000000) >> 24;
+}
+
+static void
+le64p(uint64_t n, char *cp)
+{
+	cp[0] = (n&0x00000000000000ffLL);
+	cp[1] = (n&0x000000000000ff00LL) >> 8;
+	cp[2] = (n&0x0000000000ff0000LL) >> 16;
+	cp[3] = (n&0x00000000ff000000LL) >> 24;
+	cp[4] = (n&0x000000ff00000000LL) >> 32;
+	cp[5] = (n&0x0000ff0000000000LL) >> 40;
+	cp[6] = (n&0x00ff000000000000LL) >> 48;
+	cp[7] = (n&0xff00000000000000LL) >> 56;
+}
+
+static void
+be64p(uint64_t n, char *cp)
+{
+	cp[7] = (n&0x00000000000000ffLL);
+	cp[6] = (n&0x000000000000ff00LL) >> 8;
+	cp[5] = (n&0x0000000000ff0000LL) >> 16;
+	cp[4] = (n&0x00000000ff000000LL) >> 24;
+	cp[3] = (n&0x000000ff00000000LL) >> 32;
+	cp[2] = (n&0x0000ff0000000000LL) >> 40;
+	cp[1] = (n&0x00ff000000000000LL) >> 48;
+	cp[0] = (n&0xff00000000000000LL) >> 56;
+}
+
+#define	TNAMSIZ	100
+#define	TPFXSIZ	155
+#define	TMAGSIZ	6
+#define	TTIMSIZ	12
+
+/*
+ * Structure of an archive header.
+ */
+union bincpio {
+	char		data[4096];
+#define	SIZEOF_hdr_cpio	26
+	struct hdr_cpio {
+		char		c_magic[2];
+		char		c_dev[2];
+		char		c_ino[2];
+		char		c_mode[2];
+		char		c_uid[2];
+		char		c_gid[2];
+		char		c_nlink[2];
+		char		c_rdev[2];
+		char		c_mtime[4];
+		char		c_namesize[2];
+		char		c_filesize[4];
+	} Hdr;
+#define	SIZEOF_cray_hdr	152
+	struct cray_hdr {	/* with thanks to Cray-Cyber.org */
+		char		C_magic[8];
+		char		C_dev[8];
+		char		C_ino[8];
+		char		C_mode[8];
+		char		C_uid[8];
+		char		C_gid[8];
+		char		C_nlink[8];
+		char		C_rdev[8];
+				/*
+				 * The C_param field was introduced with
+				 * UNICOS 6 and is simply not present in
+				 * the earlier format. Following fields
+				 * are the same for both revisions again.
+				 */
+#define	CRAY_PARAMSZ	(8*8)
+		char		C_param[CRAY_PARAMSZ];
+		char		C_mtime[8];
+		char		C_namesize[8];
+		char		C_filesize[8];
+	} Crayhdr;
+#define	SIZEOF_c_hdr	76
+	struct c_hdr {
+		char		c_magic[6];
+		char		c_dev[6];
+		char		c_ino[6];
+		char		c_mode[6];
+		char		c_uid[6];
+		char		c_gid[6];
+		char		c_nlink[6];
+		char		c_rdev[6];
+		char		c_mtime[11];
+		char		c_namesz[6];
+		char		c_filesz[11];
+	} Cdr;
+#define	SIZEOF_d_hdr	86
+	struct d_hdr {
+		char		d_magic[6];
+		char		d_dev[6];
+		char		d_ino[6];
+		char		d_mode[6];
+		char		d_uid[6];
+		char		d_gid[6];
+		char		d_nlink[6];
+		char		d_rmaj[8];
+		char		d_rmin[8];
+		char		d_mtime[11];
+		char		d_namesz[6];
+		char		d_filesz[11];
+	} Ddr;
+#define	SIZEOF_Exp_cpio_hdr	110
+	struct Exp_cpio_hdr {
+		char		E_magic[6];
+		char		E_ino[8];
+		char		E_mode[8];
+		char		E_uid[8];
+		char		E_gid[8];
+		char		E_nlink[8];
+		char		E_mtime[8];
+		char		E_filesize[8];
+		char		E_maj[8];
+		char		E_min[8];
+		char		E_rmaj[8];
+		char		E_rmin[8];
+		char		E_namesize[8];
+		char		E_chksum[8];
+	} Edr;
+	struct tar_header {
+		char		t_name[TNAMSIZ];
+		char		t_mode[8];
+		char		t_uid[8];
+		char		t_gid[8];
+		char		t_size[12];
+		char		t_mtime[TTIMSIZ];
+		char		t_chksum[8];
+		char		t_linkflag;
+		char		t_linkname[TNAMSIZ];
+		char		t_magic[TMAGSIZ];
+		char		t_version[2];
+		char		t_uname[32];
+		char		t_gname[32];
+		char		t_devmajor[8];
+		char		t_devminor[8];
+		char		t_prefix[TPFXSIZ];
+	} Tdr;
+#define	SIZEOF_bar_header	84
+	struct bar_header {
+		char		b_mode[8];
+		char		b_uid[8];
+		char		b_gid[8];
+		char		b_size[12];
+		char		b_mtime[12];
+		char		b_chksum[8];
+		char		b_rdev[8];
+		char		b_linkflag;
+		char		b_bar_magic[2];
+		char		b_volume_num[4];
+		char		b_compressed;
+		char		b_date[12];
+	} Bdr;
+#define	SIZEOF_zip_header	30
+	struct zip_header {
+		char		z_signature[4];
+		char		z_version[2];
+		char		z_gflag[2];
+		char		z_cmethod[2];
+		char		z_modtime[2];
+		char		z_moddate[2];
+		char		z_crc32[4];
+		char		z_csize[4];
+		char		z_nsize[4];
+		char		z_namelen[2];
+		char		z_extralen[2];
+	} Zdr;
+};
+
+#define	BCUT	0177777
+#define	OCUT	0777777
+#define	ECUT	0xFFFFFFFFUL
+
+static const char	trailer[] = "TRAILER!!!";
+
+/*
+ * Structure of per-file extra data for zip format.
+ */
+union zextra {
+	char	data[1];
+#define	SIZEOF_zextra_gn	4
+	struct	zextra_gn {
+		char	ze_gn_tag[2];
+		char	ze_gn_tsize[2];
+	} Ze_gn;
+#define	SIZEOF_zextra_64	32		/* regular size */
+#define	SIZEOF_zextra_64_a	28		/* size without startn field */
+#define	SIZEOF_zextra_64_b	20		/* size without reloff field */
+	struct	zextra_64 {
+		char	ze_64_tag[2];
+		char	ze_64_tsize[2];
+		char	ze_64_nsize[8];
+		char	ze_64_csize[8];
+		char	ze_64_reloff[8];
+		char	ze_64_startn[4];
+	} Ze_64;
+#define	SIZEOF_zextra_pk	16
+	struct	zextra_pk {
+		char	ze_pk_tag[2];
+		char	ze_pk_tsize[2];
+		char	ze_pk_atime[4];
+		char	ze_pk_mtime[4];
+		char	ze_pk_uid[2];
+		char	ze_pk_gid[2];
+	} Ze_pk;
+#define	SIZEOF_zextra_ek	17
+	struct	zextra_et {
+		char	ze_et_tag[2];
+		char	ze_et_tsize[2];
+		char	ze_et_flags[1];
+		char	ze_et_mtime[4];
+		char	ze_et_atime[4];
+		char	ze_et_ctime[4];
+	} Ze_et;
+#define	SIZEOF_zextra_i1	16
+	struct	zextra_i1 {
+	char	ze_i1_tag[2];
+		char	ze_i1_tsize[2];
+		char	ze_i1_atime[4];
+		char	ze_i1_mtime[4];
+		char	ze_i1_uid[2];
+		char	ze_i1_gid[2];
+	} Ze_i1;
+#define	SIZEOF_zextra_i2	8
+	struct	zextra_i2 {
+		char	ze_i2_tag[2];
+		char	ze_i2_tsize[2];
+		char	ze_i2_uid[2];
+		char	ze_i2_gid[2];
+	} Ze_i2;
+#define	SIZEOF_zextra_as	16
+	struct	zextra_as {
+		char	ze_as_tag[2];
+		char	ze_as_tsize[2];
+		char	ze_as_crc[4];
+		char	ze_as_mode[2];
+		char	ze_as_sizdev[4];
+		char	ze_as_uid[2];
+		char	ze_as_gid[2];
+	} Ze_as;
+#define	SIZEOF_zextra_cp	40
+	struct	zextra_cp {
+		char	ze_cp_tag[2];
+		char	ze_cp_tsize[2];
+		char	ze_cp_dev[4];
+		char	ze_cp_ino[4];
+		char	ze_cp_mode[4];
+		char	ze_cp_uid[4];
+		char	ze_cp_gid[4];
+		char	ze_cp_nlink[4];
+		char	ze_cp_rdev[4];
+		char	ze_cp_mtime[4];
+		char	ze_cp_atime[4];
+	} Ze_cp;
+};
+
+static struct	zipstuff {		/* stuff for central directory at EOF */
+	struct zipstuff	*zs_next;
+	char	*zs_name;		/* file name */
+	long long	zs_size;	/* file size */
+	long long	zs_relative;	/* offset of local header */
+	long long	zs_csize;	/* compressed size */
+	uint32_t	zs_crc32;	/* CRC */
+	time_t		zs_mtime;	/* modification time */
+	enum cmethod	zs_cmethod;	/* compression method */
+	int		zs_gflag;	/* general flag */
+	mode_t		zs_mode;	/* file mode */
+} *zipbulk;
+
+/*
+ * Structure of the central zip directory at the end of the file. This
+ * (obligatory) part of a zip file is written by this implementation,
+ * but is completely ignored on copy-in. This means that we miss the
+ * mode_t stored in zc_extralen if zc_versionmade[1] is 3 (Unix). We
+ * have to do this since it contains the S_IFMT bits, thus telling us
+ * whether something is a symbolic link and resulting in different
+ * behavior - but as the input had to be seekable in order to do this,
+ * we had to store entire archives in temporary files if input came
+ * from a pipe to be consistent.
+ */
+#define	SIZEOF_zipcentral	46
+struct	zipcentral {
+	char	zc_signature[4];
+	char	zc_versionmade[2];
+	char	zc_versionextr[2];
+	char	zc_gflag[2];
+	char	zc_cmethod[2];
+	char	zc_modtime[2];
+	char	zc_moddate[2];
+	char	zc_crc32[4];
+	char	zc_csize[4];
+	char	zc_nsize[4];
+	char	zc_namelen[2];
+	char	zc_extralen[2];
+	char	zc_commentlen[2];
+	char	zc_disknstart[2];
+	char	zc_internal[2];
+	char	zc_external[4];
+	char	zc_relative[4];
+};
+
+#define	SIZEOF_zip64end		56
+struct	zip64end {
+	char	z6_signature[4];
+	char	z6_recsize[8];
+	char	z6_versionmade[2];
+	char	z6_versionextr[2];
+	char	z6_thisdiskn[4];
+	char	z6_alldiskn[4];
+	char	z6_thisentries[8];
+	char	z6_allentries[8];
+	char	z6_dirsize[8];
+	char	z6_startsize[8];
+};
+
+#define	SIZEOF_zip64loc		20
+struct	zip64loc {
+	char	z4_signature[4];
+	char	z4_startno[4];
+	char	z4_reloff[8];
+	char	z4_alldiskn[4];
+};
+
+#define	SIZEOF_zipend		22
+struct	zipend {
+	char	ze_signature[4];
+	char	ze_thisdiskn[2];
+	char	ze_alldiskn[2];
+	char	ze_thisentries[2];
+	char	ze_allentries[2];
+	char	ze_dirsize[4];
+	char	ze_startsize[4];
+	char	ze_commentlen[2];
+};
+
+#define	SIZEOF_zipddesc		16
+struct	zipddesc {
+	char	zd_signature[4];
+	char	zd_crc32[4];
+	char	zd_csize[4];
+	char	zd_nsize[4];
+};
+
+#define	SIZEOF_zipddesc64	24
+struct	zipddesc64 {
+	char	zd_signature[4];
+	char	zd_crc32[4];
+	char	zd_csize[8];
+	char	zd_nsize[8];
+};
+
+/*
+ * Magic numbers and strings.
+ */
+static const uint16_t	mag_bin = 070707;
+/*static const uint16_t	mag_bbs = 0143561;*/
+static const char	mag_asc[6] = "070701";
+static const char	mag_crc[6] = "070702";
+static const char	mag_odc[6] = "070707";
+static const long	mag_sco = 0x7ffffe00;
+
+static const char	mag_ustar[6] = "ustar\0";
+static const char	mag_gnutar[8] = "ustar  \0";
+static const char	mag_bar[2] = "V\0";
+
+static const char	mag_zipctr[4] = "PK\1\2";
+static const char	mag_zipsig[4] = "PK\3\4";
+static const char	mag_zipend[4] = "PK\5\6";
+static const char	mag_zip64e[4] = "PK\6\6";
+static const char	mag_zip64l[4] = "PK\6\7";
+static const char	mag_zipdds[4] = "PK\7\10";
+#define			mag_zip64f	0x0001
+#define			mag_zipcpio	0x0707
+
+/*
+ * Fields for the extended pax header.
+ */
+static enum paxrec {
+	PR_NONE		= 0000,
+	PR_ATIME	= 0001,
+	PR_GID		= 0002,
+	PR_LINKPATH	= 0004,
+	PR_MTIME	= 0010,
+	PR_PATH		= 0020,
+	PR_SIZE		= 0040,
+	PR_UID		= 0100,
+	PR_SUN_DEVMAJOR	= 0200,
+	PR_SUN_DEVMINOR	= 0400
+} paxrec, globrec;
+
+/*
+ * Prototype structure, collecting user-defined information
+ * about a file.
+ */
+struct prototype {
+	mode_t	pt_mode;	/* type and permission bits */
+	uid_t	pt_uid;		/* owner */
+	gid_t	pt_gid;		/* group owner */
+	time_t	pt_atime;	/* time of last access */
+	time_t	pt_mtime;	/* time of last modification */
+	dev_t	pt_rdev;	/* device major/minor */
+	enum {
+		PT_NONE	 = 0000,
+		PT_TYPE	 = 0001,
+		PT_OWNER = 0002,
+		PT_GROUP = 0004,
+		PT_MODE  = 0010,
+		PT_ATIME = 0020,
+		PT_MTIME = 0040,
+		PT_RDEV  = 0100
+	}	pt_spec;	/* specified information */
+};
+
+static struct stat	globst;
+
+/*
+ * This sets a sanity check limit on path names. If a longer path name
+ * occurs in an archive, it is treated as corrupt. This is because no
+ * known Unix system can handle path names of arbitrary length; limits
+ * are typically between 1024 and 4096. Trying to extract longer path
+ * names would fail anyway and will cpio eventually fail to allocate
+ * memory.
+ */
+#define			SANELIMIT	0177777
+
+char			*progname;	/* argv[0] to main() */
+static struct dslot	*devices;	/* devices table */
+static struct dslot	*markeddevs;	/* unusable device numbers */
+static char		*blkbuf;	/* block buffer */
+int			blksiz;		/* block buffer size */
+static int		blktop;		/* top of filled part of buffer */
+static int		curpos;		/* position in blkbuf */
+static uint32_t		fakedev;	/* fake device for single link inodes */
+static uint32_t		fakeino;	/* fake inode for single link inodes */
+static uint32_t		harddev;	/* fake device used for hard links */
+static unsigned long long	maxsize;/* maximum size for format */
+static unsigned long long	maxrdev;/* maximum st_rdev for format */
+static unsigned long long	maxmajor;/* maximum major(st_rdev) for format */
+static unsigned long long	maxminor;/* maximum minor(st_rdev) for format */
+static unsigned long long	maxuid;	/* maximum user id for format */
+static unsigned long long	maxgid;	/* maximum group id for format */
+static unsigned long long	maxnlink;/* maximum link count for format */
+static int		mt;		/* magtape file descriptor */
+static int		mfl;		/* magtape flags */
+static struct stat	mtst;		/* fstat() on mt */
+int			aflag;		/* reset access times */
+int			Aflag;		/* append to archive */
+int			bflag;		/* swap bytes */
+int			Bflag;		/* 5120 blocking */
+int			cflag;		/* ascii format */
+int			Cflag;		/* user-defined blocking */
+int			dflag;		/* create directories */
+int			Dflag;		/* do not ask for next device */
+int			eflag;		/* DEC format */
+int			cray_eflag;	/* do not archive if values too large */
+const char		*Eflag;		/* filename for files to be extracted */
+int			fflag;		/* pattern excludes */
+int			Hflag;		/* header format */
+const char		*Iflag;		/* input archive name */
+int			kflag;		/* skipt corrupted parts */
+int			Kflag;		/* IRIX-style large file support */
+int			lflag;		/* link of possible */
+int			Lflag;		/* follow symbolic links */
+int			mflag;		/* retain modification times */
+const char		*Mflag;		/* message when switching media */
+const char		*Oflag;		/* output archive name */
+int			Pflag;		/* prototype file list */
+int			rflag;		/* rename files */
+const char		*Rflag;		/* reassign ownerships */
+static uid_t		Ruid;		/* uid to assign */
+static gid_t		Rgid;		/* gid to assign */
+int			sflag;		/* swap half word bytes */
+int			Sflag;		/* swap word bytes */
+int			tflag;		/* print toc */
+int			uflag;		/* overwrite files unconditionally */
+int			hp_Uflag;	/* use umask when creating files */
+int			vflag;		/* verbose */
+int			Vflag;		/* special verbose */
+int			sixflag;	/* 6th Edition archives */
+int			action;		/* -i -o -p */
+long long		errcnt;		/* error status */
+static unsigned long long	maxpath;/* maximum path length with -i */
+static uint32_t		maxino;		/* maximum inode number with -i */
+static uid_t		myuid;		/* user id of caller */
+static gid_t		mygid;		/* group id of caller */
+static long long	blocks;		/* copying statistics: full blocks */
+static long long	bytes;		/* copying statistics: partial blocks */
+static long long	nwritten;	/* bytes written to archive */
+static off_t		aoffs;		/* offset in archive */
+static off_t		poffs;		/* physical offset in archive */
+static int		tapeblock = -1;	/* physical tape block size */
+struct glist		*patterns;	/* patterns for -i */
+static int		tty;		/* terminal file descriptor */
+static const char	*cur_ofile;	/* current original file */
+static const char	*cur_tfile;	/* current temporary file */
+static mode_t		umsk;		/* user's umask */
+static int		zipclevel;	/* zip compression level */
+static struct islot	*inull;		/* splay tree null element */
+int			printsev;	/* print message severity strings */
+static int		compressed_bar;	/* this is a compressed bar archive */
+static int		formatforced;	/* -k -i -Hfmt forces a format */
+static long long	lineno;		/* input line number */
+
+int			pax_dflag;	/* directory matches only itself */
+int			pax_kflag;	/* do not overwrite files */
+int			pax_nflag;	/* select first archive member only */
+int			pax_sflag;	/* substitute file names */
+int			pax_uflag;	/* add only recent files to archive */
+int			pax_Xflag;	/* do not cross device boundaries */
+static enum {
+	PO_NONE		= 0,
+	PO_LINKDATA	= 01,		/* include link data in type 2 */
+	PO_TIMES	= 02,		/* create atime and mtime fields */
+} pax_oflag;				/* recognized -o options */
+
+static void	copyout(int (*)(const char *, struct stat *));
+static size_t	ofiles_cpio(char **, size_t *);
+static void	dooutp(void);
+static int	outfile(const char *, struct stat *);
+static int	addfile(const char *, struct stat *, uint32_t, uint32_t, int,
+			const char *);
+static void	iflush(struct islot *, uint32_t);
+static void	lflush(void);
+static int	bigendian(void);
+static void	getbuf(char **, size_t *, size_t);
+static void	prdot(int);
+static void	newmedia(int);
+static void	mclose(void);
+static ssize_t	mwrite(int);
+static void	bwrite(const char *, size_t);
+static void	bflush(void);
+static int	sum(int, const char *, struct stat *, char *);
+static int	rstime(const char *, struct stat *, const char *);
+static struct islot	*isplay(ino_t, struct islot *);
+static struct islot	*ifind(ino_t, struct islot **);
+static void	iput(struct islot *, struct islot **);
+static struct dslot	*dfind(struct dslot **, dev_t);
+static void	done(int);
+static void	dopass(const char *);
+static int	passdata(struct file *, const char *, int);
+static int	passfile(const char *, struct stat *);
+static int	filein(struct file *, int (*)(struct file *, const char *, int),
+			char *);
+static int	linkunlink(const char *, const char *);
+static void	tunlink(char **);
+static int	filet(struct file *, int (*)(struct file *, const char *, int));
+static void	filev(struct file *);
+static int	typec(struct stat *);
+static void	permbits(mode_t);
+static void	prtime_cpio(time_t);
+static void	getpath(const char *, char **, char **, size_t *, size_t *);
+static void	setpath(const char *, char **, char **,
+			size_t, size_t *, size_t *);
+static int	imdir(char *);
+static int	setattr(const char *, struct stat *);
+static int	setowner(const char *, struct stat *);
+static int	canlink(const char *, struct stat *, int);
+static void	doinp(void);
+static void	storelink(struct file *);
+static void	flushlinks(struct file *);
+static void	flushnode(struct islot *, struct file *);
+static void	flushrest(int);
+static void	flushtree(struct islot *, int);
+static int	inpone(struct file *, int);
+static int	readhdr(struct file *, union bincpio *);
+static void	whathdr(void);
+static int	infile(struct file *);
+static int	skipfile(struct file *);
+static int	skipdata(struct file *f,
+			int (*)(struct file *, const char *, int));
+static int	indata(struct file *, const char *, int);
+static int	totrailer(void);
+static long long	rdoct(const char *, int);
+static long long	rdhex(const char *, int);
+static ssize_t	mread(void);
+static void	mstat(void);
+static int	skippad(unsigned long long, int);
+static int	allzero(const char *, int);
+static const char	*getuser(uid_t);
+static const char	*getgroup(gid_t);
+static struct glist	*want(struct file *, struct glist **);
+static void	patfile(void);
+static int	ckodd(long long, int, const char *, const char *);
+static int	rname(char **, size_t *);
+static int	redirect(const char *, const char *);
+static char	*tnameof(struct tar_header *, char *);
+static int	tmkname(struct tar_header *, const char *);
+static void	tlinkof(struct tar_header *, struct file *);
+static int	tmklink(struct tar_header *, const char *);
+static int	tlflag(struct stat *);
+static void	tchksum(union bincpio *);
+static int	tcssum(union bincpio *, int);
+static int	trdsum(union bincpio *);
+static mode_t	tifmt(int);
+static void	bchksum(union bincpio *);
+static int	bcssum(union bincpio *);
+static void	blinkof(const char *, struct file *, int);
+static void	dump_barhdr(void);
+static int	zcreat(const char *, mode_t);
+static int	zclose(int);
+static void	markdev(dev_t);
+static int	marked(dev_t);
+static void	cantsup(int, const char *);
+static void	onint(int);
+static int	zipread(struct file *, const char *, int, int);
+static void	zipreaddesc(struct file *);
+static int	cantunzip(struct file *, const char *);
+static time_t	gdostime(const char *, const char *);
+static void	mkdostime(time_t, char *, char *);
+static ssize_t	ziprxtra(struct file *, struct zip_header *);
+static void	ziptrailer(void);
+static void	zipdefer(const char *, struct stat *, long long,
+			uint32_t, long long, const struct zip_header *);
+static int	zipwrite(int, const char *, struct stat *,
+			union bincpio *, size_t, uint32_t, uint32_t,
+			uint32_t *, long long *);
+static int	zipwtemp(int, const char *, struct stat *,
+			union bincpio *, size_t, uint32_t, uint32_t,
+			uint32_t *, long long *);
+#if USE_ZLIB
+static int	zipwdesc(int, const char *, struct stat *,
+			union bincpio *, size_t, uint32_t, uint32_t,
+			uint32_t *, long long *);
+#endif	/* USE_ZLIB */
+static int	zipwxtra(const char *, struct stat *, uint32_t, uint32_t);
+static void	zipinfo(struct file *);
+static void	readK2hdr(struct file *);
+static int	readgnuname(char **, size_t *, long);
+static void	writegnuname(const char *, long, int);
+static void	tgetpax(struct tar_header *, struct file *);
+static enum paxrec	tgetrec(char **, char **, char **);
+static void	wrpax(const char *, const char *, struct stat *);
+static void	addrec(char **, long *, long *,
+			const char *, const char *, long long);
+static void	paxnam(struct tar_header *, const char *);
+static char	*sequence(void);
+static char	*joinpath(const char *, char *);
+static int	utf8(const char *);
+static char	*getproto(char *, struct prototype *);
+
+size_t		(*ofiles)(char **, size_t *) = ofiles_cpio;
+void		(*prtime)(time_t) = prtime_cpio;
+
+int
+main(int argc, char **argv)
+{
+	myuid = getuid();
+	mygid = getgid();
+	umask(umsk = umask(0));
+	progname = basename(argv[0]);
+	setlocale(LC_CTYPE, "");
+	setlocale(LC_TIME, "");
+	inull = scalloc(1, sizeof *inull);
+	inull->i_lln = inull->i_rln = inull;
+	flags(argc, argv);
+	switch (action) {
+	case 'i':
+		if (sigset(SIGINT, SIG_IGN) != SIG_IGN)
+			sigset(SIGINT, onint);
+		doinp();
+		break;
+	case 'o':
+		dooutp();
+		break;
+	case 'p':
+		if (sigset(SIGINT, SIG_IGN) != SIG_IGN)
+			sigset(SIGINT, onint);
+		dopass(argv[optind]);
+		break;
+	}
+	if (tflag)
+		fflush(stdout);
+	else if (Vflag)
+		prdot(1);
+	if (pax != PAX_TYPE_CPIO)
+		pax_onexit();
+	fprintf(stderr, "%llu blocks\n", blocks + ((bytes + 0777) >> 9));
+	mclose();
+	if (errcnt && sysv3 == 0)
+		fprintf(stderr, "%llu error(s)\n", errcnt);
+	return errcnt ? sysv3 ? 1 : 2 : 0;
+}
+
+static size_t
+ofiles_cpio(char **name, size_t *namsiz)
+{
+	static struct iblok	*ip;
+
+	if (ip == NULL)
+		ip = ib_alloc(0, 0);
+	return ib_getlin(ip, name, namsiz, srealloc);
+}
+
+/*
+ * Read the file name list for -o and -p and do initial processing
+ * for each name.
+ */
+static void
+copyout(int (*copyfn)(const char *, struct stat *))
+{
+	char	*name = NULL, *np;
+	size_t	namsiz = 0, namlen;
+	struct stat	st;
+	struct prototype	pt;
+
+	while ((namlen = ofiles(&name, &namsiz)) != 0) {
+		lineno++;
+		if (name[namlen-1] == '\n')
+			name[--namlen] = '\0';
+		if (Pflag)
+			np = getproto(name, &pt);
+		else
+			np = name;
+		while (np[0] == '.' && np[1] == '/') {
+			np += 2;
+			while (*np == '/')
+				np++;
+			if (*np == '\0') {
+				np = name;
+				break;
+			}
+		}
+		if (lstat(np, &st) < 0) {
+			if (Pflag && *np && ((pt.pt_spec &
+			    (PT_TYPE|PT_OWNER|PT_GROUP|PT_MODE|PT_RDEV) &&
+					((pt.pt_mode&S_IFMT) == S_IFBLK ||
+					 (pt.pt_mode&S_IFMT) == S_IFCHR)) ||
+				      (pt.pt_spec &
+		            (PT_TYPE|PT_OWNER|PT_GROUP|PT_MODE) &&
+			    		((pt.pt_mode&S_IFMT) == S_IFDIR ||
+					 (pt.pt_mode&S_IFMT) == S_IFIFO ||
+					 (pt.pt_mode&S_IFMT) == S_IFREG)))) {
+				memset(&st, 0, sizeof st);
+				st.st_mode = pt.pt_mode;
+				st.st_blksize = 4096;
+				st.st_nlink = 1;
+				goto missingok;
+			}
+			else if (sysv3 < 0)
+				msg(2, 0, "< %s > ?\n", np);
+			else if (sysv3 > 0)
+				msg(2, 0, "Cannot obtain information "
+						"about file:  \"%s\".\n",
+						np);
+			else
+				emsg(2, "Error with lstat of \"%s\"", np);
+			errcnt++;
+			continue;
+		}
+	missingok:
+		if (Lflag && (st.st_mode&S_IFMT) == S_IFLNK) {
+			if (stat(np, &st) < 0) {
+				emsg(2, "Cannot follow \"%s\"", np);
+				errcnt++;
+				continue;
+			}
+		}
+		/*
+		 * These file types are essentially useless in an archive
+		 * since they are recreated by any process that needs them.
+		 * We thus ignore them and do not even issue a warning,
+		 * because that would only displace more important messages
+		 * on a terminal and confuse people who just want to copy
+		 * directory hierarchies.--But for pax, POSIX.1-2001 requires
+		 * us to fail!
+		 */
+		if ((st.st_mode&S_IFMT) == S_IFSOCK ||
+				(st.st_mode&S_IFMT) == S_IFDOOR) {
+			if (pax >= PAX_TYPE_PAX2001) {
+				msg(2, 0, "Cannot handle %s \"%s\".\n",
+					(st.st_mode&S_IFMT) == S_IFSOCK ?
+						"socket" : "door", np);
+				errcnt++;
+			}
+			continue;
+		}
+		if (Pflag) {
+			if (pt.pt_spec & PT_TYPE)
+				if ((st.st_mode&S_IFMT) != (pt.pt_mode&S_IFMT))
+					msg(4, 0, "line %lld: types "
+						"do not match\n", lineno);
+			if (pt.pt_spec & PT_OWNER)
+				st.st_uid = pt.pt_uid;
+			if (pt.pt_spec & PT_GROUP)
+				st.st_gid = pt.pt_gid;
+			if (pt.pt_spec & PT_MODE) {
+				st.st_mode &= ~(mode_t)07777;
+				st.st_mode |= pt.pt_mode;
+			}
+			if (pt.pt_spec & PT_ATIME)
+				st.st_atime = pt.pt_atime;
+			if (pt.pt_spec & PT_MTIME)
+				st.st_mtime = pt.pt_mtime;
+			if (pt.pt_spec & PT_RDEV) {
+				if ((st.st_mode&S_IFMT) != S_IFBLK &&
+				    (st.st_mode&S_IFMT) != S_IFCHR)
+					msg(4, 0, "line %lld: device type "
+						"specified for non-device "
+						"file\n", lineno);
+				st.st_rdev = pt.pt_rdev;
+			}
+		}
+		if (pax_track(np, st.st_mtime) == 0)
+			continue;
+		if ((fmttype == FMT_ZIP ||
+					fmttype & TYP_BAR ||
+					fmttype == FMT_GNUTAR)
+				&& (st.st_mode&S_IFMT) == S_IFDIR &&
+				name[namlen-1] != '/') {
+			if (namlen+2 >= namsiz) {
+				size_t	diff = np - name;
+				name = srealloc(name, namsiz = namlen+2);
+				np = &name[diff];
+			}
+			name[namlen++] = '/';
+			name[namlen] = '\0';
+		}
+		errcnt += copyfn(np, &st);
+	}
+}
+
+/*
+ * Execution for -o.
+ */
+static void
+dooutp(void)
+{
+	if (Oflag) {
+		if ((mt = Aflag ? open(Oflag, O_RDWR, 0666) :
+					creat(Oflag, 0666)) < 0) {
+			if (sysv3) {
+				emsg(013, "Cannot open <%s> for %s.", Oflag,
+					Aflag ? "append" : "output");
+				done(1);
+			} else
+				msg(3, -2, "Cannot open \"%s\" for %s\n", Oflag,
+					Aflag ? "append" : "output");
+		}
+	} else
+		mt = dup(1);
+	mstat();
+	blkbuf = svalloc(blksiz, 1);
+	if (Aflag) {
+		if (totrailer() != 0)
+			return;
+	} else if (fmttype == FMT_NONE)
+		fmttype = bigendian() ? FMT_BINBE : FMT_BINLE;
+	if (fmttype & TYP_BINARY) {
+		maxino = 0177777;
+		fakeino = 0177777;
+		maxpath = 256;
+		if (fmttype & TYP_SGI) {
+			maxsize = 0x7FFFFFFFFFFFFFFFLL;
+			maxmajor = 037777;
+			maxminor = 0777777;
+		} else {
+			maxsize = 0x7FFFFFFFLL;
+			maxrdev = 0177777;
+		}
+		maxuid = 0177777;
+		maxgid = 0177777;
+		maxnlink = 0177777;
+	} else if (fmttype == FMT_ODC) {
+		maxino = 0777777;
+		fakeino = 0777777;
+		maxpath = 256;
+		maxsize = 077777777777LL;
+		maxrdev = 0777777;
+		maxuid = 0777777;
+		maxgid = 0777777;
+		maxnlink = 0777777;
+	} else if (fmttype == FMT_DEC) {
+		maxino = 0777777;
+		fakeino = 0777777;
+		maxpath = 256;
+		maxsize = 077777777777LL;
+		maxmajor = 077777777;
+		maxminor = 077777777;
+		maxuid = 0777777;
+		maxgid = 0777777;
+		maxnlink = 0777777;
+	} else if (fmttype & TYP_NCPIO) {
+		maxino = 0xFFFFFFFFUL;
+		fakeino = 0xFFFFFFFFUL;
+		maxpath = 1024;
+		maxsize = fmttype&TYP_SCO ? 0x7FFFFFFFFFFFFFFFLL : 0xFFFFFFFFUL;
+		maxmajor = 0xFFFFFFFFUL;
+		maxminor = 0xFFFFFFFFUL;
+		maxuid = 0xFFFFFFFFUL;
+		maxgid = 0xFFFFFFFFUL;
+		maxnlink = 0xFFFFFFFFUL;
+	} else if (fmttype & TYP_CRAY) {
+		maxino = 0xFFFFFFFFUL;
+		fakeino = 0xFFFFFFFFUL;
+		maxpath = SANELIMIT;
+		maxsize = 0x7FFFFFFFFFFFFFFFLL;
+		maxrdev = 0x7FFFFFFFFFFFFFFFLL;
+		maxuid = 0x7FFFFFFFFFFFFFFFLL;
+		maxgid = 0x7FFFFFFFFFFFFFFFLL;
+		maxnlink = 0x7FFFFFFFFFFFFFFFLL;
+	} else if (fmttype == FMT_GNUTAR) {
+		maxino = 0xFFFFFFFFUL;
+		fakeino = 0xFFFFFFFFUL;
+		maxpath = SANELIMIT;
+		maxsize = 0x7FFFFFFFFFFFFFFFLL;
+		maxmajor = 0x7FFFFFFFFFFFFFFFLL;
+		maxminor = 0x7FFFFFFFFFFFFFFFLL;
+		maxuid = 0x7FFFFFFFFFFFFFFFLL;
+		maxgid = 0x7FFFFFFFFFFFFFFFLL;
+		maxnlink = 0x7FFFFFFFFFFFFFFFLL;
+	} else if (fmttype & TYP_PAX) {
+		maxino = 0xFFFFFFFFUL;
+		fakeino = 0xFFFFFFFFUL;
+		maxpath = SANELIMIT;
+		maxsize = 0x7FFFFFFFFFFFFFFFLL;
+		maxmajor = fmttype==FMT_SUN ? 0x7FFFFFFFFFFFFFFFLL : 07777777;
+		maxminor = fmttype==FMT_SUN ? 0x7FFFFFFFFFFFFFFFLL : 07777777;
+		maxuid = 0x7FFFFFFFFFFFFFFFLL;
+		maxgid = 0x7FFFFFFFFFFFFFFFLL;
+		maxnlink = 0x7FFFFFFFFFFFFFFFLL;
+		if (pax_oflag & PO_TIMES)
+			globrec |= PR_ATIME|PR_MTIME;
+	} else if (fmttype & TYP_BAR) {
+		maxino = 0xFFFFFFFFUL;
+		fakeino = 0xFFFFFFFFUL;
+		maxpath = 512 - SIZEOF_bar_header - 1;
+		maxsize = 077777777777LL;
+		maxrdev = 07777777;
+		maxuid = 07777777;
+		maxgid = 07777777;
+		maxnlink = 0x7FFFFFFFFFFFFFFFLL;
+		if (nwritten == 0)
+			dump_barhdr();
+	} else if (fmttype & TYP_USTAR) {
+		maxino = 0xFFFFFFFFUL;
+		fakeino = 0xFFFFFFFFUL;
+		maxpath = 256;
+		maxsize = 077777777777LL;
+		maxmajor = 07777777;
+		maxminor = 07777777;
+		maxuid = 07777777;
+		maxgid = 07777777;
+		maxnlink = 0x7FFFFFFFFFFFFFFFLL;
+	} else if (fmttype & TYP_OTAR) {
+		maxino = 0xFFFFFFFFUL;
+		fakeino = 0xFFFFFFFFUL;
+		maxpath = 99;
+		maxsize = 077777777777LL;
+		maxuid = 07777777;
+		maxgid = 07777777;
+		maxnlink = 0x7FFFFFFFFFFFFFFFLL;
+	} else if (fmttype == FMT_ZIP) {
+		maxino = 0xFFFFFFFFUL;
+		fakeino = 0xFFFFFFFFUL;
+		maxpath = 60000;
+		maxsize = 0x7FFFFFFFFFFFFFFFLL;
+		maxrdev = 0xFFFFFFFFUL;
+		maxuid = 0xFFFFFFFFUL;
+		maxgid = 0xFFFFFFFFUL;
+		maxnlink = 0xFFFFFFFFUL;
+	} else
+		abort();
+	fakedev = 0177777;
+	harddev = 1;
+	copyout(outfile);
+	if (fmttype & TYP_NCPIO)
+		lflush();
+	if (fmttype & TYP_CPIO) {
+		struct stat	st;
+
+		memset(&st, 0, sizeof st);
+		st.st_nlink = 1;
+		outfile(trailer, &st);
+	}
+	if (fmttype & TYP_TAR) {
+		char b[512];
+
+		memset(b, 0, sizeof b);
+		bwrite(b, sizeof b);
+		bwrite(b, sizeof b);
+	}
+	if (fmttype == FMT_ZIP)
+		ziptrailer();
+	bflush();
+}
+
+/*
+ * Handle a single file for -o, do sanity checks and detect hard links.
+ */
+static int
+outfile(const char *file, struct stat *st)
+{
+	uint32_t dev, ino;
+	size_t pathsz;
+
+	if ((st->st_mode&S_IFMT) == S_IFREG)
+		if (mtst.st_dev == st->st_dev && mtst.st_ino == st->st_ino)
+			return 0;
+	if (st->st_size > maxsize) {
+		msg(2, 0, "Size of %c%s%c >%lluGB. Not dumped\n",
+				sysv3 ? '<' : '"',
+				file,
+				sysv3 ? '>' : '"',
+				(maxsize+1) / (1024*1024*1024));
+		return 1;
+	}
+	if (((st->st_mode&S_IFMT)==S_IFBLK||(st->st_mode&S_IFMT)==S_IFCHR) &&
+		(maxrdev &&
+			(unsigned long long)st->st_rdev > maxrdev ||
+		maxmajor &&
+			(unsigned long long)major(st->st_rdev) > maxmajor ||
+		maxminor &&
+			(unsigned long long)minor(st->st_rdev) > maxminor)) {
+		cantsup(1, file);
+		return 1;
+	}
+	if ((unsigned long long)st->st_uid > maxuid) {
+		if (cray_eflag) {
+			cantsup(1, file);
+			return 1;
+		}
+		cantsup(0, file);
+		st->st_uid = 60001;
+		if ((st->st_mode&S_IFMT) == S_IFREG && st->st_mode & 0111)
+			st->st_mode &= ~(mode_t)S_ISUID;
+		if ((unsigned long long)st->st_gid > maxgid) {
+			st->st_gid = 60001;
+			if ((st->st_mode&S_IFMT)==S_IFREG && st->st_mode&0010)
+				st->st_mode &= ~(mode_t)S_ISGID;
+		}
+	} else if ((unsigned long long)st->st_gid > maxgid) {
+		if (cray_eflag) {
+			cantsup(1, file);
+			return 1;
+		}
+		cantsup(0, file);
+		st->st_gid = 60001;
+		if ((st->st_mode&S_IFMT) == S_IFREG && st->st_mode & 0010)
+			st->st_mode &= ~(mode_t)S_ISGID;
+	}
+	if ((pathsz = strlen(file)) > maxpath) {
+		msg(2, 0, "%s: file name too long\n", file);
+		return 1;
+	}
+	/*
+	 * Detect hard links and compute fake inode counts. The mechanism
+	 * is as follows: If a file has more than one link, a fake device
+	 * number starting at one is used for its device, and a fake inode
+	 * number is used starting at one too.
+	 *
+	 * The information on links of directories is useless, so it is
+	 * dropped and handled like a file with a single link only: Fake
+	 * devices are allocated just below the format's limit, fake
+	 * i-nodes the same.
+	 *
+	 * This way even the binary cpio format can have up to ~4G files.
+	 */
+	if (maxino && st->st_nlink > 1 && (st->st_mode&S_IFMT) != S_IFDIR) {
+		struct dslot *ds, *dp;
+		struct islot *ip;
+
+		dev = 1;
+		ds = devices;
+		dp = NULL;
+nextdev:
+		for (; ds; dp = ds, ds = ds->d_nxt, dev++ /* see below! */)
+			if (ds->d_dev == st->st_dev)
+				break;
+		if (markeddevs && marked(dev)) {
+			dev++;
+			goto nextdev;
+		}
+		if (dev >= fakedev)
+			msg(4, 1, "Too many devices in archive, exiting\n");
+		if (ds == NULL) {
+			ds = scalloc(1, sizeof *ds);
+			ds->d_dev = st->st_dev;
+			ds->d_fake = dev;
+			if (devices == NULL)
+				devices = ds;
+			else
+				dp->d_nxt = ds;
+		}
+		harddev = dev;
+		if ((ip = ifind(st->st_ino, &ds->d_isl)) == NULL) {
+			if (ds->d_cnt >= maxino) {
+				/* corresponds to for loop above */
+				dev++, dp = ds, ds = ds->d_nxt;
+				goto nextdev;
+			}
+			ip = scalloc(1, sizeof *ip);
+			ip->i_ino = st->st_ino;
+			ip->i_fino = ++ds->d_cnt;
+			ip->i_nlk = st->st_nlink;
+			if (fmttype & TYP_TAR)
+				ip->i_name = sstrdup(file);
+			if (fmttype & TYP_NCPIO) {
+				ip->i_st = smalloc(sizeof *ip->i_st);
+				*ip->i_st = *st;
+			}
+			iput(ip, &ds->d_isl);
+		}
+		ino = ip->i_fino;
+		if (fmttype & TYP_NCPIO) {
+			/*
+			 * In SVR4 ascii cpio format, files with multiple
+			 * links are stored with a zero size except for the
+			 * last link, which contains the actual file content.
+			 * As one cannot know which is the last link in
+			 * advance since some links may be outside the
+			 * archive content, all links have to be collected
+			 * and written out at once.
+			 */
+			struct ilink *il, *ik;
+
+			switch (ip->i_nlk) {
+			case 1:
+				/*
+				 * This was the last link to a file. Write
+				 * all previous links and break to write
+				 * the actual file content. Free the pointers
+				 * in islot; islot remains within the tree
+				 * with a remaining link count of zero.
+				 */
+				ip->i_nlk--;
+				free(ip->i_st);
+				ip->i_st = NULL;
+				for (il = ip->i_lnk, ik = NULL; il;
+						ik = il, il = il->l_nxt,
+						ik ? free(ik), 0 : 0) {
+					errcnt += addfile(il->l_nam, st,
+							dev, ino, 1, 0);
+					free(il->l_nam);
+				}
+				break;
+			case 0:
+				/*
+				 * This file got a link during operation, or
+				 * -L was specified and we encountered a link
+				 * more than once. Start with a fresh link
+				 * count again.
+				 */
+				ip->i_nlk = st->st_nlink;
+				ip->i_lnk = NULL;
+				ip->i_st = smalloc(sizeof *ip->i_st);
+				*ip->i_st = *st;
+				/*FALLTHRU*/
+			default:
+				/*
+				 * There are more links to this file. Store
+				 * only the name and return.
+				 */
+				ip->i_nlk--;
+				if (ip->i_lnk) {
+					for (il = ip->i_lnk; il->l_nxt;
+							il = il->l_nxt);
+					il->l_nxt = scalloc(1,sizeof*il->l_nxt);
+					il = il->l_nxt;
+				} else {
+					ip->i_lnk = scalloc(1,sizeof*ip->i_lnk);
+					il = ip->i_lnk;
+				}
+				il->l_nam = smalloc(pathsz + 1);
+				strcpy(il->l_nam, file);
+				return 0;
+			}
+		} else if (fmttype & TYP_TAR) {
+			if (strcmp(ip->i_name, file))
+				return addfile(file, st, dev, ino, 1,
+						ip->i_name);
+		}
+	} else {	/* single-linked or directory */
+		dev = fakedev;
+		while (markeddevs && marked(dev))
+			dev--;
+		if ((ino = fakeino--) == 0) {
+			if (--dev <= harddev)
+				msg(4, 1, "Too many devices in archive, "
+						"exiting\n");
+			fakedev = dev;
+			ino = maxino;
+			fakeino = ino - 1;
+		}
+	}
+	return addfile(file, st, dev, ino, 0, 0);
+}
+
+/*
+ * Add a single file to the archive with -o.
+ */
+static int
+addfile(const char *realfile, struct stat *st,
+		uint32_t dev, uint32_t ino, int zerolink, const char *linkname)
+{
+	union bincpio bc;
+	int fd = -1;
+	long long size;
+	int pad, i;
+	ssize_t rsz = 0, wsz = 0, hsz, fsz, psz;
+	long long remsz, relative, nlink;
+	long long Kbase = 0, Krest = 0, Ksize = 0;
+	struct hdr_cpio	K2hdr;
+	uint32_t	crc = 0;
+	long long	csize = 0;
+	char	*file;
+	char	*symblink = NULL;
+	int	failure = 1;
+
+	file = sstrdup(realfile);
+	if (pax != PAX_TYPE_CPIO && strcmp(file, trailer)) {
+		size_t	junk = 0;
+		if (pax_sflag && pax_sname(&file, &junk) == 0)
+			goto cleanup;
+		if (rflag && rname(&file, &junk) == 0)
+			goto cleanup;
+	}
+	fsz = strlen(file);
+	relative = nwritten;
+	memset(bc.data, 0, sizeof bc.data);
+	if (fmttype == FMT_PAX && pax_oflag & PO_LINKDATA &&
+			(st->st_mode&S_IFMT) == S_IFREG)
+		size = st->st_size;
+	else if (zerolink)
+		size = 0;
+	else if ((st->st_mode&S_IFMT) == S_IFREG)
+		size = st->st_size;
+	else if ((st->st_mode&S_IFMT) == S_IFLNK) {
+		i = st->st_size ? st->st_size : PATH_MAX;
+		symblink = smalloc(i+1);
+		if ((size = readlink(realfile, symblink, i)) < 0) {
+			emsg(3, "Cannot read symbolic link \"%s\"", realfile);
+			goto cleanup;
+		}
+		symblink[size] = '\0';
+	} else
+		size = 0;
+	nlink = ((unsigned long long)st->st_nlink>maxnlink ?
+			maxnlink : st->st_nlink);
+	if (fmttype & TYP_NCPIO) {
+		long	size1;
+		if (fmttype & TYP_SCO && size >= mag_sco) {
+			char	*ofile = file;
+			size1 = mag_sco;
+			fsz += 22;
+			file = smalloc(fsz + 1);
+			snprintf(file, fsz + 1, "%s%csize=%016llx",
+					ofile, 0, size);
+			free(ofile);
+		} else
+			size1 = size;
+		pad = 4;
+		sprintf(bc.data, "%*.*s%08lx%08lx%08lx%08lx%08lx%08lx"
+				"%08lx%08lx%08lx%08lx%08lx%08lx%08lx",
+			(int)(fmttype&TYP_CRC? sizeof mag_crc:sizeof mag_asc),
+			(int)(fmttype&TYP_CRC? sizeof mag_crc:sizeof mag_asc),
+			fmttype & TYP_CRC ? mag_crc : mag_asc,
+			(long)ino & ECUT,
+			(long)st->st_mode & ECUT,
+			(long)st->st_uid & ECUT,
+			(long)st->st_gid & ECUT,
+			(long)nlink & ECUT,
+			(long)st->st_mtime & ECUT,
+			(long)size1 & ECUT,
+			(long)major(dev) & ECUT,
+			(long)minor(dev) & ECUT,
+			(long)major(st->st_rdev) & ECUT,
+			(long)minor(st->st_rdev) & ECUT,
+			(long)++fsz,
+			0L);
+		hsz = SIZEOF_Exp_cpio_hdr;
+		if ((psz = (hsz + fsz) % pad) != 0)
+			psz = pad - psz;
+	} else if (fmttype == FMT_ODC) {
+		pad = 1;
+		sprintf(bc.data, "%*.*s%06lo%06lo%06lo%06lo%06lo%06lo%06lo"
+				"%011lo%06lo%011lo",
+			(int)sizeof mag_odc, (int)sizeof mag_odc, mag_odc,
+			(long)dev & OCUT,
+			(long)ino & OCUT,
+			(long)st->st_mode & OCUT,
+			(long)st->st_uid & OCUT,
+			(long)st->st_gid & OCUT,
+			(long)nlink & OCUT,
+			(long)st->st_rdev & OCUT,
+			(long)st->st_mtime,
+			(long)++fsz,
+			(long)size);
+		hsz = SIZEOF_c_hdr;
+		if ((psz = (hsz + fsz) % pad) != 0)
+			psz = pad - psz;
+	} else if (fmttype == FMT_DEC) {
+		pad = 1;
+		sprintf(bc.data, "%*.*s%06lo%06lo%06lo%06lo%06lo%06lo"
+				"%08lo%08lo%011lo%06lo%011lo",
+			(int)sizeof mag_odc, (int)sizeof mag_odc, mag_odc,
+			(long)dev & OCUT,
+			(long)ino & OCUT,
+			(long)st->st_mode & OCUT,
+			(long)st->st_uid & OCUT,
+			(long)st->st_gid & OCUT,
+			(long)nlink & OCUT,
+			(long)major(st->st_rdev) & 077777777,
+			(long)minor(st->st_rdev) & 077777777,
+			(long)st->st_mtime,
+			(long)++fsz,
+			(long)size);
+		hsz = SIZEOF_d_hdr;
+		if ((psz = (hsz + fsz) % pad) != 0)
+			psz = pad - psz;
+	} else if (fmttype & TYP_BINARY) {
+		/*
+		 * To avoid gcc's stupid 'comparison is always false due to
+		 * limited range of data type' warning.
+		 */
+		unsigned long long	gcccrap;
+		pad = 2;
+		if (fmttype & TYP_BE) {
+			be16p(mag_bin, bc.Hdr.c_magic);
+			be16p(dev, bc.Hdr.c_dev);
+			be16p(ino, bc.Hdr.c_ino);
+			be16p(st->st_mode, bc.Hdr.c_mode);
+			be16p(st->st_uid, bc.Hdr.c_uid);
+			be16p(st->st_gid, bc.Hdr.c_gid);
+			be16p(nlink, bc.Hdr.c_nlink);
+			be16p(st->st_rdev, bc.Hdr.c_rdev);
+			be32p(st->st_mtime, bc.Hdr.c_mtime);
+			be16p(++fsz, bc.Hdr.c_namesize);
+		} else {
+			le16p(mag_bin, bc.Hdr.c_magic);
+			le16p(dev, bc.Hdr.c_dev);
+			le16p(ino, bc.Hdr.c_ino);
+			le16p(st->st_mode, bc.Hdr.c_mode);
+			le16p(st->st_uid, bc.Hdr.c_uid);
+			le16p(st->st_gid, bc.Hdr.c_gid);
+			le16p(nlink, bc.Hdr.c_nlink);
+			le16p(st->st_rdev, bc.Hdr.c_rdev);
+			me32p(st->st_mtime, bc.Hdr.c_mtime);
+			le16p(++fsz, bc.Hdr.c_namesize);
+		}
+		if (fmttype & TYP_SGI && size > 0x7FFFFFFFLL) {
+			Krest = size & 0x7FFFFFFFLL;
+			Kbase = size - Krest;
+			Ksize = 0x100000000LL - (Kbase >> 31);
+			if (fmttype & TYP_BE)
+				be32p(Ksize, bc.Hdr.c_filesize);
+			else
+				me32p(Ksize, bc.Hdr.c_filesize);
+			K2hdr = bc.Hdr;
+			if (fmttype & TYP_BE)
+				be32p(Krest, K2hdr.c_filesize);
+			else
+				me32p(Krest, K2hdr.c_filesize);
+		} else {
+			if (fmttype & TYP_BE)
+				be32p(size, bc.Hdr.c_filesize);
+			else
+				me32p(size, bc.Hdr.c_filesize);
+		}
+		if (fmttype & TYP_SGI &&
+				(((st->st_mode&S_IFMT) == S_IFBLK ||
+				 (st->st_mode&S_IFMT) == S_IFCHR) &&
+				((unsigned long long)major(st->st_rdev)>0xFF ||
+				 (unsigned long long)minor(st->st_rdev)>0xFF) ||
+				(gcccrap = st->st_rdev) > 0177777)) {
+			uint32_t	rdev;
+			rdev = (minor(st->st_rdev) & 0x0003FFFF) +
+				((major(st->st_rdev)<<18) & 0xFFFC0000);
+			if (fmttype & TYP_BE) {
+				be16p(0xFFFF, bc.Hdr.c_rdev);
+				be32p(rdev, bc.Hdr.c_filesize);
+			} else {
+				le16p(0xFFFF, bc.Hdr.c_rdev);
+				me32p(rdev, bc.Hdr.c_filesize);
+			}
+		}
+		hsz = SIZEOF_hdr_cpio;
+		psz = (hsz + fsz) % 2;
+	} else if (fmttype & TYP_CRAY) {
+		int	diff5 = fmttype==FMT_CRAY5 ? CRAY_PARAMSZ : 0;
+		mode_t	mo;
+		pad = 1;
+		be64p(mag_bin, bc.Crayhdr.C_magic);
+		be64p(dev, bc.Crayhdr.C_dev);
+		be64p(ino, bc.Crayhdr.C_ino);
+		if ((st->st_mode&S_IFMT) == S_IFLNK)	/* non-standard */
+			mo = st->st_mode&07777|0130000;	/* S_IFLNK on Cray */
+		else
+			mo = st->st_mode;
+		be64p(mo, bc.Crayhdr.C_mode);
+		be64p(st->st_uid, bc.Crayhdr.C_uid);
+		be64p(st->st_gid, bc.Crayhdr.C_gid);
+		be64p(nlink, bc.Crayhdr.C_nlink);
+		be64p(st->st_rdev, bc.Crayhdr.C_rdev);
+		be64p(st->st_mtime, bc.Crayhdr.C_mtime - diff5);
+		be64p(++fsz, bc.Crayhdr.C_namesize - diff5);
+		be64p(size, bc.Crayhdr.C_filesize - diff5);
+		hsz = SIZEOF_cray_hdr - diff5;
+		psz = 0;
+	} else if (fmttype & TYP_BAR) {
+		int	c, n = 0;
+		pad = 512;
+		sprintf(bc.Bdr.b_mode, "%7.7o",(int)st->st_mode&(07777|S_IFMT));
+		sprintf(bc.Bdr.b_uid, "%7.7lo", (long)st->st_uid);
+		sprintf(bc.Bdr.b_gid, "%7.7lo", (long)st->st_gid);
+		sprintf(bc.Bdr.b_size, "%11.11llo",
+				(st->st_mode&S_IFMT) == S_IFREG && !zerolink ?
+				(long long)st->st_size&077777777777LL : 0LL);
+		sprintf(bc.Bdr.b_mtime, "%11.11lo", (long)st->st_mtime);
+		sprintf(bc.Bdr.b_rdev, "%7.7lo", (long)st->st_rdev);
+		strcpy(&bc.data[SIZEOF_bar_header], file);
+		c = tlflag(st);
+		if (zerolink == 0) {
+			bc.Bdr.b_linkflag = c;
+			if (c == '2') {
+				strncpy(&bc.data[SIZEOF_bar_header+fsz+1],
+						symblink,
+						512-SIZEOF_bar_header-fsz);
+				n = size;
+			}
+		} else {
+			bc.Bdr.b_linkflag = '1';
+			strncpy(&bc.data[SIZEOF_bar_header+fsz+1], linkname,
+					512-SIZEOF_bar_header-fsz-1);
+			n = strlen(linkname);
+		}
+		if (n > 512-SIZEOF_bar_header-fsz-1) {
+			msg(3, 0, "%s: linked name too long\n", realfile);
+			goto cleanup;
+		}
+		bchksum(&bc);
+		hsz = 512;
+		psz = 0;
+		fsz = 0;
+	} else if (fmttype & TYP_TAR) {
+		const char	*cp;
+		int	c;
+		/*
+		 * Many SVR4 cpio derivatives expect the mode field
+		 * to contain S_IFMT bits. The meaning of these bits
+		 * in the mode field of the ustar header is left
+		 * unspecified by IEEE Std 1003.1, 1996, 10.1.1.
+		 */
+		int	mmask = fmttype == FMT_USTAR || fmttype == FMT_PAX ?
+				07777 : 07777|S_IFMT;
+
+		paxrec = globrec;
+		pad = 512;
+		if (tmkname(&bc.Tdr, file) != 0)
+			goto cleanup;
+		sprintf(bc.Tdr.t_mode, "%7.7o", (int)st->st_mode & mmask);
+		if (fmttype == FMT_GNUTAR && st->st_uid > 07777777) {
+			be64p(st->st_uid, bc.Tdr.t_uid);
+			bc.Tdr.t_uid[0] |= 0200;
+		} else {
+			sprintf(bc.Tdr.t_uid, "%7.7lo",
+					(long)st->st_uid&07777777);
+			if (fmttype & TYP_PAX && st->st_uid > 07777777)
+				paxrec |= PR_UID;
+		}
+		if (fmttype == FMT_GNUTAR && st->st_gid > 07777777) {
+			be64p(st->st_gid, bc.Tdr.t_gid);
+			bc.Tdr.t_gid[0] |= 0200;
+		} else {
+			sprintf(bc.Tdr.t_gid, "%7.7lo",
+					(long)st->st_gid&07777777);
+			if (fmttype & TYP_PAX && st->st_gid > 07777777)
+				paxrec |= PR_GID;
+		}
+		if (fmttype == FMT_GNUTAR && (st->st_mode&S_IFMT) == S_IFREG &&
+				st->st_size > 077777777777LL && !zerolink) {
+			bc.Tdr.t_size[0] = '\200';
+			be64p(st->st_size, &bc.Tdr.t_size[4]);
+		} else {
+			sprintf(bc.Tdr.t_size, "%11.11llo",
+				(st->st_mode&S_IFMT) == S_IFREG &&
+				(!zerolink || fmttype == FMT_PAX &&
+				 	pax_oflag & PO_LINKDATA) ?
+				(long long)st->st_size&077777777777LL : 0LL);
+			if (fmttype & TYP_PAX &&
+					(st->st_mode&S_IFMT) == S_IFREG &&
+					st->st_size > 077777777777LL &&
+					(!zerolink || fmttype == FMT_PAX &&
+					 	pax_oflag & PO_LINKDATA))
+				paxrec |= PR_SIZE;
+		}
+		sprintf(bc.Tdr.t_mtime, "%11.11lo", (long)st->st_mtime);
+		if ((c = tlflag(st)) < 0) {
+			if ((st->st_mode&S_IFMT) != S_IFDIR) {
+				msg(2, 0, "%s is not a file. Not dumped\n",
+						realfile);
+				errcnt++;
+			} else
+				failure = 0;
+			goto cleanup;
+		}
+		if (zerolink == 0) {
+			bc.Tdr.t_linkflag = c;
+			if (c == '2') {
+				if (tmklink(&bc.Tdr, symblink) != 0)
+					goto cleanup;
+			}
+		} else {
+			bc.Tdr.t_linkflag = '1';
+			if (tmklink(&bc.Tdr, linkname) != 0)
+				goto cleanup;
+		}
+		if (fmttype & TYP_USTAR) {
+			if (fmttype == FMT_GNUTAR)
+				strcpy(bc.Tdr.t_magic, mag_gnutar);
+			else {
+				strcpy(bc.Tdr.t_magic, mag_ustar);
+				bc.Tdr.t_version[0] = bc.Tdr.t_version[1] = '0';
+			}
+			if ((cp = getuser(st->st_uid)) != NULL)
+				sprintf(bc.Tdr.t_uname, "%.31s", cp);
+			else
+				msg(1, 0, "could not get passwd information "
+						"for %s\n", realfile);
+			if ((cp = getgroup(st->st_gid)) != NULL)
+				sprintf(bc.Tdr.t_gname, "%.31s", cp);
+			else
+				msg(1, 0, "could not get group information "
+						"for %s\n", realfile);
+			if (fmttype == FMT_GNUTAR &&
+					(unsigned long long)major(st->st_rdev)
+					> 077777777) {
+				be64p(major(st->st_rdev), bc.Tdr.t_devmajor);
+				bc.Tdr.t_devmajor[0] |= 0200;
+			} else {
+				if (fmttype == FMT_SUN &&
+					(unsigned long long)major(st->st_rdev)
+						> 077777777 &&
+						((st->st_mode&S_IFMT)==S_IFBLK||
+						 (st->st_mode&S_IFMT)==S_IFCHR))
+					paxrec |= PR_SUN_DEVMAJOR;
+				sprintf(bc.Tdr.t_devmajor, "%7.7o",
+					(int)major(st->st_rdev)&07777777);
+			}
+			if (fmttype == FMT_GNUTAR &&
+					(unsigned long long)minor(st->st_rdev)
+					> 077777777) {
+				be64p(minor(st->st_rdev), bc.Tdr.t_devminor);
+				bc.Tdr.t_devminor[0] |= 0200;
+			} else {
+				if (fmttype == FMT_SUN &&
+					(unsigned long long)minor(st->st_rdev)
+						> 077777777 &&
+						((st->st_mode&S_IFMT)==S_IFBLK||
+						 (st->st_mode&S_IFMT)==S_IFCHR))
+					paxrec |= PR_SUN_DEVMINOR;
+				sprintf(bc.Tdr.t_devminor, "%7.7o",
+					(int)minor(st->st_rdev)&07777777);
+			}
+		}
+		tchksum(&bc);
+		hsz = 512;
+		psz = 0;
+		fsz = 0;
+	} else if (fmttype == FMT_ZIP) {
+		pad = 1;
+		memcpy(bc.Zdr.z_signature, mag_zipsig, sizeof mag_zipsig);
+		bc.Zdr.z_version[0] = 10;
+		mkdostime(st->st_mtime, bc.Zdr.z_modtime, bc.Zdr.z_moddate);
+		if ((st->st_mode&S_IFMT) == S_IFREG ||
+				(st->st_mode&S_IFMT) == S_IFLNK) {
+			le32p(size, bc.Zdr.z_csize);
+			le32p(size, bc.Zdr.z_nsize);
+			csize = size;
+		}
+		le16p(fsz, bc.Zdr.z_namelen);
+		le16p(SIZEOF_zextra_cp, bc.Zdr.z_extralen);
+		hsz = SIZEOF_zip_header;
+		psz = 0;
+	} else
+		abort();
+	/*
+	 * Start writing the file to the archive.
+	 */
+	if ((st->st_mode&S_IFMT) == S_IFREG && st->st_size != 0 &&
+			(zerolink == 0 || fmttype == FMT_PAX &&
+			 	pax_oflag & PO_LINKDATA)) {
+		char	*buf;
+		size_t	bufsize;
+		int	readerr = 0;
+
+		if ((fd = open(realfile, O_RDONLY)) < 0) {
+			if (sysv3 < 0)
+				msg(0, 0, "< %s > ?\n", realfile);
+			else if (sysv3 > 0)
+				fprintf(stderr, "<%s> ?\n", realfile);
+			else
+				msg(0, 0, "\"%s\" ?\n", realfile);
+			goto cleanup;
+		}
+		if (fmttype == FMT_ZIP) {
+			if (zipwrite(fd, file, st, &bc, fsz, dev, ino,
+						&crc, &csize) < 0)
+				goto cleanup2;
+			goto done;
+		}
+		if (fmttype & TYP_CRC)
+			if (sum(fd, realfile, st, bc.Edr.E_chksum) < 0)
+				goto cleanup2;
+		if (fmttype & TYP_PAX && paxrec != PR_NONE)
+			wrpax(file, symblink?symblink:linkname, st);
+		bwrite(bc.data, hsz);
+		if (fsz)
+			bwrite(file, fsz);
+		if (psz)
+			bwrite(&bc.data[hsz], psz);
+		if (Kbase)
+			remsz = Kbase;
+		else
+			remsz = st->st_size;
+		getbuf(&buf, &bufsize, st->st_blksize);
+	again:	while (remsz > 0) {
+			if (fd < 0 || (rsz = read(fd, &buf[wsz],
+							bufsize - wsz)) < 0) {
+				if (readerr == 0) {
+					emsg(3, "Cannot read \"%s\"", realfile);
+					if (fd >= 0)
+						errcnt++;
+					readerr = 1;
+				}
+				if (fd >= 0 && lseek(fd, bufsize - wsz,
+							SEEK_CUR) < 0) {
+					close(fd);
+					fd = -1;
+				}
+				rsz = bufsize - wsz;
+				if (rsz > remsz)
+					rsz = remsz;
+				memset(&buf[wsz], 0, rsz);
+			}
+			if (rsz > remsz)
+				rsz = remsz;
+			wsz += rsz;
+			remsz -= rsz;
+			bwrite(buf, wsz);
+			memset(buf, 0, wsz);
+			size = wsz;
+			wsz = 0;
+		}
+		wsz = size;
+		if (Kbase) {
+			if ((i = Ksize % pad) != 0)
+				bwrite(&bc.data[hsz], i);
+			bwrite((char *)&K2hdr, hsz);
+			if (fsz)
+				bwrite(file, fsz);
+			if (psz)
+				bwrite(&bc.data[hsz], psz);
+			remsz = Krest;
+			Kbase = 0;
+			wsz = 0;
+			goto again;
+		} else if (Ksize)
+			wsz = Krest;
+	} else if ((fmttype == FMT_ZIP || fmttype & TYP_CPIO) &&
+			(st->st_mode&S_IFMT) == S_IFLNK) {
+		wsz = size;
+		if (fmttype == FMT_ZIP) {
+			crc = zipcrc(0, (unsigned char *)symblink, wsz);
+			le32p(crc, bc.Zdr.z_crc32);
+			bwrite(bc.data, SIZEOF_zip_header);
+			bwrite(file, fsz);
+			zipwxtra(file, st, dev, ino);
+			bwrite(symblink, wsz);
+		} else {
+			bwrite(bc.data, hsz);
+			if (fsz)
+				bwrite(file, fsz);
+			if (psz)
+				bwrite(&bc.data[hsz], psz);
+			bwrite(symblink, wsz);
+		}
+	} else {
+		if (fmttype & TYP_PAX && paxrec != PR_NONE)
+			wrpax(file, symblink?symblink:linkname, st);
+		bwrite(bc.data, hsz);
+		if (fsz)
+			bwrite(file, fsz);
+		if (psz)
+			bwrite(&bc.data[hsz], psz);
+		if (fmttype == FMT_ZIP)
+			zipwxtra(file, st, dev, ino);
+	}
+done:	if (fmttype == FMT_ZIP) {
+		zipdefer(file, st, relative, crc, csize, &bc.Zdr);
+	}
+	if ((i = wsz % pad) != 0)
+		bwrite(&bc.data[hsz], pad - i);
+	if (vflag && strcmp(file, trailer))
+		fprintf(stderr, "%s\n", file);
+	else if (Vflag)
+		prdot(0);
+	failure = 0;
+cleanup2:
+	if ((st->st_mode&S_IFMT) == S_IFREG) {
+		if (fd >= 0)
+			close(fd);
+		if (aflag)
+			errcnt += rstime(realfile, st, "access");
+	}
+cleanup:
+	free(file);
+	free(symblink);
+	return failure;
+}
+
+/*
+ * Flush a SVR4 cpio format inode tree for -o.
+ */
+static void
+iflush(struct islot *ip, uint32_t dev)
+{
+	if (ip == inull)
+		return;
+	iflush(ip->i_lln, dev);
+	iflush(ip->i_rln, dev);
+	if (ip->i_nlk > 0 && ip->i_st) {
+		struct ilink *il;
+
+		for (il = ip->i_lnk; il->l_nxt; il = il->l_nxt)
+			errcnt += addfile(il->l_nam, ip->i_st,
+					dev, ip->i_fino, 1, 0);
+		errcnt += addfile(il->l_nam, ip->i_st, dev, ip->i_fino, 0, 0);
+	}
+}
+
+/*
+ * Flush the SVR4 cpio link forest for -o.
+ */
+static void
+lflush(void)
+{
+	struct dslot *ds;
+
+	for (ds = devices; ds; ds = ds->d_nxt)
+		iflush(ds->d_isl, ds->d_fake);
+}
+
+int
+setfmt(char *s)
+{
+	int	i, j;
+
+	struct {
+		const char	*ucs;
+		const char	*lcs;
+		int	type;
+		int	bits;
+	} fs[] = {
+		{ "NEWC",	"newc",		FMT_ASC,	00 },
+		{ "SCO",	"sco",		FMT_SCOASC,	00 },
+		{ "CRC",	"crc",		FMT_CRC,	00 },
+		{ "SCOCRC",	"scocrc",	FMT_SCOCRC,	00 },
+		{ "ODC",	"odc",		FMT_ODC,	00 },
+		{ "DEC",	"dec",		FMT_DEC,	00 },
+		{ "BIN",	"bin",		FMT_NONE,	00 },
+		{ "BBS",	"bbs",		TYP_BE,		00 },
+		{ "SGI",	"sgi",		FMT_SGIBE,	00 },
+		{ "CRAY",	"cray",		FMT_CRAY,	00 },
+		{ "CRAY5",	"cray5",	FMT_CRAY5,	00 },
+		{ "TAR",	"tar",		FMT_TAR,	00 },
+		{ "USTAR",	"ustar",	FMT_USTAR,	00 },
+		{ "PAX:",	"pax:",		FMT_PAX,	00 },
+		{ "SUN",	"sun",		FMT_SUN,	00 },
+		{ "GNU",	"gnu",		FMT_GNUTAR,	00 },
+		{ "OTAR",	"otar",		FMT_OTAR,	00 },
+		{ "BAR",	"bar",		FMT_BAR,	00 },
+		{ "ZIP:",	"zip:",		FMT_ZIP,	00 },
+		{ NULL,		NULL,		0,		00 }
+	};
+	for (i = 0; fs[i].ucs; i++) {
+		for (j = 0; s[j] &&
+				(s[j] == fs[i].ucs[j] || s[j] == fs[i].lcs[j]);
+				j++)
+			if (fs[i].ucs[j] == ':')
+				break;
+		if (s[j] == '\0' &&
+				(fs[i].ucs[j] == '\0' || fs[i].ucs[j] == ':') ||
+				s[j] == ':' && fs[i].ucs[j] == ':') {
+			fmttype = fs[i].type;
+			if (fmttype == FMT_ZIP && s[j] == ':') {
+#if	USE_ZLIB
+				if (strcmp(&s[j+1], "en") == 0)
+					zipclevel = 00;
+				else if (strcmp(&s[j+1], "ex") == 0)
+					zipclevel = 01;
+				else if (strcmp(&s[j+1], "ef") == 0)
+					zipclevel = 02;
+				else if (strcmp(&s[j+1], "es") == 0)
+					zipclevel = 03;
+				else
+#endif	/* USE_ZLIB */
+				if (strcmp(&s[j+1], "e0") == 0)
+					zipclevel = 04;
+				else
+#if	USE_BZLIB
+				if (strcmp(&s[j+1], "bz2") == 0)
+					zipclevel = 07;
+				else
+#endif	/* USE_BZLIB */
+					continue;
+			} else if (fmttype == FMT_NONE)
+				fmttype = bigendian() ? FMT_BINBE : FMT_BINLE;
+			else if (fmttype == TYP_BE)
+				fmttype = bigendian() ? FMT_BINLE : FMT_BINBE;
+			else if (fmttype == FMT_PAX && s[j] == ':') {
+				if (pax_options(&s[j+1], 0) < 0)
+					continue;
+			}
+			return 0;
+		}
+	}
+	msg(3, 0, "Invalid header \"%s\" specified.\n", s);
+	return -1;
+}
+
+static int
+bigendian(void)
+{
+	union {
+		char	u_c[2];
+		int16_t	u_i;
+	} u;
+	u.u_i = 1;
+	return u.u_c[1] == 1;
+}
+
+int
+setreassign(const char *s)
+{
+	struct passwd	*pwd;
+	int	val = 0;
+
+	if (myuid != 0) {
+		msg(3, 0, "R option only valid for super-user.\n");
+		val = -1;
+	}
+	if ((pwd = getpwnam(s)) == NULL) {
+		msg(3, 0, "\"%s\" is not a valid user id\n", s);
+		val = -1;
+	} else {
+		Ruid = pwd->pw_uid;
+		Rgid = pwd->pw_gid;
+	}
+	return val;
+}
+
+void *
+srealloc(void *m, size_t n)
+{
+	if ((m = realloc(m, n)) == NULL) {
+		write(2, "Out of memory.\n", 15);
+		_exit(sysv3 ? 2 : 3);
+	}
+	return m;
+}
+
+void *
+smalloc(size_t n)
+{
+	return srealloc(NULL, n);
+}
+
+void *
+scalloc(size_t nmemb, size_t size)
+{
+	void	*vp;
+
+	if ((vp = calloc(nmemb, size)) == NULL) {
+		write(2, "Out of memory.\n", 15);
+		_exit(sysv3 ? 2 : 3);
+	}
+	return vp;
+}
+
+void *
+svalloc(size_t n, int force)
+{
+	static long	pagesize;
+	void	*vp;
+
+	if (pagesize == 0)
+		if ((pagesize = sysconf(_SC_PAGESIZE)) < 0)
+			pagesize = 4096;
+	if ((vp = memalign(pagesize, n)) == NULL && force) {
+		write(2, "Out of memory.\n", 15);
+		_exit(sysv3 ? 2 : 3);
+	}
+	return vp;
+}
+
+/*
+ * A single static buffer is used for intermediate copying from file
+ * data to the tape buffer and vice versa, for creating checksums, and
+ * for data transfer with -p.
+ */
+static void
+getbuf(char **bufp, size_t *sizep, size_t best)
+{
+	static char	*buf;
+	static size_t	size;
+
+	if (size != best) {
+		if (buf)
+			free(buf);
+		size = best;
+		if (size == 0 || (buf = svalloc(size, 0)) == NULL)
+			buf = svalloc(size = 512, 1);
+	}
+	*bufp = buf;
+	*sizep = size;
+}
+
+static void
+sevprnt(int sev)
+{
+	if (printsev) switch (sev) {
+	case 1:
+		fprintf(stderr, "INFORM: ");
+		break;
+	case 2:
+		fprintf(stderr, "WARNING: ");
+		break;
+	case 3:
+		fprintf(stderr, "ERROR: ");
+		break;
+	case 4:
+		fprintf(stderr, "HALT: ");
+		break;
+	}
+}
+
+void
+msg(int sev, int err, const char *fmt, ...)
+{
+	va_list	ap;
+
+	/*
+	 * The error message should appear near the file it refers to.
+	 */
+	if (tflag)
+		fflush(stdout);
+	else if (Vflag)
+		prdot(1);
+	if (sysv3 >= 0 && sev >= (printsev ? 0 : -1))
+		fprintf(stderr, "%s: ", progname);
+	sevprnt(sev);
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	if (err > 0)
+		done(err);
+	else if (err == -2) {
+		if (sysv3)
+			done(1);
+		usage();
+	}
+}
+
+void
+emsg(int sev, const char *fmt, ...)
+{
+	char	_fmt[60];
+	int	i, fl = sev & 030, n;
+	va_list	ap;
+
+	sev &= ~030;
+	i = errno;
+	if (tflag)
+		fflush(stdout);
+	else if (Vflag)
+		prdot(1);
+	fprintf(stderr, "%s: ", progname);
+	sevprnt(sev);
+	va_start(ap, fmt);
+	if (sysv3) {
+		if (fmt[(n=strlen(fmt))-1] == '"' && fmt[n-2] == 's' &&
+				fmt[n-3] == '%' && fmt[n-4] == '"' &&
+				n < sizeof _fmt) {
+			strcpy(_fmt, fmt);
+			_fmt[n-1] = '>';
+			_fmt[n-4] = '<';
+			fmt = _fmt;
+		}
+	}
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	if (sysv3 > 0 && sev >= 0 && fl & 010)
+		fprintf(stderr, "\n\t%s\n", strerror(i));
+	else if (sysv3 < 0) {
+		if (fl & 020)
+			putc('\n', stderr);
+		else
+			fprintf(stderr, " (errno:%d)\n", i);
+	} else
+		fprintf(stderr, ", errno %d, %s\n", i, strerror(i));
+}
+
+static void
+prdot(int flush)
+{
+	static int	column;
+
+	if (flush && column != 0 || column >= 50) {
+		write(action == 'o' && !Oflag ? 2 : 1, "\n", 1);
+		column = 0;
+	}
+	if (!flush) {
+		write(action == 'o' && !Oflag ? 2 : 1, ".", 1);
+		column++;
+	}
+}
+
+/*
+ * Ask the user for new media if applicable, or exit.
+ */
+static void
+newmedia(int err)
+{
+	static int	mediacnt = 1;
+	static char answer[PATH_MAX+1];
+	const char	*mesf = action == 'i' ?
+		(Iflag && !sysv3 ? Iflag : "input") :
+		(Oflag && !sysv3 ? Oflag : "output");
+	char c;
+	int i, j;
+
+	if (mfl == 0 && close(mt) < 0) {
+		emsg(3, "Close error on \"%s\"", mesf);
+		errcnt++;
+	}
+	mfl = -1;
+	if ((mtst.st_mode&S_IFMT)!=S_IFCHR && (mtst.st_mode&S_IFMT)!=S_IFBLK ||
+			Dflag) {
+		if (action == 'o') {
+			switch (err) {
+			case 0:
+				break;
+			case EFBIG:
+				msg(3, 0, "ulimit reached for output file.\n");
+				break;
+			case ENOSPC:
+				msg(3, 0, "No space left for output file.\n");
+				break;
+			default:
+				msg(3, 0, "I/O error - cannot continue, "
+						"errno %d, %s\n",
+						err, strerror(err));
+			}
+		}
+		return;
+	}
+	if (err == ENOSPC || err == ENXIO || err == 0)
+		msg(-2, 0, sysv3 ? "Reached end of medium on %s.\a\n" :
+				"End of medium on \"%s\".\a\n", mesf);
+	else
+		msg(3, 0, "I/O error on \"%s\", errno %d, %s\a\n", mesf,
+				err, strerror(err));
+	mediacnt++;
+	while (mfl < 0) {
+		if (Iflag || Oflag)
+			msg(-2, 0, Mflag ? Mflag :
+					"Change to part %d and press "
+					"RETURN key. [q] ", mediacnt);
+		else
+			msg(-2, 0, sysv3 ? "If you want to go on, "
+					"type device/file name when ready.\n" :
+					"To continue, type device/file name "
+					"when ready.\n");
+		if (tty == 0)
+			if ((tty = open("/dev/tty", O_RDWR)) < 0 ||
+					fcntl(tty, F_SETFD, FD_CLOEXEC) < 0) {
+			cantrt:	errcnt++;
+				msg(4, 1, "Cannot read tty.\n");
+			}
+		i = 0;
+		while ((j = read(tty, &c, 1)) == 1 && c != '\n')
+			if (i < sizeof answer - 1)
+				answer[i++] = c;
+		if (j != 1)
+			goto cantrt;
+		answer[i] = 0;
+		if (Iflag || Oflag) {
+			if (answer[0] == '\0')
+				snprintf(answer, sizeof answer, Iflag ? Iflag :
+						Oflag);
+			else if (answer[0] == 'q')
+				exit(errcnt != 0 ? sysv3 ? 1 : 2 : 0);
+			else if (Iflag)
+				Iflag = sstrdup(answer);
+			else if (Oflag)
+				Oflag = sstrdup(answer);
+		} else if (answer[0] == '\0')
+			return;
+		if ((mt = action == 'i' ? open(answer, O_RDONLY) :
+					creat(answer, 0666)) < 0) {
+			if (sysv3)
+				msg(-2, 0, "That didn't work, "
+						"cannot open \"%s\"\n%s\n",
+						answer, strerror(errno));
+			else
+				emsg(3, "Cannot open \"%s\"", answer);
+		}
+		else
+			mfl = 0;
+	}
+	mstat();
+}
+
+static void
+mclose(void)
+{
+	if (action == 'o' && mt >= 0 && close(mt) < 0) {
+		emsg(3, "Close error on \"%s\"",
+				Oflag && !sysv3 ? Oflag : "output");
+		errcnt++;
+	}
+}
+
+/*
+ * Write the archive buffer to tape.
+ */
+static ssize_t
+mwrite(int max)
+{
+	ssize_t wo, wt = 0;
+
+	do {
+		if ((wo = write(mt, blkbuf + wt, (max?max:blksiz) - wt)) < 0) {
+			if (errno == EINTR) {
+				continue;
+			} else {
+				newmedia(errno);
+				if (mfl == 0) {
+					if (fmttype & TYP_BAR)
+						dump_barhdr();
+					continue;
+				}
+				else
+					done(1);
+			}
+		}
+		poffs += wo;
+		wt += wo;
+	} while (wt < (max?max:blksiz));
+	blocks += wt >> 9;
+	bytes += wt & 0777;
+	return wt;
+}
+
+/*
+ * Buffered writes to tape.
+ */
+static void
+bwrite(const char *data, size_t sz)
+{
+	size_t di;
+
+	nwritten += sz;
+	while (curpos + sz > blksiz) {
+		di = blksiz - curpos;
+		sz -= di;
+		memcpy(&blkbuf[curpos], data, di);
+		mwrite(0);
+		data += di;
+		curpos = 0;
+	}
+	memcpy(&blkbuf[curpos], data, sz);
+	curpos += sz;
+}
+
+/*
+ * Flush the tape write buffer.
+ */
+static void
+bflush(void)
+{
+	if (curpos) {
+		memset(&blkbuf[curpos], 0, blksiz - curpos);
+		mwrite(fmttype==FMT_ZIP && (mtst.st_mode&S_IFMT) == S_IFREG ?
+			curpos : 0);
+	}
+	curpos = 0;
+}
+
+/*
+ * CRC format checksum calculation with -i.
+ */
+static int
+sum(int fd, const char *fn, struct stat *sp, char *tg)
+{
+	char	*buf;
+	size_t	bufsize;
+	uint32_t	size = sp->st_size, sum = 0;
+	ssize_t	rd;
+	char	c;
+
+	getbuf(&buf, &bufsize, sp->st_blksize);
+	/*
+	 * Unfortunately, SVR4 cpio derivatives (as on Solaris 8 and
+	 * UnixWare 2.1) compute the checksum of signed char values,
+	 * whereas GNU cpio and the pax implementations of AT&T and
+	 * BSD use unsigned chars. Since there is no 'open' standard
+	 * for the SVR4 CRC format, the SVR4 implementation should be
+	 * taken as a de facto reference and we thus create SVR4 type
+	 * checksums.
+	 */
+	while ((rd = read(fd, buf, size>bufsize ? bufsize : size )) > 0) {
+		size -= rd;
+		do
+			sum += ((signed char *)buf)[--rd];
+		while (rd);
+	}
+	if (rd < 0) {
+		msg(3, 0, "Error computing checksum\n");
+		return 1;
+	}
+	if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
+		emsg(3, "Cannot reset file after checksum");
+		return 1;
+	}
+	c = tg[8];
+	sprintf(tg, "%08lx", (long)sum);
+	tg[8] = c;
+	return 0;
+}
+
+static int
+rstime(const char *fn, struct stat *st, const char *which)
+{
+	struct utimbuf	utb;
+
+	utb.actime = st->st_atime;
+	utb.modtime = st->st_mtime;
+	if (pax != PAX_TYPE_CPIO &&
+			(pax_preserve&(PAX_P_ATIME|PAX_P_MTIME)) != 0 &&
+			(pax_preserve&PAX_P_EVERY) == 0) {
+		struct stat	xst;
+		if (stat(fn, &xst) < 0)
+			goto fail;
+		if (pax_preserve&PAX_P_ATIME)
+			utb.actime = xst.st_atime;
+		if (pax_preserve&PAX_P_MTIME)
+			utb.modtime = xst.st_mtime;
+	}
+	if (utime(fn, &utb) < 0) {
+	fail:	emsg(2, "Unable to reset %s time for \"%s\"", which, fn);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Top-down splay function for inode tree.
+ */
+static struct islot *
+isplay(ino_t ino, struct islot *x)
+{
+	struct islot	hdr;
+	struct islot	*leftmax, *rightmin;
+	struct islot	*y;
+
+	hdr.i_lln = hdr.i_rln = inull;
+	leftmax = rightmin = &hdr;
+	inull->i_ino = ino;
+	while (ino != x->i_ino) {
+		if (ino < x->i_ino) {
+			if (ino < x->i_lln->i_ino) {
+				y = x->i_lln;
+				x->i_lln = y->i_rln;
+				y->i_rln = x;
+				x = y;
+			}
+			if (x->i_lln == inull)
+				break;
+			rightmin->i_lln = x;
+			rightmin = x;
+			x = x->i_lln;
+		} else {
+			if (ino > x->i_rln->i_ino) {
+				y = x->i_rln;
+				x->i_rln = y->i_lln;
+				y->i_lln = x;
+				x = y;
+			}
+			if (x->i_rln == inull)
+				break;
+			leftmax->i_rln = x;
+			leftmax = x;
+			x = x->i_rln;
+		}
+	}
+	leftmax->i_rln = x->i_lln;
+	rightmin->i_lln = x->i_rln;
+	x->i_lln = hdr.i_rln;
+	x->i_rln = hdr.i_lln;
+	inull->i_ino = !ino;
+	return x;
+}
+
+/*
+ * Find the inode number ino.
+ */
+static struct islot *
+ifind(ino_t ino, struct islot **it)
+{
+	if (*it == NULL)
+		return NULL;
+	*it = isplay(ino, *it);
+	return (*it)->i_ino == ino ? *it : NULL;
+}
+
+/*
+ * Put ik into the tree.
+ */
+static void
+iput(struct islot *ik, struct islot **it)
+{
+	if ((*it) == NULL) {
+		ik->i_lln = ik->i_rln = inull;
+		(*it) = ik;
+	} else {
+		/* ifind() is always called before */
+		/*(*it) = isplay(ik->i_ino, (*it));*/
+		if (ik->i_ino < (*it)->i_ino) {
+			ik->i_lln = (*it)->i_lln;
+			ik->i_rln = (*it);
+			(*it)->i_lln = inull;
+			(*it) = ik;
+		} else if ((*it)->i_ino < ik->i_ino) {
+			ik->i_rln = (*it)->i_rln;
+			ik->i_lln = (*it);
+			(*it)->i_rln = inull;
+			(*it) = ik;
+		}
+	}
+}
+
+/*
+ * Find the device dev or add it to the device/inode forest if not
+ * already present.
+ */
+static struct dslot *
+dfind(struct dslot **root, dev_t dev)
+{
+	struct dslot	*ds, *dp;
+
+	for (ds = *root, dp = NULL; ds; dp = ds, ds = ds->d_nxt)
+		if (ds->d_dev == dev)
+			break;
+	if (ds == NULL) {
+		ds = scalloc(1, sizeof *ds);
+		ds->d_dev = dev;
+		if (*root == NULL)
+			*root = ds;
+		else
+			dp->d_nxt = ds;
+	}
+	return ds;
+}
+
+/*
+ * Exit on fatal error conditions.
+ */
+static void
+done(int i)
+{
+	if (tflag)
+		fflush(stdout);
+	errcnt += i;
+	mclose();
+	if (errcnt && !sysv3)
+		fprintf(stderr, "%llu errors\n", errcnt);
+	exit(sysv3 ? 2 : 3);
+}
+
+static char	*pcopy, *pcend;
+static size_t	psz, pslen, pss;
+
+/*
+ * Execution for -p.
+ */
+static void
+dopass(const char *target)
+{
+	struct stat	st;
+
+	if (access(target, W_OK) < 0) {
+		emsg(033, sysv3 ? "cannot write in <%s>" :
+				"Error during access() of \"%s\"", target);
+		if (sysv3)
+			done(1);
+		usage();
+	}
+	if (stat(target, &st) < 0) {
+		emsg(023, "Error during stat() of \"%s\"", target);
+		done(1);
+	}
+	if ((st.st_mode&S_IFMT) != S_IFDIR)
+		msg(3, 1, sysv3 ? "<%s> not a directory.\n" :
+				"\"%s\" is not a directory\n", target);
+	getpath(target, &pcopy, &pcend, &psz, &pslen);
+	copyout(passfile);
+}
+
+/*
+ * Callback for sfile().
+ */
+/*ARGSUSED*/
+void
+writerr(void *vp, int count, int written)
+{
+}
+
+/*
+ * Copy file data of regular files with -p.
+ */
+static int
+passdata(struct file *f, const char *tgt, int tfd)
+{
+	char	*buf;
+	size_t	bufsize;
+	ssize_t	rd = 0;
+
+	if (f->f_fd < 0)	/* is a zero-sized unreadable file */
+		return 0;
+#ifdef	__linux__
+	if (f->f_st.st_size > 0) {
+		long long	sent;
+
+		sent = sfile(tfd, f->f_fd, f->f_st.st_mode, f->f_st.st_size);
+		blocks += (sent + 0777) >> 9;
+		if (sent == f->f_st.st_size)
+			return 0;
+		if (sent < 0)
+			goto rerr;
+	}
+#endif	/* __linux__ */
+	getbuf(&buf, &bufsize, f->f_st.st_blksize);
+	while ((rd = read(f->f_fd, buf, bufsize)) > 0) {
+		blocks += (rd + 0777) >> 9;
+		if (write(tfd, buf, rd) != rd) {
+			emsg(3, "Cannot write \"%s\"", tgt);
+			return -1;
+		}
+	}
+	if (rd < 0) {
+#ifdef	__linux__
+	rerr:
+#endif	/* __linux__ */
+		emsg(3, "Cannot read \"%s\"", f->f_name);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Handle a single file for -p.
+ */
+static int
+passfile(const char *fn, struct stat *st)
+{
+	struct file	f;
+	ssize_t	sz;
+	int	val;
+	char	*newfn;
+	size_t	newsz = 0;
+
+	newfn = sstrdup(fn);
+	if (pax != PAX_TYPE_CPIO) {
+		if (pax_sflag && pax_sname(&newfn, &newsz) == 0)
+			return 0;
+		if (rflag && rname(&newfn, &newsz) == 0)
+			return 0;
+	}
+	setpath(newfn, &pcopy, &pcend, pslen, &psz, &pss);
+	free(newfn);
+	memset(&f, 0, sizeof f);
+	f.f_name = sstrdup(fn);
+	f.f_nsiz = strlen(fn) + 1;
+	f.f_st = *st;
+	f.f_fd = -1;
+	if ((st->st_mode&S_IFMT) == S_IFLNK) {
+		sz = st->st_size ? st->st_size : PATH_MAX;
+		f.f_lnam = smalloc(sz+1);
+		if ((sz = readlink(fn, f.f_lnam, sz+1)) < 0) {
+				emsg(3, "Cannot read symbolic link \"%s\"", fn);
+				free(f.f_lnam);
+				return 1;
+		}
+		f.f_lnam[sz] = '\0';
+	} else if ((st->st_mode&S_IFMT) == S_IFREG) {
+		if ((f.f_fd = open(fn, O_RDONLY)) < 0) {
+			if (sysv3)
+				msg(2, 0, "Cannot open file \"%s\".\n", fn);
+			else
+				emsg(2, "Cannot open \"%s\", skipped", fn);
+			if (st->st_size != 0)
+				return 1;
+		}
+	}
+	val = filein(&f, passdata, pcopy);
+	if (f.f_lnam)
+		free(f.f_lnam);
+	free(f.f_name);
+	if (f.f_fd >= 0)
+		close(f.f_fd);
+	if (val <= 1 && aflag && (st->st_mode&S_IFMT) == S_IFREG)
+		errcnt += rstime(fn, st, "access");
+	return val != 0;
+}
+
+/*
+ * Processing of a single file common to -i and -p. Return value: 0 if
+ * successful, 1 at failure if data was read, 2 at failure if no data
+ * was read.
+ */
+static int
+filein(struct file *f, int (*copydata)(struct file *, const char *, int),
+	char *tgt)
+{
+	struct stat	nst;
+	char	*temp = NULL;
+	size_t	len;
+	int	fd, i, j, new;
+	int	failure = 2;
+
+	if (fmttype == FMT_ZIP && (f->f_st.st_mode&S_IFMT) != S_IFREG &&
+			(f->f_st.st_mode&S_IFMT) != S_IFLNK &&
+			(f->f_csize > 0 || f->f_gflag & FG_DESC))
+		skipfile(f);
+	if ((new = lstat(tgt, &nst)) == 0) {
+		if (action == 'p' && f->f_st.st_dev == nst.st_dev &&
+				f->f_st.st_ino == nst.st_ino) {
+			msg(3, 0, sysv3 ?
+				"Attempt to pass file to self!\n" :
+				"Attempt to pass a file to itself.\n");
+			return 1;
+		}
+		if ((f->f_st.st_mode&S_IFMT) == S_IFDIR) {
+			if ((nst.st_mode&S_IFMT) == S_IFDIR)
+				return setattr(tgt, &f->f_st);
+			rmdir(tgt);
+		} else {
+			if (pax_kflag) {
+				failure = 0;
+				goto skip;
+			}
+			if (uflag == 0 && f->f_st.st_mtime <= nst.st_mtime) {
+				if (pax == PAX_TYPE_CPIO)
+					msg(-1, 0, sysv3 ?
+					"current <%s> newer or same age\n" :
+					"Existing \"%s\" same age or newer\n",
+						tgt);
+				else
+					failure = 0;
+				goto skip;
+			}
+		}
+	} else {
+		if (imdir(tgt) < 0)
+			goto skip;
+	}
+	if (Vflag && !vflag)
+		prdot(0);
+	if ((f->f_st.st_mode&S_IFMT) != S_IFDIR && lflag) {
+		if (Lflag) {
+			char	*symblink, *name;
+			struct stat	xst;
+			name = f->f_name;
+			for (;;) {
+				if (lstat(name, &xst) < 0) {
+					emsg(3, "Cannot lstat \"%s\"", name);
+					if (name != f->f_name)
+						free(name);
+					goto cantlink;
+				}
+				if ((xst.st_mode&S_IFMT) != S_IFLNK)
+					break;
+				i = xst.st_size ? xst.st_size : PATH_MAX;
+				symblink = smalloc(i+1);
+				if ((j = readlink(name, symblink, i)) < 0) {
+					emsg(3, "Cannot read symbolic link "
+						"\"%s\"", name);
+					free(symblink);
+					if (name != f->f_name)
+						free(name);
+					goto cantlink;
+				}
+				symblink[j] = '\0';
+				symblink = joinpath(name, symblink);
+				if (name != f->f_name)
+					free(name);
+				name = symblink;
+			}
+			if (linkunlink(name, tgt) == 0) {
+				if (vflag)
+					fprintf(stderr, "%s\n", tgt);
+				if (name != f->f_name)
+					free(name);
+				return 0;
+			}
+			if (name != f->f_name)
+				free(name);
+		} else if (linkunlink(f->f_name, tgt) == 0) {
+			if (vflag)
+				fprintf(stderr, "%s\n", tgt);
+			return 0;
+		}
+cantlink:	errcnt += 1;
+	}
+	if ((f->f_st.st_mode&S_IFMT) != S_IFDIR && f->f_st.st_nlink > 1 &&
+			(fmttype & TYP_CPIO || fmttype == FMT_ZIP
+			 || action == 'p') &&
+			(i = canlink(tgt, &f->f_st, 1)) != 0) {
+		if (i < 0)
+			goto skip;
+		/*
+		 * At this point, hard links in SVR4 cpio format have
+		 * been reordered and data is associated with the first
+		 * link; remaining links have st_size == 0 so don't
+		 * overwrite the data here.
+		 */
+		if (fmttype & TYP_NCPIO && f->f_st.st_size == 0 ||
+				(f->f_st.st_mode&S_IFMT) != S_IFREG) {
+			if (vflag)
+				fprintf(stderr, "%s\n", f->f_name);
+			return 0;
+		}
+		/*
+		 * Make sure we can creat() this file later.
+		 */
+		chmod(tgt, 0600);
+	} else if (fmttype & TYP_TAR && f->f_st.st_nlink > 1) {
+		if (linkunlink(f->f_lnam, f->f_name) == 0) {
+			if (fmttype & TYP_USTAR && f->f_st.st_size > 0)
+				chmod(tgt, 0600);
+			else {
+				if (vflag)
+					fprintf(stderr, "%s\n", f->f_name);
+				return 0;
+			}
+		} else {
+			goto restore;
+		}
+	} else if (new == 0 && (f->f_st.st_mode&S_IFMT) != S_IFDIR) {
+		len = strlen(tgt);
+		temp = smalloc(len + 7);
+		strcpy(temp, tgt);
+		strcpy(&temp[len], "XXXXXX");
+		if ((fd = mkstemp(temp)) < 0 || close(fd) < 0) {
+			emsg(3, "Cannot create temporary file");
+			if (fd < 0) {
+				free(temp);
+				temp = NULL;
+			}
+			goto skip;
+		}
+		cur_ofile = tgt;
+		cur_tfile = temp;
+		if (rename(tgt, temp) < 0) {
+			emsg(3, "Cannot rename current \"%s\"", tgt);
+			tunlink(&temp);
+			goto skip;
+		}
+	}
+	switch (f->f_st.st_mode & S_IFMT) {
+	case S_IFDIR:
+		if (!dflag) {
+			if (action == 'p')
+				msg(-1, 0, "Use -d option to copy \"%s\"\n",
+						f->f_name);
+			goto restore;
+		}
+		if (mkdir(tgt, 0777) < 0 && errno != EEXIST) {
+			emsg(-1, "Cannot create directory \"%s\"", tgt);
+			goto restore;
+		}
+		break;
+	case S_IFLNK:
+		if (symlink(f->f_lnam, tgt) < 0) {
+			emsg(3, "Cannot create \"%s\"", tgt);
+			goto restore;
+		}
+		break;
+	case S_IFREG:
+		if (temp && f->f_fd < 0)
+			goto restore;
+		cur_ofile = tgt;
+		if ((fd = (compressed_bar ? zcreat : creat)(tgt,
+						f->f_st.st_mode & 0777)) < 0) {
+			emsg(3, "Cannot create \"%s\"", tgt);
+			goto skip;
+		}
+		failure = 1;
+		if (copydata(f, tgt, fd) != 0) {
+			close(fd);
+			goto restore;
+		}
+		if ((compressed_bar ? zclose : close)(fd) < 0) {
+			emsg(3, "Close error on \"%s\"", tgt);
+			goto restore;
+		}
+		break;
+	case S_IFBLK:
+	case S_IFCHR:
+	case S_IFIFO:
+	case S_IFNAM:
+	case S_IFNWK:
+		if (mknod(tgt, f->f_st.st_mode&(S_IFMT|0777),
+					f->f_st.st_rdev) < 0) {
+			emsg(3, "Cannot mknod() \"%s\"", tgt);
+			goto restore;
+		}
+		break;
+	default:
+		msg(-1, 0, "Impossible file type\n");
+		goto skip;
+	}
+	if (vflag)
+		fprintf(stderr, "%s\n", f->f_name);
+	tunlink(&temp);
+	return setattr(tgt, &f->f_st);
+skip:	if (copydata == indata)
+		skipdata(f, copydata);
+restore:
+	if (temp) {
+		if (rename(temp, tgt) < 0) {
+			emsg(3, "Cannot recover original version of \"%s\"",
+					tgt);
+			tunlink(&temp);
+		} else
+			fprintf(stderr, "Restoring existing \"%s\"\n", tgt);
+		cur_tfile = cur_ofile = NULL;
+	}
+	return failure;
+}
+
+static int
+linkunlink(const char *path1, const char *path2)
+{
+	int	twice = 0;
+
+	do {
+		if (link(path1, path2) == 0) {
+			if (vflag && pax == PAX_TYPE_CPIO)
+				printf("%s linked to %s\n", path1, path2);
+			return 0;
+		}
+		if (errno == EEXIST && unlink(path2) < 0)
+			emsg(3, sysv3 ? "cannot unlink <%s>" :
+					"Error cannot unlink \"%s\"", path2);
+	} while (twice++ == 0);
+	emsg(023, sysv3 ? "Cannot link <%s> & <%s>" :
+			"Cannot link \"%s\" and \"%s\"", path1, path2);
+	return -1;
+}
+
+static void
+tunlink(char **fn)
+{
+	cur_tfile = cur_ofile = NULL;
+	if (*fn) {
+		if (unlink(*fn) < 0)
+			emsg(3, "Cannot unlink() temp file \"%s\"", *fn);
+		free(*fn);
+		*fn = NULL;
+	}
+}
+
+/*
+ * For -it[v] option.
+ */
+static int
+filet(struct file *f, int (*copydata)(struct file *, const char *, int))
+{
+	if (vflag && (
+		(fmttype == FMT_ZIP && f->f_gflag & FG_DESC &&
+		(f->f_cmethod == C_DEFLATED || f->f_cmethod == C_ENHDEFLD) &&
+				(f->f_gflag & FG_CRYPT) == 0) ||
+		f->f_Kbase)) {
+		/*
+		 * Need to read zip data descriptor located after the
+		 * file contents in order to know the file size. Or
+		 * need to read second header of -K archive.
+		 */
+		int	i;
+		i = skipdata(f, copydata);
+		filev(f);
+		return i;
+	}
+	if (vflag)
+		filev(f);
+	else
+		puts(f->f_name);
+	return skipdata(f, copydata);
+}
+
+static void
+filev(struct file *f)
+{
+	const char	*cp;
+	long	c;
+
+	if (pax == PAX_TYPE_CPIO && fmttype & TYP_TAR && f->f_st.st_nlink > 1)
+		printf("%s linked to %s\n", f->f_lnam, f->f_name);
+	if (sysv3)
+		printf("%-6o", (int)f->f_st.st_mode&(07777|S_IFMT));
+	else {
+		c = typec(&f->f_st);
+		putchar(c);
+		permbits(f->f_st.st_mode);
+	}
+	if (fmttype == FMT_ZIP && vflag > 1)
+		zipinfo(f);
+	else {
+		if (sysv3 == 0)
+			printf(" %3d", fmttype&TYP_TAR &&
+					(f->f_st.st_mode&S_IFMT) == S_IFLNK ?
+					2 : (int)f->f_st.st_nlink);
+		if ((cp = getuser(f->f_st.st_uid)) != NULL)
+			printf(sysv3 ? " %-6s" : " %-8s", cp);
+		else
+			printf(sysv3 ? " %-6lu" : " %-8lu",
+					(long)f->f_st.st_uid);
+		if (sysv3 == 0) {
+			if ((cp = getgroup(f->f_st.st_gid)) != NULL)
+				printf(" %-8s", cp);
+			else
+				printf(" %-8lu", (long)f->f_st.st_gid);
+		}
+	}
+	if (sysv3 || (f->f_st.st_mode&S_IFMT)!=S_IFCHR &&
+			(f->f_st.st_mode&S_IFMT)!=S_IFBLK &&
+			(f->f_st.st_mode&S_IFMT)!=S_IFNAM &&
+			(f->f_st.st_mode&S_IFMT)!=S_IFNWK)
+		printf(pax != PAX_TYPE_CPIO ? "%8llu" :
+				sysv3 ? "%7llu" : " %-7llu", f->f_dsize);
+	else
+		printf(" %3lu,%3lu", (long)f->f_rmajor, (long)f->f_rminor);
+	prtime(f->f_st.st_mtime);
+	printf("%s", f->f_name);
+	if ((f->f_st.st_mode&S_IFMT) == S_IFLNK)
+		printf(" -> %s", f->f_lnam);
+	if (pax != PAX_TYPE_CPIO && (f->f_st.st_mode&S_IFMT) != S_IFDIR &&
+			f->f_st.st_nlink>1) {
+		if (fmttype & TYP_TAR)
+			printf(" == %s", f->f_lnam);
+		else
+			canlink(f->f_name, &f->f_st, 0);
+	}
+	putchar('\n');
+}
+
+static int
+typec(struct stat *st)
+{
+	switch (st->st_mode&S_IFMT) {
+	case S_IFREG:
+		return '-';
+	case S_IFDIR:
+		return 'd';
+	case S_IFLNK:
+		return 'l';
+	case S_IFCHR:
+		return 'c';
+	case S_IFBLK:
+		return 'b';
+	case S_IFIFO:
+		return 'p';
+	case S_IFNWK:
+		return 'n';
+	case S_IFNAM:
+		switch (st->st_rdev) {
+		case S_INSEM:
+			return 's';
+		case S_INSHD:
+			return 'm';
+		}
+		/*FALLTHRU*/
+	default:
+		msg(-1, 0, "Impossible file type\n");
+		errcnt++;
+		return '-';
+	}
+}
+
+static void
+permbits(mode_t mode)
+{
+	mode_t	mask = 0700, shft = 6;
+
+	while (mask) {
+		if (((mode & mask) >> shft) & 04)
+			putchar('r');
+		else
+			putchar('-');
+		if (((mode & mask) >> shft) & 02)
+			putchar('w');
+		else
+			putchar('-');
+		if (mask == 0700 && mode & 04000)
+			putchar('s');
+		else if (mask == 0070 && (mode & 02010) == 02010)
+			putchar('s');
+		else if (mask == 0070 && mode & 02000)
+			putchar('l');
+		else if (mask == 0007 && mode & 01000)
+			putchar('t');
+		else if (((mode & mask) >> shft) & 01)
+			putchar('x');
+		else
+			putchar('-');
+		mask >>= 3;
+		shft -= 3;
+	}
+}
+
+static void
+prtime_cpio(time_t t)
+{
+	char	b[30];
+
+	strftime(b, sizeof b, sysv3 ? "%b %e %H:%M:%S %Y" : "%b %e %H:%M %Y",
+			localtime(&t));
+	printf(sysv3 ? "  %s  " : " %s, ", b);
+}
+
+/*
+ * Prepare path to add names of files below it later.
+ */
+static void
+getpath(const char *path, char **file, char **filend, size_t *sz, size_t *slen)
+{
+	*sz = 14 + strlen(path) + 2;
+	*file = smalloc(*sz);
+	*filend = *file;
+	if (path[0] == '/' && path[1] == '\0')
+		*(*filend)++ = '/';
+	else {
+		const char	*cp = path;
+		while ((*(*filend)++ = *cp++) != '\0');
+		(*filend)[-1] = '/';
+	}
+	*slen = *filend - *file;
+}
+
+/*
+ * Concatenate base (prepared with getpath()) and file.
+ */
+static void
+setpath(const char *base, char **file, char **filend,
+		size_t slen, size_t *sz, size_t *ss)
+{
+	if (slen + (*ss = strlen(base)) >= *sz) {
+		*sz += slen + *ss + 15;
+		*file = srealloc(*file, *sz);
+		*filend = &(*file)[slen];
+	}
+	strcpy(*filend, base);
+}
+
+/*
+ * Create intermediate directories with -m.
+ */
+static int
+imdir(char *fn)
+{
+	struct stat	st;
+	char	*cp;
+	int	dfl = dflag != 0;
+
+	for (cp = fn; *cp == '/'; cp++);
+	do {
+		while (*cp && *cp != '/')
+			cp++;
+		if (*cp == '/') {
+			*cp = '\0';
+			if (stat(fn, &st) < 0) {
+				if (dfl) {
+					if (mkdir(fn, 0777) < 0) {
+						*cp = '/';
+						emsg(-1, "Cannot create "
+							"directory for \"%s\"",
+							fn);
+						return -1;
+					}
+				} else {
+					msg(-1, 0, sysv3 ?
+						"missing 'd' option\n" :
+						"Missing -d option\n");
+					dfl = 2;
+				}
+			}
+			*cp = '/';
+			while (*cp == '/')
+				cp++;
+		}
+	} while (*cp);
+	return 0;
+}
+
+/*
+ * Set file attributes and make sure that suid/sgid bits are only restored
+ * if the owner is the same as on the tape.
+ */
+static int
+setattr(const char *fn, struct stat *st)
+{
+	mode_t	mode = st->st_mode & 07777;
+	uid_t	uid = Rflag ? Ruid : myuid;
+	gid_t	gid = Rflag ? Rgid : mygid;
+
+	if ((pax != PAX_TYPE_CPIO || myuid == 0) &&
+			(pax == PAX_TYPE_CPIO ||
+			 pax_preserve&(PAX_P_OWNER|PAX_P_EVERY))) {
+		if (setowner(fn, st) != 0)
+			return 1;
+	}
+	if (pax != PAX_TYPE_CPIO &&
+			(pax_preserve&(PAX_P_OWNER|PAX_P_EVERY)) == 0)
+		mode &= ~(mode_t)(S_ISUID|S_ISGID);
+	if (myuid != 0 || Rflag) {
+		if (st->st_uid != uid || st->st_gid != gid) {
+			mode &= ~(mode_t)S_ISUID;
+			if ((st->st_mode&S_IFMT) != S_IFDIR && mode & 0010)
+				mode &= ~(mode_t)S_ISGID;
+			if ((st->st_mode&S_IFMT) == S_IFDIR && st->st_gid!=gid)
+				mode &= ~(mode_t)S_ISGID;
+		}
+	}
+	if ((st->st_mode&S_IFMT) == S_IFLNK)
+		return 0;
+	if (hp_Uflag)
+		mode &= ~umsk|S_IFMT;
+	if (pax != PAX_TYPE_CPIO &&
+			(pax_preserve&(PAX_P_MODE|PAX_P_OWNER|PAX_P_EVERY))==0)
+		mode &= 01777|S_IFMT;
+	if ((pax == PAX_TYPE_CPIO || pax_preserve&(PAX_P_MODE|PAX_P_EVERY)) &&
+			chmod(fn, mode) < 0) {
+		emsg(2, "Cannot chmod() \"%s\"", fn);
+		return 1;
+	}
+	if (pax != PAX_TYPE_CPIO ?
+			(pax_preserve&(PAX_P_ATIME|PAX_P_MTIME|PAX_P_EVERY)) !=
+			(PAX_P_ATIME|PAX_P_MTIME) : mflag)
+		return rstime(fn, st, "modification");
+	else
+		return 0;
+}
+
+static int
+setowner(const char *fn, struct stat *st)
+{
+	uid_t	uid = Rflag ? Ruid : myuid ? myuid : st->st_uid;
+	gid_t	gid = Rflag ? Rgid : st->st_gid;
+
+	if (((st->st_mode&S_IFMT)==S_IFLNK?lchown:chown)(fn, uid, gid) < 0) {
+		emsg(2, "Cannot chown() \"%s\"", fn);
+		return 1;
+	}
+	if (pax >= PAX_TYPE_PAX2001 && myuid && myuid != st->st_uid &&
+			pax_preserve & (PAX_P_OWNER|PAX_P_EVERY)) {
+		/*
+		 * Do not even try to preserve user ownership in this case.
+		 * It would either fail, or, without _POSIX_CHOWN_RESTRICTED,
+		 * leave us with a file we do not own and which we thus could
+		 * not chmod() later.
+		 */
+		errno = EPERM;
+		emsg(2, "Cannot chown() \"%s\"", fn);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * For -i and -p: Check if device/inode have been created already and
+ * if so, link path (or print the link name).
+ */
+static int
+canlink(const char *path, struct stat *st, int really)
+{
+	struct dslot	*ds;
+	struct islot	*ip;
+
+	ds = dfind(&devices, st->st_dev);
+	if ((ip = ifind(st->st_ino, &ds->d_isl)) == NULL ||
+			ip->i_name == NULL) {
+		if (ip == NULL) {
+			ip = scalloc(1, sizeof *ip);
+			ip->i_ino = st->st_ino;
+			if ((fmttype&(TYP_NCPIO|TYP_TAR)) == 0)
+				ip->i_nlk = st->st_nlink;
+			iput(ip, &ds->d_isl);
+		}
+		ip->i_name = sstrdup(path);
+	} else {
+		if ((fmttype&(TYP_NCPIO|TYP_TAR)) == 0) {
+			/*
+			 * If an archive inode has more links than given in
+			 * st_nlink, write a new disk inode. See the comments
+			 * to storelink() for the rationale.
+			 */
+			if (--ip->i_nlk == 0) {
+				free(ip->i_name);
+				ip->i_name = sstrdup(path);
+				ip->i_nlk = st->st_nlink;
+				return 0;
+			}
+		}
+		if (really) {
+			/*
+			 * If there was file data before the last link with
+			 * SVR4 cpio formats, do not create a hard link.
+			 */
+			if (fmttype & TYP_NCPIO && ip->i_nlk == 0)
+				return 0;
+			if (linkunlink(ip->i_name, path) == 0)
+				return 1;
+			else
+				return -1;
+		} else {
+			printf(" == %s", ip->i_name);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Execution for -i.
+ */
+static void
+doinp(void)
+{
+	union bincpio	bc;
+	struct file	f;
+	int	n;
+
+	memset(&f, 0, sizeof f);
+	if (Eflag)
+		patfile();
+	if (Iflag) {
+		if ((mt = open(Iflag, O_RDONLY)) < 0) {
+			if (sysv3) {
+				emsg(3, "Cannot open <%s> for input.", Iflag);
+				done(1);
+			}
+			else
+				msg(3, -2, "Cannot open \"%s\" for input\n",
+						Iflag);
+		}
+	} else
+		mt = dup(0);
+	mstat();
+	blkbuf = svalloc(blksiz, 1);
+	if ((n = mread()) == 0)
+		unexeoa();
+	else if (n < 0) {
+		emsg(3, "Read error on \"%s\"",
+			Iflag && !sysv3 ? Iflag : "input");
+		done(1);
+	}
+	if (kflag == 0 && sixflag == 0)
+		fmttype = FMT_NONE;
+	if (fmttype == FMT_NONE)
+		whathdr();
+	else
+		formatforced = 1;
+	while (readhdr(&f, &bc) == 0) {
+		if (fmttype & TYP_NCPIO && f.f_st.st_nlink > 1 &&
+				(f.f_st.st_mode&S_IFMT) != S_IFDIR) {
+			if (f.f_st.st_size != 0)
+				flushlinks(&f);
+			else
+				storelink(&f);
+		} else
+			inpone(&f, 1);
+		f.f_Kbase = f.f_Krest = f.f_Ksize = 0;
+		f.f_oflag = 0;
+	}
+	if (fmttype & TYP_NCPIO)
+		flushrest(f.f_pad);
+}
+
+/*
+ * SVR4 cpio link handling with -i; called if we assume that more links
+ * to this file will follow.
+ */
+static void
+storelink(struct file *f)
+{
+	struct dslot	*ds;
+	struct islot	*ip;
+	struct ilink	*il, *iz;
+
+	ds = dfind(&devices, f->f_st.st_dev);
+	if ((ip = ifind(f->f_st.st_ino, &ds->d_isl)) == NULL) {
+		ip = scalloc(1, sizeof *ip);
+		ip->i_ino = f->f_st.st_ino;
+		ip->i_nlk = f->f_st.st_nlink;
+		ip->i_st = smalloc(sizeof *ip->i_st);
+		*ip->i_st = f->f_st;
+		iput(ip, &ds->d_isl);
+	} else {
+		if (ip->i_nlk == 0) {
+			/*
+			 * More links to an inode than given in the first
+			 * st_nlink occurence are found within this archive.
+			 * This happens if -L was specified and soft links
+			 * point to a file with multiple hard links. We do
+			 * the same as SVR4 cpio implementations here and
+			 * associate these links with a new inode, since it
+			 * is related to the way a file with a single hard
+			 * link but referenced by soft links is unpacked.
+			 */
+			ip->i_nlk = f->f_st.st_nlink;
+			if (ip->i_name)
+				free(ip->i_name);
+			ip->i_name = NULL;
+			ip->i_st = smalloc(sizeof *ip->i_st);
+			*ip->i_st = f->f_st;
+		} else if (ip->i_nlk <= 2) {
+			/*
+			 * We get here if
+			 * - a file with multiple links is empty;
+			 * - a broken implementation has stored file data
+			 *   before the last link;
+			 * - a linked file has been added to the archive later
+			 *   again (does not happen with our implementation).
+			 */
+			flushnode(ip, f);
+			return;
+		} else
+			ip->i_nlk--;
+	}
+	for (il = ip->i_lnk, iz = NULL; il; il = il->l_nxt)
+		iz = il;
+	il = scalloc(1, sizeof *il);
+	il->l_siz = strlen(f->f_name) + 1;
+	il->l_nam = smalloc(il->l_siz);
+	strcpy(il->l_nam, f->f_name);
+	if (iz)
+		iz->l_nxt = il;
+	else
+		ip->i_lnk = il;
+}
+
+/*
+ * Flush all links of a file with SVR4 cpio format and -i.
+ */
+static void
+flushlinks(struct file *f)
+{
+	struct dslot	*ds;
+	struct islot	*ip;
+
+	ds = dfind(&devices, f->f_st.st_dev);
+	ip = ifind(f->f_st.st_ino, &ds->d_isl);
+	flushnode(ip, f);
+}
+
+/*
+ * Data of a multi-linked file shall be transferred now for SVR4 cpio
+ * format and -i.
+ */
+static void
+flushnode(struct islot *ip, struct file *f)
+{
+	struct file	nf;
+	struct ilink	*il, *iz;
+
+	f->f_dsize = f->f_st.st_size;
+	if (ip && ip->i_nlk > 0) {
+		/*
+		 * Write out the file data with the first link the user
+		 * wants to be extracted, but show the same display size
+		 * for all links.
+		 */
+		for (il = ip->i_lnk, iz = NULL; il;
+				iz = il, il = il->l_nxt, iz ? free(iz), 0 : 0) {
+			memset(&nf, 0, sizeof nf);
+			nf.f_name = il->l_nam;
+			nf.f_nsiz = il->l_siz;
+			nf.f_st = f->f_st;
+			nf.f_chksum = f->f_chksum;
+			nf.f_pad = f->f_pad;
+			nf.f_dsize = f->f_dsize;
+			if (inpone(&nf, 0) == 0) {
+				f->f_chksum = 0;
+				f->f_st.st_size = 0;
+			}
+			free(il->l_nam);
+		}
+		ip->i_lnk = NULL;
+		if (ip->i_st)
+			free(ip->i_st);
+		ip->i_st = NULL;
+	}
+	if (f->f_name)
+		inpone(f, 1);
+	if (ip) {
+		if (ip->i_nlk <= 2 && ip->i_name) {
+			free(ip->i_name);
+			ip->i_name = NULL;
+		}
+		ip->i_nlk = 0;
+	}
+}
+
+/*
+ * This writes all remaining multiply linked files, i. e. those with
+ * st_size == 0 and st_nlink > number of links within the archive.
+ */
+static void
+flushrest(int pad)
+{
+	struct dslot	*ds;
+
+	for (ds = devices; ds; ds = ds->d_nxt)
+		if (ds->d_isl != NULL)
+			flushtree(ds->d_isl, pad);
+}
+
+static void
+flushtree(struct islot *ip, int pad)
+{
+	struct file	f;
+
+	if (ip == inull)
+		return;
+	flushtree(ip->i_lln, pad);
+	flushtree(ip->i_rln, pad);
+	if (ip->i_nlk > 0 && ip->i_st) {
+		memset(&f, 0, sizeof f);
+		f.f_st = *ip->i_st;
+		f.f_pad = pad;
+		flushnode(ip, &f);
+	}
+}
+
+/*
+ * See if the user wants to have this file with -i, and extract it or
+ * skip its data on the tape.
+ */
+static int
+inpone(struct file *f, int shallskip)
+{
+	struct glist	*gp = NULL, *gb = NULL;
+	int	val = -1, selected = 0;
+
+	if ((patterns == NULL || (gp = want(f, &gb)) != NULL ^ fflag) &&
+			pax_track(f->f_name, f->f_st.st_mtime)) {
+		selected = 1;
+		if ((pax_sflag == 0 || pax_sname(&f->f_name, &f->f_nsiz)) &&
+				(rflag == 0 || rname(&f->f_name, &f->f_nsiz))) {
+			errcnt += infile(f);
+			val = 0;
+		}
+	} else if (shallskip)
+		errcnt += skipfile(f);
+	if (gp != NULL && selected) {
+		gp->g_gotcha = 1;
+		if (gp->g_nxt && gp->g_nxt->g_art)
+			gp->g_nxt->g_gotcha = 1;
+		else if (gp->g_art && gb)
+			gb->g_gotcha = 1;
+	}
+	return val;
+}
+
+/*
+ * Read the header for a file with -i. Return values: 0 okay, 1 end of
+ * archive, -1 failure.
+ */
+static int
+readhdr(struct file *f, union bincpio *bp)
+{
+	long	namlen, l1, l2, rd, hsz;
+	static long	attempts;
+	long long	skipped = 0;
+
+	if (fmttype & TYP_TAR) {
+		if (f->f_name)
+			f->f_name[0] = '\0';
+		if (f->f_lnam)
+			f->f_lnam[0] = '\0';
+	}
+	paxrec = globrec;
+retry:	f->f_st = globst;
+retry2:	if (fmttype & TYP_BINARY) {
+		hsz = SIZEOF_hdr_cpio;
+		if (attempts == 0 && bread(bp->data, hsz) != hsz)
+			unexeoa();
+		if ((fmttype&TYP_BE ? pbe16(bp->Hdr.c_magic) :
+				ple16(bp->Hdr.c_magic)) != mag_bin)
+			goto badhdr;
+		if (fmttype & TYP_BE) {
+			f->f_st.st_dev = pbe16(bp->Hdr.c_dev)&0177777;
+			f->f_st.st_ino = pbe16(bp->Hdr.c_ino)&0177777;
+			f->f_st.st_mode = pbe16(bp->Hdr.c_mode);
+		} else {
+			f->f_st.st_dev = ple16(bp->Hdr.c_dev)&0177777;
+			f->f_st.st_ino = ple16(bp->Hdr.c_ino)&0177777;
+			f->f_st.st_mode = ple16(bp->Hdr.c_mode);
+		}
+		if (sixflag) {
+			/*
+			 * relevant Unix 6th Edition style mode bits
+			 * (according to /usr/sys/inode.h, untested:)
+			 *
+			 * 060000	IFMT	type of file
+			 * 040000	IFDIR	directory
+			 * 020000	IFCHR	character special
+			 * 060000	IFBLK	block special, 0 is regular
+			 * 007777		permission bits as today
+			 */
+			f->f_st.st_mode &= 067777;
+			if ((f->f_st.st_mode & 060000) == 0)
+				f->f_st.st_mode |= S_IFREG;
+		}
+		if (fmttype & TYP_BE) {
+			f->f_st.st_uid = pbe16(bp->Hdr.c_uid)&0177777;
+			f->f_st.st_gid = pbe16(bp->Hdr.c_gid)&0177777;
+			f->f_st.st_nlink = pbe16(bp->Hdr.c_nlink)&0177777;
+			f->f_st.st_mtime = pbe32(bp->Hdr.c_mtime);
+			f->f_st.st_rdev = pbe16(bp->Hdr.c_rdev);
+			namlen = pbe16(bp->Hdr.c_namesize);
+			f->f_st.st_size = pbe32(bp->Hdr.c_filesize)&0xFFFFFFFF;
+		} else {
+			f->f_st.st_uid = ple16(bp->Hdr.c_uid)&0177777;
+			f->f_st.st_gid = ple16(bp->Hdr.c_gid)&0177777;
+			f->f_st.st_nlink = ple16(bp->Hdr.c_nlink)&0177777;
+			f->f_st.st_mtime = pme32(bp->Hdr.c_mtime);
+			f->f_st.st_rdev = ple16(bp->Hdr.c_rdev);
+			namlen = ple16(bp->Hdr.c_namesize);
+			f->f_st.st_size = pme32(bp->Hdr.c_filesize)&0xFFFFFFFF;
+		}
+		f->f_rmajor = major(f->f_st.st_rdev);
+		f->f_rminor = minor(f->f_st.st_rdev);
+		if ((f->f_st.st_rdev&0xFFFF) == 0xFFFF &&
+				f->f_st.st_size > 0 &&
+				((f->f_st.st_mode&S_IFMT) == S_IFBLK ||
+				 (f->f_st.st_mode&S_IFMT) == S_IFCHR &&
+				 (!formatforced || fmttype & TYP_SGI))) {
+			fmttype |= TYP_SGI;
+			f->f_rmajor = (f->f_st.st_size&0xFFFC0000)>>18;
+			f->f_rminor = f->f_st.st_size&0x0003FFFF;
+			f->f_st.st_rdev = makedev(f->f_rmajor, f->f_rminor);
+			f->f_st.st_size = 0;
+		}
+		if ((f->f_st.st_mode&S_IFMT) == S_IFREG &&
+				f->f_st.st_size&0x80000000 &&
+				(!formatforced || fmttype & TYP_SGI)) {
+			fmttype |= TYP_SGI;
+			f->f_Ksize = f->f_st.st_size&0xFFFFFFFF;
+			f->f_Kbase = (0x100000000LL-f->f_st.st_size) *
+				0x80000000;
+			f->f_st.st_size = 0;
+		}
+		f->f_pad = 2;
+		rd = SIZEOF_hdr_cpio;
+	} else if (fmttype == FMT_ODC) {
+		hsz = SIZEOF_c_hdr;
+		if (attempts == 0 && bread(bp->data, hsz) != hsz)
+			unexeoa();
+		if(memcmp(bp->Cdr.c_magic, mag_odc, sizeof mag_odc))
+			goto badhdr;
+		f->f_st.st_dev = rdoct(bp->Cdr.c_dev, 6);
+		f->f_st.st_ino = rdoct(bp->Cdr.c_ino, 6);
+		f->f_st.st_mode = rdoct(bp->Cdr.c_mode, 6);
+		f->f_st.st_uid = rdoct(bp->Cdr.c_uid, 6);
+		f->f_st.st_gid = rdoct(bp->Cdr.c_gid, 6);
+		f->f_st.st_nlink = rdoct(bp->Cdr.c_nlink, 6);
+		f->f_st.st_rdev = rdoct(bp->Cdr.c_rdev, 6);
+		f->f_rmajor = major(f->f_st.st_rdev);
+		f->f_rminor = minor(f->f_st.st_rdev);
+		f->f_st.st_mtime = rdoct(bp->Cdr.c_mtime, 11);
+		namlen = rdoct(bp->Cdr.c_namesz, 6);
+		f->f_st.st_size = rdoct(bp->Cdr.c_filesz, 11);
+		f->f_pad = 1;
+		rd = SIZEOF_c_hdr;
+	} else if (fmttype == FMT_DEC) {
+		hsz = SIZEOF_d_hdr;
+		if (attempts == 0 && bread(bp->data, hsz) != hsz)
+			unexeoa();
+		if(memcmp(bp->Ddr.d_magic, mag_odc, sizeof mag_odc))
+			goto badhdr;
+		f->f_st.st_dev = rdoct(bp->Ddr.d_dev, 6);
+		f->f_st.st_ino = rdoct(bp->Ddr.d_ino, 6);
+		f->f_st.st_mode = rdoct(bp->Ddr.d_mode, 6);
+		f->f_st.st_uid = rdoct(bp->Ddr.d_uid, 6);
+		f->f_st.st_gid = rdoct(bp->Ddr.d_gid, 6);
+		f->f_st.st_nlink = rdoct(bp->Ddr.d_nlink, 6);
+		f->f_rmajor = rdoct(bp->Ddr.d_rmaj, 8);
+		f->f_rminor = rdoct(bp->Ddr.d_rmin, 8);
+		f->f_st.st_rdev = makedev(f->f_rmajor, f->f_rminor);
+		f->f_st.st_mtime = rdoct(bp->Ddr.d_mtime, 11);
+		namlen = rdoct(bp->Ddr.d_namesz, 6);
+		f->f_st.st_size = rdoct(bp->Ddr.d_filesz, 11);
+		f->f_pad = 1;
+		rd = SIZEOF_d_hdr;
+	} else if (fmttype & TYP_NCPIO) {
+		hsz = SIZEOF_Exp_cpio_hdr;
+		if (attempts == 0 && bread(bp->data, hsz) != hsz)
+			unexeoa();
+		if (memcmp(bp->Edr.E_magic, mag_asc, sizeof mag_asc) &&
+		    memcmp(bp->Edr.E_magic, mag_crc, sizeof mag_crc))
+			goto badhdr;
+		f->f_st.st_ino = rdhex(bp->Edr.E_ino, 8);
+		f->f_st.st_mode = rdhex(bp->Edr.E_mode, 8);
+		f->f_st.st_uid = rdhex(bp->Edr.E_uid, 8);
+		f->f_st.st_gid = rdhex(bp->Edr.E_gid, 8);
+		f->f_st.st_nlink = rdhex(bp->Edr.E_nlink, 8);
+		f->f_st.st_mtime = rdhex(bp->Edr.E_mtime, 8);
+		f->f_st.st_size = rdhex(bp->Edr.E_filesize, 8);
+		l1 = rdhex(bp->Edr.E_maj, 8);
+		l2 = rdhex(bp->Edr.E_min, 8);
+		f->f_st.st_dev = makedev(l1, l2);
+		f->f_rmajor = rdhex(bp->Edr.E_rmaj, 8);
+		f->f_rminor = rdhex(bp->Edr.E_rmin, 8);
+		f->f_st.st_rdev = makedev(f->f_rmajor, f->f_rminor);
+		namlen = rdhex(bp->Edr.E_namesize, 8);
+		f->f_chksum = rdhex(bp->Edr.E_chksum, 8);
+		f->f_pad = 4;
+		rd = SIZEOF_Exp_cpio_hdr;
+	} else if (fmttype & TYP_CRAY) {
+		int	diff5 = fmttype==FMT_CRAY5 ? CRAY_PARAMSZ : 0;
+		hsz = SIZEOF_cray_hdr - diff5;
+		if (attempts == 0 && bread(bp->data, hsz) != hsz)
+			unexeoa();
+		if (pbe64(bp->Crayhdr.C_magic) != mag_bin)
+			goto badhdr;
+		f->f_st.st_dev = pbe64(bp->Crayhdr.C_dev);
+		f->f_st.st_ino = pbe64(bp->Crayhdr.C_ino);
+		f->f_st.st_mode = pbe64(bp->Crayhdr.C_mode);
+		/*
+		 * Some of the S_IFMT bits on Cray UNICOS 9 differ from
+		 * the common Unix values, namely:
+		 *
+		 * S_IFLNK	0130000		symbolic link
+		 * S_IFOFD	0110000		off line, with data
+		 * S_IFOFL	0120000		off line, with no data
+		 *
+		 * We treat the latter ones as regular files.
+		 */
+		if ((f->f_st.st_mode&S_IFMT) == 0130000)
+			f->f_st.st_mode = f->f_st.st_mode&07777|S_IFLNK;
+		else if ((f->f_st.st_mode&S_IFMT) == 0110000 ||
+				(f->f_st.st_mode&S_IFMT) == 0120000)
+			f->f_st.st_mode = f->f_st.st_mode&07777|S_IFREG;
+		f->f_st.st_uid = pbe64(bp->Crayhdr.C_uid);
+		f->f_st.st_gid = pbe64(bp->Crayhdr.C_gid);
+		f->f_st.st_nlink = pbe64(bp->Crayhdr.C_nlink);
+		f->f_st.st_mtime = pbe64(bp->Crayhdr.C_mtime - diff5);
+		f->f_st.st_rdev = pbe64(bp->Crayhdr.C_rdev);
+		f->f_rmajor = major(f->f_st.st_rdev);
+		f->f_rminor = minor(f->f_st.st_rdev);
+		f->f_st.st_size = pbe64(bp->Crayhdr.C_filesize - diff5);
+		namlen = pbe64(bp->Crayhdr.C_namesize - diff5);
+		f->f_pad = 1;
+		rd = SIZEOF_cray_hdr - diff5;
+	} else if (fmttype & TYP_BAR) {
+		hsz = 512;
+		if (attempts == 0 && bread(bp->data, hsz) != hsz)
+			unexeoa();
+		if (bp->data[SIZEOF_bar_header] == '\0') {
+			if (kflag && !allzero(bp->data, hsz))
+				goto badhdr;
+			return 1;
+		}
+		if (trdsum(bp) != 0 && kflag == 0)
+			goto badhdr;
+		bp->data[512] = bp->data[513] = '\0';
+		if (f->f_name == NULL || f->f_name[0] == '\0') {
+			if (f->f_nsiz < 512) {
+				free(f->f_name);
+				f->f_name = smalloc(f->f_nsiz = 512);
+			}
+			strcpy(f->f_name, &bp->data[SIZEOF_bar_header]);
+		}
+		namlen = strlen(f->f_name) + 1;
+		f->f_st.st_mode = rdoct(bp->Bdr.b_mode, 8);
+		f->f_st.st_uid = rdoct(bp->Bdr.b_uid, 8);
+		f->f_st.st_gid = rdoct(bp->Bdr.b_gid, 8);
+		f->f_st.st_size = rdoct(bp->Bdr.b_size, 12);
+		f->f_st.st_mtime = rdoct(bp->Bdr.b_mtime, 12);
+		f->f_st.st_rdev = rdoct(bp->Bdr.b_rdev, 8);
+		f->f_rmajor = major(f->f_st.st_rdev);
+		f->f_rminor = minor(f->f_st.st_rdev);
+		switch (bp->Bdr.b_linkflag) {
+		case '0':
+			f->f_st.st_mode &= 07777;
+			if (f->f_name[namlen-2] == '/')
+				f->f_st.st_mode |= S_IFDIR;
+			else
+				f->f_st.st_mode |= S_IFREG;
+			break;
+		case '1':
+			if (f->f_lnam == NULL || f->f_lnam[0] == '\0')
+				blinkof(bp->data, f, namlen);
+			f->f_st.st_nlink = 2;
+			if ((f->f_st.st_mode&S_IFMT) == 0)
+				f->f_st.st_mode |= S_IFREG;
+			break;
+		case '2':
+			if (f->f_lnam == NULL || f->f_lnam[0] == '\0')
+				blinkof(bp->data, f, namlen);
+			f->f_st.st_mode &= 07777;
+			f->f_st.st_mode |= S_IFLNK;
+		}
+		f->f_pad = 512;
+		rd = 512;
+	} else if (fmttype & TYP_TAR) {
+		hsz = 512;
+		if (attempts == 0 && bread(bp->data, hsz) != hsz)
+			unexeoa();
+		if (bp->Tdr.t_name[0] == '\0') {
+			if (kflag && !allzero(bp->data, hsz))
+				goto badhdr;
+			return 1;
+		}
+		if (fmttype == FMT_GNUTAR) {
+			if (memcmp(bp->Tdr.t_magic, mag_gnutar, 8))
+				goto badhdr;
+		} else if (fmttype & TYP_USTAR) {
+			if (memcmp(bp->Tdr.t_magic, mag_ustar, 6))
+				goto badhdr;
+		}
+		if (trdsum(bp) != 0 && kflag == 0)
+			goto badhdr;
+		if ((fmttype & TYP_PAX) == 0 && (fmttype == FMT_GNUTAR ||
+				strcmp(bp->Tdr.t_name, "././@LongLink") == 0)) {
+			switch (bp->Tdr.t_linkflag) {
+			case 'L':
+				if (readgnuname(&f->f_name, &f->f_nsiz,
+						rdoct(bp->Tdr.t_size, 12)) < 0)
+					goto badhdr;
+				goto retry;
+			case 'K':
+				if (readgnuname(&f->f_lnam, &f->f_lsiz,
+						rdoct(bp->Tdr.t_size, 12)) < 0)
+					goto badhdr;
+				goto retry;
+			}
+		}
+		if (fmttype & TYP_USTAR && fmttype != FMT_GNUTAR) {
+			switch (bp->Tdr.t_linkflag) {
+			case 'g':
+			case 'x':
+				if (formatforced && fmttype != FMT_PAX)
+					break;
+				fmttype = FMT_PAX;
+				tgetpax(&bp->Tdr, f);
+				goto retry2;
+			case 'X':
+				if (formatforced && fmttype != FMT_SUN)
+					break;
+				fmttype = FMT_SUN;
+				tgetpax(&bp->Tdr, f);
+				goto retry2;
+			}
+		}
+		if (f->f_name == NULL || f->f_name[0] == '\0') {
+			if (f->f_nsiz < TNAMSIZ+TPFXSIZ+2) {
+				free(f->f_name);
+				f->f_name= smalloc(f->f_nsiz=TNAMSIZ+TPFXSIZ+2);
+			}
+			tnameof(&bp->Tdr, f->f_name);
+		}
+		namlen = strlen(f->f_name) + 1;
+		f->f_st.st_mode = rdoct(bp->Tdr.t_mode, 8) & 07777;
+		if (paxrec & PR_UID)
+			/*EMPTY*/;
+		else if (fmttype == FMT_GNUTAR && bp->Tdr.t_uid[0] & 0200)
+			f->f_st.st_uid = pbe64(bp->Tdr.t_uid) &
+				0x7FFFFFFFFFFFFFFFLL;
+		else
+			f->f_st.st_uid = rdoct(bp->Tdr.t_uid, 8);
+		if (paxrec & PR_GID)
+			/*EMPTY*/;
+		else if (fmttype == FMT_GNUTAR && bp->Tdr.t_gid[0] & 0200)
+			f->f_st.st_gid = pbe64(bp->Tdr.t_gid) &
+				0x7FFFFFFFFFFFFFFFLL;
+		else
+			f->f_st.st_gid = rdoct(bp->Tdr.t_gid, 8);
+		if (paxrec & PR_SIZE)
+			/*EMPTY*/;
+		else if (fmttype == FMT_GNUTAR && bp->Tdr.t_size[0] == '\200')
+			f->f_st.st_size = pbe64(&bp->Tdr.t_size[4]);
+		else
+			f->f_st.st_size = rdoct(bp->Tdr.t_size, 12);
+		if ((paxrec & PR_MTIME) == 0)
+			f->f_st.st_mtime = rdoct(bp->Tdr.t_mtime, TTIMSIZ);
+		if (bp->Tdr.t_linkflag == '1') {
+			if (f->f_lnam == NULL || f->f_lnam[0] == '\0')
+				tlinkof(&bp->Tdr, f);
+			f->f_st.st_mode |= S_IFREG;	/* for -tv */
+			f->f_st.st_nlink = 2;
+		} else if (bp->Tdr.t_linkflag == '2') {
+			if (f->f_lnam == NULL || f->f_lnam[0] == '\0')
+				tlinkof(&bp->Tdr, f);
+			f->f_st.st_mode |= S_IFLNK;
+		} else if (tflag == 0 && (f->f_name)[namlen-2] == '/')
+			f->f_st.st_mode |= S_IFDIR;
+		else
+			f->f_st.st_mode |= tifmt(bp->Tdr.t_linkflag);
+		if (paxrec & PR_SUN_DEVMAJOR)
+			/*EMPTY*/;
+		else if (fmttype == FMT_GNUTAR && bp->Tdr.t_devmajor[0] & 0200)
+			f->f_rmajor = pbe64(bp->Tdr.t_devmajor) &
+				0x7FFFFFFFFFFFFFFFLL;
+		else
+			f->f_rmajor = rdoct(bp->Tdr.t_devmajor, 8);
+		if (paxrec & PR_SUN_DEVMINOR)
+			/*EMPTY*/;
+		else if (fmttype == FMT_GNUTAR && bp->Tdr.t_devminor[0] & 0200)
+			f->f_rminor = pbe64(bp->Tdr.t_devminor) &
+				0x7FFFFFFFFFFFFFFFLL;
+		else
+			f->f_rminor = rdoct(bp->Tdr.t_devminor, 8);
+		f->f_st.st_rdev = makedev(f->f_rmajor, f->f_rminor);
+		f->f_pad = 512;
+		rd = 512;
+	} else if (fmttype == FMT_ZIP) {
+		hsz = SIZEOF_zip_header;
+		if (attempts == 0 && bread(bp->data, hsz) != hsz)
+			unexeoa();
+		if (memcmp(bp->Zdr.z_signature, mag_zipctr,
+					sizeof mag_zipctr) == 0 ||
+				memcmp(bp->Zdr.z_signature, mag_zipend,
+					sizeof mag_zipend) == 0 ||
+				memcmp(bp->Zdr.z_signature, mag_zip64e,
+					sizeof mag_zip64e) == 0 ||
+				memcmp(bp->Zdr.z_signature, mag_zip64l,
+					sizeof mag_zip64l) == 0)
+			return 1;
+		if (memcmp(bp->Zdr.z_signature, mag_zipsig, sizeof mag_zipsig))
+			goto badhdr;
+		f->f_st.st_uid = myuid;
+		f->f_st.st_gid = mygid;
+		f->f_st.st_nlink = 1;
+		f->f_st.st_mtime =
+			gdostime(bp->Zdr.z_modtime, bp->Zdr.z_moddate);
+		f->f_st.st_size = ple32(bp->Zdr.z_nsize);
+		f->f_csize = ple32(bp->Zdr.z_csize);
+		f->f_cmethod = ple16(bp->Zdr.z_cmethod);
+		f->f_chksum = ple32(bp->Zdr.z_crc32);
+		f->f_gflag = ple16(bp->Zdr.z_gflag);
+		rd = SIZEOF_zip_header;
+		namlen = ple16(bp->Zdr.z_namelen)&0177777;
+		if (f->f_nsiz < namlen+1) {
+			free(f->f_name);
+			f->f_name = smalloc(f->f_nsiz = namlen+1);
+		}
+		if (bread(f->f_name, namlen) != namlen)
+			goto corrupt;
+		(f->f_name)[namlen] = '\0';
+		if (f->f_name[namlen-1] == '/')
+			f->f_st.st_mode = 0777&~(mode_t)umsk|S_IFDIR;
+		else
+			f->f_st.st_mode = 0666&~(mode_t)umsk|S_IFREG;
+		rd += namlen;
+		if ((l1 = ziprxtra(f, &bp->Zdr)) < 0)
+			goto corrupt;
+		rd += l1;
+		f->f_pad = 1;
+	} else
+		abort();
+	if (fmttype & TYP_CPIO) {
+		if (f->f_st.st_nlink <= 0 || namlen <= 0 || namlen >= SANELIMIT)
+			goto corrupt;
+		if (namlen > f->f_nsiz) {
+			if (f->f_name)
+				free(f->f_name);
+			f->f_name = smalloc(f->f_nsiz = namlen);
+		}
+		if (bread(f->f_name, namlen) != namlen)
+			unexeoa();
+		if (f->f_name[namlen-1] != '\0')
+			goto corrupt;
+		rd += namlen;
+		skippad(rd, f->f_pad);
+		if (fmttype & TYP_NCPIO &&
+				(!formatforced || fmttype & TYP_SCO)) {
+			/*
+			 * The UnixWare format is a hack, but not a bad
+			 * one. It is backwards compatible as far as
+			 * possible; old implementations can use the -k
+			 * option and will then get only the beginning
+			 * of a large file, but all other files in the
+			 * archive.
+			 */
+			if (namlen >= 24 && memcmp(&f->f_name[namlen-23],
+						"\0size=", 6) == 0) {
+				fmttype |= TYP_SCO;
+				f->f_st.st_size = rdhex(&f->f_name[namlen-17],
+						16);
+			}
+		}
+	}
+	if (attempts) {
+		if (tflag)
+			fflush(stdout);
+		msg(0, 0, sysv3 < 0 ?
+			"Re-synced after skipping %lld bytes.\n" :
+			"Re-synchronized on magic number/header.\n",
+			skipped);
+	}
+	attempts = 0;
+	if (f->f_st.st_atime == 0 || (pax_preserve&(PAX_P_ATIME|PAX_P_EVERY)) ==
+			PAX_P_ATIME)
+		f->f_st.st_atime = f->f_st.st_mtime;
+	if ((f->f_dsize = f->f_st.st_size) < 0)
+		goto badhdr;
+	if (fmttype & TYP_CPIO && strcmp(f->f_name, trailer) == 0)
+		return 1;
+	return 0;
+corrupt:
+	if (kflag) {
+		if (tflag)
+			fflush(stdout);
+		msg(3, 0, "Corrupt header, file(s) may be lost.\n");
+	}
+badhdr:
+	if (kflag) {
+		int	next = fmttype & TYP_TAR ? 512 : 1;
+		if (attempts++ == 0) {
+			if (tflag)
+				fflush(stdout);
+			msg(1, 0, sysv3 < 0 ? "Out of phase; resyncing.\n" :
+				"Searching for magic number/header.\n");
+			errcnt++;
+		}
+		for (l1 = next; l1 < hsz; l1++)
+			bp->data[l1-next] = bp->data[l1];
+		if (bread(&bp->data[l1-next], next) != next)
+			unexeoa();
+		skipped++;
+		goto retry;
+	}
+	if (tflag)
+		fflush(stdout);
+	msg(3, 1, sysv3 < 0 ? "Out of phase--get help\n" :
+			sysv3 > 0 ? "Out of sync, bad magic number/header.\n" :
+			"Bad magic number/header.\n");
+	/*NOTREACHED*/
+	return -1;
+}
+
+/*
+ * Determine the kind of archive on tape.
+ */
+static void
+whathdr(void)
+{
+again:	if (blktop >= SIZEOF_hdr_cpio &&
+			ple16(blkbuf) == mag_bin) {
+		fmttype = FMT_BINLE;
+	} else if (blktop >= SIZEOF_hdr_cpio &&
+			pbe16(blkbuf) == mag_bin) {
+		fmttype = FMT_BINBE;
+	} else if (blktop >= SIZEOF_c_hdr &&
+			memcmp(blkbuf, mag_odc, sizeof mag_odc) == 0) {
+		/*
+		 * The DEC format is rubbish. Instead of introducing a new
+		 * archive magic, its engineers reused the POSIX/odc magic
+		 * and changed the fields. But there's a workaround: For a
+		 * real odc archive, the byte following the file name is a
+		 * \0 byte (unless the archive is damaged, of course). If
+		 * it is not a \0 byte, but a \0 byte appears at the
+		 * corresponding location for the DEC format, this is
+		 * treated as a DEC archive. It must be noted that the
+		 * Tru64 UNIX 5.1 cpio command is too stupid even for
+		 * doing that - it will spill out a list of complaints
+		 * if an extended archive is read but -e is not given.
+		 */
+		int	ns1, ns2;
+		ns1 = rdoct(((struct c_hdr *)blkbuf)->c_namesz, 6);
+		ns2 = rdoct(((struct d_hdr *)blkbuf)->d_namesz, 6);
+		if (blktop >= SIZEOF_d_hdr &&
+				(ns1 >= blktop - SIZEOF_c_hdr ||
+				 blkbuf[SIZEOF_c_hdr+ns1-1] != '\0') &&
+				ns2 <= blktop - SIZEOF_d_hdr &&
+				blkbuf[SIZEOF_d_hdr+ns2-1] == '\0')
+			fmttype = FMT_DEC;
+		else
+			fmttype = FMT_ODC;
+	} else if (blktop >= SIZEOF_Exp_cpio_hdr &&
+			memcmp(blkbuf, mag_asc, sizeof mag_asc) == 0) {
+		fmttype = FMT_ASC;
+	} else if (blktop >= SIZEOF_Exp_cpio_hdr &&
+			memcmp(blkbuf, mag_crc, sizeof mag_crc) == 0) {
+		fmttype = FMT_CRC;
+	} else if (blktop >= SIZEOF_cray_hdr &&
+			pbe64(blkbuf) == mag_bin) {
+		/*
+		 * Old and new Cray headers are identical in the first
+		 * 64 header bytes (including the magic). cpio(5) on
+		 * UNICOS does not describe what the new param field
+		 * is for.
+		 *
+		 * An archive is treated as old format if the mtime
+		 * and namesize fields make sense and all characters
+		 * of the name are non-null.
+		 */
+		struct cray_hdr	*Cp = (struct cray_hdr *)blkbuf;
+		long long	mtime, namesize;
+		fmttype = FMT_CRAY;
+		mtime = pbe64(Cp->C_mtime - CRAY_PARAMSZ);
+		namesize = pbe64(Cp->C_namesize - CRAY_PARAMSZ);
+		if (mtime > 0 && mtime < (1LL<<31) &&
+				namesize > 0 && namesize < 2048 &&
+				blktop > SIZEOF_cray_hdr-
+					CRAY_PARAMSZ+namesize+1) {
+			int	i;
+			for (i = 0; i < namesize; i++)
+				if (blkbuf[SIZEOF_cray_hdr-
+						CRAY_PARAMSZ+i] == '\0')
+					break;
+			if (i == namesize-1)
+				fmttype = FMT_CRAY5;
+		}
+	} else if (blktop >= 512 &&
+			memcmp(&blkbuf[257], mag_ustar, 6) == 0 &&
+			tcssum((union bincpio *)blkbuf, 1) == 0) {
+		fmttype = FMT_USTAR;
+	} else if (blktop >= 512 &&
+			memcmp(&blkbuf[257], mag_gnutar, 8) == 0 &&
+			tcssum((union bincpio *)blkbuf, 1) == 0) {
+		fmttype = FMT_GNUTAR;
+	} else if (blktop >= 512 && blkbuf[0] &&	/* require filename
+							   to avoid match on
+							   /dev/zero etc. */
+			memcmp(&blkbuf[257], "\0\0\0\0\0", 5) == 0 &&
+			tcssum((union bincpio *)blkbuf, 0) == 0) {
+		fmttype = FMT_OTAR;
+	} else if (blktop >= SIZEOF_zip_header &&
+			(memcmp(blkbuf, mag_zipctr, sizeof mag_zipctr) == 0 ||
+			 memcmp(blkbuf, mag_zipsig, sizeof mag_zipsig) == 0 ||
+			 memcmp(blkbuf, mag_zipend, sizeof mag_zipend) == 0 ||
+			 memcmp(blkbuf, mag_zip64e, sizeof mag_zip64e) == 0 ||
+			 memcmp(blkbuf, mag_zip64l, sizeof mag_zip64l) == 0)) {
+		fmttype = FMT_ZIP;
+	} else if (blktop >= 512 && memcmp(blkbuf,"\0\0\0\0\0\0\0\0",8) == 0 &&
+			memcmp(&blkbuf[65], mag_bar, sizeof mag_bar) == 0 &&
+			bcssum((union bincpio *)blkbuf) == 0) {
+		fmttype = FMT_BAR;
+		compressed_bar = blkbuf[71] == '1';
+		curpos = 512;
+	} else if (!Aflag && blktop > 3 && memcmp(blkbuf, "BZh", 3) == 0 &&
+			redirect("bzip2", "-cd") == 0) {
+		goto zip;
+	} else if (!Aflag && blktop > 2 && memcmp(blkbuf, "\37\235", 2) == 0 &&
+			redirect("zcat", NULL) == 0) {
+		goto zip;
+	} else if (!Aflag && blktop > 2 && memcmp(blkbuf, "\37\213", 2) == 0 &&
+			redirect("gzip", "-cd") == 0) {
+		goto zip;
+	} else if (!Aflag && blktop > 4 &&
+			memcmp(blkbuf, "\355\253\356\333", 4) == 0 &&
+			redirect("rpm2cpio", "-") == 0) {
+		goto zip;
+	} else {
+		msg(3, 0, sysv3 ? "This is not a cpio file, bad header.\n" :
+				"Not a cpio file, bad header.\n");
+		done(1);
+	}
+	return;
+zip:
+	blktop = curpos = 0;
+	blocks = 0;
+	bytes = 0;
+	mfl = 0;
+	mstat();
+	if (mread() == 0)
+		unexeoa();
+	goto again;
+}
+
+/*
+ * Processing of a single file with -i.
+ */
+static int
+infile(struct file *f)
+{
+	int	val;
+
+	if ((fmttype & TYP_CPIO || fmttype == FMT_ZIP && f->f_st.st_size) &&
+			(f->f_st.st_mode&S_IFMT) == S_IFLNK) {
+		if (f->f_lsiz < f->f_st.st_size+1)
+			f->f_lnam = srealloc(f->f_lnam,
+					f->f_lsiz = f->f_st.st_size+1);
+		if (bread(f->f_lnam, f->f_st.st_size) != f->f_st.st_size)
+			unexeoa();
+		f->f_lnam[f->f_st.st_size] = '\0';
+		skippad(f->f_st.st_size, f->f_pad);
+	}
+	if (tflag)
+		val = filet(f, indata);
+	else
+		val = filein(f, indata, f->f_name);
+	return val != 0;
+}
+
+/*
+ * Fetch the data of regular files from tape and write it to tfd or, if
+ * tfd < 0, discard it.
+ */
+static int
+indata(struct file *f, const char *tgt, int tfd)
+{
+	char	*buf;
+	size_t	bufsize;
+	struct stat	ts;
+	long long	size;
+	ssize_t	rd;
+	uint32_t	ssum = 0, usum = 0;
+	int	val = 0;
+	int	doswap = 0;
+
+	size = fmttype == FMT_ZIP ? f->f_csize :
+		f->f_Kbase ? f->f_Kbase : f->f_st.st_size;
+	doswap = ((bflag|sflag) == 0 ||
+			ckodd(size, 2, "bytes", f->f_name) == 0) &
+		((bflag|Sflag) == 0 ||
+			 ckodd(size, 4, "halfwords", f->f_name) == 0) &
+		(bflag|sflag|Sflag);
+	if (fmttype == FMT_ZIP && f->f_cmethod != C_STORED)
+		return zipread(f, tgt, tfd, doswap);
+	if (tfd < 0 || fstat(tfd, &ts) < 0)
+		ts.st_blksize = 4096;
+	getbuf(&buf, &bufsize, ts.st_blksize);
+again:	while (size) {
+		if ((rd = bread(buf, size > bufsize ? bufsize : size)) <= 0)
+			unexeoa();
+		if (doswap)
+			swap(buf, rd, bflag || sflag, bflag || Sflag);
+		if (tfd >= 0 && write(tfd, buf, rd) != rd) {
+			emsg(3, "Cannot write \"%s\"", tgt);
+			tfd = -1;
+			val = -1;
+		}
+		size -= rd;
+		if (fmttype & TYP_CRC)
+			do {
+				rd--;
+				ssum += ((signed char *)buf)[rd];
+				usum += ((unsigned char *)buf)[rd];
+			} while (rd);
+	}
+	if (f->f_Kbase) {
+		skippad(f->f_Ksize, f->f_pad);
+		readK2hdr(f);
+		size = f->f_Krest;
+		goto again;
+	}
+	skippad(fmttype==FMT_ZIP ? f->f_csize :
+			f->f_Ksize ? f->f_Krest : f->f_st.st_size, f->f_pad);
+	if (fmttype & TYP_CRC) {
+		if (f->f_chksum != ssum && f->f_chksum != usum) {
+			msg(3, 0, "\"%s\" - checksum error\n", f->f_name);
+			if (kflag)
+				errcnt++;
+			else
+				val = -1;
+		}
+	}
+	return val;
+}
+
+/*
+ * Skip the data for a file on tape.
+ */
+static int
+skipfile(struct file *f)
+{
+	char	b[4096];
+	long long	size;
+	ssize_t	rd;
+
+	if (fmttype & TYP_TAR && ((f->f_st.st_mode&S_IFMT) == S_IFLNK ||
+			f->f_st.st_nlink > 1)) {
+		if (fmttype & TYP_USTAR && (!formatforced ||
+				fmttype == FMT_PAX) &&
+				f->f_st.st_nlink > 1 &&
+				f->f_st.st_size > 0)
+			/*EMPTY*/;
+		else
+			return 0;
+	}
+	/*
+	 * SVR4 cpio derivatives always ignore the size of these,
+	 * even if not reading tar formats. We do the same for now,
+	 * although POSIX (for -H odc format) says the contrary.
+	 */
+	if (fmttype != FMT_ZIP && ((f->f_st.st_mode&S_IFMT) == S_IFDIR ||
+			(f->f_st.st_mode&S_IFMT) == S_IFCHR ||
+			(f->f_st.st_mode&S_IFMT) == S_IFBLK ||
+			(f->f_st.st_mode&S_IFMT) == S_IFIFO ||
+			(f->f_st.st_mode&S_IFMT) == S_IFNAM ||
+			(f->f_st.st_mode&S_IFMT) == S_IFNWK))
+		return 0;
+	if (fmttype == FMT_ZIP && f->f_gflag & FG_DESC)
+		return zipread(f, f->f_name, -1, 0);
+	size = fmttype == FMT_ZIP ? f->f_csize :
+		f->f_Kbase ? f->f_Kbase : f->f_st.st_size;
+again:	while (size) {
+		if ((rd = bread(b, size > sizeof b ? sizeof b : size)) <= 0)
+			unexeoa();
+		size -= rd;
+	}
+	if (f->f_Kbase) {
+		skippad(f->f_Ksize, f->f_pad);
+		readK2hdr(f);
+		size = f->f_Krest;
+		goto again;
+	}
+	skippad(fmttype==FMT_ZIP ? f->f_csize :
+			f->f_Ksize ? f->f_Krest : f->f_st.st_size, f->f_pad);
+	return 0;
+}
+
+/*
+ * Skip data also, but perform checks as if copying.
+ */
+static int
+skipdata(struct file *f, int (*copydata)(struct file *, const char *, int))
+{
+	switch (f->f_st.st_mode&S_IFMT) {
+	case S_IFLNK:
+		break;
+	case S_IFDIR:
+	case S_IFBLK:
+	case S_IFCHR:
+	case S_IFIFO:
+	case S_IFNAM:
+	case S_IFNWK:
+		if (fmttype != FMT_ZIP)
+			break;
+		/*FALLTHRU*/
+	case S_IFREG:
+	default:
+		if (fmttype & TYP_TAR && f->f_st.st_nlink > 1 &&
+				((fmttype & TYP_USTAR) == 0 ||
+				 formatforced && fmttype != FMT_PAX))
+			break;
+		if (copydata(f, f->f_name, -1) != 0)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Seek to a position in the archive measured from the begin of
+ * operation. Handle media-dependent seeks. n must be a multiple
+ * of the tape device's physical block size.
+ */
+static int
+tseek(off_t n)
+{
+	int	fault;
+
+	if (tapeblock > 0) {
+		int	i = (n - poffs) / tapeblock;
+#if defined (__linux__) || defined (__sun) || defined (__FreeBSD__) || \
+	defined (__hpux) || defined (_AIX) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+		struct mtop	mo;
+		mo.mt_op = i > 0 ? MTFSR : MTBSR;
+		mo.mt_count = i > 0 ? i : -i;
+		fault = ioctl(mt, MTIOCTOP, &mo);
+#else	/* SVR4.2MP */
+		int	t, a;
+		t = i > 0 ? T_SBF : T_SBB;
+		a = i > 0 ? i : -i;
+		fault = ioctl(mt, t, a);
+#endif	/* SVR4.2MP */
+	} else
+		fault = lseek(mt, n - poffs, SEEK_CUR) == (off_t)-1 ? -1 : 0;
+	if (fault == 0)
+		poffs = n;
+	return fault;
+}
+
+/*
+ * Advance to the trailer on the tape (for -A).
+ */
+static int
+totrailer(void)
+{
+	union bincpio	bc;
+	struct file	f;
+	off_t	ooffs, noffs, diff;
+	int	i;
+
+	if (mread() == 0)
+		unexeoa();
+	if (fmttype == FMT_NONE)
+		whathdr();
+	memset(&f, 0, sizeof f);
+	for (;;) {
+		ooffs = aoffs;
+		if ((i = readhdr(&f, &bc)) < 0)
+			goto fail;
+		if (i > 0)
+			break;
+		markdev(f.f_st.st_dev);
+		if (skipfile(&f) != 0)
+			goto fail;
+		if (fmttype == FMT_ZIP)
+			zipdefer(f.f_name, &f.f_st, ooffs,
+					f.f_chksum, f.f_csize, &bc.Zdr);
+		pax_track(f.f_name, f.f_st.st_mtime);
+	}
+	/*
+	 * Now seek to the position of the trailer, but retain the
+	 * block alignment.
+	 */
+	diff = ooffs % blksiz;
+	noffs = ooffs - diff;
+	if (diff ? tseek(noffs) == 0 && mread() >= diff && tseek(noffs) == 0
+			: tseek(ooffs) == 0) {
+		free(f.f_name);
+		free(f.f_lnam);
+		nwritten = ooffs;
+		curpos = diff;
+		return 0;
+	}
+fail:	msg(4, 1, "Unable to append to this archive\n");
+	/*NOTREACHED*/
+	return 1;
+}
+
+static long long
+rdoct(const char *data, int len)
+{
+	int	i;
+	long long	val = 0;
+
+	for (i = 0; i < len && data[i] == ' '; i++);
+	for ( ; i < len && data[i] && data[i] != ' '; i++) {
+		val <<= 3;
+		val += data[i] - '0';
+	}
+	return val;
+}
+
+static long long
+rdhex(const char *data, int len)
+{
+	int	i;
+	long long	val = 0;
+
+	for (i = 0; i < len && data[i] == ' '; i++);
+	for ( ; i < len && data[i] && data[i] != ' '; i++) {
+		val <<= 4;
+		val += data[i] > '9' ? data[i] > 'F' ? data[i] - 'a' + 10 :
+			data[i] - 'A' + 10 : data[i] - '0';
+	}
+	return val;
+}
+
+void
+unexeoa(void)
+{
+	if (sysv3) {
+		fprintf(stderr,
+		"Can't read input:  end of file encountered "
+			"prior to expected end of archive.\n");
+		done(1);
+	}
+	else
+		msg(3, 1, "Unexpected end-of-archive encountered.\n");
+}
+
+static char	*peekdata;
+static size_t	peekbot, peektop, peeksize;
+
+void
+bunread(const char *data, size_t sz)
+{
+	peekdata = srealloc(peekdata, peeksize += sz);
+	memcpy(&peekdata[peekbot], data, sz);
+	peektop += sz;
+	aoffs -= sz;
+}
+
+/*
+ * Buffered read of data from tape. sz is the amount of data required
+ * by the archive format; if it cannot be retrieved, processing fails.
+ */
+ssize_t
+bread(char *data, size_t sz)
+{
+	ssize_t	rd = 0;
+
+	if (peekdata) {
+		rd = sz>peektop-peekbot ? peektop-peekbot : sz;
+		memcpy(&data[0], &peekdata[peekbot], rd);
+		sz -= rd;
+		peekbot += rd;
+		if (peekbot == peektop) {
+			free(peekdata);
+			peekdata = 0;
+			peeksize = 0;
+			peekbot = peektop = 0;
+		}
+	}
+	while (sz) {
+		if (blktop - curpos >= sz) {
+			memcpy(&data[rd], &blkbuf[curpos], sz);
+			curpos += sz;
+			rd += sz;
+			aoffs += rd;
+			return rd;
+		}
+		if (blktop > curpos) {
+			memcpy(&data[rd], &blkbuf[curpos], blktop - curpos);
+			rd += blktop - curpos;
+			sz -= blktop - curpos;
+			curpos = blktop;
+		}
+		if (mfl < 0) {
+			if (mfl == -1) {
+				emsg(3, "I/O error on \"%s\"",
+						Iflag ? Iflag : "input");
+				if (kflag == 0)
+					break;
+				if (tapeblock < 0 && (
+						(mtst.st_mode&S_IFMT)==S_IFBLK||
+						(mtst.st_mode&S_IFMT)==S_IFCHR||
+						(mtst.st_mode&S_IFMT)==S_IFREG
+						) && lseek(mt, blksiz, SEEK_CUR)
+							== (off_t)-1) {
+					emsg(3, "Cannot lseek()");
+					done(1);
+				}
+			}
+			if (kflag == 0 || mfl == -2) {
+				if ((mtst.st_mode&S_IFMT)!=S_IFCHR &&
+						(mtst.st_mode&S_IFMT)!=S_IFBLK)
+					break;
+				newmedia(mfl == -1 ? errno : 0);
+				if (mfl == -1) {
+					mfl = -2;
+					break;
+				}
+				if (fmttype & TYP_BAR)
+					curpos = 512;
+			}
+		}
+		mread();
+	}
+	aoffs += rd;
+	return rd;
+}
+
+/*
+ * Read a block of data from tape.
+ */
+static ssize_t
+mread(void)
+{
+	ssize_t	ro, rt = 0;
+
+	do {
+		if ((ro = read(mt, blkbuf + rt, blksiz - rt)) <= 0) {
+			if (ro < 0) {
+				if (errno == EINTR)
+					continue;
+				mfl = -1;
+			} else
+				mfl = -2;
+			if (rt > 0) {
+				rt += ro;
+				break;
+			}
+			curpos = blktop = 0;
+			return ro;
+		}
+		rt += ro;
+		poffs += ro;
+		if (tapeblock == 0) {
+			tapeblock = ro;
+			if (!Bflag && !Cflag)
+				blksiz = ro;
+		}
+	} while (rt < blksiz);
+	curpos = 0;
+	blocks += rt >> 9;
+	bytes += rt & 0777;
+	blktop = rt;
+	return rt;
+}
+
+/*
+ * Look what kind of tape or other archive media we are working on and
+ * set the buffer size appropriately (if not specified by the user).
+ */
+static void
+mstat(void)
+{
+	if (fstat(mt, &mtst) < 0) {
+		emsg(3, "Error during stat() of archive");
+		done(1);
+	}
+#if defined (__linux__)
+	if ((mtst.st_mode&S_IFMT) == S_IFCHR) {
+		struct mtget	mg;
+		if (ioctl(mt, MTIOCGET, &mg) == 0)
+			tapeblock = (mg.mt_dsreg&MT_ST_BLKSIZE_MASK) >>
+					MT_ST_BLKSIZE_SHIFT;
+	} else if ((mtst.st_mode&S_IFMT) == S_IFBLK) {
+		/*
+		 * If using a block device, write blocks of the floppy
+		 * disk sector with direct i/o. This enables signals
+		 * after each block is written instead of being ~40
+		 * seconds in uninterruptible sleep when calling close()
+		 * later. For block devices other than floppies, use the 
+		 * kernel defined i/o block size. For floppies, use direct
+		 * i/o even when reading since it is faster.
+		 */
+		struct floppy_struct	fs;
+		int	floppy = -1;
+		int	blkbsz;
+
+		if (blksiz == 0) {
+			if ((floppy = ioctl(mt, FDGETPRM, &fs)) == 0)
+				blksiz = fs.sect * FD_SECTSIZE(&fs);
+#ifdef	BLKBSZGET
+			else if (ioctl(mt, BLKBSZGET, &blkbsz) == 0)
+				blksiz = blkbsz;
+#endif	/* BLKBSZGET */
+		}
+#ifdef	O_DIRECT
+		if ((action == 'o' || floppy == 0) && blksiz != 0) {
+			int	flags;
+			if ((flags = fcntl(mt, F_GETFL)) != -1)
+				fcntl(mt, F_SETFL, flags | O_DIRECT);
+		}
+	}
+#endif	/* O_DIRECT */
+#elif defined (__sun)
+	if ((mtst.st_mode&S_IFMT) == S_IFCHR) {
+		struct mtdrivetype_request	mr;
+		static struct mtdrivetype	md;
+		mr.size = sizeof md;
+		mr.mtdtp = &md;
+		if (ioctl(mt,  MTIOCGETDRIVETYPE, &mr) == 0)
+			tapeblock = md.bsize;
+	}
+#elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
+		|| defined (__DragonFly__) || defined (__APPLE__)
+	if ((mtst.st_mode&S_IFMT) == S_IFCHR) {
+		struct mtget	mg;
+		if (ioctl(mt, MTIOCGET, &mg) == 0)
+			tapeblock = mg.mt_blksiz;
+	}
+#elif defined (__hpux) || defined (_AIX)
+#else	/* SVR4.2MP */
+	if ((mtst.st_mode&S_IFMT) == S_IFCHR) {
+		struct blklen	bl;
+		if (ioctl(mt, T_RDBLKLEN, &bl) == 0)
+			/*
+			 * These are not the values we're interested in
+			 * (always 1 and 16M-1 for DAT/DDS tape drives).
+			 */
+			tapeblock = 0;
+	}
+#endif	/* SVR4.2MP */
+	if (blksiz == 0)
+		switch (mtst.st_mode&S_IFMT) {
+		case S_IFREG:
+		case S_IFBLK:
+			blksiz = 4096;
+			break;
+		case S_IFCHR:
+			if (action == 'o' && !Aflag) {
+				if (pax != PAX_TYPE_CPIO) {
+					if (fmttype & TYP_PAX)
+						blksiz = 5120;
+					else if (fmttype & TYP_TAR)
+						blksiz = 10240;
+					else if (fmttype & TYP_CPIO)
+						blksiz = 5120;
+					else
+						blksiz = 512;
+				} else
+					blksiz = tapeblock>0 ? tapeblock : 512;
+			} else
+				blksiz = tapeblock > 0 && tapeblock % 1024 ?
+					tapeblock : tapeblock > 10240 ?
+					tapeblock : 10240;
+			break;
+		default:
+			blksiz = 512;
+		}
+}
+
+/*
+ * Skip tape data such that size becomes aligned to pad.
+ */
+static int
+skippad(unsigned long long size, int pad)
+{
+	char	b[512];
+	int	to;
+
+	if ((to = size % pad) != 0) {
+		if (bread(b, pad - to) != pad - to)
+			unexeoa();
+	}
+	return 0;
+}
+
+static int
+allzero(const char *bp, int n)
+{
+	int	i;
+
+	for (i = 0; i < n; i++)
+		if (bp[i] != '\0')
+			return 0;
+	return 1;
+}
+
+#define	CACHESIZE	16
+
+static const char *
+getuser(uid_t uid)
+{
+	static struct {
+		char	*name;
+		uid_t	uid;
+	} cache[CACHESIZE];
+	static int	last;
+	int	i;
+	struct passwd	*pwd;
+	const char	*name;
+
+	for (i = 0; i < CACHESIZE && cache[i].name; i++)
+		if (cache[i].uid == uid)
+			goto found;
+	if ((pwd = getpwuid(uid)) != NULL)
+		name = pwd->pw_name;
+	else
+		name = "";
+	if (i >= CACHESIZE) {
+		if (last >= CACHESIZE)
+			last = 0;
+		i = last++;
+	}
+	if (cache[i].name)
+		free(cache[i].name);
+	cache[i].name = sstrdup(name);
+	cache[i].uid = uid;
+found:	return cache[i].name[0] ? cache[i].name : NULL;
+}
+
+static const char *
+getgroup(gid_t gid)
+{
+	static struct {
+		char	*name;
+		gid_t	gid;
+	} cache[CACHESIZE];
+	static int	last;
+	int	i;
+	struct group	*grp;
+	const char	*name;
+
+	for (i = 0; i < CACHESIZE && cache[i].name; i++)
+		if (cache[i].gid == gid)
+			goto found;
+	if ((grp = getgrgid(gid)) != NULL)
+		name = grp->gr_name;
+	else
+		name = "";
+	if (i >= CACHESIZE) {
+		if (last >= CACHESIZE)
+			last = 0;
+		i = last++;
+	}
+	if (cache[i].name)
+		free(cache[i].name);
+	cache[i].name = sstrdup(name);
+	cache[i].gid = gid;
+found:	return cache[i].name[0] ? cache[i].name : NULL;
+}
+
+/*
+ * Return a version of the passed string that contains at most one '%d'
+ * and no other printf formats.
+ */
+char *
+oneintfmt(const char *op)
+{
+	char	*new, *np;
+	int	no = 0;
+
+	np = new = smalloc(2 * strlen(op) + 1);
+	do {
+		if (*op == '%') {
+			*np++ = *op++;
+			if (*op != '%')
+				if (*op != 'd' || no++)
+					*np++ = '%';
+		}
+		*np++ = *op;
+	} while (*op++);
+	return new;
+}
+
+char *
+sstrdup(const char *op)
+{
+	char	*np;
+
+	np = smalloc(strlen(op) + 1);
+	strcpy(np, op);
+	return np;
+}
+
+/*
+ * Add this pattern to the extraction list with -i.
+ */
+void
+addg(const char *pattern, int art)
+{
+	struct glist	*gp;
+
+	gp = scalloc(1, sizeof *gp);
+	if (pax == PAX_TYPE_CPIO && pattern[0] == '!') {
+		gp->g_not = 1;
+		pattern++;
+	}
+	gp->g_pat = sstrdup(pattern);
+	gp->g_art = art;
+	if (pax != PAX_TYPE_CPIO) {
+		struct glist	*gb = NULL, *gc;
+		for (gc = patterns; gc; gc = gc->g_nxt)
+			gb = gc;
+		if (gb)
+			gb->g_nxt = gp;
+		else
+			patterns = gp;
+	} else {
+		gp->g_nxt = patterns;
+		patterns = gp;
+	}
+}
+
+/*
+ * Check if the file name s matches any of the given patterns.
+ */
+static struct glist *
+want(struct file *f, struct glist **gb)
+{
+	extern int	gmatch(const char *, const char *);
+	struct glist	*gp;
+
+	for (gp = patterns; gp; gp = gp->g_nxt) {
+		if ((gmatch(f->f_name, gp->g_pat) != 0) ^ gp->g_not &&
+				(pax_nflag == 0 || gp->g_gotcha == 0)) {
+			return gp;
+		}
+		*gb = gp;
+	}
+	return NULL;
+}
+
+static void
+patfile(void)
+{
+	struct iblok	*ip;
+	char	*name = NULL;
+	size_t	namsiz = 0, namlen;
+
+	if ((ip = ib_open(Eflag, 0)) == NULL)
+		msg(3, -2, "Cannot open \"%s\" to read patterns\n", Eflag);
+	while ((namlen = ib_getlin(ip, &name, &namsiz, srealloc)) != 0) {
+		if (name[namlen-1] == '\n')
+			name[--namlen] = '\0';
+		addg(name, 0);
+	}
+	ib_close(ip);
+}
+
+void
+swap(char *b, size_t sz, int s8, int s16)
+{
+	uint8_t	u8;
+	uint16_t	u16;
+	union types2	*t2;
+	union types4	*t4;
+	int	i;
+
+	if (s8) {
+		for (i = 0; i < (sz >> 1); i++) {
+			t2 = &((union types2 *)b)[i];
+			u8 = t2->byte[0];
+			t2->byte[0] = t2->byte[1];
+			t2->byte[1] = u8;
+		}
+	}
+	if (s16) {
+		for (i = 0; i < (sz >> 2); i++) {
+			t4 = &((union types4 *)b)[i];
+			u16 = t4->sword[0];
+			t4->sword[0] = t4->sword[1];
+			t4->sword[1] = u16;
+		}
+	}
+}
+
+static int
+ckodd(long long size, int mod, const char *str, const char *fn)
+{
+	if (size % mod) {
+		msg(3, 0, "Cannot swap %s of \"%s\", odd number of %s\n",
+				str, fn, str);
+		errcnt++;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Interactive rename (-r option).
+ */
+static int
+rname(char **oldp, size_t *olds)
+{
+	char	*new = NULL;
+	size_t	newsize = 0;
+	int	i, r;
+	char	c;
+
+	fprintf(stderr, "Rename \"%s\"? ", *oldp);
+	if (tty == 0)
+		if ((tty = open("/dev/tty", O_RDWR)) < 0 ||
+				fcntl(tty, F_SETFD, FD_CLOEXEC) < 0)
+		err:	msg(3, 1, "Cannot read tty.\n");
+	i = 0;
+	while ((r = read(tty, &c, 1)) == 1 && c != '\n') {
+		if (i+1 >= newsize)
+			new = srealloc(new, newsize += 32);
+		new[i++] = c;
+	}
+	if (r <= 0)
+		goto err;
+	if (new == NULL)
+		return 0;
+	new[i] = '\0';
+	if (new[0] == '.' && new[1] == '\0') {
+		free(new);
+	} else {
+		free(*oldp);
+		*oldp = new;
+		*olds = newsize;
+	}
+	return 1;
+}
+
+/*
+ * Filter data from tape through the commands given in arg?.
+ */
+static int
+redirect(const char *arg0, const char *arg1)
+{
+	int	pd[2];
+
+	if (pipe(pd) < 0)
+		return -1;
+	switch (fork()) {
+	case 0:
+		if (tapeblock>=0 || lseek(mt, -blktop, SEEK_CUR) == (off_t)-1) {
+			int	xpd[2];
+			if (pipe(xpd) == 0 && fork() == 0) {
+				ssize_t	rd, wo, wt;
+				close(xpd[0]);
+				do {
+					wo = wt = 0;
+					do {
+						if ((wo = write(xpd[1],
+								blkbuf + wt,
+								blktop - wt))
+									<= 0) {
+							if (errno == EINTR)
+								continue;
+							_exit(0);
+						}
+						wt += wo;
+					} while (wt < blktop);
+				} while ((rd = mread()) >= 0);
+				if (rd < 0) {
+					emsg(3, "Read error on \"%s\"",
+							Iflag && !sysv3 ?
+							Iflag : "input");
+				}
+				_exit(0);
+			} else {
+				close(xpd[1]);
+				dup2(xpd[0], 0);
+				close(xpd[0]);
+			}
+		} else {
+			dup2(mt, 0);
+		}
+		close(mt);
+		dup2(pd[1], 1);
+		close(pd[0]);
+		close(pd[1]);
+		execlp(arg0, arg0, arg1, NULL);
+		fprintf(stderr, "%s: could not exec %s: %s\n",
+				progname, arg0, strerror(errno));
+		_exit(0177);
+		/*NOTREACHED*/
+	default:
+		dup2(pd[0], mt);
+		close(pd[0]);
+		close(pd[1]);
+		tapeblock = -1;
+		break;
+	case -1:
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Get the name stored in a tar header. buf is expected to be at least
+ * TPFXSIZ+TNAMSIZ+2 bytes.
+ */
+static char *
+tnameof(struct tar_header *hp, char *buf)
+{
+	const char	*cp;
+	char	*bp = buf;
+
+	if (fmttype & TYP_USTAR && fmttype != FMT_GNUTAR &&
+			hp->t_prefix[0] != '\0') {
+		cp = hp->t_prefix;
+		while (cp < &hp->t_prefix[TPFXSIZ] && *cp)
+			*bp++ = *cp++;
+		if (bp > buf)
+			*bp++ = '/';
+	}
+	cp = hp->t_name;
+	while (cp < &hp->t_name[TNAMSIZ] && *cp)
+		*bp++ = *cp++;
+	*bp = '\0';
+	return buf;
+}
+
+/*
+ * Store fn as file name in a tar header.
+ */
+static int
+tmkname(struct tar_header *hp, const char *fn)
+{
+	const char	*cp, *cs = NULL;
+
+	for (cp = fn; *cp; cp++) {
+		if (fmttype & TYP_USTAR && *cp == '/' && cp[1] != '\0' &&
+				cp > fn && cp-fn <= TPFXSIZ)
+			cs = cp;
+	}
+	if (fmttype == FMT_GNUTAR && cp - fn > 99) {
+		writegnuname(fn, cp - fn + 1, 'L');
+		cp = &fn[99];
+	} else if (cp - (cs ? &cs[1] : fn) > TNAMSIZ) {
+		if (fmttype & TYP_PAX && utf8(fn)) {
+			paxrec |= PR_PATH;
+			strcpy(hp->t_name, sequence());
+			return 0;
+		}
+		msg(3, 0, "%s: file name too long\n", fn);
+		return -1;
+	}
+	if (cs && cp - fn > TNAMSIZ) {
+		memcpy(hp->t_prefix, fn, cs - fn);
+		if (cs - fn < TPFXSIZ)
+			hp->t_prefix[cs - fn] = '\0';
+		memcpy(hp->t_name, &cs[1], cp - &cs[1]);
+		if (cp - &cs[1] < TNAMSIZ)
+			hp->t_name[cp - &cs[1]] = '\0';
+	} else {
+		memcpy(hp->t_name, fn, cp - fn);
+		if (cp - fn < TNAMSIZ)
+			hp->t_name[cp - fn] = '\0';
+	}
+	return 0;
+}
+
+/*
+ * Get the link name of a tar header.
+ */
+static void
+tlinkof(struct tar_header *hp, struct file *f)
+{
+	const char	*cp;
+	char	*bp;
+
+
+	if (f->f_lsiz < TNAMSIZ+1)
+		f->f_lnam = srealloc(f->f_lnam, f->f_lsiz = TNAMSIZ+1);
+	cp = hp->t_linkname;
+	bp = f->f_lnam;
+	while (cp < &hp->t_linkname[TNAMSIZ] && *cp)
+		*bp++ = *cp++;
+	*bp = '\0';
+}
+
+/*
+ * Create the link name in a tar header.
+ */
+static int
+tmklink(struct tar_header *hp, const char *fn)
+{
+	const char	*cp;
+
+	for (cp = fn; *cp; cp++);
+	if (fmttype == FMT_GNUTAR && cp - fn > 99) {
+		writegnuname(fn, cp - fn + 1, 'K');
+		cp = &fn[99];
+	} else if (cp - fn > TNAMSIZ) {
+		if (fmttype & TYP_PAX && utf8(fn)) {
+			paxrec |= PR_LINKPATH;
+			strcpy(hp->t_linkname, sequence());
+			return 0;
+		}
+		msg(3, 0, "%s: linked name too long\n", fn);
+		return -1;
+	}
+	memcpy(hp->t_linkname, fn, cp - fn);
+	if (cp - fn < TNAMSIZ)
+		hp->t_linkname[cp - fn] = '\0';
+	return 0;
+}
+
+static int
+tlflag(struct stat *st)
+{
+	if (fmttype & TYP_BAR) {
+		switch (st->st_mode & S_IFMT) {
+		case S_IFREG:
+		case S_IFDIR:
+			return '0';
+		case S_IFLNK:
+			return '2';
+		default:
+			return '3';
+		}
+	} else if (fmttype & TYP_USTAR) {
+		switch (st->st_mode & S_IFMT) {
+		case S_IFREG:
+			return '0';
+		case S_IFLNK:
+			return '2';
+		case S_IFCHR:
+			return '3';
+		case S_IFBLK:
+			return '4';
+		case S_IFDIR:
+			return '5';
+		case S_IFIFO:
+			return '6';
+		default:
+			return -1;
+		}
+	} else {
+		switch (st->st_mode & S_IFMT) {
+		case S_IFREG:
+			return '\0';
+		case S_IFLNK:
+			return '2';
+		default:
+			return -1;
+		}
+	}
+}
+
+/*
+ * Ustar checksums are created using unsigned chars, as specified by
+ * POSIX. Traditional tar implementations use signed chars. Some
+ * implementations (notably SVR4 cpio derivatives) use signed chars
+ * even for ustar archives, but this is clearly an implementation bug.
+ */
+static void
+tchksum(union bincpio *bp)
+{
+	uint32_t	sum;
+	char	*cp;
+
+	memset(bp->Tdr.t_chksum, ' ', sizeof bp->Tdr.t_chksum);
+	sum = 0;
+	if (fmttype & TYP_USTAR)
+		for (cp = bp->data; cp < &bp->data[512]; cp++)
+			sum += *((unsigned char *)cp);
+	else
+		for (cp = bp->data; cp < &bp->data[512]; cp++)
+			sum += *((signed char *)cp);
+	sprintf(bp->Tdr.t_chksum, "%7.7o", sum);
+}
+
+static int
+tcssum(union bincpio *bp, int ustar)
+{
+	uint32_t	ssum = 0, usum = 0, osum;
+	char	ochk[sizeof bp->Tdr.t_chksum];
+	char	*cp;
+
+	osum = rdoct(bp->Tdr.t_chksum, 8);
+	memcpy(ochk, bp->Tdr.t_chksum, sizeof ochk);
+	memset(bp->Tdr.t_chksum, ' ', sizeof bp->Tdr.t_chksum);
+	for (cp = bp->data; cp < &bp->data[512]; cp++) {
+		ssum += *((signed char *)cp);
+		usum += *((unsigned char *)cp);
+	}
+	memcpy(bp->Tdr.t_chksum, ochk, sizeof bp->Tdr.t_chksum);
+	return ssum != osum && usum != osum;
+}
+
+static int
+trdsum(union bincpio *bp)
+{
+	int	i;
+
+	if (fmttype & TYP_BAR)
+		i = bcssum(bp);
+	else
+		i = tcssum(bp, fmttype & TYP_USTAR);
+	if (i)
+		msg(3, 0, "Bad header - checksum error.\n");
+	return i;
+}
+
+static mode_t
+tifmt(int c)
+{
+	switch (c) {
+	default:
+	case '\0':
+	case '0':
+		return S_IFREG;
+	case '2':
+		return S_IFLNK;
+	case '3':
+		return S_IFCHR;
+	case '4':
+		return S_IFBLK;
+	case '5':
+		return S_IFDIR;
+	case '6':
+		return S_IFIFO;
+	}
+}
+
+/*
+ * bar format support functions.
+ */
+static void
+bchksum(union bincpio *bp)
+{
+	uint32_t	sum;
+	char	*cp;
+
+	memset(bp->Bdr.b_chksum, ' ', sizeof bp->Bdr.b_chksum);
+	sum = 0;
+	for (cp = bp->data; cp < &bp->data[512]; cp++)
+		sum += *((signed char *)cp);
+	sprintf(bp->Bdr.b_chksum, "%7.7o", sum);
+}
+
+static int
+bcssum(union bincpio *bp)
+{
+	uint32_t	sum, osum;
+	char	ochk[sizeof bp->Bdr.b_chksum];
+	char	*cp;
+
+	osum = rdoct(bp->Bdr.b_chksum, 8);
+	memcpy(ochk, bp->Bdr.b_chksum, sizeof ochk);
+	memset(bp->Bdr.b_chksum, ' ', sizeof bp->Bdr.b_chksum);
+	sum = 0;
+	for (cp = bp->data; cp < &bp->data[512]; cp++)
+		sum += *((signed char *)cp);
+	memcpy(bp->Bdr.b_chksum, ochk, sizeof bp->Bdr.b_chksum);
+	return sum != osum;
+}
+
+static void
+blinkof(const char *cp, struct file *f, int namlen)
+{
+	if (f->f_lsiz < 512)
+		f->f_lnam = srealloc(f->f_lnam, f->f_lsiz = 512);
+	strcpy(f->f_lnam, &cp[SIZEOF_bar_header + namlen]);
+}
+
+static void
+dump_barhdr(void)
+{
+	union bincpio	bc;
+	static int	volno;
+	static time_t	now = -1;
+
+	memset(&bc, 0, 512);
+	sprintf(bc.Bdr.b_uid, "%d", myuid & 07777777);
+	sprintf(bc.Bdr.b_gid, "%d", mygid & 07777777);
+	bc.Bdr.b_size[0] = '0';
+	memcpy(bc.Bdr.b_bar_magic, mag_bar, sizeof bc.Bdr.b_bar_magic);
+	sprintf(bc.Bdr.b_volume_num, "%d", ++volno & 0777);
+	bc.Bdr.b_compressed = '0';
+	if (now == (time_t)-1)
+		time(&now);
+	sprintf(bc.Bdr.b_date, "%llo", now & 077777777777LL);
+	bchksum(&bc);
+	bwrite(bc.data, 512);
+}
+
+/*
+ * Support for compressed bar format (any regular file is piped through zcat).
+ */
+static pid_t	zpid;
+
+static int
+zcreat(const char *name, mode_t mode)
+{
+	int	pd[2];
+	int	fd;
+
+	if (pipe(pd) < 0)
+		return -1;
+	if ((fd = creat(name, mode)) < 0) {
+		fd = errno;
+		close(pd[0]);
+		close(pd[1]);
+		errno = fd;
+		return -1;
+	}
+	switch (zpid = fork()) {
+	case -1:
+		return -1;
+	case 0:
+		dup2(pd[0], 0);
+		dup2(fd, 1);
+		close(pd[0]);
+		close(pd[1]);
+		close(fd);
+		execlp("zcat", "zcat", NULL);
+		_exit(0177);
+		/*NOTREACHED*/
+	}
+	close(pd[0]);
+	close(fd);
+	sigset(SIGPIPE, SIG_IGN);
+	return pd[1];
+}
+
+static int
+zclose(int fd)
+{
+	int	c, s;
+
+	c = close(fd);
+	while (waitpid(zpid, &s, 0) != zpid);
+	return c != 0 || s != 0 ? -1 : 0;
+}
+
+/*
+ * If using the -A option, device numbers that appear in the archive
+ * are not reused for appended files. This avoids wrong hardlink
+ * connections on extraction.
+ *
+ * In fact, this should be done even if we did not fake device and
+ * inode numbers, since it is not guaranteed that the archive was
+ * created on the same machine, or even on the same machine, inode
+ * number could have changed after a file was unlinked.
+ */
+static void
+markdev(dev_t dev)
+{
+	struct dslot	*dp, *dq = NULL;;
+
+	for (dp = markeddevs; dp; dp = dp->d_nxt) {
+		if (dp->d_dev == dev)
+			return;
+		dq = dp;
+	}
+	dp = scalloc(1, sizeof *dp);
+	dp->d_dev = dev;
+	if (markeddevs == NULL)
+		markeddevs = dp;
+	else
+		dq->d_nxt = dp;
+}
+
+static int
+marked(dev_t dev)
+{
+	struct dslot	*dp;
+
+	for (dp = markeddevs; dp; dp = dp->d_nxt)
+		if (dp->d_dev == dev)
+			return 1;
+	return 0;
+}
+
+static void
+cantsup(int err, const char *file)
+{
+	if (sysv3)
+		msg(err ? 3 : 2, 0,
+			"format can't support expanded types on %s\n",
+			file);
+	else
+		msg(0, 0, "%s format can't support expanded types on %s\n",
+			err ? "Error" : "Warning", file);
+	errcnt++;
+}
+
+static void
+onint(int signo)
+{
+	if (cur_ofile && cur_tfile && rename(cur_tfile, cur_ofile) < 0)
+		emsg(3, "Cannot recover original \"%s\"", cur_ofile);
+	if (cur_ofile && cur_tfile == NULL && unlink(cur_ofile) < 0)
+		emsg(3, "Cannot remove incomplete \"%s\"", cur_ofile);
+	exit(signo | 0200);
+}
+
+/*
+ * Read the compressed zip data part for a file.
+ */
+static int
+zipread(struct file *f, const char *tgt, int tfd, int doswap)
+{
+	int	val = 0;
+	uint32_t	crc = 0;
+
+	if (f->f_gflag & FG_DESC) {
+		if (f->f_cmethod != C_DEFLATED && f->f_cmethod != C_ENHDEFLD ||
+				f->f_gflag & FG_CRYPT)
+			msg(4, 1, "Cannot handle zip data descriptor\n");
+		f->f_csize = 0x7FFFFFFFFFFFFFFFLL;
+		f->f_st.st_size = 0x7FFFFFFFFFFFFFFFLL;
+	} else if (tfd < 0)
+		return skipfile(f);
+	if (f->f_gflag & FG_CRYPT)
+		return cantunzip(f, "encrypted");
+	switch (f->f_cmethod) {
+	case C_DEFLATED:
+	case C_ENHDEFLD:
+		val = zipinflate(f, tgt, tfd, doswap, &crc);
+		break;
+	case C_SHRUNK:
+		val = zipunshrink(f, tgt, tfd, doswap, &crc);
+		break;
+	case C_IMPLODED:
+		val = zipexplode(f, tgt, tfd, doswap, &crc);
+		break;
+	case C_REDUCED1:
+	case C_REDUCED2:
+	case C_REDUCED3:
+	case C_REDUCED4:
+		val = zipexpand(f, tgt, tfd, doswap, &crc);
+		break;
+	case C_TOKENIZED:
+		return cantunzip(f, "tokenized");
+	case C_DCLIMPLODED:
+		val = zipblast(f, tgt, tfd, doswap, &crc);
+		break;
+	case C_BZIP2:
+#if USE_BZLIB
+		val = zipunbz2(f, tgt, tfd, doswap, &crc);
+		break;
+#else	/* !USE_BZLIB */
+		return cantunzip(f, "bzip2 compressed");
+#endif	/* !USE_BZLIB */
+	default:
+		return cantunzip(f, "compressed");
+	}
+	if (f->f_gflag & FG_DESC)
+		zipreaddesc(f);
+	if (val == 0 && crc != f->f_chksum) {
+		msg(3, 0, "\"%s\" - checksum error\n", f->f_name);
+		return -1;
+	}
+	return val;
+}
+
+/*
+ * Read a zip data descriptor (i. e. a field after the compressed data
+ * that contains the actual values for sizes and crc).
+ */
+static void
+zipreaddesc(struct file *f)
+{
+	if (f->f_oflag & OF_ZIP64) {
+		struct	zipddesc64	zd64;
+		bread((char *)&zd64, SIZEOF_zipddesc64);
+		if (memcmp(zd64.zd_signature, mag_zipdds, sizeof mag_zipdds))
+			msg(4, 1, "Invalid zip data descriptor\n");
+		f->f_chksum = ple32(zd64.zd_crc32);
+		f->f_dsize = f->f_st.st_size = ple64(zd64.zd_nsize) &
+			0xFFFFFFFFFFFFFFFFULL;
+		f->f_csize = ple64(zd64.zd_csize) &
+			0xFFFFFFFFFFFFFFFFULL;
+	} else {
+		struct	zipddesc zd;
+		bread((char *)&zd, SIZEOF_zipddesc);
+		if (memcmp(zd.zd_signature, mag_zipdds, sizeof mag_zipdds))
+			msg(4, 1, "Invalid zip data descriptor\n");
+		f->f_chksum = ple32(zd.zd_crc32);
+		f->f_dsize = f->f_st.st_size = ple32(zd.zd_nsize)&0xFFFFFFFFUL;
+		f->f_csize = ple32(zd.zd_csize)&0xFFFFFFFFUL;
+	}
+}
+
+static int
+cantunzip(struct file *f, const char *method)
+{
+	msg(3, 0, "Cannot unzip %s file \"%s\"\n", method, f->f_name);
+	errcnt++;
+	return skipfile(f);
+}
+
+/*
+ * PC-DOS time format:
+ *
+ * 31            24      20        15        10           4       0
+ * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+ * |               |               |               |               |
+ * |year         |months |days     |hours    |minutes    |biseconds|
+ *
+ * refers to local time on the machine it was created on.
+ */
+
+static time_t
+gdostime(const char *tp, const char *dp)
+{
+	uint32_t	v;
+	struct tm	tm;
+
+	v = (int)(tp[0]&0377) +
+		((int)(tp[1]&0377) << 8) +
+		((int)(dp[0]&0377) << 16) +
+		((int)(dp[1]&0377) << 24);
+	memset(&tm, 0, sizeof tm);
+	tm.tm_sec = (v&0x1F) << 1;
+	tm.tm_min = (v&0x7E0) >> 5;
+	tm.tm_hour = (v&0xF800) >> 11;
+	tm.tm_mday = ((v&0x1F0000) >> 16);
+	tm.tm_mon = ((v&0x1E00000) >> 21) - 1;
+	tm.tm_year = ((v&0xFE000000) >> 25) + 80;
+	tm.tm_isdst = -1;
+	return mktime(&tm);
+}
+
+static void
+mkdostime(time_t t, char *tp, char *dp)
+{
+	uint32_t	v;
+	struct tm	*tm;
+
+	tm = localtime(&t);
+	v = (tm->tm_sec >> 1) + (tm->tm_sec&1) + (tm->tm_min << 5) +
+		(tm->tm_hour << 11) + (tm->tm_mday << 16) +
+		((tm->tm_mon+1) << 21) + ((tm->tm_year - 80) << 25);
+	le16p(v&0x0000ffff, tp);
+	le16p((v&0xffff0000) >> 16, dp);
+}
+
+/*
+ * Read and interpret the zip extra field for a file.
+ */
+static ssize_t
+ziprxtra(struct file *f, struct zip_header *z)
+{
+	union zextra	*x, *xp;
+	short	tag, size;
+	ssize_t	len;
+
+	len = ple16(z->z_extralen)&0177777;
+	if (len > 0) {
+		x = smalloc(len);
+		if (bread((char *)x, len) != len)
+			return -1;
+		if (len < 4)
+			return len;
+		xp = x;
+		while (len > 0) {
+			if (len < 4)
+				return -1;
+			tag = ple16(xp->Ze_gn.ze_gn_tag);
+			size = (ple16(xp->Ze_gn.ze_gn_tsize)&0177777) + 4;
+			switch (tag) {
+			case mag_zip64f:	/* ZIP64 extended information */
+				if (size != SIZEOF_zextra_64 &&
+						size != SIZEOF_zextra_64_a &&
+						size != SIZEOF_zextra_64_b)
+					break;
+				if (f->f_st.st_size == 0xffffffff)
+					f->f_st.st_size =
+						ple64(xp->Ze_64.ze_64_nsize);
+				if (f->f_csize == 0xffffffff)
+					f->f_csize =
+						ple64(xp->Ze_64.ze_64_csize);
+				f->f_oflag |= OF_ZIP64;
+				break;
+			case 0x000d:	/* PKWARE Unix Extra Field */
+				if (size != SIZEOF_zextra_pk)
+					break;
+				f->f_st.st_atime = ple32(xp->Ze_pk.ze_pk_atime);
+				f->f_st.st_mtime = ple32(xp->Ze_pk.ze_pk_mtime);
+				f->f_st.st_uid = ple16(xp->Ze_pk.ze_pk_uid) &
+					0177777;
+				f->f_st.st_gid = ple16(xp->Ze_pk.ze_pk_gid) &
+					0177777;
+				break;
+			case 0x5455:	/* Extended Timestamp Extra Field */
+				if (xp->Ze_et.ze_et_flags[0] & 1)
+					f->f_st.st_atime =
+						ple32(xp->Ze_et.ze_et_atime);
+				if (xp->Ze_et.ze_et_flags[0] & 2)
+					f->f_st.st_mtime =
+						ple32(xp->Ze_et.ze_et_mtime);
+				if (xp->Ze_et.ze_et_flags[0] & 3)
+					f->f_st.st_ctime =
+						ple32(xp->Ze_et.ze_et_ctime);
+				break;
+			case 0x5855:	/* Info-ZIP Unix Extra Field #1 */
+				if (size != SIZEOF_zextra_i1)
+					break;
+				f->f_st.st_atime = ple32(xp->Ze_i1.ze_i1_atime);
+				f->f_st.st_mtime = ple32(xp->Ze_i1.ze_i1_mtime);
+				f->f_st.st_uid = ple16(xp->Ze_i1.ze_i1_uid) &
+					0177777;
+				f->f_st.st_gid = ple16(xp->Ze_i1.ze_i1_gid) &
+					0177777;
+				break;
+			case 0x7855:	/* Info-ZIP Unix Extra Field #2 */
+				if (size != SIZEOF_zextra_i2)
+					break;
+				f->f_st.st_uid = ple16(xp->Ze_i2.ze_i2_uid) &
+					0177777;
+				f->f_st.st_gid = ple16(xp->Ze_i2.ze_i2_gid) &
+					0177777;
+				break;
+			case 0x756e:	/* ASi Unix Extra Field */
+				if (size < SIZEOF_zextra_as)
+					break;
+				f->f_st.st_mode = ple16(xp->Ze_as.ze_as_mode);
+				f->f_st.st_uid = ple16(xp->Ze_as.ze_as_uid) &
+					0177777;
+				f->f_st.st_gid = ple16(xp->Ze_as.ze_as_gid) &
+					0177777;
+				if ((f->f_st.st_mode&S_IFMT) == S_IFLNK) {
+					if (f->f_lsiz < size-14+1)
+						f->f_lnam = srealloc(f->f_lnam,
+								f->f_lsiz =
+								size-18+1);
+					memcpy(f->f_lnam, &((char *)xp)[18],
+							size-18);
+					f->f_lnam[size-18] = '\0';
+					f->f_st.st_size = size-18;
+				} else {
+					f->f_st.st_rdev =
+						ple32(xp->Ze_as.ze_as_sizdev);
+					f->f_rmajor = major(f->f_st.st_rdev);
+					f->f_rminor = minor(f->f_st.st_rdev);
+				}
+				break;
+			case mag_zipcpio:
+				if (size != SIZEOF_zextra_cp)
+					break;
+				f->f_st.st_dev = ple32(xp->Ze_cp.ze_cp_dev);
+				f->f_st.st_ino = ple32(xp->Ze_cp.ze_cp_ino);
+				f->f_st.st_mode = ple32(xp->Ze_cp.ze_cp_mode);
+				f->f_st.st_uid = ple32(xp->Ze_cp.ze_cp_uid) &
+					0xFFFFFFFFUL;
+				f->f_st.st_gid = ple32(xp->Ze_cp.ze_cp_gid) &
+					0xFFFFFFFFUL;
+				f->f_st.st_nlink = ple32(xp->Ze_cp.ze_cp_nlink)&
+					0xFFFFFFFFUL;
+				f->f_st.st_rdev = ple32(xp->Ze_cp.ze_cp_rdev);
+				f->f_rmajor = major(f->f_st.st_rdev);
+				f->f_rminor = minor(f->f_st.st_rdev);
+				f->f_st.st_mtime = ple32(xp->Ze_cp.ze_cp_mtime);
+				f->f_st.st_atime = ple32(xp->Ze_cp.ze_cp_atime);
+				break;
+			}
+			xp = (union zextra *)&((char *)xp)[size];
+			len -= size;
+		}
+		free(x);
+	}
+	return len;
+}
+
+/*
+ * Write the central directory and the end of a zip file.
+ */
+static void
+ziptrailer(void)
+{
+	struct zipstuff	*zs;
+	struct zipcentral	zc;
+	struct zipend	ze;
+	long long	cpstart, cpend, entries = 0;
+	size_t	sz;
+
+	cpstart = nwritten;
+	for (zs = zipbulk; zs; zs = zs->zs_next) {
+		entries++;
+		memset(&zc, 0, SIZEOF_zipcentral);
+		memcpy(zc.zc_signature, mag_zipctr, 4);
+		zc.zc_versionmade[0] = 20;
+		zc.zc_versionextr[0] = zs->zs_cmethod == 8 ? 20 : 10;
+		mkdostime(zs->zs_mtime, zc.zc_modtime, zc.zc_moddate);
+		le32p(zs->zs_crc32, zc.zc_crc32);
+		le16p(zs->zs_cmethod, zc.zc_cmethod);
+		le16p(zs->zs_gflag, zc.zc_gflag);
+		/*
+		 * We flag files as created on PC-DOS / FAT filesystem
+		 * and thus set PC-DOS attributes here.
+		 */
+		if ((zs->zs_mode&0222) == 0)
+			zc.zc_external[0] |= 0x01;	/* readonly attribute */
+		if ((zs->zs_mode&S_IFMT) == S_IFDIR)
+			zc.zc_external[0] |= 0x10;	/* directory attr. */
+		sz = strlen(zs->zs_name);
+		le16p(sz, zc.zc_namelen);
+		if (zs->zs_size >= 0xffffffff || zs->zs_csize >= 0xffffffff ||
+				zs->zs_relative >= 0xffffffff) {
+			struct zextra_64	zf;
+
+			memset(&zf, 0, SIZEOF_zextra_64);
+			le16p(mag_zip64f, zf.ze_64_tag);
+			le16p(SIZEOF_zextra_64 - 4, zf.ze_64_tsize);
+			if ((zs->zs_mode&S_IFMT) == S_IFREG ||
+					(zs->zs_mode&S_IFMT) == S_IFLNK) {
+				le32p(0xffffffff, zc.zc_csize);
+				le32p(0xffffffff, zc.zc_nsize);
+				le64p(zs->zs_csize, zf.ze_64_csize);
+				le64p(zs->zs_size, zf.ze_64_nsize);
+			}
+			le64p(zs->zs_relative, zf.ze_64_reloff);
+			le32p(0xffffffff, zc.zc_relative);
+			le16p(SIZEOF_zextra_64, zc.zc_extralen);
+			bwrite((char *)&zc, SIZEOF_zipcentral);
+			bwrite(zs->zs_name, sz);
+			bwrite((char *)&zf, SIZEOF_zextra_64);
+		} else {
+			if ((zs->zs_mode&S_IFMT) == S_IFREG ||
+					(zs->zs_mode&S_IFMT) == S_IFLNK) {
+				le32p(zs->zs_csize, zc.zc_csize);
+				le32p(zs->zs_size, zc.zc_nsize);
+			}
+			le32p(zs->zs_relative, zc.zc_relative);
+			bwrite((char *)&zc, SIZEOF_zipcentral);
+			bwrite(zs->zs_name, sz);
+		}
+	}
+	cpend = nwritten;
+	memset(&ze, 0, SIZEOF_zipend);
+	memcpy(ze.ze_signature, mag_zipend, 4);
+	if (cpend >= 0xffffffff || entries >= 0xffff) {
+		struct zip64end	z6;
+		struct zip64loc	z4;
+
+		memset(&z6, 0, SIZEOF_zip64end);
+		memcpy(z6.z6_signature, mag_zip64e, 4);
+		le64p(SIZEOF_zip64end - 12, z6.z6_recsize);
+		z6.z6_versionmade[0] = 20;
+		z6.z6_versionextr[0] = 20;
+		le64p(entries, z6.z6_thisentries);
+		le64p(entries, z6.z6_allentries);
+		le64p(cpend - cpstart, z6.z6_dirsize);
+		le64p(cpstart, z6.z6_startsize);
+		bwrite((char *)&z6, SIZEOF_zip64end);
+		memset(&z4, 0, SIZEOF_zip64loc);
+		memcpy(z4.z4_signature, mag_zip64l, 4);
+		le64p(cpend, z4.z4_reloff);
+		le32p(1, z4.z4_alldiskn);
+		bwrite((char *)&z4, SIZEOF_zip64loc);
+		le16p(0xffff, ze.ze_thisentries);
+		le16p(0xffff, ze.ze_allentries);
+		le32p(0xffffffff, ze.ze_dirsize);
+		le32p(0xffffffff, ze.ze_startsize);
+	} else {
+		le16p(entries, ze.ze_thisentries);
+		le16p(entries, ze.ze_allentries);
+		le32p(cpend - cpstart, ze.ze_dirsize);
+		le32p(cpstart, ze.ze_startsize);
+	}
+	bwrite((char *)&ze, SIZEOF_zipend);
+}
+
+/*
+ * Store the data later needed for the central directory.
+ */
+static void
+zipdefer(const char *fn, struct stat *st, long long relative,
+		uint32_t crc, long long csize, const struct zip_header *zh)
+{
+	struct zipstuff	*zp;
+
+	zp = scalloc(1, sizeof *zp);
+	zp->zs_name = sstrdup(fn);
+	zp->zs_size = st->st_size;
+	zp->zs_mtime = st->st_mtime;
+	zp->zs_mode = st->st_mode;
+	zp->zs_relative = relative;
+	zp->zs_cmethod = ple16(zh->z_cmethod);
+	zp->zs_gflag = ple16(zh->z_gflag);
+	zp->zs_csize = csize;
+	zp->zs_crc32 = crc;
+	zp->zs_next = zipbulk;
+	zipbulk = zp;
+}
+
+#define	ziptrlevel()	( \
+	zipclevel == 01 ? 9 : 	/* maximum */	\
+	zipclevel == 02 ? 3 : 	/* fast */	\
+	zipclevel == 03 ? 1 :	/* super fast */\
+	/*zipclevel==00*/ 6  	/* normal */	\
+)
+
+/*
+ * Write (and compress) data for a regular file to a zip archive.
+ */
+static int
+zipwrite(int fd, const char *fn, struct stat *st, union bincpio *bp, size_t sz,
+		uint32_t dev, uint32_t ino, uint32_t *crc, long long *csize)
+{
+#if USE_ZLIB
+	struct z_stream_s	z;
+	int	i;
+	size_t	osize = 0;
+#endif	/* USE_ZLIB */
+	char	*ibuf, *obuf = 0;
+
+	if (st->st_size > 196608 || (ibuf = malloc(st->st_size)) == 0) {
+#if USE_ZLIB
+		if (zipclevel < 04)
+			return zipwdesc(fd, fn, st, bp, sz, dev, ino,
+					crc, csize);
+#endif	/* USE_ZLIB */
+		return zipwtemp(fd, fn, st, bp, sz, dev, ino, crc, csize);
+	}
+	*csize = 0;
+	if (read(fd, ibuf, st->st_size) != st->st_size) {
+		free(ibuf);
+		emsg(3, "Cannot read \"%s\"", fn);
+		close(fd);
+		return -1;
+	}
+	*crc = zipcrc(0, (unsigned char *)ibuf, st->st_size);
+#if USE_BZLIB
+	if (zipclevel == 07) {
+		unsigned int	sb;
+		if ((obuf = malloc(sb = st->st_size)) == 0)
+			goto store;
+		if (BZ2_bzBuffToBuffCompress(obuf, &sb, ibuf, st->st_size,
+					9, 0, 0) != BZ_OK)
+			goto store;
+		*csize = sb;
+		bp->Zdr.z_cmethod[0] = C_BZIP2;
+		bp->Zdr.z_version[0] = 0x2e;
+		goto out;
+	}
+#endif /* USE_BZLIB */
+	if (zipclevel > 03)
+		goto store;
+#if USE_ZLIB
+	memset(&z, 0, sizeof z);
+	if (deflateInit2(&z, ziptrlevel(), Z_DEFLATED, -15,
+			8, Z_DEFAULT_STRATEGY) < 0)
+		goto store;
+	z.next_in = (unsigned char *)ibuf;
+	z.avail_in = z.total_in = st->st_size;
+	do {
+		if (z.avail_out == 0) {
+			if ((obuf = realloc(obuf, osize += 4096)) == 0) {
+				deflateEnd(&z);
+				goto store;
+			}
+			z.next_out = (unsigned char *)&obuf[*csize];
+			z.avail_out = osize - *csize;
+		}
+		if ((i = deflate(&z, z.avail_in ? Z_NO_FLUSH : Z_FINISH)) < 0) {
+			deflateEnd(&z);
+			goto store;
+		}
+		*csize = osize - z.avail_out;
+	} while (z.avail_in || i != Z_STREAM_END);
+	deflateEnd(&z);
+	if (*csize < st->st_size) {
+		bp->Zdr.z_cmethod[0] = C_DEFLATED;
+		bp->Zdr.z_gflag[0] |= zipclevel << 1;
+		bp->Zdr.z_version[0] = 20;
+	} else
+#endif	/* USE_ZLIB */
+	store:	*csize = st->st_size;
+#if USE_BZLIB
+out:
+#endif /* USE_BZLIB */
+	le32p(*crc, bp->Zdr.z_crc32);
+	le32p(*csize, bp->Zdr.z_csize);
+	bwrite((char *)bp, SIZEOF_zip_header);
+	bwrite(fn, sz);
+	zipwxtra(fn, st, dev, ino);
+	switch (bp->Zdr.z_cmethod[0]) {
+	case C_DEFLATED:
+	case C_BZIP2:
+		bwrite(obuf, *csize);
+		break;
+	default:
+		bwrite(ibuf, *csize);
+	}
+	free(ibuf);
+	free(obuf);
+	close(fd);
+	return 0;
+}
+
+/*
+ * Write and compress data to a zip archive for a file that is to large
+ * too be kept in memory. If there is an error with the temporary file
+ * (e. g. no space left on device), the file is stored in uncompressed
+ * form.
+ */
+static int
+zipwtemp(int fd, const char *fn, struct stat *st, union bincpio *bp, size_t sz,
+		uint32_t dev, uint32_t ino, uint32_t *crc, long long *csize)
+{
+	static int	tf = -1;
+	static char	tlate[] = "/var/tmp/cpioXXXXXX";
+	char	ibuf[32768];
+#if USE_ZLIB || USE_BZLIB
+	char	obuf[32768];
+#endif	/* USE_ZLIB || USE_BZLIB */
+	struct zextra_64	zf;
+	struct zextra_64	*zfp = 0;
+	long long	size = st->st_size;
+	const char	*sname;
+	int	cuse, sf;
+	ssize_t	rd;
+
+	*csize = 0;
+	*crc = 0;
+#if USE_ZLIB || USE_BZLIB
+	if (tf < 0) {
+		if ((tf = mkstemp(tlate)) >= 0)
+			unlink(tlate);
+	} else if (lseek(tf, 0, SEEK_SET) != 0) {
+		close(tf);
+		tf = -1;
+	}
+#endif	/* USE_ZLIB || USE_BZLIB */
+#if USE_ZLIB
+	if (zipclevel < 04) {
+		struct z_stream_s	z;
+		memset(&z, 0, sizeof z);
+		if ((cuse = deflateInit2(&z, ziptrlevel(), Z_DEFLATED,
+				-15, 8, Z_DEFAULT_STRATEGY)) < 0)
+			goto store;
+		do {
+			if (z.avail_in == 0 && size > 0) {
+				if ((rd = read(fd, ibuf, sizeof ibuf)) <= 0) {
+					emsg(3, "Cannot read \"%s\"", fn);
+					close(fd);
+					ftruncate(tf, 0);
+					return -1;
+				}
+				z.next_in = (unsigned char *)ibuf;
+				z.avail_in = z.total_in = rd;
+				size -= rd;
+				*crc = zipcrc(*crc, (unsigned char *)ibuf, rd);
+			}
+			if (z.next_out == NULL || (char *)z.next_out > obuf) {
+				if (z.next_out && tf >= 0) {
+					if (write(tf, obuf,
+					    (char *)z.next_out-obuf) !=
+					    (char *)z.next_out-obuf) {
+						close(tf);
+						tf = -1;
+					}
+					*csize += (char *)z.next_out - obuf;
+				}
+				z.next_out = (unsigned char *)obuf;
+				z.avail_out = sizeof obuf;
+			}
+			if (cuse >= 0 && cuse != Z_STREAM_END)
+				cuse = deflate(&z,
+					z.avail_in?Z_NO_FLUSH:Z_FINISH);
+			else
+				z.avail_in = 0;
+		} while (size>0 || (char *)z.next_out>obuf ||
+				cuse>=0 && cuse!=Z_STREAM_END);
+		deflateEnd(&z);
+		goto out;
+	}
+#endif	/* USE_ZLIB */
+#if USE_BZLIB
+	if (zipclevel == 07) {
+		bz_stream	bs;
+		int	ok, on;
+		memset(&bs, sizeof bs, 0);
+		if ((ok = BZ2_bzCompressInit(&bs, 9, 0, 0)) != BZ_OK)
+			goto store;
+		cuse = 1;
+		do {
+			if (bs.avail_in == 0 && size > 0) {
+				if ((rd = read(fd, ibuf, sizeof ibuf)) <= 0) {
+					emsg(3, "Cannot read \"%s\"", fn);
+					close(fd);
+					ftruncate(tf, 0);
+					return -1;
+				}
+				bs.next_in = ibuf;
+				bs.avail_in = rd;
+				size -= rd;
+				*crc = zipcrc(*crc, (unsigned char *)ibuf, rd);
+			}
+			if (bs.next_out == NULL || bs.next_out > obuf) {
+				if (bs.next_out && tf >= 0) {
+					on = bs.next_out - obuf;
+					if (write(tf, obuf, on) != on) {
+						close(tf);
+						tf = -1;
+					}
+					*csize += on;
+				}
+				bs.next_out = obuf;
+				bs.avail_out = sizeof obuf;
+			}
+			if (ok != BZ_STREAM_END) {
+				switch (ok = BZ2_bzCompress(&bs,
+					bs.avail_in?BZ_RUN:BZ_FINISH)) {
+				case BZ_RUN_OK:
+				case BZ_FINISH_OK:
+				case BZ_STREAM_END:
+					break;
+				default:
+					msg(3, 1, "Compression error %d "
+							"on \"%s\"\n", ok, fn);
+					close(fd);
+					return -1;
+				}
+			}
+		} while (size > 0 || bs.next_out > obuf || ok != BZ_STREAM_END);
+		BZ2_bzCompressEnd(&bs);
+		goto out;
+	}
+#endif	/* USE_BZLIB */
+store:	cuse = -1;
+	while (size > 0) {
+		if ((rd = read(fd, ibuf, sizeof ibuf)) <= 0) {
+			emsg(3, "Cannot read \"%s\"", fn);
+			close(fd);
+			return -1;
+		}
+		size -= rd;
+		*crc = zipcrc(*crc, (unsigned char *)ibuf, rd);
+	}
+out:	if (tf >= 0 && cuse >= 0 && *csize < st->st_size) {
+		if (zipclevel == 07) {
+			bp->Zdr.z_cmethod[0] = C_BZIP2;
+			bp->Zdr.z_version[0] = 0x2e;
+		} else {
+			bp->Zdr.z_cmethod[0] = C_DEFLATED;
+			bp->Zdr.z_gflag[0] |= zipclevel << 1;
+			bp->Zdr.z_version[0] = 20;
+		}
+		sf = tf;
+		sname = tlate;
+	} else {
+		*csize = st->st_size;
+		sf = fd;
+		sname = fn;
+	}
+	if ((lseek(sf, 0, SEEK_SET)) != 0) {
+		emsg(3, "Cannot rewind \"%s\"", sname);
+		errcnt++;
+		close(fd);
+		ftruncate(tf, 0);
+		return -1;
+	}
+	le32p(*crc, bp->Zdr.z_crc32);
+	if (st->st_size >= 0xffffffff || *csize >= 0xffffffff) {
+		int	n;
+		zfp = &zf;
+		memset(&zf, 0, SIZEOF_zextra_64);
+		le16p(mag_zip64f, zf.ze_64_tag);
+		le16p(SIZEOF_zextra_64 - 4, zf.ze_64_tsize);
+		le64p(st->st_size, zf.ze_64_nsize);
+		le64p(*csize, zf.ze_64_csize);
+		le32p(0xffffffff, bp->Zdr.z_csize);
+		le32p(0xffffffff, bp->Zdr.z_nsize);
+		n = (ple16(bp->Zdr.z_extralen)&0177777) + SIZEOF_zextra_64;
+		le16p(n, bp->Zdr.z_extralen);
+	} else
+		le32p(*csize, bp->Zdr.z_csize);
+	bwrite((char *)bp, SIZEOF_zip_header);
+	bwrite(fn, sz);
+	if (zfp)
+		bwrite((char *)zfp, SIZEOF_zextra_64);
+	zipwxtra(fn, st, dev, ino);
+	size = *csize;
+	while (size) {
+		if ((rd=read(sf, ibuf, size>sizeof ibuf?sizeof ibuf:size)) <= 0)
+			msg(3, 1, "Cannot read \"%s\"\n", sname);
+		bwrite(ibuf, rd);
+		size -= rd;
+	}
+	ftruncate(tf, 0);
+	close(fd);
+	return 0;
+}
+
+#if USE_ZLIB
+/*
+ * Write a zip archive entry using the data descriptor structure.
+ */
+static int
+zipwdesc(int fd, const char *fn, struct stat *st, union bincpio *bp, size_t sz,
+		uint32_t dev, uint32_t ino, uint32_t *crc, long long *csize)
+{
+	struct zextra_64	zf;
+	struct zextra_64	*zfp = 0;
+	char	ibuf[32768], obuf[32768];
+	long long	size = st->st_size;
+	ssize_t	rd;
+	struct z_stream_s	z;
+	int	cuse;
+
+	*csize = 0;
+	*crc = 0;
+	memset(&z, 0, sizeof z);
+	if ((cuse = deflateInit2(&z, ziptrlevel(), Z_DEFLATED,
+					-15, 8, Z_DEFAULT_STRATEGY)) < 0)
+		return zipwtemp(fd, fn, st, bp, sz, dev, ino, crc, csize);
+	bp->Zdr.z_cmethod[0] = C_DEFLATED;
+	bp->Zdr.z_gflag[0] |= zipclevel << 1 | FG_DESC;
+	bp->Zdr.z_version[0] = 20;
+	/*
+	 * RFC 1951 states that deflate compression needs 5 bytes additional
+	 * space per 32k block in the worst case. Thus a compressed size
+	 * greater than 4G-1 can be reached if at least 131052 blocks are
+	 * used.
+	 */
+	if (st->st_size >= 131052LL*32768) {
+		int	n;
+		zfp = &zf;
+		memset(&zf, 0, SIZEOF_zextra_64);
+		le16p(mag_zip64f, zf.ze_64_tag);
+		le16p(SIZEOF_zextra_64 - 4, zf.ze_64_tsize);
+		le32p(0xffffffff, bp->Zdr.z_csize);
+		le32p(0xffffffff, bp->Zdr.z_nsize);
+		n = (ple16(bp->Zdr.z_extralen)&0177777) + SIZEOF_zextra_64;
+		le16p(n, bp->Zdr.z_extralen);
+	}
+	bwrite((char *)bp, SIZEOF_zip_header);
+	bwrite(fn, sz);
+	if (zfp)
+		bwrite((char *)zfp, SIZEOF_zextra_64);
+	zipwxtra(fn, st, dev, ino);
+	do {
+		if (z.avail_in == 0 && size > 0) {
+			if ((rd = read(fd, ibuf, sizeof ibuf)) <= 0) {
+				emsg(3, "Cannot read \"%s\"", fn);
+				st->st_size -= size;
+				size = 0;	/* can't simply stop here */
+				rd = 0;		/* no data */
+			}
+			z.next_in = (unsigned char *)ibuf;
+			z.avail_in = z.total_in = rd;
+			size -= rd;
+			*crc = zipcrc(*crc, (unsigned char *)ibuf, rd);
+		}
+		if (z.next_out == NULL || (char *)z.next_out > obuf) {
+			if (z.next_out) {
+				bwrite(obuf, (char *)z.next_out - obuf);
+				*csize += (char *)z.next_out - obuf;
+			}
+			z.next_out = (unsigned char *)obuf;
+			z.avail_out = sizeof obuf;
+		}
+		if (cuse >= 0 && cuse != Z_STREAM_END)
+			cuse = deflate(&z, z.avail_in?Z_NO_FLUSH:Z_FINISH);
+		else
+			z.avail_in = 0;
+	} while (size > 0 || (char *)z.next_out > obuf ||
+			cuse >= 0 && cuse != Z_STREAM_END);
+	deflateEnd(&z);
+	if (zfp) {
+		struct zipddesc64	zd64;
+		memcpy(zd64.zd_signature, mag_zipdds, sizeof mag_zipdds);
+		le32p(*crc, zd64.zd_crc32);
+		le64p(st->st_size, zd64.zd_nsize);
+		le64p(*csize, zd64.zd_csize);
+		bwrite((char *)&zd64, SIZEOF_zipddesc64);
+	} else {
+		struct zipddesc	zd;
+		memcpy(zd.zd_signature, mag_zipdds, sizeof mag_zipdds);
+		le32p(*crc, zd.zd_crc32);
+		le32p(st->st_size, zd.zd_nsize);
+		le32p(*csize, zd.zd_csize);
+		bwrite((char *)&zd, SIZEOF_zipddesc);
+	}
+	close(fd);
+	return 0;
+}
+#endif	/* USE_ZLIB */
+
+/*
+ * Write the extra fields for a file to a zip archive (currently
+ * our own field type). Note that the z_extralen field in the file
+ * header must correspond to the size of the data written here.
+ */
+static int
+zipwxtra(const char *fn, struct stat *st, uint32_t dev, uint32_t ino)
+{
+	struct zextra_cp	z;
+
+	memset(&z, 0, SIZEOF_zextra_cp);
+	le16p(mag_zipcpio, z.ze_cp_tag);
+	le16p(SIZEOF_zextra_cp - 4, z.ze_cp_tsize);
+	le32p(dev, z.ze_cp_mode);
+	le32p(ino, z.ze_cp_ino);
+	le32p(st->st_mode&(S_IFMT|07777), z.ze_cp_mode);
+	le32p(st->st_uid, z.ze_cp_uid);
+	le32p(st->st_gid, z.ze_cp_gid);
+	le32p(st->st_nlink, z.ze_cp_nlink);
+	le32p(st->st_rdev, z.ze_cp_rdev);
+	le32p(st->st_mtime, z.ze_cp_mtime);
+	le32p(st->st_atime, z.ze_cp_atime);
+	bwrite((char *)&z, SIZEOF_zextra_cp);
+	return SIZEOF_zextra_cp;
+}
+
+static void
+zipinfo(struct file *f)
+{
+	const char	*cp;
+	char	b[5];
+	int	i;
+
+	printf(" %7llu", f->f_csize);
+	if (f->f_dsize) {
+		i = f->f_csize*100 / f->f_dsize;
+		i += f->f_csize*200 / f->f_dsize & 1;
+		i = 100 - i;
+	} else
+		i = 0;
+	printf(" %3d%%", i);
+	switch (f->f_cmethod) {
+	case C_STORED:
+		cp = "stor";
+		break;
+	case C_SHRUNK:
+		cp = "shrk";
+		break;
+	case C_REDUCED1:
+		cp = "re:1";
+		break;
+	case C_REDUCED2:
+		cp = "re:2";
+		break;
+	case C_REDUCED3:
+		cp = "re:3";
+		break;
+	case C_REDUCED4:
+		cp = "re:4";
+		break;
+	case C_IMPLODED:
+		b[0] = 'i';
+		b[1] = f->f_gflag & FG_BIT1 ? '8' : '4';
+		b[2] = ':';
+		b[3] = f->f_gflag & FG_BIT2 ? '3' : '2';
+		b[4] = '\0';
+		cp = b;
+		break;
+	case C_TOKENIZED:
+		cp = "tokn";
+		break;
+	case C_DEFLATED:
+		b[0] = 'd', b[1] = 'e', b[2] = 'f', b[4] = '\0';
+		if (f->f_gflag & FG_BIT2)
+			b[3] = f->f_gflag & FG_BIT1 ? 'S' : 'F';
+		else
+			b[3] = f->f_gflag & FG_BIT1 ? 'X' : 'N';
+		cp = b;
+		break;
+	case C_ENHDEFLD:
+		cp = "edef";
+		break;
+	case C_DCLIMPLODED:
+		cp = "dcli";
+		break;
+	case C_BZIP2:
+		cp = "bz2 ";
+		break;
+	default:
+		snprintf(b, sizeof b, "%4.4X", f->f_cmethod);
+		cp = b;
+	}
+	printf(" %s", cp);
+}
+
+#if USE_BZLIB
+int
+zipunbz2(struct file *f, const char *tgt, int tfd, int doswap, uint32_t *crc)
+{
+	bz_stream	bs;
+	long long	isize = f->f_csize;
+	char	ibuf[4096], obuf[8192];
+	int	in, on, val = 0, ok;
+
+	memset(&bs, 0, sizeof bs);
+
+	if ((ok = BZ2_bzDecompressInit(&bs, 0, 0)) != BZ_OK) {
+		msg(3, 0, "bzip2 initialization error %d on \"%s\"\n",
+				ok, f->f_name);
+		errcnt++;
+		return skipfile(f);
+	}
+	while (isize > 0 || ok == BZ_OK) {
+		if (bs.avail_in == 0 && isize > 0) {
+			in = sizeof ibuf < isize ? sizeof ibuf : isize;
+			isize -= in;
+			if (bread(ibuf, in) != in)
+				unexeoa();
+			if (doswap)
+				swap(ibuf, in, bflag || sflag, bflag || Sflag);
+			bs.next_in = ibuf;
+			bs.avail_in = in;
+		}
+		if (ok == BZ_OK) {
+			bs.next_out = obuf;
+			bs.avail_out = sizeof obuf;
+			switch (ok = BZ2_bzDecompress(&bs)) {
+			case BZ_OK:
+			case BZ_STREAM_END:
+				on = sizeof obuf - bs.avail_out;
+				if (tfd >= 0 && write(tfd, obuf, on) != on) {
+					emsg(3, "Cannot write \"%s\"", tgt);
+					tfd = -1;
+					val = 1;
+				}
+				*crc = zipcrc(*crc, (unsigned char *)obuf, on);
+				break;
+			default:
+				msg(3, 0, "compression error %d on \"%s\"\n",
+					ok, f->f_name);
+				errcnt++;
+				val = 1;
+			}
+		}
+	}
+	BZ2_bzDecompressEnd(&bs);
+	return val;
+}
+#endif	/* USE_BZLIB */
+
+struct	blasthow {
+	struct file	*bh_f;
+	const char	*bh_tgt;
+	long long	bh_isize;
+	uint32_t	*bh_crc;
+	int		bh_tfd;
+	int		bh_doswap;
+	int		bh_val;
+};
+
+static unsigned
+blastin(void *how, unsigned char **buf)
+{
+	const int	chunk = 16384;
+	static unsigned char	*hold;
+	struct blasthow	*bp = how;
+	unsigned	sz;
+
+	if (bp->bh_isize <= 0)
+		return 0;
+	if (hold == NULL)
+		hold = smalloc(chunk);
+	sz = bp->bh_isize > chunk ? chunk : bp->bh_isize;
+	bp->bh_isize -= sz;
+	if (bread((char *)hold, sz) != sz)
+		unexeoa();
+	if (bp->bh_doswap)
+		swap((char *)hold, sz, bflag || sflag, bflag || Sflag);
+	*buf = hold;
+	return sz;
+}
+
+static int
+blastout(void *how, unsigned char *buf, unsigned len)
+{
+	struct blasthow	*bp = how;
+
+	if (bp->bh_tfd >= 0 && write(bp->bh_tfd, buf, len) != len) {
+		emsg(3, "Cannot write \"%s\"", bp->bh_tgt);
+		bp->bh_tfd = -1;
+		bp->bh_val = 1;
+	}
+	*bp->bh_crc = zipcrc(*bp->bh_crc, buf, len);
+	return 0;
+}
+
+int
+zipblast(struct file *f, const char *tgt, int tfd, int doswap, uint32_t *crc)
+{
+	struct blasthow	bh;
+	int	n;
+
+	bh.bh_f = f;
+	bh.bh_tgt = tgt;
+	bh.bh_isize = f->f_csize;
+	bh.bh_crc = crc;
+	bh.bh_tfd = tfd;
+	bh.bh_doswap = doswap;
+	bh.bh_val = 0;
+	switch (n = blast(blastin, &bh, blastout, &bh)) {
+	case 0:
+		break;
+	default:
+		msg(3, 0, "compression error %d on \"%s\"\n", n, f->f_name);
+		errcnt++;
+		bh.bh_val = 1;
+	}
+	while (bh.bh_isize) {
+		char	buf[4096];
+		unsigned	n;
+		n = bh.bh_isize > sizeof buf ? sizeof buf : bh.bh_isize;
+		if (bread(buf, n) != n)
+			unexeoa();
+		bh.bh_isize -= n;
+	}
+	return bh.bh_val;
+}
+
+/*
+ * The SGI -K format was introduced with SGI's IRIX 5.X. It is essentially
+ * a slightly extended binary format. The known additions are:
+ *
+ * - If the major or minor st_rdev device number exceeds the limit of
+ *   255 imposed by the 16-bit c_rdev field, this field is set to 0xFFFF
+ *   and st_rdev is stored in the c_filesize 32-bit field. The first 14
+ *   bits of this field compose the major device number, the minor is
+ *   stored in the remaining 18 bits. This enables implementations to
+ *   read the modified format without special support if they ignore
+ *   the size of device files; otherwise they will try to read a lot
+ *   of archive data and fail.
+ *
+ * - If the file is larger than 2 GB - 1 byte, two nearly identical
+ *   archive headers are stored for it. The only difference is in
+ *   the c_filesize field:
+ *
+ *   [first header: file size X times 2 GB]
+ *    [first data part: X times 2 GB]
+ *   [second header: file size modulo 2 GB]
+ *    [second data part: rest of data]
+ *
+ *   The first header can be recognized by a negative c_filesize. A
+ *   value of 0xFFFFFFFF means that 2 GB follow, 0xFFFFFFFE -> 4 GB
+ *   0xFFFFFFFD -> 6 GB, 0xFFFFFFFC -> 8 GB, and so forth. The second
+ *   is a standard binary cpio header, although the following data is
+ *   meant to be appended to the preceding file.
+ *
+ *   It is important to note that padding follows the number in
+ *   c_filesize, not the amount of data written; thus all data parts
+ *   with odd c_filesize fields (0xFFFFFFFF = 2+ GB, 0xFFFFFFFD = 6+ GB
+ *   etc.) cause the following archive entries to be aligned on an odd
+ *   offset. This seems to be an implementation artifact but has to be
+ *   followed for compatibility.
+ *
+ *   This extension seems a bit weird since no known cpio implementation
+ *   is able to read these archive entries without special support. Thus
+ *   a more straightforward extension (such as storing the size just past
+ *   the file name) would well have had the same effect. Nevertheless,
+ *   the cpio -K format is useful, so it is implemented here.
+ *
+ *   --Note that IRIX 6.X tar also has a -K option. This option extends
+ *   the tar format in essentially the same way as the second extension
+ *   to cpio described above. Unfortunately, the result is definitively
+ *   broken. Contrasting to the binary cpio format, the standard POSIX
+ *   tar format is well able to hold files of size 0xFFFFFFFF and below
+ *   in a regular manner. Thus, a tar -K archive entry is _exactly_ the
+ *   same as two regular POSIX tar entries for the same file. And this
+ *   situation even occurs on a regular basis with tar -r! For this
+ *   reason, we do not implement the IRIX tar -K format and will probably
+ *   never do so unless it is changed (the tar format really has a lot
+ *   of options to indicate extensions that might be used for this).
+ *
+ *   Many thanks to Sven Mascheck who made archiving tests on the IRIX
+ *   machine.
+ */
+/*
+ * This function reads the second header of a SGI -K format archive.
+ */
+static void
+readK2hdr(struct file *f)
+{
+	struct file	n;
+	union bincpio	bc;
+
+	n.f_name = n.f_lnam = NULL;
+	n.f_nsiz = n.f_lsiz = 0;
+	readhdr(&n, &bc);
+	f->f_Krest = n.f_st.st_size;
+	f->f_dsize = f->f_st.st_size = n.f_st.st_size + f->f_Kbase;
+	f->f_Kbase = 0;
+	free(n.f_name);
+	free(n.f_lnam);
+}
+
+/*
+ * Read the data of a GNU filename extra header.
+ */
+static int
+readgnuname(char **np, size_t *sp, long length)
+{
+	if (length > SANELIMIT)
+		return -1;
+	if (*sp == 0 || *sp <= length)
+		*np = srealloc(*np, *sp = length+1);
+	bread(*np, length);
+	(*np)[length] = '\0';
+	skippad(length, 512);
+	return 0;
+}
+
+/*
+ * Write a GNU filename extra header and its data.
+ */
+static void
+writegnuname(const char *fn, long length, int flag)
+{
+	union bincpio	bc;
+
+	memset(bc.data, 0, 512);
+	strcpy(bc.Tdr.t_name, "././@LongLink");
+	sprintf(bc.Tdr.t_mode, "%7.7o", 0);
+	sprintf(bc.Tdr.t_uid, "%7.7o", 0);
+	sprintf(bc.Tdr.t_gid, "%7.7o", 0);
+	sprintf(bc.Tdr.t_size, "%11.11lo", length);
+	sprintf(bc.Tdr.t_mtime, "%11.11lo", 0L);
+	bc.Tdr.t_linkflag = flag;
+	memcpy(bc.Tdr.t_magic, mag_gnutar, 8);
+	strcpy(bc.Tdr.t_uname, "root");
+	strcpy(bc.Tdr.t_gname, "root");
+	tchksum(&bc);
+	bwrite(bc.data, 512);
+	bwrite(fn, length);
+	length %= 512;
+	memset(bc.data, 0, 512 - length);
+	bwrite(bc.data, 512 - length);
+}
+
+/*
+ * POSIX.1-2001 pax format support.
+ */
+static void
+tgetpax(struct tar_header *tp, struct file *f)
+{
+	char	*keyword, *value;
+	char	*block, *bp;
+	long long	n;
+	enum paxrec	pr;
+
+	n = rdoct(tp->t_size, 12);
+	bp = block = smalloc(n+1);
+	bread(block, n);
+	skippad(n, 512);
+	block[n] = '\0';
+	while (bp < &block[n]) {
+		int	c;
+		pr = tgetrec(&bp, &keyword, &value);
+		switch (pr) {
+		case PR_ATIME:
+			f->f_st.st_atime = strtoll(value, NULL, 10);
+			break;
+		case PR_GID:
+			f->f_st.st_gid = strtoll(value, NULL, 10);
+			break;
+		case PR_LINKPATH:
+			c = strlen(value);
+			if (f->f_lnam == NULL || f->f_lsiz < c+1) {
+				f->f_lsiz = c+1;
+				f->f_lnam = srealloc(f->f_lnam, c+1);
+			}
+			strcpy(f->f_lnam, value);
+			break;
+		case PR_MTIME:
+			f->f_st.st_mtime = strtoll(value, NULL, 10);
+			break;
+		case PR_PATH:
+			c = strlen(value);
+			if (f->f_name == NULL || f->f_nsiz < c+1) {
+				f->f_nsiz = c+1;
+				f->f_name = srealloc(f->f_name, c+1);
+			}
+			strcpy(f->f_name, value);
+			break;
+		case PR_SIZE:
+			f->f_st.st_size = strtoll(value, NULL, 10);
+			break;
+		case PR_UID:
+			f->f_st.st_uid = strtoll(value, NULL, 10);
+			break;
+		case PR_SUN_DEVMAJOR:
+			f->f_rmajor = strtoll(value, NULL, 10);
+			break;
+		case PR_SUN_DEVMINOR:
+			f->f_rminor = strtoll(value, NULL, 10);
+			break;
+		}
+		paxrec |= pr;
+	}
+	if (tp->t_linkflag == 'g') {
+		globrec = paxrec & ~(PR_LINKPATH|PR_PATH|PR_SIZE);
+		globst = f->f_st;
+	}
+	free(block);
+}
+
+static enum paxrec
+tgetrec(char **bp, char **keyword, char **value)
+{
+	char	*x;
+	long	n = 0;
+	enum paxrec	pr;
+
+	*keyword = "";
+	*value = "";
+	while (**bp && (n = strtol(*bp, &x, 10)) <= 0 && (*x!=' ' || *x!='\t'))
+		do
+			(*bp)++;
+		while (**bp && **bp != '\n');
+	if (*x == '\0' || **bp == '\0') {
+		(*bp)++;
+		return PR_NONE;
+	}
+	while (x < &(*bp)[n] && (*x == ' ' || *x == '\t'))
+		x++;
+	if (x == &(*bp)[n] || *x == '=')
+		goto out;
+	*keyword = x;
+	while (x < &(*bp)[n] && *x != '=')
+		x++;
+	if (x == &(*bp)[n])
+		goto out;
+	*x = '\0';
+	if (&x[1] < &(*bp)[n])
+		*value = &x[1];
+	(*bp)[n-1] = '\0';
+out:	*bp = &(*bp)[n];
+	if (strcmp(*keyword, "atime") == 0)
+		pr = PR_ATIME;
+	else if (strcmp(*keyword, "gid") == 0)
+		pr = PR_GID;
+	else if (strcmp(*keyword, "linkpath") == 0)
+		pr = PR_LINKPATH;
+	else if (strcmp(*keyword, "mtime") == 0)
+		pr = PR_MTIME;
+	else if (strcmp(*keyword, "path") == 0)
+		pr = PR_PATH;
+	else if (strcmp(*keyword, "size") == 0)
+		pr = PR_SIZE;
+	else if (strcmp(*keyword, "uid") == 0)
+		pr = PR_UID;
+	else if (strcmp(*keyword, "SUN.devmajor") == 0)
+		pr = PR_SUN_DEVMAJOR;
+	else if (strcmp(*keyword, "SUN.devminor") == 0)
+		pr = PR_SUN_DEVMINOR;
+	else
+		pr = PR_NONE;
+	return pr;
+}
+
+static void
+wrpax(const char *longname, const char *linkname, struct stat *sp)
+{
+	union bincpio	bc;
+	char	*pdata = NULL;
+	long	psize = 0, pcur = 0;
+	long long	blocks;
+
+	memset(bc.data, 0, 512);
+	if (paxrec & PR_ATIME)
+		addrec(&pdata, &psize, &pcur, "atime", NULL, sp->st_atime);
+	if (paxrec & PR_GID)
+		addrec(&pdata, &psize, &pcur, "gid", NULL, sp->st_gid);
+	if (paxrec & PR_LINKPATH)
+		addrec(&pdata, &psize, &pcur, "linkpath", linkname, 0);
+	if (paxrec & PR_MTIME)
+		addrec(&pdata, &psize, &pcur, "mtime", NULL, sp->st_mtime);
+	if (paxrec & PR_PATH)
+		addrec(&pdata, &psize, &pcur, "path", longname, 0);
+	if (paxrec & PR_SIZE)
+		addrec(&pdata, &psize, &pcur, "size", NULL, sp->st_size);
+	if (paxrec & PR_UID)
+		addrec(&pdata, &psize, &pcur, "uid", NULL, sp->st_uid);
+	if (paxrec & PR_SUN_DEVMAJOR)
+		addrec(&pdata, &psize, &pcur, "SUN.devmajor", NULL,
+				major(sp->st_rdev));
+	if (paxrec & PR_SUN_DEVMINOR)
+		addrec(&pdata, &psize, &pcur, "SUN.devminor", NULL,
+				minor(sp->st_rdev));
+	paxnam(&bc.Tdr, longname);
+	sprintf(bc.Tdr.t_mode, "%7.7o", fmttype==FMT_SUN ? 0444|S_IFREG : 0444);
+	sprintf(bc.Tdr.t_uid, "%7.7o", 0);
+	sprintf(bc.Tdr.t_gid, "%7.7o", 0);
+	sprintf(bc.Tdr.t_size, "%11.11lo", pcur);
+	sprintf(bc.Tdr.t_mtime, "%11.11o", 0);
+	strcpy(bc.Tdr.t_magic, "ustar");
+	bc.Tdr.t_version[0] = bc.Tdr.t_version[1] = '0';
+	strcpy(bc.Tdr.t_uname, "root");
+	strcpy(bc.Tdr.t_gname, "root");
+	bc.Tdr.t_linkflag = fmttype==FMT_SUN ? 'X' : 'x';
+	tchksum(&bc);
+	bwrite(bc.data, 512);
+	memset(&pdata[pcur], 0, psize - pcur);
+	blocks = (pcur + (512-1)) / 512;
+	bwrite(pdata, blocks * 512);
+	free(pdata);
+}
+
+static void
+addrec(char **pdata, long *psize, long *pcur,
+		const char *keyword, const char *sval, long long lval)
+{
+	char	dval[25], xval[25];
+	long	od, d, r;
+
+	if (sval == 0) {
+		sprintf(xval, "%lld", lval);
+		sval = xval;
+	}
+	r = strlen(keyword) + strlen(sval) + 3;
+	d = 0;
+	do {
+		od = d;
+		d = sprintf(dval, "%ld", od + r);
+	} while (d != od);
+	*psize += d + r + 1 + 512;
+	*pdata = srealloc(*pdata, *psize);
+	sprintf(&(*pdata)[*pcur], "%s %s=%s\n", dval, keyword, sval);
+	*pcur += d + r;
+}
+
+static void
+paxnam(struct tar_header *hp, const char *name)
+{
+	char	buf[257], *bp;
+	const char	*cp, *np;
+	int	bl = 0;
+	static int	pid;
+
+	if (pid == 0)
+		pid = getpid();
+	for (np = name; *np; np++);
+	while (np > name && *np != '/') {
+		np--;
+		bl++;
+	}
+	if ((np > name || *name == '/') && np-name <= 120)
+		for (bp = buf, cp = name; cp < np; bp++, cp++)
+			*bp = *cp;
+	else {
+		*buf = '.';
+		bp = &buf[1];
+	}
+	snprintf(bp, sizeof buf - (bp - buf), "/PaxHeaders.%d/%s",
+			pid, bl < 100 ? np>name?&np[1]:name : sequence());
+	tmkname(hp, buf);
+}
+
+static char *
+sequence(void)
+{
+	static char	buf[25];
+	static long long	d;
+
+	sprintf(buf, "%10.10lld", ++d);
+	return buf;
+}
+
+static int
+pax_oneopt(const char *s, int warn)
+{
+	if (strcmp(s, "linkdata") == 0)
+		pax_oflag |= PO_LINKDATA;
+	else if (strcmp(s, "times") == 0)
+		pax_oflag |= PO_TIMES;
+	else {
+		if (warn)
+			msg(2, 0, "Unknown flag \"-o %s\"\n", s);
+		return -1;
+	}
+	return 0;
+}
+
+int
+pax_options(char *s, int warn)
+{
+	char	*o = s, c;
+	int	val = 0, word = 0;
+
+	do {
+		if (word == 0) {
+			if (isspace(*s&0377))
+				o = &s[1];
+			else
+				word = 1;
+		}
+		if (*s == ',' || *s == '\0') {
+			c = *s;
+			*s = '\0';
+			val |= pax_oneopt(o, warn);
+			*s = c;
+			o = &s[1];
+			word = 0;
+		}
+	} while (*s++);
+	return val;
+}
+
+/*
+ * Given a symbolic link "base" and the result of readlink "name", form
+ * a valid path name for the link target.
+ */
+static char *
+joinpath(const char *base, char *name)
+{
+	const char	*bp = NULL, *cp;
+	char	*new, *np;
+
+	if (*name == '/')
+		return name;
+	for (cp = base; *cp; cp++)
+		if (*cp == '/')
+			bp = cp;
+	if (bp == NULL)
+		return name;
+	np = new = smalloc(bp - base + strlen(name) + 2);
+	for (cp = base; cp < bp; cp++)
+		*np++ = *cp;
+	*np++ = '/';
+	for (cp = name; *cp; cp++)
+		*np++ = *cp;
+	*np = '\0';
+	free(name);
+	return new;
+}
+
+static int
+utf8(const char *cp)
+{
+	int	c, n;
+
+	while (*cp) if ((c = *cp++ & 0377) & 0200) {
+		if (c == (c & 037 | 0300))
+			n = 1;
+		else if (c == (c & 017 | 0340))
+			n = 2;
+		else if (c == (c & 07 | 0360))
+			n = 3;
+		else if (c == (c & 03 | 0370))
+			n = 4;
+		else if (c == (c & 01 | 0374))
+			n = 5;
+		else
+			return 0;
+		while (n--) {
+			c = *cp++ & 0377;
+			if (c != (c & 077 | 0200))
+				return 0;
+		}
+	}
+	return 1;
+}
+
+static time_t
+fetchtime(const char *cp)
+{
+	struct tm	tm;
+	time_t	t;
+	char	*xp;
+	int	n;
+
+	t = strtoll(cp, &xp, 10);
+	if (*xp == '\0')
+		return t;
+	memset(&tm, 0, sizeof tm);
+	n = sscanf(cp, "%4d%2d%2dT%2d%2d%2d",
+			&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+			&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+	tm.tm_year -= 1900;
+	tm.tm_mon--;
+	tm.tm_isdst = -1;
+	t = mktime(&tm);
+	if (n < 3 || t == (time_t)-1)
+		msg(4, 1, "line %lld: illegal time \"%s\"\n",
+				lineno, cp);
+	return t;
+}
+
+static char *
+nextfield(char *cp, const char *fieldname)
+{
+	while (*cp && *cp != ':')
+		cp++;
+	if (*cp == 0)
+		msg(4, 1, "line %lld: unterminated \"%s\" field\n",
+				lineno, fieldname);
+	*cp++ = 0;
+	return cp;
+}
+
+static char *
+getproto(char *np, struct prototype *pp)
+{
+	char	*tp, *xp;
+	long long	t, u;
+
+	memset(pp, 0, sizeof *pp);
+	if (*np == ':')
+		np++;
+	else {
+		tp = nextfield(np, "type");
+		if (np[1]) 
+			goto notype;
+		switch (np[0]) {
+		case 'b':
+			pp->pt_mode |= S_IFBLK;
+			break;
+		case 'c':
+			pp->pt_mode |= S_IFCHR;
+			break;
+		case 'd':
+			pp->pt_mode |= S_IFDIR;
+			break;
+		case 'f':
+			pp->pt_mode |= S_IFREG;
+			break;
+		case 'p':
+			pp->pt_mode |= S_IFIFO;
+			break;
+		case 's':
+			pp->pt_mode |= S_IFLNK;
+			break;
+		default:
+		notype:
+			msg(4, 1, "line %lld: unknown type \"%s\"\n",
+					lineno, np);
+		}
+		pp->pt_spec |= PT_TYPE;
+		np = tp;
+	}
+	if (*np == ':')
+		np++;
+	else {
+		struct passwd	*pwd;
+		tp = nextfield(np, "owner");
+		t = strtoll(np, &xp, 10);
+		if (*xp == '\0')
+			pp->pt_uid = t;
+		else {
+			if ((pwd = getpwnam(np)) == NULL)
+				msg(4, 1, "line %lld: unknown user \"%s\"\n",
+						lineno, np);
+			pp->pt_uid = pwd->pw_uid;
+		}
+		pp->pt_spec |= PT_OWNER;
+		np = tp;
+	}
+	if (*np == ':')
+		np++;
+	else {
+		struct group	*grp;
+		tp = nextfield(np, "group");
+		t = strtoll(np, &xp, 10);
+		if (*xp == '\0')
+			pp->pt_gid = t;
+		else {
+			if ((grp = getgrnam(np)) == NULL)
+				msg(4, 1, "line %lld: unknown group \"%s\"\n",
+						lineno, np);
+			pp->pt_gid = grp->gr_gid;
+		}
+		pp->pt_spec |= PT_GROUP;
+		np = tp;
+	}
+	if (*np == ':')
+		np++;
+	else {
+		tp = nextfield(np, "mode");
+		t = strtol(np, &xp, 8);
+		if (t & ~07777 || *xp)
+			msg(4, 1, "line %lld: illegal mode \"%s\"\n",
+					lineno, np);
+		pp->pt_mode |= t;
+		pp->pt_spec |= PT_MODE;
+		np = tp;
+	}
+	if (*np == ':')
+		np++;
+	else {
+		tp = nextfield(np, "access time");
+		pp->pt_atime = fetchtime(np);
+		pp->pt_spec |= PT_ATIME;
+		np = tp;
+	}
+	if (*np == ':')
+		np++;
+	else {
+		tp = nextfield(np, "modification time");
+		pp->pt_mtime = fetchtime(np);
+		pp->pt_spec |= PT_MTIME;
+		np = tp;
+	}
+	if (*np == ':') {
+		np++;
+		if (*np++ != ':')
+		majmin:	msg(4, 1, "line %lld: need either both major and "
+				"minor or none\n",
+				lineno);
+	} else {
+		tp = nextfield(np, "major");
+		t = strtoll(np, &xp, 10);
+		if (*xp)
+			msg(4, 1, "line %lld: illegal major \"%s\"\n",
+					lineno, np);
+		np = tp;
+		if (*np == ':')
+			goto majmin;
+		tp = nextfield(np, "minor");
+		u = strtoll(np, &xp, 10);
+		if (*xp)
+			msg(4, 1, "line %lld: illegal minor \"%s\"\n",
+					lineno, np);
+		np = tp;
+		pp->pt_rdev = makedev(t, u);
+		pp->pt_spec |= PT_RDEV;
+	}
+	return np;
+}

+ 232 - 0
tools/cpio/src/cpio.h

@@ -0,0 +1,232 @@
+/*
+ * cpio - copy file archives in and out
+ *
+ * Gunnar Ritter, Freiburg i. Br., Germany, April 2003.
+ */
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+/*	Sccsid @(#)cpio.h	1.29 (gritter) 3/26/07	*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+enum	{
+	FMT_NONE	= 00000000,	/* no format chosen yet */
+
+	TYP_PAX		= 00000010,	/* uses pax-like extended headers */
+	TYP_BE		= 00000100,	/* this binary archive is big-endian */
+	TYP_SGI		= 00000200,	/* SGI cpio -K flag binary archive */
+	TYP_SCO		= 00000200,	/* SCO UnixWare 7.1 extended archive */
+	TYP_CRC		= 00000400,	/* this has a SVR4 'crc' checksum */
+	TYP_BINARY	= 00001000,	/* this is a binary cpio type */
+	TYP_OCPIO	= 00002000,	/* this is an old cpio type */
+	TYP_NCPIO	= 00004000,	/* this is a SVR4 cpio type */
+	TYP_CRAY	= 00010000,	/* this is a Cray cpio archive */
+	TYP_CPIO	= 00077000,	/* this is a cpio type */
+	TYP_OTAR	= 00100000,	/* this is an old tar type */
+	TYP_USTAR	= 00200000,	/* this is a ustar type */
+	TYP_BAR		= 00400000,	/* this is a bar type */
+	TYP_TAR		= 00700000,	/* this is a tar type */
+
+	FMT_ODC		= 00002001,	/* POSIX ASCII cpio format */
+	FMT_DEC		= 00002002,	/* DEC extended cpio format */
+	FMT_BINLE	= 00003001,	/* binary (default) cpio format LE */
+	FMT_BINBE	= 00003101,	/* binary (default) cpio format BE */
+	FMT_SGILE	= 00003201,	/* IRIX-style -K binary format LE */
+	FMT_SGIBE	= 00003301,	/* IRIX-style -K binary format BE */
+	FMT_ASC		= 00004001,	/* SVR4 ASCII cpio format */
+	FMT_SCOASC	= 00004201,	/* UnixWare 7.1 ASCII cpio format */
+	FMT_CRC		= 00004401,	/* SVR4 ASCII cpio format w/checksum */
+	FMT_SCOCRC	= 00004601,	/* UnixWare 7.1 ASCII cpio w/checksum */
+	FMT_CRAY	= 00010001,	/* Cray cpio, UNICOS 6 and later */
+	FMT_CRAY5	= 00010002,	/* Cray cpio, UNICOS 5 and earlier */
+	FMT_OTAR	= 00100001,	/* obsolete tar format */
+	FMT_TAR		= 00200001,	/* our tar format type */
+	FMT_USTAR	= 00200002,	/* ustar format */
+	FMT_GNUTAR	= 00200003,	/* GNU tar format type */
+	FMT_PAX		= 00200011,	/* POSIX.1-2001 pax format type */
+	FMT_SUN		= 00200012,	/* Sun extended tar format type */
+	FMT_BAR		= 00400001,	/* bar format type */
+
+	FMT_ZIP		= 01000000	/* zip format */
+} fmttype;
+
+/*
+ * Zip compression method.
+ */
+enum	cmethod {
+	C_STORED	= 0,		/* no compression */
+	C_SHRUNK	= 1,
+	C_REDUCED1	= 2,
+	C_REDUCED2	= 3,
+	C_REDUCED3	= 4,
+	C_REDUCED4	= 5,
+	C_IMPLODED	= 6,
+	C_TOKENIZED	= 7,
+	C_DEFLATED	= 8,
+	C_ENHDEFLD	= 9,
+	C_DCLIMPLODED	= 10,
+	C_PKRESERVED	= 11,
+	C_BZIP2		= 12,
+};
+
+/*
+ * A collection of the interesting facts about a file in copy-in mode.
+ */
+struct	file {
+	struct stat	f_st;		/* file stat */
+	long long	f_rmajor;	/* st_rdev major */
+	long long	f_rminor;	/* st_rdev minor */
+	long long	f_dsize;	/* display size */
+	long long	f_csize;	/* compressed size */
+	long long	f_Kbase;	/* base size for -K */
+	long long	f_Krest;	/* rest size for -K */
+	long long	f_Ksize;	/* faked -K size field */
+	char		*f_name;	/* file name */
+	size_t		f_nsiz;		/* file name size */
+	char		*f_lnam;	/* link name */
+	size_t		f_lsiz;		/* link name size */
+	uint32_t	f_chksum;	/* checksum */
+	int		f_pad;		/* padding size */
+	int		f_fd;		/* file descriptor (for pass mode) */
+	enum cmethod	f_cmethod;	/* zip compression method */
+	enum {
+		FG_CRYPT	= 0001,	/* encrypted zip file */
+		FG_BIT1		= 0002,
+		FG_BIT2		= 0004,
+		FG_DESC		= 0010	/* zip file with data descriptor */
+	}		f_gflag;	/* zip general flag */
+	enum {
+		OF_ZIP64	= 0001	/* is a zip64 archive entry */
+	}		f_oflag;	/* other flags */
+};
+
+/*
+ * Patterns for gmatch().
+ */
+struct glist {
+	struct glist	*g_nxt;
+	const char	*g_pat;
+	unsigned	g_gotcha : 1;
+	unsigned	g_not    : 1;
+	unsigned	g_art    : 1;
+};
+
+extern int		aflag;
+extern int		Aflag;
+extern int		bflag;
+extern int		Bflag;
+extern int		cflag;
+extern int		Cflag;
+extern int		dflag;
+extern int		Dflag;
+extern int		eflag;
+extern int		cray_eflag;
+extern const char	*Eflag;
+extern int		fflag;
+extern int		Hflag;
+extern const char	*Iflag;
+extern int		kflag;
+extern int		Kflag;
+extern int		lflag;
+extern int		Lflag;
+extern int		mflag;
+extern const char	*Mflag;
+extern const char	*Oflag;
+extern int		Pflag;
+extern int		rflag;
+extern const char	*Rflag;
+extern int		sflag;
+extern int		Sflag;
+extern int		tflag;
+extern int		uflag;
+extern int		hp_Uflag;
+extern int		vflag;
+extern int		Vflag;
+extern int		sixflag;
+extern int		action;
+extern long long	errcnt;
+extern int		blksiz;
+extern int		sysv3;
+extern int		printsev;
+extern char		*progname;
+extern struct glist	*patterns;
+
+enum {			/* type of pax command this is */
+	PAX_TYPE_CPIO		= 0,	/* not a pax command */
+	PAX_TYPE_PAX1992	= 1,	/* POSIX.2 pax command */
+	PAX_TYPE_PAX2001	= 2	/* POSIX.1-2001 pax command */
+} pax;
+extern int		pax_dflag;
+extern int		pax_kflag;
+extern int		pax_nflag;
+extern int		pax_sflag;
+extern int		pax_uflag;
+extern int		pax_Xflag;
+
+enum {
+	PAX_P_NONE	= 0000,
+	PAX_P_ATIME	= 0001,
+	PAX_P_MTIME	= 0004,
+	PAX_P_OWNER	= 0010,
+	PAX_P_MODE	= 0020,
+	PAX_P_EVERY	= 0400
+} pax_preserve;
+
+extern size_t		(*ofiles)(char **, size_t *);
+extern void		(*prtime)(time_t);
+
+extern ssize_t	bread(char *, size_t);
+extern void	bunread(const char *, size_t);
+extern void	swap(char *, size_t, int, int);
+extern void	msg(int, int, const char *, ...);
+extern void	emsg(int, const char *, ...);
+extern void	unexeoa(void);
+extern int	setfmt(char *);
+extern char	*oneintfmt(const char *);
+extern int	setreassign(const char *);
+extern void	addg(const char *, int);
+extern void	*srealloc(void *, size_t);
+extern void	*smalloc(size_t);
+extern void	*scalloc(size_t, size_t);
+extern void	*svalloc(size_t, int);
+extern char	*sstrdup(const char *);
+extern int	pax_options(char *, int);
+
+extern int	zipunshrink(struct file *, const char *, int, int, uint32_t *);
+extern int	zipexplode(struct file *, const char *, int, int, uint32_t *);
+extern int	zipexpand(struct file *, const char *, int, int, uint32_t *);
+extern int	zipinflate(struct file *, const char *, int, int, uint32_t *);
+extern int	zipunbz2(struct file *, const char *, int, int, uint32_t *);
+extern int	zipblast(struct file *, const char *, int, int, uint32_t *);
+
+extern uint32_t	zipcrc(uint32_t, const uint8_t *, size_t);
+
+extern void	flags(int, char **);
+extern void	usage(void);
+
+extern int	pax_track(const char *, time_t);
+extern void	pax_prlink(struct file *);
+extern int	pax_sname(char **, size_t *);
+extern void	pax_onexit(void);

+ 115 - 0
tools/cpio/src/crc32.c

@@ -0,0 +1,115 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, May 2003.
+ *
+ * Derived from zlib 1.1.4
+ *
+ * Sccsid @(#)crc32.c	1.2 (gritter) 5/29/03
+ */
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+
+  Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+ */
+
+#include "cpio.h"
+
+/*
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+static const uint32_t crc_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uint32_t
+zipcrc(uint32_t crc, const uint8_t *buf, size_t len)
+{
+    if (buf == 0)
+	    return 0L;
+    crc = crc ^ 0xffffffffL;
+    while (len >= 8)
+    {
+      DO8(buf);
+      len -= 8;
+    }
+    if (len) do {
+      DO1(buf);
+    } while (--len);
+    return crc ^ 0xffffffffL;
+}

+ 193 - 0
tools/cpio/src/expand.c

@@ -0,0 +1,193 @@
+/*
+ * cpio - copy file archives in and out
+ *
+ * Gunnar Ritter, Freiburg i. Br., Germany, April 2003.
+ */
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+/*	Sccsid @(#)expand.c	1.6 (gritter) 12/15/03	*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cpio.h"
+
+#define	DLE	144
+
+static void
+zexread(char *data, size_t size, int doswap)
+{
+	if (bread(data, size) != size)
+		unexeoa();
+	if (doswap)
+		swap(data, size, bflag || sflag, bflag || Sflag);
+}
+
+#define	nextbyte()	( \
+	ipos >= sizeof ibuf && isize > 0 ? ( \
+		zexread(ibuf, isize>sizeof ibuf?sizeof ibuf:isize, doswap), \
+		ipos = 0 \
+	) : 0, \
+	isize--, \
+	ibuf[ipos++] & 0377 \
+)
+
+#define	nextbit()	( \
+	ibit = ibit >= 7 ? (ibyte = nextbyte(), 0) : ibit + 1, \
+	isize < 0 ? (ieof = 1, -1) : (ibyte & (1<<ibit)) >> ibit \
+)
+
+#define	sixbits(n)	{ \
+	int	t; \
+	(n) = 0; \
+	for (t = 0; t < 6; t++) \
+		(n) |= nextbit() << t; \
+}
+
+#define	eightbits(n)	{ \
+	int	t; \
+	(n) = 0; \
+	for (t = 0; t < 8; t++) \
+		(n) |= nextbit() << t; \
+}
+
+static void
+zexwrite(int *tfd, char *data, size_t size, uint32_t *crc, int *val,
+		const char *tgt, long long *nsize)
+{
+	if (size) {
+		if (size > *nsize)
+			size = *nsize;
+		if (*tfd >= 0 && write(*tfd, data, size) != size) {
+			emsg(3, "Cannot write \"%s\"", tgt);
+			*tfd = -1;
+			*val = -1;
+		}
+		*crc = zipcrc(*crc, (unsigned char *)data, size);
+		*nsize -= size;
+	}
+}
+
+#define	wadd(c)		( \
+	wpos >= sizeof wbuf ? ( \
+		zexwrite(&tfd, wbuf, sizeof wbuf, crc, &val, tgt, &nsize), \
+		wpos = 0 \
+	) : 0, \
+	wsize++, \
+	wbuf[wpos++] = (c) \
+)
+
+#define	zex_L(x)	( \
+	f->f_cmethod == C_REDUCED1 ? (x) & 0177 : \
+	f->f_cmethod == C_REDUCED2 ? (x) & 077 : \
+	f->f_cmethod == C_REDUCED3 ? (x) & 037 : \
+	/* f->f_cmethod == C_REDUCED4 */ (x) & 017 \
+)
+
+#define	zex_F(x)	( \
+	f->f_cmethod == C_REDUCED1 ? (x) == 0177 ? 2 : 3 : \
+	f->f_cmethod == C_REDUCED2 ? (x) == 077 ? 2 : 3 : \
+	f->f_cmethod == C_REDUCED3 ? (x) == 037 ? 2 : 3 : \
+	/* f->f_cmethod == C_REDUCED4 */ (x) == 017 ? 2 : 3 \
+)
+
+#define	zex_D(x, y)	( \
+	f->f_cmethod == C_REDUCED1 ? (((x)&0200)>>7) * 0400 + (y) + 1 : \
+	f->f_cmethod == C_REDUCED2 ? (((x)&0300)>>6) * 0400 + (y) + 1 : \
+	f->f_cmethod == C_REDUCED3 ? (((x)&0340)>>5) * 0400 + (y) + 1 : \
+	/* f->f_cmethod == C_REDUCED4 */ (((x)&0360)>>4) * 0400 + (y) + 1 \
+)
+
+int
+zipexpand(struct file *f, const char *tgt, int tfd, int doswap, uint32_t *crc)
+{
+	char	fset[256][33];
+	char	ibuf[4096], ibyte = 0, wbuf[8192];
+	long	ipos = sizeof ibuf, wpos = 0, isize = f->f_csize, wsize = 0;
+	int	val = 0, ieof = 0;
+	int	c = 0, i, j, k, n, ibit = 7, lastc, state, v = 0, len = 0;
+	long long	nsize = f->f_st.st_size;
+
+	*crc = 0;
+	memset(fset, 0, sizeof fset);
+	for (j = 255; j >= 0; j--) {
+		sixbits(n);
+		for (i = 0; i < n; i++) {
+			eightbits(fset[j][i]);
+		}
+		fset[j][32] = n<1?0:n<3?1:n<5?2:n<9?3:n<17?4:n<37?5:n<65?6:7;
+	}
+	lastc = 0;
+	state = 0;
+	while (ieof == 0) {
+		if (fset[lastc][32] == 0) {
+			eightbits(c);
+		} else {
+			if (nextbit() != 0) {
+				eightbits(c);
+			} else {
+				i = 0;
+				for (k = 0; k < fset[lastc][32]; k++)
+					i |= nextbit() << k;
+				c = fset[lastc][i] & 0377;
+			}
+		}
+		lastc = c;
+		switch (state) {
+		case 0:
+			if (c != DLE)
+				wadd(c);
+			else
+				state = 1;
+			break;
+		case 1:
+			if (c != 0) {
+				v = c;
+				len = zex_L(v);
+				state = zex_F(len);
+			} else {
+				wadd(DLE);
+				state = 0;
+			}
+			break;
+		case 2:
+			len += c;
+			state = 3;
+			break;
+		case 3:
+			n = wsize - zex_D(v, c);
+			for (i = 0; i < len + 3; i++) {
+				c = n+i >= 0 ? wbuf[n+i&sizeof wbuf-1]&0377 : 0;
+				wadd(c);
+			}
+			state = 0;
+		}
+	}
+	zexwrite(&tfd, wbuf, wpos, crc, &val, tgt, &nsize);
+	while (isize >= 0)
+		nextbyte();
+	return val;
+}

+ 1138 - 0
tools/cpio/src/explode.c

@@ -0,0 +1,1138 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, May 2003.
+ *
+ * Derived from unzip 5.40.
+ *
+ * Sccsid @(#)explode.c	1.6 (gritter) 9/30/03
+ */
+/* explode.c -- put in the public domain by Mark Adler
+   version c15, 6 July 1996 */
+
+
+/* You can do whatever you like with this source file, though I would
+   prefer that if you modify it and redistribute it that you include
+   comments to that effect with your name and the date.  Thank you.
+
+   History:
+   vers    date          who           what
+   ----  ---------  --------------  ------------------------------------
+    c1   30 Mar 92  M. Adler        explode that uses huft_build from inflate
+                                    (this gives over a 70% speed improvement
+                                    over the original unimplode.c, which
+                                    decoded a bit at a time)
+    c2    4 Apr 92  M. Adler        fixed bug for file sizes a multiple of 32k.
+    c3   10 Apr 92  M. Adler        added a little memory tracking if DEBUG
+    c4   11 Apr 92  M. Adler        added NOMEMCPY do kill use of memcpy()
+    c5   21 Apr 92  M. Adler        added the WSIZE #define to allow reducing
+                                    the 32K window size for specialized
+                                    applications.
+    c6   31 May 92  M. Adler        added typecasts to eliminate some warnings
+    c7   27 Jun 92  G. Roelofs      added more typecasts.
+    c8   17 Oct 92  G. Roelofs      changed ULONG/UWORD/byte to ulg/ush/uch.
+    c9   19 Jul 93  J. Bush         added more typecasts (to return values);
+                                    made l[256] array static for Amiga.
+    c10   8 Oct 93  G. Roelofs      added used_csize for diagnostics; added
+                                    buf and unshrink arguments to flush();
+                                    undef'd various macros at end for Turbo C;
+                                    removed NEXTBYTE macro (now in unzip.h)
+                                    and bytebuf variable (not used); changed
+                                    memset() to memzero().
+    c11   9 Jan 94  M. Adler        fixed incorrect used_csize calculation.
+    c12   9 Apr 94  G. Roelofs      fixed split comments on preprocessor lines
+                                    to avoid bug in Encore compiler.
+    c13  25 Aug 94  M. Adler        fixed distance-length comment (orig c9 fix)
+    c14  22 Nov 95  S. Maxwell      removed unnecessary "static" on auto array
+    c15   6 Jul 96  W. Haidinger    added ulg typecasts to flush() calls.
+    c16   8 Feb 98  C. Spieler      added ZCONST modifiers to const tables
+                                    and #ifdef DEBUG around debugging code.
+    c16b 25 Mar 98  C. Spieler      modified DLL code for slide redirection.
+
+         23 May 03  Gunnar Ritter   use cpio structures; C99 conversion.
+ */
+
+
+/*
+   Explode imploded (PKZIP method 6 compressed) data.  This compression
+   method searches for as much of the current string of bytes (up to a length
+   of ~320) in the previous 4K or 8K bytes.  If it doesn't find any matches
+   (of at least length 2 or 3), it codes the next byte.  Otherwise, it codes
+   the length of the matched string and its distance backwards from the
+   current position.  Single bytes ("literals") are preceded by a one (a
+   single bit) and are either uncoded (the eight bits go directly into the
+   compressed stream for a total of nine bits) or Huffman coded with a
+   supplied literal code tree.  If literals are coded, then the minimum match
+   length is three, otherwise it is two.
+
+   There are therefore four kinds of imploded streams: 8K search with coded
+   literals (min match = 3), 4K search with coded literals (min match = 3),
+   8K with uncoded literals (min match = 2), and 4K with uncoded literals
+   (min match = 2).  The kind of stream is identified in two bits of a
+   general purpose bit flag that is outside of the compressed stream.
+
+   Distance-length pairs for matched strings are preceded by a zero bit (to
+   distinguish them from literals) and are always coded.  The distance comes
+   first and is either the low six (4K) or low seven (8K) bits of the
+   distance (uncoded), followed by the high six bits of the distance coded.
+   Then the length is six bits coded (0..63 + min match length), and if the
+   maximum such length is coded, then it's followed by another eight bits
+   (uncoded) to be added to the coded length.  This gives a match length
+   range of 2..320 or 3..321 bytes.
+
+   The literal, length, and distance codes are all represented in a slightly
+   compressed form themselves.  What is sent are the lengths of the codes for
+   each value, which is sufficient to construct the codes.  Each byte of the
+   code representation is the code length (the low four bits representing
+   1..16), and the number of values sequentially with that length (the high
+   four bits also representing 1..16).  There are 256 literal code values (if
+   literals are coded), 64 length code values, and 64 distance code values,
+   in that order at the beginning of the compressed stream.  Each set of code
+   values is preceded (redundantly) with a byte indicating how many bytes are
+   in the code description that follows, in the range 1..256.
+
+   The codes themselves are decoded using tables made by huft_build() from
+   the bit lengths.  That routine and its comments are in the inflate.c
+   module.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cpio.h"
+#include "unzip.h"  /* must supply slide[] (uint8_t) array and NEXTBYTE macro */
+
+/* routines here */
+static int get_tree(struct globals *, unsigned *l, unsigned n);
+static int explode_lit8(struct globals *, struct huft *tb, struct huft *tl,
+                            struct huft *td, int bb, int bl, int bd);
+static int explode_lit4(struct globals *, struct huft *tb, struct huft *tl,
+                            struct huft *td, int bb, int bl, int bd);
+static int explode_nolit8(struct globals *, struct huft *tl, struct huft *td,
+                              int bl, int bd);
+static int explode_nolit4(struct globals *, struct huft *tl, struct huft *td,
+                              int bl, int bd);
+
+/* The implode algorithm uses a sliding 4K or 8K byte window on the
+   uncompressed stream to find repeated byte strings.  This is implemented
+   here as a circular buffer.  The index is updated simply by incrementing
+   and then and'ing with 0x0fff (4K-1) or 0x1fff (8K-1).  Here, the 32K
+   buffer of inflate is used, and it works just as well to always have
+   a 32K circular buffer, so the index is anded with 0x7fff.  This is
+   done to allow the window to also be used as the output buffer. */
+/* This must be supplied in an external module useable like
+   "uint8_t slide[8192];" or "uint8_t *slide;", where the latter would
+   be malloc'ed.  In unzip, slide[] is actually a 32K area for use by
+   inflate, which uses a 32K sliding window.
+ */
+
+
+/* Tables for length and distance */
+static const uint16_t cplen2[] =
+        {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+        18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+        35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65};
+static const uint16_t cplen3[] =
+        {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+        19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+        36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+        53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66};
+static const uint8_t extra[] =
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        8};
+static const uint16_t cpdist4[] =
+        {1, 65, 129, 193, 257, 321, 385, 449, 513, 577, 641, 705,
+        769, 833, 897, 961, 1025, 1089, 1153, 1217, 1281, 1345, 1409, 1473,
+        1537, 1601, 1665, 1729, 1793, 1857, 1921, 1985, 2049, 2113, 2177,
+        2241, 2305, 2369, 2433, 2497, 2561, 2625, 2689, 2753, 2817, 2881,
+        2945, 3009, 3073, 3137, 3201, 3265, 3329, 3393, 3457, 3521, 3585,
+        3649, 3713, 3777, 3841, 3905, 3969, 4033};
+static const uint16_t cpdist8[] =
+        {1, 129, 257, 385, 513, 641, 769, 897, 1025, 1153, 1281,
+        1409, 1537, 1665, 1793, 1921, 2049, 2177, 2305, 2433, 2561, 2689,
+        2817, 2945, 3073, 3201, 3329, 3457, 3585, 3713, 3841, 3969, 4097,
+        4225, 4353, 4481, 4609, 4737, 4865, 4993, 5121, 5249, 5377, 5505,
+        5633, 5761, 5889, 6017, 6145, 6273, 6401, 6529, 6657, 6785, 6913,
+        7041, 7169, 7297, 7425, 7553, 7681, 7809, 7937, 8065};
+
+
+/* Macros for inflate() bit peeking and grabbing.
+   The usage is:
+
+        NEEDBITS(j)
+        x = b & mask_bits[j];
+        DUMPBITS(j)
+
+   where NEEDBITS makes sure that b has at least j bits in it, and
+   DUMPBITS removes the bits from b.  The macros use the variable k
+   for the number of bits in b.  Normally, b and k are register
+   variables for speed.
+ */
+
+#define NEEDBITS(n) {while(k<(n)){b|=((uint32_t)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+#define	Bits	16
+#define	Nob	16
+#define	Eob	15
+
+#define	G	(*Gp)
+
+static int
+get_tree(struct globals *Gp, unsigned *l, unsigned n)
+/*unsigned *l;*/          /* bit lengths */
+/*unsigned n;*/           /* number expected */
+/* Get the bit lengths for a code representation from the compressed
+   stream.  If get_tree() returns 4, then there is an error in the data.
+   Otherwise zero is returned. */
+{
+  unsigned i;           /* bytes remaining in list */
+  unsigned k;           /* lengths entered */
+  unsigned j;           /* number of codes */
+  unsigned b;           /* bit length for those codes */
+
+
+  /* get bit lengths */
+  i = NEXTBYTE + 1;                     /* length/count pairs to read */
+  k = 0;                                /* next code */
+  do {
+    b = ((j = NEXTBYTE) & 0xf) + 1;     /* bits in code (1..16) */
+    j = ((j & 0xf0) >> 4) + 1;          /* codes with those bits (1..16) */
+    if (k + j > n)
+      return 4;                         /* don't overflow l[] */
+    do {
+      l[k++] = b;
+    } while (--j);
+  } while (--i);
+  return k != n ? 4 : 0;                /* should have read n of them */
+}
+
+
+
+static int
+explode_lit8(struct globals *Gp,
+		struct huft *tb, struct huft *tl, struct huft *td,
+		int bb, int bl, int bd)
+/*struct huft *tb, *tl, *td;*/    /* literal, length, and distance tables */
+/*int bb, bl, bd;*/               /* number of bits decoded by those */
+/* Decompress the imploded data using coded literals and an 8K sliding
+   window. */
+{
+  long s;               /* bytes to decompress */
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned mb, ml, md;  /* masks for bb, bl, and bd bits */
+  register uint32_t b;  /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  unsigned u;           /* true if unflushed */
+
+
+  /* explode the coded data */
+  b = k = w = 0;                /* initialize bit buffer, window */
+  u = 1;                        /* buffer unflushed */
+  mb = mask_bits[bb];           /* precompute masks for speed */
+  ml = mask_bits[bl];
+  md = mask_bits[bd];
+  s = G.ucsize;
+  while (s > 0)                 /* do until ucsize bytes uncompressed */
+  {
+    NEEDBITS(1)
+    if (b & 1)                  /* then literal--decode it */
+    {
+      DUMPBITS(1)
+      s--;
+      NEEDBITS((unsigned)bb)    /* get coded literal */
+      if ((e = (t = tb + ((~(unsigned)b) & mb))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      redirSlide[w++] = (uint8_t)t->v.n;
+      if (w == WSIZE)
+      {
+        flush(&G, redirSlide, (uint32_t)w);
+        w = u = 0;
+      }
+    }
+    else                        /* else distance/length */
+    {
+      DUMPBITS(1)
+      NEEDBITS(7)               /* get distance low bits */
+      d = (unsigned)b & 0x7f;
+      DUMPBITS(7)
+      NEEDBITS((unsigned)bd)    /* get coded distance high bits */
+      if ((e = (t = td + ((~(unsigned)b) & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      d = w - d - t->v.n;       /* construct offset */
+      NEEDBITS((unsigned)bl)    /* get coded length */
+      if ((e = (t = tl + ((~(unsigned)b) & ml))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      n = t->v.n;
+      if (e)                    /* get length extra bits */
+      {
+        NEEDBITS(8)
+        n += (unsigned)b & 0xff;
+        DUMPBITS(8)
+      }
+
+      /* do the copy */
+      s -= n;
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+        if (u && w <= d)
+        {
+          memset(redirSlide + w, 0, e);
+          w += e;
+          d += e;
+        }
+        else
+#ifndef NOMEMCPY
+          if (w - d >= e)       /* (this test assumes unsigned comparison) */
+          {
+            memcpy(redirSlide + w, redirSlide + d, e);
+            w += e;
+            d += e;
+          }
+          else                  /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+            do {
+              redirSlide[w++] = redirSlide[d++];
+            } while (--e);
+        if (w == WSIZE)
+        {
+          flush(&G, redirSlide, (uint32_t)w);
+          w = u = 0;
+        }
+      } while (n);
+    }
+  }
+
+  /* flush out redirSlide */
+  flush(&G, redirSlide, (uint32_t)w);
+  if (G.csize + G.incnt + (k >> 3))   /* should have read csize bytes, but */
+  {                        /* sometimes read one too many:  k>>3 compensates */
+    /*G.used_csize = G.zsize - G.csize - G.incnt - (k >> 3);*/
+    return 5;
+  }
+  return 0;
+}
+
+
+
+static int
+explode_lit4(struct globals *Gp,
+		struct huft *tb, struct huft *tl, struct huft *td,
+		int bb, int bl, int bd)
+/*struct huft *tb, *tl, *td;*/    /* literal, length, and distance tables */
+/*int bb, bl, bd;*/               /* number of bits decoded by those */
+/* Decompress the imploded data using coded literals and a 4K sliding
+   window. */
+{
+  long s;               /* bytes to decompress */
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned mb, ml, md;  /* masks for bb, bl, and bd bits */
+  register uint32_t b;  /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  unsigned u;           /* true if unflushed */
+
+
+  /* explode the coded data */
+  b = k = w = 0;                /* initialize bit buffer, window */
+  u = 1;                        /* buffer unflushed */
+  mb = mask_bits[bb];           /* precompute masks for speed */
+  ml = mask_bits[bl];
+  md = mask_bits[bd];
+  s = G.ucsize;
+  while (s > 0)                 /* do until ucsize bytes uncompressed */
+  {
+    NEEDBITS(1)
+    if (b & 1)                  /* then literal--decode it */
+    {
+      DUMPBITS(1)
+      s--;
+      NEEDBITS((unsigned)bb)    /* get coded literal */
+      if ((e = (t = tb + ((~(unsigned)b) & mb))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      redirSlide[w++] = (uint8_t)t->v.n;
+      if (w == WSIZE)
+      {
+        flush(&G, redirSlide, (uint32_t)w);
+        w = u = 0;
+      }
+    }
+    else                        /* else distance/length */
+    {
+      DUMPBITS(1)
+      NEEDBITS(6)               /* get distance low bits */
+      d = (unsigned)b & 0x3f;
+      DUMPBITS(6)
+      NEEDBITS((unsigned)bd)    /* get coded distance high bits */
+      if ((e = (t = td + ((~(unsigned)b) & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      d = w - d - t->v.n;       /* construct offset */
+      NEEDBITS((unsigned)bl)    /* get coded length */
+      if ((e = (t = tl + ((~(unsigned)b) & ml))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      n = t->v.n;
+      if (e)                    /* get length extra bits */
+      {
+        NEEDBITS(8)
+        n += (unsigned)b & 0xff;
+        DUMPBITS(8)
+      }
+
+      /* do the copy */
+      s -= n;
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+        if (u && w <= d)
+        {
+          memset(redirSlide + w, 0, e);
+          w += e;
+          d += e;
+        }
+        else
+#ifndef NOMEMCPY
+          if (w - d >= e)       /* (this test assumes unsigned comparison) */
+          {
+            memcpy(redirSlide + w, redirSlide + d, e);
+            w += e;
+            d += e;
+          }
+          else                  /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+            do {
+              redirSlide[w++] = redirSlide[d++];
+            } while (--e);
+        if (w == WSIZE)
+        {
+          flush(&G, redirSlide, (uint32_t)w);
+          w = u = 0;
+        }
+      } while (n);
+    }
+  }
+
+  /* flush out redirSlide */
+  flush(&G, redirSlide, (uint32_t)w);
+  if (G.csize + G.incnt + (k >> 3))   /* should have read csize bytes, but */
+  {                        /* sometimes read one too many:  k>>3 compensates */
+    /*G.used_csize = G.zsize - G.csize - G.incnt - (k >> 3);*/
+    return 5;
+  }
+  return 0;
+}
+
+
+
+static int
+explode_nolit8(struct globals *Gp,
+		struct huft *tl, struct huft *td, int bl, int bd)
+/*struct huft *tl, *td;*/ /* length and distance decoder tables */
+/*int bl, bd;*/           /* number of bits decoded by tl[] and td[] */
+/* Decompress the imploded data using uncoded literals and an 8K sliding
+   window. */
+{
+  long s;               /* bytes to decompress */
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned ml, md;      /* masks for bl and bd bits */
+  register uint32_t b;  /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  unsigned u;           /* true if unflushed */
+
+
+  /* explode the coded data */
+  b = k = w = 0;                /* initialize bit buffer, window */
+  u = 1;                        /* buffer unflushed */
+  ml = mask_bits[bl];           /* precompute masks for speed */
+  md = mask_bits[bd];
+  s = G.ucsize;
+  while (s > 0)                 /* do until ucsize bytes uncompressed */
+  {
+    NEEDBITS(1)
+    if (b & 1)                  /* then literal--get eight bits */
+    {
+      DUMPBITS(1)
+      s--;
+      NEEDBITS(8)
+      redirSlide[w++] = (uint8_t)b;
+      if (w == WSIZE)
+      {
+        flush(&G, redirSlide, (uint32_t)w);
+        w = u = 0;
+      }
+      DUMPBITS(8)
+    }
+    else                        /* else distance/length */
+    {
+      DUMPBITS(1)
+      NEEDBITS(7)               /* get distance low bits */
+      d = (unsigned)b & 0x7f;
+      DUMPBITS(7)
+      NEEDBITS((unsigned)bd)    /* get coded distance high bits */
+      if ((e = (t = td + ((~(unsigned)b) & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      d = w - d - t->v.n;       /* construct offset */
+      NEEDBITS((unsigned)bl)    /* get coded length */
+      if ((e = (t = tl + ((~(unsigned)b) & ml))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      n = t->v.n;
+      if (e)                    /* get length extra bits */
+      {
+        NEEDBITS(8)
+        n += (unsigned)b & 0xff;
+        DUMPBITS(8)
+      }
+
+      /* do the copy */
+      s -= n;
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+        if (u && w <= d)
+        {
+          memset(redirSlide + w, 0, e);
+          w += e;
+          d += e;
+        }
+        else
+#ifndef NOMEMCPY
+          if (w - d >= e)       /* (this test assumes unsigned comparison) */
+          {
+            memcpy(redirSlide + w, redirSlide + d, e);
+            w += e;
+            d += e;
+          }
+          else                  /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+            do {
+              redirSlide[w++] = redirSlide[d++];
+            } while (--e);
+        if (w == WSIZE)
+        {
+          flush(&G, redirSlide, (uint32_t)w);
+          w = u = 0;
+        }
+      } while (n);
+    }
+  }
+
+  /* flush out redirSlide */
+  flush(&G, redirSlide, (uint32_t)w);
+  if (G.csize + G.incnt + (k >> 3))   /* should have read csize bytes, but */
+  {                        /* sometimes read one too many:  k>>3 compensates */
+    /*G.used_csize = G.zsize - G.csize - G.incnt - (k >> 3);*/
+    return 5;
+  }
+  return 0;
+}
+
+
+
+static int
+explode_nolit4(struct globals *Gp,
+		struct huft *tl, struct huft *td, int bl, int bd)
+/*struct huft *tl, *td;*/ /* length and distance decoder tables */
+/*int bl, bd;*/           /* number of bits decoded by tl[] and td[] */
+/* Decompress the imploded data using uncoded literals and a 4K sliding
+   window. */
+{
+  long s;               /* bytes to decompress */
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned ml, md;      /* masks for bl and bd bits */
+  register uint32_t b;  /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  unsigned u;           /* true if unflushed */
+
+
+  /* explode the coded data */
+  b = k = w = 0;                /* initialize bit buffer, window */
+  u = 1;                        /* buffer unflushed */
+  ml = mask_bits[bl];           /* precompute masks for speed */
+  md = mask_bits[bd];
+  s = G.ucsize;
+  while (s > 0)                 /* do until ucsize bytes uncompressed */
+  {
+    NEEDBITS(1)
+    if (b & 1)                  /* then literal--get eight bits */
+    {
+      DUMPBITS(1)
+      s--;
+      NEEDBITS(8)
+      redirSlide[w++] = (uint8_t)b;
+      if (w == WSIZE)
+      {
+        flush(&G, redirSlide, (uint32_t)w);
+        w = u = 0;
+      }
+      DUMPBITS(8)
+    }
+    else                        /* else distance/length */
+    {
+      DUMPBITS(1)
+      NEEDBITS(6)               /* get distance low bits */
+      d = (unsigned)b & 0x3f;
+      DUMPBITS(6)
+      NEEDBITS((unsigned)bd)    /* get coded distance high bits */
+      if ((e = (t = td + ((~(unsigned)b) & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      d = w - d - t->v.n;       /* construct offset */
+      NEEDBITS((unsigned)bl)    /* get coded length */
+      if ((e = (t = tl + ((~(unsigned)b) & ml))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((~(unsigned)b) & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      n = t->v.n;
+      if (e)                    /* get length extra bits */
+      {
+        NEEDBITS(8)
+        n += (unsigned)b & 0xff;
+        DUMPBITS(8)
+      }
+
+      /* do the copy */
+      s -= n;
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+        if (u && w <= d)
+        {
+          memset(redirSlide + w, 0, e);
+          w += e;
+          d += e;
+        }
+        else
+#ifndef NOMEMCPY
+          if (w - d >= e)       /* (this test assumes unsigned comparison) */
+          {
+            memcpy(redirSlide + w, redirSlide + d, e);
+            w += e;
+            d += e;
+          }
+          else                  /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+            do {
+              redirSlide[w++] = redirSlide[d++];
+            } while (--e);
+        if (w == WSIZE)
+        {
+          flush(&G, redirSlide, (uint32_t)w);
+          w = u = 0;
+        }
+      } while (n);
+    }
+  }
+
+  /* flush out redirSlide */
+  flush(&G, redirSlide, (uint32_t)w);
+  if (G.csize + G.incnt + (k >> 3))   /* should have read csize bytes, but */
+  {                        /* sometimes read one too many:  k>>3 compensates */
+    /*G.used_csize = G.zsize - G.csize - G.incnt - (k >> 3);*/
+    return 5;
+  }
+  return 0;
+}
+
+#undef	G
+
+int
+zipexplode(struct file *f, const char *tgt, int tfd, int doswap, uint32_t *crc)
+/* Explode an imploded compressed stream.  Based on the general purpose
+   bit flag, decide on coded or uncoded literals, and an 8K or 4K sliding
+   window.  Construct the literal (if any), length, and distance codes and
+   the tables needed to decode them (using huft_build() from inflate.c),
+   and call the appropriate routine for the type of data in the remainder
+   of the stream.  The four routines are nearly identical, differing only
+   in whether the literal is decoded or simply read in, and in how many
+   bits are read in, uncoded, for the low distance bits. */
+{
+  struct globals G;
+  unsigned r;           /* return codes */
+  struct huft *tb;      /* literal code table */
+  struct huft *tl;      /* length code table */
+  struct huft *td;      /* distance code table */
+  int bb;               /* bits for tb */
+  int bl;               /* bits for tl */
+  int bd;               /* bits for td */
+  unsigned l[256];      /* bit lengths for codes */
+
+  memset(&G, 0, sizeof G);
+  G.tgt = tgt;
+  G.tfd = tfd;
+  G.doswap = doswap;
+  G.crc = crc;
+  G.zsize = G.uzsize = f->f_csize;
+  G.ucsize = f->f_st.st_size;
+
+  /* Tune base table sizes.  Note: I thought that to truly optimize speed,
+     I would have to select different bl, bd, and bb values for different
+     compressed file sizes.  I was surprised to find out that the values of
+     7, 7, and 9 worked best over a very wide range of sizes, except that
+     bd = 8 worked marginally better for large compressed sizes. */
+  bl = 7;
+  bd = (G.csize + G.incnt) > 200000L ? 8 : 7;
+
+
+  /* With literal tree--minimum match length is 3 */
+#ifdef DEBUG
+  G.hufts = 0;                    /* initialize huft's malloc'ed */
+#endif
+  if (f->f_gflag & FG_BIT2)
+  {
+    bb = 9;                     /* base table size for literals */
+    if ((r = get_tree(&G, l, 256)) != 0)
+      goto err;
+    if ((r = huft_build(l, 256, 256, NULL, NULL, &tb, &bb,
+		Bits, Nob, Eob)) != 0)
+    {
+      if (r == 1)
+        huft_free(tb);
+      goto err;
+    }
+    if ((r = get_tree(&G, l, 64)) != 0)
+      goto err;
+    if ((r = huft_build(l, 64, 0, cplen3, extra, &tl, &bl,
+		Bits, Nob, Eob)) != 0)
+    {
+      if (r == 1)
+        huft_free(tl);
+      huft_free(tb);
+      goto err;
+    }
+    if ((r = get_tree(&G, l, 64)) != 0)
+      goto err;
+    if (f->f_gflag & FG_BIT1)      /* true if 8K */
+    {
+      if ((r = huft_build(l, 64, 0, cpdist8, extra, &td, &bd,
+		Bits, Nob, Eob)) != 0)
+      {
+        if (r == 1)
+          huft_free(td);
+        huft_free(tl);
+        huft_free(tb);
+        goto err;
+      }
+      r = explode_lit8(&G, tb, tl, td, bb, bl, bd);
+    }
+    else                                        /* else 4K */
+    {
+      if ((r = huft_build(l, 64, 0, cpdist4, extra, &td, &bd,
+		Bits, Nob, Eob)) != 0)
+      {
+        if (r == 1)
+          huft_free(td);
+        huft_free(tl);
+        huft_free(tb);
+        goto err;
+      }
+      r = explode_lit4(&G, tb, tl, td, bb, bl, bd);
+    }
+    huft_free(td);
+    huft_free(tl);
+    huft_free(tb);
+  }
+  else
+
+
+  /* No literal tree--minimum match length is 2 */
+  {
+    if ((r = get_tree(&G, l, 64)) != 0)
+      goto err;
+    if ((r = huft_build(l, 64, 0, cplen2, extra, &tl, &bl,
+		Bits, Nob, Eob)) != 0)
+    {
+      if (r == 1)
+        huft_free(tl);
+      goto err;
+    }
+    if ((r = get_tree(&G, l, 64)) != 0)
+      goto err;
+    if (f->f_gflag & FG_BIT1)      /* true if 8K */
+    {
+      if ((r = huft_build(l, 64, 0, cpdist8, extra, &td, &bd,
+		Bits, Nob, Eob)) != 0)
+      {
+        if (r == 1)
+          huft_free(td);
+        huft_free(tl);
+        goto err;
+      }
+      r = explode_nolit8(&G, tl, td, bl, bd);
+    }
+    else                                        /* else 4K */
+    {
+      if ((r = huft_build(l, 64, 0, cpdist4, extra, &td, &bd,
+		Bits, Nob, Eob)) != 0)
+      {
+        if (r == 1)
+          huft_free(td);
+        huft_free(tl);
+        goto err;
+      }
+      r = explode_nolit4(&G, tl, td, bl, bd);
+    }
+    huft_free(td);
+    huft_free(tl);
+  }
+  Trace((stderr, "<%u > ", G.hufts));
+err:
+  switch (r) {
+  case 0:
+	  break;
+  case 5:
+	  while (G.uzsize > 0)
+		  NEXTBYTE;
+	  /*FALLTHRU*/
+  default:
+	  msg(3, 0, "compression error on \"%s\"\n", f->f_name);
+  }
+  return r || G.status ? -1 : 0;
+}
+
+/* The following code is derived from: */
+
+/* inflate.c -- put in the public domain by Mark Adler
+   version c16b, 29 March 1998 */
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uint32_t. */
+#define BMAX 16         /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+
+int
+huft_build(const unsigned *b, unsigned n, unsigned s,
+		const uint16_t *d, const uint8_t *e,
+		struct huft **t, int *m,
+		int bits, int nob, int eob)
+/*const unsigned *b;*/ /* code lengths in bits (all assumed <= BMAX) */
+/*unsigned n;*/         /* number of codes (assumed <= N_MAX) */
+/*unsigned s;*/         /* number of simple-valued codes (0..s-1) */
+/*const uint16_t *d;*/  /* list of base values for non-simple codes */
+/*const uint16_t *e;*/  /* list of extra bits for non-simple codes */
+/*struct huft **t;*/    /* result: starting table */
+/*int *m;*/             /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return zero on success, one if
+   the given code set is incomplete (the tables are still built in this
+   case), two if the input is invalid (all zero length codes or an
+   oversubscribed set of lengths), and three if not enough memory.
+   The code with value 256 is special, and the tables are constructed
+   so that no bits beyond that code are fetched when that code is
+   decoded. */
+{
+  unsigned a;                   /* counter for codes of length k */
+  unsigned c[BMAX+1];           /* bit length count table */
+  unsigned el;                  /* length of EOB code (value 256) */
+  unsigned f;                   /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register unsigned i;          /* counter, current code */
+  register unsigned j;          /* counter */
+  register int k;               /* number of bits in current code */
+  int lx[BMAX+1];               /* memory for l[-1..BMAX-1] */
+  int *l = lx+1;                /* stack of bits per table */
+  register unsigned *p;         /* pointer into c[], b[], or v[] */
+  register struct huft *q;      /* points to current table */
+  struct huft r;                /* table entry for structure assignment */
+  struct huft *u[BMAX];         /* table stack */
+  unsigned v[N_MAX];            /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  unsigned x[BMAX+1];           /* bit offsets, then code stack */
+  unsigned *xp;                 /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  unsigned z;                   /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  el = n > 256 ? b[256] : BMAX; /* set length of EOB code, if any */
+  memset(c, 0, sizeof c);
+  p = (unsigned *)b;  i = n;
+  do {
+    c[*p]++; p++;               /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = NULL;
+    *m = 0;
+    return 0;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((unsigned)*m < j)
+    *m = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((unsigned)*m > i)
+    *m = i;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return 2;                 /* bad input: more codes than bits */
+  if ((y -= c[i]) < 0)
+    return 2;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  memset(v, 0, sizeof v);
+  p = (unsigned *)b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                     /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = l[-1] = 0;                /* no bits decoded yet */
+  u[0] = NULL;   		/* just to keep compilers happy */
+  q = NULL;     		 /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l[h])
+      {
+        w += l[h++];            /* add bits already decoded */
+
+        /* compute minimum size table less than or equal to *m bits */
+        z = (z = g - w) > (unsigned)*m ? *m : z;        /* upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          while (++j < z)       /* try smaller tables up to z bits */
+          {
+            if ((f <<= 1) <= *++xp)
+              break;            /* enough codes to use up j bits */
+            f -= *xp;           /* else deduct codes from patterns */
+          }
+        }
+        if ((unsigned)w + j > el && (unsigned)w < el)
+          j = el - w;           /* make EOB code end at table */
+        z = 1 << j;             /* table entries for j-bit table */
+        l[h] = j;               /* set table size in stack */
+
+        /* allocate and link in new table */
+        if ((q = malloc((z + 1)*sizeof(struct huft))) == NULL)
+        {
+          if (h)
+            huft_free(u[0]);
+          return 3;             /* not enough memory */
+        }
+#ifdef DEBUG
+        G.hufts += z + 1;         /* track memory usage */
+#endif
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->v.t)) = NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.b = (uint8_t)l[h-1];    /* bits to dump before this table */
+          r.e = (uint8_t)(bits + j);  /* bits in this table */
+          r.v.t = q;            /* pointer to this table */
+          j = (i & ((1 << w) - 1)) >> (w - l[h-1]);
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.b = (uint8_t)(k - w);
+      if (p >= v + n)
+        r.e = 99;               /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.e = (uint8_t)(*p < 256 ? nob : eob);  /* 256 is end-of-block code */
+        r.v.n = (uint16_t)*p++;           /* simple code is just the value */
+      }
+      else
+      {
+        r.e = (uint8_t)e[*p - s];   /* non-simple--look up in lists */
+        r.v.n = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+        w -= l[--h];            /* don't need to update q */
+    }
+  }
+
+
+  /* return actual size of base table */
+  *m = l[0];
+
+
+  /* Return true (1) if we were given an incomplete table */
+  return y != 0 && g != 1;
+}
+
+
+void
+huft_free(struct huft *t)
+/*struct huft *t;*/         /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register struct huft *p, *q;
+
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != NULL)
+  {
+    q = (--p)->v.t;
+    free(p);
+    p = q;
+  }
+}
+
+const uint16_t	mask_bits[] = {
+	0x0000,
+	0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+	0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+void
+flush(struct globals *Gp, const void *data, size_t size)
+{
+	if (Gp->tfd>=0 && write(Gp->tfd, data, size) != size) {
+		emsg(3, "Cannot write \"%s\"", Gp->tgt);
+		Gp->tfd = -1;
+		Gp->status = -1;
+	}
+	*Gp->crc = zipcrc(*Gp->crc, data, size);
+}
+
+int
+readbyte(struct globals *Gp)
+{
+	if (Gp->uzsize <= 0)
+		return EOF;
+	Gp->incnt = bread((char *)Gp->inbuf,
+		Gp->uzsize>sizeof Gp->inbuf?sizeof Gp->inbuf:Gp->uzsize);
+	if (Gp->incnt <= 0)
+		unexeoa();
+	if (Gp->doswap)
+		swap((char *)Gp->inbuf, Gp->incnt, bflag||sflag,bflag||Sflag);
+	Gp->uzsize -= Gp->incnt;
+	Gp->incnt--;
+	Gp->inptr = Gp->inbuf;
+	return (int)(*Gp->inptr++);
+}

+ 257 - 0
tools/cpio/src/flags.c

@@ -0,0 +1,257 @@
+/*
+ * cpio - copy file archives in and out
+ *
+ * Gunnar Ritter, Freiburg i. Br., Germany, April 2003.
+ */
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+/*	Sccsid @(#)flags.c	1.6 (gritter) 3/26/07	*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "cpio.h"
+
+void
+flags(int ac, char **av)
+{
+	const char	optstring[] =
+		"iopaAbBcC:dDeE:fH:I:kKlLmM:O:PrR:sStTuvV6";
+	int	i, illegal = 0;
+
+	if (getenv("SYSV3") != NULL)
+		sysv3 = printsev = 1;
+	while ((i = getopt(ac, av, optstring)) != EOF) {
+		switch (i) {
+		case 'i':
+		case 'o':
+		case 'p':
+			if (action && action != i)
+				illegal = 1;
+			action = i;
+			break;
+		case 'a':
+			aflag = 1;
+			break;
+		case 'A':
+			Aflag = 1;
+			break;
+		case 'b':
+			bflag = 1;
+			break;
+		case 'B':
+			blksiz = 5120;
+			Bflag = 1;
+			break;
+		case 'c':
+			fmttype = sysv3 ? FMT_ODC : FMT_ASC;
+			cflag = 1;
+			break;
+		case 'C':
+			if ((blksiz = atol(optarg)) <= 0)
+				msg(4, -2,
+					"Illegal size given for -C option.\n");
+			Cflag = 1;
+			break;
+		case 'd':
+			dflag = 1;
+			break;
+		case 'D':
+			Dflag = 1;
+			break;
+		case 'e':
+			/*
+			 * This option is accepted for compatibility only,
+			 * -Hdec should be used instead.
+			 */
+			fmttype = FMT_DEC;
+			eflag = 1;
+			break;
+		case 'E':
+			Eflag = optarg;
+			break;
+		case 'f':
+			fflag = 1;
+			break;
+		case 'H':
+			if (setfmt(optarg) < 0)
+				illegal = 1;
+			Hflag = 1;
+			break;
+		case 'I':
+			Iflag = optarg;
+			break;
+		case 'k':
+			kflag = 1;
+			break;
+		case 'K':
+			/*
+			 * This option is accepted for compatibility only,
+			 * -Hsgi should be used instead.
+			 */
+			fmttype = FMT_SGIBE;
+			Kflag = 1;
+			break;
+		case 'l':
+			lflag = 1;
+			break;
+		case 'L':
+			Lflag = 1;
+			break;
+		case 'm':
+			mflag = 1;
+			break;
+		case 'M':
+			Mflag = oneintfmt(optarg);
+			break;
+		case 'O':
+			Oflag = optarg;
+			break;
+		case 'P':
+			Pflag = 1;
+			break;
+		case 'r':
+			rflag = 1;
+			break;
+		case 'R':
+			if (setreassign(Rflag = optarg) < 0)
+				illegal = 1;
+			break;
+		case 's':
+			sflag = 1;
+			break;
+		case 'S':
+			Sflag = 1;
+			break;
+		case 't':
+			tflag = 1;
+			break;
+		case 'u':
+			uflag = 1;
+			break;
+		case 'v':
+			vflag++;
+			break;
+		case 'V':
+			Vflag = 1;
+			break;
+		case '6':
+			sixflag = 1;
+			fmttype = FMT_BINLE;
+			break;
+		default:
+			if (sysv3)
+				usage();
+			illegal = 1;
+		}
+	}
+	switch (action) {
+	case 'i':
+		if (Oflag || Kflag || eflag || Lflag || lflag || aflag ||
+				Aflag || Pflag)
+			illegal = 1;
+		for (i = optind; i < ac; i++)
+			addg(av[i], 0);
+		break;
+	case 'o':
+		if (Iflag || dflag || fflag || kflag || mflag ||
+				rflag || tflag || uflag ||
+				sixflag || Eflag || Rflag)
+			illegal = 1;
+		if (optind != ac)
+			illegal = 1;
+		break;
+	case 'p':
+		if (Iflag || Oflag || blksiz || Eflag || fmttype != FMT_NONE ||
+				Mflag || bflag || fflag || kflag || sflag ||
+				tflag || Sflag || sixflag)
+			illegal = 1;
+		if (optind + 1 != ac)
+			illegal = 1;
+		break;
+	default:
+		if (sysv3 == 0)
+			msg(3, 0, "One of -i, -o or -p must be specified.\n");
+		else if (ac > 1)
+			msg(3, -2, "Options must include one: -o, -i, -p.\n");
+		illegal = 1;
+	}
+	/*
+	 * Sanity checks. No check for multiple occurences of options
+	 * since they can make sense, behave as other programs and use
+	 * the latter one.
+	 */
+	/*if (aflag && mflag) {
+		msg(3, 0, "-a and -m are mutually exclusive.\n");
+		illegal = 1;
+	} why? */
+	/*if (cflag && (Hflag || Kflag || eflag)) {
+		msg(3, 0, "-c and -H are mutually exclusive.\n");
+		illegal = 1;
+	} allow overriding -c with -H and vice versa */
+	if ((vflag || tflag) && Vflag) {
+		msg(3, 0, "-v and -V are mutually exclusive.\n");
+		illegal = 1;
+	}
+	/*if (Bflag && Cflag) {
+		msg(3, 0, "-B and -C are mutually exclusive.\n");
+		illegal = 1;
+	} allow overriding of block sizes */
+	if ((Hflag || cflag || Kflag || eflag) && sixflag) {
+		msg(3, 0, "-H and -6 are mutually exclusive.\n");
+		illegal = 1;
+	}
+	if (!sysv3 && Mflag && Oflag == NULL && Iflag == NULL) {
+		msg(3, 0, "-M not meaningful without -O or -I.\n");
+		illegal = 1;
+	}
+	if (!sysv3 && Aflag && Oflag == NULL) {
+		msg(3, 0, "-A requires the -O option\n");
+		illegal = 1;
+	}
+	if (illegal)
+		usage();
+}
+
+void
+usage(void)
+{
+	if (sysv3)
+		fprintf(stderr, "\
+Usage:  %s -o[acvVABL] [-Csize] [-Hhdr] [-Mmsg] <name-list >collection\n\
+\t%s -o[acvVABL] -Ocollection [-Csize] [-Hhdr] [-Mmsg] <name-list\n\
+\t%s -i[bcdkmrsStuvVfB6] [-Csize] [-Efile] [-Hhdr] [-Mmsg] [-Rid] [pattern ...] <collection\n\
+\t%s -i[bcdkmrsStuvVfB6] -Icollection [-Csize] [-Efile] [-Hhdr] [-Mmsg] [-Rid] [pattern ...]\n\
+\t%s -p[adlmruvVL] [-Rid] directory <name-list\n",
+			progname, progname, progname, progname, progname);
+	else
+		fprintf(stderr, "USAGE:\n\
+\t%s -i[bcdfkmrstuvBSV6] [-C size] [-E file] [-H hdr] [[-I file] [-M msg]] \
+[-R id] [patterns]\n\
+\t%s -o[acvABLV] [-C size] [-H hdr] [[-M msg] [-O file]]\n\
+\t%s -p[adlmuvLV] [-R id] directory\n",
+			progname, progname, progname);
+	exit(1);
+}

+ 197 - 0
tools/cpio/src/getdir.c

@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)getdir.c	1.20 (gritter) 5/14/06	*/
+
+#ifndef	__linux__
+/*
+ * 32-bit Solaris and Open UNIX do not have 64-bit getdents(); but
+ * having _FILE_OFFSET_BITS=64 will make it use a dirent64 struct
+ * on Open UNIX -> SEGV.
+ */
+#undef	_FILE_OFFSET_BITS
+#endif	/* !__linux__ */
+
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<stdlib.h>
+#include	<errno.h>
+#include	<string.h>
+
+#if defined (__UCLIBC__)
+#include <linux/types.h>
+#include <linux/dirent.h>
+#define	getdents(a, b, c)	__getdents64(a, b, c)
+#define	dirent	dirent64
+extern int	getdents(int, struct dirent *, size_t);
+#elif defined	(__GLIBC__) || defined (__FreeBSD__) || defined (_AIX) || \
+	defined (__NetBSD__) || defined (__OpenBSD__) || \
+	defined (__DragonFly__) || defined (__APPLE__)
+#include	<dirent.h>
+#define	getdents(a, b, c)	getdirentries((a), (char *)(b), (c), &(db->g_offs))
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \
+	defined (__DragonFly__) || defined (__APPLE__)
+#undef	d_ino
+#endif	/* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__
+	 || __APPLE__ */
+#elif defined	(__dietlibc__)
+#include	<dirent.h>
+#include	<unistd.h>
+#else		/* !__GLIBC__, !__dietlibc__ */
+#ifdef	__hpux
+#define		_KERNEL
+#endif	/* __hpux */
+#include	<sys/dirent.h>
+#ifdef		__hpux
+#ifndef	_INO64_T
+typedef	unsigned long long	uint64_t;
+typedef	uint64_t	ino64_t;
+#endif	/* !_INO64_T */
+#ifdef	__LP64__
+#define	dirent		__dirent64
+#else	/* !__LP64__ */
+#define	dirent		__dirent32
+#endif	/* !__LP64__ */
+#define	d_reclen	__d_reclen
+#define	d_name		__d_name
+#define	d_ino		__d_ino
+#endif		/* __hpux */
+#endif		/* !__GLIBC__, !__dietlibc__ */
+
+#include	"getdir.h"
+
+#define	DIBSIZE	5120
+
+struct	getdb {
+#if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
+		&& !defined (__DragonFly__) && !defined (__APPLE__)
+	off_t		g_offs;
+#else	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+	long		g_offs;
+#endif	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+	struct dirent	*g_dirp;
+	const char	*g_path;
+	struct direc	g_dic;
+	union {
+		char		g_dirbuf[DIBSIZE+1];
+		struct dirent	g_dummy[1];
+	} g_u;
+	int		g_num;
+	int		g_fd;
+};
+
+struct getdb *
+getdb_alloc(const char *path, int fd)
+{
+	struct getdb	*db;
+
+	if ((db = malloc(sizeof *db)) == NULL)
+		return NULL;
+	db->g_dirp = NULL;
+	db->g_offs = 0;
+	db->g_fd = fd;
+	db->g_path = path;
+	return db;
+}
+
+void
+getdb_free(struct getdb *db)
+{
+	free(db);
+}
+
+struct direc *
+getdir(struct getdb *db, int *err)
+{
+	int	reclen;
+
+	*err = 0;
+	while (db->g_dirp == NULL)
+	{
+		/*LINTED*/
+		db->g_num = getdents(db->g_fd,
+				(struct dirent *)db->g_u.g_dirbuf,
+				DIBSIZE);
+		if (db->g_num <= 0) {
+			if (db->g_num < 0)
+				*err = errno;
+			db->g_offs = 0;
+			return NULL;
+		}
+		/*LINTED*/
+		db->g_dirp = (struct dirent *)db->g_u.g_dirbuf;
+		while (db->g_dirp &&
+#if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
+		&& !defined (__DragonFly__) && !defined (__APPLE__)
+				db->g_dirp->d_ino == 0
+#else	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+				(db->g_dirp->d_fileno == 0
+#ifdef DT_WHT
+				  || db->g_dirp->d_type == DT_WHT
+#endif
+				  )
+#endif	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+		      )
+		{
+		next:
+#ifndef	__DragonFly__
+			reclen = db->g_dirp->d_reclen;
+#else
+			reclen = _DIRENT_DIRSIZ(db->g_dirp);
+#endif
+			if ((db->g_num -= reclen) == 0 || reclen == 0)
+				db->g_dirp = NULL;
+			else
+				db->g_dirp =
+					/*LINTED*/
+					(struct dirent *)((char *)db->g_dirp
+						+ reclen);
+		}
+	}
+#if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
+		&& !defined (__DragonFly__) && !defined (__APPLE__)
+	if (db->g_dirp->d_ino == 0)
+		goto next;
+	db->g_dic.d_ino = db->g_dirp->d_ino;
+#else	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+	if (db->g_dirp->d_fileno == 0
+#ifdef DT_WHT
+	    || db->g_dirp->d_type == DT_WHT
+#endif
+	    )
+	{
+		goto next;
+	}
+	db->g_dic.d_ino = db->g_dirp->d_fileno;
+#endif	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+	db->g_dic.d_name = db->g_dirp->d_name;
+#ifndef	__DragonFly__
+		reclen = db->g_dirp->d_reclen;
+#else
+		reclen = _DIRENT_DIRSIZ(db->g_dirp);
+#endif
+	if ((db->g_num -= reclen) == 0 || reclen == 0)
+		db->g_dirp = NULL;
+	else
+		/*LINTED*/
+		db->g_dirp = (struct dirent *)((char *)db->g_dirp + reclen);
+	return &(db->g_dic);
+}

+ 33 - 0
tools/cpio/src/getdir.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)getdir.h	1.4 (gritter) 10/19/03	*/
+
+#include	<sys/types.h>
+
+struct	direc {
+	unsigned long long	d_ino;
+	char	*d_name;
+};
+
+extern struct getdb	*getdb_alloc(const char *, int);
+extern void		getdb_free(struct getdb *);
+extern struct direc	*getdir(struct getdb *, int *);

+ 141 - 0
tools/cpio/src/getopt.c

@@ -0,0 +1,141 @@
+/*
+ * getopt() - command option parsing
+ *
+ * Gunnar Ritter, Freiburg i. Br., Germany, March 2002.
+ */
+
+/*	Sccsid @(#)getopt.c	1.6 (gritter) 12/16/07	*/
+
+#include	<sys/types.h>
+#include	<alloca.h>
+#include	<string.h>
+#include	"msgselect.h"
+
+/*
+ * One should not think that re-implementing this is necessary, but
+ *
+ * - Some libcs print weird messages.
+ *
+ * - GNU libc getopt() is totally brain-damaged, as it requires special
+ *   care _not_ to reorder parameters and can't be told to work correctly
+ *   with ':' as first optstring character at all.
+ */
+
+char	*optarg = 0;
+int	optind = 1;
+int	opterr = 1;
+int	optopt = 0;
+extern char	*pfmt_label__;
+
+static void
+error(const char *s, int c)
+{
+	/*
+	 * Avoid including <unistd.h>, in case its getopt() declaration
+	 * conflicts.
+	 */
+	extern ssize_t	write(int, const void *, size_t);
+	const char	*msg = 0;
+	char	*buf, *bp;
+
+	if (pfmt_label__)
+		s = pfmt_label__;
+	switch (c) {
+	case '?':
+		msg = ": " msgselect("I","i") "llegal option -- ";
+		break;
+	case ':':
+		msg = ": " msgselect("O","o") "ption requires an argument -- ";
+		break;
+	}
+	bp = buf = alloca(strlen(s) + strlen(msg) + 2);
+	while (*s)
+		*bp++ = *s++;
+	while (*msg)
+		*bp++ = *msg++;
+	*bp++ = optopt;
+	*bp++ = '\n';
+	write(2, buf, bp - buf);
+}
+
+int
+getopt(int argc, char *const argv[], const char *optstring)
+{
+	int	colon;
+	static const char	*lastp;
+	const char	*curp;
+
+	if (optstring[0] == ':') {
+		colon = 1;
+		optstring++;
+	} else
+		colon = 0;
+	if (lastp) {
+		curp = lastp;
+		lastp = 0;
+	} else {
+		if (optind >= argc || argv[optind] == 0 ||
+				argv[optind][0] != '-' ||
+				argv[optind][1] == '\0')
+			return -1;
+		if (argv[optind][1] == '-' && argv[optind][2] == '\0') {
+			optind++;
+			return -1;
+		}
+		curp = &argv[optind][1];
+	}
+	optopt = curp[0] & 0377;
+	while (optstring[0]) {
+		if (optstring[0] == ':') {
+			optstring++;
+			continue;
+		}
+		if ((optstring[0] & 0377) == optopt) {
+			if (optstring[1] == ':') {
+				if (curp[1] != '\0') {
+					optarg = (char *)&curp[1];
+					optind++;
+				} else {
+					if ((optind += 2) > argc) {
+						if (!colon && opterr)
+							error(argv[0], ':');
+						return colon ? ':' : '?';
+					}
+					optarg = argv[optind - 1];
+				}
+			} else {
+				if (curp[1] != '\0')
+					lastp = &curp[1];
+				else
+					optind++;
+				optarg = 0;
+			}
+			return optopt;
+		}
+		optstring++;
+	}
+	if (!colon && opterr)
+		error(argv[0], '?');
+	if (curp[1] != '\0')
+		lastp = &curp[1];
+	else
+		optind++;
+	optarg = 0;
+	return '?';
+}
+
+#ifdef __APPLE__
+/*
+ * Starting with Mac OS 10.5 Leopard, <unistd.h> turns getopt()
+ * into getopt$UNIX2003() by default. Consequently, this function
+ * is called instead of the one defined above. However, optind is
+ * still taken from this file, so in effect, options are not
+ * properly handled. Defining an own getopt$UNIX2003() function
+ * works around this issue.
+ */
+int
+getopt$UNIX2003(int argc, char *const argv[], const char *optstring)
+{
+	return getopt(argc, argv, optstring);
+}
+#endif	/* __APPLE__ */

+ 136 - 0
tools/cpio/src/gmatch.c

@@ -0,0 +1,136 @@
+/*
+ * Derived from /usr/src/cmd/sh/expand.c, Unix 7th Edition:
+ *
+ * Copyright(C) Caldera International Inc. 2001-2002. 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 and documentation 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.
+ *   All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed or owned by Caldera
+ *      International, Inc.
+ *   Neither the name of Caldera International, Inc. nor the names of
+ *    other contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
+ */
+
+#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
+#define	USED	__attribute__ ((used))
+#elif defined __GNUC__
+#define	USED	__attribute__ ((unused))
+#else
+#define	USED
+#endif
+static const char sccsid[] USED = "@(#)gmatch.sl	1.5 (gritter) 5/29/05";
+
+#include	<stdlib.h>
+#include	<wchar.h>
+#include	<limits.h>
+
+#include	"mbtowi.h"
+
+#define	fetch(wc, s, n)	((mb_cur_max > 1 && *(s) & 0200 ? \
+		((n) = mbtowi(&(wc), (s), mb_cur_max), \
+		 (n) = ((n) > 0 ? (n) : (n) < 0 ? (wc = WEOF, 1) : 1)) :\
+	((wc) = *(s) & 0377, (n) = 1)), (s) += (n), (wc))
+
+int
+gmatch(const char *s, const char *p)
+{
+	const char	*bs = s;
+	int	mb_cur_max = MB_CUR_MAX;
+	wint_t	c, scc;
+	int	n;
+
+	if (fetch(scc, s, n) == WEOF)
+		return (0);
+	switch (fetch(c, p, n)) {
+
+	case '[':	{
+		int	ok = 0, excl;
+		unsigned long	lc = ULONG_MAX;
+		const char	*bp;
+
+		if (*p == '!') {
+			p++;
+			excl = 1;
+		} else
+			excl = 0;
+		fetch(c, p, n);
+		bp = p;
+		while (c != '\0') {
+			if (c == ']' && p > bp)
+				return (ok ^ excl ? gmatch(s, p) : 0);
+			else if (c == '-' && p > bp && *p != ']') {
+				if (*p == '\\')
+					p++;
+				if (fetch(c, p, n) == '\0')
+					break;
+				if (lc <= scc && scc <= c)
+					ok = 1;
+			} else {
+				if (c == '\\') {
+					if (fetch(c, p, n) == '\0')
+						break;
+				}
+				if (scc == (lc = c))
+					ok = 1;
+			}
+			fetch(c, p, n);
+		}
+		return (0);
+	}
+
+	case '\\':
+		fetch(c, p, n);
+		if (c == '\0')
+			return (0);
+		/*FALLTHRU*/
+
+	default:
+		if (c != scc)
+			return (0);
+		/*FALLTHRU*/
+
+	case '?':
+		return (scc ? gmatch(s, p) : 0);
+
+	case '*':
+		if (*p == '\0')
+			return (1);
+		s = bs;
+		while (*s) {
+			if (gmatch(s, p))
+				return (1);
+			fetch(scc, s, n);
+		}
+		return (0);
+
+	case '\0':
+		return (scc == '\0');
+
+	case WEOF:
+		return (0);
+
+	}
+}

+ 61 - 0
tools/cpio/src/ib_alloc.c

@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_alloc.c	1.5 (gritter) 3/12/05	*/
+
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<fcntl.h>
+#include	<unistd.h>
+#include	<string.h>
+#include	<errno.h>
+#include	<stdlib.h>
+#include	<malloc.h>
+
+#include	"memalign.h"
+#include	"iblok.h"
+
+struct iblok *
+ib_alloc(int fd, unsigned blksize)
+{
+	static long	pagesize;
+	struct iblok	*ip;
+	struct stat	st;
+
+	if (pagesize == 0)
+		if ((pagesize = sysconf(_SC_PAGESIZE)) < 0)
+			pagesize = 4096;
+	if (blksize == 0) {
+		if (fstat(fd, &st) < 0)
+			return NULL;
+		blksize = st.st_blksize > 0 ? st.st_blksize : 512;
+	}
+	if ((ip = calloc(1, sizeof *ip)) == NULL)
+		return NULL;
+	if ((ip->ib_blk = memalign(pagesize, blksize)) == NULL) {
+		free(ip);
+		return NULL;
+	}
+	ip->ib_blksize = blksize;
+	ip->ib_fd = fd;
+	ip->ib_mb_cur_max = MB_CUR_MAX;
+	return ip;
+}

+ 36 - 0
tools/cpio/src/ib_close.c

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_close.c	1.2 (gritter) 4/17/03	*/
+
+#include	<unistd.h>
+
+#include	"iblok.h"
+
+int
+ib_close(struct iblok *ip)
+{
+	int	fd;
+
+	fd = ip->ib_fd;
+	ib_free(ip);
+	return close(fd);
+}

+ 33 - 0
tools/cpio/src/ib_free.c

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_free.c	1.2 (gritter) 4/17/03	*/
+
+#include	<stdlib.h>
+
+#include	"iblok.h"
+
+void
+ib_free(struct iblok *ip)
+{
+	free(ip->ib_blk);
+	free(ip);
+}

+ 78 - 0
tools/cpio/src/ib_getlin.c

@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_getlin.c	1.2 (gritter) 4/17/03	*/
+
+#include	<string.h>
+#include	<stdlib.h>
+#include	"iblok.h"
+
+size_t
+ib_getlin(struct iblok *ip, char **line, size_t *alcd,
+		void *(*reallc)(void *, size_t))
+{
+	char *nl;
+	size_t sz, llen = 0, nllen;
+
+	for (;;) {
+		if (ip->ib_cur >= ip->ib_end) {
+			if (ip->ib_incompl) {
+				ip->ib_incompl = 0;
+				return 0;
+			}
+			if (ib_read(ip) == EOF) {
+				if (llen) {
+					ip->ib_incompl++;
+					(*line)[llen] = '\0';
+					return llen;
+				} else
+					return 0;
+			}
+			/*
+			 * ib_read() advances ib_cur since *ib_cur++ gives
+			 * better performance than *++ib_cur for ib_get().
+			 * Go back again.
+			 */
+			ip->ib_cur--;
+		}
+		sz = ip->ib_end - ip->ib_cur;
+		if ((nl = memchr(ip->ib_cur, '\n', sz)) != NULL) {
+			sz = nl - ip->ib_cur + 1;
+			if ((nllen = llen + sz + 1) > *alcd) {
+				*line = reallc(*line, nllen);
+				*alcd = nllen;
+			}
+			memcpy(&(*line)[llen], ip->ib_cur, sz);
+			(*line)[llen + sz] = '\0';
+			ip->ib_cur = nl + 1;
+			return llen + sz;
+		}
+		if ((nllen = llen + sz + 1) > *alcd) {
+			*line = reallc(*line, nllen);
+			*alcd = nllen;
+		}
+		memcpy(&(*line)[llen], ip->ib_cur, sz);
+		llen += sz;
+		ip->ib_cur = ip->ib_end;
+	}
+	/*NOTREACHED*/
+	return 0;
+}

+ 81 - 0
tools/cpio/src/ib_getw.c

@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_getw.c	1.5 (gritter) 7/16/04	*/
+
+#include	<stdlib.h>
+#include	<string.h>
+#include	"iblok.h"
+#include	"mbtowi.h"
+
+char *
+ib_getw(struct iblok *ip, wint_t *wc, int *len)
+{
+	size_t	rest;
+	int	c, i, n;
+
+	i = 0;
+	rest = ip->ib_mend - ip->ib_mcur;
+	if (rest && ip->ib_mcur > ip->ib_mbuf) {
+		do
+			ip->ib_mbuf[i] = ip->ib_mcur[i];
+		while (i++, --rest);
+	} else if (ip->ib_incompl) {
+		ip->ib_incompl = 0;
+		*wc = WEOF;
+		ip->ib_mend = ip->ib_mcur = NULL;
+		return NULL;
+	}
+	if (i == 0) {
+		c = ib_get(ip);
+		if (c == EOF) {
+			*wc = WEOF;
+			ip->ib_mend = ip->ib_mcur = NULL;
+			return NULL;
+		}
+		ip->ib_mbuf[i++] = (char)c;
+	}
+	if (ip->ib_mbuf[0] & 0200) {
+		while (ip->ib_mbuf[i-1] != '\n' && i < ip->ib_mb_cur_max &&
+				ip->ib_incompl == 0) {
+			c = ib_get(ip);
+			if (c != EOF)
+				ip->ib_mbuf[i++] = (char)c;
+			else
+				ip->ib_incompl = 1;
+		}
+		n = mbtowi(wc, ip->ib_mbuf, i);
+		if (n < 0) {
+			*len = 1;
+			*wc = WEOF;
+		} else if (n == 0) {
+			*len = 1;
+			*wc = '\0';
+		} else
+			*len = n;
+	} else {
+		*wc = ip->ib_mbuf[0];
+		*len = n = 1;
+	}
+	ip->ib_mcur = &ip->ib_mbuf[*len];
+	ip->ib_mend = &ip->ib_mcur[i - *len];
+	return ip->ib_mbuf;
+}

+ 48 - 0
tools/cpio/src/ib_open.c

@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_open.c	1.2 (gritter) 4/17/03	*/
+
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<fcntl.h>
+#include	<unistd.h>
+#include	<string.h>
+#include	<errno.h>
+#include	<stdlib.h>
+
+#include	"iblok.h"
+
+struct iblok *
+ib_open(const char *name, unsigned blksize)
+{
+	struct iblok	*ip;
+	int	fd, err;
+
+	if ((fd = open(name, O_RDONLY)) < 0)
+		return NULL;
+	if ((ip = ib_alloc(fd, blksize)) == NULL) {
+		err = errno;
+		close(fd);
+		errno = err;
+	}
+	return ip;
+}

+ 87 - 0
tools/cpio/src/ib_popen.c

@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_popen.c	1.2 (gritter) 4/17/03	*/
+
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<sys/wait.h>
+#include	<fcntl.h>
+#include	<unistd.h>
+#include	<string.h>
+#include	<errno.h>
+#include	<stdlib.h>
+#include	<signal.h>
+
+#include	"iblok.h"
+
+struct iblok *
+ib_popen(const char *cmd, unsigned blksize)
+{
+	struct iblok	*ip;
+	int	fd[2], err;
+	pid_t	pid;
+	char	*shell;
+
+	if (pipe(fd) < 0)
+		return NULL;
+	switch (pid = fork()) {
+	case -1:
+		return NULL;
+	case 0:
+		close(fd[0]);
+		dup2(fd[1], 1);
+		close(fd[1]);
+		if ((shell = getenv("SHELL")) == NULL)
+			shell = "/bin/sh";
+		execl(shell, shell, "-c", cmd, NULL);
+		_exit(0177);
+		/*NOTREACHED*/
+	}
+	close(fd[1]);
+	if ((ip = ib_alloc(fd[0], blksize)) == NULL) {
+		err = errno;
+		close(fd[0]);
+		errno = err;
+	}
+	ip->ib_pid = pid;
+	return ip;
+}
+
+int
+ib_pclose(struct iblok *ip)
+{
+	struct sigaction	oldhup, oldint, oldquit, act;
+	int	status;
+
+	close(ip->ib_fd);
+	act.sa_handler = SIG_IGN;
+	sigemptyset(&act.sa_mask);
+	act.sa_flags = 0;
+	sigaction(SIGHUP, &act, &oldhup);
+	sigaction(SIGINT, &act, &oldint);
+	sigaction(SIGQUIT, &act, &oldquit);
+	while (waitpid(ip->ib_pid, &status, 0) < 0 && errno == EINTR);
+	sigaction(SIGHUP, &oldhup, NULL);
+	sigaction(SIGINT, &oldint, NULL);
+	sigaction(SIGQUIT, &oldquit, NULL);
+	return status;
+}

+ 51 - 0
tools/cpio/src/ib_read.c

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_read.c	1.2 (gritter) 4/17/03	*/
+
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<fcntl.h>
+#include	<unistd.h>
+#include	<string.h>
+#include	<errno.h>
+#include	<stdlib.h>
+
+#include	"iblok.h"
+
+int
+ib_read(struct iblok *ip)
+{
+	ssize_t	sz;
+
+	do {
+		if ((sz = read(ip->ib_fd, ip->ib_blk, ip->ib_blksize)) > 0) {
+			ip->ib_endoff += sz;
+			ip->ib_cur = ip->ib_blk;
+			ip->ib_end = &ip->ib_blk[sz];
+			return *ip->ib_cur++ & 0377;
+		}
+	} while (sz < 0 && errno == EINTR);
+	if (sz < 0)
+		ip->ib_errno = errno;
+	ip->ib_cur = ip->ib_end = NULL;
+	return EOF;
+}

+ 53 - 0
tools/cpio/src/ib_seek.c

@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)ib_seek.c	1.4 (gritter) 5/8/03	*/
+
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<fcntl.h>
+#include	<unistd.h>
+#include	<string.h>
+#include	<errno.h>
+#include	<stdlib.h>
+
+#include	"iblok.h"
+
+off_t
+ib_seek(struct iblok *ip, off_t off, int whence)
+{
+	if (whence == SEEK_CUR) {
+		off = ip->ib_endoff - (ip->ib_end - ip->ib_cur);
+		whence = SEEK_SET;
+	}
+	if (ip->ib_seekable && whence == SEEK_SET && ip->ib_cur && ip->ib_end &&
+			off < ip->ib_endoff &&
+			off >= ip->ib_endoff - (ip->ib_end - ip->ib_blk)) {
+		ip->ib_cur = ip->ib_end - (ip->ib_endoff - off);
+		return off;
+	}
+	if ((off = lseek(ip->ib_fd, off, whence)) == (off_t)-1)
+		return -1;
+	ip->ib_cur = ip->ib_end = NULL;
+	ip->ib_endoff = off;
+	ip->ib_seekable = 1;
+	return off;
+}

+ 135 - 0
tools/cpio/src/iblok.h

@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)iblok.h	1.5 (gritter) 7/16/04	*/
+
+/*
+ * Functions to read a file sequentially.
+ */
+
+#include	<sys/types.h>		/* for off_t, pid_t */
+#include	<stdio.h>		/* for EOF */
+#include	<wchar.h>		/* for wchar_t */
+#include	<limits.h>		/* for MB_LEN_MAX */
+
+struct	iblok {
+	long long	ib_endoff;	/* offset of endc from start of file */
+	char	ib_mbuf[MB_LEN_MAX+1];	/* multibyte overflow buffer */
+	char	*ib_mcur;		/* next byte to read in ib_mbuf */
+	char	*ib_mend;		/* one beyond last byte in ib_mbuf */
+	char	*ib_blk;		/* buffered data */
+	char	*ib_cur;		/* next character in ib_blk */
+	char	*ib_end;		/* one beyond last byte in ib_blk */
+	int	ib_fd;			/* input file descriptor */
+	int	ib_errno;		/* errno on error, or 0 */
+	int	ib_incompl;		/* had an incomplete last line */
+	int	ib_mb_cur_max;		/* MB_CUR_MAX at time of ib_alloc() */
+	int	ib_seekable;		/* had a successful lseek() */
+	pid_t	ib_pid;			/* child from ib_popen() */
+	unsigned	ib_blksize;	/* buffer size */
+};
+
+/*
+ * Allocate an input buffer with file descriptor fd. blksize may be
+ * either the size of a buffer to allocate in ib_blk, or 0 if the
+ * size is determined automatically. On error, NULL is returned and
+ * errno indicates the offending error.
+ */
+extern struct iblok	*ib_alloc(int fd, unsigned blksize);
+
+/*
+ * Deallocate the passed input buffer. The file descriptor is not
+ * closed.
+ */
+extern void		ib_free(struct iblok *ip);
+
+/*
+ * Open file name and do ib_alloc() on the descriptor.
+ */
+extern struct iblok	*ib_open(const char *name, unsigned blksize);
+
+/*
+ * Close the file descriptor in ip and do ib_free(). Return value is
+ * the result of close().
+ */
+extern int		ib_close(struct iblok *ip);
+
+/*
+ * A workalike of popen(cmd, "r") using iblok facilities.
+ */
+extern struct iblok	*ib_popen(const char *cmd, unsigned blksize);
+
+/*
+ * Close an iblok opened with ib_popen().
+ */
+extern int		ib_pclose(struct iblok *ip);
+
+/*
+ * Read new input buffer. Returns the next character (or EOF) and advances
+ * ib_cur by one above the bottom of the buffer.
+ */
+extern int		ib_read(struct iblok *ip);
+
+/*
+ * Get next character. Return EOF at end-of-file or read error.
+ */
+#define	ib_get(ip)	((ip)->ib_cur < (ip)->ib_end ? *(ip)->ib_cur++ & 0377 :\
+				ib_read(ip))
+
+/*
+ * Unget a character. Note that this implementation alters the read buffer.
+ * Caution: Calling this macro more than once might underflow ib_blk.
+ */
+#define ib_unget(c, ip)	(*(--(ip)->ib_cur) = (char)(c))
+
+/*
+ * Get file offset of last read character.
+ */
+#define	ib_offs(ip)	((ip)->ib_endoff - ((ip)->ib_end - (ip)->ib_cur - 1))
+
+/*
+ * Read a wide character using ib_get() facilities. *wc is used to store
+ * the wide character, or WEOF if an invalid byte sequence was found.
+ * The number of bytes consumed is stored in *len. Return value is the
+ * corresponding byte sequence, or NULL at end-of-file in input.
+ *
+ * Note that it is not possible to mix calls to ib_getw() with calls to
+ * ib_get(), ib_unget() or ib_seek() unless the last character read by
+ * ib_getw() was L'\n'.
+ */
+extern char	*ib_getw(struct iblok *ip, wint_t *wc, int *len);
+
+/*
+ * Get a line from ip, returning the line length. Further arguments are either
+ * the pointer to a malloc()ed buffer and a pointer to its size, or (NULL, 0)
+ * if ib_getlin() shall allocate the buffer itselves. ib_getlin() will use
+ * the realloc-style function reallc() to increase the buffer if necessary;
+ * this function is expected never to fail (i. e., it must longjmp() or abort
+ * if it cannot allocate a buffer of the demanded size).
+ * On end-of-file or error, 0 is returned.
+ */
+extern size_t	ib_getlin(struct iblok *ip, char **line, size_t *alcd,
+			void *(*reallc)(void *, size_t));
+
+/*
+ * Like lseek().
+ */
+extern off_t	ib_seek(struct iblok *ip, off_t off, int whence);

+ 991 - 0
tools/cpio/src/inflate.c

@@ -0,0 +1,991 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, May 2003.
+ *
+ * Derived from Info-ZIP 5.50.
+ *
+ * Sccsid @(#)inflate.c	1.6 (gritter) 10/13/04
+ */
+/*
+This is version 2002-Feb-16 of the Info-ZIP copyright and license.
+The definitive version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely.
+
+
+Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+For the purposes of this copyright and license, "Info-ZIP" is defined as
+the following set of individuals:
+
+   Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+   Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase,
+   Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David Kirschbaum,
+   Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve P. Miller,
+   Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, Kai Uwe Rommel,
+   Steve Salisbury, Dave Smith, Christian Spieler, Antoine Verheijen,
+   Paul von Behren, Rich Wales, Mike White
+
+This software is provided "as is," without warranty of any kind, express
+or implied.  In no event shall Info-ZIP or its contributors be held liable
+for any direct, indirect, incidental, special or consequential damages
+arising out of the use of or inability to use this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+    1. Redistributions of source code must retain the above copyright notice,
+       definition, disclaimer, and this list of conditions.
+
+    2. Redistributions in binary form (compiled executables) must reproduce
+       the above copyright notice, definition, disclaimer, and this list of
+       conditions in documentation and/or other materials provided with the
+       distribution.  The sole exception to this condition is redistribution
+       of a standard UnZipSFX binary as part of a self-extracting archive;
+       that is permitted without inclusion of this license, as long as the
+       normal UnZipSFX banner has not been removed from the binary or disabled.
+
+    3. Altered versions--including, but not limited to, ports to new operating
+       systems, existing ports with new graphical interfaces, and dynamic,
+       shared, or static library versions--must be plainly marked as such
+       and must not be misrepresented as being the original source.  Such
+       altered versions also must not be misrepresented as being Info-ZIP
+       releases--including, but not limited to, labeling of the altered
+       versions with the names "Info-ZIP" (or any variation thereof, including,
+       but not limited to, different capitalizations), "Pocket UnZip," "WiZ"
+       or "MacZip" without the explicit permission of Info-ZIP.  Such altered
+       versions are further prohibited from misrepresentative use of the
+       Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s).
+
+    4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
+       "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its
+       own source and binary releases.
+*/
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in unzip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* inflate.c -- by Mark Adler
+   version c17a, 04 Feb 2001 */
+
+
+/* Copyright history:
+   - Starting with UnZip 5.41 of 16-April-2000, this source file
+     is covered by the Info-Zip LICENSE cited above.
+   - Prior versions of this source file, found in UnZip source packages
+     up to UnZip 5.40, were put in the public domain.
+     The original copyright note by Mark Adler was:
+         "You can do whatever you like with this source file,
+         though I would prefer that if you modify it and
+         redistribute it that you include comments to that effect
+         with your name and the date.  Thank you."
+
+   History:
+   vers    date          who           what
+   ----  ---------  --------------  ------------------------------------
+    a    ~~ Feb 92  M. Adler        used full (large, one-step) lookup table
+    b1   21 Mar 92  M. Adler        first version with partial lookup tables
+    b2   21 Mar 92  M. Adler        fixed bug in fixed-code blocks
+    b3   22 Mar 92  M. Adler        sped up match copies, cleaned up some
+    b4   25 Mar 92  M. Adler        added prototypes; removed window[] (now
+                                    is the responsibility of unzip.h--also
+                                    changed name to slide[]), so needs diffs
+                                    for unzip.c and unzip.h (this allows
+                                    compiling in the small model on MSDOS);
+                                    fixed cast of q in huft_build();
+    b5   26 Mar 92  M. Adler        got rid of unintended macro recursion.
+    b6   27 Mar 92  M. Adler        got rid of nextbyte() routine.  fixed
+                                    bug in inflate_fixed().
+    c1   30 Mar 92  M. Adler        removed lbits, dbits environment variables.
+                                    changed BMAX to 16 for explode.  Removed
+                                    OUTB usage, and replaced it with flush()--
+                                    this was a 20% speed improvement!  Added
+                                    an explode.c (to replace unimplod.c) that
+                                    uses the huft routines here.  Removed
+                                    register union.
+    c2    4 Apr 92  M. Adler        fixed bug for file sizes a multiple of 32k.
+    c3   10 Apr 92  M. Adler        reduced memory of code tables made by
+                                    huft_build significantly (factor of two to
+                                    three).
+    c4   15 Apr 92  M. Adler        added NOMEMCPY do kill use of memcpy().
+                                    worked around a Turbo C optimization bug.
+    c5   21 Apr 92  M. Adler        added the WSIZE #define to allow reducing
+                                    the 32K window size for specialized
+                                    applications.
+    c6   31 May 92  M. Adler        added some typecasts to eliminate warnings
+    c7   27 Jun 92  G. Roelofs      added some more typecasts (444:  MSC bug).
+    c8    5 Oct 92  J-l. Gailly     added ifdef'd code to deal with PKZIP bug.
+    c9    9 Oct 92  M. Adler        removed a memory error message (~line 416).
+    c10  17 Oct 92  G. Roelofs      changed ULONG/UWORD/byte to ulg/ush/uch,
+                                    removed old inflate, renamed inflate_entry
+                                    to inflate, added Mark's fix to a comment.
+   c10.5 14 Dec 92  M. Adler        fix up error messages for incomplete trees.
+    c11   2 Jan 93  M. Adler        fixed bug in detection of incomplete
+                                    tables, and removed assumption that EOB is
+                                    the longest code (bad assumption).
+    c12   3 Jan 93  M. Adler        make tables for fixed blocks only once.
+    c13   5 Jan 93  M. Adler        allow all zero length codes (pkzip 2.04c
+                                    outputs one zero length code for an empty
+                                    distance tree).
+    c14  12 Mar 93  M. Adler        made inflate.c standalone with the
+                                    introduction of inflate.h.
+   c14b  16 Jul 93  G. Roelofs      added (unsigned) typecast to w at 470.
+   c14c  19 Jul 93  J. Bush         changed v[N_MAX], l[288], ll[28x+3x] arrays
+                                    to static for Amiga.
+   c14d  13 Aug 93  J-l. Gailly     de-complicatified Mark's c[*p++]++ thing.
+   c14e   8 Oct 93  G. Roelofs      changed memset() to memzero().
+   c14f  22 Oct 93  G. Roelofs      renamed quietflg to qflag; made Trace()
+                                    conditional; added inflate_free().
+   c14g  28 Oct 93  G. Roelofs      changed l/(lx+1) macro to pointer (Cray bug)
+   c14h   7 Dec 93  C. Ghisler      huft_build() optimizations.
+   c14i   9 Jan 94  A. Verheijen    set fixed_t{d,l} to NULL after freeing;
+                    G. Roelofs      check NEXTBYTE macro for EOF.
+   c14j  23 Jan 94  G. Roelofs      removed Ghisler "optimizations"; ifdef'd
+                                    EOF check.
+   c14k  27 Feb 94  G. Roelofs      added some typecasts to avoid warnings.
+   c14l   9 Apr 94  G. Roelofs      fixed split comments on preprocessor lines
+                                    to avoid bug in Encore compiler.
+   c14m   7 Jul 94  P. Kienitz      modified to allow assembler version of
+                                    inflate_codes() (define ASM_INFLATECODES)
+   c14n  22 Jul 94  G. Roelofs      changed fprintf to macro for DLL versions
+   c14o  23 Aug 94  C. Spieler      added a newline to a debug statement;
+                    G. Roelofs      added another typecast to avoid MSC warning
+   c14p   4 Oct 94  G. Roelofs      added (voidp *) cast to free() argument
+   c14q  30 Oct 94  G. Roelofs      changed fprintf macro to MESSAGE()
+   c14r   1 Nov 94  G. Roelofs      fixed possible redefinition of CHECK_EOF
+   c14s   7 May 95  S. Maxwell      OS/2 DLL globals stuff incorporated;
+                    P. Kienitz      "fixed" ASM_INFLATECODES macro/prototype
+   c14t  18 Aug 95  G. Roelofs      added UZinflate() to use zlib functions;
+                                    changed voidp to zvoid; moved huft_build()
+                                    and huft_free() to end of file
+   c14u   1 Oct 95  G. Roelofs      moved G into definition of MESSAGE macro
+   c14v   8 Nov 95  P. Kienitz      changed ASM_INFLATECODES to use a regular
+                                    call with __G__ instead of a macro
+    c15   3 Aug 96  M. Adler        fixed bomb-bug on random input data (Adobe)
+   c15b  24 Aug 96  M. Adler        more fixes for random input data
+   c15c  28 Mar 97  G. Roelofs      changed USE_ZLIB fatal exit code from
+                                    PK_MEM2 to PK_MEM3
+    c16  20 Apr 97  J. Altman       added memzero(v[]) in huft_build()
+   c16b  29 Mar 98  C. Spieler      modified DLL code for slide redirection
+   c16c  04 Apr 99  C. Spieler      fixed memory leaks when processing gets
+                                    stopped because of input data errors
+   c16d  05 Jul 99  C. Spieler      take care of FLUSH() return values and
+                                    stop processing in case of errors
+    c17  31 Dec 00  C. Spieler      added preliminary support for Deflate64
+   c17a  04 Feb 01  C. Spieler      complete integration of Deflate64 support
+   c17b  16 Feb 02  C. Spieler      changed type of "extra bits" arrays and
+                                    corresponding huft_buid() parameter e from
+                                    ush into uch, to save space
+ */
+
+
+/*
+   Inflate deflated (PKZIP's method 8 compressed) data.  The compression
+   method searches for as much of the current string of bytes (up to a
+   length of 258) in the previous 32K bytes.  If it doesn't find any
+   matches (of at least length 3), it codes the next byte.  Otherwise, it
+   codes the length of the matched string and its distance backwards from
+   the current position.  There is a single Huffman code that codes both
+   single bytes (called "literals") and match lengths.  A second Huffman
+   code codes the distance information, which follows a length code.  Each
+   length or distance code actually represents a base value and a number
+   of "extra" (sometimes zero) bits to get to add to the base value.  At
+   the end of each deflated block is a special end-of-block (EOB) literal/
+   length code.  The decoding process is basically: get a literal/length
+   code; if EOB then done; if a literal, emit the decoded byte; if a
+   length then get the distance and emit the referred-to bytes from the
+   sliding window of previously emitted data.
+
+   There are (currently) three kinds of inflate blocks: stored, fixed, and
+   dynamic.  The compressor outputs a chunk of data at a time and decides
+   which method to use on a chunk-by-chunk basis.  A chunk might typically
+   be 32K to 64K, uncompressed.  If the chunk is uncompressible, then the
+   "stored" method is used.  In this case, the bytes are simply stored as
+   is, eight bits per byte, with none of the above coding.  The bytes are
+   preceded by a count, since there is no longer an EOB code.
+
+   If the data are compressible, then either the fixed or dynamic methods
+   are used.  In the dynamic method, the compressed data are preceded by
+   an encoding of the literal/length and distance Huffman codes that are
+   to be used to decode this block.  The representation is itself Huffman
+   coded, and so is preceded by a description of that code.  These code
+   descriptions take up a little space, and so for small blocks, there is
+   a predefined set of codes, called the fixed codes.  The fixed method is
+   used if the block ends up smaller that way (usually for quite small
+   chunks); otherwise the dynamic method is used.  In the latter case, the
+   codes are customized to the probabilities in the current block and so
+   can code it much better than the pre-determined fixed codes can.
+
+   The Huffman codes themselves are decoded using a multi-level table
+   lookup, in order to maximize the speed of decoding plus the speed of
+   building the decoding tables.  See the comments below that precede the
+   lbits and dbits tuning parameters.
+
+   GRR:  return values(?)
+           0  OK
+           1  incomplete table
+           2  bad input
+           3  not enough memory
+         the following return codes are passed through from FLUSH() errors
+           50 (PK_DISK)   "overflow of output space"
+           80 (IZ_CTRLC)  "canceled by user's request"
+ */
+
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+  14. The Deflate64 (PKZIP method 9) variant of the compression algorithm
+      differs from "classic" deflate in the following 3 aspect:
+      a) The size of the sliding history window is expanded to 64 kByte.
+      b) The previously unused distance codes #30 and #31 code distances
+         from 32769 to 49152 and 49153 to 65536.  Both codes take 14 bits
+         of extra data to determine the exact position in their 16 kByte
+         range.
+      c) The last lit/length code #285 gets a different meaning. Instead
+         of coding a fixed maximum match length of 258, it is used as a
+         "generic" match length code, capable of coding any length from
+         3 (min match length + 0) to 65538 (min match length + 65535).
+         This means that the length code #285 takes 16 bits (!) of uncoded
+         extra data, added to a fixed min length of 3.
+      Changes a) and b) would have been transparent for valid deflated
+      data, but change c) requires to switch decoder configurations between
+      Deflate and Deflate64 modes.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "cpio.h"
+#include "unzip.h"
+
+/*
+    inflate.h must supply the uch slide[WSIZE] array, the zvoid typedef
+    (void if (void *) is accepted, else char) and the NEXTBYTE,
+    FLUSH() and memzero macros.  If the window size is not 32K, it
+    should also define WSIZE.  If INFMOD is defined, it can include
+    compiled functions to support the NEXTBYTE and/or FLUSH() macros.
+    There are defaults for NEXTBYTE and FLUSH() below for use as
+    examples of what those functions need to do.  Normally, you would
+    also want FLUSH() to compute a crc on the data.  inflate.h also
+    needs to provide these typedefs:
+
+        typedef unsigned char uch;
+        typedef unsigned short ush;
+        typedef unsigned long ulg;
+
+    This module uses the external functions malloc() and free() (and
+    probably memset() or bzero() in the memzero() macro).  Their
+    prototypes are normally found in <string.h> and <stdlib.h>.
+ */
+
+/* marker for "unused" huft code, and corresponding check macro */
+#define INVALID_CODE 99
+#define IS_INVALID_CODE(c)  ((c) == INVALID_CODE)
+
+static int	inflate_codes(struct globals *Gp,
+			struct huft *tl, struct huft *td,
+                      int bl, int bd);
+static int	inflate_stored(struct globals *Gp);
+static int	inflate_fixed(struct globals *Gp);
+static int	inflate_dynamic(struct globals *Gp);
+static int	inflate_block(struct globals *Gp, int *e);
+
+#define	FLUSH(n)	(flush(&G, redirSlide, (n)), 0)
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+   stream to find repeated byte strings.  This is implemented here as a
+   circular buffer.  The index is updated simply by incrementing and then
+   and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area.  It is assumed
+   to be usable as if it were declared "uch slide[32768];" or as just
+   "uch *slide;" and then malloc'ed in the latter case.  The definition
+   must be in unzip.h, included above. */
+
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+/* - Order of the bit length code lengths */
+static const unsigned border[] = {
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/* - Copy lengths for literal codes 257..285 */
+static const uint16_t cplens64[] = {
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 3, 0, 0};
+        /* For Deflate64, the code 285 is defined differently. */
+static const uint16_t cplens32[] = {
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* note: see note #13 above about the 258 in this list. */
+/* - Extra bits for literal codes 257..285 */
+static const uint8_t cplext64[] = {
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16, INVALID_CODE, INVALID_CODE};
+static const uint8_t cplext32[] = {
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, INVALID_CODE, INVALID_CODE};
+
+/* - Copy offsets for distance codes 0..29 (0..31 for Deflate64) */
+static const uint16_t cpdist[] = {
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 32769, 49153};
+
+/* - Extra bits for distance codes 0..29 (0..31 for Deflate64) */
+static const uint8_t cpdext64[] = {
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13, 14, 14};
+static const uint8_t cpdext32[] = {
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13, INVALID_CODE, INVALID_CODE};
+
+#  define MAXLITLENS 288
+#  define MAXDISTS 32
+
+/* Macros for inflate() bit peeking and grabbing.
+   The usage is:
+
+        NEEDBITS(j)
+        x = b & mask_bits[j];
+        DUMPBITS(j)
+
+   where NEEDBITS makes sure that b has at least j bits in it, and
+   DUMPBITS removes the bits from b.  The macros use the variable k
+   for the number of bits in b.  Normally, b and k are register
+   variables for speed and are initialized at the begining of a
+   routine that uses these macros from a global bit buffer and count.
+
+   In order to not ask for more bits than there are in the compressed
+   stream, the Huffman tables are constructed to only ask for just
+   enough bits to make up the end-of-block code (value 256).  Then no
+   bytes need to be "returned" to the buffer at the end of the last
+   block.  See the huft_build() routine.
+ */
+
+#  define NEEDBITS(n) {while(k<(n)){int c=NEXTBYTE;\
+    if(c==EOF){retval=1;goto cleanup_and_exit;}\
+    b|=((uint32_t)c)<<k;k+=8;}}
+
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+#define	Bits	32
+#define	Nob	32
+#define	Eob	31
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   are not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+static const int lbits = 9;    /* bits in base literal/length lookup table */
+static const int dbits = 6;    /* bits in base distance lookup table */
+
+#define	G	(*Gp)
+
+static int
+inflate_codes(struct globals *Gp,
+		struct huft *tl, struct huft *td, int bl, int bd)
+/*struct huft *tl, *td;*/ /* literal/length and distance decoder tables */
+/*int bl, bd;*/           /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+   Return an error code or zero if it all goes ok. */
+{
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned d;           /* index for copy */
+  uint32_t n;           /* length for copy (deflate64: might be 64k+2) */
+  uint32_t w;           /* current window position (deflate64: up to 64k) */
+  struct huft *t;       /* pointer to table entry */
+  unsigned ml, md;      /* masks for bl and bd bits */
+  register uint32_t b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  int retval = 0;       /* error code returned: initialized to "no error" */
+
+
+  /* make local copies of globals */
+  b = G.bb;                       /* initialize bit buffer */
+  k = G.bk;
+  w = G.wp;                       /* initialize window position */
+
+
+  /* inflate the coded data */
+  ml = mask_bits[bl];           /* precompute masks for speed */
+  md = mask_bits[bd];
+  while (1)                     /* do until end of block */
+  {
+    NEEDBITS((unsigned)bl)
+    t = tl + ((unsigned)b & ml);
+    while (1) {
+      DUMPBITS(t->b)
+
+      if ((e = t->e) == 32)     /* then it's a literal */
+      {
+        redirSlide[w++] = (uint8_t)t->v.n;
+        if (w == WSIZE)
+        {
+          if ((retval = FLUSH(w)) != 0) goto cleanup_and_exit;
+          w = 0;
+        }
+        break;
+      }
+
+      if (e < 31)               /* then it's a length */
+      {
+        /* get length of block to copy */
+        NEEDBITS(e)
+        n = t->v.n + ((unsigned)b & mask_bits[e]);
+        DUMPBITS(e)
+
+        /* decode distance of block to copy */
+        NEEDBITS((unsigned)bd)
+        t = td + ((unsigned)b & md);
+        while (1) {
+          DUMPBITS(t->b)
+          if ((e = t->e) < 32)
+            break;
+          if (IS_INVALID_CODE(e))
+            return 1;
+          e &= 31;
+          NEEDBITS(e)
+          t = t->v.t + ((unsigned)b & mask_bits[e]);
+        }
+        NEEDBITS(e)
+        d = (unsigned)w - t->v.n - ((unsigned)b & mask_bits[e]);
+        DUMPBITS(e)
+
+        /* do the copy */
+        do {
+            e = (unsigned)(WSIZE -
+                           ((d &= (unsigned)(WSIZE-1)) > (unsigned)w ?
+                            (uint32_t)d : w));
+          if ((uint32_t)e > n) e = (unsigned)n;
+          n -= e;
+#ifndef NOMEMCPY
+          if ((unsigned)w - d >= e)
+          /* (this test assumes unsigned comparison) */
+          {
+            memcpy(redirSlide + (unsigned)w, redirSlide + d, e);
+            w += e;
+            d += e;
+          }
+          else                  /* do it slowly to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+            do {
+              redirSlide[w++] = redirSlide[d++];
+            } while (--e);
+          if (w == WSIZE)
+          {
+            if ((retval = FLUSH(w)) != 0) goto cleanup_and_exit;
+            w = 0;
+          }
+        } while (n);
+        break;
+      }
+
+      if (e == 31)              /* it's the EOB signal */
+      {
+        /* sorry for this goto, but we have to exit two loops at once */
+        goto cleanup_decode;
+      }
+
+      if (IS_INVALID_CODE(e))
+        return 1;
+
+      e &= 31;
+      NEEDBITS(e)
+      t = t->v.t + ((unsigned)b & mask_bits[e]);
+    }
+  }
+cleanup_decode:
+
+  /* restore the globals from the locals */
+  G.wp = (unsigned)w;             /* restore global window pointer */
+  G.bb = b;                       /* restore global bit buffer */
+  G.bk = k;
+
+
+cleanup_and_exit:
+  /* done */
+  return retval;
+}
+
+static int
+inflate_stored(struct globals *Gp)
+/* "decompress" an inflated type 0 (stored) block. */
+{
+  uint32_t w;           /* current window position (deflate64: up to 64k!) */
+  unsigned n;           /* number of bytes in block */
+  register uint32_t b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  int retval = 0;       /* error code returned: initialized to "no error" */
+
+
+  /* make local copies of globals */
+  Trace((stderr, "\nstored block"));
+  b = G.bb;                       /* initialize bit buffer */
+  k = G.bk;
+  w = G.wp;                       /* initialize window position */
+
+
+  /* go to byte boundary */
+  n = k & 7;
+  DUMPBITS(n);
+
+
+  /* get the length and its complement */
+  NEEDBITS(16)
+  n = ((unsigned)b & 0xffff);
+  DUMPBITS(16)
+  NEEDBITS(16)
+  if (n != (unsigned)((~b) & 0xffff))
+    return 1;                   /* error in compressed data */
+  DUMPBITS(16)
+
+
+  /* read and output the compressed data */
+  while (n--)
+  {
+    NEEDBITS(8)
+    redirSlide[w++] = (uint8_t)b;
+    if (w == WSIZE)
+    {
+      if ((retval = FLUSH(w)) != 0) goto cleanup_and_exit;
+      w = 0;
+    }
+    DUMPBITS(8)
+  }
+
+
+  /* restore the globals from the locals */
+  G.wp = (unsigned)w;             /* restore global window pointer */
+  G.bb = b;                       /* restore global bit buffer */
+  G.bk = k;
+
+cleanup_and_exit:
+  return retval;
+}
+
+
+static int
+inflate_fixed(struct globals *Gp)
+/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
+   either replace this with a custom decoder, or at least precompute the
+   Huffman tables. */
+{
+  /* if first time, set up tables for fixed blocks */
+  Trace((stderr, "\nliteral block"));
+  if (G.fixed_tl == NULL)
+  {
+    int i;                /* temporary variable */
+    unsigned l[288];      /* length list for huft_build */
+
+    /* literal table */
+    for (i = 0; i < 144; i++)
+      l[i] = 8;
+    for (; i < 256; i++)
+      l[i] = 9;
+    for (; i < 280; i++)
+      l[i] = 7;
+    for (; i < 288; i++)          /* make a complete, but wrong code set */
+      l[i] = 8;
+    G.fixed_bl = 7;
+    if ((i = huft_build(l, 288, 257, G.cplens, G.cplext,
+                        &G.fixed_tl, &G.fixed_bl,
+			Bits, Nob, Eob)) != 0)
+    {
+      G.fixed_tl = NULL;
+      return i;
+    }
+
+    /* distance table */
+    for (i = 0; i < MAXDISTS; i++)      /* make an incomplete code set */
+      l[i] = 5;
+    G.fixed_bd = 5;
+    if ((i = huft_build(l, MAXDISTS, 0, cpdist, G.cpdext,
+                        &G.fixed_td, &G.fixed_bd,
+			Bits, Nob, Eob)) > 1)
+    {
+      huft_free(G.fixed_tl);
+      G.fixed_td = G.fixed_tl = NULL;
+      return i;
+    }
+  }
+
+  /* decompress until an end-of-block code */
+  return inflate_codes(&G, G.fixed_tl, G.fixed_td,
+                             G.fixed_bl, G.fixed_bd);
+}
+
+
+
+static int inflate_dynamic(struct globals *Gp)
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+  int i;                /* temporary variables */
+  unsigned j;
+  unsigned l;           /* last length */
+  unsigned m;           /* mask for bit lengths table */
+  unsigned n;           /* number of lengths to get */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned nb;          /* number of bit length codes */
+  unsigned nl;          /* number of literal/length codes */
+  unsigned nd;          /* number of distance codes */
+  unsigned ll[MAXLITLENS+MAXDISTS]; /* lit./length and distance code lengths */
+  register uint32_t b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  int retval = 0;       /* error code returned: initialized to "no error" */
+
+
+  /* make local bit buffer */
+  Trace((stderr, "\ndynamic block"));
+  b = G.bb;
+  k = G.bk;
+
+
+  /* read in table lengths */
+  NEEDBITS(5)
+  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
+  DUMPBITS(5)
+  NEEDBITS(5)
+  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
+  DUMPBITS(5)
+  NEEDBITS(4)
+  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
+  DUMPBITS(4)
+  if (nl > MAXLITLENS || nd > MAXDISTS)
+    return 1;                   /* bad lengths */
+
+
+  /* read in bit-length-code lengths */
+  for (j = 0; j < nb; j++)
+  {
+    NEEDBITS(3)
+    ll[border[j]] = (unsigned)b & 7;
+    DUMPBITS(3)
+  }
+  for (; j < 19; j++)
+    ll[border[j]] = 0;
+
+
+  /* build decoding table for trees--single level, 7 bit lookup */
+  bl = 7;
+  retval = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl,
+		  Bits, Nob, Eob);
+  if (bl == 0)                  /* no bit lengths */
+    retval = 1;
+  if (retval)
+  {
+    if (retval == 1)
+      huft_free(tl);
+    return retval;              /* incomplete code set */
+  }
+
+
+  /* read in literal and distance code lengths */
+  n = nl + nd;
+  m = mask_bits[bl];
+  i = l = 0;
+  while ((unsigned)i < n)
+  {
+    NEEDBITS((unsigned)bl)
+    j = (td = tl + ((unsigned)b & m))->b;
+    DUMPBITS(j)
+    j = td->v.n;
+    if (j < 16)                 /* length of code in bits (0..15) */
+      ll[i++] = l = j;          /* save last length in l */
+    else if (j == 16)           /* repeat last length 3 to 6 times */
+    {
+      NEEDBITS(2)
+      j = 3 + ((unsigned)b & 3);
+      DUMPBITS(2)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = l;
+    }
+    else if (j == 17)           /* 3 to 10 zero length codes */
+    {
+      NEEDBITS(3)
+      j = 3 + ((unsigned)b & 7);
+      DUMPBITS(3)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+    else                        /* j == 18: 11 to 138 zero length codes */
+    {
+      NEEDBITS(7)
+      j = 11 + ((unsigned)b & 0x7f);
+      DUMPBITS(7)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+  }
+
+
+  /* free decoding table for trees */
+  huft_free(tl);
+
+
+  /* restore the global bit buffer */
+  G.bb = b;
+  G.bk = k;
+
+
+  /* build the decoding tables for literal/length and distance codes */
+  bl = lbits;
+  retval = huft_build(ll, nl, 257, G.cplens, G.cplext, &tl, &bl,
+		  Bits, Nob, Eob);
+  if (bl == 0)                  /* no literals or lengths */
+    retval = 1;
+  if (retval)
+  {
+    if (retval == 1) {
+      /*if (!uO.qflag)
+        MESSAGE((uint8_t *)"(incomplete l-tree)  ", 21L, 1);*/
+      huft_free(tl);
+    }
+    return retval;              /* incomplete code set */
+  }
+  bd = dbits;
+  retval = huft_build(ll + nl, nd, 0, cpdist, G.cpdext, &td, &bd,
+		  Bits, Nob, Eob);
+  if (retval == 1)
+    retval = 0;
+  if (bd == 0 && nl > 257)    /* lengths but no distances */
+    retval = 1;
+  if (retval)
+  {
+    if (retval == 1) {
+      /*if (!uO.qflag)
+        MESSAGE((uint8_t *)"(incomplete d-tree)  ", 21L, 1);*/
+      huft_free(td);
+    }
+    huft_free(tl);
+    return retval;
+  }
+
+  /* decompress until an end-of-block code */
+  retval = inflate_codes(&G, tl, td, bl, bd);
+
+cleanup_and_exit:
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+  return retval;
+}
+
+
+
+static int inflate_block(struct globals *Gp, int *e)
+/*int *e;*/             /* last block flag */
+/* decompress an inflated block */
+{
+  unsigned t;           /* block type */
+  register uint32_t b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  int retval = 0;       /* error code returned: initialized to "no error" */
+
+
+  /* make local bit buffer */
+  b = G.bb;
+  k = G.bk;
+
+
+  /* read in last block bit */
+  NEEDBITS(1)
+  *e = (int)b & 1;
+  DUMPBITS(1)
+
+
+  /* read in block type */
+  NEEDBITS(2)
+  t = (unsigned)b & 3;
+  DUMPBITS(2)
+
+
+  /* restore the global bit buffer */
+  G.bb = b;
+  G.bk = k;
+
+
+  /* inflate that block type */
+  if (t == 2)
+    return inflate_dynamic(&G);
+  if (t == 0)
+    return inflate_stored(&G);
+  if (t == 1)
+    return inflate_fixed(&G);
+
+
+  /* bad block type */
+  retval = 2;
+
+cleanup_and_exit:
+  return retval;
+}
+
+#undef	G
+
+int
+zipinflate(struct file *f, const char *tgt, int tfd, int doswap, uint32_t *crc)
+/* decompress an inflated entry */
+{
+  struct globals G;
+  int e = 0;            /* last block flag */
+  int r;                /* result code */
+  int is_defl64;
+#ifdef DEBUG
+  unsigned h = 0;       /* maximum struct huft's malloc'ed */
+#endif
+
+  is_defl64 = f->f_cmethod == C_ENHDEFLD;
+  memset(&G, 0, sizeof G);
+  G.tgt = tgt;
+  G.tfd = tfd;
+  G.doswap = doswap;
+  G.crc = crc;
+  G.zsize = G.uzsize = f->f_csize;
+  G.ucsize = f->f_st.st_size;
+  /* initialize window, bit buffer */
+  G.wp = 0;
+  G.bk = 0;
+  G.bb = 0;
+
+  if (is_defl64) {
+    G.cplens = cplens64;
+    G.cplext = cplext64;
+    G.cpdext = cpdext64;
+    G.fixed_tl = G.fixed_tl64;
+    G.fixed_bl = G.fixed_bl64;
+    G.fixed_td = G.fixed_td64;
+    G.fixed_bd = G.fixed_bd64;
+  } else {
+    G.cplens = cplens32;
+    G.cplext = cplext32;
+    G.cpdext = cpdext32;
+    G.fixed_tl = G.fixed_tl32;
+    G.fixed_bl = G.fixed_bl32;
+    G.fixed_td = G.fixed_td32;
+    G.fixed_bd = G.fixed_bd32;
+  }
+
+  /* decompress until the last block */
+  do {
+#ifdef DEBUG
+    G.hufts = 0;
+#endif
+    if ((r = inflate_block(&G, &e)) != 0) {
+      if ((f->f_gflag & FG_DESC) == 0)
+      	while (G.uzsize > 0)
+	      	NEXTBYTE;
+      msg(3, 0, "compression error on \"%s\"\n", f->f_name);
+      return -1;
+    }
+#ifdef DEBUG
+    if (G.hufts > h)
+      h = G.hufts;
+#endif
+  } while (!e);
+
+  Trace((stderr, "\n%u bytes in Huffman tables (%u/entry)\n",
+         h * (unsigned)sizeof(struct huft), (unsigned)sizeof(struct huft)));
+
+  if (is_defl64) {
+    G.fixed_tl64 = G.fixed_tl;
+    G.fixed_bl64 = G.fixed_bl;
+    G.fixed_td64 = G.fixed_td;
+    G.fixed_bd64 = G.fixed_bd;
+  } else {
+    G.fixed_tl32 = G.fixed_tl;
+    G.fixed_bl32 = G.fixed_bl;
+    G.fixed_td32 = G.fixed_td;
+    G.fixed_bd32 = G.fixed_bd;
+  }
+
+  /* flush out redirSlide and return (success, unless final FLUSH failed) */
+  (FLUSH(G.wp));
+  if (f->f_gflag & FG_DESC)
+	  bunread((char *)G.inptr, G.incnt);
+  return G.status;
+}

+ 22 - 0
tools/cpio/src/mbtowi.h

@@ -0,0 +1,22 @@
+/*	Sccsid @(#)mbtowi.h	1.2 (gritter) 7/16/04	*/
+
+#ifndef	LIBCOMMON_MBTOWI_H
+#define	LIBCOMMON_MBTOWI_H
+
+static
+#if defined (__GNUC__) || defined (__USLC__) || defined (__INTEL_COMPILER) || \
+		defined (__IBMC__) || defined (__SUNPRO_C)
+	inline
+#endif
+	int
+mbtowi(wint_t *pwi, const char *s, size_t n)
+{
+	wchar_t	wc;
+	int	i;
+
+	i = mbtowc(&wc, s, n);
+	*pwi = wc;
+	return i;
+}
+
+#endif	/* !LIBCOMMON_MBTOWI_H */

+ 51 - 0
tools/cpio/src/memalign.c

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)memalign.c	1.7 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (_AIX) || \
+	defined (__NetBSD__) || defined (__OpenBSD__) || \
+	defined (__DragonFly__) || defined (__APPLE__)
+/*
+ * FreeBSD malloc(3) promises to page-align the return of malloc() calls
+ * if size is at least a page. This serves for a poor man's memalign() 
+ * implementation that matches our needs.
+ */
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "memalign.h"
+
+void *
+memalign(size_t alignment, size_t size)
+{
+	static long	pagesize;
+
+	if (pagesize == 0)
+		pagesize = sysconf(_SC_PAGESIZE);
+	if (alignment != pagesize)
+		return NULL;
+	if (size < pagesize)
+		size = pagesize;
+	return malloc(size);
+}
+#endif	/* __FreeBSD__ || __dietlibc__ || _AIX || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */

+ 35 - 0
tools/cpio/src/memalign.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)memalign.h	1.7 (gritter) 1/22/06	*/
+
+#ifndef	LIBCOMMON_MEMALIGN_H
+#define	LIBCOMMON_MEMALIGN_H
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (_AIX) || \
+	defined (__NetBSD__) || defined (__OpenBSD__) || \
+	defined (__DragonFly__) || defined (__APPLE__)
+#include	<stdlib.h>
+
+extern void	*memalign(size_t, size_t);
+#endif	/* __FreeBSD__ || __dietlibc__ || _AIX || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */
+#endif	/* !LIBCOMMON_MEMALIGN_H */

+ 30 - 0
tools/cpio/src/msgselect.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)msgselect.h	1.2 (gritter) 9/21/03	*/
+
+#define	MSG_LEVEL	0
+
+#if MSG_LEVEL == 1
+#define	msgselect(a, b)	a
+#else
+#define	msgselect(a, b)	b
+#endif

+ 55 - 0
tools/cpio/src/nonpax.c

@@ -0,0 +1,55 @@
+/*
+ * cpio - copy file archives in and out
+ *
+ * Gunnar Ritter, Freiburg i. Br., Germany, April 2003.
+ */
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+/*	Sccsid @(#)nonpax.c	1.1 (gritter) 2/24/04	*/
+
+#include "cpio.h"
+
+/*ARGSUSED*/
+int
+pax_track(const char *name, time_t mtime)
+{
+	return 1;
+}
+
+/*ARGSUSED*/
+void
+pax_prlink(struct file *f)
+{
+}
+
+/*ARGSUSED*/
+int
+pax_sname(char **oldp, size_t *olds)
+{
+	return 1;
+}
+
+void
+pax_onexit(void)
+{
+}

+ 260 - 0
tools/cpio/src/oblok.c

@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)oblok.c	1.7 (gritter) 7/16/04	*/
+
+#include	<sys/types.h>
+#include	<unistd.h>
+#include	<string.h>
+#include	<errno.h>
+#include	<stdio.h>
+#include	<stdlib.h>
+#include	<malloc.h>
+
+#include	"memalign.h"
+#include	"oblok.h"
+
+struct	list {
+	struct list	*l_nxt;
+	struct oblok	*l_op;
+};
+
+static struct list	*bloks;
+static int	exitset;
+
+int
+ob_clear(void)
+{
+	struct list	*lp;
+	int	val = 0;
+
+	for (lp = bloks; lp; lp = lp->l_nxt) {
+		if (ob_flush(lp->l_op) < 0)
+			val = -1;
+		else if (val >= 0)
+			val++;
+	}
+	return val;
+}
+
+static void
+add(struct oblok *op)
+{
+	struct list	*lp, *lq;
+
+	if ((lp = calloc(1, sizeof *lp)) != NULL) {
+		lp->l_nxt = NULL;
+		lp->l_op = op;
+		if (bloks) {
+			for (lq = bloks; lq->l_nxt; lq = lq->l_nxt);
+			lq->l_nxt = lp;
+		} else
+			bloks = lp;
+		if (exitset == 0) {
+			exitset = 1;
+			atexit((void (*)(void))ob_clear);
+		}
+	}
+}
+
+static void
+del(struct oblok *op)
+{
+	struct list	*lp, *lq = NULL;
+
+	if (bloks) {
+		for (lp = bloks; lp && lp->l_op != op; lp = lp->l_nxt)
+			lq = lp;
+		if (lp) {
+			if (lq)
+				lq->l_nxt = lp->l_nxt;
+			if (lp == bloks)
+				bloks = bloks->l_nxt;
+			free(lp);
+		}
+	}
+}
+
+struct oblok *
+ob_alloc(int fd, enum ob_mode bf)
+{
+	static long	pagesize;
+	struct oblok	*op;
+
+	if (pagesize == 0)
+		if ((pagesize = sysconf(_SC_PAGESIZE)) < 0)
+			pagesize = 4096;
+	if ((op = memalign(pagesize, sizeof *op)) == NULL)
+		return NULL;
+	memset(op, 0, sizeof *op);
+	op->ob_fd = fd;
+	switch (bf) {
+	case OB_EBF:
+		op->ob_bf = isatty(fd) ? OB_LBF : OB_FBF;
+		break;
+	default:
+		op->ob_bf = bf;
+	}
+	add(op);
+	return op;
+}
+
+ssize_t
+ob_free(struct oblok *op)
+{
+	ssize_t	wrt;
+
+	wrt = ob_flush(op);
+	del(op);
+	free(op);
+	return wrt;
+}
+
+static ssize_t
+swrite(int fd, const char *data, size_t sz)
+{
+	ssize_t	wo, wt = 0;
+
+	do {
+		if ((wo = write(fd, data + wt, sz - wt)) < 0) {
+			if (errno == EINTR)
+				continue;
+			else
+				return wt;
+		}
+		wt += wo;
+	} while (wt < sz);
+	return sz;
+}
+
+ssize_t
+ob_write(struct oblok *op, const char *data, size_t sz)
+{
+	ssize_t	wrt;
+	size_t	di, isz;
+
+	switch (op->ob_bf) {
+	case OB_NBF:
+		wrt = swrite(op->ob_fd, data, sz);
+		op->ob_wrt += wrt;
+		if (wrt != sz) {
+			op->ob_bf = OB_EBF;
+			writerr(op, sz, wrt>0?wrt:0);
+			return -1;
+		}
+		return wrt;
+	case OB_LBF:
+	case OB_FBF:
+		isz = sz;
+		while (op->ob_pos + sz > (OBLOK)) {
+			di = (OBLOK) - op->ob_pos;
+			sz -= di;
+			if (op->ob_pos > 0) {
+				memcpy(&op->ob_blk[op->ob_pos], data, di);
+				wrt = swrite(op->ob_fd, op->ob_blk, (OBLOK));
+			} else
+				wrt = swrite(op->ob_fd, data, (OBLOK));
+			op->ob_wrt += wrt;
+			if (wrt != (OBLOK)) {
+				op->ob_bf = OB_EBF;
+				writerr(op, (OBLOK), wrt>0?wrt:0);
+				return -1;
+			}
+			data += di;
+			op->ob_pos = 0;
+		}
+		if (op->ob_bf == OB_LBF) {
+			const char	*cp;
+
+			cp = data;
+			while (cp < &data[sz]) {
+				if (*cp == '\n') {
+					di = cp - data + 1;
+					sz -= di;
+					if (op->ob_pos > 0) {
+						memcpy(&op->ob_blk[op->ob_pos],
+								data, di);
+						wrt = swrite(op->ob_fd,
+							op->ob_blk,
+							op->ob_pos + di);
+					} else
+						wrt = swrite(op->ob_fd,
+							data, di);
+					op->ob_wrt += wrt;
+					if (wrt != op->ob_pos + di) {
+						op->ob_bf = OB_EBF;
+						writerr(op, di, wrt>0?wrt:0);
+						return -1;
+					}
+					op->ob_pos = 0;
+					data += di;
+					cp = data;
+				}
+				cp++;
+			}
+		}
+		if (sz == (OBLOK)) {
+			wrt = swrite(op->ob_fd, data, sz);
+			op->ob_wrt += wrt;
+			if (wrt != sz) {
+				op->ob_bf = OB_EBF;
+				writerr(op, sz, wrt>0?wrt:0);
+				return -1;
+			}
+		} else if (sz) {
+			memcpy(&op->ob_blk[op->ob_pos], data, sz);
+			op->ob_pos += sz;
+		}
+		return isz;
+	case OB_EBF:
+		;
+	}
+	return -1;
+}
+
+ssize_t
+ob_flush(struct oblok *op)
+{
+	ssize_t	wrt = 0;
+
+	if (op->ob_pos) {
+		wrt = swrite(op->ob_fd, op->ob_blk, op->ob_pos);
+		op->ob_wrt += wrt;
+		if (wrt != op->ob_pos) {
+			op->ob_bf = OB_EBF;
+			writerr(op, op->ob_pos, wrt>0?wrt:0);
+			wrt = -1;
+		}
+		op->ob_pos = 0;
+	}
+	return wrt;
+}
+
+int
+ob_chr(int c, struct oblok *op)
+{
+	char	b;
+	ssize_t	wrt;
+
+	b = (char)c;
+	wrt = ob_write(op, &b, 1);
+	return wrt < 0 ? EOF : c;
+}

+ 96 - 0
tools/cpio/src/oblok.h

@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)oblok.h	1.3 (gritter) 4/17/03	*/
+
+#include	<sys/types.h>
+
+#ifndef	OBLOK
+enum	{
+	OBLOK = 4096
+};
+#endif	/* !OBLOK */
+
+enum	ob_mode {
+	OB_EBF = 0,		/* error or mode unset */
+	OB_NBF = 1,		/* not buffered */
+	OB_LBF = 2,		/* line buffered */
+	OB_FBF = 3		/* fully buffered */
+};
+
+struct	oblok {
+	char	ob_blk[OBLOK];		/* buffered data */
+	long long	ob_wrt;			/* amount of data written */
+	int	ob_pos;			/* position of first empty date byte */
+	int	ob_fd;			/* file descriptor to write to */
+	enum ob_mode	ob_bf;		/* buffering mode */
+};
+
+/*
+ * Allocate an output buffer with file descriptor fd and buffer mode bf.
+ * If bf is OB_EBF, the choice is made dependant upon the file type.
+ * NULL is returned if no memory is available.
+ */
+extern struct oblok	*ob_alloc(int fd, enum ob_mode bf);
+
+/*
+ * Deallocate the passed output buffer, flushing all data. The file
+ * descriptor is not closed. Returns -1 if flushing fails.
+ */
+extern ssize_t	ob_free(struct oblok *op);
+
+/*
+ * Write data of length sz to the passed output buffer. Returns -1 on
+ * error or the amount of data written.
+ */
+extern ssize_t	ob_write(struct oblok *op, const char *data, size_t sz);
+
+/*
+ * Flush all data in the passed output buffer. Returns -1 on error or
+ * the amount of data written; 0 is success and means 'nothing to flush'.
+ * The underlying device is not flushed (i. e. no fsync() is performed).
+ */
+extern ssize_t	ob_flush(struct oblok *op);
+
+/*
+ * Flush all output buffers. Called automatically using atexit(). Returns
+ * -1 on error or the number of buffers flushed; 0 is success.
+ */
+extern int	ob_clear(void);
+
+/*
+ * putc() workalike.
+ */
+#define	ob_put(c, op)	((op)->ob_bf != OB_FBF || (op)->ob_pos >= (OBLOK) - 1 ?\
+				ob_chr((c), (op)) : \
+				(int)((op)->ob_blk[(op)->ob_pos++] = (char)(c)))
+
+
+/*
+ * fputc() workalike.
+ */
+extern int	ob_chr(int c, struct oblok *op);
+
+/*
+ * This function must be supplied by the calling code; it is called on
+ * write error.
+ */
+extern void	writerr(struct oblok *op, int count, int written);

+ 51 - 0
tools/cpio/src/pathconf.c

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)pathconf.c	1.2 (gritter) 5/1/04	*/
+
+#ifdef	__dietlibc__
+#include <unistd.h>
+#include "pathconf.h"
+
+static long
+pc(int name)
+{
+	switch (name) {
+	case _PC_PATH_MAX:
+		return 1024;
+	case _PC_VDISABLE:
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+long
+fpathconf(int fildes, int name)
+{
+	return pc(name);
+}
+
+long
+pathconf(const char *path, int name) {
+	return pc(name);
+}
+#endif	/* __dietlibc__ */

+ 29 - 0
tools/cpio/src/pathconf.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)pathconf.h	1.2 (gritter) 5/1/04	*/
+
+#ifdef	__dietlibc__
+#include <unistd.h>
+
+extern long	fpathconf(int, int);
+extern long	pathconf(const char *, int);
+#endif	/* __dietlibc__ */

+ 919 - 0
tools/cpio/src/pax.1

@@ -0,0 +1,919 @@
+'\" t
+.\" Copyright (c) 2004 Gunnar Ritter
+.\"
+.\" This software is provided 'as-is', without any express or implied
+.\" warranty. In no event will the authors be held liable for any damages
+.\" arising from the use of this software.
+.\"
+.\" Permission is granted to anyone to use this software for any purpose,
+.\" including commercial applications, and to alter it and redistribute
+.\" it freely, subject to the following restrictions:
+.\"
+.\" 1. The origin of this software must not be misrepresented; you must not
+.\"    claim that you wrote the original software. If you use this software
+.\"    in a product, an acknowledgment in the product documentation would be
+.\"    appreciated but is not required.
+.\"
+.\" 2. Altered source versions must be plainly marked as such, and must not be
+.\"    misrepresented as being the original software.
+.\"
+.\" 3. This notice may not be removed or altered from any source distribution.
+.\" Sccsid @(#)pax.1	1.38 (gritter) 8/13/09
+.TH PAX 1 "8/13/09" "Heirloom Toolchest" "User Commands"
+.SH NAME
+pax \- portable archive interchange
+.SH SYNOPSIS
+.PD 0
+.HP
+.nh
+.ad l
+\fBpax\fR [\fB\-cdnvK\fR] [\fB\-b\ \fIsize\fR]
+[\fB\-f\ \fIfile\fR] [\fB\-s\ \fIreplstr\fR]
+[\fB\-x\ \fIhdr\fR] [\fIpatterns\fR]
+.HP
+.ad l
+\fBpax\fR \fB\-r\fR[\fBcdiknuvK\fR] [\fB\-b\ \fIsize\fR]
+[\fB\-f\ \fIfile\fR]
+[\fB\-o\ \fIoptions\fR]
+[\fB\-p\ \fIpriv\fR] [\fB\-s\ \fIreplstr\fR]
+[\fB\-x\ \fIhdr\fR] [\fIpatterns\fR]
+.HP
+.ad l
+\fBpax\fR \fB\-w\fR[\fBadiHtuvLX\fR] [\fB\-b\ \fIsize\fR]
+[\fB\-f\ \fIfile\fR]
+[\fB\-o\ \fIoptions\fR]
+[\fB\-s\ \fIreplstr\fR]
+[\fB\-x\ \fIhdr\fR] [\fIfiles\fR]
+.HP
+.ad l
+\fBpax\fR \fB\-rw\fR[\fBdiHklntuvLX\fR]
+[\fB\-p\ \fIpriv\fR] [\fB\-s\ \fIreplstr\fR]
+[\fIfiles\fR] \fIdirectory\fR
+.br
+.ad b
+.hy 1
+.PD
+.SH DESCRIPTION
+.I Pax
+creates and extracts file archives and copies files.
+.PP
+If neither the
+.I \-r
+or
+.I \-w
+options are given,
+.I pax
+works in
+.I list
+mode
+and prints the contents of the archive.
+.PP
+With the
+.B \-r
+option,
+.I pax
+works in
+.RI ` read '
+mode and extracts files from a file archive.
+By default,
+the archive is read from standard input.
+Optional arguments are interpreted as
+.I patterns
+and restrict the set of extracted files
+to those matching any of the
+.IR patterns .
+The syntax is identical to that described in
+.IR glob (7),
+except that the slash character
+.RB ` / '
+is matched by
+meta-character constructs with
+.RB ` * ',
+.RB ` ? '
+and
+.RB ` [ '.
+Care must be taken to quote meta-characters appropriately from the shell.
+If a pattern matches the prefix name of a directory in the archive,
+all files below that directory are also extracted.
+File permissions are set to those in the archive;
+if the caller is the super-user,
+ownerships are restored as well.
+options are specified.
+Archives compressed with
+.IR bzip2 (1),
+.IR compress (1),
+.IR gzip (1),
+or
+.IR rpm (1)
+are transparently de\%compressed on input.
+.PP
+With
+.BR \-w ,
+.I pax
+works in
+.RI ` write '
+mode,
+creates archives
+and writes them to standard output per default.
+A list of filenames to be included in the archive is
+read from standard input;
+if the name of a directory appears,
+all its members and the directory itself are recursively
+included in the archive.
+The
+.IR find (1)
+utility is useful to generate a list of files
+(see also its
+.I \-cpio
+and
+.I \-ncpio
+operators).
+When producing a filename list for
+.IR pax ,
+find should always be invoked with
+.I \-depth
+since this makes it possible to extract write-protected directories
+for users other than the super-user.
+If
+.I files
+are given on the command line,
+they are included in the archive
+in the same manner as described above
+and standard input is not read.
+.PP
+The
+.B \-rw
+options selects
+.RI ` copy '
+mode;
+a list of
+.I files
+is read from standard input
+or taken from the command line
+as described for
+.IR \-w ;
+files are copied to the specified
+.IR directory ,
+preserving attributes as described for
+.IR \-r .
+Special files are re-created in the target hierarchy,
+and hard links between copied files are preserved.
+.PP
+When a premature end-of-file is detected with
+.I \-r
+and
+.I \-w
+and the archive is a block or character special file,
+the user is prompted for new media.
+.PP
+The following options alter the behavior of
+.IR pax :
+.TP
+.B \-a
+Append files to the archive.
+The archive must be seekable,
+such as a regular file or a block device,
+or a tape device capable of writing between filemarks.
+.TP
+\fB\-b\fI size\fR[\fBw\fR|\fBb\fR|\fBk\fR|\fBm\fR]
+Blocks input and output archives at
+.I size
+byte records.
+The optional suffix multiplies
+.I size
+by 2 for
+.BR w ,
+512 for
+.BR b ,
+1024 for
+.BR k ,
+and 1048576 for
+.BR m .
+.TP
+.B \-c
+Reverses the sense of patterns
+such that a file that does not match any of the patterns
+is selected.
+.TP
+.B \-d
+Causes
+.I pax
+to ignore files below directories.
+In read mode,
+patterns matching directories
+cause only the directory itself to extracted,
+files below will be ignored
+unless another pattern applies to them.
+In write mode,
+arguments or standard input lines referring to directories
+do not cause files below the respective directory
+to be archived.
+.TP
+\fB\-f\fI\ file\fR
+Selects a
+.I file
+that is read with the
+.I \-r
+option instead of standard input
+or written with the
+.I \-w
+option instead of standard output.
+.TP
+.B \-H
+Follow symbolic links given on the command line when reading files with
+.I \-w
+or
+.IR \-rw ,
+but do not follow symbolic links encountered during directory traversal.
+.TP
+.B \-i
+Rename files interactively.
+Before a file is extracted from the archive,
+its file name is printed on standard error
+and the user is prompted to specify a substitute file name.
+If the line read from the terminal is empty,
+the file is skipped;
+if the line consists of a single dot,
+the name is retained;
+otherwise,
+the line forms the new file name.
+.TP
+.B \-k
+Causes existing files not to be overwritten.
+.TP
+.B \-K
+Try to continue operation on read errors and invalid headers.
+If an archive contains another archive,
+files from either archive may be chosen.
+.TP
+.B \-l
+Link files instead of copying them with
+.I \-rw
+if possible.
+.TP
+.B \-L
+Follow symbolic links when reading files with
+.I \-w
+or
+.IR \-rw .
+.B /usr/posix2001/bin/pax
+terminates immediately when it
+detects a symbolic link loop with this option.
+.TP
+.B \-n
+If any
+.I pattern
+arguments are present,
+each pattern can match exactly one archive member;
+further members that could match the particular pattern are ignored.
+Without
+.I pattern
+arguments,
+only the first occurence of
+a file that occurs more than once in the archive
+is selected, the following are ignored.
+.TP
+\fB\-o\ \fIoption\fB,\fR[\fIoption\fB,\fR\|...]
+Specifies options as described for \fI\-x pax\fR.
+.TP
+\fB\-p\ \fIstring\fR
+Specifies which file modes are to be preserved or ignored.
+.I string
+may contain one or more of
+.RS
+.TP
+.B a
+Inhibits preservation of file access times.
+.TP
+.B e
+Causes preservation of every possible mode, ownership and time.
+.TP
+.B m
+Inhibits preservation of file modification times.
+.TP
+.B o
+Causes preservation of owner and group IDs.
+.TP
+.B p
+Causes preservation of file mode bits
+regardless of the umask
+(see
+.IR umask (2)).
+.RE
+.IP
+If file ownership is preserved,
+.I pax
+tries to set the group ownerships to those specified in the archive
+or the original hierarchy, respectively,
+regardless of the privilegues of the invoking user.
+.BR /usr/5bin/pax ,
+.BR /usr/5bin/s42/pax ,
+and
+.B /usr/5bin/posix/pax
+try to set the user ownerships only if invoked by the super-user;
+if invoked by regular users,
+.B /usr/5bin/posix2001/pax
+will produce an error for any file that is not owned by the invoking user.
+.TP
+\fB\-s\ /\fIregular expression\fB/\fIreplacement\fB/\fR[\fBgp\fR]
+Modifies file names in a manner similar to that described in
+.IR ed (1).
+The
+.I p
+flag causes each modified file name to printed.
+Any character can be used as delimiter instead of
+.RI ` / '.
+If a file name is empty after the replacement is done,
+the file is ignored.
+This option can be specified multiple times
+to execute multiple substitutions in the order specified.
+.TP
+.B \-t
+Resets the access times of files
+that were included in the archive with
+.IR \-r .
+.TP
+.B \-u
+In read mode,
+.I pax
+will not overwrite existing target files
+that were modified more recently than the file in the archive
+when this option is given.
+In write mode,
+.I pax
+will read the archive first.
+It will then only append those files to the archive
+that are not already included
+or were more recently modified.
+.TP
+.B \-v
+Prints the file names of archived or extracted files with
+.I \-r
+and
+.I \-w
+and a verbose output format
+if neither of them is given.
+.TP
+\fB\-x\fI header\fR
+Specifies the archive header format to be one of:
+.sp
+.in +6
+.TS
+lfB l.
+\fBnewc\fR	SVR4 ASCII cpio format;\ 
+\fBcrc\fR	SVR4 ASCII cpio format with checksum;\ 
+\fBsco\fR	T{
+SCO UnixWare 7.1 ASCII cpio format;
+T}
+\fBscocrc\fR	T{
+SCO UnixWare 7.1 ASCII cpio format with checksum;
+T}
+\fBodc\fR	T{
+traditional ASCII cpio format, as standardized in IEEE Std. 1003.1, 1996;
+T}
+\fBcpio\fR	T{
+same as \fIodc\fR;
+T}
+\fBbin\fR	binary cpio format;
+\fBbbs\fR	byte-swapped binary cpio format;
+\fBsgi\fR	T{
+SGI IRIX extended binary cpio format;
+T}
+\fBcray\fR	T{
+Cray UNICOS 9 cpio format;
+T}
+\fBcray5\fR	T{
+Cray UNICOS 5 cpio format;
+T}
+\fBdec\fR	T{
+Digital UNIX extended cpio format;
+T}
+\fBtar\fR	tar format;
+\fBotar\fR	old tar format;
+\fBustar\fR	T{
+IEEE Std. 1003.1, 1996 tar format;
+T}
+.T&
+l s.
+\fBpax\fR[\fB:\fIoption\fB,\fR[\fIoption\fB,\fR\|...]]
+.T&
+l l.
+\&	T{
+IEEE Std. 1003.1, 2001 pax format.
+Format-specific \fIoptions\fR are:
+.in +2n
+.ti 0
+.br
+\fBlinkdata\fR
+.br
+For a regular file which has multiple hard links,
+the file data is stored once for each link in the archive,
+instead of being stored for the first entry only.
+This option must be used with care
+since many implementations are unable
+to read the resulting archive.
+.ti 0
+.br                                                                            
+\fBtimes\fR
+.br
+Causes the times of last access and last modification
+of each archived file
+to be stored in an extended \fIpax\fR header.
+This in particular allows the time of last access
+to be restored when the archive is read.
+.br
+.in -2n
+T}
+\fBsun\fR	T{
+Sun Solaris 7 extended tar format;
+T}
+\fBbar\fR	T{
+SunOS 4 bar format;
+T}
+\fBgnu\fR	T{
+GNU tar format;
+T}
+\fBzip\fR[\fB:\fIcc\fR]	T{
+zip format with optional compression method.
+If \fIcc\fR is one of
+\fBen\fR (normal, default),
+\fBex\fR (extra),
+\fBef\fR (fast),
+or
+\fBes\fR (super fast),
+the standard \fIdeflate\fR compression is used.
+\fBe0\fR selects no compression,
+and
+\fBbz2\fR selects \fIbzip2\fR compression.
+T}
+.TE
+.in -6
+.sp
+This option is ignored with
+.I \-r
+unless the
+.I \-K
+option is also present.
+The default for
+.I \-w
+is traditional ASCII cpio
+.I (odc)
+format.
+.PP
+.ne 38
+Characteristics of archive formats are as follows:
+.sp
+.TS
+allbox;
+l r r r l
+l1fB r2 n2 r2 c.
+	T{
+.ad l
+maximum user/\%group id
+T}	T{
+.ad l
+maximum file size
+T}	T{
+.ad l
+maximum pathname length
+T}	T{
+.ad l
+bits in dev_t (major/minor)
+T}
+\-x\ bin	65535	2 GB\ 	256	\ 16
+\-x\ sgi	65535	9 EB\ 	256	\ 14/18
+T{
+\-x\ odc
+T}	262143	8 GB\ 	256	\ 18
+\-x\ dec	262143	8 GB\ 	256	\ 24/24
+T{
+\-x\ newc,
+\-x\ crc
+T}	4.3e9	4 GB\ 	1024	\ 32/32
+T{
+\-x\ sco, \-x\ scocrc
+T}	4.3e9	9 EB\ 	1024	\ 32/32
+T{
+\-x\ cray, \-x\ cray5
+T}	1.8e19	9 EB\ 	65535	\ 64
+\-x\ otar	2097151	8 GB\ 	99	\ n/a
+T{
+\-x\ tar,
+\-x\ ustar
+T}	2097151	8 GB\ 	256 (99)	\ 21/21
+\-x\ pax	1.8e19	9 EB\ 	65535	\ 21/21
+\-x\ sun	1.8e19	9 EB\ 	65535	\ 63/63
+\-x\ gnu	1.8e19	9 EB\ 	65535	\ 63/63
+\-x\ bar	2097151	8 GB\ 	427	\ 21
+\-x\ zip	4.3e9	9 EB\ 	60000	\ 32
+.TE
+.sp
+.PP
+The byte order of
+.B binary
+cpio archives
+depends on the machine
+on which the archive is created.
+Unlike some other implementations,
+.I pax
+fully supports
+archives of either byte order.
+.I \-x\ bbs
+can be used to create an archive
+with the byte order opposed to that of the current machine.
+.PP
+The
+.B sgi
+format extends the binary format
+to handle larger files and more device bits.
+If an archive does not contain any entries
+that actually need the extensions,
+it is identical to a binary archive.
+.I \-x\ sgi
+archives are always created in MSB order.
+.PP
+The
+.B odc
+format was introduced with System\ III
+and standardized with IEEE Std. 1003.1.
+All known
+.I cpio
+and
+.I pax
+implementations since around 1980 can read this format.
+.PP
+The
+.B dec
+format extends the
+.I odc
+format
+to support more device bits.
+Archives in this format are generally incompatible with
+.I odc
+archives
+and need special implementation support to be read.
+.PP
+The
+.B \-x\ newc
+format was introduced with System\ V Release\ 4.
+Except for the file size,
+it imposes no practical limitations
+on files archived.
+The original SVR4 implementation
+stores the contents of hard linked files
+only once and with the last archived link.
+This
+.I pax
+ensures compatibility with SVR4.
+With archives created by implementations that employ other methods
+for storing hard linked files,
+each file is extracted as a single link,
+and some of these files may be empty.
+Implementations that expect methods other than the original SVR4 one
+may extract no data for hard linked files at all.
+.PP
+The
+.B crc
+format is essentially the same as the
+.I \-x\ newc
+format
+but adds a simple checksum (not a CRC, despite its name)
+for the data of regular files.
+The checksum requires the implementation to read each file twice,
+which can considerably increase running time and system overhead.
+As not all implementations claiming to support this format
+handle the checksum correctly,
+it is of limited use.
+.PP
+The
+.B sco
+and
+.B scocrc
+formats are variants of the
+.I \-x\ newc
+and
+.I \-x\ crc
+formats, respectively,
+with extensions to support larger files.
+The extensions result in a different archive format
+only if files larger than slightly below 2\ GB occur.
+.PP
+The
+.B cray
+format extends all header fields to 64 bits.
+It thus imposes no practical limitations of any kind
+on archived files,
+but requires special implementation support
+to be read.
+Although it is originally a binary format,
+the byte order is always MSB as on Cray machines.
+The
+.B cray5
+format is an older variant
+that was used with UNICOS 5 and earlier.
+.PP
+The
+.B otar
+format was introduced with the Unix 7th Edition
+.I tar
+utility.
+Archives in this format
+can be read on all Unix systems since about 1980.
+It can only hold regular files
+(and, on more recent systems, symbolic links).
+For file names that contain characters with the most significant bit set
+(non-ASCII characters),
+implementations differ in the interpretation of the header checksum.
+.PP
+The
+.B ustar
+format was introduced with IEEE Std. 1003.1.
+It extends the old
+.I tar
+format
+with support for directories, device files,
+and longer file names.
+Pathnames of single-linked files can consist of up to 256 characters,
+dependent on the position of slashes.
+Files with multiple links can only be archived
+if the first link encountered is no longer than 100 characters.
+Due to implementation errors,
+file names longer than 99 characters
+can not considered to be generally portable.
+Another addition of the
+.I ustar
+format
+are fields for the symbolic user and group IDs.
+These fields are created by
+.IR pax ,
+but ignored when reading such archives.
+.PP
+With
+.BR "\-x tar" ,
+a variant of the
+.I ustar
+format is selected
+which stores file type bits in the mode field
+to work around common implementation problems.
+These bits are ignored by
+.I pax
+when reading archives.
+.PP
+The
+.B pax
+format is an extension to the
+.I ustar
+format.
+If attributes cannot be archived with
+.IR ustar ,
+an extended header is written.
+Unless the size of an entry is greater than 8\ GB,
+a
+.I pax
+archive should be readable by any implementation                               
+capable of reading
+.I ustar
+archives,
+although files may be extracted under wrong names
+and extended headers may be extracted as separate files.
+If a file name contains non-UTF-8 characters,
+it may not be archived or extracted correctly
+because of a problem of the
+.I pax
+format specification.
+.PP
+The
+.B sun
+format extends the
+.I ustar
+format similar as the
+.I pax
+format does.
+The extended headers in
+.I sun
+format archives are not understood
+by implementations that support only the
+.I pax
+format and vice-versa.
+The
+.I sun
+format has also problems with non-UTF-8 characters in file names.
+.PP
+The
+.B GNU
+.I tar
+format is mostly compatible with the other
+.I tar
+formats,
+unless an archive entry actually uses its extended features.
+There are no practical limitations on files archived with this format.
+The implementation of
+.I pax
+is limited to expanded numerical fields
+and long file names;
+in particular,
+there is no support for sparse files or incremental backups.
+If
+.I pax
+creates a multi-volume
+.I GNU
+archive,
+it just splits a single-volume archive in multiple parts,
+as with the other formats;
+.I GNU
+multi-volume archives are not supported.
+.PP
+The
+.B bar
+format is similar to the
+.I tar
+format, but can store longer file names.
+It requires special implementation support to be read.
+.PP
+The
+.B zip
+format can be read in many non-Unix environments.
+There are several restrictions on archives
+intended for data exchange:
+only regular files should be stored;
+file times, permissions and ownerships
+might be ignored by other implementations;
+there should be no more than 65536 files in the archive;
+the total archive size should not exceed 2 GB;
+only
+.I deflate
+compression should be used.
+Otherwise,
+.I pax
+stores all information available with other archive formats
+in extended
+.I zip
+file headers,
+so if archive portability is of no concern,
+the
+.I zip
+implementation in
+.I pax
+can archive complete Unix file hierarchies.
+.I Pax
+supports the
+.I zip64
+format extension for large files;
+it automatically writes
+.I zip64
+entries if necessary.
+.I Pax
+can extract all known
+.I zip
+format compression codes.
+It does not support
+.I zip
+encryption.
+Multi-volume
+.I zip
+archives are created as splitted single-volume archives,
+as with the other formats written by
+.IR pax ;
+generic multi-volume
+.I zip
+archives are not supported.
+.SH EXAMPLES
+Extract all files named
+.I Makefile
+or
+.I makefile
+from the archive stored on
+.IR /dev/rmt/c0s0 ,
+overwriting recent files:
+.RS 2
+.sp
+pax \-r \-f /dev/rmt/c0s0 \'[Mm]akefile\' \'*/[Mm]akefile\'
+.RE
+.PP
+List the files contained in a software distribution archive:
+.RS 2
+.sp
+pax \-v \-f distribution.tar.gz
+.RE
+.PP
+Write a
+.IR gzip (1)
+compressed
+.I ustar
+archive containing all files below the directory
+.I \%project
+to the file
+.IR \%project.tar.gz ,
+excluding all directories named
+.I CVS
+or
+.I SCCS
+and their contents:
+.RS 2
+.sp
+find project \-depth \-print | egrep \-v \'/(CVS|SCCS)(/|$)\' |
+.br
+      pax \-wd \-x ustar | gzip \-c > project.tar.gz
+.RE
+.PP
+Copy the directory
+.I work
+and its contents
+to the directory
+.IR \%savedfiles ,
+preserving all file attributes:
+.RS 2
+.sp
+pax \-rw \-pe work savedfiles
+.RE
+.PP
+Self-extracting zip archives are not automatically recognized,
+but can normally be read using the
+.I \-K
+option, as with
+.RS 2
+.sp
+pax \-rK \-x zip \-f archive.exe
+.sp
+.RE
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.BR LANG ", " LC_ALL
+See
+.IR locale (7).
+.TP
+.B LC_CTYPE
+Selects the mapping of bytes to characters
+used for matching patterns
+and regular expressions.
+.TP
+.B LC_TIME
+Sets the month names printed in list mode.
+.SH "SEE ALSO"
+cpio(1),
+find(1),
+tar(1)
+.SH DIAGNOSTICS
+.I Pax
+exits with
+.sp
+.TS
+l8fB l.
+0	after successful operation;
+1	on usage errors;
+2	when operation was continued after minor errors;
+3	on fatal error conditions.
+.TE
+.SH NOTES
+Device and inode numbers
+are used for hard link recognition
+with the various cpio formats.
+Since the header space cannot hold
+large numbers present in current file systems,
+devices and inode numbers are set on a per-archive basis.
+This enables hard link recognition with all cpio formats,
+but the link connection to files appended with
+.I \-a
+is not preserved.
+.PP
+If a numeric user or group id does not fit
+within the size of the header field in the selected format,
+files are stored with the user id (or group id, respectively)
+set to 60001.
+.PP
+Use of the
+.I \-a
+option with a
+.I zip
+format archive may cause data loss
+if the archive was not previously created by
+.I cpio
+or
+.I pax
+itself.
+.PP
+If the file names passed to
+.I "pax -w"
+begin with a slash character,
+absolute path names are stored in the archive
+and will be extracted to these path names later
+regardless of the current working directory.
+This is normally not advisable,
+and relative path names should be passed to
+.I pax
+only.
+The
+.I \-s
+option can be used to substitute relative for absolute path names
+and vice-versa.
+.PP
+.I Pax
+does not currently accept the
+\fB\-o delete\fR,
+\fB\-o exthdr.name\fR,
+\fB\-o globexthdr.name\fR,
+\fB\-o invalid\fR,
+\fB\-o listopt\fR,
+and
+\fB\-o keyword\fR
+options from POSIX.1-2001.

+ 757 - 0
tools/cpio/src/pax.c

@@ -0,0 +1,757 @@
+/*
+ * cpio - copy file archives in and out
+ *
+ * Gunnar Ritter, Freiburg i. Br., Germany, April 2003.
+ */
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
+#define	USED	__attribute__ ((used))
+#elif defined __GNUC__
+#define	USED	__attribute__ ((unused))
+#else
+#define	USED
+#endif
+#if defined (SU3)
+static const char sccsid[] USED = "@(#)pax_su3.sl	1.26 (gritter) 6/26/05";
+#else
+static const char sccsid[] USED = "@(#)pax.sl	1.26 (gritter) 6/26/05";
+#endif
+/*	Sccsid @(#)pax.c	1.26 (gritter) 6/26/05	*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fnmatch.h>
+#include <dirent.h>
+#include <regex.h>
+#include <wchar.h>
+#include <time.h>
+#include <inttypes.h>
+
+#include "iblok.h"
+#include "cpio.h"
+
+static char		**files;
+static int		filec;
+static struct iblok	*filinp;
+static char		*path;
+static size_t		pathsz;
+static int		pax_Hflag;
+
+static void		setpres(const char *);
+static size_t		ofiles_pax(char **, size_t *);
+static void		prtime_pax(time_t);
+static void		parsesub(char *);
+
+void
+flags(int ac, char **av)
+{
+	const char	optstring[] = "rwab:cdf:HikKlLno:p:s:tuvx:X";
+	int	i;
+	int	illegal = 0;
+	char	*x;
+
+#if defined (SU3)
+	pax = PAX_TYPE_PAX2001;
+#else
+	pax = PAX_TYPE_PAX1992;
+#endif
+	dflag = 1;
+	uflag = 1;
+	ofiles = ofiles_pax;
+	prtime = prtime_pax;
+	while ((i = getopt(ac, av, optstring)) != EOF) {
+		switch (i) {
+		case 'r':
+			if (action && action != 'i')
+				action = 'p';
+			else
+				action = 'i';
+			break;
+		case 'w':
+			if (action && action != 'o')
+				action = 'p';
+			else
+				action = 'o';
+			break;
+		case 'a':
+			Aflag = 1;
+			break;
+		case 'b':
+			blksiz = strtol(optarg, &x, 10);
+			switch (*x) {
+			case 'b':
+				blksiz *= 512;
+				break;
+			case 'k':
+				blksiz *= 1024;
+				break;
+			case 'm':
+				blksiz *= 1048576;
+				break;
+			case 'w':
+				blksiz *= 2;
+				break;
+			}
+			if (blksiz <= 0)
+				msg(4, -2,
+					"Illegal size given for -b option.\n");
+			Cflag = 1;
+			break;
+		case 'c':
+			fflag = 1;
+			break;
+		case 'd':
+			pax_dflag = 1;
+			break;
+		case 'f':
+			Oflag = Iflag = optarg;
+			break;
+		case 'H':
+			pax_Hflag = 1;
+			break;
+		case 'i':
+			rflag = 1;
+			break;
+		case 'k':
+			pax_kflag = 1;
+			break;
+		case 'K':
+			kflag = 1;
+			break;
+		case 'l':
+			lflag = 1;
+			break;
+		case 'L':
+			Lflag = 1;
+			break;
+		case 'n':
+			pax_nflag = 1;
+			break;
+		case 'o':
+			pax_options(optarg, 1);
+			break;
+		case 'p':
+			setpres(optarg);
+			break;
+		case 's':
+			pax_sflag = 1;
+			parsesub(optarg);
+			break;
+		case 't':
+			aflag = 1;
+			break;
+		case 'u':
+			uflag = 0;
+			pax_uflag = 1;
+			break;
+		case 'v':
+			vflag = 1;
+			break;
+		case 'x':
+			if (strcmp(optarg, "cpio") == 0)
+				fmttype = FMT_ODC;
+			else {
+				if (setfmt(optarg) < 0)
+					illegal = 1;
+			}
+			break;
+		case 'X':
+			pax_Xflag = 1;
+			break;
+		default:
+			illegal = 1;
+		}
+	}
+	switch (action) {
+	case 0:
+		if (rflag || pax_kflag || pax_uflag || pax_preserve)
+			illegal = 1;
+		action = 'i';
+		tflag = 1;
+		setvbuf(stdout, NULL, _IOLBF, 0);
+		/*FALLTHRU*/
+	case 'i':
+		if (aflag || pax_Xflag || lflag)
+			illegal = 1;
+		for (i = optind; i < ac; i++) {
+			addg(av[i], 0);
+			if (pax_dflag == 0) {
+				char	*da;
+				int	j;
+
+				da = smalloc(strlen(av[i]) + 2);
+				for (j = 0; av[i][j]; j++)
+					da[j] = av[i][j];
+				da[j++] = '/';
+				da[j++] = '*';
+				da[j] = 0;
+				addg(da, 1);
+				free(da);
+			}
+		}
+		break;
+	case 'o':
+		if (fflag || pax_kflag || pax_nflag || kflag)
+			illegal = 1;
+		if (Aflag && Oflag == NULL) {
+			msg(3, 0, "-a requires the -f option\n");
+			illegal = 1;
+		}
+		if (optind != ac) {
+			files = &av[optind];
+			filec = ac - optind;
+		} else
+			filinp = ib_alloc(0, 0);
+		if (pax_uflag)
+			Aflag = 1;
+		if (Aflag == 0 && fmttype == FMT_NONE)
+			fmttype = FMT_ODC;
+		break;
+	case 'p':
+		if (fflag || blksiz || Oflag || Iflag || fmttype != FMT_NONE ||
+				kflag)
+			illegal = 1;
+		if (optind == ac)
+			illegal = 1;
+		else if (optind+1 != ac) {
+			files = &av[optind];
+			filec = ac - optind - 1;
+			optind = ac - 1;
+		} else
+			filinp = ib_alloc(0, 0);
+		break;
+	}
+	if (illegal)
+		usage();
+}
+
+void
+usage(void)
+{
+	fprintf(stderr, "USAGE:\n\
+\t%s [-cdnvK] [-b size] [-f file] [-s replstr] [-x hdr] [patterns]\n\
+\t%s -r[cdiknuvK] [-b size] [-f file] [-p priv] [-s replstr] [-x hdr] [patterns]\n\
+\t%s -w[adituvLX] [-b size] [-f file] [-s replstr] [-x hdr] [files]\n\
+\t%s -rw[diklntuvLX] [-p priv] [-s replstr] [files] directory\n",
+		progname, progname, progname, progname);
+	exit(1);
+}
+
+static void
+setpres(const char *s)
+{
+	s--;
+	while (*++s) {
+		pax_preserve &= ~PAX_P_EVERY;
+		switch (*s) {
+		case 'a':
+			pax_preserve |= PAX_P_ATIME;
+			break;
+		case 'e':
+			pax_preserve |= PAX_P_EVERY;
+			break;
+		case 'm':
+			pax_preserve |= PAX_P_MTIME;
+			break;
+		case 'o':
+			pax_preserve |= PAX_P_OWNER;
+			break;
+		case 'p':
+			pax_preserve |= PAX_P_MODE;
+			break;
+		default:
+			msg(2, 0, "ignoring unknown option \"-p%c\"\n",
+					*s&0377);
+		}
+	}
+	if (pax_preserve & PAX_P_EVERY)
+		pax_preserve |= PAX_P_OWNER|PAX_P_MODE;
+}
+
+int
+gmatch(const char *s, const char *p)
+{
+	int	val;
+#ifdef	__GLIBC__
+	/* avoid glibc's broken [^...] */
+	extern char	**environ;
+	char	**savenv = environ;
+	char	*newenv[] = { "POSIXLY_CORRECT=", NULL };
+	environ = newenv;
+#endif	/* __GLIBC__ */
+	val = fnmatch(p, s, 0) == 0;
+#ifdef	__GLIBC__
+	environ = savenv;
+#endif	/* __GLIBC__ */
+	return val;
+}
+
+static const char *
+nextfile(void)
+{
+	char	*line = NULL;
+	size_t	linsiz = 0, linlen;
+
+	if (filinp) {
+		pax_Hflag = 0;
+		if ((linlen=ib_getlin(filinp, &line, &linsiz, srealloc)) == 0) {
+			filinp = NULL;
+			return NULL;
+		}
+		if (line[linlen-1] == '\n')
+			line[--linlen] = '\0';
+		return line;
+	} else if (filec > 0) {
+		filec--;
+		return *files++;
+	} else
+		return NULL;
+}
+
+static size_t
+catpath(size_t pend, const char *base)
+{
+	size_t	blen = strlen(base);
+
+	if (pend + blen + 2 >= pathsz)
+		path = srealloc(path, pathsz = pend + blen + 16);
+	if (pend == 0 || path[pend-1] != '/')
+		path[pend++] = '/';
+	strcpy(&path[pend], base);
+	return pend + blen;
+}
+
+/*
+ * Descend the directory hierarchies given using stdin or arguments
+ * and return file names one per one.
+ */
+static size_t
+ofiles_pax(char **name, size_t *namsiz)
+{
+	static DIR	**dt;
+	static int	dti, dts;
+	static int	*pend;
+	static dev_t	*curdev;
+	static ino_t	*curino;
+	struct stat	st;
+	struct dirent	*dp;
+	const char	*nf;
+	int	i;
+
+	if (dt == NULL) {
+		dt = scalloc(dts = 1, sizeof *dt);
+		pend = scalloc(dts, sizeof *pend);
+		curdev = scalloc(dts, sizeof *curdev);
+		curino = scalloc(dts, sizeof *curino);
+	}
+	for (;;) {
+		if (dti >= 0 && dt[dti] != NULL) {
+			if ((dp = readdir(dt[dti])) != NULL) {
+				if (dp->d_name[0] == '.' &&
+						(dp->d_name[1] == '\0' ||
+						 dp->d_name[1] == '.' &&
+						 dp->d_name[2] == '\0'))
+					continue;
+				if (dti+1 <= dts) {
+					dt = srealloc(dt, sizeof *dt * ++dts);
+					pend = srealloc(pend, sizeof *pend*dts);
+					curdev = srealloc(curdev, sizeof *curdev
+							* dts);
+					curino = srealloc(curino, sizeof *curino
+							* dts);
+				}
+				pend[dti+1] = catpath(pend[dti], dp->d_name);
+				if (pax_Hflag)
+					Lflag = dti < 0;
+				if ((Lflag ? stat : lstat)(path, &st) < 0) {
+					emsg(2, "Error with %s of \"%s\"",
+							lflag? "stat" : "lstat",
+							path);
+					errcnt++;
+				} else if ((st.st_mode&S_IFMT) == S_IFDIR &&
+						(pax_Xflag == 0 ||
+						 curdev[0] == st.st_dev)) {
+					if (Lflag) {
+						for (i = 0; i <= dti; i++)
+							if (st.st_dev ==
+								curdev[i] &&
+								st.st_ino ==
+								curino[i]) {
+							    if (pax ==
+							      PAX_TYPE_PAX2001)
+							     msg(4, 1,
+								"Symbolic link "
+								"loop at "
+								"\"%s\"\n",
+								path);
+							    break;
+							}
+						if (i <= dti)
+							break;
+					}
+					if ((dt[dti+1]=opendir(path)) == NULL) {
+						emsg(2, "Cannot open directory "
+								"\"%s\"", path);
+						errcnt++;
+					} else {
+						dti++;
+						curdev[dti] = st.st_dev;
+						curino[dti] = st.st_ino;
+						continue;
+					}
+				} else
+					break;
+			} else {
+				path[pend[dti]] = '\0';
+				closedir(dt[dti]);
+				dt[dti--] = NULL;
+				if (pax_Hflag)
+					Lflag = dti < 0;
+				break;
+			}
+		} else {
+			if (pax_Hflag)
+				Lflag = 1;
+			while ((nf = nextfile()) != NULL &&
+					(Lflag ? stat : lstat)(nf, &st) < 0) {
+				emsg(2, "Error with stat of \"%s\"", nf);
+				errcnt++;
+			}
+			if (nf == NULL)
+				return 0;
+			dti = 0;
+			if (path)
+				free(path);
+			pend[dti] = strlen(nf);
+			strcpy(path = smalloc(pathsz = pend[dti]+1), nf);
+			if (pax_dflag || (st.st_mode&S_IFMT) != S_IFDIR) {
+				dti = -1;
+				break;
+			}
+			curdev[dti] = st.st_dev;
+			curino[dti] = st.st_ino;
+			if ((dt[dti] = opendir(path)) == NULL) {
+				emsg(2, "Cannot open directory \"%s\"", path);
+				errcnt++;
+			}
+		}
+	}
+	if (*name == NULL || *namsiz < pathsz) {
+		free(*name);
+		*name = smalloc(*namsiz=pathsz);
+	}
+	strcpy(*name, path);
+	return pend[dti+1];
+}
+
+struct	pax_had {
+	struct pax_had	*p_next;
+	const char	*p_name;
+	time_t		p_mtime;
+};
+
+static int	pprime = 7919;
+
+static int
+phash(const char *s)
+{
+	uint32_t	h = 0, g;
+
+	s--;
+	while (*++s) {
+		h = (h << 4) + (*s & 0377);
+		if (g = h & 0xf0000000) {
+			h = h ^ (g >> 24);
+			h = h ^ g;
+		}
+	}
+	return h % pprime;
+}
+
+static int
+plook(const char *name, struct pax_had **pp)
+{
+	static struct pax_had	**pt;
+	uint32_t	h, had;
+
+	if (pt == NULL)
+		pt = scalloc(pprime, sizeof *pt);
+	(*pp) = pt[h = phash(name)];
+	while (*pp != NULL) {
+		if (strcmp((*pp)->p_name, name) == 0)
+			break;
+		*pp = (*pp)->p_next;
+	}
+	had = *pp != NULL;
+	if (*pp == NULL) {
+		*pp = scalloc(1, sizeof **pp);
+		(*pp)->p_name = sstrdup(name);
+		(*pp)->p_next = pt[h];
+		pt[h] = *pp;
+	}
+	return had;
+}
+
+int
+pax_track(const char *name, time_t mtime)
+{
+	struct pax_had	*pp;
+	struct stat	st;
+
+	if (pax_uflag == 0 && (pax_nflag == 0 || patterns))
+		return 1;
+	if (action == 'i' && pax_uflag) {
+		if (lstat(name, &st) == 0 && mtime < st.st_mtime)
+			return 0;
+	}
+	if (action != 'i' || pax_nflag) {
+		if (plook(name, &pp) != 0) {
+			if (action != 'i' && pax_uflag == 0)
+				return 0;
+			if (mtime > pp->p_mtime) {
+				pp->p_mtime = mtime;
+				return 1;
+			}
+			return 0;
+		} else
+			pp->p_mtime = mtime;
+	}
+	return 1;
+}
+
+static void
+prtime_pax(time_t t)
+{
+	char	b[30];
+	time_t	now;
+
+	time(&now);
+	if (t > now || t < now - (6*30*86400))
+		strftime(b, sizeof b, "%b %e  %Y", localtime(&t));
+	else
+		strftime(b, sizeof b, "%b %e %H:%M", localtime(&t));
+	printf(" %s ", b);
+}
+
+struct replacement {
+	regex_t			r_re;
+	const char		*r_rhs;
+	int			r_nbra;
+	enum {
+		REPL_0	= 0,
+		REPL_G	= 1,
+		REPL_P	= 2
+	}			r_flags;
+} *rep;
+
+#define	NBRA	9
+static int	ren, res;
+static int	mb_cur_max;
+
+static wchar_t
+nextc(char **sc, int *np)
+{
+	char	*p = *sc;
+	wchar_t	wcbuf;
+	int	len;
+
+	if (**sc == '\0') {
+		*np = 0;
+		return 0;
+	}
+	if (mb_cur_max == 1 || (**sc&0200) == 0) {
+		*np = 1;
+		return *(*sc)++ & 0377;
+	}
+	if ((len = mbtowc(&wcbuf, p, mb_cur_max)) < 0)
+		msg(3, -2, "Invalid multibyte character for \"-s\" option\n");
+	*np = len;
+	*sc += len;
+	return wcbuf;
+}
+
+static void
+parsesub(char *s)
+{
+	int	len;
+	char	*ps = NULL;
+	wchar_t	seof = nextc(&s, &len);
+	wint_t	c, d;
+	int	nbra = 0;
+	int	reflags;
+
+	if (seof == 0)
+		goto unt;
+	mb_cur_max = MB_CUR_MAX;
+	ps = s;
+	do {
+		if ((c = nextc(&s, &len)) == seof)
+			break;
+		if (c == '\\') {
+			if ((c = nextc(&s, &len)) == '(')
+				nbra++;
+			continue;
+		} else if (c == '[') {
+			d = WEOF;
+			do {
+				if ((c = nextc(&s, &len)) == '\0')
+					continue;
+				if (d == '[' && (c == ':' || c == '.' ||
+							c == '=')) {
+					d = c;
+					do {
+						if ((c=nextc(&s, &len)) == '\0')
+							continue;
+					} while (c != d || *s != ']');
+					nextc(&s, &len);
+					c = WEOF; /* reset d and continue */
+				}
+				d = c;
+			} while (c != ']');
+		}
+	} while (*s != '\0');
+	if (c != seof)
+	unt:	msg(3, -2, "Unterminated argument for \"-s\" option.\n");
+	s[-len] = '\0';
+	if (ren <= res)
+		rep = srealloc(rep, ++res * sizeof *rep);
+	reflags = REG_ANGLES;
+	if (pax >= PAX_TYPE_PAX2001)
+		reflags |= REG_AVOIDNULL;
+	if (regcomp(&rep[ren].r_re, ps, reflags) != 0)
+		msg(3, -2, "Regular expression error in \"-s\" option\n");
+	rep[ren].r_rhs = s;
+	rep[ren].r_nbra = nbra;
+	while ((c = nextc(&s, &len)) != 0) {
+		if (c == '\\')
+			c = nextc(&s, &len);
+		else if (c == seof)
+			break;
+	}
+	rep[ren].r_flags = 0;
+	if (c == seof) {
+		s[-len] = '\0';
+		while ((c = nextc(&s, &len)) != '\0') {
+			switch (c) {
+			case 'g':
+				rep[ren].r_flags |= REPL_G;
+				break;
+			case 'p':
+				rep[ren].r_flags |= REPL_P;
+				break;
+			default:
+				msg(2, 0, "Ignoring unknown -s flag \"%c\"\n",
+						c);
+			}
+		}
+	}
+	ren++;
+}
+
+#define	put(c)	((new = innew+1>=newsize ? srealloc(new, newsize+=32) : new), \
+			new[innew++] = (c))
+
+int
+pax_sname(char **oldp, size_t *olds)
+{
+	char	*new = NULL;
+	size_t	newsize = 0;
+	regmatch_t	bralist[NBRA+1];
+	int	c, i, k, l, y, z;
+	int	innew = 0, ef = 0;
+	char	*inp = *oldp;
+
+	for (z = 0; z < ren; z++) {
+	in:	if (regexec(&rep[z].r_re, inp, NBRA+1, bralist, ef) != 0) {
+			if (ef == 0)
+				continue;
+			goto out;
+		}
+		for (i = 0; i < bralist[0].rm_so; i++)
+			put(inp[i]);
+		k = 0;
+		while (c = rep[z].r_rhs[k++] & 0377) {
+			y = -1;
+			if (c == '&')
+				y = 0;
+			else if (c == '\\') {
+				c = rep[z].r_rhs[k++] & 0377;
+				if (c >= '1' && c < rep[z].r_nbra+'1')
+					y = c - '0';
+			}
+			if (y >= 0)
+				for (l = bralist[y].rm_so; l < bralist[y].rm_eo;
+						l++)
+					put(inp[l]);
+			else
+				put(c);
+		}
+		k = innew;
+		for (i = bralist[0].rm_eo; inp[i]; i++)
+			put(inp[i]);
+		put('\0');
+		if (rep[z].r_flags & REPL_G) {
+			ef = REG_NOTBOL;
+			inp = &inp[bralist[0].rm_eo];
+			innew = k;
+			if (bralist[0].rm_so == bralist[0].rm_eo) {
+				if (inp[0] && (nextc(&inp, &l), inp[0]))
+					innew++;
+				else
+					goto out;
+			}
+			goto in;
+		}
+	out:	if (rep[z].r_flags & REPL_P)
+			fprintf(stderr, "%s >> %s\n", *oldp, new);
+		free(*oldp);
+		*oldp = new;
+		*olds = newsize;
+		return *new != '\0';
+	}
+	return 1;
+}
+
+void
+pax_onexit(void)
+{
+	struct glist	*gp;
+
+	for (gp = patterns; gp; gp = gp->g_nxt) {
+		if (gp->g_art)
+			continue;
+		if (gp->g_gotcha == 0 && (gp->g_nxt == NULL ||
+					gp->g_nxt->g_art == 0 ||
+					gp->g_gotcha == 0)) {
+			msg(3, 0, "Pattern not matched: \"%s\"\n", gp->g_pat);
+			errcnt++;
+		}
+	}
+}

+ 39 - 0
tools/cpio/src/pfmt.c

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)pfmt.c	1.2 (gritter) 9/21/03	*/
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "pfmt.h"
+
+int
+pfmt(FILE *stream, long flags, const char *fmt, ...)
+{
+	va_list	ap;
+	int	i;
+
+	va_start(ap, fmt);
+	i = vpfmt(stream, flags, fmt, ap);
+	va_end(ap);
+	return i;
+}

+ 46 - 0
tools/cpio/src/pfmt.h

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)pfmt.h	1.2 (gritter) 9/21/03	*/
+
+#include <stdio.h>
+
+extern int	pfmt(FILE *stream, long flags, const char *format, ...);
+
+#include <stdarg.h>
+
+extern int	vpfmt(FILE *stream, long flags, const char *format, va_list ap);
+
+#define	MM_HALT		0x00000001
+#define	MM_ERROR	0x00000000
+#define	MM_WARNING	0x00000002
+#define	MM_INFO		0x00000004
+#define	MM_ACTION	0x00000100
+#define	MM_NOSTD	0x00000200
+#define	MM_STD		0x00000000
+#define	MM_NOGET	0x00000400
+#define	MM_GET		0x00000000
+
+extern int	setlabel(const char *label);
+extern int	setuxlabel(const char *label);
+
+#define	setcat(s)	(s)
+#define	gettxt(n, s)	(s)

+ 1 - 0
tools/cpio/src/pfmt_label.c

@@ -0,0 +1 @@
+char	*pfmt_label__;

+ 1211 - 0
tools/cpio/src/regexp.h

@@ -0,0 +1,1211 @@
+/*
+ * Simple Regular Expression functions. Derived from Unix 7th Edition,
+ * /usr/src/cmd/expr.y
+ *
+ * Modified by Gunnar Ritter, Freiburg i. Br., Germany, February 2002.
+ *
+ * Copyright(C) Caldera International Inc. 2001-2002. 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 and documentation 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.
+ *   All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed or owned by Caldera
+ *      International, Inc.
+ *   Neither the name of Caldera International, Inc. nor the names of
+ *    other contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
+ */
+
+#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
+#define	REGEXP_H_USED	__attribute__ ((used))
+#elif defined __GNUC__
+#define	REGEXP_H_USED	__attribute__ ((unused))
+#else
+#define	REGEXP_H_USED
+#endif
+static const char regexp_h_sccsid[] REGEXP_H_USED =
+	"@(#)regexp.sl	1.56 (gritter) 5/29/05";
+
+#if !defined (REGEXP_H_USED_FROM_VI) && !defined (__dietlibc__)
+#define	REGEXP_H_WCHARS
+#endif
+
+#define	CBRA	2
+#define	CCHR	4
+#define	CDOT	8
+#define	CCL	12
+/*	CLNUM	14	used in sed */
+/*	CEND	16	used in sed */
+#define	CDOL	20
+#define	CCEOF	22
+#define	CKET	24
+#define	CBACK	36
+#define	CNCL	40
+#define	CBRC	44
+#define	CLET	48
+#define	CCH1	52
+#define	CCH2	56
+#define	CCH3	60
+
+#define	STAR	01
+#define RNGE	03
+#define	REGEXP_H_LEAST	0100
+
+#ifdef	REGEXP_H_WCHARS
+#define	CMB	0200
+#else	/* !REGEXP_H_WCHARS */
+#define	CMB	0
+#endif	/* !REGEXP_H_WCHARS */
+
+#define	NBRA	9
+
+#define PLACE(c)	ep[c >> 3] |= bittab[c & 07]
+#define ISTHERE(c)	(ep[c >> 3] & bittab[c & 07])
+
+#ifdef	REGEXP_H_WCHARS
+#define	REGEXP_H_IS_THERE(ep, c)	((ep)[c >> 3] & bittab[c & 07])
+#endif
+
+#include	<ctype.h>
+#include	<string.h>
+#include	<limits.h>
+#ifdef	REGEXP_H_WCHARS
+#include	<stdlib.h>
+#include	<wchar.h>
+#include	<wctype.h>
+#endif	/* REGEXP_H_WCHARS */
+
+#define	regexp_h_uletter(c)	(isalpha(c) || (c) == '_')
+#ifdef	REGEXP_H_WCHARS
+#define	regexp_h_wuletter(c)	(iswalpha(c) || (c) == L'_')
+
+/*
+ * Used to allocate memory for the multibyte star algorithm.
+ */
+#ifndef	regexp_h_malloc
+#define	regexp_h_malloc(n)	malloc(n)
+#endif
+#ifndef	regexp_h_free
+#define	regexp_h_free(p)	free(p)
+#endif
+
+/*
+ * Can be predefined to 'inline' to inline some multibyte functions;
+ * may improve performance for files that contain many multibyte
+ * sequences.
+ */
+#ifndef	regexp_h_inline
+#define	regexp_h_inline
+#endif
+
+/*
+ * Mask to determine whether the first byte of a sequence possibly
+ * starts a multibyte character. Set to 0377 to force mbtowc() for
+ * any byte sequence (except 0).
+ */
+#ifndef	REGEXP_H_MASK
+#define	REGEXP_H_MASK	0200
+#endif
+#endif	/* REGEXP_H_WCHARS */
+
+/*
+ * For regexpr.h.
+ */
+#ifndef	regexp_h_static
+#define	regexp_h_static
+#endif
+#ifndef	REGEXP_H_STEP_INIT
+#define	REGEXP_H_STEP_INIT
+#endif
+#ifndef	REGEXP_H_ADVANCE_INIT
+#define	REGEXP_H_ADVANCE_INIT
+#endif
+
+char	*braslist[NBRA];
+char	*braelist[NBRA];
+int	nbra;
+char	*loc1, *loc2, *locs;
+int	sed;
+int	nodelim;
+
+regexp_h_static int	circf;
+regexp_h_static int	low;
+regexp_h_static int	size;
+
+regexp_h_static unsigned char	bittab[] = {
+	1,
+	2,
+	4,
+	8,
+	16,
+	32,
+	64,
+	128
+};
+static int	regexp_h_advance(register const char *lp,
+			register const char *ep);
+static void	regexp_h_getrnge(register const char *str, int least);
+
+static const char	*regexp_h_bol;	/* beginning of input line (for \<) */
+
+#ifdef	REGEXP_H_WCHARS
+static int	regexp_h_wchars;
+static int	regexp_h_mbcurmax;
+
+static const char	*regexp_h_firstwc;	/* location of first
+						   multibyte character
+						   on input line */
+
+#define	regexp_h_getwc(c)	{ \
+	if (regexp_h_wchars) { \
+		char mbbuf[MB_LEN_MAX + 1], *mbptr; \
+		wchar_t wcbuf; \
+		int mb, len; \
+		mbptr = mbbuf; \
+		do { \
+			mb = GETC(); \
+			*mbptr++ = mb; \
+			*mbptr = '\0'; \
+		} while ((len = mbtowc(&wcbuf, mbbuf, regexp_h_mbcurmax)) < 0 \
+			&& mb != eof && mbptr < mbbuf + MB_LEN_MAX); \
+		if (len == -1) \
+			ERROR(67); \
+		c = wcbuf; \
+	} else { \
+		c = GETC(); \
+	} \
+}
+
+#define	regexp_h_store(wc, mb, me)	{ \
+	int len; \
+	if (wc == WEOF) \
+		ERROR(67); \
+	if ((len = me - mb) <= regexp_h_mbcurmax) { \
+		char mt[MB_LEN_MAX]; \
+		if (wctomb(mt, wc) >= len) \
+			ERROR(50); \
+	} \
+	switch (len = wctomb(mb, wc)) { \
+	case -1: \
+		 ERROR(67); \
+	case 0: \
+		mb++; \
+		break; \
+	default: \
+		mb += len; \
+	} \
+}
+
+static regexp_h_inline wint_t
+regexp_h_fetchwc(const char **mb, int islp)
+{
+	wchar_t wc;
+	int len;
+
+	if ((len = mbtowc(&wc, *mb, regexp_h_mbcurmax)) < 0) {
+		(*mb)++;
+		return WEOF;
+	}
+	if (islp && regexp_h_firstwc == NULL)
+		regexp_h_firstwc = *mb;
+	/*if (len == 0) {
+		(*mb)++;
+		return L'\0';
+	} handled in singlebyte code */
+	*mb += len;
+	return wc;
+}
+
+#define	regexp_h_fetch(mb, islp)	((*(mb) & REGEXP_H_MASK) == 0 ? \
+						(*(mb)++&0377): \
+						regexp_h_fetchwc(&(mb), islp))
+
+static regexp_h_inline wint_t
+regexp_h_showwc(const char *mb)
+{
+	wchar_t wc;
+
+	if (mbtowc(&wc, mb, regexp_h_mbcurmax) < 0)
+		return WEOF;
+	return wc;
+}
+
+#define	regexp_h_show(mb)	((*(mb) & REGEXP_H_MASK) == 0 ? (*(mb)&0377): \
+					regexp_h_showwc(mb))
+
+/*
+ * Return the character immediately preceding mb. Since no byte is
+ * required to be the first byte of a character, the longest multibyte
+ * character ending at &[mb-1] is searched.
+ */
+static regexp_h_inline wint_t
+regexp_h_previous(const char *mb)
+{
+	const char *p = mb;
+	wchar_t wc, lastwc = WEOF;
+	int len, max = 0;
+
+	if (regexp_h_firstwc == NULL || mb <= regexp_h_firstwc)
+		return (mb > regexp_h_bol ? (mb[-1] & 0377) : WEOF);
+	while (p-- > regexp_h_bol) {
+		mbtowc(NULL, NULL, 0);
+		if ((len = mbtowc(&wc, p, mb - p)) >= 0) {
+			if (len < max || len < mb - p)
+				break;
+			max = len;
+			lastwc = wc;
+		} else if (len < 0 && max > 0)
+			break;
+	}
+	return lastwc;
+}
+
+#define	regexp_h_cclass(set, c, af)	\
+	((c) == 0 || (c) == WEOF ? 0 : ( \
+		((c) > 0177) ? \
+			regexp_h_cclass_wc(set, c, af) : ( \
+				REGEXP_H_IS_THERE((set)+1, (c)) ? (af) : !(af) \
+			) \
+		) \
+	)
+
+static regexp_h_inline int
+regexp_h_cclass_wc(const char *set, register wint_t c, int af)
+{
+	register wint_t wc, wl = WEOF;
+	const char *end;
+
+	end = &set[18] + set[0] - 1;
+	set += 17;
+	while (set < end) {
+		wc = regexp_h_fetch(set, 0);
+#ifdef	REGEXP_H_VI_BACKSLASH
+		if (wc == '\\' && set < end &&
+				(*set == ']' || *set == '-' ||
+				 *set == '^' || *set == '\\')) {
+			wc = regexp_h_fetch(set, 0);
+		} else
+#endif	/* REGEXP_H_VI_BACKSLASH */
+		if (wc == '-' && wl != WEOF && set < end) {
+			wc = regexp_h_fetch(set, 0);
+#ifdef	REGEXP_H_VI_BACKSLASH
+			if (wc == '\\' && set < end &&
+					(*set == ']' || *set == '-' ||
+					 *set == '^' || *set == '\\')) {
+				wc = regexp_h_fetch(set, 0);
+			}
+#endif	/* REGEXP_H_VI_BACKSLASH */
+			if (c > wl && c < wc)
+				return af;
+		}
+		if (c == wc)
+			return af;
+		wl = wc;
+	}
+	return !af;
+}
+#else	/* !REGEXP_H_WCHARS */
+#define	regexp_h_wchars		0
+#define	regexp_h_getwc(c)	{ c = GETC(); }
+#endif	/* !REGEXP_H_WCHARS */
+
+regexp_h_static char *
+compile(char *instring, char *ep, const char *endbuf, int seof)
+{
+	INIT	/* Dependent declarations and initializations */
+	register int c;
+	register int eof = seof;
+	char *lastep = instring;
+	int cclcnt;
+	char bracket[NBRA], *bracketp;
+	int closed;
+	char neg;
+	int lc;
+	int i, cflg;
+
+#ifdef	REGEXP_H_WCHARS
+	char *eq;
+	regexp_h_mbcurmax = MB_CUR_MAX;
+	regexp_h_wchars = regexp_h_mbcurmax > 1 ? CMB : 0;
+#endif
+	lastep = 0;
+	bracketp = bracket;
+	if((c = GETC()) == eof || c == '\n') {
+		if (c == '\n') {
+			UNGETC(c);
+			nodelim = 1;
+		}
+		if(*ep == 0 && !sed)
+			ERROR(41);
+		if (bracketp > bracket)
+			ERROR(42);
+		RETURN(ep);
+	}
+	circf = closed = nbra = 0;
+	if (c == '^')
+		circf++;
+	else
+		UNGETC(c);
+	for (;;) {
+		if (ep >= endbuf)
+			ERROR(50);
+		regexp_h_getwc(c);
+		if(c != '*' && ((c != '\\') || (PEEKC() != '{')))
+			lastep = ep;
+		if (c == eof) {
+			*ep++ = CCEOF;
+			if (bracketp > bracket)
+				ERROR(42);
+			RETURN(ep);
+		}
+		switch (c) {
+
+		case '.':
+			*ep++ = CDOT|regexp_h_wchars;
+			continue;
+
+		case '\n':
+			if (sed == 0) {
+				UNGETC(c);
+				*ep++ = CCEOF;
+				nodelim = 1;
+				RETURN(ep);
+			}
+			ERROR(36);
+		case '*':
+			if (lastep==0 || *lastep==CBRA || *lastep==CKET ||
+					*lastep==(CBRC|regexp_h_wchars) ||
+					*lastep==(CLET|regexp_h_wchars))
+				goto defchar;
+			*lastep |= STAR;
+			continue;
+
+		case '$':
+			if(PEEKC() != eof)
+				goto defchar;
+			*ep++ = CDOL;
+			continue;
+
+		case '[':
+#ifdef	REGEXP_H_WCHARS
+			if (regexp_h_wchars == 0) {
+#endif
+				if(&ep[33] >= endbuf)
+					ERROR(50);
+
+				*ep++ = CCL;
+				lc = 0;
+				for(i = 0; i < 32; i++)
+					ep[i] = 0;
+
+				neg = 0;
+				if((c = GETC()) == '^') {
+					neg = 1;
+					c = GETC();
+				}
+
+				do {
+					c &= 0377;
+					if(c == '\0' || c == '\n')
+						ERROR(49);
+#ifdef	REGEXP_H_VI_BACKSLASH
+					if(c == '\\' && ((c = PEEKC()) == ']' ||
+							c == '-' || c == '^' ||
+							c == '\\')) {
+						c = GETC();
+						c &= 0377;
+					} else
+#endif	/* REGEXP_H_VI_BACKSLASH */
+					if(c == '-' && lc != 0) {
+						if ((c = GETC()) == ']') {
+							PLACE('-');
+							break;
+						}
+#ifdef	REGEXP_H_VI_BACKSLASH
+						if(c == '\\' &&
+							((c = PEEKC()) == ']' ||
+								c == '-' ||
+								c == '^' ||
+								c == '\\'))
+							c = GETC();
+#endif	/* REGEXP_H_VI_BACKSLASH */
+						c &= 0377;
+						while(lc < c) {
+							PLACE(lc);
+							lc++;
+						}
+					}
+					lc = c;
+					PLACE(c);
+				} while((c = GETC()) != ']');
+				if(neg) {
+					for(cclcnt = 0; cclcnt < 32; cclcnt++)
+						ep[cclcnt] ^= 0377;
+					ep[0] &= 0376;
+				}
+
+				ep += 32;
+#ifdef	REGEXP_H_WCHARS
+			} else {
+				if (&ep[18] >= endbuf)
+					ERROR(50);
+				*ep++ = CCL|CMB;
+				*ep++ = 0;
+				lc = 0;
+				for (i = 0; i < 16; i++)
+					ep[i] = 0;
+				eq = &ep[16];
+				regexp_h_getwc(c);
+				if (c == L'^') {
+					regexp_h_getwc(c);
+					ep[-2] = CNCL|CMB;
+				}
+				do {
+					if (c == '\0' || c == '\n')
+						ERROR(49);
+#ifdef	REGEXP_H_VI_BACKSLASH
+					if(c == '\\' && ((c = PEEKC()) == ']' ||
+							c == '-' || c == '^' ||
+							c == '\\')) {
+						regexp_h_store(c, eq, endbuf);
+						regexp_h_getwc(c);
+					} else
+#endif	/* REGEXP_H_VI_BACKSLASH */
+					if (c == '-' && lc != 0 && lc <= 0177) {
+						regexp_h_store(c, eq, endbuf);
+						regexp_h_getwc(c);
+						if (c == ']') {
+							PLACE('-');
+							break;
+						}
+#ifdef	REGEXP_H_VI_BACKSLASH
+						if(c == '\\' &&
+							((c = PEEKC()) == ']' ||
+								c == '-' ||
+								c == '^' ||
+								c == '\\')) {
+							regexp_h_store(c, eq,
+								endbuf);
+							regexp_h_getwc(c);
+						}
+#endif	/* REGEXP_H_VI_BACKSLASH */
+						while (lc < (c & 0177)) {
+							PLACE(lc);
+							lc++;
+						}
+					}
+					lc = c;
+					if (c <= 0177)
+						PLACE(c);
+					regexp_h_store(c, eq, endbuf);
+					regexp_h_getwc(c);
+				} while (c != L']');
+				if ((i = eq - &ep[16]) > 255)
+					ERROR(50);
+				lastep[1] = i;
+				ep = eq;
+			}
+#endif	/* REGEXP_H_WCHARS */
+
+			continue;
+
+		case '\\':
+			regexp_h_getwc(c);
+			switch(c) {
+
+			case '(':
+				if(nbra >= NBRA)
+					ERROR(43);
+				*bracketp++ = nbra;
+				*ep++ = CBRA;
+				*ep++ = nbra++;
+				continue;
+
+			case ')':
+				if(bracketp <= bracket)
+					ERROR(42);
+				*ep++ = CKET;
+				*ep++ = *--bracketp;
+				closed++;
+				continue;
+
+			case '<':
+				*ep++ = CBRC|regexp_h_wchars;
+				continue;
+
+			case '>':
+				*ep++ = CLET|regexp_h_wchars;
+				continue;
+
+			case '{':
+				if(lastep == (char *) (0))
+					goto defchar;
+				*lastep |= RNGE;
+				cflg = 0;
+			nlim:
+				c = GETC();
+				i = 0;
+				do {
+					if ('0' <= c && c <= '9')
+						i = 10 * i + c - '0';
+					else
+						ERROR(16);
+				} while(((c = GETC()) != '\\') && (c != ','));
+				if (i > 255)
+					ERROR(11);
+				*ep++ = i;
+				if (c == ',') {
+					if(cflg++)
+						ERROR(44);
+					if((c = GETC()) == '\\') {
+						*ep++ = (char)255;
+						*lastep |= REGEXP_H_LEAST;
+					} else {
+						UNGETC(c);
+						goto nlim; /* get 2'nd number */
+					}
+				}
+				if(GETC() != '}')
+					ERROR(45);
+				if(!cflg)	/* one number */
+					*ep++ = i;
+				else if((ep[-1] & 0377) < (ep[-2] & 0377))
+					ERROR(46);
+				continue;
+
+			case '\n':
+				ERROR(36);
+
+			case 'n':
+				c = '\n';
+				goto defchar;
+
+			default:
+				if(c >= '1' && c <= '9') {
+					if((c -= '1') >= closed)
+						ERROR(25);
+					*ep++ = CBACK;
+					*ep++ = c;
+					continue;
+				}
+			}
+			/* Drop through to default to use \ to turn off special chars */
+
+		defchar:
+		default:
+			lastep = ep;
+#ifdef	REGEXP_H_WCHARS
+			if (regexp_h_wchars == 0) {
+#endif
+				*ep++ = CCHR;
+				*ep++ = c;
+#ifdef	REGEXP_H_WCHARS
+			} else {
+				char	mbbuf[MB_LEN_MAX];
+
+				switch (wctomb(mbbuf, c)) {
+				case 1: *ep++ = CCH1;
+					break;
+				case 2:	*ep++ = CCH2;
+					break;
+				case 3:	*ep++ = CCH3;
+					break;
+				default:
+					*ep++ = CCHR|CMB;
+				}
+				regexp_h_store(c, ep, endbuf);
+			}
+#endif	/* REGEXP_H_WCHARS */
+		}
+	}
+}
+
+int
+step(const char *p1, const char *p2)
+{
+	register int c;
+#ifdef	REGEXP_H_WCHARS
+	register int d;
+#endif	/* REGEXP_H_WCHARS */
+
+	REGEXP_H_STEP_INIT	/* get circf */
+	regexp_h_bol = p1;
+#ifdef	REGEXP_H_WCHARS
+	regexp_h_firstwc = NULL;
+#endif	/* REGEXP_H_WCHARS */
+	if (circf) {
+		loc1 = (char *)p1;
+		return(regexp_h_advance(p1, p2));
+	}
+	/* fast check for first character */
+	if (*p2==CCHR) {
+		c = p2[1] & 0377;
+		do {
+			if ((*p1 & 0377) != c)
+				continue;
+			if (regexp_h_advance(p1, p2)) {
+				loc1 = (char *)p1;
+				return(1);
+			}
+		} while (*p1++);
+		return(0);
+	}
+#ifdef	REGEXP_H_WCHARS
+	else if (*p2==CCH1) {
+		do {
+			if (p1[0] == p2[1] && regexp_h_advance(p1, p2)) {
+				loc1 = (char *)p1;
+				return(1);
+			}
+			c = regexp_h_fetch(p1, 1);
+		} while (c);
+		return(0);
+	} else if (*p2==CCH2) {
+		do {
+			if (p1[0] == p2[1] && p1[1] == p2[2] &&
+					regexp_h_advance(p1, p2)) {
+				loc1 = (char *)p1;
+				return(1);
+			}
+			c = regexp_h_fetch(p1, 1);
+		} while (c);
+		return(0);
+	} else if (*p2==CCH3) {
+		do {
+			if (p1[0] == p2[1] && p1[1] == p2[2] && p1[2] == p2[3]&&
+					regexp_h_advance(p1, p2)) {
+				loc1 = (char *)p1;
+				return(1);
+			}
+			c = regexp_h_fetch(p1, 1);
+		} while (c);
+		return(0);
+	} else if ((*p2&0377)==(CCHR|CMB)) {
+		d = regexp_h_fetch(p2, 0);
+		do {
+			c = regexp_h_fetch(p1, 1);
+			if (c == d && regexp_h_advance(p1, p2)) {
+				loc1 = (char *)p1;
+				return(1);
+			}
+		} while(c);
+		return(0);
+	}
+		/* regular algorithm */
+	if (regexp_h_wchars)
+		do {
+			if (regexp_h_advance(p1, p2)) {
+				loc1 = (char *)p1;
+				return(1);
+			}
+			c = regexp_h_fetch(p1, 1);
+		} while (c);
+	else
+#endif	/* REGEXP_H_WCHARS */
+		do {
+			if (regexp_h_advance(p1, p2)) {
+				loc1 = (char *)p1;
+				return(1);
+			}
+		} while (*p1++);
+	return(0);
+}
+
+#ifdef	REGEXP_H_WCHARS
+/*
+ * It is painfully slow to read character-wise backwards in a
+ * multibyte string (see regexp_h_previous() above). For the star
+ * algorithm, we therefore keep track of every character as it is
+ * read in forward direction.
+ *
+ * Don't use alloca() for stack blocks since there is no measurable
+ * speedup and huge amounts of memory are used up for long input
+ * lines.
+ */
+#ifndef	REGEXP_H_STAKBLOK
+#define	REGEXP_H_STAKBLOK	1000
+#endif
+
+struct	regexp_h_stack {
+	struct regexp_h_stack	*s_nxt;
+	struct regexp_h_stack	*s_prv;
+	const char	*s_ptr[REGEXP_H_STAKBLOK];
+};
+
+#define	regexp_h_push(sb, sp, sc, lp)	(regexp_h_wchars ? \
+			regexp_h_pushwc(sb, sp, sc, lp) : (void)0)
+
+static regexp_h_inline void
+regexp_h_pushwc(struct regexp_h_stack **sb,
+		struct regexp_h_stack **sp,
+		const char ***sc, const char *lp)
+{
+	if (regexp_h_firstwc == NULL || lp < regexp_h_firstwc)
+		return;
+	if (*sb == NULL) {
+		if ((*sb = regexp_h_malloc(sizeof **sb)) == NULL)
+			return;
+		(*sb)->s_nxt = (*sb)->s_prv = NULL;
+		*sp = *sb;
+		*sc = &(*sb)->s_ptr[0];
+	} else if (*sc >= &(*sp)->s_ptr[REGEXP_H_STAKBLOK]) {
+		if ((*sp)->s_nxt == NULL) {
+			struct regexp_h_stack	*bq;
+
+			if ((bq = regexp_h_malloc(sizeof *bq)) == NULL)
+				return;
+			bq->s_nxt = NULL;
+			bq->s_prv = *sp;
+			(*sp)->s_nxt = bq;
+			*sp = bq;
+		} else
+			*sp = (*sp)->s_nxt;
+		*sc = &(*sp)->s_ptr[0];
+	}
+	*(*sc)++ = lp;
+}
+
+static regexp_h_inline const char *
+regexp_h_pop(struct regexp_h_stack **sb, struct regexp_h_stack **sp,
+		const char ***sc, const char *lp)
+{
+	if (regexp_h_firstwc == NULL || lp <= regexp_h_firstwc)
+		return &lp[-1];
+	if (*sp == NULL)
+		return regexp_h_firstwc;
+	if (*sc == &(*sp)->s_ptr[0]) {
+		if ((*sp)->s_prv == NULL) {
+			regexp_h_free(*sp);
+			*sp = NULL;
+			*sb = NULL;
+			return regexp_h_firstwc;
+		}
+		*sp = (*sp)->s_prv;
+		regexp_h_free((*sp)->s_nxt);
+		(*sp)->s_nxt = NULL ;
+		*sc = &(*sp)->s_ptr[REGEXP_H_STAKBLOK];
+	}
+	return *(--(*sc));
+}
+
+static void
+regexp_h_zerostak(struct regexp_h_stack **sb, struct regexp_h_stack **sp)
+{
+	for (*sp = *sb; *sp && (*sp)->s_nxt; *sp = (*sp)->s_nxt)
+		if ((*sp)->s_prv)
+			regexp_h_free((*sp)->s_prv);
+	if (*sp) {
+		if ((*sp)->s_prv)
+			regexp_h_free((*sp)->s_prv);
+		regexp_h_free(*sp);
+	}
+	*sp = *sb = NULL;
+}
+#else	/* !REGEXP_H_WCHARS */
+#define	regexp_h_push(sb, sp, sc, lp)
+#endif	/* !REGEXP_H_WCHARS */
+
+static int
+regexp_h_advance(const char *lp, const char *ep)
+{
+	register const char *curlp;
+	int c, least;
+#ifdef	REGEXP_H_WCHARS
+	int d;
+	struct regexp_h_stack	*sb = NULL, *sp = NULL;
+	const char	**sc;
+#endif	/* REGEXP_H_WCHARS */
+	char *bbeg;
+	int ct;
+
+	for (;;) switch (least = *ep++ & 0377, least & ~REGEXP_H_LEAST) {
+
+	case CCHR:
+#ifdef	REGEXP_H_WCHARS
+	case CCH1:
+#endif
+		if (*ep++ == *lp++)
+			continue;
+		return(0);
+
+#ifdef	REGEXP_H_WCHARS
+	case CCHR|CMB:
+		if (regexp_h_fetch(ep, 0) == regexp_h_fetch(lp, 1))
+			continue;
+		return(0);
+
+	case CCH2:
+		if (ep[0] == lp[0] && ep[1] == lp[1]) {
+			ep += 2, lp += 2;
+			continue;
+		}
+		return(0);
+
+	case CCH3:
+		if (ep[0] == lp[0] && ep[1] == lp[1] && ep[2] == lp[2]) {
+			ep += 3, lp += 3;
+			continue;
+		}
+		return(0);
+#endif	/* REGEXP_H_WCHARS */
+
+	case CDOT:
+		if (*lp++)
+			continue;
+		return(0);
+#ifdef	REGEXP_H_WCHARS
+	case CDOT|CMB:
+		if ((c = regexp_h_fetch(lp, 1)) != L'\0' && c != WEOF)
+			continue;
+		return(0);
+#endif	/* REGEXP_H_WCHARS */
+
+	case CDOL:
+		if (*lp==0)
+			continue;
+		return(0);
+
+	case CCEOF:
+		loc2 = (char *)lp;
+		return(1);
+
+	case CCL:
+		c = *lp++ & 0377;
+		if(ISTHERE(c)) {
+			ep += 32;
+			continue;
+		}
+		return(0);
+
+#ifdef	REGEXP_H_WCHARS
+	case CCL|CMB:
+	case CNCL|CMB:
+		c = regexp_h_fetch(lp, 1);
+		if (regexp_h_cclass(ep, c, (ep[-1] & 0377) == (CCL|CMB))) {
+			ep += (*ep & 0377) + 17;
+			continue;
+		}
+		return 0;
+#endif	/* REGEXP_H_WCHARS */
+
+	case CBRA:
+		braslist[*ep++ & 0377] = (char *)lp;
+		continue;
+
+	case CKET:
+		braelist[*ep++ & 0377] = (char *)lp;
+		continue;
+
+	case CBRC:
+		if (lp == regexp_h_bol && locs == NULL)
+			continue;
+		if ((isdigit(lp[0] & 0377) || regexp_h_uletter(lp[0] & 0377))
+				&& !regexp_h_uletter(lp[-1] & 0377)
+				&& !isdigit(lp[-1] & 0377))
+			continue;
+		return(0);
+
+#ifdef	REGEXP_H_WCHARS
+	case CBRC|CMB:
+		c = regexp_h_show(lp);
+		d = regexp_h_previous(lp);
+		if ((iswdigit(c) || regexp_h_wuletter(c))
+				&& !regexp_h_wuletter(d)
+				&& !iswdigit(d))
+			continue;
+		return(0);
+#endif	/* REGEXP_H_WCHARS */
+
+	case CLET:
+		if (!regexp_h_uletter(lp[0] & 0377) && !isdigit(lp[0] & 0377))
+			continue;
+		return(0);
+
+#ifdef	REGEXP_H_WCHARS
+	case CLET|CMB:
+		c = regexp_h_show(lp);
+		if (!regexp_h_wuletter(c) && !iswdigit(c))
+			continue;
+		return(0);
+#endif	/* REGEXP_H_WCHARS */
+
+	case CCHR|RNGE:
+		c = *ep++;
+		regexp_h_getrnge(ep, least);
+		while(low--)
+			if(*lp++ != c)
+				return(0);
+		curlp = lp;
+		while(size--) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			if(*lp++ != c)
+				break;
+		}
+		if(size < 0) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			lp++;
+		}
+		ep += 2;
+		goto star;
+
+#ifdef	REGEXP_H_WCHARS
+	case CCHR|RNGE|CMB:
+	case CCH1|RNGE:
+	case CCH2|RNGE:
+	case CCH3|RNGE:
+		c = regexp_h_fetch(ep, 0);
+		regexp_h_getrnge(ep, least);
+		while (low--)
+			if (regexp_h_fetch(lp, 1) != c)
+				return 0;
+		curlp = lp;
+		while (size--) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			if (regexp_h_fetch(lp, 1) != c)
+				break;
+		}
+		if(size < 0) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			regexp_h_fetch(lp, 1);
+		}
+		ep += 2;
+		goto star;
+#endif	/* REGEXP_H_WCHARS */
+
+	case CDOT|RNGE:
+		regexp_h_getrnge(ep, least);
+		while(low--)
+			if(*lp++ == '\0')
+				return(0);
+		curlp = lp;
+		while(size--) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			if(*lp++ == '\0')
+				break;
+		}
+		if(size < 0) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			lp++;
+		}
+		ep += 2;
+		goto star;
+
+#ifdef	REGEXP_H_WCHARS
+	case CDOT|RNGE|CMB:
+		regexp_h_getrnge(ep, least);
+		while (low--)
+			if ((c = regexp_h_fetch(lp, 1)) == L'\0' || c == WEOF)
+				return 0;
+		curlp = lp;
+		while (size--) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			if ((c = regexp_h_fetch(lp, 1)) == L'\0' || c == WEOF)
+				break;
+		}
+		if (size < 0) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			regexp_h_fetch(lp, 1);
+		}
+		ep += 2;
+		goto star;
+#endif	/* REGEXP_H_WCHARS */
+
+	case CCL|RNGE:
+		regexp_h_getrnge(ep + 32, least);
+		while(low--) {
+			c = *lp++ & 0377;
+			if(!ISTHERE(c))
+				return(0);
+		}
+		curlp = lp;
+		while(size--) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			c = *lp++ & 0377;
+			if(!ISTHERE(c))
+				break;
+		}
+		if(size < 0) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			lp++;
+		}
+		ep += 34;		/* 32 + 2 */
+		goto star;
+
+#ifdef	REGEXP_H_WCHARS
+	case CCL|RNGE|CMB:
+	case CNCL|RNGE|CMB:
+		regexp_h_getrnge(ep + (*ep & 0377) + 17, least);
+		while (low--) {
+			c = regexp_h_fetch(lp, 1);
+			if (!regexp_h_cclass(ep, c,
+					(ep[-1] & 0377 & ~REGEXP_H_LEAST)
+					== (CCL|RNGE|CMB)))
+				return 0;
+		}
+		curlp = lp;
+		while (size--) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			c = regexp_h_fetch(lp, 1);
+			if (!regexp_h_cclass(ep, c,
+					(ep[-1] & 0377 & ~REGEXP_H_LEAST)
+					== (CCL|RNGE|CMB)))
+				break;
+		}
+		if (size < 0) {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			regexp_h_fetch(lp, 1);
+		}
+		ep += (*ep & 0377) + 19;
+		goto star;
+#endif	/* REGEXP_H_WCHARS */
+
+	case CBACK:
+		bbeg = braslist[*ep & 0377];
+		ct = braelist[*ep++ & 0377] - bbeg;
+
+		if(strncmp(bbeg, lp, ct) == 0) {
+			lp += ct;
+			continue;
+		}
+		return(0);
+
+	case CBACK|STAR:
+		bbeg = braslist[*ep & 0377];
+		ct = braelist[*ep++ & 0377] - bbeg;
+		curlp = lp;
+		while(strncmp(bbeg, lp, ct) == 0)
+			lp += ct;
+
+		while(lp >= curlp) {
+			if(regexp_h_advance(lp, ep))	return(1);
+			lp -= ct;
+		}
+		return(0);
+
+
+	case CDOT|STAR:
+		curlp = lp;
+		do
+			regexp_h_push(&sb, &sp, &sc, lp);
+		while (*lp++);
+		goto star;
+
+#ifdef	REGEXP_H_WCHARS
+	case CDOT|STAR|CMB:
+		curlp = lp;
+		do
+			regexp_h_push(&sb, &sp, &sc, lp);
+		while ((c = regexp_h_fetch(lp, 1)) != L'\0' && c != WEOF);
+		goto star;
+#endif	/* REGEXP_H_WCHARS */
+
+	case CCHR|STAR:
+		curlp = lp;
+		do
+			regexp_h_push(&sb, &sp, &sc, lp);
+		while (*lp++ == *ep);
+		ep++;
+		goto star;
+
+#ifdef	REGEXP_H_WCHARS
+	case CCHR|STAR|CMB:
+	case CCH1|STAR:
+	case CCH2|STAR:
+	case CCH3|STAR:
+		curlp = lp;
+		d = regexp_h_fetch(ep, 0);
+		do
+			regexp_h_push(&sb, &sp, &sc, lp);
+		while (regexp_h_fetch(lp, 1) == d);
+		goto star;
+#endif	/* REGEXP_H_WCHARS */
+
+	case CCL|STAR:
+		curlp = lp;
+		do {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			c = *lp++ & 0377;
+		} while(ISTHERE(c));
+		ep += 32;
+		goto star;
+
+#ifdef	REGEXP_H_WCHARS
+	case CCL|STAR|CMB:
+	case CNCL|STAR|CMB:
+		curlp = lp;
+		do {
+			regexp_h_push(&sb, &sp, &sc, lp);
+			c = regexp_h_fetch(lp, 1);
+		} while (regexp_h_cclass(ep, c, (ep[-1] & 0377)
+					== (CCL|STAR|CMB)));
+		ep += (*ep & 0377) + 17;
+		goto star;
+#endif	/* REGEXP_H_WCHARS */
+
+	star:
+#ifdef	REGEXP_H_WCHARS
+		if (regexp_h_wchars == 0) {
+#endif
+			do {
+				if(--lp == locs)
+					break;
+				if (regexp_h_advance(lp, ep))
+					return(1);
+			} while (lp > curlp);
+#ifdef	REGEXP_H_WCHARS
+		} else {
+			do {
+				lp = regexp_h_pop(&sb, &sp, &sc, lp);
+				if (lp <= locs)
+					break;
+				if (regexp_h_advance(lp, ep)) {
+					regexp_h_zerostak(&sb, &sp);
+					return(1);
+				}
+			} while (lp > curlp);
+			regexp_h_zerostak(&sb, &sp);
+		}
+#endif	/* REGEXP_H_WCHARS */
+		return(0);
+
+	}
+}
+
+static void
+regexp_h_getrnge(register const char *str, int least)
+{
+	low = *str++ & 0377;
+	size = least & REGEXP_H_LEAST ? /*20000*/INT_MAX : (*str & 0377) - low;
+}
+
+int
+advance(const char *lp, const char *ep)
+{
+	REGEXP_H_ADVANCE_INIT	/* skip past circf */
+	regexp_h_bol = lp;
+#ifdef	REGEXP_H_WCHARS
+	regexp_h_firstwc = NULL;
+#endif	/* REGEXP_H_WCHARS */
+	return regexp_h_advance(lp, ep);
+}

+ 90 - 0
tools/cpio/src/regexpr.c

@@ -0,0 +1,90 @@
+/*
+ * Simple Regular Expression functions. Derived from Unix 7th Edition,
+ * /usr/src/cmd/expr.y
+ *
+ * Modified by Gunnar Ritter, Freiburg i. Br., Germany, January 2003.
+ *
+ * Copyright(C) Caldera International Inc. 2001-2002. 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 and documentation 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.
+ *   All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed or owned by Caldera
+ *      International, Inc.
+ *   Neither the name of Caldera International, Inc. nor the names of
+ *    other contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
+ */
+
+/*	Sccsid @(#)regexpr.c	1.8 (gritter) 10/13/04	*/
+
+#include	<stdlib.h>
+#include	"regexpr.h"
+
+int	regerrno, reglength;
+static int	circf;
+
+static char	*regexpr_compile(char *, char *, const char *, int);
+
+char *
+compile(const char *instring, char *ep, char *endbuf)
+{
+	char	*cp;
+	int	sz = 0;
+
+	if (ep == 0) {
+		for (cp = (char *)instring; *cp != '\0'; cp++)
+			if (*cp == '[')
+				sz += 32;
+		sz += 2 * (cp - instring) + 5;
+		if ((ep = malloc(sz)) == 0) {
+			regerrno = 11;
+			return 0;
+		}
+		endbuf = &ep[sz];
+		ep[1] = '\0';
+	}
+	if ((cp=regexpr_compile((char *)instring, &ep[1], endbuf, '\0')) == 0) {
+		if (sz)
+			free(ep);
+		return 0;
+	}
+	ep[0] = circf;
+	reglength = cp - ep;
+	return sz ? ep : cp;
+}
+
+#define	INIT			register char *sp = instring;
+#define	GETC()			(*sp++)
+#define	PEEKC()			(*sp)
+#define	UNGETC(c)		(--sp)
+#define	RETURN(c)		return (c);
+#define	ERROR(c)		{ regerrno = c; return 0; }
+
+#define	compile(a, b, c, d)	regexpr_compile(a, b, c, d)
+#define	regexp_h_static		static
+#define	REGEXP_H_STEP_INIT	circf = *p2++;
+#define	REGEXP_H_ADVANCE_INIT	circf = *ep++;
+
+#include	"regexp.h"

+ 53 - 0
tools/cpio/src/regexpr.h

@@ -0,0 +1,53 @@
+/*
+ * Simple Regular Expression functions. Derived from Unix 7th Edition,
+ * /usr/src/cmd/expr.y
+ *
+ * Modified by Gunnar Ritter, Freiburg i. Br., Germany, January 2003.
+ *
+ * Copyright(C) Caldera International Inc. 2001-2002. 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 and documentation 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.
+ *   All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed or owned by Caldera
+ *      International, Inc.
+ *   Neither the name of Caldera International, Inc. nor the names of
+ *    other contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
+ */
+
+/*	Sccsid @(#)regexpr.h	1.2 (gritter) 1/11/03	*/
+
+#define	NBRA	9
+
+extern char	*braslist[NBRA];
+extern char	*braelist[NBRA];
+extern int	nbra;
+extern int	regerrno, reglength;
+extern char	*loc1, *loc2, *locs;
+extern int	sed;
+
+extern char	*compile(const char *, char *, char *);
+extern int	step(const char *, const char *);
+extern int	advance(const char *, const char *);

+ 40 - 0
tools/cpio/src/setlabel.c

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)setlabel.c	1.1 (gritter) 9/21/03	*/
+
+extern char	*pfmt_label__;
+
+int
+setlabel(const char *s)
+{
+	static char	lbuf[26];
+	char	*lp;
+
+	if (s && s[0]) {
+		for (lp = lbuf; *s && lp < &lbuf[sizeof lbuf-1]; s++, lp++)
+			*lp = *s;
+		*lp = '\0';
+		pfmt_label__ = lbuf;
+	} else
+		pfmt_label__ = 0;
+	return 0;
+}

+ 47 - 0
tools/cpio/src/setuxlabel.c

@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)setuxlabel.c	1.1 (gritter) 9/21/03	*/
+
+#include	"msgselect.h"
+
+extern char	*pfmt_label__;
+
+int
+setuxlabel(const char *s)
+{
+	static char	lbuf[msgselect(29,26)];
+	char	*lp, *mp;
+
+	if (s && s[0]) {
+		lp = lbuf;
+		mp = msgselect("UX:","");
+		while (*mp)
+			*lp++ = *mp++;
+		lbuf[0] = 'U', lbuf[1] = 'X', lbuf[2] = ':';
+		while (*s && lp < &lbuf[sizeof lbuf-1])
+			*lp++ = *s++;
+		*lp = '\0';
+		pfmt_label__ = lbuf;
+	} else
+		pfmt_label__ = 0;
+	return 0;
+}

+ 99 - 0
tools/cpio/src/sfile.c

@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)sfile.c	1.9 (gritter) 6/7/04	*/
+
+#ifdef	__linux__
+#undef	_FILE_OFFSET_BITS
+
+#include	<sys/types.h>
+#include	<sys/sendfile.h>
+#include	<sys/stat.h>
+#include	<unistd.h>
+#include	<limits.h>
+#include	<errno.h>
+#include	"sfile.h"
+
+long long
+sfile(int dfd, int sfd, mode_t mode, long long count)
+{
+	static int	enosys, einval, success;
+	off_t	offset;
+	ssize_t	sent, total;
+	extern void	writerr(void *, int, int);
+	/*
+	 * A process is not interruptible while executing a sendfile()
+	 * system call. So it is not advisable to to send an entire
+	 * file with one call; it is sent in parts so signals can
+	 * be delivered in between.
+	 */
+	const ssize_t	chunk = 196608;
+
+	/*
+	 * If a previous call returned ENOSYS, the operating system does
+	 * not support sendfile() at all and it makes no sense to try it
+	 * again.
+	 *
+	 * If a previous call returned EINVAL and there was no successful
+	 * call yet, it is very likely that this is a permanent error
+	 * condition (on Linux 2.6.0-test4, sendfile() may be used for
+	 * socket targets only; older versions don't support tmpfs as
+	 * source file system etc.).
+	 */
+	if (enosys || !success && einval ||
+			(mode&S_IFMT) != S_IFREG || count > SSIZE_MAX)
+		return 0;
+	offset = lseek(sfd, 0, SEEK_CUR);
+	sent = 0, total = 0;
+	while (count > 0 && (sent = sendfile(dfd, sfd, &offset,
+					count > chunk ? chunk : count)) > 0) {
+		count -= sent, total += sent;
+	}
+	if (total && lseek(sfd, offset, SEEK_SET) == (off_t)-1)
+		return -1;
+	if (count == 0 || sent == 0) {
+		success = 1;
+		return total;
+	}
+	switch (errno) {
+	case ENOSYS:
+		enosys = 1;
+		return 0;
+	case EINVAL:
+		einval = 1;
+		return 0;
+	case ENOMEM:
+		return 0;
+	default:
+		writerr(NULL, count > chunk ? chunk : count, 0);
+		return -1;
+	}
+}
+#else	/* !__linux__ */
+#include	<sys/types.h>
+
+/*ARGSUSED*/
+long long
+sfile(int dfd, int sfd, mode_t mode, long long count)
+{
+	return 0;
+}
+#endif	/* __linux__ */

+ 40 - 0
tools/cpio/src/sfile.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)sfile.h	1.4 (gritter) 4/17/03	*/
+
+/*
+ * Return values:
+ *
+ * src_size	The entire range has been copied. The file offset of both
+ *              dst_fd	and src_fd have been set to this position. The
+ *              operation has been completed successfully.
+ *
+ * >0		Number of bytes written. The file offset of both dst_fd
+ * 		and src_fd have been set to this position. The operation
+ * 		may continue using read()/write().
+ *
+ * 0		No data was written; operation may continue.
+ *
+ * -1		An error occured; operation may not continue.
+ */
+extern long long	sfile(int dst_fd, int src_fd, mode_t src_mode,
+				long long src_size);

+ 41 - 0
tools/cpio/src/sighold.c

@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)sighold.c	1.7 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+#include <signal.h>
+#include "sigset.h"
+
+int
+sighold(int sig)
+{
+	sigset_t	set, oset;
+
+	if (sig <= 0)
+		return -1;
+	sigemptyset(&set);
+	sigaddset(&set, sig);
+	return sigprocmask(SIG_BLOCK, &set, &oset);
+}
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */

+ 45 - 0
tools/cpio/src/sigignore.c

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)sigignore.c	1.6 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+#include <signal.h>
+#include "sigset.h"
+
+int
+sigignore(int sig)
+{
+	struct sigaction	act;
+
+	if (sig <= 0)
+		return -1;
+	act.sa_handler = SIG_IGN;
+	act.sa_flags = 0;
+	if (sig == SIGCHLD)
+		act.sa_flags |= SA_NOCLDSTOP|SA_NOCLDWAIT;
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask, sig);
+	return sigaction(sig, &act, (struct sigaction *)0);
+}
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */

+ 45 - 0
tools/cpio/src/signal.c

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)signal.c	1.6 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+#include <signal.h>
+#include "sigset.h"
+
+void (*signal(int sig, void (*func)(int)))(int)
+{
+	struct sigaction nact, oact;
+
+	if (sig <= 0)
+		return SIG_ERR;
+	nact.sa_handler = func;
+	nact.sa_flags = SA_RESETHAND|SA_NODEFER;
+	if (sig == SIGCHLD && func == SIG_IGN)
+		nact.sa_flags |= SA_NOCLDSTOP|SA_NOCLDWAIT;
+	sigemptyset(&nact.sa_mask);
+	if (sigaction(sig, &nact, &oact) == -1)
+		return SIG_ERR;
+	return oact.sa_handler;
+}
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */

+ 48 - 0
tools/cpio/src/sigpause.c

@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)sigpause.c	1.6 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+#include <signal.h>
+#include "sigset.h"
+
+int
+sigpause(int sig)
+{
+	sigset_t	nset, oset;
+	int	ret;
+
+	if (sig <= 0)
+		return -1;
+	sigemptyset(&nset);
+	sigaddset(&nset, sig);
+	if (sigprocmask(SIG_UNBLOCK, &nset, &oset) < 0)
+		return -1;
+	sigemptyset(&nset);
+	ret = sigsuspend(&nset);
+	if (sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0) < 0)
+		ret = -1;
+	return ret;
+}
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */

+ 41 - 0
tools/cpio/src/sigrelse.c

@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)sigrelse.c	1.8 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+#include <signal.h>
+#include "sigset.h"
+
+int
+sigrelse(int sig)
+{
+	sigset_t	set, oset;
+
+	if (sig <= 0)
+		return -1;
+	sigemptyset(&set);
+	sigaddset(&set, sig);
+	return sigprocmask(SIG_UNBLOCK, &set, &oset);
+}
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */

+ 55 - 0
tools/cpio/src/sigset.c

@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)sigset.c	1.7 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+#include <signal.h>
+#include "sigset.h"
+
+void (*sigset(int sig, void (*func)(int)))(int)
+{
+	struct sigaction nact, oact;
+	sigset_t	nset, oset;
+
+	if (sig <= 0)
+		return SIG_ERR;
+	sigemptyset(&nset);
+	sigaddset(&nset, sig);
+	if (sigprocmask(func==SIG_HOLD?SIG_BLOCK:SIG_UNBLOCK, &nset, &oset) < 0)
+		return SIG_ERR;
+	nact.sa_handler = func;
+	nact.sa_flags = 0;
+	if (sig == SIGCHLD && func == SIG_IGN)
+		nact.sa_flags |= SA_NOCLDSTOP|SA_NOCLDWAIT;
+	sigemptyset(&nact.sa_mask);
+	sigaddset(&nact.sa_mask, sig);
+	if (sigaction(sig, func==SIG_HOLD?(struct sigaction *)0:&nact, &oact)
+			== -1)
+		return SIG_ERR;
+	if (sigismember(&oset, sig))
+		return SIG_HOLD;
+	else
+		return (oact.sa_handler);
+}
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */

+ 38 - 0
tools/cpio/src/sigset.h

@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)sigset.h	1.9 (gritter) 1/22/06	*/
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
+
+#ifndef	SIG_HOLD
+#define	SIG_HOLD	((void (*)(int))2)
+#endif	/* !SIG_HOLD */
+
+extern int	sighold(int);
+extern int	sigignore(int);
+extern int	sigpause(int);
+extern int	sigrelse(int);
+extern void	(*sigset(int, void (*)(int)))(int);
+extern void	(*signal(int, void (*)(int)))(int);
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
+	__DragonFly__ || __APPLE__ */

+ 117 - 0
tools/cpio/src/strtol.c

@@ -0,0 +1,117 @@
+/*	Sccsid @(#)strtol.c	1.6 (gritter) 7/18/04	*/
+
+#if defined (__hpux) || defined (_AIX) || \
+	defined (__FreeBSD__) && (__FreeBSD__) < 5
+
+#include	<stdlib.h>
+#include	<ctype.h>
+#include	<errno.h>
+
+#include	"atoll.h"
+
+#ifdef	__hpux
+#ifndef	_INCLUDE__STDC_A1_SOURCE
+#error	You must use cc -D_INCLUDE__STDC_A1_SOURCE on HP-UX
+#endif
+#endif	/* __hpux */
+
+static long long
+internal(const char *nptr, char **endptr, int base, int flags)
+{
+	const char	*pp = nptr, *bptr;
+	long long	v = 0, ov;
+	int	sign = 1;
+	int	c;
+	int	valid = 1;
+
+	/* XXX
+	 * iswspace() should be used.
+	 */
+	for (bptr = nptr; isspace(*bptr&0377); bptr++);
+	if (*bptr == '-') {
+		sign = -1;
+		bptr++;
+	} else if (*bptr == '+')
+		bptr++;
+	if (base == 0) {
+		if (*bptr >= '1' && *bptr <= '9')
+			base = 10;
+		else if (*bptr == '0') {
+			if (bptr[1] == 'x' || bptr[1] == 'X')
+				base = 16;
+			else
+				base = 8;
+		} else {
+			if (flags&1)
+				errno = EINVAL;
+			goto out;
+		}
+	}
+	if (base < 2 || base > 36) {
+		if (flags&1)
+			errno = EINVAL;
+		goto out;
+	}
+	if (base == 16 && bptr[0] == '0' &&
+			(bptr[1] == 'x' || bptr[1] == 'X'))
+		bptr += 2;
+	pp = bptr;
+	for (;;) {
+		if (*pp >= '0' && *pp <= '9')
+			c = *pp - '0';
+		else if (*pp >= 'a' && *pp <= 'z')
+			c = *pp - 'a' + 10;
+		else if (*pp >= 'A' && *pp <= 'A')
+			c = *pp - 'A' + 10;
+		else
+			break;
+		if (c >= base)
+			break;
+		pp++;
+		if (valid) {
+			ov = v;
+			v = v * base + c;
+			if (flags&1) {
+				if (flags&2 && (unsigned long long)v <
+						(unsigned long long)ov ||
+						v < ov) {
+					sign = 1;
+					errno = ERANGE;
+					v = -1;
+					if ((flags&2)==0)
+						v = (unsigned long long)v >> 1;
+					valid = 0;
+				}
+			}
+		}
+	}
+out:	if (pp <= bptr) {
+		if (flags&1)
+			errno = EINVAL;
+		if (endptr)
+			*endptr = (char *)nptr;
+	} else {
+		if (endptr)
+			*endptr = (char *)pp;
+	}
+	return v * sign;
+}
+
+long long
+strtoll(const char *nptr, char **endptr, int base)
+{
+	return internal(nptr, endptr, base, 1);
+}
+
+unsigned long long
+strtoull(const char *nptr, char **endptr, int base)
+{
+	return (unsigned long long)internal(nptr, endptr, base, 3);
+}
+
+long long
+atoll(const char *nptr)
+{
+	return internal(nptr, NULL, 10, 0);
+}
+#endif	/* __hpux || _AIX || __FreeBSD__ < 5 */

+ 307 - 0
tools/cpio/src/unshrink.c

@@ -0,0 +1,307 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, May 2003.
+ *
+ * Derived from unzip 5.40.
+ *
+ * Sccsid @(#)unshrink.c	1.4 (gritter) 6/18/04
+ */
+/*---------------------------------------------------------------------------
+
+  unshrink.c                     version 1.21                     23 Nov 95
+
+
+       NOTE:  This code may or may not infringe on the so-called "Welch
+       patent" owned by Unisys.  (From reading the patent, it appears
+       that a pure LZW decompressor is *not* covered, but this claim has
+       not been tested in court, and Unisys is reported to believe other-
+       wise.)  It is therefore the responsibility of the user to acquire
+       whatever license(s) may be required for legal use of this code.
+
+       THE INFO-ZIP GROUP DISCLAIMS ALL LIABILITY FOR USE OF THIS CODE
+       IN VIOLATION OF APPLICABLE PATENT LAW.
+
+
+  Shrinking is basically a dynamic LZW algorithm with allowed code sizes of
+  up to 13 bits; in addition, there is provision for partial clearing of
+  leaf nodes.  PKWARE uses the special code 256 (decimal) to indicate a
+  change in code size or a partial clear of the code tree:  256,1 for the
+  former and 256,2 for the latter.  [Note that partial clearing can "orphan"
+  nodes:  the parent-to-be can be cleared before its new child is added,
+  but the child is added anyway (as an orphan, as though the parent still
+  existed).  When the tree fills up to the point where the parent node is
+  reused, the orphan is effectively "adopted."  Versions prior to 1.05 were
+  affected more due to greater use of pointers (to children and siblings
+  as well as parents).]
+
+  This replacement version of unshrink.c was written from scratch.  It is
+  based only on the algorithms described in Mark Nelson's _The Data Compres-
+  sion Book_ and in Terry Welch's original paper in the June 1984 issue of
+  IEEE _Computer_; no existing source code, including any in Nelson's book,
+  was used.
+
+  Memory requirements have been reduced in this version and are now no more
+  than the original Sam Smith code.  This is still larger than any of the
+  other algorithms:  at a minimum, 8K+8K+16K (stack+values+parents) assuming
+  16-bit short ints, and this does not even include the output buffer (the
+  other algorithms leave the uncompressed data in the work area, typically
+  called slide[]).  For machines with a 64KB data space this is a problem,
+  particularly when text conversion is required and line endings have more
+  than one character.  UnZip's solution is to use two roughly equal halves
+  of outbuf for the ASCII conversion in such a case; the "unshrink" argument
+  to flush() signals that this is the case.
+
+  For large-memory machines, a second outbuf is allocated for translations,
+  but only if unshrinking and only if translations are required.
+
+              | binary mode  |        text mode
+    ---------------------------------------------------
+    big mem   |  big outbuf  | big outbuf + big outbuf2  <- malloc'd here
+    small mem | small outbuf | half + half small outbuf
+
+  Copyright 1994, 1995 Greg Roelofs.  See the accompanying file "COPYING"
+  in UnZip 5.20 (or later) source or binary distributions.
+
+  From "COPYING":
+
+   The following copyright applies to the new version of unshrink.c,
+   distributed with UnZip version 5.2 and later:
+
+     * Copyright (c) 1994 Greg Roelofs.
+     * Permission is granted to any individual/institution/corporate
+     * entity to use, copy, redistribute or modify this software for
+     * any purpose whatsoever, subject to the conditions noted in the
+     * Frequently Asked Questions section below, plus one additional
+     * condition:  namely, that my name not be removed from the source
+     * code.  (Other names may, of course, be added as modifications
+     * are made.)  Corporate legal staff (like at IBM :-) ) who have
+     * problems understanding this can contact me through Zip-Bugs...
+
+
+   Q. Can I use the source code of Zip and UnZip in my commercial
+      application?
+
+   A. Yes, so long as you include in your product an acknowledgment; a
+      pointer to the original, free compression sources; and a statement
+      making it clear that there are no extra or hidden charges resulting
+      from the use of our compression code in your product (see below for
+      an example).  The acknowledgment should appear in at least one piece
+      of human-readable documentation (e.g., a README file or man page),
+      although additionally putting it in the executable(s) is OK, too.
+      In other words, you are allowed to sell only your own work, not ours,
+      and we'd like a little credit.  (Note the additional restrictions
+      above on the code in unreduce.c, unshrink.c, vms.c, time_lib.c, and
+      everything in the wince and windll subdirectories.)  Contact us at
+      Zip-Bugs@lists.wku.edu if you have special requirements.  We also
+      like to hear when our code is being used, but we don't require that.
+
+         <Product> incorporates compression code from the Info-ZIP group.
+         There are no extra charges or costs due to the use of this code,
+         and the original compression sources are freely available from
+         http://www.cdrom.com/pub/infozip/ or ftp://ftp.cdrom.com/pub/infozip/
+         on the Internet.
+
+      If you only need compression capability, not full zipfile support,
+      you might want to look at zlib instead; it has fewer restrictions
+      on commercial use.  See http://www.cdrom.com/pub/infozip/zlib/ .
+
+  ---------------------------------------------------------------------------*/
+
+#include <string.h>
+#include <stdio.h>
+
+#include "cpio.h"
+#include "unzip.h"
+
+static void	partial_clear(struct globals *);
+
+#define	trace()
+
+/* HSIZE is defined as 2^13 (8192) in unzip.h */
+#define	BOGUSCODE  256
+#define	FLAG_BITS  parent        /* upper bits of parent[] used as flag bits */
+#define	CODE_MASK  (HSIZE - 1)   /* 0x1fff (lower bits are parent's index) */
+#define	FREE_CODE  HSIZE         /* 0x2000 (code is unused or was cleared) */
+#define	HAS_CHILD  (HSIZE << 1)  /* 0x4000 (code has a child--do not clear) */
+
+#define parent G.area.shrink.Parent
+#define Value  G.area.shrink.value /* "value" conflicts with Pyramid ioctl.h */
+#define stack  G.area.shrink.Stack
+
+/***********************/
+/* Function unshrink() */
+/***********************/
+
+int
+zipunshrink(struct file *f, const char *tgt, int tfd, int doswap, uint32_t *crc)
+{
+    struct globals G;
+    int offset = (HSIZE - 1);
+    uint8_t *stacktop = stack + offset;
+    register uint8_t *newstr;
+    int codesize=9, len, KwKwK;
+    int16_t code, oldcode, freecode, curcode;
+    int16_t lastfreecode;
+    unsigned int outbufsiz;
+
+/*---------------------------------------------------------------------------
+    Initialize various variables.
+  ---------------------------------------------------------------------------*/
+
+    memset(&G, 0, sizeof G);
+    G.tgt = tgt;
+    G.tfd = tfd;
+    G.doswap = doswap;
+    G.crc = crc;
+    G.zsize = G.uzsize = f->f_csize;
+    lastfreecode = BOGUSCODE;
+
+    for (code = 0;  code < BOGUSCODE;  ++code) {
+        Value[code] = (uint8_t)code;
+        parent[code] = BOGUSCODE;
+    }
+    for (code = BOGUSCODE+1;  code < HSIZE;  ++code)
+        parent[code] = FREE_CODE;
+
+    outbufsiz = OUTBUFSIZ;
+    G.outptr = G.outbuf;
+    G.outcnt = 0L;
+
+/*---------------------------------------------------------------------------
+    Get and output first code, then loop over remaining ones.
+  ---------------------------------------------------------------------------*/
+
+    READBITS(codesize, oldcode)
+    if (!G.zipeof) {
+        *G.outptr++ = (uint8_t)oldcode;
+        ++G.outcnt;
+    }
+
+    do {
+        READBITS(codesize, code)
+        if (G.zipeof)
+            break;
+        if (code == BOGUSCODE) {   /* possible to have consecutive escapes? */
+            READBITS(codesize, code)
+            if (code == 1) {
+                ++codesize;
+                Trace((stderr, " (codesize now %d bits)\n", codesize));
+            } else if (code == 2) {
+                Trace((stderr, " (partial clear code)\n"));
+                partial_clear(&G);   /* clear leafs (nodes with no children) */
+                Trace((stderr, " (done with partial clear)\n"));
+                lastfreecode = BOGUSCODE;  /* reset start of free-node search */
+            }
+            continue;
+        }
+
+    /*-----------------------------------------------------------------------
+        Translate code:  traverse tree from leaf back to root.
+      -----------------------------------------------------------------------*/
+
+        newstr = stacktop;
+        curcode = code;
+
+        if (parent[curcode] == FREE_CODE) {
+            /* or (FLAG_BITS[curcode] & FREE_CODE)? */
+            KwKwK = TRUE;
+            Trace((stderr, " (found a KwKwK code %d; oldcode = %d)\n", code,
+              oldcode));
+            --newstr;   /* last character will be same as first character */
+            curcode = oldcode;
+        } else
+            KwKwK = FALSE;
+
+        do {
+            *newstr-- = Value[curcode];
+            curcode = (int16_t)(parent[curcode] & CODE_MASK);
+        } while (curcode != BOGUSCODE);
+
+        len = (int)(stacktop - newstr++);
+        if (KwKwK)
+            *stacktop = *newstr;
+
+    /*-----------------------------------------------------------------------
+        Write expanded string in reverse order to output buffer.
+      -----------------------------------------------------------------------*/
+
+        Trace((stderr, "code %4d; oldcode %4d; char %3d (%c); string [", code,
+          oldcode, (int)(*newstr), (*newstr<32 || *newstr>=127)? ' ':*newstr));
+
+        {
+            register uint8_t *p;
+
+            for (p = newstr;  p < newstr+len;  ++p) {
+                *G.outptr++ = *p;
+                if (++G.outcnt == outbufsiz) {
+		    flush(&G, G.outbuf, G.outcnt);
+                    G.outptr = G.outbuf;
+                    G.outcnt = 0L;
+                }
+            }
+        }
+
+    /*-----------------------------------------------------------------------
+        Add new leaf (first character of newstr) to tree as child of oldcode.
+      -----------------------------------------------------------------------*/
+
+        /* search for freecode */
+        freecode = (int16_t)(lastfreecode + 1);
+        /* add if-test before loop for speed? */
+        while (parent[freecode] != FREE_CODE)
+            ++freecode;
+        lastfreecode = freecode;
+        Trace((stderr, "]; newcode %d\n", freecode));
+
+        Value[freecode] = *newstr;
+        parent[freecode] = oldcode;
+        oldcode = code;
+
+    } while (!G.zipeof);
+
+/*---------------------------------------------------------------------------
+    Flush any remaining data and return to sender...
+  ---------------------------------------------------------------------------*/
+
+    if (G.outcnt > 0L)
+	    flush(&G, G.outbuf, G.outcnt);
+
+    return G.status;
+
+} /* end function unshrink() */
+
+
+
+
+
+/****************************/
+/* Function partial_clear() */      /* no longer recursive... */
+/****************************/
+
+static void
+partial_clear(struct globals *Gp)
+{
+#define	G	(*Gp)
+    register int16_t code;
+
+    /* clear all nodes which have no children (i.e., leaf nodes only) */
+
+    /* first loop:  mark each parent as such */
+    for (code = BOGUSCODE+1;  code < HSIZE;  ++code) {
+        register int16_t cparent = (int16_t)(parent[code] & CODE_MASK);
+
+        if (cparent > BOGUSCODE && cparent != FREE_CODE)
+            FLAG_BITS[cparent] |= HAS_CHILD;   /* set parent's child-bit */
+    }
+
+    /* second loop:  clear all nodes *not* marked as parents; reset flag bits */
+    for (code = BOGUSCODE+1;  code < HSIZE;  ++code) {
+        if (FLAG_BITS[code] & HAS_CHILD)    /* just clear child-bit */
+            FLAG_BITS[code] &= ~HAS_CHILD;
+        else {                              /* leaf:  lose it */
+            Trace((stderr, "%d\n", code));
+            parent[code] = FREE_CODE;
+        }
+    }
+
+    return;
+}

+ 121 - 0
tools/cpio/src/unzip.h

@@ -0,0 +1,121 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, May 2003.
+ *
+ * Derived from unzip 5.40.
+ *
+ * Sccsid @(#)unzip.h	1.5 (gritter) 7/16/04
+ */
+
+#include <inttypes.h>
+
+#define	Trace(a)
+
+#define	MAX_BITS	13
+#define	HSIZE		(1 << MAX_BITS)
+#define	WSIZE		65536L	/* at least 64K for enhanced deflate */
+
+#define	redirSlide	G.area.Slide
+
+#define	NEXTBYTE	(--G.incnt >= 0 ? (int)(*G.inptr++) : readbyte(&G))
+
+#define	READBITS(nbits, zdest)	{ \
+	if (nbits > G.bits_left) { \
+		int temp; \
+		G.zipeof = 1; \
+		while (G.bits_left <= 8 * (int)(sizeof G.bitbuf - 1) && \
+				(temp = NEXTBYTE) != EOF) { \
+			G.bitbuf |= (uint32_t)temp << G.bits_left; \
+			G.bits_left += 8; \
+			G.zipeof = 0; \
+		} \
+	} \
+	zdest = (int16_t)((uint16_t)G.bitbuf & mask_bits[nbits]); \
+	G.bitbuf >>= nbits; \
+	G.bits_left -= nbits; \
+}
+
+#undef	FALSE
+#undef	TRUE
+enum	{
+	FALSE = 0,
+	TRUE = 1
+};
+
+union	work {
+	struct	{
+		int16_t	Parent[HSIZE];
+		uint8_t	value[HSIZE];
+		uint8_t	Stack[HSIZE];
+	} shrink;
+	uint8_t	Slide[WSIZE];
+};
+
+#define	OUTBUFSIZ	4096
+
+struct	globals {
+	union work	area;
+	uint8_t	inbuf[4096];
+	long long	zsize;
+	long long	uzsize;
+	uint8_t	*inptr;
+	const char	*tgt;
+	struct huft	*fixed_tl;
+	struct huft	*fixed_td;
+	struct huft	*fixed_tl64;
+	struct huft	*fixed_td64;
+	struct huft	*fixed_tl32;
+	struct huft	*fixed_td32;
+	const uint16_t	*cplens;
+	const uint8_t	*cplext;
+	const uint8_t	*cpdext;
+	long	csize;
+	long	ucsize;
+	uint8_t	outbuf[OUTBUFSIZ];
+	uint8_t	*outptr;
+	uint32_t	*crc;
+	uint32_t	bitbuf;
+	uint32_t	wp;
+	uint32_t	bb;
+	uint32_t	bk;
+	unsigned	outcnt;
+	int	tfd;
+	int	doswap;
+	int	incnt;
+	int	bits_left;
+	int	zipeof;
+	int	fixed_bl;
+	int	fixed_bd;
+	int	fixed_bl64;
+	int	fixed_bd64;
+	int	fixed_bl32;
+	int	fixed_bd32;
+	int	status;
+};
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model).
+   Valid extra bits are 0..13.  e == 15 is EOB (end of block), e == 16
+   means that v is a literal, 16 < e < 32 means that v is a pointer to
+   the next table, which codes e - 16 bits, and lastly e == 99 indicates
+   an unused code.  If a code with e == 99 is looked up, this implies an
+   error in the data. */
+
+struct huft {
+    uint8_t e;            /* number of extra bits or operation */
+    uint8_t b;            /* number of bits in this code or subcode */
+    union {
+        uint16_t n;       /* literal, length base, or distance base */
+        struct huft *t;   /* pointer to next level of table */
+    } v;
+};
+
+extern const uint16_t	mask_bits[];
+
+extern void	flush(struct globals *, const void *, size_t);
+extern int	readbyte(struct globals *);
+
+extern int	huft_build(const unsigned *b, unsigned n, unsigned s,
+			const uint16_t *d, const uint8_t *e,
+			struct huft **t, int *m,
+			int bits, int nob, int eob);
+extern void	huft_free(struct huft *);

+ 252 - 0
tools/cpio/src/utmpx.c

@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2004 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)utmpx.c	1.13 (gritter) 12/16/07	*/
+
+#include <stdio.h>
+
+#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
+	defined (__UCLIBC__) || defined (__OpenBSD__) || \
+	defined (__DragonFly__) || \
+	defined (__APPLE__) && \
+		(__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_OS_X_VERSION_10_5)
+#include <sys/types.h>
+#include <sys/time.h>
+#include <utmp.h>
+#include <string.h>
+
+#include "utmpx.h"
+
+static FILE	*utfp;
+static struct utmpx	utx;
+static const char	*utmpfile = _PATH_UTMP;
+
+static FILE *
+init(void)
+{
+	if (utfp == NULL && (utfp = fopen(utmpfile, "r+")) == NULL)
+		if ((utfp = fopen(utmpfile, "r")) == NULL)
+			return NULL;
+	return utfp;
+}
+
+static struct utmpx *
+utmp2utmpx(struct utmpx *ux, const struct utmp *up)
+{
+#ifndef	__dietlibc__
+	memset(ux, 0, sizeof *ux);
+	ux->ut_tv.tv_sec = up->ut_time;
+	memcpy(ux->ut_line, up->ut_line, UT_LINESIZE);
+	memcpy(ux->ut_user, up->ut_name, UT_NAMESIZE);
+	memcpy(ux->ut_host, up->ut_host, UT_HOSTSIZE);
+	if (strcmp(up->ut_line, "~") == 0)
+		ux->ut_type = BOOT_TIME;
+	else if (strcmp(up->ut_line, "|") == 0)
+		ux->ut_type = OLD_TIME;
+	else if (strcmp(up->ut_line, "}") == 0)
+		ux->ut_type = NEW_TIME;
+	else if (*up->ut_name == 0)
+		ux->ut_type = DEAD_PROCESS;
+	else
+		ux->ut_type = USER_PROCESS;
+#else	/* __dietlibc__ */
+	*ux = *up;
+#endif	/* __dietlibc__ */
+	return ux;
+}
+
+static struct utmp *
+utmpx2utmp(struct utmp *up, const struct utmpx *ux)
+{
+#ifndef	__dietlibc__
+	memset(up, 0, sizeof *up);
+	up->ut_time = ux->ut_tv.tv_sec;
+	switch (ux->ut_type) {
+	case DEAD_PROCESS:
+		memcpy(up->ut_line, ux->ut_line, UT_LINESIZE);
+		break;
+	default:
+	case EMPTY:
+	case INIT_PROCESS:
+	case LOGIN_PROCESS:
+	case RUN_LVL:
+	case ACCOUNTING:
+		return NULL;
+	case BOOT_TIME:
+		strcpy(up->ut_name, "reboot");
+		strcpy(up->ut_line, "~");
+		break;
+	case OLD_TIME:
+		strcpy(up->ut_name, "date");
+		strcpy(up->ut_line, "|");
+		break;
+	case NEW_TIME:
+		strcpy(up->ut_name, "date");
+		strcpy(up->ut_line, "{");
+		break;
+	case USER_PROCESS:
+		memcpy(up->ut_line, ux->ut_line, UT_LINESIZE);
+		memcpy(up->ut_name, ux->ut_user, UT_NAMESIZE);
+		memcpy(up->ut_host, ux->ut_host, UT_HOSTSIZE);
+	}
+#else	/* __dietlibc__ */
+	*up = *ux;
+#endif	/* __dietlibc__ */
+	return up;
+}
+
+struct utmpx *
+getutxent(void)
+{
+	static struct utmp	zero;
+	struct utmp	ut;
+
+	if (init() == NULL)
+		return NULL;
+	do {
+		if (fread(&ut, sizeof ut, 1, utfp) != 1)
+			return NULL;
+	} while (memcmp(&ut, &zero, sizeof ut) == 0);
+	return utmp2utmpx(&utx, &ut);
+}
+
+struct utmpx *
+getutxline(const struct utmpx *ux)
+{
+	struct utmp	ut;
+
+	if (init() == NULL)
+		return NULL;
+	fseek(utfp, 0, SEEK_SET);
+	while (fread(&ut, sizeof ut, 1, utfp) == 1) {
+		utmp2utmpx(&utx, &ut);
+		if ((utx.ut_type == LOGIN_PROCESS ||
+					utx.ut_type == USER_PROCESS) &&
+				strcmp(ut.ut_line, utx.ut_line) == 0)
+			return &utx;
+	}
+	return NULL;
+}
+
+struct utmpx *
+getutxid(const struct utmpx *ux)
+{
+#ifdef	__dietlibc__
+	struct utmp	ut;
+#endif
+
+	if (init() == NULL)
+		return NULL;
+#ifdef	__dietlibc__
+	fseek(utfp, 0, SEEK_SET);
+	while (fread(&ut, sizeof ut, 1, utfp) == 1) {
+		utmp2utmpx(&utx, &ut);
+		switch (ux->ut_type) {
+		case BOOT_TIME:
+		case OLD_TIME:
+		case NEW_TIME:
+			if (ux->ut_type == utx.ut_type)
+				return &utx;
+			break;
+		case INIT_PROCESS:
+		case LOGIN_PROCESS:
+		case USER_PROCESS:
+		case DEAD_PROCESS:
+			if (ux->ut_type == utx.ut_type &&
+					ux->ut_id == utx.ut_id)
+				return &utx;
+			break;
+		}
+	}
+#endif	/* __dietlibc__ */
+	return NULL;
+}
+
+void
+setutxent(void)
+{
+	if (init() == NULL)
+		return;
+	fseek(utfp, 0, SEEK_SET);
+}
+
+void
+endutxent(void)
+{
+	FILE	*fp;
+
+	if (init() == NULL)
+		return;
+	fp = utfp;
+	utfp = NULL;
+	fclose(fp);
+}
+
+int
+utmpxname(const char *name)
+{
+	utmpfile = strdup(name);
+	return 0;
+}
+
+extern struct utmpx *
+pututxline(const struct utmpx *up)
+{
+	struct utmp	ut;
+	struct utmpx	*rp;
+
+	if (init() == NULL)
+		return NULL;
+	/*
+	 * Cannot use getutxid() because there is no id field. Use
+	 * the equivalent of getutxline() instead.
+	 */
+	while (fread(&ut, sizeof ut, 1, utfp) == 1) {
+		if (strncmp(ut.ut_line, up->ut_line, UT_LINESIZE) == 0) {
+			fseek(utfp, -sizeof ut, SEEK_CUR);
+			break;
+		}
+	}
+	fflush(utfp);
+	if (utmpx2utmp(&ut, up) == NULL)
+		rp = NULL;
+	else if (fwrite(&ut, sizeof ut, 1, utfp) == 1) {
+		utx = *up;
+		rp = &utx;
+	} else
+		rp = NULL;
+	fflush(utfp);
+	return rp;
+}
+
+extern void
+updwtmpx(const char *name, const struct utmpx *up)
+{
+	FILE	*fp;
+
+	if ((fp = fopen(name, "a")) == NULL)
+		return;
+	fwrite(up, sizeof *up, 1, fp);
+	fclose(fp);
+}
+
+#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __UCLIBC__ ||
+	 	__OpenBSD__ || __DragonFly__ || __APPLE__ */

+ 26 - 0
tools/cpio/src/version.c

@@ -0,0 +1,26 @@
+#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
+#define	USED	__attribute__ ((used))
+#elif defined __GNUC__
+#define	USED	__attribute__ ((unused))
+#else
+#define	USED
+#endif
+static const char sccsid[] USED = "@(#)cpio.sl	2.9 (gritter) 8/14/09";
+/* SLIST */
+/*
+blast.c: * Sccsid @(#)blast.c	1.2 (gritter) 2/17/04
+blast.h: * Sccsid @(#)blast.h	1.2 (gritter) 2/17/04
+cpio.c: * Sccsid @(#)cpio.c	1.305 (gritter) 8/14/09
+cpio.h:	Sccsid @(#)cpio.h	1.29 (gritter) 3/26/07	
+crc32.c: * Sccsid @(#)crc32.c	1.2 (gritter) 5/29/03
+expand.c:	Sccsid @(#)expand.c	1.6 (gritter) 12/15/03	
+explode.c: * Sccsid @(#)explode.c	1.6 (gritter) 9/30/03
+flags.c:	Sccsid @(#)flags.c	1.6 (gritter) 3/26/07	
+inflate.c: * Sccsid @(#)inflate.c	1.6 (gritter) 10/13/04
+nonpax.c:	Sccsid @(#)nonpax.c	1.1 (gritter) 2/24/04	
+pax.c:static const char sccsid[] USED = "@(#)pax_su3.sl	1.26 (gritter) 6/26/05";
+pax.c:static const char sccsid[] USED = "@(#)pax.sl	1.26 (gritter) 6/26/05";
+pax.c:	Sccsid @(#)pax.c	1.26 (gritter) 6/26/05	
+unshrink.c: * Sccsid @(#)unshrink.c	1.4 (gritter) 6/18/04
+unzip.h: * Sccsid @(#)unzip.h	1.5 (gritter) 7/16/04
+*/

+ 90 - 0
tools/cpio/src/vpfmt.c

@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*	Sccsid @(#)vpfmt.c	1.2 (gritter) 9/21/03	*/
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "pfmt.h"
+
+extern char	*pfmt_label__;
+
+/*
+ * Strip catalog and msgnum from s, but only if they actually appear.
+ */
+static const char *
+begin(const char *s, long flags)
+{
+	const char	*sp;
+
+	if (flags & MM_NOGET)
+		return s;
+	sp = s;
+	if (*sp && *sp != ':') {
+		sp++;
+		while (*sp && *sp != '/' && *sp != ':' && sp - s < 14)
+			sp++;
+	}
+	if (*sp++ != ':')
+		return s;
+	while (*sp >= '0' && *sp <= '9')
+		sp++;
+	if (*sp++ != ':' || *sp == '\0')
+		return s;
+	return sp;
+}
+
+int
+vpfmt(FILE *stream, long flags, const char *fmt, va_list ap)
+{
+	int	n = 0;
+	const char	*severity = NULL;
+	char	sevbuf[25];
+
+	if ((flags&MM_NOSTD) == 0) {
+		if (flags & MM_ACTION)
+			severity = "TO FIX";
+		else switch (flags & 0377) {
+		case MM_HALT:
+			severity = "HALT";
+			break;
+		case MM_WARNING:
+			severity = "WARNING";
+			break;
+		case MM_INFO:
+			severity = "INFO";
+			break;
+		case MM_ERROR:
+			severity = "ERROR";
+			break;
+		default:
+			snprintf(sevbuf, sizeof sevbuf, "SEV=%ld", flags&0377);
+			severity = sevbuf;
+		}
+		if (pfmt_label__)
+			n = fprintf(stream, "%s: ", pfmt_label__);
+		if (severity)
+			n += fprintf(stream, "%s: ", severity);
+	}
+	n += vfprintf(stream, begin(fmt, flags), ap);
+	return n;
+}

+ 3 - 14
tools/mkcrypt/Makefile

@@ -3,20 +3,9 @@
 
 include $(TOPDIR)/rules.mk
 
-PKG_NAME:=		mkcrypt
-PKG_VERSION:=		0.1
-PKG_RELEASE:=		1
-NO_DISTFILES:=		1
+${STAGING_TOOLS}/bin/mkcrypt:
+	$(HOSTCC) -o $(STAGING_TOOLS)/bin/mkcrypt mkcrypt.c
 
-include ../rules.mk
-
-$(WRKBUILD)/.compiled: ${WRKDIST}/.prepared
-	$(HOSTCC) -o $(WRKBUILD)/mkcrypt mkcrypt.c
-	touch $@
-
-$(WRKBUILD)/.installed: $(WRKBUILD)/.compiled
-	$(INSTALL_BIN) $(WRKBUILD)/mkcrypt \
-		${STAGING_TOOLS}/bin
-	touch $@
+install: ${STAGING_TOOLS}/bin/mkcrypt
 
 include $(TOPDIR)/mk/tools.mk

+ 0 - 7
tools/rules.mk

@@ -1,7 +0,0 @@
-# This file is part of the OpenADK project. OpenADK is copyrighted
-# material, please see the LICENCE file in the top-level directory.
-
-WRKDIR_BASE=    ${TOOLS_BUILD_DIR}
-WRKDIR=		${WRKDIR_BASE}
-
-include ${TOPDIR}/mk/buildhlp.mk