diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2010-07-29 15:25:12 +0200 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2010-07-29 15:25:12 +0200 |
commit | fd6481d82ff407139157e53df28563d40bb3ad3b (patch) | |
tree | ed2ae9e08c31d1eed424793272a60c25cdec6c00 /tools/cpio/src | |
parent | 14804005d5b33beb6f52d4a72034acb00c00eb90 (diff) |
add a cpio implementation to tools directory
cpio utility is a mess in point of portability.
For example NetBSD cpio implementation does not support
userid and groupid changes for the archive. This
feature is required for initramfs filesystem targets.
This cpio is from the Heirloom project.
Fix needed rebuild of tools, when changing targets.
Diffstat (limited to 'tools/cpio/src')
65 files changed, 18253 insertions, 0 deletions
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; +} |