/* * 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 #include #ifdef __linux__ #if !defined (__UCLIBC__) && !defined (__dietlibc__) #include #endif /* !__UCLIBC__, !__dietlibc__ */ #include #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 #include #include #include #include #include #include "sigset.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "memalign.h" int sysv3; #if USE_ZLIB #include #endif /* USE_ZLIB */ #if USE_BZLIB #include #endif /* USE_BZLIB */ #include #if defined (__linux__) || defined (__sun) || defined (__FreeBSD__) || \ defined (__hpux) || defined (_AIX) || defined (__NetBSD__) || \ defined (__OpenBSD__) || defined (__DragonFly__) || \ defined (__CYGWIN__) #include #endif #include #include #include #ifdef _AIX #include #endif /* _AIX */ #ifndef major #include #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); 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