diff options
Diffstat (limited to 'package/heirloom-cpio/src/cpio.c')
-rw-r--r-- | package/heirloom-cpio/src/cpio.c | 7172 |
1 files changed, 7172 insertions, 0 deletions
diff --git a/package/heirloom-cpio/src/cpio.c b/package/heirloom-cpio/src/cpio.c new file mode 100644 index 000000000..e5090e4c9 --- /dev/null +++ b/package/heirloom-cpio/src/cpio.c @@ -0,0 +1,7172 @@ +/* + * 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 <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 (__CYGWIN__) +#include <sys/mtio.h> +#endif + +#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) + |