Home | History | Annotate | Download | only in cpio
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
     27 /*	All Rights Reserved					*/
     28 
     29 /*
     30  * Portions of this source code were derived from Berkeley 4.3 BSD
     31  * under license from the Regents of the University of California.
     32  */
     33 
     34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     35 
     36 #include <stdio.h>
     37 #include <sys/types.h>
     38 #include <errno.h>
     39 #include <unistd.h>
     40 #include <stdlib.h>
     41 #include <fcntl.h>
     42 #include <memory.h>
     43 #include <string.h>
     44 #include <stdarg.h>
     45 #include <sys/stat.h>
     46 #include <sys/statvfs.h>
     47 #include <sys/mkdev.h>
     48 #include <sys/param.h>
     49 #include <utime.h>
     50 #include <pwd.h>
     51 #include <grp.h>
     52 #include <signal.h>
     53 #include <ctype.h>
     54 #include <archives.h>
     55 #include <locale.h>
     56 #include <sys/ioctl.h>
     57 #include <sys/mtio.h>
     58 #include <sys/fdio.h>
     59 #include "cpio.h"
     60 #include <sys/acl.h>
     61 #include <sys/time.h>
     62 #include <sys/resource.h>
     63 #include <fnmatch.h>
     64 #include <libgen.h>
     65 #include <libintl.h>
     66 #include <dirent.h>
     67 #include <limits.h>
     68 #include <aclutils.h>
     69 #if defined(_PC_SATTR_ENABLED)
     70 #include <libnvpair.h>
     71 #include <attr.h>
     72 #include <libcmdutils.h>
     73 #endif	/* _PC_SATTR_ENABLED */
     74 #ifdef SOLARIS_PRIVS
     75 #include <priv.h>
     76 #endif	/* SOLARIS_PRIVS */
     77 
     78 /*
     79  * Special kludge for off_t being a signed quantity.
     80  */
     81 #if _FILE_OFFSET_BITS == 64
     82 typedef	u_longlong_t	u_off_t;
     83 #else
     84 typedef	ulong_t		u_off_t;
     85 #endif
     86 
     87 #define	SECMODE	0xe080
     88 
     89 #define	DEVNULL		"/dev/null"
     90 #define	XATTRHDR	".hdr"
     91 
     92 #define	NAMELEN		32
     93 #define	TYPELEN 	16
     94 #define	PERMLEN		4
     95 
     96 #define	FILE_COPIED	1
     97 #define	FILE_LINKED	2
     98 #define	FILE_PASS_ERR	-1
     99 
    100 #define	ARCHIVE_NORMAL	0
    101 #define	ARCHIVE_ACL	1
    102 #define	ARCHIVE_XATTR	2
    103 
    104 #ifndef	VIEW_READONLY
    105 #define	VIEW_READONLY	"SUNWattr_ro"
    106 #endif
    107 
    108 #ifndef	VIEW_READWRITE
    109 #define	VIEW_READWRITE	"SUNWattr_rw"
    110 #endif
    111 
    112 
    113 #define	LSTAT(dir, path, statbuf) fstatat(dir, \
    114     get_component((Gen.g_attrnam_p == NULL) ? \
    115     path : Gen.g_attrnam_p), statbuf, AT_SYMLINK_NOFOLLOW)
    116 #define	STAT(dir, path, statbuf) fstatat(dir, \
    117     get_component((Gen.g_attrnam_p == NULL) ? \
    118     path : Gen.g_attrnam_p), statbuf, 0)
    119 
    120 /*
    121  *	These limits reflect the maximum size regular file that
    122  *	can be archived, depending on the archive type. For archives
    123  *	with character-format headers (odc, tar, ustar) we use
    124  *	CHAR_OFFSET_MAX.  For archives with SVR4 ASCII headers (-c, -H crc)
    125  *	we store filesize in an 8-char hexadecimal string and use
    126  *	ASC_OFFSET_MAX.  Otherwise, we are limited to the size that will
    127  *	fit in a signed long value.
    128  */
    129 #define	CHAR_OFFSET_MAX	077777777777ULL	/* 11 octal digits */
    130 #define	ASC_OFFSET_MAX	0XFFFFFFFF	/* 8 hexadecimal digits */
    131 #define	BIN_OFFSET_MAX	LONG_MAX	/* signed long max value */
    132 
    133 #define	POSIXMODES	07777
    134 
    135 static char	aclchar = ' ';
    136 
    137 static struct Lnk *add_lnk(struct Lnk **);
    138 static int bfill(void);
    139 static void bflush(void);
    140 static int chgreel(int dir);
    141 static int ckname(int);
    142 static void ckopts(long mask);
    143 static long cksum(char hdr, int byt_cnt, int *err);
    144 static int creat_hdr(void);
    145 static int creat_lnk(int dirfd, char *name1_p, char *name2_p);
    146 static int creat_spec(int dirfd);
    147 static int creat_tmp(char *nam_p);
    148 static void data_in(int proc_mode);
    149 static void data_out(void);
    150 static void data_pass(void);
    151 static void file_in(void);
    152 static int file_out(void);
    153 static int file_pass(void);
    154 static void flush_lnks(void);
    155 static int gethdr(void);
    156 static int getname(void);
    157 static void getpats(int largc, char **largv);
    158 static void ioerror(int dir);
    159 static int matched(void);
    160 static int missdir(char *nam_p);
    161 static long mklong(short v[]);
    162 static void mkshort(short sval[], long v);
    163 static void msg(int severity, const char *fmt, ...);
    164 static int openout(int dirfd);
    165 static int read_hdr(int hdr);
    166 static void reclaim(struct Lnk *l_p);
    167 static void rstbuf(void);
    168 static void setpasswd(char *nam);
    169 static void rstfiles(int over, int dirfd);
    170 static void scan4trail(void);
    171 static void setup(int largc, char **largv);
    172 static void set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime);
    173 static void sigint(int sig);
    174 static void swap(char *buf_p, int cnt);
    175 static void usage(void);
    176 static void verbose(char *nam_p);
    177 static void write_hdr(int secflag, off_t len);
    178 static void write_trail(void);
    179 static int ustar_dir(void);
    180 static int ustar_spec(void);
    181 static struct stat *convert_to_old_stat(struct stat *, char *, char *);
    182 static void read_bar_vol_hdr(void);
    183 static void read_bar_file_hdr(void);
    184 static void setup_uncompress(FILE **);
    185 static void skip_bar_volhdr(void);
    186 static void bar_file_in(void);
    187 static int g_init(int *devtype, int *fdes);
    188 static int g_read(int, int, char *, unsigned);
    189 static int g_write(int, int, char *, unsigned);
    190 static int is_floppy(int);
    191 static int is_tape(int);
    192 static void write_ancillary(char *secinfo, int len);
    193 static int remove_dir(char *);
    194 static int save_cwd(void);
    195 static void rest_cwd(int cwd);
    196 
    197 static void xattrs_out(int (*func)());
    198 static void get_parent(char *path, char *dir);
    199 static void prepare_xattr_hdr(char **attrbuf, char *filename,
    200     char *attrname, char typeflag, struct Lnk *linkinfo, int *rlen);
    201 static char tartype(int type);
    202 static int openfile(int omode);
    203 static mode_t attrmode(char type);
    204 static char *get_component(char *path);
    205 static int open_dir(char *name);
    206 static int open_dirfd();
    207 static void close_dirfd();
    208 static void write_xattr_hdr();
    209 static char *skipslashes(char *string, char *start);
    210 static int read_xattr_hdr();
    211 static void chop_endslashes(char *path);
    212 
    213 
    214 /* helpful types */
    215 
    216 static
    217 struct passwd	*Curpw_p,	/* Current password entry for -t option */
    218 		*Rpw_p,		/* Password entry for -R option */
    219 		*dpasswd;
    220 
    221 static
    222 struct group	*Curgr_p,	/* Current group entry for -t option */
    223 		*dgroup;
    224 
    225 /* Data structure for buffered I/O. */
    226 
    227 static
    228 struct buf_info {
    229 	char	*b_base_p,	/* Pointer to base of buffer */
    230 		*b_out_p,	/* Position to take bytes from buffer at */
    231 		*b_in_p,	/* Position to put bytes into buffer at */
    232 		*b_end_p;	/* Pointer to end of buffer */
    233 	long	b_cnt,		/* Count of unprocessed bytes */
    234 		b_size;		/* Size of buffer in bytes */
    235 } Buffr;
    236 
    237 /* Generic header format */
    238 
    239 static
    240 struct gen_hdr {
    241 	ulong_t	g_magic,	/* Magic number field */
    242 		g_ino,		/* Inode number of file */
    243 		g_mode,		/* Mode of file */
    244 		g_uid,		/* Uid of file */
    245 		g_gid,		/* Gid of file */
    246 		g_nlink,	/* Number of links */
    247 		g_mtime;	/* Modification time */
    248 	off_t	g_filesz;	/* Length of file */
    249 	ulong_t	g_dev,		/* File system of file */
    250 		g_rdev,		/* Major/minor numbers of special files */
    251 		g_namesz,	/* Length of filename */
    252 		g_cksum;	/* Checksum of file */
    253 	char	g_gname[32],
    254 		g_uname[32],
    255 		g_version[2],
    256 		g_tmagic[6],
    257 		g_typeflag;
    258 	char	*g_tname,
    259 		*g_prefix,
    260 		*g_nam_p,	/* Filename */
    261 		*g_attrparent_p, /* attribute parent */
    262 		*g_attrpath_p, /* attribute path */
    263 		*g_attrnam_p,	/* attribute */
    264 		*g_attrfnam_p,  /* Real file name attr belongs to */
    265 		*g_linktoattrfnam_p, /* file linked attribute belongs to */
    266 		*g_linktoattrnam_p,  /* attribute g_attrnam_p is linked to */
    267 		*g_dirpath;	/* dirname currently opened */
    268 	int	g_dirfd;	/* directory file descriptor */
    269 	int	g_passdirfd;	/* directory fd to pass to */
    270 	int	g_rw_sysattr;	/* read-write system attribute */
    271 	int	g_baseparent_fd;	/* base file's parent fd */
    272 
    273 } Gen, *G_p;
    274 
    275 /* Data structure for handling multiply-linked files */
    276 static
    277 char	prebuf[PRESIZ+1],
    278 	nambuf[NAMSIZ+1],
    279 	fullnam[MAXNAM+1];
    280 
    281 
    282 static
    283 struct Lnk {
    284 	short	L_cnt,		/* Number of links encountered */
    285 		L_data;		/* Data has been encountered if 1 */
    286 	struct gen_hdr	L_gen;	/* gen_hdr information for this file */
    287 	struct Lnk	*L_nxt_p,	/* Next file in list */
    288 			*L_bck_p,	/* Previous file in list */
    289 			*L_lnk_p;	/* Next link for this file */
    290 } Lnk_hd;
    291 
    292 static
    293 struct hdr_cpio	Hdr;
    294 
    295 /*
    296  * -------------------------------------------------------------------------
    297  *		   Stuff needed to pre-view the name stream
    298  *
    299  * issymlink is used to remember that the current file is a symlink between
    300  * getname() and file_pass(); the former trashes this information immediately
    301  * when -L is specified.
    302  */
    303 
    304 static
    305 int	issymlink = 0;
    306 
    307 static
    308 FILE	*In_p = stdin;		/* Where the input comes from */
    309 
    310 typedef struct sl_info
    311 {
    312 	struct sl_info *llink;	/* Left subtree ptr (tree depth in *sl_head) */
    313 	struct sl_info *rlink;	/* Right subtree ptr */
    314 	int bal;		/* Subtree balance factor */
    315 	ulong_t	sl_count;	/* Number of symlinks */
    316 	int	sl_ftype;	/* file type of inode */
    317 	ino_t	sl_ino;		/* Inode of file */
    318 	ino_t	sl_ino2;	/* alternate inode for -Hodc */
    319 } sl_info_t;
    320 
    321 typedef struct data_in
    322 {
    323 	int	data_in_swapfile;
    324 	int	data_in_proc_mode;
    325 	int	data_in_partialflg;
    326 	int	data_in_compress_flag;
    327 	long	data_in_cksumval;
    328 	FILE	*data_in_pipef;
    329 } data_in_t;
    330 
    331 /*
    332  * The following structure maintains a hash entry for the
    333  * balancing trees which are allocated for each device nodes.
    334  */
    335 typedef struct sl_info_link
    336 {
    337 	dev_t		dev;
    338 	sl_info_t	*head;
    339 	struct sl_info_link *next;
    340 } sl_info_link_t;
    341 
    342 #define	SL_INFO_ALLOC_CHUNK	1024
    343 #define	NDEVHENTRY		0x40
    344 #define	DEV_HASHKEY(x)		((x) & (NDEVHENTRY -1))
    345 
    346 /*
    347  * For remapping dev,inode for -Hodc archives.
    348  */
    349 
    350 typedef struct sl_remap
    351 {
    352 	dev_t			dev;		/* device */
    353 	int			inode_count;	/* # inodes seen on dev */
    354 	struct sl_remap 	*next;		/* next in the chain */
    355 } sl_remap_t;
    356 
    357 /* forward declarations */
    358 
    359 static sl_info_t 	*sl_info_alloc(void);
    360 static sl_info_t 	*sl_insert(dev_t, ino_t, int);
    361 static ulong_t		sl_numlinks(dev_t, ino_t, int);
    362 static void		sl_preview_synonyms(void);
    363 static void		sl_remember_tgt(const struct stat *, int, int);
    364 static sl_info_t 	*sl_search(dev_t, ino_t, int);
    365 static sl_info_t	*sl_devhash_lookup(dev_t);
    366 static void		sl_devhash_insert(dev_t, sl_info_t *);
    367 
    368 extern int		sl_compare(ino_t, int, ino_t, int);
    369 #define	sl_compare(lino, lftype, rino, rftype)	(lino < rino ? -1 : \
    370 	    (lino > rino ? 1 : (lftype < rftype ? -1 : \
    371 	    (lftype > rftype ? 1 : 0))))
    372 
    373 /* global storage */
    374 
    375 static sl_remap_t  *sl_remap_head = NULL; /* head of the inode-remap list */
    376 static sl_info_link_t	*sl_devhash[NDEVHENTRY]; /* hash table */
    377 
    378 /*
    379  * -------------------------------------------------------------------------
    380  */
    381 
    382 static
    383 struct stat	ArchSt,	/* stat(2) information of the archive */
    384 		SrcSt,	/* stat(2) information of source file */
    385 		DesSt,	/* stat(2) of destination file */
    386 		*OldSt = NULL;	/* stat info converted to svr32 format */
    387 
    388 /*
    389  * bin_mag: Used to validate a binary magic number,
    390  * by combining to bytes into an unsigned short.
    391  */
    392 
    393 static
    394 union bin_mag {
    395 	unsigned char b_byte[2];
    396 	ushort_t b_half;
    397 } Binmag;
    398 
    399 static
    400 union tblock *Thdr_p;	/* TAR header pointer */
    401 
    402 static union b_block *bar_Vhdr;
    403 static struct gen_hdr Gen_bar_vol;
    404 
    405 /*
    406  * swpbuf: Used in swap() to swap bytes within a halfword,
    407  * halfwords within a word, or to reverse the order of the
    408  * bytes within a word.  Also used in mklong() and mkshort().
    409  */
    410 
    411 static
    412 union swpbuf {
    413 	unsigned char	s_byte[4];
    414 	ushort_t	s_half[2];
    415 	ulong_t	s_word;
    416 } *Swp_p;
    417 
    418 static
    419 char	*myname,		/* program name */
    420 	Adir,			/* Flags object as a directory */
    421 	Hiddendir,		/* Processing hidden attribute directory */
    422 	Aspec,			/* Flags object as a special file */
    423 	Do_rename,		/* Indicates rename() is to be used */
    424 	Time[50],		/* Array to hold date and time */
    425 	Ttyname[] = "/dev/tty",	/* Controlling console */
    426 	T_lname[MAXPATHLEN],	/* Array to hold links name for tar */
    427 	*Buf_p,			/* Buffer for file system I/O */
    428 	*Empty,			/* Empty block for TARTYP headers */
    429 	*Full_p,		/* Pointer to full pathname */
    430 	*Efil_p,		/* -E pattern file string */
    431 	*Eom_p = "Change to part %d and press RETURN key. [q] ",
    432 	*Fullnam_p,		/* Full pathname */
    433 	*Attrfile_p,		/* attribute file */
    434 	*Hdr_p,			/* -H header type string */
    435 	*IOfil_p,		/* -I/-O input/output archive string */
    436 	*Lnkend_p,		/* Pointer to end of Lnknam_p */
    437 	*Lnknam_p,		/* Buffer for linking files with -p option */
    438 	*Nam_p,			/* Array to hold filename */
    439 	*Savenam_p,		/* copy of filename xattr belongs to */
    440 	*Own_p,			/* New owner login id string */
    441 	*Renam_p,		/* Buffer for renaming files */
    442 	*Renam_attr_p,		/* Buffer for renaming attr with sys attrs */
    443 	*Renametmp_p,		/* Tmp Buffer for renaming files */
    444 	*Symlnk_p,		/* Buffer for holding symbolic link name */
    445 	*Over_p,		/* Holds temporary filename when overwriting */
    446 	**Pat_pp = 0,		/* Pattern strings */
    447 	bar_linkflag,		/* flag to indicate if the file is a link */
    448 	bar_linkname[MAXPATHLEN]; /* store the name of the link */
    449 
    450 static
    451 int	Append = 0,	/* Flag set while searching to end of archive */
    452 	Archive,	/* File descriptor of the archive */
    453 	Buf_error = 0,	/* I/O error occurred during buffer fill */
    454 	Def_mode = 0777,	/* Default file/directory protection modes */
    455 	Device,		/* Device type being accessed (used with libgenIO) */
    456 	Error_cnt = 0,	/* Cumulative count of I/O errors */
    457 	Finished = 1,	/* Indicates that a file transfer has completed */
    458 	Hdrsz = ASCSZ,	/* Fixed length portion of the header */
    459 	Hdr_type,		/* Flag to indicate type of header selected */
    460 	Ifile,		/* File des. of file being archived */
    461 	Ofile,		/* File des. of file being extracted from archive */
    462 	Use_old_stat = 0,    /* Create an old style -Hodc hdr (small dev's) */
    463 	Onecopy = 0,	/* Flags old vs. new link handling */
    464 	Pad_val = 0,	/* Indicates the number of bytes to pad (if any) */
    465 	PageSize = 0,	/* The native page size, used for figuring block size */
    466 	Volcnt = 1,	/* Number of archive volumes processed */
    467 	Verbcnt = 0,	/* Count of number of dots '.' output */
    468 	Eomflag = 0,
    469 	Dflag = 0,
    470 	Atflag = 0,	/* Archive/restore extended attributes */
    471 	SysAtflag = 0,	/* Archive/restore extended system attributes */
    472 	Compressed,	/* Flag to indicate if the bar archive is compressed */
    473 	Bar_vol_num = 0, /* Volume number count for bar archive */
    474 	privileged = 0,	/* Flag set if running with higher privileges */
    475 	attr_baseparent_fd = -1;	/* attribute's base file descriptor */
    476 
    477 
    478 static
    479 gid_t	Lastgid = (gid_t)-1;	/* Used with -t & -v to record current gid */
    480 
    481 static
    482 uid_t	Lastuid = (uid_t)-1;	/* Used with -t & -v to record current uid */
    483 
    484 static
    485 long	Args,		/* Mask of selected options */
    486 	Max_namesz = CPATH;	/* Maximum size of pathnames/filenames */
    487 
    488 static
    489 int	Bufsize = BUFSZ;	/* Default block size */
    490 
    491 
    492 static u_longlong_t    Blocks;	/* full blocks transferred */
    493 static u_longlong_t    SBlocks;	/* cumulative char count from short reads */
    494 
    495 
    496 static off_t	Max_offset = BIN_OFFSET_MAX;	/* largest file size */
    497 static off_t	Max_filesz;			/* from getrlimit */
    498 
    499 static ulong_t	Savedev;
    500 
    501 static
    502 FILE	*Ef_p,			/* File pointer of pattern input file */
    503 	*Err_p = stderr,	/* File pointer for error reporting */
    504 	*Out_p = stdout,	/* File pointer for non-archive output */
    505 	*Rtty_p,		/* Input file pointer for interactive rename */
    506 	*Wtty_p;		/* Output file ptr for interactive rename */
    507 
    508 static
    509 ushort_t	Ftype = S_IFMT;	/* File type mask */
    510 
    511 /* ACL support */
    512 static struct sec_attr {
    513 	char	attr_type;
    514 	char	attr_len[7];
    515 	char	attr_info[1];
    516 } *attr;
    517 
    518 static int	Pflag = 0;	/* flag indicates that acl is preserved */
    519 static int	acl_is_set = 0; /* True if an acl was set on the file */
    520 
    521 acl_t *aclp;
    522 
    523 #if defined(O_XATTR)
    524 typedef enum {
    525 	ATTR_OK,
    526 	ATTR_SKIP,
    527 	ATTR_CHDIR_ERR,
    528 	ATTR_OPEN_ERR,
    529 	ATTR_XATTR_ERR,
    530 	ATTR_SATTR_ERR
    531 } attr_status_t;
    532 #endif
    533 
    534 #if defined(O_XATTR)
    535 typedef enum {
    536 	ARC_CREATE,
    537 	ARC_RESTORE
    538 } arc_action_t;
    539 #endif
    540 
    541 
    542 /*
    543  *
    544  * cpio has been changed to support extended attributes.
    545  *
    546  * As part of this change cpio has been changed to use the new *at() syscalls
    547  * such as openat, fchownat(), unlinkat()...
    548  *
    549  * This was done so that attributes can be handled with as few code changes
    550  * as possible.
    551  *
    552  * What this means is that cpio now opens the directory that a file or directory
    553  * resides in and then performs *at() functions to manipulate the entry.
    554  *
    555  * For example a new file is now created like this:
    556  *
    557  * dfd = open(<some dir path>)
    558  * fd = openat(dfd, <name>,....);
    559  *
    560  * or in the case of an extended attribute
    561  *
    562  * dfd = attropen(<pathname>, ".", ....)
    563  *
    564  * Once we have a directory file descriptor all of the *at() functions can
    565  * be applied to it.
    566  *
    567  * unlinkat(dfd, <component name>,...)
    568  * fchownat(dfd, <component name>,..)
    569  *
    570  * This works for both normal namespace files and extended attribute file
    571  *
    572  */
    573 
    574 /*
    575  * Extended attribute layout
    576  *
    577  * Extended attributes are stored in two pieces.
    578  * 1. An attribute header which has information about
    579  *    what file the attribute is for and what the attribute
    580  *    is named.
    581  * 2. The attribute record itself.  Stored as a normal file type
    582  *    of entry.
    583  * Both the header and attribute record have special modes/typeflags
    584  * associated with them.
    585  *
    586  * The names of the header in the archive look like:
    587  * /dev/null/attr.hdr
    588  *
    589  * The name of the attribute looks like:
    590  * /dev/null/attr.
    591  *
    592  * This is done so that an archiver that doesn't understand these formats
    593  * can just dispose of the attribute records unless the user chooses to
    594  * rename them via cpio -r or pax -i
    595  *
    596  * The format is composed of a fixed size header followed
    597  * by a variable sized xattr_buf. If the attribute is a hard link
    598  * to another attribute, then another xattr_buf section is included
    599  * for the link.
    600  *
    601  * The xattr_buf is used to define the necessary "pathing" steps
    602  * to get to the extended attribute.  This is necessary to support
    603  * a fully recursive attribute model where an attribute may itself
    604  * have an attribute.
    605  *
    606  * The basic layout looks like this.
    607  *
    608  *     --------------------------------
    609  *     |                              |
    610  *     |         xattr_hdr            |
    611  *     |                              |
    612  *     --------------------------------
    613  *     --------------------------------
    614  *     |                              |
    615  *     |        xattr_buf             |
    616  *     |                              |
    617  *     --------------------------------
    618  *     --------------------------------
    619  *     |                              |
    620  *     |      (optional link info)    |
    621  *     |                              |
    622  *     --------------------------------
    623  *     --------------------------------
    624  *     |                              |
    625  *     |      attribute itself        |
    626  *     |      stored as normal tar    |
    627  *     |      or cpio data with       |
    628  *     |      special mode or         |
    629  *     |      typeflag                |
    630  *     |                              |
    631  *     --------------------------------
    632  *
    633  */
    634 
    635 /*
    636  * Extended attributes structures
    637  *
    638  * xattrhead is the complete extended attribute header, as read of off
    639  * disk/tape. It includes the variable xattr_buf portion.
    640  *
    641  * xattrp is basically an offset into xattrhead that points to the
    642  * "pathing" section which defines how to get to the attribute.
    643  *
    644  * xattr_linkp is identical to xattrp except that it is used for linked
    645  * attributes.  It provides the pathing steps to get to the linked
    646  * attribute.
    647  *
    648  * These structures are updated when an extended attribute header is read off
    649  * of disk/tape.
    650  */
    651 static struct xattr_hdr	*xattrhead;
    652 static struct xattr_buf	*xattrp;
    653 static struct xattr_buf	*xattr_linkp;
    654 static int 		xattrbadhead;	/* is extended attribute header bad? */
    655 
    656 static int	append_secattr(char **, int *, acl_t *);
    657 static void	write_ancillary(char *, int);
    658 
    659 /*
    660  * Note regarding cpio and changes to ensure cpio doesn't try to second
    661  * guess whether it runs with sufficient privileges or not:
    662  *
    663  * cpio has been changed so that it doesn't carry a second implementation of
    664  * the kernel's policy with respect to privileges.  Instead of attempting
    665  * to restore uid and gid from an archive only if cpio is run as uid 0,
    666  * cpio now *always* tries to restore the uid and gid from the archive
    667  * except when the -R option is specified.  When the -R is specified,
    668  * the uid and gid of the restored file will be changed to those of the
    669  * login id specified.  In addition, chown(), set_tym(), and chmod() should
    670  * only be executed once during archive extraction, and to ensure
    671  * setuid/setgid bits are restored properly, chown() should always be
    672  * executed before chmod().
    673  *
    674  * Note regarding debugging mechanism for cpio:
    675  *
    676  * The following mechanism is provided to allow us to debug cpio in complicated
    677  * situations, like when it is part of a pipe.  The idea is that you compile
    678  * with -DWAITAROUND defined, and then add the "-z" command line option to the
    679  * target cpio invocation.  If stderr is available, it will tell you to which
    680  * pid to attach the debugger; otherwise, use ps to find it.  Attach to the
    681  * process from the debugger, and, *PRESTO*, you are there!
    682  *
    683  * Simply assign "waitaround = 0" once you attach to the process, and then
    684  * proceed from there as usual.
    685  */
    686 
    687 #ifdef WAITAROUND
    688 int waitaround = 0;		/* wait for rendezvous with the debugger */
    689 #endif
    690 
    691 /*
    692  * Allocation wrappers and their flags
    693  */
    694 #define	E_NORMAL	0x0	/* Return NULL if allocation fails */
    695 #define	E_EXIT		0x1	/* Exit if allocation fails */
    696 
    697 static void *e_realloc(int flag, void *old, size_t newsize);
    698 static char *e_strdup(int flag, const char *arg);
    699 static void *e_valloc(int flag, size_t size);
    700 static void *e_zalloc(int flag, size_t size);
    701 
    702 #define	EXIT_CODE	(Error_cnt > 255 ? 255 : Error_cnt)
    703 
    704 /*
    705  * main: Call setup() to process options and perform initializations,
    706  * and then select either copy in (-i), copy out (-o), or pass (-p) action.
    707  */
    708 
    709 int
    710 main(int argc, char **argv)
    711 {
    712 	int i;
    713 	int passret;
    714 
    715 	(void) setlocale(LC_ALL, "");
    716 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
    717 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
    718 #endif
    719 	(void) textdomain(TEXT_DOMAIN);
    720 
    721 	(void) memset(&Gen, 0, sizeof (Gen));
    722 	myname = e_strdup(E_EXIT, basename(argv[0]));
    723 	setup(argc, argv);
    724 
    725 	if (signal(SIGINT, sigint) == SIG_IGN)
    726 		(void) signal(SIGINT, SIG_IGN);
    727 	switch (Args & (OCi | OCo | OCp)) {
    728 	case OCi: /* COPY IN */
    729 		Hdr_type = NONE;
    730 		if (Atflag || SysAtflag) {
    731 			/*
    732 			 * Save the current working directory, so
    733 			 * we can change back here after cd'ing into
    734 			 * the attribute directory when processing
    735 			 * attributes.
    736 			 */
    737 			if ((attr_baseparent_fd = save_cwd()) < 0) {
    738 				msg(EXT, "Unable to open current directory.");
    739 			}
    740 		}
    741 		while ((i = gethdr()) != 0) {
    742 			Gen.g_dirfd = -1;
    743 			if (i == 1) {
    744 				file_in();
    745 				/*
    746 				 * Any ACL info for this file would or should
    747 				 * have been used after file_in(); clear out
    748 				 * aclp so it is is not erroneously used on
    749 				 * the next file.
    750 				 */
    751 				if (aclp != NULL) {
    752 					acl_free(aclp);
    753 					aclp = NULL;
    754 				}
    755 				acl_is_set = 0;
    756 			}
    757 			(void) memset(&Gen, 0, sizeof (Gen));
    758 		}
    759 		/* Do not count "extra" "read-ahead" buffered data */
    760 		if (Buffr.b_cnt > Bufsize)
    761 			Blocks -=  (u_longlong_t)(Buffr.b_cnt / Bufsize);
    762 		break;
    763 	case OCo: /* COPY OUT */
    764 		if (Args & OCA) {
    765 			scan4trail();
    766 		}
    767 
    768 		Gen.g_dirfd = -1;
    769 		Gen.g_dirpath = NULL;
    770 		sl_preview_synonyms();
    771 
    772 		while ((i = getname()) != 0) {
    773 			if (i == 1) {
    774 				(void) file_out();
    775 				if (Atflag || SysAtflag) {
    776 					if (Gen.g_dirfd != -1) {
    777 						(void) close(Gen.g_dirfd);
    778 					}
    779 					Gen.g_dirfd = -1;
    780 					xattrs_out(file_out);
    781 				}
    782 			}
    783 			if (aclp != NULL) {
    784 				acl_free(aclp);
    785 				aclp = NULL;
    786 				acl_is_set = 0;
    787 			}
    788 		}
    789 		write_trail();
    790 		break;
    791 	case OCp: /* PASS */
    792 		sl_preview_synonyms();
    793 
    794 		Gen.g_dirfd = -1;
    795 		Gen.g_passdirfd = -1;
    796 		Gen.g_dirpath = NULL;
    797 		while (getname()) {
    798 			/*
    799 			 * If file is a fully qualified path then
    800 			 * file_pass will strip off the leading '/'
    801 			 * and we need to save off the unstripped
    802 			 * name for attribute traversal.
    803 			 */
    804 			if (Atflag || SysAtflag) {
    805 				(void) strcpy(Savenam_p, Gen.g_nam_p);
    806 			}
    807 			passret = file_pass();
    808 			if (aclp != NULL) {
    809 				acl_free(aclp);
    810 				aclp = NULL;
    811 				acl_is_set = 0;
    812 			}
    813 			if (Gen.g_passdirfd != -1)
    814 				(void) close(Gen.g_passdirfd);
    815 			Gen.g_passdirfd = -1;
    816 			if (Atflag || SysAtflag) {
    817 				if (Gen.g_dirfd != -1) {
    818 					(void) close(Gen.g_dirfd);
    819 				}
    820 				Gen.g_dirfd = -1;
    821 				if (passret != FILE_LINKED) {
    822 					Gen.g_nam_p = Savenam_p;
    823 					xattrs_out(file_pass);
    824 				}
    825 			}
    826 		}
    827 		break;
    828 	default:
    829 		msg(EXT, "Impossible action.");
    830 	}
    831 	if (Ofile > 0) {
    832 		if (close(Ofile) != 0)
    833 			msg(EXTN, "close error");
    834 	}
    835 	if (Archive > 0) {
    836 		if (close(Archive) != 0)
    837 			msg(EXTN, "close error");
    838 	}
    839 	Blocks = (u_longlong_t)(Blocks * Bufsize + SBlocks + 0x1FF) >> 9;
    840 	msg(EPOST, "%lld blocks", Blocks);
    841 	if (Error_cnt)
    842 		msg(EPOST, "%d error(s)", Error_cnt);
    843 	return (EXIT_CODE);
    844 }
    845 
    846 /*
    847  * add_lnk: Add a linked file's header to the linked file data structure, by
    848  * either adding it to the end of an existing sub-list or starting
    849  * a new sub-list.  Each sub-list saves the links to a given file.
    850  *
    851  * Directly returns a pointer to the new entry; returns a pointer to the head
    852  * of the sub-list in which that entry is located through the argument.
    853  */
    854 
    855 static struct Lnk *
    856 add_lnk(struct Lnk **sublist_return)
    857 {
    858 	struct Lnk *new_entry, *sublist;
    859 
    860 	for (sublist = Lnk_hd.L_nxt_p;
    861 	    sublist != &Lnk_hd;
    862 	    sublist = sublist->L_nxt_p) {
    863 		if (sublist->L_gen.g_ino == G_p->g_ino &&
    864 		    sublist->L_gen.g_dev == G_p->g_dev) {
    865 			/* found */
    866 			break;
    867 		}
    868 	}
    869 
    870 	new_entry = e_zalloc(E_EXIT, sizeof (struct Lnk));
    871 
    872 	new_entry->L_lnk_p = NULL;
    873 	new_entry->L_gen = *G_p; /* structure copy */
    874 
    875 	new_entry->L_gen.g_nam_p = e_zalloc(E_EXIT, (size_t)G_p->g_namesz);
    876 
    877 	(void) strcpy(new_entry->L_gen.g_nam_p, G_p->g_nam_p);
    878 
    879 	if (sublist == &Lnk_hd) {
    880 		/* start new sub-list */
    881 		new_entry->L_nxt_p = &Lnk_hd;
    882 		new_entry->L_bck_p = Lnk_hd.L_bck_p;
    883 		Lnk_hd.L_bck_p = new_entry->L_bck_p->L_nxt_p = new_entry;
    884 		new_entry->L_lnk_p = NULL;
    885 		new_entry->L_cnt = 1;
    886 		new_entry->L_data = Onecopy ? 0 : 1;
    887 		sublist = new_entry;
    888 	} else {
    889 		/* add to existing sub-list */
    890 		struct Lnk *ptr;
    891 
    892 		sublist->L_cnt++;
    893 
    894 		for (ptr = sublist;
    895 		    ptr->L_lnk_p != NULL;
    896 		    ptr = ptr->L_lnk_p) {
    897 			ptr->L_gen.g_filesz = G_p->g_filesz;
    898 		}
    899 
    900 		ptr->L_gen.g_filesz = G_p->g_filesz;
    901 		ptr->L_lnk_p = new_entry;
    902 	}
    903 
    904 	*sublist_return = sublist;
    905 	return (new_entry);
    906 }
    907 
    908 /*
    909  * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
    910  * moving them to rd_buf_p.  When there are no bytes left in the I/O buffer,
    911  * Fillbuf is set and the I/O buffer is filled.  The variable dist is the
    912  * distance to lseek if an I/O error is encountered with the -k option set
    913  * (converted to a multiple of Bufsize).
    914  */
    915 
    916 static int
    917 bfill(void)
    918 {
    919 	int i = 0, rv;
    920 	static int eof = 0;
    921 
    922 	if (!Dflag) {
    923 	while ((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) {
    924 		errno = 0;
    925 		if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
    926 			if (((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) &&
    927 			    (Eomflag == 0)) {
    928 				Eomflag = 1;
    929 				return (1);
    930 			}
    931 			if (errno == ENOSPC) {
    932 				(void) chgreel(INPUT);
    933 				if (Hdr_type == BAR) {
    934 					skip_bar_volhdr();
    935 				}
    936 				continue;
    937 			} else if (Args & OCk) {
    938 				if (i++ > MX_SEEKS)
    939 					msg(EXT, "Cannot recover.");
    940 				if (lseek(Archive, Bufsize, SEEK_REL) < 0)
    941 					msg(EXTN, "Cannot lseek()");
    942 				Error_cnt++;
    943 				Buf_error++;
    944 				rv = 0;
    945 				continue;
    946 			} else
    947 				ioerror(INPUT);
    948 		} /* (rv = g_read(Device, Archive ... */
    949 		if (Hdr_type != BAR || rv == Bufsize) {
    950 			Buffr.b_in_p += rv;
    951 			Buffr.b_cnt += (long)rv;
    952 		}
    953 		if (rv == Bufsize) {
    954 			eof = 0;
    955 			Blocks++;
    956 		} else if (rv == 0) {
    957 			if (!eof) {
    958 				eof = 1;
    959 				break;
    960 			}
    961 			(void) chgreel(INPUT);
    962 			eof = 0;	/* reset the eof after chgreel	*/
    963 
    964 			/*
    965 			 * if spans multiple volume, skip the volume header of
    966 			 * the next volume so that the file currently being
    967 			 * extracted can continue to be extracted.
    968 			 */
    969 			if (Hdr_type == BAR) {
    970 				skip_bar_volhdr();
    971 			}
    972 
    973 			continue;
    974 		} else {
    975 			eof = 0;
    976 			SBlocks += (u_longlong_t)rv;
    977 		}
    978 	} /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
    979 
    980 	} else {			/* Dflag */
    981 		errno = 0;
    982 		if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
    983 			return (-1);
    984 		} /* (rv = g_read(Device, Archive ... */
    985 		Buffr.b_in_p += rv;
    986 		Buffr.b_cnt += (long)rv;
    987 		if (rv == Bufsize) {
    988 			eof = 0;
    989 			Blocks++;
    990 		} else if (!rv) {
    991 			if (!eof) {
    992 				eof = 1;
    993 				return (rv);
    994 			}
    995 			return (-1);
    996 		} else {
    997 			eof = 0;
    998 			SBlocks += (u_longlong_t)rv;
    999 		}
   1000 	}
   1001 	return (rv);
   1002 }
   1003 
   1004 /*
   1005  * bflush: Move wr_cnt bytes from data_p into the I/O buffer.  When the
   1006  * I/O buffer is full, Flushbuf is set and the buffer is written out.
   1007  */
   1008 
   1009 static void
   1010 bflush(void)
   1011 {
   1012 	int rv;
   1013 
   1014 	while (Buffr.b_cnt >= Bufsize) {
   1015 		errno = 0;
   1016 		if ((rv = g_write(Device, Archive, Buffr.b_out_p,
   1017 		    Bufsize)) < 0) {
   1018 			if (errno == ENOSPC && !Dflag)
   1019 				rv = chgreel(OUTPUT);
   1020 			else
   1021 				ioerror(OUTPUT);
   1022 		}
   1023 		Buffr.b_out_p += rv;
   1024 		Buffr.b_cnt -= (long)rv;
   1025 		if (rv == Bufsize)
   1026 			Blocks++;
   1027 		else if (rv > 0)
   1028 			SBlocks += (u_longlong_t)rv;
   1029 	}
   1030 	rstbuf();
   1031 }
   1032 
   1033 /*
   1034  * chgreel: Determine if end-of-medium has been reached.  If it has,
   1035  * close the current medium and prompt the user for the next medium.
   1036  */
   1037 
   1038 static int
   1039 chgreel(int dir)
   1040 {
   1041 	int lastchar, tryagain, askagain, rv;
   1042 	int tmpdev;
   1043 	char str[APATH];
   1044 	struct stat statb;
   1045 
   1046 	rv = 0;
   1047 	if (fstat(Archive, &statb) < 0)
   1048 		msg(EXTN, "Error during stat() of archive");
   1049 	if ((statb.st_mode & S_IFMT) != S_IFCHR) {
   1050 		if (dir == INPUT) {
   1051 			msg(EXT, "%s%s\n",
   1052 			    "Can't read input:  end of file encountered ",
   1053 			    "prior to expected end of archive.");
   1054 		}
   1055 	}
   1056 	msg(EPOST, "\007End of medium on \"%s\".", dir ? "output" : "input");
   1057 	if (is_floppy(Archive))
   1058 		(void) ioctl(Archive, FDEJECT, NULL);
   1059 	if ((close(Archive) != 0) && (dir == OUTPUT))
   1060 		msg(EXTN, "close error");
   1061 	Archive = 0;
   1062 	Volcnt++;
   1063 	for (;;