diff options
72 files changed, 18300 insertions, 62 deletions
diff --git a/mk/image.mk b/mk/image.mk index 440d975b4..6c3b1e5f9 100644 --- a/mk/image.mk +++ b/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 > \ diff --git a/mk/tools.mk b/mk/tools.mk index 429e741c2..b91e478fd 100644 --- a/mk/tools.mk +++ b/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) diff --git a/scripts/cpio b/scripts/cpio deleted file mode 100755 index 790593b97..000000000 --- a/scripts/cpio +++ /dev/null @@ -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 diff --git a/tools/Makefile b/tools/Makefile index 67b54b096..7c5931319 100644 --- a/tools/Makefile +++ b/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) diff --git a/tools/cpio/Makefile b/tools/cpio/Makefile new file mode 100644 index 000000000..e9533a498 --- /dev/null +++ b/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 diff --git a/tools/cpio/src/_alloca.h b/tools/cpio/src/_alloca.h new file mode 100644 index 000000000..dc2afe5b4 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/_malloc.h b/tools/cpio/src/_malloc.h new file mode 100644 index 000000000..1693e3673 --- /dev/null +++ b/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); diff --git a/tools/cpio/src/_utmpx.h b/tools/cpio/src/_utmpx.h new file mode 100644 index 000000000..c32bd9527 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/asciitype.c b/tools/cpio/src/asciitype.c new file mode 100644 index 000000000..f7f322173 --- /dev/null +++ b/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 +}; diff --git a/tools/cpio/src/asciitype.h b/tools/cpio/src/asciitype.h new file mode 100644 index 000000000..6ac1961a1 --- /dev/null +++ b/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)) diff --git a/tools/cpio/src/atoll.h b/tools/cpio/src/atoll.h new file mode 100644 index 000000000..8283aff64 --- /dev/null +++ b/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 */ diff --git a/tools/cpio/src/blank.h b/tools/cpio/src/blank.h new file mode 100644 index 000000000..1ab3d57b8 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/blast.c b/tools/cpio/src/blast.c new file mode 100644 index 000000000..b62efd585 --- /dev/null +++ b/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 diff --git a/tools/cpio/src/blast.h b/tools/cpio/src/blast.h new file mode 100644 index 000000000..0c16d1391 --- /dev/null +++ b/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. + */ diff --git a/tools/cpio/src/cpio.1 b/tools/cpio/src/cpio.1 new file mode 100644 index 000000000..9c8b1f98c --- /dev/null +++ b/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. diff --git a/tools/cpio/src/cpio.c b/tools/cpio/src/cpio.c new file mode 100644 index 000000000..1300d2d70 --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/cpio.h b/tools/cpio/src/cpio.h new file mode 100644 index 000000000..131a3d388 --- /dev/null +++ b/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); diff --git a/tools/cpio/src/crc32.c b/tools/cpio/src/crc32.c new file mode 100644 index 000000000..084cb52cf --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/expand.c b/tools/cpio/src/expand.c new file mode 100644 index 000000000..5a5233f3e --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/explode.c b/tools/cpio/src/explode.c new file mode 100644 index 000000000..863dbf672 --- /dev/null +++ b/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++); +} diff --git a/tools/cpio/src/flags.c b/tools/cpio/src/flags.c new file mode 100644 index 000000000..e06c8e80d --- /dev/null +++ b/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); +} diff --git a/tools/cpio/src/getdir.c b/tools/cpio/src/getdir.c new file mode 100644 index 000000000..245b7641e --- /dev/null +++ b/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); +} diff --git a/tools/cpio/src/getdir.h b/tools/cpio/src/getdir.h new file mode 100644 index 000000000..29d107b6f --- /dev/null +++ b/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 *); diff --git a/tools/cpio/src/getopt.c b/tools/cpio/src/getopt.c new file mode 100644 index 000000000..0a68ac8e9 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/gmatch.c b/tools/cpio/src/gmatch.c new file mode 100644 index 000000000..a2c5eb7ba --- /dev/null +++ b/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); + + } +} diff --git a/tools/cpio/src/ib_alloc.c b/tools/cpio/src/ib_alloc.c new file mode 100644 index 000000000..338d0622b --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/ib_close.c b/tools/cpio/src/ib_close.c new file mode 100644 index 000000000..946bb9ef6 --- /dev/null +++ b/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); +} diff --git a/tools/cpio/src/ib_free.c b/tools/cpio/src/ib_free.c new file mode 100644 index 000000000..72143afef --- /dev/null +++ b/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); +} diff --git a/tools/cpio/src/ib_getlin.c b/tools/cpio/src/ib_getlin.c new file mode 100644 index 000000000..ddee226b4 --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/ib_getw.c b/tools/cpio/src/ib_getw.c new file mode 100644 index 000000000..b7f2e6762 --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/ib_open.c b/tools/cpio/src/ib_open.c new file mode 100644 index 000000000..18e09c776 --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/ib_popen.c b/tools/cpio/src/ib_popen.c new file mode 100644 index 000000000..9aa873042 --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/ib_read.c b/tools/cpio/src/ib_read.c new file mode 100644 index 000000000..3794f3e95 --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/ib_seek.c b/tools/cpio/src/ib_seek.c new file mode 100644 index 000000000..48b2f99bc --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/iblok.h b/tools/cpio/src/iblok.h new file mode 100644 index 000000000..66964627f --- /dev/null +++ b/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); diff --git a/tools/cpio/src/inflate.c b/tools/cpio/src/inflate.c new file mode 100644 index 000000000..2c6d3e59f --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/mbtowi.h b/tools/cpio/src/mbtowi.h new file mode 100644 index 000000000..525ad08d1 --- /dev/null +++ b/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 */ diff --git a/tools/cpio/src/memalign.c b/tools/cpio/src/memalign.c new file mode 100644 index 000000000..268949b20 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/memalign.h b/tools/cpio/src/memalign.h new file mode 100644 index 000000000..edaef031b --- /dev/null +++ b/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 */ diff --git a/tools/cpio/src/msgselect.h b/tools/cpio/src/msgselect.h new file mode 100644 index 000000000..94a5daa9f --- /dev/null +++ b/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 diff --git a/tools/cpio/src/nonpax.c b/tools/cpio/src/nonpax.c new file mode 100644 index 000000000..d0eb585b7 --- /dev/null +++ b/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) +{ +} diff --git a/tools/cpio/src/oblok.c b/tools/cpio/src/oblok.c new file mode 100644 index 000000000..38859ba6d --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/oblok.h b/tools/cpio/src/oblok.h new file mode 100644 index 000000000..1ee91b1c5 --- /dev/null +++ b/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); diff --git a/tools/cpio/src/pathconf.c b/tools/cpio/src/pathconf.c new file mode 100644 index 000000000..a6b91ef86 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/pathconf.h b/tools/cpio/src/pathconf.h new file mode 100644 index 000000000..79696b6da --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/pax.1 b/tools/cpio/src/pax.1 new file mode 100644 index 000000000..4fb9206f9 --- /dev/null +++ b/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. diff --git a/tools/cpio/src/pax.c b/tools/cpio/src/pax.c new file mode 100644 index 000000000..50632b6b1 --- /dev/null +++ b/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++; + } + } +} diff --git a/tools/cpio/src/pfmt.c b/tools/cpio/src/pfmt.c new file mode 100644 index 000000000..8adc22f23 --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/pfmt.h b/tools/cpio/src/pfmt.h new file mode 100644 index 000000000..012667b0b --- /dev/null +++ b/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) diff --git a/tools/cpio/src/pfmt_label.c b/tools/cpio/src/pfmt_label.c new file mode 100644 index 000000000..5b1a53f0a --- /dev/null +++ b/tools/cpio/src/pfmt_label.c @@ -0,0 +1 @@ +char *pfmt_label__; diff --git a/tools/cpio/src/regexp.h b/tools/cpio/src/regexp.h new file mode 100644 index 000000000..5b1fee5e6 --- /dev/null +++ b/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); +} diff --git a/tools/cpio/src/regexpr.c b/tools/cpio/src/regexpr.c new file mode 100644 index 000000000..40dceb525 --- /dev/null +++ b/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" diff --git a/tools/cpio/src/regexpr.h b/tools/cpio/src/regexpr.h new file mode 100644 index 000000000..74f4a1426 --- /dev/null +++ b/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 *); diff --git a/tools/cpio/src/setlabel.c b/tools/cpio/src/setlabel.c new file mode 100644 index 000000000..a1db0646e --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/setuxlabel.c b/tools/cpio/src/setuxlabel.c new file mode 100644 index 000000000..9d304869e --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/sfile.c b/tools/cpio/src/sfile.c new file mode 100644 index 000000000..089d85fdf --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/sfile.h b/tools/cpio/src/sfile.h new file mode 100644 index 000000000..53d832a6f --- /dev/null +++ b/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); diff --git a/tools/cpio/src/sighold.c b/tools/cpio/src/sighold.c new file mode 100644 index 000000000..e35c33e0f --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/sigignore.c b/tools/cpio/src/sigignore.c new file mode 100644 index 000000000..6938ef676 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/signal.c b/tools/cpio/src/signal.c new file mode 100644 index 000000000..e511aeba6 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/sigpause.c b/tools/cpio/src/sigpause.c new file mode 100644 index 000000000..504a5ed4d --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/sigrelse.c b/tools/cpio/src/sigrelse.c new file mode 100644 index 000000000..c6976c9b8 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/sigset.c b/tools/cpio/src/sigset.c new file mode 100644 index 000000000..fe1482f14 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/sigset.h b/tools/cpio/src/sigset.h new file mode 100644 index 000000000..d4b834d19 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/strtol.c b/tools/cpio/src/strtol.c new file mode 100644 index 000000000..cd8ecfe7a --- /dev/null +++ b/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 */ diff --git a/tools/cpio/src/unshrink.c b/tools/cpio/src/unshrink.c new file mode 100644 index 000000000..61f5c507c --- /dev/null +++ b/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; +} diff --git a/tools/cpio/src/unzip.h b/tools/cpio/src/unzip.h new file mode 100644 index 000000000..d53f81024 --- /dev/null +++ b/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 *); diff --git a/tools/cpio/src/utmpx.c b/tools/cpio/src/utmpx.c new file mode 100644 index 000000000..d88a627a7 --- /dev/null +++ b/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__ */ diff --git a/tools/cpio/src/version.c b/tools/cpio/src/version.c new file mode 100644 index 000000000..a9d4a4681 --- /dev/null +++ b/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 +*/ diff --git a/tools/cpio/src/vpfmt.c b/tools/cpio/src/vpfmt.c new file mode 100644 index 000000000..fdbb4ccb0 --- /dev/null +++ b/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; +} diff --git a/tools/mkcrypt/Makefile b/tools/mkcrypt/Makefile index e6c8d83e1..3b1924c5b 100644 --- a/tools/mkcrypt/Makefile +++ b/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 diff --git a/tools/rules.mk b/tools/rules.mk deleted file mode 100644 index a6a3684ac..000000000 --- a/tools/rules.mk +++ /dev/null @@ -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 |