summaryrefslogtreecommitdiff
path: root/package/heirloom-cpio/src/cpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'package/heirloom-cpio/src/cpio.c')
-rw-r--r--package/heirloom-cpio/src/cpio.c7172
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)
+