cpio.c revision 4321:a8930ec16e52
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 2007 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#ifdef SOLARIS_PRIVS
70#include <priv.h>
71#endif	/* SOLARIS_PRIVS */
72
73/*
74 * Special kludge for off_t being a signed quantity.
75 */
76#if _FILE_OFFSET_BITS == 64
77typedef	u_longlong_t	u_off_t;
78#else
79typedef	ulong_t		u_off_t;
80#endif
81
82#define	SECMODE	0xe080
83
84#define	DEVNULL		"/dev/null"
85#define	XATTRHDR	".hdr"
86
87#define	NAMELEN		32
88#define	TYPELEN 	16
89#define	PERMLEN		4
90
91#define	FILE_COPIED	1
92#define	FILE_LINKED	2
93#define	FILE_PASS_ERR	-1
94
95#define	ARCHIVE_NORMAL	0
96#define	ARCHIVE_ACL	1
97#define	ARCHIVE_XATTR	2
98
99#define	LSTAT(dir, path, statbuf) fstatat(dir, \
100    get_component((Gen.g_attrnam_p == (char *)NULL) ? \
101    path : Gen.g_attrnam_p), statbuf, AT_SYMLINK_NOFOLLOW)
102#define	STAT(dir, path, statbuf) fstatat(dir, \
103    get_component((Gen.g_attrnam_p == (char *)NULL) ? \
104    path : Gen.g_attrnam_p), statbuf, 0)
105
106/*
107 *	These limits reflect the maximum size regular file that
108 *	can be archived, depending on the archive type. For archives
109 *	with character-format headers (odc, tar, ustar) we use
110 *	CHAR_OFFSET_MAX.  For archives with SVR4 ASCII headers (-c, -H crc)
111 *	we store filesize in an 8-char hexadecimal string and use
112 *	ASC_OFFSET_MAX.  Otherwise, we are limited to the size that will
113 *	fit in a signed long value.
114 */
115#define	CHAR_OFFSET_MAX	077777777777ULL	/* 11 octal digits */
116#define	ASC_OFFSET_MAX	0XFFFFFFFF	/* 8 hexadecimal digits */
117#define	BIN_OFFSET_MAX	LONG_MAX	/* signed long max value */
118
119#define	POSIXMODES	07777
120
121static char	aclchar = ' ';
122
123static struct Lnk *add_lnk(struct Lnk **);
124static int bfill(void);
125static void bflush(void);
126static int chgreel(int dir);
127static int ckname(int);
128static void ckopts(long mask);
129static long cksum(char hdr, int byt_cnt, int *err);
130static int creat_hdr(void);
131static int creat_lnk(int dirfd, char *name1_p, char *name2_p);
132static int creat_spec(int dirfd);
133static int creat_tmp(char *nam_p);
134static void data_in(int proc_mode);
135static void data_out(void);
136static void data_pass(void);
137static void file_in(void);
138static int file_out(void);
139static int file_pass(void);
140static void flush_lnks(void);
141static int gethdr(void);
142static int getname(void);
143static void getpats(int largc, char **largv);
144static void ioerror(int dir);
145static int matched(void);
146static int missdir(char *nam_p);
147static long mklong(short v[]);
148static void mkshort(short sval[], long v);
149static void msg(int severity, const char *fmt, ...);
150static int openout(int dirfd);
151static int read_hdr(int hdr);
152static void reclaim(struct Lnk *l_p);
153static void rstbuf(void);
154static void setpasswd(char *nam);
155static void rstfiles(int over, int dirfd);
156static void scan4trail(void);
157static void setup(int largc, char **largv);
158static void set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime);
159static void sigint(int sig);
160static void swap(char *buf_p, int cnt);
161static void usage(void);
162static void verbose(char *nam_p);
163static void write_hdr(int secflag, off_t len);
164static void write_trail(void);
165static int ustar_dir(void);
166static int ustar_spec(void);
167static struct stat *convert_to_old_stat(struct stat *, char *, char *);
168static void read_bar_vol_hdr(void);
169static void read_bar_file_hdr(void);
170static void setup_uncompress(FILE **);
171static void skip_bar_volhdr(void);
172static void bar_file_in(void);
173static int g_init(int *devtype, int *fdes);
174static int g_read(int, int, char *, unsigned);
175static int g_write(int, int, char *, unsigned);
176static int is_floppy(int);
177static int is_tape(int);
178static void write_ancillary(char *secinfo, int len);
179static int remove_dir(char *);
180static int save_cwd(void);
181static void rest_cwd(int cwd);
182
183static void xattrs_out(int (*func)());
184static void get_parent(char *path, char *dir);
185static void prepare_xattr_hdr(char **attrbuf, char *filename,
186    char *attrname, char typeflag, struct Lnk *linkinfo, int *rlen);
187static char tartype(int type);
188static int openfile(int omode);
189static mode_t attrmode(char type);
190static char *get_component(char *path);
191static int open_dir(char *name);
192static int open_dirfd();
193static void close_dirfd();
194static void write_xattr_hdr();
195static int retry_attrdir_open(char *name);
196static char *skipslashes(char *string, char *start);
197static int read_xattr_hdr();
198static void chop_endslashes(char *path);
199
200
201/* helpful types */
202
203static
204struct passwd	*Curpw_p,	/* Current password entry for -t option */
205		*Rpw_p,		/* Password entry for -R option */
206		*dpasswd;
207
208static
209struct group	*Curgr_p,	/* Current group entry for -t option */
210		*dgroup;
211
212/* Data structure for buffered I/O. */
213
214static
215struct buf_info {
216	char	*b_base_p,	/* Pointer to base of buffer */
217		*b_out_p,	/* Position to take bytes from buffer at */
218		*b_in_p,	/* Position to put bytes into buffer at */
219		*b_end_p;	/* Pointer to end of buffer */
220	long	b_cnt,		/* Count of unprocessed bytes */
221		b_size;		/* Size of buffer in bytes */
222} Buffr;
223
224/* Generic header format */
225
226static
227struct gen_hdr {
228	ulong_t	g_magic,	/* Magic number field */
229		g_ino,		/* Inode number of file */
230		g_mode,		/* Mode of file */
231		g_uid,		/* Uid of file */
232		g_gid,		/* Gid of file */
233		g_nlink,	/* Number of links */
234		g_mtime;	/* Modification time */
235	off_t	g_filesz;	/* Length of file */
236	ulong_t	g_dev,		/* File system of file */
237		g_rdev,		/* Major/minor numbers of special files */
238		g_namesz,	/* Length of filename */
239		g_cksum;	/* Checksum of file */
240	char	g_gname[32],
241		g_uname[32],
242		g_version[2],
243		g_tmagic[6],
244		g_typeflag;
245	char	*g_tname,
246		*g_prefix,
247		*g_nam_p,	/* Filename */
248		*g_attrnam_p,	/* attribute */
249		*g_attrfnam_p,  /* Real file name attr belongs to */
250		*g_linktoattrfnam_p, /* file linked attribute belongs to */
251		*g_linktoattrnam_p,  /* attribute g_attrnam_p is linked to */
252		*g_dirpath;	/* dirname currently opened */
253	int	g_dirfd;	/* directory file descriptor */
254	int	g_passdirfd;	/* directory fd to pass to */
255
256} Gen, *G_p;
257
258/* Data structure for handling multiply-linked files */
259static
260char	prebuf[PRESIZ+1],
261	nambuf[NAMSIZ+1],
262	fullnam[MAXNAM+1];
263
264
265static
266struct Lnk {
267	short	L_cnt,		/* Number of links encountered */
268		L_data;		/* Data has been encountered if 1 */
269	struct gen_hdr	L_gen;	/* gen_hdr information for this file */
270	struct Lnk	*L_nxt_p,	/* Next file in list */
271			*L_bck_p,	/* Previous file in list */
272			*L_lnk_p;	/* Next link for this file */
273} Lnk_hd;
274
275static
276struct hdr_cpio	Hdr;
277
278/*
279 * -------------------------------------------------------------------------
280 *		   Stuff needed to pre-view the name stream
281 *
282 * issymlink is used to remember that the current file is a symlink between
283 * getname() and file_pass(); the former trashes this information immediately
284 * when -L is specified.
285 */
286
287static
288int	issymlink = 0;
289
290static
291FILE	*In_p = stdin;		/* Where the input comes from */
292
293typedef struct sl_info
294{
295	struct sl_info *llink;	/* Left subtree ptr (tree depth in *sl_head) */
296	struct sl_info *rlink;	/* Right subtree ptr */
297	int bal;		/* Subtree balance factor */
298	ulong_t	sl_count;	/* Number of symlinks */
299	ino_t	sl_ino;		/* Inode of file */
300	ino_t	sl_ino2;	/* alternate inode for -Hodc */
301} sl_info_t;
302
303/*
304 * The following structure maintains a hash entry for the
305 * balancing trees which are allocated for each device nodes.
306 */
307typedef struct sl_info_link
308{
309	dev_t		dev;
310	sl_info_t	*head;
311	struct sl_info_link *next;
312} sl_info_link_t;
313
314#define	SL_INFO_ALLOC_CHUNK	1024
315#define	NDEVHENTRY		0x40
316#define	DEV_HASHKEY(x)		((x) & (NDEVHENTRY -1))
317
318/*
319 * For remapping dev,inode for -Hodc archives.
320 */
321
322typedef struct sl_remap
323{
324	dev_t			dev;		/* device */
325	int			inode_count;	/* # inodes seen on dev */
326	struct sl_remap 	*next;		/* next in the chain */
327} sl_remap_t;
328
329/* forward declarations */
330
331static sl_info_t 	*sl_info_alloc(void);
332static sl_info_t 	*sl_insert(dev_t, ino_t);
333static ulong_t		sl_numlinks(dev_t, ino_t);
334static void		sl_preview_synonyms(void);
335static void		sl_remember_tgt(const struct stat *, int);
336static sl_info_t 	*sl_search(dev_t, ino_t);
337static sl_info_t	*sl_devhash_lookup(dev_t);
338static void		sl_devhash_insert(dev_t, sl_info_t *);
339
340extern int		sl_compare(ino_t, ino_t);
341#define	sl_compare(lino, rino)	(lino < rino ? -1 : (lino > rino ? 1 : 0))
342
343/* global storage */
344
345static sl_remap_t  *sl_remap_head = NULL; /* head of the inode-remap list */
346static sl_info_link_t	*sl_devhash[NDEVHENTRY]; /* hash table */
347
348/*
349 * -------------------------------------------------------------------------
350 */
351
352static
353struct stat	ArchSt,	/* stat(2) information of the archive */
354		SrcSt,	/* stat(2) information of source file */
355		DesSt,	/* stat(2) of destination file */
356		*OldSt = NULL;	/* stat info converted to svr32 format */
357
358/*
359 * bin_mag: Used to validate a binary magic number,
360 * by combining to bytes into an unsigned short.
361 */
362
363static
364union bin_mag {
365	unsigned char b_byte[2];
366	ushort_t b_half;
367} Binmag;
368
369static
370union tblock *Thdr_p;	/* TAR header pointer */
371
372static union b_block *bar_Vhdr;
373static struct gen_hdr Gen_bar_vol;
374
375/*
376 * swpbuf: Used in swap() to swap bytes within a halfword,
377 * halfwords within a word, or to reverse the order of the
378 * bytes within a word.  Also used in mklong() and mkshort().
379 */
380
381static
382union swpbuf {
383	unsigned char	s_byte[4];
384	ushort_t	s_half[2];
385	ulong_t	s_word;
386} *Swp_p;
387
388static
389char	Adir,			/* Flags object as a directory */
390	Hiddendir,		/* Processing hidden attribute directory */
391	Aspec,			/* Flags object as a special file */
392	Do_rename,		/* Indicates rename() is to be used */
393	Time[50],		/* Array to hold date and time */
394	Ttyname[] = "/dev/tty",	/* Controlling console */
395	T_lname[MAXPATHLEN],	/* Array to hold links name for tar */
396	*Buf_p,			/* Buffer for file system I/O */
397	*Empty,			/* Empty block for TARTYP headers */
398	*Full_p,		/* Pointer to full pathname */
399	*Efil_p,		/* -E pattern file string */
400	*Eom_p = "Change to part %d and press RETURN key. [q] ",
401	*Fullnam_p,		/* Full pathname */
402	*Attrfile_p,		/* attribute file */
403	*Hdr_p,			/* -H header type string */
404	*IOfil_p,		/* -I/-O input/output archive string */
405	*Lnkend_p,		/* Pointer to end of Lnknam_p */
406	*Lnknam_p,		/* Buffer for linking files with -p option */
407	*Nam_p,			/* Array to hold filename */
408	*Savenam_p,		/* copy of filename xattr belongs to */
409	*Own_p,			/* New owner login id string */
410	*Renam_p,		/* Buffer for renaming files */
411	*Renametmp_p,		/* Tmp Buffer for renaming files */
412	*Symlnk_p,		/* Buffer for holding symbolic link name */
413	*Over_p,		/* Holds temporary filename when overwriting */
414	**Pat_pp = 0,		/* Pattern strings */
415	bar_linkflag,		/* flag to indicate if the file is a link */
416	bar_linkname[MAXPATHLEN]; /* store the name of the link */
417
418static
419int	Append = 0,	/* Flag set while searching to end of archive */
420	Archive,	/* File descriptor of the archive */
421	Buf_error = 0,	/* I/O error occured during buffer fill */
422	Def_mode = 0777,	/* Default file/directory protection modes */
423	Device,		/* Device type being accessed (used with libgenIO) */
424	Error_cnt = 0,	/* Cumulative count of I/O errors */
425	Finished = 1,	/* Indicates that a file transfer has completed */
426	Hdrsz = ASCSZ,	/* Fixed length portion of the header */
427	Hdr_type,		/* Flag to indicate type of header selected */
428	Ifile,		/* File des. of file being archived */
429	Ofile,		/* File des. of file being extracted from archive */
430	Use_old_stat = 0,    /* Create an old style -Hodc hdr (small dev's) */
431	Onecopy = 0,	/* Flags old vs. new link handling */
432	Pad_val = 0,	/* Indicates the number of bytes to pad (if any) */
433	PageSize = 0,	/* The native page size, used for figuring block size */
434	Volcnt = 1,	/* Number of archive volumes processed */
435	Verbcnt = 0,	/* Count of number of dots '.' output */
436	Eomflag = 0,
437	Dflag = 0,
438	Atflag = 0,	/* Archive/restore extended attributes */
439	Compressed,	/* Flag to indicate if the bar archive is compressed */
440	Bar_vol_num = 0, /* Volume number count for bar archive */
441	privileged = 0;	/* Flag set if running with higher privileges */
442
443
444static
445gid_t	Lastgid = (gid_t)-1;	/* Used with -t & -v to record current gid */
446
447static
448uid_t	Lastuid = (uid_t)-1;	/* Used with -t & -v to record current uid */
449
450static
451long	Args,		/* Mask of selected options */
452	Max_namesz = CPATH;	/* Maximum size of pathnames/filenames */
453
454static
455int	Bufsize = BUFSZ;	/* Default block size */
456
457
458static u_longlong_t    Blocks;	/* full blocks transferred */
459static u_longlong_t    SBlocks;	/* cumulative char count from short reads */
460
461
462static off_t	Max_offset = BIN_OFFSET_MAX;	/* largest file size */
463static off_t	Max_filesz;			/* from getrlimit */
464
465static
466FILE	*Ef_p,			/* File pointer of pattern input file */
467	*Err_p = stderr,	/* File pointer for error reporting */
468	*Out_p = stdout,	/* File pointer for non-archive output */
469	*Rtty_p,		/* Input file pointer for interactive rename */
470	*Wtty_p;		/* Output file ptr for interactive rename */
471
472static
473ushort_t	Ftype = S_IFMT;	/* File type mask */
474
475/* ACL support */
476static struct sec_attr {
477	char	attr_type;
478	char	attr_len[7];
479	char	attr_info[1];
480} *attr;
481
482static int	Pflag = 0;	/* flag indicates that acl is preserved */
483static int	acl_is_set = 0; /* True if an acl was set on the file */
484
485acl_t *aclp;
486
487/*
488 *
489 * cpio has been changed to support extended attributes.
490 *
491 * As part of this change cpio has been changed to use the new *at() syscalls
492 * such as openat, fchownat(), unlinkat()...
493 *
494 * This was done so that attributes can be handled with as few code changes
495 * as possible.
496 *
497 * What this means is that cpio now opens the directory that a file or directory
498 * resides in and then performs *at() functions to manipulate the entry.
499 *
500 * For example a new file is now created like this:
501 *
502 * dfd = open(<some dir path>)
503 * fd = openat(dfd, <name>,....);
504 *
505 * or in the case of an extended attribute
506 *
507 * dfd = attropen(<pathname>, ".", ....)
508 *
509 * Once we have a directory file descriptor all of the *at() functions can
510 * be applied to it.
511 *
512 * unlinkat(dfd, <component name>,...)
513 * fchownat(dfd, <component name>,..)
514 *
515 * This works for both normal namespace files and extended attribute file
516 *
517 */
518
519/*
520 * Extended attribute layout
521 *
522 * Extended attributes are stored in two pieces.
523 * 1. An attribute header which has information about
524 *    what file the attribute is for and what the attribute
525 *    is named.
526 * 2. The attribute record itself.  Stored as a normal file type
527 *    of entry.
528 * Both the header and attribute record have special modes/typeflags
529 * associated with them.
530 *
531 * The names of the header in the archive look like:
532 * /dev/null/attr.hdr
533 *
534 * The name of the attribute looks like:
535 * /dev/null/attr.
536 *
537 * This is done so that an archiver that doesn't understand these formats
538 * can just dispose of the attribute records unless the user chooses to
539 * rename them via cpio -r or pax -i
540 *
541 * The format is composed of a fixed size header followed
542 * by a variable sized xattr_buf. If the attribute is a hard link
543 * to another attribute, then another xattr_buf section is included
544 * for the link.
545 *
546 * The xattr_buf is used to define the necessary "pathing" steps
547 * to get to the extended attribute.  This is necessary to support
548 * a fully recursive attribute model where an attribute may itself
549 * have an attribute.
550 *
551 * The basic layout looks like this.
552 *
553 *     --------------------------------
554 *     |                              |
555 *     |         xattr_hdr            |
556 *     |                              |
557 *     --------------------------------
558 *     --------------------------------
559 *     |                              |
560 *     |        xattr_buf             |
561 *     |                              |
562 *     --------------------------------
563 *     --------------------------------
564 *     |                              |
565 *     |      (optional link info)    |
566 *     |                              |
567 *     --------------------------------
568 *     --------------------------------
569 *     |                              |
570 *     |      attribute itself        |
571 *     |      stored as normal tar    |
572 *     |      or cpio data with       |
573 *     |      special mode or         |
574 *     |      typeflag                |
575 *     |                              |
576 *     --------------------------------
577 *
578 */
579
580/*
581 * Extended attributes structures
582 *
583 * xattrhead is the complete extended attribute header, as read of off
584 * disk/tape. It includes the variable xattr_buf portion.
585 *
586 * xattrp is basically an offset into xattrhead that points to the
587 * "pathing" section which defines how to get to the attribute.
588 *
589 * xattr_linkp is identical to xattrp except that it is used for linked
590 * attributes.  It provides the pathing steps to get to the linked
591 * attribute.
592 *
593 * These structures are updated when an extended attribute header is read off
594 * of disk/tape.
595 */
596static struct xattr_hdr	*xattrhead;
597static struct xattr_buf	*xattrp;
598static struct xattr_buf	*xattr_linkp;
599static int 		xattrbadhead;	/* is extended attribute header bad? */
600
601static int	append_secattr(char **, int *, acl_t *);
602static void	write_ancillary(char *, int);
603
604/*
605 * Note regarding cpio and changes to ensure cpio doesn't try to second
606 * guess whether it runs with sufficient privileges or not:
607 *
608 * cpio has been changed so that it doesn't carry a second implementation of
609 * the kernel's policy with respect to privileges.  Instead of attempting
610 * to restore uid and gid from an archive only if cpio is run as uid 0,
611 * cpio now *always* tries to restore the uid and gid from the archive
612 * except when the -R option is specified.  When the -R is specified,
613 * the uid and gid of the restored file will be changed to those of the
614 * login id specified.  In addition, chown(), set_tym(), and chmod() should
615 * only be executed once during archive extraction, and to ensure
616 * setuid/setgid bits are restored properly, chown() should always be
617 * executed before chmod().
618 *
619 * Note regarding debugging mechanism for cpio:
620 *
621 * The following mechanism is provided to allow us to debug cpio in complicated
622 * situations, like when it is part of a pipe.  The idea is that you compile
623 * with -DWAITAROUND defined, and then add the "-z" command line option to the
624 * target cpio invocation.  If stderr is available, it will tell you to which
625 * pid to attach the debugger; otherwise, use ps to find it.  Attach to the
626 * process from the debugger, and, *PRESTO*, you are there!
627 *
628 * Simply assign "waitaround = 0" once you attach to the process, and then
629 * proceed from there as usual.
630 */
631
632#ifdef WAITAROUND
633int waitaround = 0;		/* wait for rendezvous with the debugger */
634#endif
635
636/*
637 * Allocation wrappers and their flags
638 */
639#define	E_NORMAL	0x0	/* Return NULL if allocation fails */
640#define	E_EXIT		0x1	/* Exit if allocation fails */
641
642static void *e_realloc(int flag, void *old, size_t newsize);
643static char *e_strdup(int flag, const char *arg);
644static void *e_valloc(int flag, size_t size);
645static void *e_zalloc(int flag, size_t size);
646
647#define	EXIT_CODE	(Error_cnt > 255 ? 255 : Error_cnt)
648
649/*
650 * main: Call setup() to process options and perform initializations,
651 * and then select either copy in (-i), copy out (-o), or pass (-p) action.
652 */
653
654int
655main(int argc, char **argv)
656{
657	int i;
658	int passret;
659
660	(void) setlocale(LC_ALL, "");
661#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
662#define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
663#endif
664	(void) textdomain(TEXT_DOMAIN);
665
666	(void) memset(&Gen, 0, sizeof (Gen));
667	setup(argc, argv);
668
669	if (signal(SIGINT, sigint) == SIG_IGN)
670		(void) signal(SIGINT, SIG_IGN);
671	switch (Args & (OCi | OCo | OCp)) {
672	case OCi: /* COPY IN */
673		Hdr_type = NONE;
674		while ((i = gethdr()) != 0) {
675			Gen.g_dirfd = -1;
676			if (i == 1) {
677				file_in();
678				/*
679				 * Any ACL info for this file would or should
680				 * have been used after file_in(); clear out
681				 * aclp so it is is not erroneously used on
682				 * the next file.
683				 */
684				if (aclp != NULL) {
685					acl_free(aclp);
686					aclp = NULL;
687				}
688				acl_is_set = 0;
689			}
690			(void) memset(&Gen, 0, sizeof (Gen));
691		}
692		/* Do not count "extra" "read-ahead" buffered data */
693		if (Buffr.b_cnt > Bufsize)
694			Blocks -=  (u_longlong_t)(Buffr.b_cnt / Bufsize);
695		break;
696	case OCo: /* COPY OUT */
697		if (Args & OCA) {
698			scan4trail();
699		}
700
701		Gen.g_dirfd = -1;
702		Gen.g_dirpath = NULL;
703		sl_preview_synonyms();
704
705		while ((i = getname()) != 0) {
706			if (i == 1) {
707				(void) file_out();
708				if (Atflag) {
709					if (Gen.g_dirfd != -1) {
710						(void) close(Gen.g_dirfd);
711					}
712					Gen.g_dirfd = -1;
713					xattrs_out(file_out);
714				}
715				Hiddendir = 0;
716			}
717			if (aclp != NULL) {
718				acl_free(aclp);
719				aclp = NULL;
720				acl_is_set = 0;
721			}
722		}
723		write_trail();
724		break;
725	case OCp: /* PASS */
726		sl_preview_synonyms();
727
728		Gen.g_dirfd = -1;
729		Gen.g_passdirfd = -1;
730		Gen.g_dirpath = NULL;
731		while (getname()) {
732			/*
733			 * If file is a fully qualified path then
734			 * file_pass will strip off the leading '/'
735			 * and we need to save off the unstripped
736			 * name for attribute traversal.
737			 */
738			if (Atflag) {
739				(void) strcpy(Savenam_p, Gen.g_nam_p);
740			}
741			passret = file_pass();
742			if (aclp != NULL) {
743				acl_free(aclp);
744				aclp = NULL;
745				acl_is_set = 0;
746			}
747			if (Gen.g_passdirfd != -1)
748				(void) close(Gen.g_passdirfd);
749			Gen.g_passdirfd = -1;
750			if (Atflag) {
751				if (Gen.g_dirfd != -1) {
752					(void) close(Gen.g_dirfd);
753				}
754				Gen.g_dirfd = -1;
755				if (passret != FILE_LINKED) {
756					Gen.g_nam_p = Savenam_p;
757					xattrs_out(file_pass);
758				}
759			}
760		}
761		break;
762	default:
763		msg(EXT, "Impossible action.");
764	}
765	if (Ofile > 0) {
766		if (close(Ofile) != 0)
767			msg(EXTN, "close error");
768	}
769	if (Archive > 0) {
770		if (close(Archive) != 0)
771			msg(EXTN, "close error");
772	}
773	Blocks = (u_longlong_t)(Blocks * Bufsize + SBlocks + 0x1FF) >> 9;
774	msg(EPOST, "%lld blocks", Blocks);
775	if (Error_cnt)
776		msg(EPOST, "%d error(s)", Error_cnt);
777	return (EXIT_CODE);
778}
779
780/*
781 * add_lnk: Add a linked file's header to the linked file data structure, by
782 * either adding it to the end of an existing sub-list or starting
783 * a new sub-list.  Each sub-list saves the links to a given file.
784 *
785 * Directly returns a pointer to the new entry; returns a pointer to the head
786 * of the sub-list in which that entry is located through the argument.
787 */
788
789static struct Lnk *
790add_lnk(struct Lnk **sublist_return)
791{
792	struct Lnk *new_entry, *sublist;
793
794	for (sublist = Lnk_hd.L_nxt_p;
795	    sublist != &Lnk_hd;
796	    sublist = sublist->L_nxt_p) {
797		if (sublist->L_gen.g_ino == G_p->g_ino &&
798		    sublist->L_gen.g_dev == G_p->g_dev) {
799			/* found */
800			break;
801		}
802	}
803
804	new_entry = e_zalloc(E_EXIT, sizeof (struct Lnk));
805
806	new_entry->L_lnk_p = NULL;
807	new_entry->L_gen = *G_p; /* structure copy */
808
809	new_entry->L_gen.g_nam_p = e_zalloc(E_EXIT, (size_t)G_p->g_namesz);
810
811	(void) strcpy(new_entry->L_gen.g_nam_p, G_p->g_nam_p);
812
813	if (sublist == &Lnk_hd) {
814		/* start new sub-list */
815		new_entry->L_nxt_p = &Lnk_hd;
816		new_entry->L_bck_p = Lnk_hd.L_bck_p;
817		Lnk_hd.L_bck_p = new_entry->L_bck_p->L_nxt_p = new_entry;
818		new_entry->L_lnk_p = NULL;
819		new_entry->L_cnt = 1;
820		new_entry->L_data = Onecopy ? 0 : 1;
821		sublist = new_entry;
822	} else {
823		/* add to existing sub-list */
824		struct Lnk *ptr;
825
826		sublist->L_cnt++;
827
828		for (ptr = sublist;
829		    ptr->L_lnk_p != NULL;
830		    ptr = ptr->L_lnk_p) {
831			ptr->L_gen.g_filesz = G_p->g_filesz;
832		}
833
834		ptr->L_gen.g_filesz = G_p->g_filesz;
835		ptr->L_lnk_p = new_entry;
836	}
837
838	*sublist_return = sublist;
839	return (new_entry);
840}
841
842/*
843 * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
844 * moving them to rd_buf_p.  When there are no bytes left in the I/O buffer,
845 * Fillbuf is set and the I/O buffer is filled.  The variable dist is the
846 * distance to lseek if an I/O error is encountered with the -k option set
847 * (converted to a multiple of Bufsize).
848 */
849
850static int
851bfill(void)
852{
853	int i = 0, rv;
854	static int eof = 0;
855
856	if (!Dflag) {
857	while ((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) {
858		errno = 0;
859		if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
860			if (((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) &&
861			    (Eomflag == 0)) {
862				Eomflag = 1;
863				return (1);
864			}
865			if (errno == ENOSPC) {
866				(void) chgreel(INPUT);
867				if (Hdr_type == BAR) {
868					skip_bar_volhdr();
869				}
870				continue;
871			} else if (Args & OCk) {
872				if (i++ > MX_SEEKS)
873					msg(EXT, "Cannot recover.");
874				if (lseek(Archive, Bufsize, SEEK_REL) < 0)
875					msg(EXTN, "Cannot lseek()");
876				Error_cnt++;
877				Buf_error++;
878				rv = 0;
879				continue;
880			} else
881				ioerror(INPUT);
882		} /* (rv = g_read(Device, Archive ... */
883		if (Hdr_type != BAR || rv == Bufsize) {
884			Buffr.b_in_p += rv;
885			Buffr.b_cnt += (long)rv;
886		}
887		if (rv == Bufsize) {
888			eof = 0;
889			Blocks++;
890		} else if (rv == 0) {
891			if (!eof) {
892				eof = 1;
893				break;
894			}
895			(void) chgreel(INPUT);
896			eof = 0;	/* reset the eof after chgreel	*/
897
898			/*
899			 * if spans multiple volume, skip the volume header of
900			 * the next volume so that the file currently being
901			 * extracted can continue to be extracted.
902			 */
903			if (Hdr_type == BAR) {
904				skip_bar_volhdr();
905			}
906
907			continue;
908		} else {
909			eof = 0;
910			SBlocks += (u_longlong_t)rv;
911		}
912	} /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
913
914	} else {			/* Dflag */
915		errno = 0;
916		if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
917			return (-1);
918		} /* (rv = g_read(Device, Archive ... */
919		Buffr.b_in_p += rv;
920		Buffr.b_cnt += (long)rv;
921		if (rv == Bufsize) {
922			eof = 0;
923			Blocks++;
924		} else if (!rv) {
925			if (!eof) {
926				eof = 1;
927				return (rv);
928			}
929			return (-1);
930		} else {
931			eof = 0;
932			SBlocks += (u_longlong_t)rv;
933		}
934	}
935	return (rv);
936}
937
938/*
939 * bflush: Move wr_cnt bytes from data_p into the I/O buffer.  When the
940 * I/O buffer is full, Flushbuf is set and the buffer is written out.
941 */
942
943static void
944bflush(void)
945{
946	int rv;
947
948	while (Buffr.b_cnt >= Bufsize) {
949		errno = 0;
950		if ((rv = g_write(Device, Archive, Buffr.b_out_p,
951		    Bufsize)) < 0) {
952			if (errno == ENOSPC && !Dflag)
953				rv = chgreel(OUTPUT);
954			else
955				ioerror(OUTPUT);
956		}
957		Buffr.b_out_p += rv;
958		Buffr.b_cnt -= (long)rv;
959		if (rv == Bufsize)
960			Blocks++;
961		else if (rv > 0)
962			SBlocks += (u_longlong_t)rv;
963	}
964	rstbuf();
965}
966
967/*
968 * chgreel: Determine if end-of-medium has been reached.  If it has,
969 * close the current medium and prompt the user for the next medium.
970 */
971
972static int
973chgreel(int dir)
974{
975	int lastchar, tryagain, askagain, rv;
976	int tmpdev;
977	char str[APATH];
978	struct stat statb;
979
980	rv = 0;
981	if (fstat(Archive, &statb) < 0)
982		msg(EXTN, "Error during stat() of archive");
983	if ((statb.st_mode & S_IFMT) != S_IFCHR) {
984		if (dir == INPUT) {
985			msg(EXT, "%s%s\n",
986			    "Can't read input:  end of file encountered ",
987			    "prior to expected end of archive.");
988		}
989	}
990	msg(EPOST, "\007End of medium on \"%s\".", dir ? "output" : "input");
991	if (is_floppy(Archive))
992		(void) ioctl(Archive, FDEJECT, NULL);
993	if ((close(Archive) != 0) && (dir == OUTPUT))
994		msg(EXTN, "close error");
995	Archive = 0;
996	Volcnt++;
997	for (;;) {
998		if (Rtty_p == (FILE *)NULL)
999			Rtty_p = fopen(Ttyname, "r");
1000		do { /* tryagain */
1001			if (IOfil_p) {
1002				do {
1003					msg(EPOST, gettext(Eom_p), Volcnt);
1004					if (!Rtty_p || fgets(str, sizeof (str),
1005					    Rtty_p) == (char *)NULL)
1006						msg(EXT, "Cannot read tty.");
1007					askagain = 0;
1008					switch (*str) {
1009					case '\n':
1010						(void) strcpy(str, IOfil_p);
1011						break;
1012					case 'q':
1013						exit(EXIT_CODE);
1014					default:
1015						askagain = 1;
1016					}
1017				} while (askagain);
1018			} else {
1019
1020				if (Hdr_type == BAR)
1021					Bar_vol_num++;
1022
1023				msg(EPOST,
1024				    "To continue, type device/file name when "
1025				    "ready.");
1026				if (!Rtty_p || fgets(str, sizeof (str),
1027				    Rtty_p) == (char *)NULL)
1028					msg(EXT, "Cannot read tty.");
1029				lastchar = strlen(str) - 1;
1030				if (*(str + lastchar) == '\n') /* remove '\n' */
1031					*(str + lastchar) = '\0';
1032				if (!*str)
1033					exit(EXIT_CODE);
1034			}
1035			tryagain = 0;
1036			if ((Archive = open(str, dir)) < 0) {
1037				msg(ERRN, "Cannot open \"%s\"", str);
1038				tryagain = 1;
1039			}
1040		} while (tryagain);
1041		(void) g_init(&tmpdev, &Archive);
1042		if (tmpdev != Device)
1043			msg(EXT, "Cannot change media types in mid-stream.");
1044		if (dir == INPUT)
1045			break;
1046		else { /* dir == OUTPUT */
1047			errno = 0;
1048			if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1049			    Bufsize)) == Bufsize)
1050				break;
1051			else
1052				msg(ERR,
1053				    "Unable to write this medium, try "
1054				    "another.");
1055		}
1056	} /* ;; */
1057	Eomflag = 0;
1058	return (rv);
1059}
1060
1061/*
1062 * ckname: Check filenames against user specified patterns,
1063 * and/or ask the user for new name when -r is used.
1064 */
1065
1066static int
1067ckname(int flag)
1068{
1069	int lastchar, len;
1070
1071	if (Hdr_type != TAR && Hdr_type != USTAR && Hdr_type != BAR) {
1072		/* Re-visit tar size issues later */
1073		if (G_p->g_namesz - 1 > Max_namesz) {
1074			msg(ERR, "Name exceeds maximum length - skipped.");
1075			return (F_SKIP);
1076		}
1077	}
1078
1079	if (Pat_pp && !matched())
1080		return (F_SKIP);
1081	if ((Args & OCr) && !Adir) { /* rename interactively */
1082		(void) fprintf(Wtty_p, gettext("Rename \"%s%s%s\"? "),
1083		    (G_p->g_attrnam_p == (char *)NULL) ?
1084		    G_p->g_nam_p : Renam_p,
1085		    (G_p->g_attrnam_p == (char *)NULL) ?
1086		    "" : gettext(" Attribute "),
1087		    (G_p->g_attrnam_p == (char *)NULL) ?
1088		    "" : G_p->g_attrnam_p);
1089		(void) fflush(Wtty_p);
1090		if (fgets(Renametmp_p, Max_namesz + 1, Rtty_p) == (char *)NULL)
1091			msg(EXT, "Cannot read tty.");
1092		if (feof(Rtty_p))
1093			exit(EXIT_CODE);
1094		lastchar = strlen(Renametmp_p) - 1;
1095
1096		/* remove trailing '\n' */
1097		if (*(Renametmp_p + lastchar) == '\n')
1098			*(Renametmp_p + lastchar) = '\0';
1099		if (*Renametmp_p == '\0') {
1100			msg(POST, "%s%s%s Skipped.",
1101			    (G_p->g_attrnam_p == (char *)NULL) ?
1102			    G_p->g_nam_p : G_p->g_attrfnam_p,
1103			    (G_p->g_attrnam_p == (char *)NULL) ?
1104			    "" : gettext(" Attribute "),
1105			    (G_p->g_attrnam_p == (char *)NULL) ?
1106			    "" : G_p->g_attrnam_p);
1107			*G_p->g_nam_p = '\0';
1108			return (F_SKIP);
1109		} else if (strcmp(Renametmp_p, ".") != 0) {
1110			len = strlen(Renametmp_p);
1111			if (len > (int)strlen(G_p->g_nam_p)) {
1112				if ((G_p->g_nam_p != &nambuf[0]) &&
1113				    (G_p->g_nam_p != &fullnam[0]))
1114					free(G_p->g_nam_p);
1115				G_p->g_nam_p = e_zalloc(E_EXIT, len + 1);
1116			}
1117			if (G_p->g_attrnam_p != (char *)NULL) {
1118				free(G_p->g_attrnam_p);
1119				G_p->g_attrnam_p = e_strdup(E_EXIT,
1120				    Renametmp_p);
1121				(void) strcpy(G_p->g_nam_p, Renam_p);
1122			} else {
1123				(void) strcpy(Renam_p, Renametmp_p);
1124				(void) strcpy(G_p->g_nam_p, Renametmp_p);
1125			}
1126
1127		}
1128	}
1129	if (flag != 0 || Onecopy == 0) {
1130		VERBOSE((Args & OCt), G_p->g_nam_p);
1131	}
1132	if (Args & OCt)
1133		return (F_SKIP);
1134	return (F_EXTR);
1135}
1136
1137/*
1138 * ckopts: Check the validity of all command line options.
1139 */
1140
1141static void
1142ckopts(long mask)
1143{
1144	int oflag;
1145	char *t_p;
1146	long errmsk;
1147	uid_t	Euid = geteuid();	/* Effective uid of invoker */
1148#ifdef SOLARIS_PRIVS
1149	priv_set_t *privset;
1150	priv_set_t *zones_privset;
1151#endif	/* SOLARIS_PRIVS */
1152
1153	if (mask & OCi) {
1154		errmsk = mask & INV_MSK4i;
1155	} else if (mask & OCo) {
1156		errmsk = mask & INV_MSK4o;
1157	} else if (mask & OCp) {
1158		errmsk = mask & INV_MSK4p;
1159	} else {
1160		msg(ERR, "One of -i, -o or -p must be specified.");
1161		errmsk = 0;
1162	}
1163
1164	if (errmsk) {
1165		/* if non-zero, invalid options were specified */
1166		Error_cnt++;
1167	}
1168
1169	if ((mask & OCa) && (mask & OCm) && ((mask & OCi) ||
1170	    (mask & OCo))) {
1171		msg(ERR, "-a and -m are mutually exclusive.");
1172	}
1173
1174	if ((mask & OCc) && (mask & OCH) && (strcmp("odc", Hdr_p))) {
1175		msg(ERR, "-c and -H are mutually exclusive.");
1176	}
1177
1178	if ((mask & OCv) && (mask & OCV)) {
1179		msg(ERR, "-v and -V are mutually exclusive.");
1180	}
1181
1182	if ((mask & OCt) && (mask & OCV)) {
1183		msg(ERR, "-t and -V are mutually exclusive.");
1184	}
1185
1186	if ((mask & OCB) && (mask & OCC)) {
1187		msg(ERR, "-B and -C are mutually exclusive.");
1188	}
1189
1190	if ((mask & OCH) && (mask & OC6)) {
1191		msg(ERR, "-H and -6 are mutually exclusive.");
1192	}
1193
1194	if ((mask & OCM) && !((mask & OCI) || (mask & OCO))) {
1195		msg(ERR, "-M not meaningful without -O or -I.");
1196	}
1197
1198	if ((mask & OCA) && !(mask & OCO)) {
1199		msg(ERR, "-A requires the -O option.");
1200	}
1201
1202	if (Bufsize <= 0) {
1203		msg(ERR, "Illegal size given for -C option.");
1204	}
1205
1206	if (mask & OCH) {
1207		t_p = Hdr_p;
1208
1209		while (*t_p != NULL) {
1210			if (isupper(*t_p)) {
1211				*t_p = 'a' + (*t_p - 'A');
1212			}
1213
1214			t_p++;
1215		}
1216
1217		if (!(strcmp("odc", Hdr_p))) {
1218			Hdr_type = CHR;
1219			Max_namesz = CPATH;
1220			Onecopy = 0;
1221			Use_old_stat = 1;
1222		} else if (!(strcmp("crc", Hdr_p))) {
1223			Hdr_type = CRC;
1224			Max_namesz = APATH;
1225			Onecopy = 1;
1226		} else if (!(strcmp("tar", Hdr_p))) {
1227			if (Args & OCo) {
1228				Hdr_type = USTAR;
1229				Max_namesz = HNAMLEN - 1;
1230			} else {
1231				Hdr_type = TAR;
1232				Max_namesz = TNAMLEN - 1;
1233			}
1234			Onecopy = 0;
1235		} else if (!(strcmp("ustar", Hdr_p))) {
1236			Hdr_type = USTAR;
1237			Max_namesz = HNAMLEN - 1;
1238			Onecopy = 0;
1239		} else if (!(strcmp("bar", Hdr_p))) {
1240			if ((Args & OCo) || (Args & OCp)) {
1241				msg(ERR,
1242				    "Header type bar can only be used with -i");
1243			}
1244
1245			if (Args & OCP) {
1246				msg(ERR,
1247				    "Can't preserve using bar header");
1248			}
1249
1250			Hdr_type = BAR;
1251			Max_namesz = TNAMLEN - 1;
1252			Onecopy = 0;
1253		} else {
1254			msg(ERR, "Invalid header \"%s\" specified", Hdr_p);
1255		}
1256	}
1257
1258	if (mask & OCr) {
1259		Rtty_p = fopen(Ttyname, "r");
1260		Wtty_p = fopen(Ttyname, "w");
1261
1262		if (Rtty_p == (FILE *)NULL || Wtty_p == (FILE *)NULL) {
1263			msg(ERR, "Cannot rename, \"%s\" missing", Ttyname);
1264		}
1265	}
1266
1267	if ((mask & OCE) && (Ef_p = fopen(Efil_p, "r")) == (FILE *)NULL) {
1268		msg(ERR, "Cannot open \"%s\" to read patterns", Efil_p);
1269	}
1270
1271	if ((mask & OCI) && (Archive = open(IOfil_p, O_RDONLY)) < 0) {
1272		msg(ERR, "Cannot open \"%s\" for input", IOfil_p);
1273	}
1274
1275	if (mask & OCO) {
1276		if (mask & OCA) {
1277			if ((Archive = open(IOfil_p, O_RDWR)) < 0) {
1278				msg(ERR,
1279				    "Cannot open \"%s\" for append",
1280				    IOfil_p);
1281			}
1282		} else {
1283			oflag = (O_WRONLY | O_CREAT | O_TRUNC);
1284
1285			if ((Archive = open(IOfil_p, oflag, 0777)) < 0) {
1286				msg(ERR,
1287				    "Cannot open \"%s\" for output",
1288				    IOfil_p);
1289			}
1290		}
1291	}
1292
1293#ifdef SOLARIS_PRIVS
1294	if ((privset = priv_allocset()) == NULL) {
1295		msg(ERR, "Unable to allocate privilege set");
1296	} else if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1297		msg(ERR, "Unable to obtain privilege set");
1298	} else {
1299		zones_privset = priv_str_to_set("zone", "", NULL);
1300		if (zones_privset != NULL) {
1301			privileged = (priv_issubset(zones_privset,
1302			    privset) == B_TRUE);
1303			priv_freeset(zones_privset);
1304		} else {
1305			msg(ERR, "Unable to map privilege to privilege set");
1306		}
1307	}
1308	if (privset != NULL) {
1309		priv_freeset(privset);
1310	}
1311#else
1312	privileged = (Euid == 0);
1313#endif	/* SOLARIS_PRIVS */
1314
1315	if (mask & OCR) {
1316		if ((Rpw_p = getpwnam(Own_p)) == (struct passwd *)NULL) {
1317			msg(ERR, "\"%s\" is not a valid user id", Own_p);
1318		} else if ((Euid != Rpw_p->pw_uid) && !privileged) {
1319			msg(ERR, "R option only valid for super-user or "
1320			    "id matches login id of user executing cpio");
1321		}
1322	}
1323
1324	if ((mask & OCo) && !(mask & OCO)) {
1325		Out_p = stderr;
1326	}
1327
1328	if ((mask & OCp) && ((mask & (OCB|OCC)) == 0)) {
1329		/*
1330		 * We are in pass mode with no block size specified.  Use the
1331		 * larger of the native page size and 8192.
1332		 */
1333
1334		Bufsize = (PageSize > 8192) ? PageSize : 8192;
1335	}
1336}
1337
1338/*
1339 * cksum: Calculate the simple checksum of a file (CRC) or header
1340 * (TARTYP (TAR and USTAR)).  For -o and the CRC header, the file is opened and
1341 * the checksum is calculated.  For -i and the CRC header, the checksum
1342 * is calculated as each block is transferred from the archive I/O buffer
1343 * to the file system I/O buffer.  The TARTYP (TAR and USTAR) headers calculate
1344 * the simple checksum of the header (with the checksum field of the
1345 * header initialized to all spaces (\040).
1346 */
1347
1348static long
1349cksum(char hdr, int byt_cnt, int *err)
1350{
1351	char *crc_p, *end_p;
1352	int cnt;
1353	long checksum = 0L, have;
1354	off_t lcnt;
1355
1356	if (err != NULL)
1357		*err = 0;
1358	switch (hdr) {
1359	case CRC:
1360		if (Args & OCi) { /* do running checksum */
1361			end_p = Buffr.b_out_p + byt_cnt;
1362			for (crc_p = Buffr.b_out_p; crc_p < end_p; crc_p++)
1363				checksum += (long)*crc_p;
1364			break;
1365		}
1366		/* OCo - do checksum of file */
1367		lcnt = G_p->g_filesz;
1368
1369		while (lcnt > 0) {
1370			have = (lcnt < Bufsize) ? lcnt : Bufsize;
1371			errno = 0;
1372			if (read(Ifile, Buf_p, have) != have) {
1373				msg(ERR, "Error computing checksum.");
1374				if (err != NULL)
1375					*err = 1;
1376				break;
1377			}
1378			end_p = Buf_p + have;
1379			for (crc_p = Buf_p; crc_p < end_p; crc_p++)
1380				checksum += (long)*crc_p;
1381			lcnt -= have;
1382		}
1383		if (lseek(Ifile, (off_t)0, SEEK_ABS) < 0)
1384			msg(ERRN, "Cannot reset file after checksum");
1385		break;
1386	case TARTYP: /* TAR and USTAR */
1387		crc_p = Thdr_p->tbuf.t_cksum;
1388		for (cnt = 0; cnt < TCRCLEN; cnt++) {
1389			*crc_p = '\040';
1390			crc_p++;
1391		}
1392		crc_p = (char *)Thdr_p;
1393		for (cnt = 0; cnt < TARSZ; cnt++) {
1394			/*
1395			 * tar uses unsigned checksum, so we must use unsigned
1396			 * here in order to be able to read tar archives.
1397			 */
1398			checksum += (long)((unsigned char)(*crc_p));
1399			crc_p++;
1400		}
1401		break;
1402	default:
1403		msg(EXT, "Impossible header type.");
1404	} /* hdr */
1405	return (checksum);
1406}
1407
1408/*
1409 * creat_hdr: Fill in the generic header structure with the specific
1410 *            header information based on the value of Hdr_type.
1411 *
1412 *            return (1) if this process was successful, and (0) otherwise.
1413 */
1414
1415static int
1416creat_hdr(void)
1417{
1418	ushort_t ftype;
1419	int fullnamesize;
1420	dev_t dev;
1421	ino_t ino;
1422
1423	ftype = SrcSt.st_mode & Ftype;
1424	Adir = (ftype == S_IFDIR);
1425	Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO);
1426	switch (Hdr_type) {
1427		case BIN:
1428			Gen.g_magic = CMN_BIN;
1429			break;
1430		case CHR:
1431			Gen.g_magic = CMN_BIN;
1432			break;
1433		case ASC:
1434			Gen.g_magic = CMN_ASC;
1435			break;
1436		case CRC:
1437			Gen.g_magic = CMN_CRC;
1438			break;
1439		case USTAR:
1440			/*
1441			 * If the length of the full name is greater than 256,
1442			 * print out a message and return.
1443			 */
1444			if ((fullnamesize = strlen(Gen.g_nam_p)) > MAXNAM) {
1445				msg(ERR,
1446				    "%s: file name too long", Gen.g_nam_p);
1447				return (0);
1448			} else if (fullnamesize > NAMSIZ) {
1449				/*
1450				 * The length of the full name is greater than
1451				 * 100, so we must split the filename from the
1452				 * path
1453				 */
1454				char namebuff[NAMSIZ+1];
1455				char prebuff[PRESIZ+1];
1456				char *lastslash;
1457				int presize, namesize;
1458
1459				(void) memset(namebuff, '\0',
1460				    sizeof (namebuff));
1461				(void) memset(prebuff, '\0', sizeof (prebuff));
1462
1463				lastslash = strrchr(Gen.g_nam_p, '/');
1464
1465				if (lastslash != NULL) {
1466					namesize = strlen(++lastslash);
1467					presize = fullnamesize - namesize - 1;
1468				} else {
1469					namesize = fullnamesize;
1470					lastslash = Gen.g_nam_p;
1471					presize = 0;
1472				}
1473
1474				/*
1475				 * If the filename is greater than 100 we can't
1476				 * archive the file
1477				 */
1478				if (namesize > NAMSIZ) {
1479					msg(ERR,
1480					    "%s: filename is greater than %d",
1481					    lastslash, NAMSIZ);
1482					return (0);
1483				}
1484				(void) strncpy(&namebuff[0], lastslash,
1485				    namesize);
1486				/*
1487				 * If the prefix is greater than 155 we can't
1488				 * archive the file.
1489				 */
1490				if (presize > PRESIZ) {
1491					msg(ERR,
1492					    "%s: prefix is greater than %d",
1493					    Gen.g_nam_p, PRESIZ);
1494					return (0);
1495				}
1496				(void) strncpy(&prebuff[0], Gen.g_nam_p,
1497				    presize);
1498
1499				Gen.g_tname = e_zalloc(E_EXIT, namesize + 1);
1500				(void) strcpy(Gen.g_tname, namebuff);
1501
1502				Gen.g_prefix = e_zalloc(E_EXIT, presize + 1);
1503				(void) strcpy(Gen.g_prefix, prebuff);
1504			} else {
1505				Gen.g_tname = Gen.g_nam_p;
1506			}
1507			(void) strcpy(Gen.g_tmagic, "ustar");
1508			(void) strcpy(Gen.g_version, "00");
1509
1510			dpasswd = getpwuid(SrcSt.st_uid);
1511			if (dpasswd == (struct passwd *)NULL) {
1512				msg(EPOST,
1513				    "cpio: could not get passwd information "
1514				    "for %s%s%s",
1515				    (Gen.g_attrnam_p == (char *)NULL) ?
1516				    Gen.g_nam_p : Gen.g_attrfnam_p,
1517				    (Gen.g_attrnam_p == (char *)NULL) ?
1518				    "" : gettext(" Attribute "),
1519				    (Gen.g_attrnam_p == (char *)NULL) ?
1520				    "" : Gen.g_attrnam_p);
1521				/* make name null string */
1522				Gen.g_uname[0] = '\0';
1523			} else {
1524				(void) strncpy(&Gen.g_uname[0],
1525				    dpasswd->pw_name, 32);
1526			}
1527			dgroup = getgrgid(SrcSt.st_gid);
1528			if (dgroup == (struct group *)NULL) {
1529				msg(EPOST,
1530				    "cpio: could not get group information "
1531				    "for %s%s%S",
1532				    (Gen.g_attrnam_p == (char *)NULL) ?
1533				    Gen.g_nam_p : Gen.g_attrfnam_p,
1534				    (Gen.g_attrnam_p == (char *)NULL) ?
1535				    "" : gettext(" Attribute "),
1536				    (Gen.g_attrnam_p == (char *)NULL) ?
1537				    "" : Gen.g_attrnam_p);
1538				/* make name null string */
1539				Gen.g_gname[0] = '\0';
1540			} else {
1541				(void) strncpy(&Gen.g_gname[0],
1542				    dgroup->gr_name, 32);
1543			}
1544			Gen.g_typeflag = tartype(ftype);
1545			/* FALLTHROUGH */
1546		case TAR:
1547			(void) memset(T_lname, '\0', sizeof (T_lname));
1548			break;
1549		default:
1550			msg(EXT, "Impossible header type.");
1551	}
1552
1553	dev = SrcSt.st_dev;
1554	ino = SrcSt.st_ino;
1555
1556	if (Use_old_stat) {
1557		SrcSt = *OldSt;
1558	}
1559
1560	Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
1561	Gen.g_uid = SrcSt.st_uid;
1562	Gen.g_gid = SrcSt.st_gid;
1563	Gen.g_dev = SrcSt.st_dev;
1564
1565	if (Use_old_stat) {
1566		/* -Hodc */
1567
1568		sl_info_t *p = sl_search(dev, ino);
1569		Gen.g_ino = p ? p->sl_ino2 : -1;
1570
1571		if (Gen.g_ino == (ulong_t)-1) {
1572			msg(ERR, "%s%s%s: cannot be archived - inode too big "
1573			    "for -Hodc format",
1574			    (Gen.g_attrnam_p == (char *)NULL) ?
1575			    Gen.g_nam_p : Gen.g_attrfnam_p,
1576			    (Gen.g_attrnam_p == (char *)NULL) ?
1577			    "" : gettext(" Attribute "),
1578			    (Gen.g_attrnam_p == (char *)NULL) ?
1579			    "" : Gen.g_attrnam_p);
1580			return (0);
1581		}
1582	} else {
1583		Gen.g_ino = SrcSt.st_ino;
1584	}
1585
1586	Gen.g_mode = SrcSt.st_mode;
1587	Gen.g_mtime = SrcSt.st_mtime;
1588	Gen.g_nlink = (Adir) ? SrcSt.st_nlink
1589	    : sl_numlinks(dev, ino);
1590
1591	if (ftype == S_IFREG || ftype == S_IFLNK)
1592		Gen.g_filesz = (off_t)SrcSt.st_size;
1593	else
1594		Gen.g_filesz = (off_t)0;
1595	Gen.g_rdev = SrcSt.st_rdev;
1596	return (1);
1597}
1598
1599/*
1600 * creat_lnk: Create a link from the existing name1_p to name2_p.
1601 */
1602
1603static
1604int
1605creat_lnk(int dirfd, char *name1_p, char *name2_p)
1606{
1607	int cnt = 0;
1608
1609	do {
1610		errno = 0;
1611		if (!link(name1_p, name2_p)) {
1612			if (aclp != NULL) {
1613				acl_free(aclp);
1614				aclp = NULL;
1615				acl_is_set = 0;
1616			}
1617			cnt = 0;
1618			break;
1619		} else if ((errno == EEXIST) && (cnt == 0)) {
1620			struct stat lsb1;
1621			struct stat lsb2;
1622
1623			/*
1624			 * Check to see if we are trying to link this
1625			 * file to itself.  If so, count the effort as
1626			 * successful.  If the two files are different,
1627			 * or if either lstat is unsuccessful, proceed
1628			 * as we would have otherwise; the appropriate
1629			 * error will be reported subsequently.
1630			 */
1631
1632			if (lstat(name1_p, &lsb1) != 0) {
1633				msg(ERR, "Cannot lstat source file %s",
1634				    name1_p);
1635			} else {
1636				if (lstat(name2_p, &lsb2) != 0) {
1637					msg(ERR, "Cannot lstat "
1638					    "destination file %s", name2_p);
1639				} else {
1640					if (lsb1.st_dev == lsb2.st_dev &&
1641					    lsb1.st_ino == lsb2.st_ino) {
1642						VERBOSE((Args & (OCv | OCV)),
1643						    name2_p);
1644						return (0);
1645					}
1646				}
1647			}
1648
1649			if (!(Args & OCu) && G_p->g_mtime <= DesSt.st_mtime)
1650				msg(ERR, "Existing \"%s\" same age or newer",
1651				    name2_p);
1652			else if (unlinkat(dirfd, get_component(name2_p), 0) < 0)
1653				msg(ERRN, "Error cannot unlink \"%s\"",
1654				    name2_p);
1655		}
1656		cnt++;
1657	} while ((cnt < 2) && missdir(name2_p) == 0);
1658	if (!cnt) {
1659		char *newname;
1660		char *fromname;
1661		char *attrname;
1662
1663		newname = name2_p;
1664		fromname = name1_p;
1665		attrname = Gen.g_attrnam_p;
1666		if (attrname) {
1667			if (Args & OCp) {
1668				newname = fromname = Fullnam_p;
1669			} else {
1670				newname = Gen.g_attrfnam_p;
1671			}
1672		}
1673		if (Args & OCv) {
1674			(void) fprintf(Err_p,
1675			    gettext("%s%s%s linked to %s%s%s\n"), newname,
1676			    (attrname == (char *)NULL) ?
1677			    "" : gettext(" attribute "),
1678			    (attrname == (char *)NULL) ?
1679			    "" : attrname, fromname,
1680			    (attrname == (char *)NULL) ?
1681			    "" : gettext(" attribute "),
1682			    (attrname == (char *)NULL) ?
1683			    "" : name1_p);
1684		}
1685		VERBOSE((Args & (OCv | OCV)), newname);
1686	} else if (cnt == 1)
1687		msg(ERRN,
1688		    "Unable to create directory for \"%s\"", name2_p);
1689	else if (cnt == 2)
1690		msg(ERRN,
1691		    "Cannot link \"%s\" and \"%s\"", name1_p, name2_p);
1692	return (cnt);
1693}
1694
1695/*
1696 * creat_spec:
1697 *   Create one of the following:
1698 *       directory
1699 *       character special file
1700 *       block special file
1701 *       fifo
1702 */
1703
1704static int
1705creat_spec(int dirfd)
1706{
1707	char *nam_p;
1708	int cnt, result, rv = 0;
1709	char *curdir;
1710	char *lastslash;
1711
1712	Do_rename = 0;	/* creat_tmp() may reset this */
1713
1714	if (Args & OCp) {
1715		nam_p = Fullnam_p;
1716	} else {
1717		nam_p = G_p->g_nam_p;
1718	}
1719
1720	/*
1721	 * Is this the extraction of the hidden attribute directory?
1722	 * If so then just set the mode/times correctly, and return.
1723	 */
1724
1725	if (Hiddendir) {
1726		if (Args & OCR) {
1727			if (fchownat(dirfd, ".", Rpw_p->pw_uid,
1728			    Rpw_p->pw_gid, 0) != 0) {
1729				msg(ERRN,
1730				    "Cannot chown() \"attribute directory of "
1731				    "file %s\"", G_p->g_attrfnam_p);
1732			}
1733		} else if ((fchownat(dirfd, ".", G_p->g_uid,
1734		    G_p->g_gid, 0) != 0) && privileged) {
1735			msg(ERRN,
1736			    "Cannot chown() \"attribute directory of "
1737			    "file %s\"", G_p->g_attrfnam_p);
1738		}
1739
1740		if (fchmod(dirfd, G_p->g_mode) != 0) {
1741			msg(ERRN,
1742			    "Cannot chmod() \"attribute directory of "
1743			    "file %s\"", G_p->g_attrfnam_p);
1744		}
1745
1746		acl_is_set = 0;
1747		if (Pflag && aclp != NULL) {
1748			if (facl_set(dirfd, aclp) < 0) {
1749				msg(ERRN,
1750				    "failed to set acl on attribute"
1751				    " directory of %s ", G_p->g_attrfnam_p);
1752			} else {
1753				acl_is_set = 1;
1754			}
1755			acl_free(aclp);
1756			aclp = NULL;
1757		}
1758
1759		return (1);
1760	}
1761
1762	result = stat(nam_p, &DesSt);
1763
1764	if (ustar_dir() || Adir) {
1765		/*
1766		 *  The archive file is a directory.
1767		 *  Skip "." and ".."
1768		 */
1769
1770		curdir = strrchr(nam_p, '.');
1771
1772		if (curdir != NULL && curdir[1] == NULL) {
1773			lastslash = strrchr(nam_p, '/');
1774
1775			if (lastslash != NULL) {
1776				lastslash++;
1777			} else {
1778				lastslash = nam_p;
1779			}
1780
1781			if (!(strcmp(lastslash, ".")) ||
1782			    !(strcmp(lastslash, ".."))) {
1783				return (1);
1784			}
1785		}
1786
1787		if (result == 0) {
1788			/* A file by the same name exists. */
1789
1790			/* Take care of ACLs */
1791			acl_is_set = 0;
1792
1793			if (Pflag && aclp != NULL) {
1794				if (acl_set(nam_p, aclp) < 0) {
1795					msg(ERRN,
1796					    "\"%s\": failed to set acl",
1797					    nam_p);
1798				} else {
1799					acl_is_set = 1;
1800				}
1801
1802				acl_free(aclp);
1803				aclp = NULL;
1804			}
1805			if (Args & OCd) {
1806				/*
1807				 * We are creating directories.  Keep the
1808				 * existing file.
1809				 */
1810
1811				rstfiles(U_KEEP, dirfd);
1812			}
1813
1814			/* Report success. */
1815
1816			return (1);
1817		}
1818	} else {
1819		/* The archive file is not a directory. */
1820
1821		if (result == 0) {
1822			/*
1823			 * A file by the same name exists.  Move it to a
1824			 * temporary file.
1825			 */
1826
1827			if (creat_tmp(nam_p) < 0) {
1828				/*
1829				 * We weren't able to create the temp file.
1830				 * Report failure.
1831				 */
1832
1833				return (0);
1834			}
1835		}
1836	}
1837
1838	/*
1839	 * This pile tries to create the file directly, and, if there is a
1840	 * problem, creates missing directories, and then tries to create the
1841	 * file again.  Two strikes and you're out.
1842	 */
1843
1844	cnt = 0;
1845
1846	do {
1847		if (ustar_dir() || Adir) {
1848			/* The archive file is a directory. */
1849
1850			result = mkdir(nam_p, G_p->g_mode);
1851		} else if (ustar_spec() || Aspec) {
1852			/*
1853			 * The archive file is block special,
1854			 * char special or a fifo.
1855			 */
1856
1857			result = mknod(nam_p, (int)G_p->g_mode,
1858			    (int)G_p->g_rdev);
1859		}
1860
1861		if (result >= 0) {
1862			/*
1863			 * The file creation succeeded.  Take care of the ACLs.
1864			 */
1865
1866			acl_is_set = 0;
1867
1868			if (Pflag && aclp != NULL) {
1869				if (acl_set(nam_p, aclp) < 0) {
1870					msg(ERRN,
1871					    "\"%s\": failed to set acl", nam_p);
1872				} else {
1873					acl_is_set = 1;
1874				}
1875
1876				acl_free(aclp);
1877				aclp = NULL;
1878			}
1879
1880			cnt = 0;
1881			break;
1882		}
1883
1884		cnt++;
1885	} while (cnt < 2 && missdir(nam_p) == 0);
1886
1887	switch (cnt) {
1888	case 0:
1889		rv = 1;
1890		rstfiles(U_OVER, dirfd);
1891		break;
1892
1893	case 1:
1894		msg(ERRN,
1895		    "Cannot create directory for \"%s\"", nam_p);
1896
1897		if (*Over_p == '\0') {
1898			rstfiles(U_KEEP, dirfd);
1899		}
1900
1901		break;
1902
1903	case 2:
1904		if (ustar_dir() || Adir) {
1905			msg(ERRN, "Cannot create directory \"%s\"", nam_p);
1906		} else if (ustar_spec() || Aspec) {
1907			msg(ERRN, "Cannot mknod() \"%s\"", nam_p);
1908		}
1909
1910		if (*Over_p == '\0') {
1911			rstfiles(U_KEEP, dirfd);
1912		}
1913
1914		break;
1915
1916	default:
1917		msg(EXT, "Impossible case.");
1918	}
1919
1920	return (rv);
1921}
1922
1923/*
1924 * creat_tmp:
1925 */
1926
1927static int
1928creat_tmp(char *nam_p)
1929{
1930	char *t_p;
1931	int	cwd;
1932
1933	if ((Args & OCp) && G_p->g_ino == DesSt.st_ino &&
1934	    G_p->g_dev == DesSt.st_dev) {
1935		msg(ERR, "Attempt to pass a file to itself.");
1936		return (-1);
1937	}
1938
1939	if (G_p->g_mtime <= DesSt.st_mtime && !(Args & OCu)) {
1940		msg(ERR, "Existing \"%s\" same age or newer", nam_p);
1941		return (-1);
1942	}
1943
1944	/* Make the temporary file name. */
1945
1946	(void) strcpy(Over_p, nam_p);
1947	t_p = Over_p + strlen(Over_p);
1948
1949	while (t_p != Over_p) {
1950		if (*(t_p - 1) == '/')
1951			break;
1952		t_p--;
1953	}
1954
1955	(void) strcpy(t_p, "XXXXXX");
1956
1957	if (G_p->g_attrnam_p != (char *)NULL) {
1958		/*
1959		 * Save our current directory, so we can go into
1960		 * the attribute directory to make the temp file
1961		 * and then return.
1962		 */
1963
1964		cwd = save_cwd();
1965		(void) fchdir(G_p->g_dirfd);
1966	}
1967
1968	(void) mktemp(Over_p);
1969
1970	if (G_p->g_attrnam_p != (char *)NULL) {
1971		/* Return to the current directory. */
1972
1973		rest_cwd(cwd);
1974	}
1975
1976	if (*Over_p == '\0') {
1977		/* mktemp reports a failure. */
1978
1979		msg(ERR, "Cannot get temporary file name.");
1980		return (-1);
1981	}
1982
1983	/*
1984	 * If it's a regular file, write to the temporary file, and then rename
1985	 * in order to accomodate potential executables.
1986	 *
1987	 * Note: g_typeflag is only defined (set) for USTAR archive types.  It
1988	 * defaults to 0 in the cpio-format-regular file case, so this test
1989	 * succeeds.
1990	 */
1991
1992	if (G_p->g_typeflag == 0 &&
1993	    (DesSt.st_mode & (ulong_t)Ftype) == S_IFREG &&
1994	    (G_p->g_mode & (ulong_t)Ftype) == S_IFREG) {
1995		/*
1996		 * The archive file and the filesystem file are both regular
1997		 * files.  We write to the temporary file in this case.
1998		 */
1999
2000		if (Args & OCp) {
2001			if (G_p->g_attrnam_p == (char *)NULL) {
2002				Fullnam_p = Over_p;
2003			} else {
2004				Attrfile_p = Over_p;
2005			}
2006		} else {
2007			G_p->g_nam_p = Over_p;
2008			if (G_p->g_attrnam_p != (char *)NULL) {
2009				Attrfile_p = Over_p;
2010			}
2011		}
2012
2013		if (G_p->g_attrnam_p == (char *)NULL) {
2014			Over_p = nam_p;
2015		} else {
2016			Over_p = G_p->g_attrnam_p;
2017		}
2018
2019		Do_rename = 1;
2020	} else {
2021		/*
2022		 * Either the archive file or the filesystem file is not a
2023		 * regular file.
2024		 */
2025
2026		Do_rename = 0;
2027
2028		if (S_ISDIR(DesSt.st_mode)) {
2029			/*
2030			 * The filesystem file is a directory.
2031			 *
2032			 * Save the current working directory because we will
2033			 * want to restore it back just in case remove_dir()
2034			 * fails or get confused about where we should be.
2035			 */
2036
2037			*Over_p = '\0';
2038			cwd = save_cwd();
2039
2040			if (remove_dir(nam_p) < 0) {
2041				msg(ERRN,
2042				    "Cannot remove the directory \"%s\"",
2043				    nam_p);
2044				/*
2045				 * Restore working directory back to the one
2046				 * saved earlier.
2047				 */
2048
2049				rest_cwd(cwd);
2050				return (-1);
2051			}
2052
2053			/*
2054			 * Restore working directory back to the one
2055			 * saved earlier
2056			 */
2057
2058			rest_cwd(cwd);
2059		} else {
2060			/*
2061			 * The file is not a directory. Will use the original
2062			 * link/unlink construct, however, if the file is
2063			 * namefs, link would fail with EXDEV. Therefore, we
2064			 * use rename() first to back up the file.
2065			 */
2066			if (rename(nam_p, Over_p) < 0) {
2067				/*
2068				 * If rename failed, try old construction
2069				 * method.
2070				 */
2071				if (link(nam_p, Over_p) < 0) {
2072					msg(ERRN,
2073					    "Cannot create temporary file");
2074					*Over_p = '\0';
2075					return (-1);
2076				}
2077
2078				if (unlink(nam_p) < 0) {
2079					msg(ERRN,
2080					    "Cannot unlink() current \"%s\"",
2081					    nam_p);
2082					(void) unlink(Over_p);
2083					*Over_p = '\0';
2084					return (-1);
2085				}
2086			}
2087		}
2088	}
2089
2090	return (1);
2091}
2092
2093/*
2094 * data_in:  If proc_mode == P_PROC, bread() the file's data from the archive
2095 * and write(2) it to the open fdes gotten from openout().  If proc_mode ==
2096 * P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data
2097 * and ignore it.  If the user specified any of the "swap" options (b, s or S),
2098 * and the length of the file is not appropriate for that action, do not
2099 * perform the "swap", otherwise perform the action on a buffer by buffer basis.
2100 * If the CRC header was selected, calculate a running checksum as each buffer
2101 * is processed.
2102 */
2103
2104static void
2105data_in(int proc_mode)
2106{
2107	char *nam_p;
2108	int cnt, pad;
2109	long cksumval = 0L;
2110	off_t filesz;
2111	int rv, swapfile = 0;
2112	int compress_flag = 0;	/* if the file is compressed */
2113	int cstatus = 0;
2114	FILE *pipef;		/* pipe for bar to do de-compression */
2115
2116
2117	if (G_p->g_attrnam_p != (char *)NULL) {
2118		nam_p = G_p->g_attrnam_p;
2119	} else {
2120		nam_p = G_p->g_nam_p;
2121	}
2122
2123
2124	if (((G_p->g_mode & Ftype) == S_IFLNK && proc_mode != P_SKIP) ||
2125	    (Hdr_type == BAR && bar_linkflag == '2' && proc_mode != P_SKIP)) {
2126		proc_mode = P_SKIP;
2127		VERBOSE((Args & (OCv | OCV)), nam_p);
2128	}
2129	if (Args & (OCb | OCs | OCS)) { /* verfify that swapping is possible */
2130		swapfile = 1;
2131		if (Args & (OCs | OCb) && G_p->g_filesz % 2) {
2132			msg(ERR,
2133			    "Cannot swap bytes of \"%s\", odd number of bytes",
2134			    nam_p);
2135			swapfile = 0;
2136		}
2137		if (Args & (OCS | OCb) && G_p->g_filesz % 4) {
2138			msg(ERR,
2139			    "Cannot swap halfwords of \"%s\", odd number "
2140			    "of halfwords", nam_p);
2141			swapfile = 0;
2142		}
2143	}
2144	filesz = G_p->g_filesz;
2145
2146	/* This writes out the file from the archive */
2147
2148	while (filesz > 0) {
2149		cnt = (int)(filesz > CPIOBSZ) ? CPIOBSZ : filesz;
2150		FILL(cnt);
2151		if (proc_mode != P_SKIP) {
2152			if (Hdr_type == CRC)
2153				cksumval += cksum(CRC, cnt, NULL);
2154			if (swapfile)
2155				swap(Buffr.b_out_p, cnt);
2156			errno = 0;
2157
2158			/*
2159			 * if the bar archive is compressed, set up a pipe and
2160			 * do the de-compression while reading in the file
2161			 */
2162			if (Hdr_type == BAR) {
2163				if (compress_flag == 0 && Compressed) {
2164					setup_uncompress(&pipef);
2165					compress_flag++;
2166				}
2167
2168			}
2169
2170			rv = write(Ofile, Buffr.b_out_p, cnt);
2171			if (rv < cnt) {
2172				if (rv < 0)
2173					msg(ERRN, "Cannot write \"%s\"", nam_p);
2174				else
2175					msg(EXTN, "Cannot write \"%s\"", nam_p);
2176				proc_mode = P_SKIP;
2177				rstfiles(U_KEEP, G_p->g_dirfd);
2178				cstatus = close(Ofile);
2179				Ofile = 0;
2180				if (cstatus != 0) {
2181					msg(EXTN, "close error");
2182				}
2183			}
2184		}
2185		Buffr.b_out_p += cnt;
2186		Buffr.b_cnt -= (long)cnt;
2187		filesz -= (off_t)cnt;
2188	} /* filesz */
2189
2190	pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
2191	if (pad != 0) {
2192		FILL(pad);
2193		Buffr.b_out_p += pad;
2194		Buffr.b_cnt -= pad;
2195	}
2196	if (proc_mode != P_SKIP) {
2197		if (Hdr_type == CRC && Gen.g_cksum != cksumval) {
2198			msg(ERR, "\"%s\" - checksum error", nam_p);
2199			rstfiles(U_KEEP, G_p->g_dirfd);
2200		} else
2201			rstfiles(U_OVER, G_p->g_dirfd);
2202		if (Hdr_type == BAR && compress_flag) {
2203			(void) pclose(pipef);
2204		} else {
2205			cstatus = close(Ofile);
2206		}
2207		Ofile = 0;
2208		if (cstatus != 0) {
2209			msg(EXTN, "close error");
2210		}
2211	}
2212	VERBOSE((proc_mode != P_SKIP && (Args & (OCv | OCV))), G_p->g_nam_p);
2213	Finished = 1;
2214}
2215
2216/*
2217 * data_out:  open(2) the file to be archived, compute the checksum
2218 * of it's data if the CRC header was specified and write the header.
2219 * read(2) each block of data and bwrite() it to the archive.  For TARTYP (TAR
2220 * and USTAR) archives, pad the data with NULLs to the next 512 byte boundary.
2221 */
2222
2223static void
2224data_out(void)
2225{
2226	char *nam_p;
2227	int cnt, amount_read, pad;
2228	off_t amt_to_read, real_filesz;
2229	int	errret = 0;
2230
2231	nam_p = G_p->g_nam_p;
2232	if (Aspec) {
2233		if (Pflag && aclp != NULL) {
2234			char    *secinfo = NULL;
2235			int	len = 0;
2236
2237			/* append security attributes */
2238			if (append_secattr(&secinfo, &len, aclp) == -1) {
2239				msg(ERR,
2240				    "can create security information");
2241			}
2242			/* call append_secattr() if more than one */
2243
2244			if (len > 0) {
2245			/* write ancillary only if there is sec info */
2246				(void) write_hdr(ARCHIVE_ACL, (off_t)len);
2247				(void) write_ancillary(secinfo, len);
2248			}
2249		}
2250		write_hdr(ARCHIVE_NORMAL, (off_t)0);
2251		rstfiles(U_KEEP, G_p->g_dirfd);
2252		VERBOSE((Args & (OCv | OCV)), nam_p);
2253		return;
2254	}
2255	if ((G_p->g_mode & Ftype) == S_IFLNK && (Hdr_type !=
2256	    USTAR && Hdr_type != TAR)) { /* symbolic link */
2257		int size;
2258		write_hdr(ARCHIVE_NORMAL, (off_t)0);
2259
2260		FLUSH(G_p->g_filesz);
2261		errno = 0;
2262
2263		/* Note that "size" and G_p->g_filesz are the same number */
2264
2265		if ((size = readlink(nam_p, Buffr.b_in_p, G_p->g_filesz)) <
2266		    0) {
2267			msg(ERRN, "Cannot read symbolic link \"%s\"", nam_p);
2268			return;
2269		}
2270
2271		/*
2272		 * Note that it is OK not to add the NUL after the name read by
2273		 * readlink, because it is not being used subsequently.
2274		 */
2275
2276		Buffr.b_in_p += size;
2277		Buffr.b_cnt += size;
2278		pad = (Pad_val + 1 - (size & Pad_val)) & Pad_val;
2279		if (pad != 0) {
2280			FLUSH(pad);
2281			(void) memcpy(Buffr.b_in_p, Empty, pad);
2282			Buffr.b_in_p += pad;
2283			Buffr.b_cnt += pad;
2284		}
2285		VERBOSE((Args & (OCv | OCV)), nam_p);
2286		return;
2287	} else if ((G_p->g_mode & Ftype) == S_IFLNK &&
2288	    (Hdr_type == USTAR || Hdr_type == TAR)) {
2289		int size;
2290
2291		/*
2292		 * G_p->g_filesz is the length of the right-hand side of
2293		 * the symlink "x -> y".
2294		 * The tar link field is only NAMSIZ long.
2295		 */
2296
2297		if (G_p->g_filesz > NAMSIZ) {
2298			msg(ERRN,
2299			    "Symbolic link too long \"%s\"", nam_p);
2300			return;
2301		}
2302		if ((size = readlink(nam_p, T_lname, G_p->g_filesz)) < 0) {
2303			msg(ERRN,
2304			    "Cannot read symbolic link \"%s\"", nam_p);
2305			return;
2306		}
2307		T_lname[size] = '\0';
2308		G_p->g_filesz = (off_t)0;
2309		write_hdr(ARCHIVE_NORMAL, (off_t)0);
2310		VERBOSE((Args & (OCv | OCV)), nam_p);
2311		return;
2312	}
2313	if ((Ifile = openfile(O_RDONLY)) < 0) {
2314		msg(ERR, "\"%s%s%s\" ?",
2315		    (Gen.g_attrnam_p == (char *)NULL) ?
2316		    nam_p : Gen.g_attrfnam_p,
2317		    (Gen.g_attrnam_p == (char *)NULL) ?
2318		    "" : gettext(" Attribute "),
2319		    (Gen.g_attrnam_p == (char *)NULL) ?
2320		    "" : Gen.g_attrnam_p);
2321		return;
2322	}
2323
2324	/*
2325	 * Dump extended attribute header.
2326	 */
2327
2328	if (Gen.g_attrnam_p != (char *)NULL) {
2329		write_xattr_hdr();
2330	}
2331
2332	if (Hdr_type == CRC) {
2333		long csum = cksum(CRC, 0, &errret);
2334		if (errret != 0) {
2335			G_p->g_cksum = (ulong_t)-1;
2336			msg(POST, "\"%s%s%s\" skipped",
2337			    (Gen.g_attrnam_p == (char *)NULL) ?
2338			    nam_p : Gen.g_attrfnam_p,
2339			    (Gen.g_attrnam_p == (char *)NULL) ?
2340			    "" : gettext(" Attribute "),
2341			    (Gen.g_attrnam_p == (char *)NULL) ?
2342			    "" : nam_p);
2343			(void) close(Ifile);
2344			return;
2345		}
2346		G_p->g_cksum = csum;
2347	} else {
2348		G_p->g_cksum = 0;
2349	}
2350
2351	/*
2352	 * ACL has been retrieved in getname().
2353	 */
2354	if (Pflag) {
2355		char    *secinfo = NULL;
2356		int	len = 0;
2357
2358		/* append security attributes */
2359		if ((append_secattr(&secinfo, &len, aclp)) == -1)
2360			msg(ERR, "can create security information");
2361
2362		/* call append_secattr() if more than one */
2363
2364		if (len > 0) {
2365		/* write ancillary only if there is sec info */
2366			(void) write_hdr(ARCHIVE_ACL, (off_t)len);
2367			(void) write_ancillary(secinfo, len);
2368		}
2369	}
2370
2371	write_hdr(ARCHIVE_NORMAL, (off_t)0);
2372
2373	real_filesz = 0;
2374
2375	for (amt_to_read = G_p->g_filesz;
2376	    amt_to_read > 0;
2377	    amt_to_read -= (off_t)amount_read) {
2378		FLUSH(CPIOBSZ);
2379		errno = 0;
2380
2381		if ((amount_read = read(Ifile, Buffr.b_in_p, CPIOBSZ)) < 0) {
2382			msg(EXTN, "Cannot read \"%s%s%s\"",
2383			    (Gen.g_attrnam_p == (char *)NULL) ?
2384			    nam_p : Gen.g_attrfnam_p,
2385			    (Gen.g_attrnam_p == (char *)NULL) ?
2386			    "" : gettext(" Attribute "),
2387			    (Gen.g_attrnam_p == (char *)NULL) ?
2388			    "" : nam_p);
2389			break;
2390		}
2391
2392		if (amount_read == 0) {
2393			/* the file has shrunk */
2394			real_filesz = G_p->g_filesz - amt_to_read;
2395			break;
2396		} else if (amount_read > amt_to_read) {
2397			/* the file has grown */
2398			real_filesz = G_p->g_filesz +
2399			    (amount_read - amt_to_read);
2400			amount_read = amt_to_read;
2401		} else if (amount_read == amt_to_read) {
2402			/* the file is the same size */
2403			real_filesz = G_p->g_filesz;
2404		}
2405
2406		Buffr.b_in_p += amount_read;
2407		Buffr.b_cnt += (long)amount_read;
2408	}
2409
2410	while (amt_to_read > 0) {
2411		cnt = (amt_to_read > CPIOBSZ) ? CPIOBSZ : (int)amt_to_read;
2412		FLUSH(cnt);
2413		(void) memset(Buffr.b_in_p, NULL, cnt);
2414		Buffr.b_in_p += cnt;
2415		Buffr.b_cnt += cnt;
2416		amt_to_read -= cnt;
2417	}
2418
2419	pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
2420	if (pad != 0) {
2421		FLUSH(pad);
2422		(void) memcpy(Buffr.b_in_p, Empty, pad);
2423		Buffr.b_in_p += pad;
2424		Buffr.b_cnt += pad;
2425	}
2426
2427	if (real_filesz > G_p->g_filesz) {
2428		msg(ERR, "File size of \"%s%s%s\" has increased by %lld",
2429		    (Gen.g_attrnam_p == (char *)NULL) ?
2430		    G_p->g_nam_p : Gen.g_attrfnam_p,
2431		    (Gen.g_attrnam_p == (char *)NULL) ?
2432		    "" : gettext(" Attribute "),
2433		    (Gen.g_attrnam_p == (char *)NULL) ?
2434		    "" : G_p->g_nam_p,
2435		    (real_filesz - G_p->g_filesz));
2436	}
2437	if (real_filesz < G_p->g_filesz) {
2438		msg(ERR, "File size of \"%s%s%s\" has decreased by %lld",
2439		    (Gen.g_attrnam_p == (char *)NULL) ?
2440		    G_p->g_nam_p : Gen.g_attrfnam_p,
2441		    (Gen.g_attrnam_p == (char *)NULL) ?
2442		    "" : gettext(" Attribute "),
2443		    (Gen.g_attrnam_p == (char *)NULL) ?
2444		    "" : G_p->g_nam_p,
2445		    (G_p->g_filesz - real_filesz));
2446	}
2447
2448	(void) close(Ifile);
2449	rstfiles(U_KEEP, G_p->g_dirfd);
2450	VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
2451}
2452
2453/*
2454 * data_pass:  If not a special file (Aspec), open(2) the file to be
2455 * transferred, read(2) each block of data and write(2) it to the output file
2456 * Ofile, which was opened in file_pass().
2457 */
2458
2459static void
2460data_pass(void)
2461{
2462	int cnt, done = 1;
2463	int cstatus;
2464	off_t filesz;
2465	char *namep = Nam_p;
2466
2467	if (G_p->g_attrnam_p != (char *)NULL) {
2468		namep = G_p->g_attrnam_p;
2469	}
2470	if (Aspec) {
2471		rstfiles(U_KEEP, G_p->g_passdirfd);
2472		cstatus = close(Ofile);
2473		Ofile = 0;
2474		VERBOSE((Args & (OCv | OCV)), Nam_p);
2475		if (cstatus != 0) {
2476			msg(EXTN, "close error");
2477		}
2478		return;
2479	}
2480	if ((Ifile = openat(G_p->g_dirfd, get_component(namep), 0)) < 0) {
2481		msg(ERRN, "Cannot open \"%s%s%s\", skipped",
2482		    (G_p->g_attrnam_p == (char *)NULL) ?
2483		    Nam_p : G_p->g_attrfnam_p,
2484		    (G_p->g_attrnam_p == (char *)NULL) ?
2485		    "" : gettext(" Attribute "),
2486		    (G_p->g_attrnam_p == (char *)NULL) ?
2487		    "" : G_p->g_attrnam_p);
2488		rstfiles(U_KEEP, G_p->g_passdirfd);
2489		cstatus = close(Ofile);
2490		Ofile = 0;
2491		if (cstatus != 0) {
2492			msg(EXTN, "close error");
2493		}
2494		return;
2495	}
2496	filesz = G_p->g_filesz;
2497
2498	while (filesz > 0) {
2499		cnt = (unsigned)(filesz > Bufsize) ? Bufsize : filesz;
2500		errno = 0;
2501		if (read(Ifile, Buf_p, (unsigned)cnt) < 0) {
2502			msg(ERRN, "Cannot read \"%s%s%s\"",
2503			    (G_p->g_attrnam_p == (char *)NULL) ?
2504			    Nam_p : G_p->g_attrfnam_p,
2505			    (G_p->g_attrnam_p == (char *)NULL) ?
2506			    "" : gettext(" Attribute "),
2507			    (G_p->g_attrnam_p == (char *)NULL) ?
2508			    "" : G_p->g_attrnam_p);
2509			done = 0;
2510			break;
2511		}
2512		errno = 0;
2513		if (write(Ofile, Buf_p, (unsigned)cnt) < 0) {
2514			if (Do_rename) {
2515				msg(ERRN, "Cannot write \"%s%s%s\"", Over_p,
2516				    (G_p->g_attrnam_p == (char *)NULL) ?
2517				    "" : gettext(" Attribute "),
2518				    (G_p->g_attrnam_p == (char *)NULL) ?
2519				    "" : Over_p);
2520			} else {
2521				msg(ERRN, "Cannot write \"%s%s%s\"",
2522				    Fullnam_p,
2523				    (G_p->g_attrnam_p == (char *)NULL) ?
2524				    "" : gettext(" Attribute "),
2525				    (G_p->g_attrnam_p == (char *)NULL) ?
2526				    "" : G_p->g_attrnam_p);
2527			}
2528
2529			done = 0;
2530			break;
2531		}
2532		Blocks += (u_longlong_t)((cnt + (Bufsize - 1)) / Bufsize);
2533		filesz -= (off_t)cnt;
2534	}
2535	if (done) {
2536		rstfiles(U_OVER, G_p->g_passdirfd);
2537	} else {
2538		rstfiles(U_KEEP, G_p->g_passdirfd);
2539	}
2540	(void) close(Ifile);
2541	cstatus = close(Ofile);
2542	Ofile = 0;
2543	if (cstatus != 0) {
2544		msg(EXTN, "close error");
2545	}
2546	VERBOSE((Args & (OCv | OCV)), Fullnam_p);
2547	Finished = 1;
2548}
2549
2550/*
2551 * Allocation wrappers.  Used to centralize error handling for
2552 * failed allocations.
2553 */
2554static void *
2555e_alloc_fail(int flag)
2556{
2557	if (flag == E_EXIT) {
2558		msg(EXTN, "Out of memory");
2559	}
2560
2561	return (NULL);
2562}
2563
2564/*
2565 *  Note: unlike the other e_*lloc functions, e_realloc does not zero out the
2566 *  additional memory it returns.  Ensure that you do not trust its contents
2567 *  when you call it.
2568 */
2569
2570static void *
2571e_realloc(int flag, void *old, size_t newsize)
2572{
2573	void *ret = realloc(old, newsize);
2574
2575	if (ret == NULL) {
2576		return (e_alloc_fail(flag));
2577	}
2578
2579	return (ret);
2580}
2581
2582static char *
2583e_strdup(int flag, const char *arg)
2584{
2585	char *ret = strdup(arg);
2586
2587	if (ret == NULL) {
2588		return (e_alloc_fail(flag));
2589	}
2590
2591	return (ret);
2592}
2593
2594static void *
2595e_valloc(int flag, size_t size)
2596{
2597	void *ret = valloc(size);
2598
2599	if (ret == NULL) {
2600		return (e_alloc_fail(flag));
2601	}
2602
2603	return (ret);
2604}
2605
2606static void *
2607e_zalloc(int flag, size_t size)
2608{
2609	void *ret = malloc(size);
2610
2611	if (ret == NULL) {
2612		return (e_alloc_fail(flag));
2613	}
2614
2615	(void) memset(ret, 0, size);
2616	return (ret);
2617}
2618
2619/*
2620 * file_in:  Process an object from the archive.  If a TARTYP (TAR or USTAR)
2621 * archive and g_nlink == 1, link this file to the file name in t_linkname
2622 * and return.  Handle linked files in one of two ways.  If Onecopy == 0, this
2623 * is an old style (binary or -c) archive, create and extract the data for the
2624 * first link found, link all subsequent links to this file and skip their data.
2625 * If Oncecopy == 1, save links until all have been processed, and then
2626 * process the links first to last checking their names against the patterns
2627 * and/or asking the user to rename them.  The first link that is accepted
2628 * for xtraction is created and the data is read from the archive.
2629 * All subsequent links that are accepted are linked to this file.
2630 */
2631
2632static void
2633file_in(void)
2634{
2635	struct Lnk *l_p, *tl_p;
2636	int lnkem = 0, cleanup = 0;
2637	int proc_file;
2638	struct Lnk *ttl_p;
2639	int typeflag;
2640	char savacl;
2641	int cwd;
2642
2643	G_p = &Gen;
2644
2645	/*
2646	 * Open target directory if this isn't a skipped file
2647	 * and g_nlink == 1
2648	 *
2649	 * Links are handled further down in this function.
2650	 */
2651
2652	proc_file = ckname(0);
2653
2654	if (proc_file == F_SKIP && G_p->g_nlink == 1) {
2655		/*
2656		 * Normally ckname() prints out the file as a side
2657		 * effect except for table of contents listing
2658		 * when its parameter is zero and Onecopy isn't
2659		 * Zero.  Due to this we need to force the name
2660		 * to be printed here.
2661		 */
2662		if (Onecopy == 1) {
2663			VERBOSE((Args & OCt), G_p->g_nam_p);
2664		}
2665		data_in(P_SKIP);
2666		return;
2667	}
2668
2669	if (proc_file != F_SKIP && open_dirfd() != 0) {
2670		data_in(P_SKIP);
2671		return;
2672	}
2673
2674	if (Hdr_type == BAR) {
2675		bar_file_in();
2676		close_dirfd();
2677		return;
2678	}
2679
2680	/*
2681	 * For archives in USTAR format, the files are extracted according
2682	 * to the typeflag.
2683	 */
2684	if (Hdr_type == USTAR || Hdr_type == TAR) {
2685		typeflag = Thdr_p->tbuf.t_typeflag;
2686		if (G_p->g_nlink == 1) {		/* hard link */
2687			if (proc_file != F_SKIP) {
2688				int i;
2689				char lname[NAMSIZ+1];
2690				(void) memset(lname, '\0', sizeof (lname));
2691
2692				(void) strncpy(lname, Thdr_p->tbuf.t_linkname,
2693				    NAMSIZ);
2694				for (i = 0; i <= NAMSIZ && lname[i] != 0; i++)
2695					;
2696
2697				lname[i] = 0;
2698				(void) creat_lnk(G_p->g_dirfd,
2699				    &lname[0], G_p->g_nam_p);
2700			}
2701			close_dirfd();
2702			return;
2703		}
2704		if (typeflag == '3' || typeflag == '4' || typeflag == '5' ||
2705		    typeflag == '6') {
2706			if (proc_file != F_SKIP &&
2707			    creat_spec(G_p->g_dirfd) > 0) {
2708				VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
2709			}
2710			close_dirfd();
2711			return;
2712		} else if (Adir || Aspec) {
2713			if ((proc_file == F_SKIP) ||
2714			    (Ofile = openout(G_p->g_dirfd)) < 0) {
2715				data_in(P_SKIP);
2716			} else {
2717				data_in(P_PROC);
2718			}
2719			close_dirfd();
2720			return;
2721		}
2722	}
2723
2724	if (Adir) {
2725		if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
2726			VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
2727		}
2728		close_dirfd();
2729		if (Onecopy == 1) {
2730			VERBOSE((Args & OCt), G_p->g_nam_p);
2731		}
2732		return;
2733	}
2734	if (G_p->g_nlink == 1 || (Hdr_type == TAR ||
2735	    Hdr_type == USTAR)) {
2736		if (Aspec) {
2737			if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0)
2738				VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
2739		} else {
2740			if ((proc_file == F_SKIP) ||
2741			    (Ofile = openout(G_p->g_dirfd)) < 0) {
2742				data_in(P_SKIP);
2743			} else {
2744				data_in(P_PROC);
2745			}
2746		}
2747		close_dirfd();
2748		return;
2749	}
2750	close_dirfd();
2751
2752	tl_p = add_lnk(&ttl_p);
2753	l_p = ttl_p;
2754	if (l_p->L_cnt == l_p->L_gen.g_nlink)
2755		cleanup = 1;
2756	if (!Onecopy || G_p->g_attrnam_p != (char *)NULL) {
2757		lnkem = (tl_p != l_p) ? 1 : 0;
2758		G_p = &tl_p->L_gen;
2759		if (proc_file == F_SKIP) {
2760			data_in(P_SKIP);
2761		} else {
2762			if (open_dirfd() != 0)
2763				return;
2764			if (!lnkem) {
2765				if (Aspec) {
2766					if (creat_spec(G_p->g_dirfd) > 0)
2767						VERBOSE((Args & (OCv | OCV)),
2768						    G_p->g_nam_p);
2769				} else if ((Ofile =
2770				    openout(G_p->g_dirfd)) < 0) {
2771					data_in(P_SKIP);
2772					close_dirfd();
2773					reclaim(l_p);
2774				} else {
2775					data_in(P_PROC);
2776					close_dirfd();
2777				}
2778			} else {
2779				/*
2780				 * Are we linking an attribute?
2781				 */
2782				cwd = -1;
2783				if (l_p->L_gen.g_attrnam_p != (char *)NULL) {
2784					(void) strcpy(Lnkend_p,
2785					    l_p->L_gen.g_attrnam_p);
2786					(void) strcpy(Full_p,
2787					    tl_p->L_gen.g_attrnam_p);
2788					cwd = save_cwd();
2789					(void) fchdir(G_p->g_dirfd);
2790				} else {
2791					(void) strcpy(Lnkend_p,
2792					    l_p->L_gen.g_nam_p);
2793					(void) strcpy(Full_p,
2794					    tl_p->L_gen.g_nam_p);
2795				}
2796				(void) creat_lnk(G_p->g_dirfd,
2797				    Lnkend_p, Full_p);
2798				data_in(P_SKIP);
2799				close_dirfd();
2800				l_p->L_lnk_p = (struct Lnk *)NULL;
2801				free(tl_p->L_gen.g_nam_p);
2802				free(tl_p);
2803				if (cwd != -1)
2804					rest_cwd(cwd);
2805			}
2806		}
2807	} else { /* Onecopy */
2808		if (tl_p->L_gen.g_filesz)
2809			cleanup = 1;
2810		if (!cleanup) {
2811			close_dirfd();
2812			return; /* don't do anything yet */
2813		}
2814		tl_p = l_p;
2815		/*
2816		 * ckname will clear aclchar. We need to keep aclchar for
2817		 * all links.
2818		 */
2819		savacl = aclchar;
2820		while (tl_p != (struct Lnk *)NULL) {
2821			G_p = &tl_p->L_gen;
2822			aclchar = savacl;
2823			if ((proc_file = ckname(1)) != F_SKIP) {
2824				if (open_dirfd() != 0) {
2825					return;
2826				}
2827				if (l_p->L_data) {
2828					(void) creat_lnk(G_p->g_dirfd,
2829					    l_p->L_gen.g_nam_p,
2830					    G_p->g_nam_p);
2831				} else if (Aspec) {
2832					(void) creat_spec(G_p->g_dirfd);
2833					l_p->L_data = 1;
2834					VERBOSE((Args & (OCv | OCV)),
2835					    G_p->g_nam_p);
2836				} else if ((Ofile =
2837				    openout(G_p->g_dirfd)) < 0) {
2838					proc_file = F_SKIP;
2839				} else {
2840					data_in(P_PROC);
2841					l_p->L_data = 1;
2842				}
2843			} /* (proc_file = ckname(1)) != F_SKIP */
2844
2845			tl_p = tl_p->L_lnk_p;
2846
2847			close_dirfd();
2848
2849			if (proc_file == F_SKIP && !cleanup) {
2850				tl_p->L_nxt_p = l_p->L_nxt_p;
2851				tl_p->L_bck_p = l_p->L_bck_p;
2852				l_p->L_bck_p->L_nxt_p = tl_p;
2853				l_p->L_nxt_p->L_bck_p = tl_p;
2854				free(l_p->L_gen.g_nam_p);
2855				free(l_p);
2856			}
2857		} /* tl_p->L_lnk_p != (struct Lnk *)NULL */
2858		if (l_p->L_data == 0) {
2859			data_in(P_SKIP);
2860		}
2861	}
2862	if (cleanup) {
2863		reclaim(l_p);
2864	}
2865}
2866
2867/*
2868 * file_out:  If the current file is not a special file (!Aspec) and it
2869 * is identical to the archive, skip it (do not archive the archive if it
2870 * is a regular file).  If creating a TARTYP (TAR or USTAR) archive, the first
2871 * time a link to a file is encountered, write the header and file out normally.
2872 * Subsequent links to this file put this file name in their t_linkname field.
2873 * Otherwise, links are handled in one of two ways, for the old headers
2874 * (i.e. binary and -c), linked files are written out as they are encountered.
2875 * For the new headers (ASC and CRC), links are saved up until all the links
2876 * to each file are found.  For a file with n links, write n - 1 headers with
2877 * g_filesz set to 0, write the final (nth) header with the correct g_filesz
2878 * value and write the data for the file to the archive.
2879 */
2880
2881static
2882int
2883file_out(void)
2884{
2885	struct Lnk *l_p, *tl_p;
2886	int cleanup = 0;
2887	struct Lnk *ttl_p;
2888
2889	G_p = &Gen;
2890	if (!Aspec && IDENT(SrcSt, ArchSt))
2891		return (1); /* do not archive the archive if it's a reg file */
2892	if (G_p->g_filesz > Max_offset) {
2893		msg(ERR, "cpio: %s%s%s: too large to archive in current mode",
2894		    G_p->g_nam_p,
2895		    (G_p->g_attrnam_p == (char *)NULL) ?
2896		    "" : gettext(" Attribute "),
2897		    (G_p->g_attrnam_p == (char *)NULL) ?
2898		    "" : G_p->g_attrnam_p);
2899		return (1); /* do not archive if it's too big */
2900	}
2901	if (Hdr_type == TAR || Hdr_type == USTAR) { /* TAR and USTAR */
2902		if (Adir) {
2903			if (Gen.g_attrnam_p != (char *)NULL) {
2904				write_xattr_hdr();
2905			}
2906			write_hdr(ARCHIVE_NORMAL, 0);
2907			return (0);
2908		}
2909		if (G_p->g_nlink == 1) {
2910			data_out();
2911			return (0);
2912		}
2913		tl_p = add_lnk(&ttl_p);
2914		l_p = ttl_p;
2915		if (tl_p == l_p) { /* first link to this file encountered */
2916			data_out();
2917			return (0);
2918		}
2919		(void) strncpy(T_lname, l_p->L_gen.g_nam_p,
2920		    l_p->L_gen.g_namesz);
2921
2922		/*
2923		 * check if linkname is greater than 100 characters
2924		 */
2925		if (strlen(T_lname) > NAMSIZ) {
2926			msg(EPOST, "cpio: %s: linkname %s is greater than %d",
2927			    G_p->g_nam_p, T_lname, NAMSIZ);
2928			return (1);
2929		}
2930
2931		write_hdr(ARCHIVE_NORMAL, (off_t)0);
2932		VERBOSE((Args & (OCv | OCV)), tl_p->L_gen.g_nam_p);
2933
2934		/* find the lnk entry in sublist, unlink it, and free it */
2935		for (; ttl_p->L_lnk_p != NULL;
2936		    ttl_p = ttl_p->L_lnk_p) {
2937			if (ttl_p->L_lnk_p == tl_p) {
2938				ttl_p->L_lnk_p = tl_p->L_lnk_p;
2939				free(tl_p->L_gen.g_nam_p);
2940				free(tl_p);
2941				break;
2942			}
2943		}
2944
2945		return (0);
2946	}
2947	if (Adir) {
2948		/*
2949		 * ACL has been retrieved in getname().
2950		 */
2951		if (Pflag) {
2952			char    *secinfo = NULL;
2953			int	len = 0;
2954
2955			/* append security attributes */
2956			if ((append_secattr(&secinfo, &len, aclp)) == -1)
2957				msg(ERR, "can create security information");
2958
2959			/* call append_secattr() if more than one */
2960
2961			if (len > 0) {
2962			/* write ancillary */
2963				(void) write_hdr(ARCHIVE_ACL, (off_t)len);
2964				(void) write_ancillary(secinfo, len);
2965			}
2966		}
2967
2968		if (Gen.g_attrnam_p != (char *)NULL) {
2969			write_xattr_hdr();
2970		}
2971		write_hdr(ARCHIVE_NORMAL, (off_t)0);
2972		VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
2973		return (0);
2974	}
2975	if (G_p->g_nlink == 1) {
2976		data_out();
2977		return (0);
2978	} else {
2979		tl_p = add_lnk(&ttl_p);
2980		l_p = ttl_p;
2981
2982		if (l_p->L_cnt == l_p->L_gen.g_nlink)
2983			cleanup = 1;
2984		else if (Onecopy && G_p->g_attrnam_p == (char *)NULL) {
2985			return (0); /* don't process data yet */
2986		}
2987	}
2988	if (Onecopy && G_p->g_attrnam_p == (char *)NULL) {
2989		tl_p = l_p;
2990		while (tl_p->L_lnk_p != (struct Lnk *)NULL) {
2991			G_p = &tl_p->L_gen;
2992			G_p->g_filesz = (off_t)0;
2993			/* one link with the acl is sufficient */
2994			write_hdr(ARCHIVE_NORMAL, (off_t)0);
2995			VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
2996			tl_p = tl_p->L_lnk_p;
2997		}
2998		G_p = &tl_p->L_gen;
2999		if (open_dirfd() != 0)
3000			return (1);
3001	}
3002	/* old style: has acl and data for every link */
3003	data_out();
3004	if (cleanup)
3005		reclaim(l_p);
3006	return (0);
3007}
3008
3009/*
3010 * file_pass:  If the -l option is set (link files when possible), and the
3011 * source and destination file systems are the same, link the source file
3012 * (G_p->g_nam_p) to the destination file (Fullnam) and return.  If not a
3013 * linked file, transfer the data.  Otherwise, the first link to a file
3014 * encountered is transferred normally and subsequent links are linked to it.
3015 */
3016
3017static int
3018file_pass(void)
3019{
3020	struct Lnk *l_p, *tl_p;
3021	struct Lnk *ttl_p;
3022	char *save_name;
3023	int size;
3024	int cwd;
3025	char *lfrom, *lto;
3026
3027	G_p = &Gen;
3028
3029	if (Adir && !(Args & OCd)) {
3030		msg(ERR, "Use -d option to copy \"%s\"", G_p->g_nam_p);
3031		return (FILE_PASS_ERR);
3032	}
3033
3034	save_name = G_p->g_nam_p;
3035
3036	while (*(G_p->g_nam_p) == '/') {
3037		G_p->g_nam_p++;
3038	}
3039
3040	(void) strcpy(Full_p,
3041	    (G_p->g_attrfnam_p == (char *)NULL) ?
3042	    G_p->g_nam_p : G_p->g_attrfnam_p);
3043
3044	if (G_p->g_attrnam_p == (char *)NULL) {
3045		G_p->g_passdirfd = open_dir(Fullnam_p);
3046
3047		if (G_p->g_passdirfd == -1) {
3048			msg(ERRN,
3049			    "Cannot open/create \"%s\"", Fullnam_p);
3050			return (FILE_PASS_ERR);
3051		}
3052	} else {
3053		G_p->g_passdirfd = attropen(Fullnam_p, ".", O_RDONLY);
3054
3055		if (G_p->g_passdirfd == -1) {
3056			G_p->g_passdirfd = retry_attrdir_open(Fullnam_p);
3057
3058			if (G_p->g_passdirfd == -1) {
3059				msg(ERRN,
3060				    "Cannot open attribute directory of"
3061				    " file \"%s\"", Fullnam_p);
3062				return (FILE_PASS_ERR);
3063			}
3064		}
3065	}
3066
3067	if (Args & OCl) {
3068		/* We are linking back to the source directory. */
3069
3070		if (!Adir) {
3071			char *existingfile = save_name;
3072
3073			if ((Args & OCL) && issymlink) {
3074				/* We are chasing symlinks. */
3075
3076				if ((size = readlink(save_name, Symlnk_p,
3077				    MAXPATHLEN)) < 0) {
3078					msg(ERRN,
3079					    "Cannot read symbolic link \"%s\"",
3080					    save_name);
3081					return (FILE_PASS_ERR);
3082				}
3083
3084				Symlnk_p[size] = '\0';
3085				existingfile = Symlnk_p;
3086			}
3087
3088			if (G_p->g_attrnam_p == (char *)NULL) {
3089				if (creat_lnk(G_p->g_passdirfd,
3090				    existingfile, Fullnam_p) == 0) {
3091					return (FILE_LINKED);
3092				}
3093			}
3094		}
3095	}
3096
3097	if ((G_p->g_mode & Ftype) == S_IFLNK && !(Args & OCL)) {
3098		/* The archive file is a symlink. */
3099
3100		errno = 0;
3101
3102		if ((size = readlink(save_name, Symlnk_p, MAXPATHLEN)) < 0) {
3103			msg(ERRN,
3104			    "Cannot read symbolic link \"%s\"", save_name);
3105			return (FILE_PASS_ERR);
3106		}
3107
3108		errno = 0;
3109		(void) missdir(Fullnam_p);
3110		*(Symlnk_p + size) = '\0';
3111
3112		if (symlink(Symlnk_p, Fullnam_p) < 0) {
3113			if (errno == EEXIST) {
3114				if (openout(G_p->g_passdirfd) < 0) {
3115					if (errno != EEXIST) {
3116						msg(ERRN,
3117						    "Cannot create \"%s\"",
3118						    Fullnam_p);
3119					}
3120					return (FILE_PASS_ERR);
3121				}
3122			} else {
3123				msg(ERRN, "Cannot create \"%s\"", Fullnam_p);
3124				return (FILE_PASS_ERR);
3125			}
3126		} else {
3127			if (Args & OCR) {
3128				if (lchown(Fullnam_p, (int)Rpw_p->pw_uid,
3129				    (int)Rpw_p->pw_gid) < 0) {
3130					msg(ERRN,
3131					    "Error during chown() of \"%s\"",
3132					    Fullnam_p);
3133				}
3134			} else if ((lchown(Fullnam_p, (int)G_p->g_uid,
3135			    (int)G_p->g_gid) < 0) && privileged) {
3136				msg(ERRN,
3137				    "Error during chown() of \"%s\"",
3138				    Fullnam_p);
3139			}
3140		}
3141
3142		VERBOSE((Args & (OCv | OCV)), Fullnam_p);
3143		return (FILE_PASS_ERR);
3144	}
3145
3146	if (!Adir && G_p->g_nlink > 1) {
3147		/* The archive file has hard links. */
3148
3149		tl_p = add_lnk(&ttl_p);
3150		l_p = ttl_p;
3151
3152		if (tl_p == l_p) {
3153			/* The archive file was not found. */
3154
3155			G_p = &tl_p->L_gen;
3156		} else {
3157			/* The archive file was found. */
3158
3159			cwd = -1;
3160
3161			if (l_p->L_gen.g_attrnam_p != (char *)NULL) {
3162				/* We are linking an attribute */
3163
3164				(void) strcpy(Lnkend_p, l_p->L_gen.g_attrnam_p);
3165				cwd = save_cwd();
3166				(void) fchdir(G_p->g_passdirfd);
3167				lfrom = get_component(Lnknam_p);
3168				lto = tl_p->L_gen.g_attrnam_p;
3169			} else {
3170				/* We are not linking an attribute */
3171
3172				(void) strcpy(Lnkend_p, l_p->L_gen.g_nam_p);
3173				(void) strcpy(Full_p, tl_p->L_gen.g_nam_p);
3174				lfrom = Lnknam_p;
3175				lto = Fullnam_p;
3176			}
3177
3178			(void) creat_lnk(G_p->g_passdirfd, lfrom, lto);
3179
3180			if (cwd) {
3181				rest_cwd(cwd);
3182			}
3183
3184			l_p->L_lnk_p = (struct Lnk *)NULL;
3185			free(tl_p->L_gen.g_nam_p);
3186			free(tl_p);
3187
3188			if (l_p->L_cnt == G_p->g_nlink) {
3189				reclaim(l_p);
3190			}
3191
3192			return (FILE_LINKED);
3193		}
3194	}
3195
3196	if (Adir || Aspec) {
3197		/*
3198		 * The archive file is a directory,  block special, char
3199		 * special or a fifo.
3200		 */
3201
3202		if (creat_spec(G_p->g_passdirfd) > 0) {
3203			VERBOSE((Args & (OCv | OCV)), Fullnam_p);
3204		}
3205	} else if ((Ofile = openout(G_p->g_passdirfd)) > 0) {
3206		data_pass();
3207	}
3208
3209	return (FILE_COPIED);
3210}
3211
3212/*
3213 * flush_lnks: With new linked file handling, linked files are not archived
3214 * until all links have been collected.  When the end of the list of filenames
3215 * to archive has been reached, all files that did not encounter all their links
3216 * are written out with actual (encountered) link counts.  A file with n links
3217 * (that are archived) will be represented by n headers (one for each link (the
3218 * first n - 1 have g_filesz set to 0)) followed by the data for the file.
3219 */
3220
3221static void
3222flush_lnks(void)
3223{
3224	struct Lnk *l_p, *tl_p;
3225	off_t tfsize;
3226
3227	l_p = Lnk_hd.L_nxt_p;
3228	while (l_p != &Lnk_hd) {
3229		(void) strcpy(Gen.g_nam_p, l_p->L_gen.g_nam_p);
3230		if (stat(Gen.g_nam_p, &SrcSt) == 0) { /* check if file exists */
3231			tl_p = l_p;
3232			(void) creat_hdr();
3233			Gen.g_nlink = l_p->L_cnt; /* "actual" link count */
3234			tfsize = Gen.g_filesz;
3235			Gen.g_filesz = (off_t)0;
3236			G_p = &Gen;
3237			while (tl_p != (struct Lnk *)NULL) {
3238				Gen.g_nam_p = tl_p->L_gen.g_nam_p;
3239				Gen.g_namesz = tl_p->L_gen.g_namesz;
3240				if (tl_p->L_lnk_p == (struct Lnk *)NULL) {
3241					Gen.g_filesz = tfsize;
3242					if (open_dirfd() != 0) {
3243						break;
3244					}
3245					data_out();
3246					break;
3247				}
3248				write_hdr(ARCHIVE_NORMAL,
3249				    (off_t)0); /* header only */
3250				VERBOSE((Args & (OCv | OCV)), Gen.g_nam_p);
3251				tl_p = tl_p->L_lnk_p;
3252			}
3253			Gen.g_nam_p = Nam_p;
3254		} else /* stat(Gen.g_nam_p, &SrcSt) == 0 */
3255			msg(ERR, "\"%s%s%s\" has disappeared",
3256			    (Gen.g_attrnam_p == (char *)NULL) ?
3257			    Gen.g_nam_p : Gen.g_attrfnam_p,
3258			    (Gen.g_attrnam_p == (char *)NULL) ?
3259			    "" : gettext(" Attribute "),
3260			    (Gen.g_attrnam_p == (char *)NULL) ?
3261			    "" : Gen.g_attrnam_p);
3262		tl_p = l_p;
3263		l_p = l_p->L_nxt_p;
3264		reclaim(tl_p);
3265	} /* l_p != &Lnk_hd */
3266}
3267
3268/*
3269 * gethdr: Get a header from the archive, validate it and check for the trailer.
3270 * Any user specified Hdr_type is ignored (set to NONE in main).  Hdr_type is
3271 * set appropriately after a valid header is found.  Unless the -k option is
3272 * set a corrupted header causes an exit with an error.  I/O errors during
3273 * examination of any part of the header cause gethdr to throw away any current
3274 * data and start over.  Other errors during examination of any part of the
3275 * header cause gethdr to advance one byte and continue the examination.
3276 */
3277
3278static int
3279gethdr(void)
3280{
3281	ushort_t ftype;
3282	int hit = NONE, cnt = 0;
3283	int goodhdr, hsize, offset;
3284	int bswap = 0;
3285	char *preptr;
3286	int k = 0;
3287	int j;
3288	int error;
3289	int aclcnt;
3290
3291	Gen.g_nam_p = Nam_p;
3292	do { /* hit == NONE && (Args & OCk) && Buffr.b_cnt > 0 */
3293		FILL(Hdrsz);
3294		switch (Hdr_type) {
3295		case NONE:
3296		case BIN:
3297			Binmag.b_byte[0] = Buffr.b_out_p[0];
3298			Binmag.b_byte[1] = Buffr.b_out_p[1];
3299			if ((Binmag.b_half == CMN_BIN) ||
3300			    (Binmag.b_half == CMN_BBS)) {
3301				hit = read_hdr(BIN);
3302				if (Hdr_type == NONE)
3303					bswap = 1;
3304				hsize = HDRSZ + Gen.g_namesz;
3305				break;
3306			}
3307			if (Hdr_type != NONE)
3308				break;
3309			/*FALLTHROUGH*/
3310		case CHR:
3311			if (!(strncmp(Buffr.b_out_p, CMS_CHR, CMS_LEN))) {
3312				hit = read_hdr(CHR);
3313				hsize = CHRSZ + Gen.g_namesz;
3314				break;
3315			}
3316			if (Hdr_type != NONE)
3317				break;
3318			/*FALLTHROUGH*/
3319		case ASC:
3320			if (!(strncmp(Buffr.b_out_p, CMS_ASC, CMS_LEN))) {
3321				hit = read_hdr(ASC);
3322				hsize = ASCSZ + Gen.g_namesz;
3323				Max_namesz = APATH;
3324				break;
3325			}
3326			if (Hdr_type != NONE)
3327				break;
3328			/*FALLTHROUGH*/
3329		case CRC:
3330			if (!(strncmp(Buffr.b_out_p, CMS_CRC, CMS_LEN))) {
3331				hit = read_hdr(CRC);
3332				hsize = ASCSZ + Gen.g_namesz;
3333				Max_namesz = APATH;
3334				break;
3335			}
3336			if (Hdr_type != NONE)
3337				break;
3338			/*FALLTHROUGH*/
3339
3340		case BAR:
3341			if (Hdr_p != NULL && strcmp(Hdr_p, "bar") == 0) {
3342				Hdrsz = BARSZ;
3343				FILL(Hdrsz);
3344				if ((hit = read_hdr(BAR)) == NONE) {
3345					Hdrsz = ASCSZ;
3346					break;
3347				}
3348				hit = BAR;
3349				hsize = BARSZ;
3350				break;
3351			}
3352			/*FALLTHROUGH*/
3353
3354		case USTAR:
3355			if (Hdr_p != NULL && strcmp(Hdr_p, "ustar") == 0) {
3356				Hdrsz = TARSZ;
3357				FILL(Hdrsz);
3358				if ((hit = read_hdr(USTAR)) == NONE) {
3359					Hdrsz = ASCSZ;
3360					break;
3361				}
3362				hit = USTAR;
3363				hsize = TARSZ;
3364				break;
3365			}
3366			/*FALLTHROUGH*/
3367		case TAR:
3368			if (Hdr_p != NULL && strcmp(Hdr_p, "tar") == 0) {
3369				Hdrsz = TARSZ;
3370				FILL(Hdrsz);
3371				if ((hit = read_hdr(TAR)) == NONE) {
3372					Hdrsz = ASCSZ;
3373					break;
3374				}
3375				hit = TAR;
3376				hsize = TARSZ;
3377				break;
3378			}
3379			/*FALLTHROUGH*/
3380		default:
3381			msg(EXT, "Impossible header type.");
3382		} /* Hdr_type */
3383
3384		if (hit == TAR || hit == USTAR) {
3385			Gen.g_nam_p = &nambuf[0];
3386		}
3387
3388		if (hit != NONE) {
3389			FILL(hsize);
3390			goodhdr = 1;
3391			if (Gen.g_filesz < (off_t)0 || Gen.g_namesz < 1)
3392				goodhdr = 0;
3393			if ((hit != USTAR) && (hit != TAR))
3394				if (Gen.g_namesz - 1 > Max_namesz)
3395					goodhdr = 0;
3396			/* TAR and USTAR */
3397			if ((hit == USTAR) || (hit == TAR)) {
3398				if (*Gen.g_nam_p == '\0') { /* tar trailer */
3399					goodhdr = 1;
3400				} else {
3401
3402					G_p = &Gen;
3403					if (G_p->g_cksum !=
3404					    cksum(TARTYP, 0, NULL)) {
3405						goodhdr = 0;
3406						msg(ERR,
3407						    "Bad header - checksum "
3408						    "error.");
3409					}
3410				}
3411			} else if (hit != BAR) { /* binary, -c, ASC and CRC */
3412				if (Gen.g_nlink <= (ulong_t)0)
3413					goodhdr = 0;
3414				if (*(Buffr.b_out_p + hsize - 1) != '\0')
3415					goodhdr = 0;
3416			}
3417			if (!goodhdr) {
3418				hit = NONE;
3419				if (!(Args & OCk))
3420					break;
3421				msg(ERR,
3422				    "Corrupt header, file(s) may be lost.");
3423			} else {
3424				FILL(hsize);
3425			}
3426		} /* hit != NONE */
3427		if (hit == NONE) {
3428			Buffr.b_out_p++;
3429			Buffr.b_cnt--;
3430			if (!(Args & OCk))
3431				break;
3432			if (!cnt++)
3433				msg(ERR, "Searching for magic number/header.");
3434		}
3435	} while (hit == NONE);
3436	if (hit == NONE) {
3437		if (Hdr_type == NONE)
3438			msg(EXT, "Not a cpio file, bad header.");
3439		else
3440			msg(EXT, "Bad magic number/header.");
3441	} else if (cnt > 0) {
3442		msg(EPOST, "Re-synchronized on magic number/header.");
3443	}
3444	if (Hdr_type == NONE) {
3445		Hdr_type = hit;
3446		switch (Hdr_type) {
3447		case BIN:
3448			if (bswap)
3449				Args |= BSM;
3450			Hdrsz = HDRSZ;
3451			Max_namesz = CPATH;
3452			Pad_val = HALFWD;
3453			Onecopy = 0;
3454			break;
3455		case CHR:
3456			Hdrsz = CHRSZ;
3457			Max_namesz = CPATH;
3458			Pad_val = 0;
3459			Onecopy = 0;
3460			break;
3461		case ASC:
3462		case CRC:
3463			Hdrsz = ASCSZ;
3464			Max_namesz = APATH;
3465			Pad_val = FULLWD;
3466			Onecopy = 1;
3467			break;
3468		case USTAR:
3469			Hdrsz = TARSZ;
3470			Max_namesz = HNAMLEN - 1;
3471			Pad_val = FULLBK;
3472			Onecopy = 0;
3473			break;
3474		case BAR:
3475		case TAR:
3476			Hdrsz = TARSZ;
3477			Max_namesz = TNAMLEN - 1;
3478			Pad_val = FULLBK;
3479			Onecopy = 0;
3480			break;
3481		default:
3482			msg(EXT, "Impossible header type.");
3483		} /* Hdr_type */
3484	} /* Hdr_type == NONE */
3485	if ((Hdr_type == USTAR) || (Hdr_type == TAR) ||
3486	    (Hdr_type == BAR)) {			/* TAR, USTAR, BAR */
3487		Gen.g_namesz = 0;
3488		if (Gen.g_nam_p[0] == '\0')
3489			return (0);
3490		else {
3491			preptr = &prebuf[0];
3492			if (*preptr != (char)NULL) {
3493				k = strlen(&prebuf[0]);
3494				if (k < PRESIZ) {
3495					(void) strcpy(&fullnam[0], &prebuf[0]);
3496					j = 0;
3497					fullnam[k++] = '/';
3498					while ((j < NAMSIZ) && (&nambuf[j] !=
3499					    (char)NULL)) {
3500						fullnam[k] = nambuf[j];
3501						k++; j++;
3502					}
3503					fullnam[k] = '\0';
3504				} else if (k >= PRESIZ) {
3505					k = 0;
3506					while ((k < PRESIZ) && (prebuf[k] !=
3507					    '\0')) {
3508						fullnam[k] = prebuf[k];
3509						k++;
3510					}
3511					fullnam[k++] = '/';
3512					j = 0;
3513					while ((j < NAMSIZ) && (nambuf[j] !=
3514					    '\0')) {
3515						fullnam[k] = nambuf[j];
3516						k++; j++;
3517					}
3518					fullnam[k] = '\0';
3519				}
3520				Gen.g_nam_p = &fullnam[0];
3521			} else
3522				Gen.g_nam_p = &nambuf[0];
3523
3524			/*
3525			 * initialize the buffer so that the prefix will not
3526			 * applied to the next entry in the archive
3527			 */
3528			(void) memset(prebuf, 0, sizeof (prebuf));
3529		}
3530	} else if (Hdr_type != BAR) {
3531		(void) memcpy(Gen.g_nam_p, Buffr.b_out_p + Hdrsz, Gen.g_namesz);
3532		if (!(strcmp(Gen.g_nam_p, "TRAILER!!!")))
3533			return (0);
3534	}
3535	offset = ((hsize + Pad_val) & ~Pad_val);
3536	FILL(offset + Hdrsz);
3537	Thdr_p = (union tblock *)Buffr.b_out_p;
3538	Buffr.b_out_p += offset;
3539	Buffr.b_cnt -= (off_t)offset;
3540	ftype = Gen.g_mode & Ftype;
3541
3542#if defined(O_XATTR)
3543	/* extended attribute support */
3544	if (((Gen.g_mode & S_IFMT) == _XATTR_CPIO_MODE) ||
3545	    ((Hdr_type == USTAR || Hdr_type == TAR) &&
3546	    Thdr_p->tbuf.t_typeflag == _XATTR_HDRTYPE)) {
3547		if (xattrp != (struct xattr_buf *)NULL) {
3548			if (xattrbadhead) {
3549				free(xattrhead);
3550				xattrp = NULL;
3551				xattr_linkp = NULL;
3552				xattrhead = NULL;
3553				return (1);
3554			}
3555			if (Atflag == 0 && ((Args & OCt) == 0)) {
3556				data_in(P_SKIP);
3557				free(xattrhead);
3558				xattrhead = NULL;
3559				xattrp = NULL;
3560				Gen.g_attrfnam_p = (char *)NULL;
3561				Gen.g_attrnam_p = (char *)NULL;
3562				return (2);
3563			}
3564
3565			if (Gen.g_attrfnam_p != (char *)NULL) {
3566				free(Gen.g_attrfnam_p);
3567				Gen.g_attrfnam_p = (char *)NULL;
3568			}
3569			if (Gen.g_attrnam_p != (char *)NULL) {
3570				free(Gen.g_attrnam_p);
3571				Gen.g_attrnam_p = (char *)NULL;
3572			}
3573			if (Renam_p && Renam_p[0] != '\0') {
3574				Gen.g_attrfnam_p = e_strdup(E_EXIT, Renam_p);
3575			} else {
3576				Gen.g_attrfnam_p = e_strdup(E_EXIT,
3577				    xattrp->h_names);
3578			}
3579
3580			Gen.g_attrnam_p = e_strdup(E_EXIT,
3581			    xattrp->h_names + strlen(xattrp->h_names) + 1);
3582
3583			if (Hdr_type != USTAR && Hdr_type != TAR) {
3584				Gen.g_mode = Gen.g_mode & (~_XATTR_CPIO_MODE);
3585				Gen.g_mode |= attrmode(xattrp->h_typeflag);
3586			} else if (Hdr_type == USTAR || Hdr_type == TAR) {
3587				Thdr_p->tbuf.t_typeflag = xattrp->h_typeflag;
3588			}
3589			if (xattr_linkp != (struct xattr_buf *)NULL) {
3590				if (Gen.g_linktoattrfnam_p != (char *)NULL) {
3591					free(Gen.g_linktoattrfnam_p);
3592					Gen.g_linktoattrfnam_p = NULL;
3593				}
3594				if (Gen.g_linktoattrnam_p != (char *)NULL) {
3595					free(Gen.g_linktoattrnam_p);
3596					Gen.g_linktoattrnam_p = NULL;
3597				}
3598				Gen.g_linktoattrfnam_p = e_strdup(E_EXIT,
3599				    xattr_linkp->h_names);
3600				Gen.g_linktoattrnam_p = e_strdup(E_EXIT,
3601				    xattr_linkp->h_names +
3602				    strlen(xattr_linkp->h_names) + 1);
3603				xattr_linkp = NULL;
3604			}
3605			ftype = Gen.g_mode & Ftype;
3606			Adir = ftype == S_IFDIR;
3607			Aspec = (ftype == S_IFBLK ||
3608			    ftype == S_IFCHR || ftype == S_IFIFO);
3609
3610			if (Gen.g_attrnam_p[0] == '.' &&
3611			    Gen.g_attrnam_p[1] == '\0' &&
3612			    xattrp->h_typeflag == DIRTYPE) {
3613				Hiddendir = 1;
3614			} else {
3615				Hiddendir = 0;
3616			}
3617
3618			free(xattrhead);
3619			xattrhead = NULL;
3620			xattrp = NULL;
3621		} else {
3622			if (xattrbadhead == 0) {
3623				(void) read_xattr_hdr();
3624				return (2);
3625			}
3626		}
3627	}
3628#endif /* O_XATTR */
3629
3630	/* acl support: grab acl info */
3631	if ((Gen.g_mode == SECMODE) || ((Hdr_type == USTAR ||
3632	    Hdr_type == TAR) && Thdr_p->tbuf.t_typeflag == 'A')) {
3633		/* this is an ancillary file */
3634		off_t	bytes;
3635		char	*secp;
3636		int	pad;
3637		int	cnt;
3638		char	*tp;
3639		int	attrsize;
3640
3641		if (Pflag) {
3642			bytes = Gen.g_filesz;
3643			secp = e_zalloc(E_EXIT, (uint_t)bytes);
3644			tp = secp;
3645
3646			while (bytes > 0) {
3647				cnt = (int)(bytes > CPIOBSZ) ? CPIOBSZ : bytes;
3648				FILL(cnt);
3649				(void) memcpy(tp, Buffr.b_out_p, cnt);
3650				tp += cnt;
3651				Buffr.b_out_p += cnt;
3652				Buffr.b_cnt -= (off_t)cnt;
3653				bytes -= (off_t)cnt;
3654			}
3655
3656			pad = (Pad_val + 1 - (Gen.g_filesz & Pad_val)) &
3657			    Pad_val;
3658			if (pad != 0) {
3659				FILL(pad);
3660				Buffr.b_out_p += pad;
3661				Buffr.b_cnt -= (off_t)pad;
3662			}
3663
3664			/* got all attributes in secp */
3665			tp = secp;
3666			do {
3667				attr = (struct sec_attr *)tp;
3668				switch (attr->attr_type) {
3669				case UFSD_ACL:
3670				case ACE_ACL:
3671					(void) sscanf(attr->attr_len, "%7lo",
3672					    (ulong_t *)&aclcnt);
3673					/* header is 8 */
3674					attrsize = 8 +
3675					    strlen(&attr->attr_info[0])
3676					    + 1;
3677
3678					error =
3679					    acl_fromtext(&attr->attr_info[0],
3680					    &aclp);
3681
3682					if (error != 0) {
3683						msg(ERR,
3684						    "aclfromtext failed: %s",
3685						    acl_strerror(error));
3686						bytes -= attrsize;
3687						break;
3688					}
3689
3690					if (aclcnt != acl_cnt(aclp)) {
3691						msg(ERR, "acl count error");
3692						bytes -= attrsize;
3693						break;
3694					}
3695					bytes -= attrsize;
3696					break;
3697
3698				/* SunFed case goes here */
3699
3700				default:
3701					msg(EXT, "unrecognized attr type");
3702					break;
3703			}
3704			/* next attributes */
3705			tp += attrsize;
3706			} while (bytes > 0);
3707			free(secp);
3708		} else {
3709			/* skip security info */
3710			G_p = &Gen;
3711			data_in(P_SKIP);
3712		}
3713		/*
3714		 * We already got the file content, dont call file_in()
3715		 * when return. The new return code(2) is used to
3716		 *  indicate that.
3717		 */
3718		VERBOSE((Args & OCt), Gen.g_nam_p);
3719		return (2);
3720	} /* acl */
3721
3722	Adir = (ftype == S_IFDIR);
3723	Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO);
3724
3725	/*
3726	 * Skip any trailing slashes
3727	 */
3728	chop_endslashes(Gen.g_nam_p);
3729	return (1);
3730}
3731
3732/*
3733 * getname: Get file names for inclusion in the archive.  When end of file
3734 * on the input stream of file names is reached, flush the link buffer out.
3735 * For each filename, remove leading "./"s and multiple "/"s, and remove
3736 * any trailing newline "\n".  Finally, verify the existance of the file,
3737 * and call creat_hdr() to fill in the gen_hdr structure.
3738 */
3739
3740static int
3741getname(void)
3742{
3743	int goodfile = 0, lastchar, err;
3744	char *s;
3745	char *dir;
3746
3747	Gen.g_nam_p = Nam_p;
3748
3749	while (!goodfile) {
3750		err = 0;
3751
3752		while ((s = fgets(Gen.g_nam_p, APATH+1, In_p))
3753		    != NULL) {
3754			lastchar = strlen(s) - 1;
3755			issymlink = 0;
3756
3757			if (s[lastchar] != '\n') {
3758				if (lastchar == APATH - 1) {
3759					if (!err) {
3760						msg(ERR,
3761						    "%s name too long.",
3762						    Nam_p);
3763					}
3764					goodfile = 0;
3765					err = 1;
3766				} else {
3767					break;
3768				}
3769			} else {
3770				s[lastchar] = '\0';
3771				break;
3772			}
3773		}
3774
3775		if (s == (char *)NULL) {
3776			if (Gen.g_dirfd != -1) {
3777				(void) close(Gen.g_dirfd);
3778				Gen.g_dirfd = -1;
3779			}
3780			if (Onecopy && (Args & OCo)) {
3781				flush_lnks();
3782			}
3783			return (0);
3784		}
3785
3786		while (*Gen.g_nam_p == '.' && Gen.g_nam_p[1] == '/') {
3787			Gen.g_nam_p += 2;
3788			while (*Gen.g_nam_p == '/')
3789				Gen.g_nam_p++;
3790		}
3791
3792		/*
3793		 * Skip any trailing slashes
3794		 */
3795		chop_endslashes(Gen.g_nam_p);
3796
3797		/*
3798		 * Figure out parent directory
3799		 */
3800
3801		if (Gen.g_attrnam_p != (char *)NULL) {
3802			if (Gen.g_dirfd != -1) {
3803				(void) close(Gen.g_dirfd);
3804			}
3805			Gen.g_dirfd = attropen(Gen.g_attrfnam_p, ".", O_RDONLY);
3806			if (Gen.g_dirfd == -1) {
3807				msg(ERRN,
3808				    "Cannot open attribute directory"
3809				    " of file %s", Gen.g_attrfnam_p);
3810				continue;
3811			}
3812		} else {
3813#ifdef O_XATTR
3814			char dirpath[PATH_MAX];
3815
3816			get_parent(Gen.g_nam_p, dirpath);
3817			if (Atflag) {
3818				dir = dirpath;
3819				if (Gen.g_dirfd != -1) {
3820					(void) close(Gen.g_dirfd);
3821				}
3822				Gen.g_dirfd = open(dir, O_RDONLY);
3823				if (Gen.g_dirfd == -1) {
3824					msg(ERRN,
3825					    "Cannot open directory %s", dir);
3826					continue;
3827				}
3828			} else {
3829				/*
3830				 * g_dirpath is the pathname cache maintaining
3831				 * the dirname which is currently opened.
3832				 * We first check the g_dirpath to see if the
3833				 * given dirname matches. If so, we don't need
3834				 * to open the dir, but we can use the g_dirfd
3835				 * as is if it is still available.
3836				 */
3837				dir = NULL;
3838				if (Gen.g_dirpath == NULL ||
3839				    Gen.g_dirfd == -1) {
3840					/*
3841					 * It's the first time or it has
3842					 * all gone.
3843					 */
3844					dir = e_strdup(E_EXIT, dirpath);
3845				} else {
3846					if (strcmp(Gen.g_dirpath,
3847					    dirpath) != 0) {
3848						/* different directory */
3849						dir = e_strdup(E_EXIT, dirpath);
3850					}
3851				}
3852				if (dir != NULL) {
3853					/*
3854					 * We need to open the new directory.
3855					 * discard the pathname and dirfd
3856					 * for the previous directory.
3857					 */
3858					if (Gen.g_dirpath != NULL) {
3859						free(Gen.g_dirpath);
3860						Gen.g_dirpath = NULL;
3861					}
3862					if (Gen.g_dirfd != -1) {
3863						(void) close(Gen.g_dirfd);
3864					}
3865					/* open the new dir */
3866					Gen.g_dirfd = open(dir, O_RDONLY);
3867					if (Gen.g_dirfd == -1) {
3868						msg(ERRN, "Cannot open "
3869						    "directory %s", dir);
3870						continue;
3871					}
3872					Gen.g_dirpath = dir;
3873				}
3874			}
3875#else
3876			Gen.g_dirfd = -1;
3877#endif
3878		}
3879
3880		/* creat_hdr checks for USTAR filename length */
3881
3882		if (Hdr_type != USTAR && strlen(Gen.g_nam_p) >
3883		    Max_namesz) {
3884			if (!err) {
3885				msg(ERR, "%s%s%s name too long.",
3886				    (Gen.g_attrnam_p == (char *)NULL) ?
3887				    Nam_p : Gen.g_attrfnam_p,
3888				    (Gen.g_attrnam_p == (char *)NULL) ?
3889				    "" : gettext(" Attribute "),
3890				    (Gen.g_attrnam_p == (char *)NULL) ?
3891				    "" : Gen.g_attrnam_p);
3892			}
3893			goodfile = 0;
3894			err = 1;
3895		}
3896
3897		if (err) {
3898			continue;
3899		} else {
3900			G_p = &Gen;
3901			if (!LSTAT(Gen.g_dirfd, Gen.g_nam_p, &SrcSt)) {
3902				goodfile = 1;
3903
3904				if ((SrcSt.st_mode & Ftype) == S_IFLNK) {
3905					issymlink = 1;
3906
3907					if ((Args & OCL)) {
3908						errno = 0;
3909						if (STAT(Gen.g_dirfd,
3910						    G_p->g_nam_p,
3911						    &SrcSt) < 0) {
3912							msg(ERRN,
3913							    "Cannot follow"
3914							    " \"%s%s%s\"",
3915							    (Gen.g_attrnam_p ==
3916							    (char *)NULL) ?
3917							    Gen.g_nam_p :
3918							    Gen.g_attrfnam_p,
3919							    (Gen.g_attrnam_p ==
3920							    (char *)NULL) ?
3921							    "" :
3922							    gettext(
3923							    " Attribute "),
3924							    (Gen.g_attrnam_p ==
3925							    (char *)NULL) ?
3926							    "" :
3927							    Gen.g_attrnam_p);
3928							goodfile = 0;
3929						}
3930					}
3931				}
3932
3933				if (Use_old_stat) {
3934					OldSt = convert_to_old_stat(&SrcSt,
3935					    Gen.g_nam_p, Gen.g_attrnam_p);
3936
3937					if (OldSt == NULL) {
3938						goodfile = 0;
3939					}
3940				}
3941			} else {
3942				msg(ERRN,
3943				    "Error with fstatat() of \"%s%s%s\"",
3944				    (Gen.g_attrnam_p == (char *)NULL) ?
3945				    Gen.g_nam_p : Gen.g_attrfnam_p,
3946				    (Gen.g_attrnam_p == (char *)NULL) ?
3947				    "" : gettext(" Attribute "),
3948				    (Gen.g_attrnam_p == (char *)NULL) ?
3949				    "" : Gen.g_attrnam_p);
3950			}
3951		}
3952	}
3953
3954	/*
3955	 * Get ACL info: dont bother allocating space if there are only
3956	 * standard permissions, i.e. ACL count < 4
3957	 */
3958	if ((SrcSt.st_mode & Ftype) != S_IFLNK && Pflag) {
3959		if (acl_get(Gen.g_nam_p, ACL_NO_TRIVIAL, &aclp) != 0)
3960			msg(ERRN, "Error with acl() of \"%s\"", Gen.g_nam_p);
3961	}
3962	/* else: only traditional permissions, so proceed as usual */
3963	if (creat_hdr())
3964		return (1);
3965	else return (2);
3966}
3967
3968/*
3969 * getpats: Save any filenames/patterns specified as arguments.
3970 * Read additional filenames/patterns from the file specified by the
3971 * user.  The filenames/patterns must occur one per line.
3972 */
3973
3974static void
3975getpats(int largc, char **largv)
3976{
3977	char **t_pp;
3978	size_t len;
3979	unsigned numpat = largc, maxpat = largc + 2;
3980
3981	Pat_pp = e_zalloc(E_EXIT, maxpat * sizeof (char *));
3982	t_pp = Pat_pp;
3983	while (*largv) {
3984		*t_pp = e_zalloc(E_EXIT, strlen(*largv) + 1);
3985		(void) strcpy(*t_pp, *largv);
3986		t_pp++;
3987		largv++;
3988	}
3989	while (fgets(Nam_p, Max_namesz + 1, Ef_p) != (char *)NULL) {
3990		if (numpat == maxpat - 1) {
3991			maxpat += 10;
3992			Pat_pp = e_realloc(E_EXIT, Pat_pp,
3993			    maxpat * sizeof (char *));
3994			t_pp = Pat_pp + numpat;
3995		}
3996		len = strlen(Nam_p); /* includes the \n */
3997		*(Nam_p + len - 1) = '\0'; /* remove the \n */
3998		*t_pp = e_zalloc(E_EXIT, len);
3999		(void) strcpy(*t_pp, Nam_p);
4000		t_pp++;
4001		numpat++;
4002	}
4003	*t_pp = (char *)NULL;
4004}
4005
4006static void
4007ioerror(int dir)
4008{
4009	int t_errno;
4010
4011	t_errno = errno;
4012	errno = 0;
4013	if (fstat(Archive, &ArchSt) < 0)
4014		msg(EXTN, "Error during stat() of archive");
4015	errno = t_errno;
4016	if ((ArchSt.st_mode & Ftype) != S_IFCHR) {
4017		if (dir) {
4018			if (errno == EFBIG)
4019				msg(EXT, "ulimit reached for output file.");
4020			else if (errno == ENOSPC)
4021				msg(EXT, "No space left for output file.");
4022			else
4023				msg(EXTN, "I/O error - cannot continue");
4024		} else
4025			msg(EXT, "Unexpected end-of-file encountered.");
4026	} else
4027		msg(EXTN, "\007I/O error on \"%s\"", dir ? "output" : "input");
4028}
4029
4030/*
4031 * matched: Determine if a filename matches the specified pattern(s).  If the
4032 * pattern is matched (the second return), return 0 if -f was specified, else
4033 * return != 0.  If the pattern is not matched (the first and third
4034 * returns), return 0 if -f was not specified, else return != 0.
4035 */
4036
4037static int
4038matched(void)
4039{
4040	char *str_p = G_p->g_nam_p;
4041	char **pat_pp = Pat_pp;
4042	int negatep, result;
4043
4044	/*
4045	 * Check for attribute
4046	 */
4047	if (G_p->g_attrfnam_p != (char *)NULL)
4048		str_p = G_p->g_attrfnam_p;
4049
4050	for (pat_pp = Pat_pp; *pat_pp; pat_pp++) {
4051		negatep = (**pat_pp == '!');
4052
4053		result = fnmatch(negatep ? (*pat_pp+1) : *pat_pp, str_p, 0);
4054
4055		if (result != 0 && result != FNM_NOMATCH) {
4056			msg(POST, "error matching file %s with pattern"
4057			    " %s\n", str_p, *pat_pp);
4058			return (Args & OCf);
4059		}
4060
4061		if ((result == 0 && ! negatep) ||
4062		    (result == FNM_NOMATCH && negatep)) {
4063			/* match occured */
4064			return (!(Args & OCf));
4065		}
4066	}
4067	return (Args & OCf); /* not matched */
4068}
4069
4070/*
4071 * missdir: Create missing directories for files.
4072 * (Possible future performance enhancement, if missdir is called, we know
4073 * that at least the very last directory of the path does not exist, therefore,
4074 * scan the path from the end
4075 */
4076
4077static int
4078missdir(char *nam_p)
4079{
4080	char *c_p;
4081	int cnt = 2;
4082	char *lastp;
4083
4084	if (*(c_p = nam_p) == '/') /* skip over 'root slash' */
4085		c_p++;
4086
4087	lastp = c_p + strlen(nam_p) - 1;
4088	if (*lastp == '/')
4089		*lastp = '\0';
4090
4091	for (; *c_p; ++c_p) {
4092		if (*c_p == '/') {
4093			*c_p = '\0';
4094			if (stat(nam_p, &DesSt) < 0) {
4095				if (Args & OCd) {
4096					cnt = mkdir(nam_p, Def_mode);
4097					if (cnt != 0) {
4098						*c_p = '/';
4099						return (cnt);
4100					}
4101				} else {
4102					msg(ERR, "Missing -d option.");
4103					*c_p = '/';
4104					return (-1);
4105				}
4106			}
4107			*c_p = '/';
4108		}
4109	}
4110	if (cnt == 2) /* the file already exists */
4111		cnt = 0;
4112	return (cnt);
4113}
4114
4115/*
4116 * mklong: Convert two shorts into one long.  For VAX, Interdata ...
4117 */
4118
4119static long
4120mklong(short v[])
4121{
4122
4123	union swpbuf swp_b;
4124
4125	swp_b.s_word = 1;
4126	if (swp_b.s_byte[0]) {
4127		swp_b.s_half[0] = v[1];
4128		swp_b.s_half[1] = v[0];
4129	} else {
4130		swp_b.s_half[0] = v[0];
4131		swp_b.s_half[1] = v[1];
4132	}
4133	return (swp_b.s_word);
4134}
4135
4136/*
4137 * mkshort: Convert a long into 2 shorts, for VAX, Interdata ...
4138 */
4139
4140static void
4141mkshort(short sval[], long v)
4142{
4143	union swpbuf *swp_p, swp_b;
4144
4145	/* LINTED alignment */
4146	swp_p = (union swpbuf *)sval;
4147	swp_b.s_word = 1;
4148	if (swp_b.s_byte[0]) {
4149		swp_b.s_word = v;
4150		swp_p->s_half[0] = swp_b.s_half[1];
4151		swp_p->s_half[1] = swp_b.s_half[0];
4152	} else {
4153		swp_b.s_word = v;
4154		swp_p->s_half[0] = swp_b.s_half[0];
4155		swp_p->s_half[1] = swp_b.s_half[1];
4156	}
4157}
4158
4159/*
4160 * msg: Print either a message (no error) (POST), an error message with or
4161 * without the errno (ERRN or ERR), or print an error message with or without
4162 * the errno and exit (EXTN or EXT).
4163 */
4164
4165static void
4166msg(int severity, const char *fmt, ...)
4167{
4168	FILE *file_p;
4169	va_list ap;
4170
4171	if ((Args & OCV) && Verbcnt) { /* clear current line of dots */
4172		(void) fputc('\n', Out_p);
4173		Verbcnt = 0;
4174	}
4175	va_start(ap, fmt);
4176	if (severity == POST)
4177		file_p = Out_p;
4178	else
4179		if (severity == EPOST)
4180			file_p = Err_p;
4181		else {
4182			file_p = Err_p;
4183			Error_cnt++;
4184		}
4185	(void) fflush(Out_p);
4186	(void) fflush(Err_p);
4187	if ((severity != POST) && (severity != EPOST))
4188		(void) fprintf(file_p, "cpio: ");
4189
4190	/* gettext replaces version of string */
4191
4192	(void) vfprintf(file_p, gettext(fmt), ap);
4193	if (severity == ERRN || severity == EXTN) {
4194		(void) fprintf(file_p, ", errno %d, ", errno);
4195		perror("");
4196	} else
4197		(void) fprintf(file_p, "\n");
4198	(void) fflush(file_p);
4199	va_end(ap);
4200	if (severity == EXT || severity == EXTN) {
4201		(void) fprintf(file_p, gettext("%d errors\n"), Error_cnt);
4202		exit(EXIT_CODE);
4203	}
4204}
4205
4206/*
4207 * openout: Open files for output and set all necessary information.
4208 * If the u option is set (unconditionally overwrite existing files),
4209 * and the current file exists, get a temporary file name from mktemp(3C),
4210 * link the temporary file to the existing file, and remove the existing file.
4211 * Finally either creat(2), mkdir(2) or mknod(2) as appropriate.
4212 *
4213 */
4214
4215static int
4216openout(int dirfd)
4217{
4218	char *nam_p;
4219	int cnt, result;
4220
4221	Do_rename = 0;	/* creat_tmp() may reset this */
4222
4223	if (G_p->g_attrnam_p != (char *)NULL) {
4224		nam_p = G_p->g_attrnam_p;
4225	} else {
4226		if (Args & OCp) {
4227			nam_p = Fullnam_p;
4228		} else {
4229			nam_p = G_p->g_nam_p;
4230		}
4231	}
4232
4233
4234	if ((Max_filesz != RLIM_INFINITY) &&
4235	    (Max_filesz < (G_p->g_filesz >> 9))) {
4236		/* ... divided by 512 ... */
4237		msg(ERR, "Skipping \"%s%s%s\": exceeds ulimit by %lld bytes",
4238		    (G_p->g_attrnam_p == (char *)NULL) ?
4239		    nam_p : G_p->g_attrfnam_p,
4240		    (G_p->g_attrnam_p == (char *)NULL) ?
4241		    "" : gettext(" Attribute "),
4242		    (G_p->g_attrnam_p == (char *)NULL) ?
4243		    "" : nam_p,
4244		    (off_t)(G_p->g_filesz - (Max_filesz << 9)));
4245		return (-1);
4246	}
4247
4248	if (LSTAT(dirfd, nam_p, &DesSt) == 0) {
4249		/*
4250		 * A file by the same name exists.  Move it to a temporary
4251		 * file.
4252		 */
4253
4254		if (creat_tmp(nam_p) < 0) {
4255			/*
4256			 * We weren't able to create the temp file.  Report
4257			 * failure.
4258			 */
4259
4260			return (-1);
4261		}
4262	}
4263
4264	if (Do_rename) {
4265		/* nam_p was changed by creat_tmp() above. */
4266
4267		if (Args & OCp) {
4268			if (G_p->g_attrnam_p != (char *)NULL) {
4269				nam_p = Attrfile_p;
4270			} else {
4271				nam_p = Fullnam_p;
4272			}
4273		} else {
4274			nam_p = G_p->g_nam_p;
4275		}
4276	}
4277
4278	/*
4279	 * This pile tries to create the file directly, and, if there is a
4280	 * problem, creates missing directories, and then tries to create the
4281	 * file again.  Two strikes and you're out.
4282	 *
4283	 * On XATTR system, the directory has already been created by
4284	 * open_dirfd(), so error shouldn't happen in the loop. However,
4285	 * on non-XATTR system, symlink/open may fail with ENOENT. In such
4286	 * case, we go to create missing directories.
4287	 */
4288
4289	cnt = 0;
4290
4291	do {
4292		errno = 0;
4293
4294		if (Hdr_type == TAR && Thdr_p->tbuf.t_typeflag == SYMTYPE) {
4295			/* The archive file is a TAR symlink. */
4296			if ((result =
4297			    symlink(Thdr_p->tbuf.t_linkname, nam_p)) >= 0) {
4298				cnt = 0;
4299				if (Over_p != NULL) {
4300					(void) unlinkat(dirfd,
4301					    get_component(Over_p), 0);
4302					*Over_p = '\0';
4303				}
4304				break;
4305			} else if (errno != ENOENT) {
4306				/* The attempt to symlink failed. */
4307				msg(ERRN,
4308				    "Cannot create symbolic link \"%s\" -> "
4309				    "\"%s\"",
4310				    Thdr_p->tbuf.t_linkname, nam_p);
4311
4312				if (*Over_p != '\0') {
4313					rstfiles(U_KEEP, dirfd);
4314				}
4315				return (-1);
4316			}
4317		} else if (Hdr_type == BAR && bar_linkflag == SYMTYPE) {
4318			if ((result = symlink(bar_linkname, nam_p)) >= 0) {
4319				cnt = 0;
4320				if (Over_p != NULL) {
4321					(void) unlinkat(dirfd,
4322					    get_component(Over_p), 0);
4323					*Over_p = '\0';
4324				}
4325				break;
4326			} else if (errno != ENOENT) {
4327				/* The attempt to symlink failed. */
4328				msg(ERRN,
4329				    "Cannot create symbolic link \"%s\" -> "
4330				    "\"%s\"",
4331				    bar_linkname, nam_p);
4332				if (*Over_p != '\0') {
4333					rstfiles(U_KEEP, dirfd);
4334				}
4335				return (-1);
4336			}
4337		} else if ((G_p->g_mode & Ftype) == S_IFLNK) {
4338			if ((!(Args & OCp)) && !(Hdr_type == USTAR)) {
4339				(void) strncpy(Symlnk_p,
4340				    Buffr.b_out_p, G_p->g_filesz);
4341				*(Symlnk_p + G_p->g_filesz) = '\0';
4342			} else if ((!(Args & OCp)) && (Hdr_type == USTAR)) {
4343				Symlnk_p[NAMSIZ] = '\0';
4344				(void) strncpy(Symlnk_p,
4345				    &Thdr_p->tbuf.t_linkname[0], NAMSIZ);
4346			}
4347			if ((result = symlink(Symlnk_p, nam_p)) >= 0) {
4348				cnt = 0;
4349				if (Over_p != NULL) {
4350					(void) unlinkat(dirfd,
4351					    get_component(Over_p), 0);
4352					*Over_p = '\0';
4353				}
4354				break;
4355			} else if (errno != ENOENT) {
4356				/* The attempt to symlink failed. */
4357				msg(ERRN,
4358				    "Cannot create symbolic link \"%s\" -> "
4359				    "\"%s\"",
4360				    Symlnk_p, nam_p);
4361
4362				if (*Over_p != '\0') {
4363					rstfiles(U_KEEP, dirfd);
4364				}
4365				return (-1);
4366			}
4367		} else {
4368			if ((result = openat(dirfd, get_component(nam_p),
4369			    O_CREAT|O_RDWR|O_TRUNC, (int)G_p->g_mode)) >= 0) {
4370				/* acl support */
4371				acl_is_set = 0;
4372				if (Pflag && aclp != NULL) {
4373					if (facl_set(result, aclp) < 0) {
4374						msg(ERRN,
4375						    "\"%s\": failed to set acl",
4376						    nam_p);
4377					} else {
4378						acl_is_set = 1;
4379					}
4380					acl_free(aclp);
4381					aclp = NULL;
4382				}
4383				cnt = 0;
4384				break;
4385			} else if (errno != ENOENT) {
4386				/* The attempt to open failed. */
4387				msg(ERRN, "Cannot open file \"%s\"", nam_p);
4388				if (*Over_p != '\0') {
4389					rstfiles(U_KEEP, dirfd);
4390				}
4391				return (-1);
4392			}
4393		}
4394		cnt++;
4395	} while (cnt < 2 && missdir(nam_p) == 0);
4396
4397	switch (cnt) {
4398	case 0:
4399		if ((Args & OCi) && (Hdr_type == USTAR)) {
4400			setpasswd(nam_p);
4401		}
4402		if ((G_p->g_mode & Ftype) == S_IFLNK ||
4403		    (Hdr_type == BAR && bar_linkflag == SYMTYPE)) {
4404			if (Args & OCR) {
4405				if (fchownat(dirfd,
4406				    get_component(nam_p),
4407				    (int)Rpw_p->pw_uid,
4408				    (int)Rpw_p->pw_gid,
4409				    AT_SYMLINK_NOFOLLOW) < 0) {
4410					msg(ERRN,
4411					    "Error during chown() of "
4412					    "\"%s%s%s\"",
4413					    (G_p->g_attrnam_p ==
4414					    (char *)NULL) ?
4415					    nam_p : G_p->g_attrfnam_p,
4416					    (G_p->g_attrnam_p ==
4417					    (char *)NULL) ?
4418					    "" : gettext(" Attribute "),
4419					    (G_p->g_attrnam_p ==
4420					    (char *)NULL) ?
4421					    "" : nam_p);
4422				}
4423			} else if ((fchownat(dirfd, get_component(nam_p),
4424			    (int)G_p->g_uid, (int)G_p->g_gid,
4425			    AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
4426				msg(ERRN,
4427				    "Error during chown() of \"%s%s%s\"",
4428				    (G_p->g_attrnam_p == (char *)NULL) ?
4429				    nam_p : G_p->g_attrfnam_p,
4430				    (G_p->g_attrnam_p == (char *)NULL) ?
4431				    "" : gettext(" Attribute "),
4432				    (G_p->g_attrnam_p == (char *)NULL) ?
4433				    "" : nam_p);
4434			}
4435		}
4436		break;
4437
4438	case 1:
4439		if (Do_rename) {
4440			msg(ERRN, "Cannot create directory for \"%s%s%s\"",
4441			    (G_p->g_attrnam_p == (char *)NULL) ? Over_p :
4442			    G_p->g_attrfnam_p,
4443			    (G_p->g_attrnam_p == (char *)NULL) ? "" :
4444			    gettext(" Attribute "),
4445			    (G_p->g_attrnam_p == (char *)NULL) ? "" : Over_p);
4446		} else {
4447			msg(ERRN, "Cannot create directory for \"%s%s%s\"",
4448			    (G_p->g_attrnam_p == (char *)NULL) ? nam_p :
4449			    G_p->g_attrfnam_p,
4450			    (G_p->g_attrnam_p == (char *)NULL) ? "" :
4451			    gettext(" Attribute "),
4452			    (G_p->g_attrnam_p == (char *)NULL) ? "" : nam_p);
4453		}
4454		break;
4455
4456	case 2:
4457		if (Do_rename) {
4458			msg(ERRN, "Cannot create \"%s%s%s\"",
4459			    (G_p->g_attrnam_p == (char *)NULL) ? Over_p :
4460			    G_p->g_attrfnam_p,
4461			    (G_p->g_attrnam_p == (char *)NULL) ? "" :
4462			    gettext(" Attribute "),
4463			    (G_p->g_attrnam_p == (char *)NULL) ? "" :
4464			    Over_p);
4465		} else {
4466			msg(ERRN, "Cannot create \"%s%s%s\"",
4467			    (G_p->g_attrnam_p == (char *)NULL) ? nam_p :
4468			    G_p->g_attrfnam_p,
4469			    (G_p->g_attrnam_p == (char *)NULL) ? "" :
4470			    gettext(" Attribute "),
4471			    (G_p->g_attrnam_p == (char *)NULL) ? "" :
4472			    nam_p);
4473		}
4474		break;
4475
4476	default:
4477		msg(EXT, "Impossible case.");
4478	}
4479
4480	Finished = 0;
4481	return (result);
4482}
4483
4484/*
4485 * read_hdr: Transfer headers from the selected format
4486 * in the archive I/O buffer to the generic structure.
4487 */
4488
4489static
4490int
4491read_hdr(int hdr)
4492{
4493	int rv = NONE;
4494	major_t maj, rmaj;
4495	minor_t min, rmin;
4496	char tmpnull;
4497	static int bar_read_cnt = 0;
4498
4499	if (hdr != BAR) {
4500		if (Buffr.b_end_p != (Buffr.b_out_p + Hdrsz)) {
4501			tmpnull = *(Buffr.b_out_p + Hdrsz);
4502			*(Buffr.b_out_p + Hdrsz) = '\0';
4503		}
4504	}
4505
4506	switch (hdr) {
4507	case BIN:
4508		(void) memcpy(&Hdr, Buffr.b_out_p, HDRSZ);
4509		if (Hdr.h_magic == (short)CMN_BBS) {
4510			swap((char *)&Hdr, HDRSZ);
4511		}
4512		Gen.g_magic = Hdr.h_magic;
4513		Gen.g_mode = Hdr.h_mode;
4514		Gen.g_uid = Hdr.h_uid;
4515		Gen.g_gid = Hdr.h_gid;
4516		Gen.g_nlink = Hdr.h_nlink;
4517		Gen.g_mtime = mklong(Hdr.h_mtime);
4518		Gen.g_ino = Hdr.h_ino;
4519		Gen.g_dev = Hdr.h_dev;
4520		Gen.g_rdev = Hdr.h_rdev;
4521		Gen.g_cksum = 0L;
4522		Gen.g_filesz = (off_t)mklong(Hdr.h_filesize);
4523		Gen.g_namesz = Hdr.h_namesize;
4524		rv = BIN;
4525		break;
4526	case CHR:
4527		if (sscanf(Buffr.b_out_p,
4528		    "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6o%11llo",
4529		    &Gen.g_magic, &Gen.g_dev, &Gen.g_ino, &Gen.g_mode,
4530		    &Gen.g_uid, &Gen.g_gid, &Gen.g_nlink, &Gen.g_rdev,
4531		    (ulong_t *)&Gen.g_mtime, (uint_t *)&Gen.g_namesz,
4532		    (u_off_t *)&Gen.g_filesz) == CHR_CNT) {
4533			rv = CHR;
4534#define	cpioMAJOR(x)	(int)(((unsigned)x >> 8) & 0x7F)
4535#define	cpioMINOR(x)	(int)(x & 0xFF)
4536			maj = cpioMAJOR(Gen.g_dev);
4537			rmaj = cpioMAJOR(Gen.g_rdev);
4538			min = cpioMINOR(Gen.g_dev);
4539			rmin = cpioMINOR(Gen.g_rdev);
4540			if (Use_old_stat) {
4541				/* needs error checking */
4542				Gen.g_dev = (maj << 8) | min;
4543				Gen.g_rdev = (rmaj << 8) | rmin;
4544			} else {
4545				Gen.g_dev = makedev(maj, min);
4546				Gen.g_rdev = makedev(rmaj, rmin);
4547			}
4548		}
4549		break;
4550	case ASC:
4551	case CRC:
4552		if (sscanf(Buffr.b_out_p,
4553		    "%6lx%8lx%8lx%8lx%8lx%8lx%8lx%8llx%8x%8x%8x%8x%8x%8lx",
4554		    &Gen.g_magic, &Gen.g_ino, &Gen.g_mode, &Gen.g_uid,
4555		    &Gen.g_gid, &Gen.g_nlink, &Gen.g_mtime,
4556		    (u_off_t *)&Gen.g_filesz, (uint_t *)&maj, (uint_t *)&min,
4557		    (uint_t *)&rmaj, (uint_t *)&rmin, (uint_t *)&Gen.g_namesz,
4558		    &Gen.g_cksum) == ASC_CNT) {
4559			Gen.g_dev = makedev(maj, min);
4560			Gen.g_rdev = makedev(rmaj, rmin);
4561			rv = hdr;
4562		}
4563		break;
4564	case USTAR: /* TAR and USTAR */
4565		if (*Buffr.b_out_p == '\0') {
4566			*Gen.g_nam_p = '\0';
4567			nambuf[0] = '\0';
4568		} else {
4569			Thdr_p = (union tblock *)Buffr.b_out_p;
4570			Gen.g_nam_p[0] = '\0';
4571			(void) strncpy((char *)&nambuf,
4572			    Thdr_p->tbuf.t_name, NAMSIZ);
4573			(void) sscanf(Thdr_p->tbuf.t_mode, "%8lo",
4574			    &Gen.g_mode);
4575			(void) sscanf(Thdr_p->tbuf.t_uid, "%8lo", &Gen.g_uid);
4576			(void) sscanf(Thdr_p->tbuf.t_gid, "%8lo", &Gen.g_gid);
4577			(void) sscanf(Thdr_p->tbuf.t_size, "%11llo",
4578			    (u_off_t *)&Gen.g_filesz);
4579			(void) sscanf(Thdr_p->tbuf.t_mtime, "%12lo",
4580			    (ulong_t *)&Gen.g_mtime);
4581			(void) sscanf(Thdr_p->tbuf.t_cksum, "%8lo",
4582			    (ulong_t *)&Gen.g_cksum);
4583			if (Thdr_p->tbuf.t_linkname[0] != (char)NULL)
4584				Gen.g_nlink = 1;
4585			else
4586				Gen.g_nlink = 0;
4587
4588			switch (Thdr_p->tbuf.t_typeflag) {
4589			case SYMTYPE:
4590				/* Symbolic Link */
4591				Gen.g_nlink = 2;
4592				break;
4593			case CHRTYPE:
4594				Gen.g_mode |= (S_IFMT & S_IFCHR);
4595				break;
4596			case BLKTYPE:
4597				Gen.g_mode |= (S_IFMT & S_IFBLK);
4598				break;
4599			case DIRTYPE:
4600				Gen.g_mode |= (S_IFMT & S_IFDIR);
4601				break;
4602			case FIFOTYPE:
4603				Gen.g_mode |= (S_IFMT & S_IFIFO);
4604				break;
4605			}
4606
4607			(void) sscanf(Thdr_p->tbuf.t_magic, "%8lo",
4608			    /* LINTED alignment */
4609			    (ulong_t *)&Gen.g_tmagic);
4610			(void) sscanf(Thdr_p->tbuf.t_version, "%8lo",
4611			    /* LINTED alignment */
4612			    (ulong_t *)&Gen.g_version);
4613			(void) sscanf(Thdr_p->tbuf.t_uname, "%32s",
4614			    (char *)&Gen.g_uname);
4615			(void) sscanf(Thdr_p->tbuf.t_gname, "%32s",
4616			    (char *)&Gen.g_gname);
4617			(void) sscanf(Thdr_p->tbuf.t_devmajor, "%8lo",
4618			    &Gen.g_dev);
4619			(void) sscanf(Thdr_p->tbuf.t_devminor, "%8lo",
4620			    &Gen.g_rdev);
4621			(void) strncpy((char *)&prebuf,
4622			    Thdr_p->tbuf.t_prefix, PRESIZ);
4623			Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
4624			Gen.g_dev = makedev(maj, min);
4625		}
4626		rv = USTAR;
4627		break;
4628	case TAR:
4629		if (*Buffr.b_out_p == '\0') {
4630			*Gen.g_nam_p = '\0';
4631			nambuf[0] = '\0';
4632		} else {
4633			Thdr_p = (union tblock *)Buffr.b_out_p;
4634			Gen.g_nam_p[0] = '\0';
4635			(void) sscanf(Thdr_p->tbuf.t_mode, "%lo", &Gen.g_mode);
4636			(void) sscanf(Thdr_p->tbuf.t_uid, "%lo", &Gen.g_uid);
4637			(void) sscanf(Thdr_p->tbuf.t_gid, "%lo", &Gen.g_gid);
4638			(void) sscanf(Thdr_p->tbuf.t_size, "%llo",
4639			    (u_off_t *)&Gen.g_filesz);
4640			(void) sscanf(Thdr_p->tbuf.t_mtime, "%lo",
4641			    &Gen.g_mtime);
4642			(void) sscanf(Thdr_p->tbuf.t_cksum, "%lo",
4643			    &Gen.g_cksum);
4644			if (Thdr_p->tbuf.t_typeflag == '1')	/* hardlink */
4645				Gen.g_nlink = 1;
4646			else
4647				Gen.g_nlink = 0;
4648			(void) strncpy(Gen.g_nam_p,
4649			    Thdr_p->tbuf.t_name, NAMSIZ);
4650			Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
4651			(void) strcpy(nambuf, Gen.g_nam_p);
4652		}
4653		rv = TAR;
4654		break;
4655	case BAR:
4656		if (Bar_vol_num == 0 && bar_read_cnt == 0) {
4657			read_bar_vol_hdr();
4658			bar_read_cnt++;
4659		}
4660		else
4661			read_bar_file_hdr();
4662		rv = BAR;
4663		break;
4664	default:
4665		msg(EXT, "Impossible header type.");
4666	}
4667
4668	if (hdr != BAR) {
4669		if (Buffr.b_end_p != (Buffr.b_out_p + Hdrsz))
4670			*(Buffr.b_out_p + Hdrsz) = tmpnull;
4671	}
4672
4673	return (rv);
4674}
4675
4676/*
4677 * reclaim: Reclaim linked file structure storage.
4678 */
4679
4680static void
4681reclaim(struct Lnk *p)
4682{
4683	p->L_bck_p->L_nxt_p = p->L_nxt_p;
4684	p->L_nxt_p->L_bck_p = p->L_bck_p;
4685
4686	while (p != NULL) {
4687		struct Lnk *new_p = p->L_lnk_p;
4688
4689		free(p->L_gen.g_nam_p);
4690		free(p);
4691		p = new_p;
4692	}
4693}
4694
4695/*
4696 * rstbuf: Reset the I/O buffer, move incomplete potential headers to
4697 * the front of the buffer and force bread() to refill the buffer.  The
4698 * return value from bread() is returned (to identify I/O errors).  On the
4699 * 3B2, reads must begin on a word boundary, therefore, with the -i option,
4700 * any remaining bytes in the buffer must be moved to the base of the buffer
4701 * in such a way that the destination locations of subsequent reads are
4702 * word aligned.
4703 */
4704
4705static void
4706rstbuf(void)
4707{
4708	int pad;
4709
4710	if ((Args & OCi) || Append) {
4711		if (Buffr.b_out_p != Buffr.b_base_p) {
4712			pad = ((Buffr.b_cnt + FULLWD) & ~FULLWD);
4713			Buffr.b_in_p = Buffr.b_base_p + pad;
4714			pad -= Buffr.b_cnt;
4715			(void) memcpy(Buffr.b_base_p + pad, Buffr.b_out_p,
4716			    (int)Buffr.b_cnt);
4717			Buffr.b_out_p = Buffr.b_base_p + pad;
4718		}
4719		if (bfill() < 0)
4720			msg(EXT, "Unexpected end-of-archive encountered.");
4721	} else { /* OCo */
4722		(void) memcpy(Buffr.b_base_p, Buffr.b_out_p, (int)Buffr.b_cnt);
4723		Buffr.b_out_p = Buffr.b_base_p;
4724		Buffr.b_in_p = Buffr.b_base_p + Buffr.b_cnt;
4725	}
4726}
4727
4728static void
4729setpasswd(char *nam)
4730{
4731	if ((dpasswd = getpwnam(&Gen.g_uname[0])) == (struct passwd *)NULL) {
4732		msg(EPOST, "cpio: problem reading passwd entry");
4733		msg(EPOST, "cpio: %s: owner not changed", nam);
4734		if (Gen.g_uid == UID_NOBODY && S_ISREG(Gen.g_mode))
4735			Gen.g_mode &= ~S_ISUID;
4736	} else
4737		Gen.g_uid = dpasswd->pw_uid;
4738
4739	if ((dgroup = getgrnam(&Gen.g_gname[0])) == (struct group *)NULL) {
4740		msg(EPOST, "cpio: problem reading group entry");
4741		msg(EPOST, "cpio: %s: group not changed", nam);
4742		if (Gen.g_gid == GID_NOBODY && S_ISREG(Gen.g_mode))
4743			Gen.g_mode &= ~S_ISGID;
4744	} else
4745		Gen.g_gid = dgroup->gr_gid;
4746	G_p = &Gen;
4747}
4748
4749/*
4750 * rstfiles:  Perform final changes to the file.  If the -u option is set,
4751 * and overwrite == U_OVER, remove the temporary file, else if overwrite
4752 * == U_KEEP, unlink the current file, and restore the existing version
4753 * of the file.  In addition, where appropriate, set the access or modification
4754 * times, change the owner and change the modes of the file.
4755 *
4756 * Note that if Do_rename is set, then the roles of original and temporary
4757 * file are reversed. If all went well, we will rename() the temporary file
4758 * over the original in order to accomodate potentially executing files.
4759 */
4760static void
4761rstfiles(int over, int dirfd)
4762{
4763	char *inam_p, *onam_p, *nam_p;
4764	int error;
4765
4766	if (Args & OCp) {
4767		if (G_p->g_attrnam_p == (char *)NULL) {
4768			nam_p = Fullnam_p;
4769		} else {
4770			nam_p = G_p->g_attrnam_p;
4771		}
4772	} else {
4773		if (Gen.g_nlink > (ulong_t)0) {
4774			nam_p = G_p->g_nam_p;
4775		} else {
4776			nam_p = Gen.g_nam_p;
4777		}
4778	}
4779	if (Gen.g_attrnam_p != (char *)NULL) {
4780		nam_p = Gen.g_attrnam_p;
4781	}
4782
4783	if ((Args & OCi) && (Hdr_type == USTAR)) {
4784		setpasswd(nam_p);
4785	}
4786	if (over == U_KEEP && *Over_p != '\0') {
4787		if (Do_rename) {
4788			msg(POST, "Restoring existing \"%s%s%s\"",
4789			    (G_p->g_attrnam_p == (char *)NULL) ?
4790			    Over_p : Fullnam_p,
4791			    (G_p->g_attrnam_p == (char *)NULL) ?
4792			    "" : gettext(" Attribute "),
4793			    (G_p->g_attrnam_p == (char *)NULL) ?
4794			    "" : Over_p);
4795		} else {
4796			msg(POST, "Restoring existing \"%s%s%s\"",
4797			    (G_p->g_attrnam_p == (char *)NULL) ?
4798			    nam_p : Fullnam_p,
4799			    (G_p->g_attrnam_p == (char *)NULL) ?
4800			    "" : gettext(" Attribute "),
4801			    (G_p->g_attrnam_p == (char *)NULL) ?
4802			    "" : nam_p);
4803		}
4804
4805		/* delete what we just built */
4806		(void) unlinkat(dirfd, get_component(nam_p), 0);
4807
4808		/* If the old file needs restoring, do the necessary links */
4809		if (Do_rename) {
4810			char *tmp_ptr;
4811
4812			if (Args & OCp) {
4813				tmp_ptr = Fullnam_p;
4814				Fullnam_p = Over_p;
4815			} else {
4816				tmp_ptr = G_p->g_nam_p;
4817				G_p->g_nam_p = Over_p;
4818			}
4819			Over_p = tmp_ptr;
4820
4821			Do_rename = 0;	/* names now have original values */
4822		} else {
4823			if (rename(Over_p, nam_p) < 0) {
4824				if (link(Over_p, nam_p) < 0) {
4825					msg(EXTN,
4826					    "Cannot recover original version"
4827					    " of \"%s%s%s\"",
4828					    (G_p->g_attrnam_p == (char *)NULL) ?
4829					    nam_p : Fullnam_p,
4830					    (G_p->g_attrnam_p == (char *)NULL) ?
4831					    "" : gettext(" Attribute "),
4832					    (G_p->g_attrnam_p == (char *)NULL) ?
4833					    "" : nam_p);
4834				}
4835				if (unlinkat(dirfd, get_component(Over_p), 0)) {
4836					msg(ERRN,
4837					    "Cannot remove temp file "
4838					    "\"%s%s%s\"",
4839					    (G_p->g_attrnam_p == (char *)NULL) ?
4840					    Over_p : Fullnam_p,
4841					    (G_p->g_attrnam_p == (char *)NULL) ?
4842					    "" : gettext(" Attribute "),
4843					    (G_p->g_attrnam_p == (char *)NULL) ?
4844					    "" : Over_p);
4845				}
4846			}
4847		}
4848		*Over_p = '\0';
4849		return;
4850	} else if (over == U_OVER && *Over_p != '\0') {
4851		if (Do_rename) {
4852			char *tmp_ptr;
4853
4854			(void) renameat(dirfd, get_component(nam_p),
4855			    dirfd, get_component(Over_p));
4856			if (Args & OCp) {
4857				if (G_p->g_attrnam_p == (char *)NULL) {
4858					tmp_ptr = Fullnam_p;
4859					Fullnam_p = Over_p;
4860					Over_p = tmp_ptr;
4861				} else {
4862					/*
4863					 * Over_p is pointing at g_attrnam_p
4864					 * which must be preserved.
4865					 *
4866					 * We don't want the tmp_ptr and so
4867					 * on to throw away our only copy of
4868					 * the name.
4869					 */
4870					Over_p = Attrfile_p;
4871				}
4872			} else {
4873				tmp_ptr = G_p->g_nam_p;
4874				G_p->g_nam_p = Over_p;
4875				Over_p = tmp_ptr;
4876			}
4877			Do_rename = 0;	/* names now have original values */
4878		} else {
4879			if (unlinkat(dirfd, get_component(Over_p), 0) < 0) {
4880				msg(ERRN,
4881				    "Cannot unlink() temp file \"%s%s%s\"",
4882				    (G_p->g_attrnam_p == (char *)NULL) ?
4883				    Over_p : Fullnam_p,
4884				    (G_p->g_attrnam_p == (char *)NULL) ?
4885				    "" : gettext(" Attribute "),
4886				    (G_p->g_attrnam_p == (char *)NULL) ?
4887				    "" : Over_p);
4888			}
4889		}
4890		*Over_p = '\0';
4891	}
4892	if (Args & OCp) {
4893		if (G_p->g_attrnam_p != (char *)NULL) {
4894			inam_p = G_p->g_attrfnam_p;
4895			onam_p = G_p->g_attrnam_p;
4896		} else {
4897			inam_p = Nam_p;
4898			onam_p = Fullnam_p;
4899		}
4900	} else /* OCi only uses onam_p, OCo only uses inam_p */
4901		if (G_p->g_attrnam_p != (char *)NULL) {
4902			inam_p = onam_p = G_p->g_attrnam_p;
4903		} else {
4904			inam_p = onam_p = G_p->g_nam_p;
4905		}
4906
4907	/*
4908	 * Change the owner, time, and mode to those of the file
4909	 * originally created in the archive.  Note: time and
4910	 * mode do not need to be restored for a symbolic link
4911	 * since rstfiles() is not called when the archived file
4912	 * is a symlink.
4913	 */
4914	if (!(Args & OCo)) {
4915		if (Args & OCR) {
4916			if (fchownat(dirfd, get_component(onam_p),
4917			    Rpw_p->pw_uid, Rpw_p->pw_gid,
4918			    AT_SYMLINK_NOFOLLOW) < 0) {
4919				msg(ERRN, "Cannot chown() \"%s%s%s\"",
4920				    onam_p,
4921				    (G_p->g_attrnam_p == (char *)NULL) ?
4922				    "" : gettext(" Attribute "),
4923				    (G_p->g_attrnam_p == (char *)NULL) ?
4924				    "" : onam_p);
4925			}
4926		} else {
4927			if ((fchownat(dirfd, get_component(onam_p),
4928			    G_p->g_uid, G_p->g_gid,
4929			    AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
4930				msg(ERRN, "Cannot chown() \"%s%s%s\"",
4931				    onam_p,
4932				    (G_p->g_attrnam_p == (char *)NULL) ?
4933				    "" : gettext(" Attribute "),
4934				    (G_p->g_attrnam_p == (char *)NULL) ?
4935				    "" : onam_p);
4936			}
4937		}
4938
4939		if (Args & OCm) {
4940			set_tym(dirfd, get_component(onam_p),
4941			    G_p->g_mtime, G_p->g_mtime);
4942		}
4943
4944		/* Acl was not set, so we must chmod */
4945		if (!acl_is_set) {
4946			mode_t orig_mask, new_mask;
4947
4948			/*
4949			 * use fchmod for attributes, since
4950			 * we known they are always regular
4951			 * files, whereas when it isn't an
4952			 * attribute it could be for a fifo
4953			 * or something other that we don't
4954			 * open and don't have a valid Ofile
4955			 * for.
4956			 */
4957			if (privileged) {
4958				new_mask = G_p->g_mode;
4959			} else {
4960				orig_mask = umask(0);
4961				new_mask = G_p->g_mode & ~orig_mask;
4962			}
4963
4964			if (G_p->g_attrnam_p != (char *)NULL) {
4965				error = fchmod(Ofile, new_mask);
4966			} else {
4967				error = chmod(onam_p, new_mask);
4968			}
4969			if (error < 0) {
4970				msg(ERRN,
4971				    "Cannot chmod() \"%s%s%s\"",
4972				    (G_p->g_attrnam_p == (char *)NULL) ?
4973				    onam_p : G_p->g_attrfnam_p,
4974				    (G_p->g_attrnam_p == (char *)NULL) ?
4975				    "" : gettext(" Attribute "),
4976				    (G_p->g_attrnam_p == (char *)NULL) ?
4977				    "" : onam_p);
4978			}
4979			if (!privileged) {
4980				(void) umask(orig_mask);
4981			}
4982		}
4983	}
4984
4985	if (!(Args & OCi) && (Args & OCa)) {
4986		/*
4987		 * Use dirfd since we are updating original file
4988		 * and not just created file
4989		 */
4990		set_tym(G_p->g_dirfd, get_component(inam_p),
4991		    (ulong_t)SrcSt.st_atime, (ulong_t)SrcSt.st_mtime);
4992	}
4993}
4994
4995/*
4996 * scan4trail: Scan the archive looking for the trailer.
4997 * When found, back the archive up over the trailer and overwrite
4998 * the trailer with the files to be added to the archive.
4999 */
5000
5001static void
5002scan4trail(void)
5003{
5004	int rv;
5005	off_t off1, off2;
5006
5007	Append = 1;
5008	Hdr_type = NONE;
5009	G_p = (struct gen_hdr *)NULL;
5010	while (gethdr()) {
5011		G_p = &Gen;
5012		data_in(P_SKIP);
5013	}
5014	off1 = Buffr.b_cnt;
5015	off2 = Bufsize - (Buffr.b_cnt % Bufsize);
5016	Buffr.b_out_p = Buffr.b_in_p = Buffr.b_base_p;
5017	Buffr.b_cnt = (off_t)0;
5018	if (lseek(Archive, -(off1 + off2), SEEK_REL) < 0)
5019		msg(EXTN, "Unable to append to this archive");
5020	if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0)
5021		msg(EXTN, "Cannot append to this archive");
5022	if (lseek(Archive, (off_t)-rv, SEEK_REL) < 0)
5023		msg(EXTN, "Unable to append to this archive");
5024	Buffr.b_cnt = off2;
5025	Buffr.b_in_p = Buffr.b_base_p + Buffr.b_cnt;
5026	Append = 0;
5027}
5028
5029/*
5030 * setup:  Perform setup and initialization functions.  Parse the options
5031 * using getopt(3C), call ckopts to check the options and initialize various
5032 * structures and pointers.  Specifically, for the -i option, save any
5033 * patterns, for the -o option, check (via stat(2)) the archive, and for
5034 * the -p option, validate the destination directory.
5035 */
5036
5037static void
5038setup(int largc, char **largv)
5039{
5040	extern int optind;
5041	extern char *optarg;
5042
5043#if defined(O_XATTR)
5044#ifdef WAITAROUND
5045	char	*opts_p = "zabcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6@";
5046#else
5047	char	*opts_p = "abcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6@";
5048#endif
5049#else
5050#ifdef WAITAROUND
5051	char	*opts_p = "zabcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6";
5052#else
5053	char	*opts_p = "abcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6";
5054#endif
5055#endif
5056
5057	char   *dupl_p = "Only one occurrence of -%c allowed";
5058	int option;
5059	int blk_cnt, blk_cnt_max;
5060	struct rlimit rlim;
5061
5062	/* Remember the native page size. */
5063
5064	PageSize = sysconf(_SC_PAGESIZE);
5065
5066	if (PageSize == -1) {
5067		/*
5068		 * This sysconf call will almost certainly never fail.  The
5069		 * symbol PAGESIZE itself resolves to the above sysconf call,
5070		 * so we should go ahead and define our own constant.
5071		 */
5072		PageSize = 8192;
5073	}
5074
5075	Hdr_type = BIN;
5076	Max_offset = (off_t)(BIN_OFFSET_MAX);
5077	Efil_p = Hdr_p = Own_p = IOfil_p = NULL;
5078	while ((option = getopt(largc, largv, opts_p)) != EOF) {
5079		switch (option) {
5080#ifdef WAITAROUND
5081		case 'z':
5082			/* rendezvous with the debugger */
5083			waitaround = 1;
5084			break;
5085#endif
5086		case 'a':	/* reset access time */
5087			Args |= OCa;
5088			break;
5089		case 'b':	/* swap bytes and halfwords */
5090			Args |= OCb;
5091			break;
5092		case 'c':	/* select character header */
5093			Args |= OCc;
5094			Hdr_type = ASC;
5095			Max_namesz = APATH;
5096			Onecopy = 1;
5097			break;
5098		case 'd':	/* create directories as needed */
5099			Args |= OCd;
5100			break;
5101		case 'f':	/* select files not in patterns */
5102			Args |= OCf;
5103			break;
5104		case 'i':	/* "copy in" */
5105			Args |= OCi;
5106			Archive = 0;
5107			break;
5108		case 'k':	/* retry after I/O errors */
5109			Args |= OCk;
5110			break;
5111		case 'l':	/* link files when possible */
5112			Args |= OCl;
5113			break;
5114		case 'm':	/* retain modification time */
5115			Args |= OCm;
5116			break;
5117		case 'o':	/* "copy out" */
5118			Args |= OCo;
5119			Archive = 1;
5120			break;
5121		case 'p':	/* "pass" */
5122			Max_namesz = APATH;
5123			Args |= OCp;
5124			break;
5125		case 'r':	/* rename files interactively */
5126			Args |= OCr;
5127			break;
5128		case 's':	/* swap bytes */
5129			Args |= OCs;
5130			break;
5131		case 't':	/* table of contents */
5132			Args |= OCt;
5133			break;
5134		case 'u':	/* copy unconditionally */
5135			Args |= OCu;
5136			break;
5137		case 'v':	/* verbose - print file names */
5138			Args |= OCv;
5139			break;
5140		case 'A':	/* append to existing archive */
5141			Args |= OCA;
5142			break;
5143		case 'B':	/* set block size to 5120 bytes */
5144			Args |= OCB;
5145			Bufsize = 5120;
5146			break;
5147		case 'C':	/* set arbitrary block size */
5148			if (Args & OCC)
5149				msg(ERR, dupl_p, 'C');
5150			else {
5151				Args |= OCC;
5152				Bufsize = atoi(optarg);
5153			}
5154			break;
5155		case 'D':
5156			Dflag = 1;
5157			break;
5158		case 'E':	/* alternate file for pattern input */
5159			if (Args & OCE)
5160				msg(ERR, dupl_p, 'E');
5161			else {
5162				Args |= OCE;
5163				Efil_p = optarg;
5164			}
5165			break;
5166		case 'H':	/* select header type */
5167			if (Args & OCH)
5168				msg(ERR, dupl_p, 'H');
5169			else {
5170				Args |= OCH;
5171				Hdr_p = optarg;
5172			}
5173			break;
5174		case 'I':	/* alternate file for archive input */
5175			if (Args & OCI)
5176				msg(ERR, dupl_p, 'I');
5177			else {
5178				Args |= OCI;
5179				IOfil_p = optarg;
5180			}
5181			break;
5182		case 'L':	/* follow symbolic links */
5183			Args |= OCL;
5184			break;
5185		case 'M':	/* specify new end-of-media message */
5186			if (Args & OCM)
5187				msg(ERR, dupl_p, 'M');
5188			else {
5189				Args |= OCM;
5190				Eom_p = optarg;
5191			}
5192			break;
5193		case 'O':	/* alternate file for archive output */
5194			if (Args & OCO)
5195				msg(ERR, dupl_p, 'O');
5196			else {
5197				Args |= OCO;
5198				IOfil_p = optarg;
5199			}
5200			break;
5201		case 'P':	/* preserve acls */
5202			Args |= OCP;
5203			Pflag++;
5204			break;
5205		case 'R':	/* change owner/group of files */
5206			if (Args & OCR)
5207				msg(ERR, dupl_p, 'R');
5208			else {
5209				Args |= OCR;
5210				Own_p = optarg;
5211			}
5212			break;
5213		case 'S':	/* swap halfwords */
5214			Args |= OCS;
5215			break;
5216		case 'V':	/* print a dot '.' for each file */
5217			Args |= OCV;
5218			break;
5219		case '6':	/* for old, sixth-edition files */
5220			Args |= OC6;
5221			Ftype = SIXTH;
5222			break;
5223#if defined(O_XATTR)
5224		case '@':
5225			Atflag++;
5226			break;
5227#endif
5228		default:
5229			Error_cnt++;
5230		} /* option */
5231	} /* (option = getopt(largc, largv, opts_p)) != EOF */
5232
5233#ifdef WAITAROUND
5234	if (waitaround) {
5235		(void) fprintf(stderr, gettext("Rendezvous with cpio on pid"
5236		    " %d\n"), getpid());
5237
5238		while (waitaround) {
5239			(void) sleep(10);
5240		}
5241	}
5242#endif
5243
5244	largc -= optind;
5245	largv += optind;
5246	ckopts(Args);
5247	if (!Error_cnt) {
5248		Empty = e_valloc(E_EXIT, TARSZ);
5249		if (Args & OCr) {
5250			Renam_p = e_zalloc(E_EXIT, APATH + 1);
5251			Renametmp_p = e_zalloc(E_EXIT, APATH + 1);
5252		}
5253		Symlnk_p = e_zalloc(E_EXIT, APATH);
5254		Over_p = e_zalloc(E_EXIT, APATH);
5255		Nam_p = e_zalloc(E_EXIT, APATH + 1);
5256		if (Args & OCp) {
5257			Savenam_p = e_zalloc(E_EXIT, APATH + 1);
5258		}
5259		Fullnam_p = e_zalloc(E_EXIT, APATH);
5260		Lnknam_p = e_zalloc(E_EXIT, APATH);
5261		Gen.g_nam_p = Nam_p;
5262		if ((Fullnam_p = getcwd((char *)NULL, APATH)) == (char *)NULL)
5263			msg(EXT, "Unable to determine current directory.");
5264		if (Args & OCi) {
5265			if (largc > 0) /* save patterns for -i option, if any */
5266				Pat_pp = largv;
5267			if (Args & OCE)
5268				getpats(largc, largv);
5269		} else if (Args & OCo) {
5270			if (largc != 0) /* error if arguments left with -o */
5271				Error_cnt++;
5272			else if (fstat(Archive, &ArchSt) < 0)
5273				msg(ERRN, "Error during stat() of archive");
5274			switch (Hdr_type) {
5275			case BIN:
5276				Hdrsz = HDRSZ;
5277				Pad_val = HALFWD;
5278				break;
5279			case CHR:
5280				Hdrsz = CHRSZ;
5281				Pad_val = 0;
5282				Max_offset = (off_t)(CHAR_OFFSET_MAX);
5283				break;
5284			case ASC:
5285			case CRC:
5286				Hdrsz = ASCSZ;
5287				Pad_val = FULLWD;
5288				Max_offset = (off_t)(ASC_OFFSET_MAX);
5289				break;
5290			case TAR:
5291			/* FALLTHROUGH */
5292			case USTAR: /* TAR and USTAR */
5293				Hdrsz = TARSZ;
5294				Pad_val = FULLBK;
5295				Max_offset = (off_t)(CHAR_OFFSET_MAX);
5296				break;
5297			default:
5298				msg(EXT, "Impossible header type.");
5299			}
5300		} else { /* directory must be specified */
5301			if (largc != 1)
5302				Error_cnt++;
5303			else if (access(*largv, 2) < 0 && (errno != EACCES))
5304				/*
5305				 * EACCES is ignored here as it may occur
5306				 * when any directory component of the path
5307				 * does not have write permission, even though
5308				 * the destination subdirectory has write
5309				 * access. Writing to a read only directory
5310				 * is handled later, as in "copy in" mode.
5311				 */
5312				msg(ERRN,
5313				    "Error during access() of \"%s\"", *largv);
5314		}
5315	}
5316	if (Error_cnt)
5317		usage(); /* exits! */
5318	if (Args & (OCi | OCo)) {
5319		if (!Dflag) {
5320			if (Args & (OCB | OCC)) {
5321				if (g_init(&Device, &Archive) < 0)
5322					msg(EXTN,
5323					    "Error during initialization");
5324			} else {
5325				if ((Bufsize = g_init(&Device, &Archive)) < 0)
5326					msg(EXTN,
5327					    "Error during initialization");
5328			}
5329		}
5330
5331		blk_cnt_max = _20K / Bufsize;
5332		if (blk_cnt_max < MX_BUFS) {
5333			blk_cnt_max = MX_BUFS;
5334		}
5335
5336		Buffr.b_base_p = NULL;
5337
5338		for (blk_cnt = blk_cnt_max; blk_cnt > 1; blk_cnt--) {
5339			Buffr.b_size = (size_t)(Bufsize * blk_cnt);
5340			Buffr.b_base_p = e_valloc(E_NORMAL, Buffr.b_size);
5341			if (Buffr.b_base_p != NULL) {
5342				break;
5343			}
5344		}
5345		if (Buffr.b_base_p == NULL || Buffr.b_size < (2 * CPIOBSZ)) {
5346			msg(EXT, "Out of memory");
5347		}
5348
5349		Buffr.b_out_p = Buffr.b_in_p = Buffr.b_base_p;
5350		Buffr.b_cnt = 0L;
5351		Buffr.b_end_p = Buffr.b_base_p + Buffr.b_size;
5352	}
5353
5354	/*
5355	 * Now that Bufsize has stabilized, we can allocate our i/o buffer
5356	 */
5357	Buf_p = e_valloc(E_EXIT, Bufsize);
5358
5359	if (Args & OCp) { /* get destination directory */
5360		(void) strcpy(Fullnam_p, *largv);
5361		if (stat(Fullnam_p, &DesSt) < 0)
5362			msg(EXTN, "Error during stat() of \"%s\"", Fullnam_p);
5363		if ((DesSt.st_mode & Ftype) != S_IFDIR)
5364			msg(EXT, "\"%s\" is not a directory", Fullnam_p);
5365	}
5366	Full_p = Fullnam_p + strlen(Fullnam_p) - 1;
5367	if (*Full_p != '/') {
5368		Full_p++;
5369		*Full_p = '/';
5370	}
5371	Full_p++;
5372	*Full_p = '\0';
5373	(void) strcpy(Lnknam_p, Fullnam_p);
5374	Lnkend_p = Lnknam_p + strlen(Lnknam_p);
5375	(void) getrlimit(RLIMIT_FSIZE, &rlim);
5376	Max_filesz = (off_t)rlim.rlim_cur;
5377	Lnk_hd.L_nxt_p = Lnk_hd.L_bck_p = &Lnk_hd;
5378	Lnk_hd.L_lnk_p = (struct Lnk *)NULL;
5379}
5380
5381/*
5382 * set_tym: Set the access and/or modification times for a file.
5383 */
5384
5385static void
5386set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime)
5387{
5388	struct timeval times[2];
5389
5390	times[0].tv_sec = atime;
5391	times[0].tv_usec = 0;
5392	times[1].tv_sec = mtime;
5393	times[1].tv_usec = 0;
5394
5395	if (futimesat(dirfd, nam_p, times) < 0) {
5396		if (Args & OCa) {
5397			msg(ERRN,
5398			    "Unable to reset access time for \"%s%s%s\"",
5399			    (G_p->g_attrnam_p == (char *)NULL) ?
5400			    nam_p : Fullnam_p,
5401			    (G_p->g_attrnam_p == (char *)NULL) ?
5402			    "" : gettext(" Attribute "),
5403			    (G_p->g_attrnam_p == (char *)NULL) ?
5404			    "" : nam_p);
5405		} else {
5406			msg(ERRN,
5407			    "Unable to reset modification time for \"%s%s%s\"",
5408			    (G_p->g_attrnam_p == (char *)NULL) ?
5409			    nam_p : Fullnam_p,
5410			    (G_p->g_attrnam_p == (char *)NULL) ?
5411			    "" : gettext(" Attribute "),
5412			    (G_p->g_attrnam_p == (char *)NULL) ?
5413			    "" : nam_p);
5414		}
5415	}
5416}
5417
5418/*
5419 * sigint:  Catch interrupts.  If an interrupt occurs during the extraction
5420 * of a file from the archive with the -u option set, and the filename did
5421 * exist, remove the current file and restore the original file.  Then exit.
5422 */
5423
5424/*ARGSUSED*/
5425static void
5426sigint(int sig)
5427{
5428	char *nam_p;
5429
5430	(void) signal(SIGINT, SIG_IGN); /* block further signals */
5431	if (!Finished) {
5432		if (Args & OCi)
5433			nam_p = G_p->g_nam_p;
5434		else /* OCp */
5435			nam_p = Fullnam_p;
5436		if (*Over_p != '\0') { /* There is a temp file */
5437			if (unlink(nam_p) < 0) {
5438				msg(ERRN,
5439				    "Cannot remove incomplete \"%s\"", nam_p);
5440			}
5441			if (rename(Over_p, nam_p) < 0) {
5442				if (link(Over_p, nam_p) < 0) {
5443					msg(ERRN,
5444					    "Cannot recover original \"%s\"",
5445					    nam_p);
5446				}
5447				if (unlink(Over_p)) {
5448					msg(ERRN,
5449					    "Cannot remove temp file \"%s\"",
5450					    Over_p);
5451				}
5452			}
5453		} else if (unlink(nam_p))
5454			msg(ERRN,
5455			    "Cannot remove incomplete \"%s\"", nam_p);
5456			*Over_p = '\0';
5457	}
5458	exit(EXIT_CODE);
5459}
5460
5461/*
5462 * swap: Swap bytes (-s), halfwords (-S) or or both halfwords and bytes (-b).
5463 */
5464
5465static void
5466swap(char *buf_p, int cnt)
5467{
5468	unsigned char tbyte;
5469	int tcnt;
5470	int rcnt;
5471	ushort_t thalf;
5472
5473	rcnt = cnt % 4;
5474	cnt /= 4;
5475	if (Args & (OCb | OCs | BSM)) {
5476		tcnt = cnt;
5477		/* LINTED alignment */
5478		Swp_p = (union swpbuf *)buf_p;
5479		while (tcnt-- > 0) {
5480			tbyte = Swp_p->s_byte[0];
5481			Swp_p->s_byte[0] = Swp_p->s_byte[1];
5482			Swp_p->s_byte[1] = tbyte;
5483			tbyte = Swp_p->s_byte[2];
5484			Swp_p->s_byte[2] = Swp_p->s_byte[3];
5485			Swp_p->s_byte[3] = tbyte;
5486			Swp_p++;
5487		}
5488		if (rcnt >= 2) {
5489		tbyte = Swp_p->s_byte[0];
5490		Swp_p->s_byte[0] = Swp_p->s_byte[1];
5491		Swp_p->s_byte[1] = tbyte;
5492		tbyte = Swp_p->s_byte[2];
5493		}
5494	}
5495	if (Args & (OCb | OCS)) {
5496		tcnt = cnt;
5497		/* LINTED alignment */
5498		Swp_p = (union swpbuf *)buf_p;
5499		while (tcnt-- > 0) {
5500			thalf = Swp_p->s_half[0];
5501			Swp_p->s_half[0] = Swp_p->s_half[1];
5502			Swp_p->s_half[1] = thalf;
5503			Swp_p++;
5504		}
5505	}
5506}
5507
5508/*
5509 * usage: Print the usage message on stderr and exit.
5510 */
5511
5512static void
5513usage(void)
5514{
5515
5516	(void) fflush(stdout);
5517#if defined(O_XATTR)
5518	(void) fprintf(stderr, gettext("USAGE:\n"
5519	    "\tcpio -i[bcdfkmrstuv@BSV6] [-C size] "
5520	    "[-E file] [-H hdr] [-I file [-M msg]] "
5521	    "[-R id] [patterns]\n"
5522	    "\tcpio -o[acv@ABLV] [-C size] "
5523	    "[-H hdr] [-O file [-M msg]]\n"
5524	    "\tcpio -p[adlmuv@LV] [-R id] directory\n"));
5525#else
5526	(void) fprintf(stderr, gettext("USAGE:\n"
5527	    "\tcpio -i[bcdfkmrstuvBSV6] [-C size] "
5528	    "[-E file] [-H hdr] [-I file [-M msg]] "
5529	    "[-R id] [patterns]\n"
5530	    "\tcpio -o[acvABLV] [-C size] "
5531	    "[-H hdr] [-O file [-M msg]]\n"
5532	    "\tcpio -p[adlmuvLV] [-R id] directory\n"));
5533#endif
5534	(void) fflush(stderr);
5535	exit(EXIT_CODE);
5536}
5537
5538/*
5539 * verbose: For each file, print either the filename (-v) or a dot (-V).
5540 * If the -t option (table of contents) is set, print either the filename,
5541 * or if the -v option is also set, print an "ls -l"-like listing.
5542 */
5543
5544static void
5545verbose(char *nam_p)
5546{
5547	int i, j, temp;
5548	mode_t mode;
5549	char modestr[12];
5550
5551	/*
5552	 * The printf format and associated arguments to print the current
5553	 * filename.  Normally, just nam_p.  If we're processing an extended
5554	 * attribute, these are overridden.
5555	 */
5556	char *name_fmt = "%s";
5557	const char *name = nam_p;
5558	const char *attribute = NULL;
5559
5560	if (Gen.g_attrnam_p != (char *)NULL) {
5561		/*
5562		 * Translation note:
5563		 * 'attribute' is a noun.
5564		 */
5565		name_fmt = gettext("%s attribute %s");
5566
5567		name = (Args & OCp) ? nam_p : Gen.g_attrfnam_p;
5568		attribute = Gen.g_attrnam_p;
5569	}
5570
5571	if ((Gen.g_mode == SECMODE) || ((Hdr_type == USTAR ||
5572	    Hdr_type == TAR) && Thdr_p->tbuf.t_typeflag == 'A')) {
5573		/* dont print ancillary file */
5574		aclchar = '+';
5575		return;
5576	}
5577	for (i = 0; i < 11; i++)
5578		modestr[i] = '-';
5579	modestr[i] = '\0';
5580	modestr[i-1] = aclchar;
5581	aclchar = ' ';
5582
5583	if ((Args & OCt) && (Args & OCv)) {
5584		mode = Gen.g_mode;
5585		for (i = 0; i < 3; i++) {
5586			temp = (mode >> (6 - (i * 3)));
5587			j = (i * 3) + 1;
5588			if (S_IROTH & temp)
5589				modestr[j] = 'r';
5590			if (S_IWOTH & temp)
5591				modestr[j + 1] = 'w';
5592			if (S_IXOTH & temp)
5593				modestr[j + 2] = 'x';
5594		}
5595
5596		if (Hdr_type != BAR) {
5597			temp = Gen.g_mode & Ftype;
5598			switch (temp) {
5599			case (S_IFIFO):
5600				modestr[0] = 'p';
5601				break;
5602			case (S_IFCHR):
5603				modestr[0] = 'c';
5604				break;
5605			case (S_IFDIR):
5606				modestr[0] = 'd';
5607				break;
5608			case (S_IFBLK):
5609				modestr[0] = 'b';
5610				break;
5611			case (S_IFREG): /* was initialized to '-' */
5612				break;
5613			case (S_IFLNK):
5614				modestr[0] = 'l';
5615				break;
5616			default:
5617				msg(ERR, "Impossible file type");
5618			}
5619		} else {		/* bar */
5620			temp = Gen.g_mode & Ftype;
5621			switch (temp) {
5622			case (S_IFIFO):
5623				modestr[0] = 'p';
5624				break;
5625			case (S_IFCHR):
5626				modestr[0] = 'c';
5627				break;
5628			case (S_IFDIR):
5629				modestr[0] = 'd';
5630				break;
5631			case (S_IFBLK):
5632				modestr[0] = 'b';
5633				break;
5634			}
5635			if (bar_linkflag == SYMTYPE)
5636				modestr[0] = 'l';
5637		}
5638		if ((S_ISUID & Gen.g_mode) == S_ISUID)
5639			modestr[3] = 's';
5640		if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
5641			modestr[9] = 't';
5642		if ((S_ISGID & G_p->g_mode) == S_ISGID && modestr[6] == 'x')
5643			modestr[6] = 's';
5644		else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
5645			modestr[6] = 'l';
5646		if ((Hdr_type == TAR || Hdr_type == USTAR) && Gen.g_nlink == 0)
5647			(void) printf("%s%4d ", modestr, (int)Gen.g_nlink+1);
5648		else
5649			(void) printf("%s%4d ", modestr, (int)Gen.g_nlink);
5650		if (Lastuid == (int)Gen.g_uid) {
5651			if (Lastuid == -1)
5652				(void) printf("-1       ");
5653			else
5654				(void) printf("%-9s", Curpw_p->pw_name);
5655		} else {
5656			if (Curpw_p = getpwuid((int)Gen.g_uid)) {
5657				(void) printf("%-9s", Curpw_p->pw_name);
5658				Lastuid = (int)Gen.g_uid;
5659			} else {
5660				(void) printf("%-9d", (int)Gen.g_uid);
5661				Lastuid = -1;
5662			}
5663		}
5664		if (Lastgid == (int)Gen.g_gid) {
5665			if (Lastgid == -1)
5666				(void) printf("-1       ");
5667			else
5668				(void) printf("%-9s", Curgr_p->gr_name);
5669		} else {
5670			if (Curgr_p = getgrgid((int)Gen.g_gid)) {
5671				(void) printf("%-9s", Curgr_p->gr_name);
5672				Lastgid = (int)Gen.g_gid;
5673			} else {
5674				(void) printf("%-9d", (int)Gen.g_gid);
5675				Lastgid = -1;
5676			}
5677		}
5678
5679		/* print file size */
5680		if (!Aspec || ((Gen.g_mode & Ftype) == S_IFIFO) ||
5681		    (Hdr_type == BAR && bar_linkflag == SYMTYPE)) {
5682			if (Gen.g_filesz < (1LL << 31))
5683				(void) printf("%7lld ",
5684				    (offset_t)Gen.g_filesz);
5685			else
5686				(void) printf("%11lld ",
5687				    (offset_t)Gen.g_filesz);
5688		} else
5689			(void) printf("%3d,%3d ", (int)major(Gen.g_rdev),
5690			    (int)minor(Gen.g_rdev));
5691		(void) cftime(Time, dcgettext(NULL, FORMAT, LC_TIME),
5692		    (time_t *)&Gen.g_mtime);
5693		(void) printf("%s, ", Time);
5694		(void) printf(name_fmt, name, attribute);
5695		if ((Gen.g_mode & Ftype) == S_IFLNK) {
5696			if (Hdr_type == USTAR || Hdr_type == TAR)
5697				(void) strcpy(Symlnk_p,
5698				    Thdr_p->tbuf.t_linkname);
5699			else {
5700				(void) strncpy(Symlnk_p, Buffr.b_out_p,
5701				    Gen.g_filesz);
5702				*(Symlnk_p + Gen.g_filesz) = '\0';
5703			}
5704			(void) printf(" -> %s", Symlnk_p);
5705		}
5706		if (Hdr_type == BAR) {
5707			if (bar_linkflag == SYMTYPE)
5708				(void) printf(gettext(" symbolic link to %s"),
5709				    bar_linkname);
5710			else if (bar_linkflag == '1')
5711				(void) printf(gettext(" linked to %s"),
5712				    bar_linkname);
5713		}
5714		if ((Hdr_type == USTAR || Hdr_type == TAR) &&
5715		    Thdr_p->tbuf.t_typeflag == '1') {
5716			(void) printf(gettext(" linked to %s%s%s"),
5717			    (Gen.g_attrnam_p == (char *)NULL) ?
5718			    Thdr_p->tbuf.t_linkname : Gen.g_attrfnam_p,
5719			    (Gen.g_attrnam_p == (char *)NULL) ?
5720			    "" : gettext(" attribute "),
5721			    (Gen.g_attrnam_p == (char *)NULL) ?
5722			    "" : Gen.g_linktoattrnam_p);
5723		}
5724		(void) printf("\n");
5725	} else if ((Args & OCt) || (Args & OCv)) {
5726		(void) fprintf(Out_p, name_fmt, name, attribute);
5727		(void) fputc('\n', Out_p);
5728	} else { /* OCV */
5729		(void) fputc('.', Out_p);
5730		if (Verbcnt++ >= 49) { /* start a new line of dots */
5731			Verbcnt = 0;
5732			(void) fputc('\n', Out_p);
5733		}
5734	}
5735	(void) fflush(Out_p);
5736}
5737
5738#define	MK_USHORT(a)	(a & 00000177777)
5739
5740/*
5741 * write_hdr: Transfer header information for the generic structure
5742 * into the format for the selected header and bwrite() the header.
5743 * ACL support: add two new argumnets. secflag indicates that it's an
5744 *	ancillary file. len is the size of the file (incl. all security
5745 *	attributes). We only have acls now.
5746 */
5747
5748static void
5749write_hdr(int secflag, off_t len)
5750{
5751	int cnt, pad;
5752	mode_t mode;
5753	uid_t uid;
5754	gid_t gid;
5755	const char warnfmt[] = "%s%s%s : %s";
5756
5757	if (secflag == ARCHIVE_ACL) {
5758		mode = SECMODE;
5759	} else {
5760		/*
5761		 * If attribute is being archived in cpio format then
5762		 * zap off the file type bits since those are truly a
5763		 * mask and reset them with _XATTR_CPIO_MODE
5764		 */
5765
5766		/*
5767		 * len is the value of g_filesz for normal files
5768		 * and the length of the special header buffer in
5769		 * the case of acl and xattr headers.
5770		 */
5771		if (G_p->g_attrnam_p != (char *)NULL && Hdr_type != USTAR &&
5772		    Hdr_type != TAR) {
5773			mode = (G_p->g_mode & POSIXMODES) | _XATTR_CPIO_MODE;
5774		} else {
5775			mode = G_p->g_mode;
5776		}
5777		if (secflag != ARCHIVE_XATTR) {
5778			len = G_p->g_filesz;
5779		}
5780	}
5781
5782	uid = G_p->g_uid;
5783	gid = G_p->g_gid;
5784	/*
5785	 * Handle EFT uids and gids.  If they get too big
5786	 * to be represented in a particular format, force 'em to 'nobody'.
5787	 */
5788	switch (Hdr_type) {
5789	case BIN:			/* 16-bits of u_short */
5790		if ((ulong_t)uid > (ulong_t)USHRT_MAX)
5791			uid = UID_NOBODY;
5792		if ((ulong_t)gid > (ulong_t)USHRT_MAX)
5793			gid = GID_NOBODY;
5794		break;
5795	case CHR:			/* %.6lo => 262143 base 10 */
5796		if ((ulong_t)uid > (ulong_t)0777777)
5797			uid = UID_NOBODY;
5798		if ((ulong_t)gid > (ulong_t)0777777)
5799			gid = GID_NOBODY;
5800		break;
5801	case ASC:			/* %.8lx => full 32 bits */
5802	case CRC:
5803		break;
5804	case USTAR:
5805	case TAR:			/* %.7lo => 2097151 base 10 */
5806		if ((ulong_t)uid > (ulong_t)07777777)
5807			uid = UID_NOBODY;
5808		if ((ulong_t)gid > (ulong_t)07777777)
5809			gid = GID_NOBODY;
5810		break;
5811	default:
5812		msg(EXT, "Impossible header type.");
5813	}
5814
5815	/*
5816	 * Since cpio formats -don't- encode the symbolic names, print
5817	 * a warning message when we map the uid or gid this way.
5818	 * Also, if the ownership just changed, clear set[ug]id bits
5819	 *
5820	 * (Except for USTAR format of course, where we have a string
5821	 * representation of the username embedded in the header)
5822	 */
5823	if (uid != G_p->g_uid && Hdr_type != USTAR) {
5824		msg(ERR, warnfmt,
5825		    (G_p->g_attrnam_p == (char *)NULL) ?
5826		    G_p->g_nam_p : G_p->g_attrfnam_p,
5827		    (G_p->g_attrnam_p == (char *)NULL) ?
5828		    "" : gettext(" Attribute "),
5829		    (G_p->g_attrnam_p == (char *)NULL) ?
5830		    "" : G_p->g_attrnam_p,
5831		    gettext("uid too large for archive format"));
5832		if (S_ISREG(mode))
5833			mode &= ~S_ISUID;
5834	}
5835	if (gid != G_p->g_gid && Hdr_type != USTAR) {
5836		msg(ERR, warnfmt,
5837		    (G_p->g_attrnam_p == (char *)NULL) ?
5838		    G_p->g_nam_p : G_p->g_attrfnam_p,
5839		    (G_p->g_attrnam_p == (char *)NULL) ?
5840		    "" : gettext(" Attribute "),
5841		    (G_p->g_attrnam_p == (char *)NULL) ?
5842		    "" : G_p->g_attrnam_p,
5843		    gettext("gid too large for archive format"));
5844		if (S_ISREG(mode))
5845			mode &= ~S_ISGID;
5846	}
5847
5848	switch (Hdr_type) {
5849	case BIN:
5850	case CHR:
5851	case ASC:
5852	case CRC:
5853		cnt = Hdrsz + G_p->g_namesz;
5854		break;
5855	case TAR:
5856		/*FALLTHROUGH*/
5857	case USTAR: /* TAR and USTAR */
5858		cnt = TARSZ;
5859		break;
5860	default:
5861		msg(EXT, "Impossible header type.");
5862	}
5863	FLUSH(cnt);
5864
5865	switch (Hdr_type) {
5866	case BIN:
5867		Hdr.h_magic = (short)G_p->g_magic;
5868		Hdr.h_dev = G_p->g_dev;
5869		Hdr.h_ino = G_p->g_ino;
5870		Hdr.h_uid = uid;
5871		Hdr.h_gid = gid;
5872		Hdr.h_mode = mode;
5873		Hdr.h_nlink = G_p->g_nlink;
5874		Hdr.h_rdev = G_p->g_rdev;
5875		mkshort(Hdr.h_mtime, (long)G_p->g_mtime);
5876		Hdr.h_namesize = (short)G_p->g_namesz;
5877		mkshort(Hdr.h_filesize, (long)len);
5878		(void) strcpy(Hdr.h_name, G_p->g_nam_p);
5879		(void) memcpy(Buffr.b_in_p, &Hdr, cnt);
5880		break;
5881	case CHR:
5882		(void) sprintf(Buffr.b_in_p,
5883		    "%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11lo%.6lo%."
5884		    "11llo%s", G_p->g_magic, G_p->g_dev, G_p->g_ino, mode,
5885		    uid, gid, G_p->g_nlink, MK_USHORT(G_p->g_rdev),
5886		    G_p->g_mtime, (long)G_p->g_namesz, (offset_t)len,
5887		    G_p->g_nam_p);
5888		break;
5889	case ASC:
5890	case CRC:
5891		(void) sprintf(Buffr.b_in_p,
5892		    "%.6lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%."
5893		    "8lx%.8lx%.8lx%.8lx%s",
5894		    G_p->g_magic, G_p->g_ino, mode, G_p->g_uid,
5895		    G_p->g_gid, G_p->g_nlink, G_p->g_mtime, (ulong_t)len,
5896		    major(G_p->g_dev), minor(G_p->g_dev),
5897		    major(G_p->g_rdev), minor(G_p->g_rdev),
5898		    G_p->g_namesz, G_p->g_cksum, G_p->g_nam_p);
5899		break;
5900	case USTAR:
5901		Thdr_p = (union tblock *)Buffr.b_in_p;
5902		(void) memcpy(Thdr_p, Empty, TARSZ);
5903		(void) strncpy(Thdr_p->tbuf.t_name, G_p->g_tname,
5904		    (int)strlen(G_p->g_tname));
5905		(void) sprintf(Thdr_p->tbuf.t_mode, "%07o", (int)mode);
5906		(void) sprintf(Thdr_p->tbuf.t_uid, "%07o", (int)uid);
5907		(void) sprintf(Thdr_p->tbuf.t_gid, "%07o", (int)gid);
5908		(void) sprintf(Thdr_p->tbuf.t_size, "%011llo",
5909		    (offset_t)len);
5910		(void) sprintf(Thdr_p->tbuf.t_mtime, "%011lo", G_p->g_mtime);
5911		if (secflag == ARCHIVE_ACL) {
5912			Thdr_p->tbuf.t_typeflag = 'A';	/* ACL file type */
5913		} else if (secflag == ARCHIVE_XATTR ||
5914		    (G_p->g_attrnam_p != (char *)NULL)) {
5915			Thdr_p->tbuf.t_typeflag = _XATTR_HDRTYPE;
5916		} else {
5917			Thdr_p->tbuf.t_typeflag = G_p->g_typeflag;
5918		}
5919		if (T_lname[0] != '\0') {
5920			/*
5921			 * if not a symbolic link
5922			 */
5923			if (((G_p->g_mode & Ftype) != S_IFLNK) &&
5924			    (G_p->g_attrnam_p == (char *)NULL)) {
5925				Thdr_p->tbuf.t_typeflag = LNKTYPE;
5926				(void) sprintf(Thdr_p->tbuf.t_size,
5927				    "%011lo", 0L);
5928			}
5929			(void) strncpy(Thdr_p->tbuf.t_linkname, T_lname,
5930			    strlen(T_lname));
5931		}
5932		(void) sprintf(Thdr_p->tbuf.t_magic, "%s", TMAGIC);
5933		(void) sprintf(Thdr_p->tbuf.t_version, "%2s", TVERSION);
5934		(void) sprintf(Thdr_p->tbuf.t_uname, "%s",  G_p->g_uname);
5935		(void) sprintf(Thdr_p->tbuf.t_gname, "%s", G_p->g_gname);
5936		(void) sprintf(Thdr_p->tbuf.t_devmajor, "%07o",
5937		    (int)major(G_p->g_rdev));
5938		(void) sprintf(Thdr_p->tbuf.t_devminor, "%07o",
5939		    (int)minor(G_p->g_rdev));
5940		if (Gen.g_prefix) {
5941			(void) sprintf(Thdr_p->tbuf.t_prefix, "%s",
5942			    Gen.g_prefix);
5943			free(Gen.g_prefix);
5944			Gen.g_prefix = NULL;
5945		} else {
5946			(void) sprintf(Thdr_p->tbuf.t_prefix, "%s", "");
5947		}
5948		(void) sprintf(Thdr_p->tbuf.t_cksum, "%07o",
5949		    (int)cksum(TARTYP, 0, NULL));
5950		break;
5951	case TAR:
5952		Thdr_p = (union tblock *)Buffr.b_in_p;
5953		(void) memcpy(Thdr_p, Empty, TARSZ);
5954		(void) strncpy(Thdr_p->tbuf.t_name, G_p->g_nam_p,
5955		    G_p->g_namesz);
5956		(void) sprintf(Thdr_p->tbuf.t_mode, "%07o ", (int)mode);
5957		(void) sprintf(Thdr_p->tbuf.t_uid, "%07o ", (int)uid);
5958		(void) sprintf(Thdr_p->tbuf.t_gid, "%07o ", (int)gid);
5959		(void) sprintf(Thdr_p->tbuf.t_size, "%011llo ",
5960		    (offset_t)len);
5961		(void) sprintf(Thdr_p->tbuf.t_mtime, "%011o ",
5962		    (int)G_p->g_mtime);
5963		if (T_lname[0] != '\0') {
5964			Thdr_p->tbuf.t_typeflag = '1';
5965		} else {
5966			Thdr_p->tbuf.t_typeflag = '\0';
5967		}
5968		(void) strncpy(Thdr_p->tbuf.t_linkname, T_lname,
5969		    strlen(T_lname));
5970		break;
5971	default:
5972		msg(EXT, "Impossible header type.");
5973	} /* Hdr_type */
5974
5975	Buffr.b_in_p += cnt;
5976	Buffr.b_cnt += cnt;
5977	pad = ((cnt + Pad_val) & ~Pad_val) - cnt;
5978	if (pad != 0) {
5979		FLUSH(pad);
5980		(void) memcpy(Buffr.b_in_p, Empty, pad);
5981		Buffr.b_in_p += pad;
5982		Buffr.b_cnt += pad;
5983	}
5984}
5985
5986/*
5987 * write_trail: Create the appropriate trailer for the selected header type
5988 * and bwrite the trailer.  Pad the buffer with nulls out to the next Bufsize
5989 * boundary, and force a write.  If the write completes, or if the trailer is
5990 * completely written (but not all of the padding nulls (as can happen on end
5991 * of medium)) return.  Otherwise, the trailer was not completely written out,
5992 * so re-pad the buffer with nulls and try again.
5993 */
5994
5995static void
5996write_trail(void)
5997{
5998	int cnt, need;
5999
6000	switch (Hdr_type) {
6001	case BIN:
6002		Gen.g_magic = CMN_BIN;
6003		break;
6004	case CHR:
6005		Gen.g_magic = CMN_BIN;
6006		break;
6007	case ASC:
6008		Gen.g_magic = CMN_ASC;
6009		break;
6010	case CRC:
6011		Gen.g_magic = CMN_CRC;
6012		break;
6013	}
6014
6015	switch (Hdr_type) {
6016	case BIN:
6017	case CHR:
6018	case ASC:
6019	case CRC:
6020		Gen.g_mode = Gen.g_uid = Gen.g_gid = 0;
6021		Gen.g_nlink = 1;
6022		Gen.g_mtime = Gen.g_ino = Gen.g_dev = 0;
6023		Gen.g_rdev = Gen.g_cksum = 0;
6024		Gen.g_filesz = (off_t)0;
6025		Gen.g_namesz = strlen("TRAILER!!!") + 1;
6026		(void) strcpy(Gen.g_nam_p, "TRAILER!!!");
6027		G_p = &Gen;
6028		write_hdr(ARCHIVE_NORMAL, (off_t)0);
6029		break;
6030	case TAR:
6031	/*FALLTHROUGH*/
6032	case USTAR: /* TAR and USTAR */
6033		for (cnt = 0; cnt < 3; cnt++) {
6034			FLUSH(TARSZ);
6035			(void) memcpy(Buffr.b_in_p, Empty, TARSZ);
6036			Buffr.b_in_p += TARSZ;
6037			Buffr.b_cnt += TARSZ;
6038		}
6039		break;
6040	default:
6041		msg(EXT, "Impossible header type.");
6042	}
6043	need = Bufsize - (Buffr.b_cnt % Bufsize);
6044	if (need == Bufsize)
6045		need = 0;
6046
6047	while (Buffr.b_cnt > 0) {
6048		while (need > 0) {
6049			cnt = (need < TARSZ) ? need : TARSZ;
6050			need -= cnt;
6051			FLUSH(cnt);
6052			(void) memcpy(Buffr.b_in_p, Empty, cnt);
6053			Buffr.b_in_p += cnt;
6054			Buffr.b_cnt += cnt;
6055		}
6056		bflush();
6057	}
6058}
6059
6060/*
6061 * if archives in USTAR format, check if typeflag == '5' for directories
6062 */
6063static int
6064ustar_dir(void)
6065{
6066	if (Hdr_type == USTAR || Hdr_type == TAR) {
6067		if (Thdr_p->tbuf.t_typeflag == '5')
6068			return (1);
6069	}
6070	return (0);
6071}
6072
6073/*
6074 * if archives in USTAR format, check if typeflag == '3' || '4' || '6'
6075 * for character, block, fifo special files
6076 */
6077static int
6078ustar_spec(void)
6079{
6080	int typeflag;
6081
6082	if (Hdr_type == USTAR || Hdr_type == TAR) {
6083		typeflag = Thdr_p->tbuf.t_typeflag;
6084		if (typeflag == '3' || typeflag == '4' || typeflag == '6')
6085			return (1);
6086	}
6087	return (0);
6088}
6089
6090/*
6091 * The return value is a pointer to a converted copy of the information in
6092 * FromStat if the file is representable in -Hodc format, and NULL otherwise.
6093 */
6094
6095static struct stat *
6096convert_to_old_stat(struct stat *FromStat, char *namep, char *attrp)
6097{
6098	static struct stat ToSt;
6099	cpioinfo_t TmpSt;
6100
6101	(void) memset(&TmpSt, 0, sizeof (cpioinfo_t));
6102	stat_to_svr32_stat(&TmpSt, FromStat);
6103	(void) memset(&ToSt, 0, sizeof (ToSt));
6104
6105	if (TmpSt.st_rdev == (o_dev_t)NODEV &&
6106	    (((TmpSt.st_mode & Ftype) == S_IFCHR) ||
6107	    ((TmpSt.st_mode & Ftype) == S_IFBLK))) {
6108		/*
6109		 * Encountered a problem representing the rdev information.
6110		 * Don't archive it.
6111		 */
6112
6113		msg(ERR, "Error -Hodc format can't support expanded"
6114		    "types on %s%s%s",
6115		    namep,
6116		    (attrp == NULL) ? "" : gettext(" Attribute"),
6117		    (attrp == NULL) ? "" : attrp);
6118		return (NULL);
6119	}
6120
6121	if (TmpSt.st_dev == (o_dev_t)NODEV) {
6122		/*
6123		 * Having trouble representing the device/inode pair.  We can't
6124		 * track links in this case; break them all into separate
6125		 * files.
6126		 */
6127
6128		TmpSt.st_ino = 0;
6129
6130		if (((TmpSt.st_mode & Ftype) != S_IFDIR) &&
6131		    TmpSt.st_nlink > 1)
6132			msg(POST,
6133			    "Warning: file %s%s%s has large "
6134			    "device number - linked "
6135			    "files will be restored as "
6136			    "separate files",
6137			    namep,
6138			    (attrp == NULL) ? "" : gettext(" Attribute"),
6139			    (attrp == NULL) ? "" : attrp);
6140
6141		/* ensure no links */
6142
6143		TmpSt.st_nlink = 1;
6144	}
6145
6146	/* Start converting values */
6147
6148	if (TmpSt.st_dev < 0) {
6149		ToSt.st_dev = 0;
6150	} else {
6151		ToSt.st_dev = (dev_t)TmpSt.st_dev;
6152	}
6153
6154	/* -actual- not truncated uid */
6155
6156	ToSt.st_uid = TmpSt.st_uid;
6157
6158	/* -actual- not truncated gid */
6159
6160	ToSt.st_gid = TmpSt.st_gid;
6161	ToSt.st_ino = (ino_t)TmpSt.st_ino;
6162	ToSt.st_mode = (mode_t)TmpSt.st_mode;
6163	ToSt.st_mtime = (ulong_t)TmpSt.st_modtime;
6164	ToSt.st_nlink = (nlink_t)TmpSt.st_nlink;
6165	ToSt.st_size = (off_t)TmpSt.st_size;
6166	ToSt.st_rdev = (dev_t)TmpSt.st_rdev;
6167
6168	return (&ToSt);
6169}
6170
6171/*
6172 * In the beginning of each bar archive, there is a header which describes the
6173 * current volume being created, followed by a header which describes the
6174 * current file being created, followed by the file itself.  If there is
6175 * more than one file to be created, a separate header will be created for
6176 * each additional file.  This structure may be repeated if the bar archive
6177 * contains multiple volumes.  If a file spans across volumes, its header
6178 * will not be repeated in the next volume.
6179 *               +------------------+
6180 *               |    vol header    |
6181 *               |------------------|
6182 *               |   file header i  |     i = 0
6183 *               |------------------|
6184 *               |     <file i>     |
6185 *               |------------------|
6186 *               |  file header i+1 |
6187 *               |------------------|
6188 *               |    <file i+1>    |
6189 *               |------------------|
6190 *               |        .         |
6191 *               |        .         |
6192 *               |        .         |
6193 *               +------------------+
6194 */
6195
6196/*
6197 * read in the header that describes the current volume of the bar archive
6198 * to be extracted.
6199 */
6200static void
6201read_bar_vol_hdr(void)
6202{
6203	union b_block *tmp_hdr;
6204
6205	tmp_hdr = (union b_block *)Buffr.b_out_p;
6206	if (tmp_hdr->dbuf.bar_magic[0] == BAR_VOLUME_MAGIC) {
6207
6208		if (bar_Vhdr == NULL) {
6209			bar_Vhdr = e_zalloc(E_EXIT, TBLOCK);
6210		}
6211		(void) memcpy(&(bar_Vhdr->dbuf), &(tmp_hdr->dbuf), TBLOCK);
6212	} else {
6213		(void) fprintf(stderr, gettext(
6214		    "bar error: cannot read volume header\n"));
6215		exit(1);
6216	}
6217
6218	(void) sscanf(bar_Vhdr->dbuf.mode, "%8lo", &Gen_bar_vol.g_mode);
6219	(void) sscanf(bar_Vhdr->dbuf.uid, "%8d", (int *)&Gen_bar_vol.g_uid);
6220	(void) sscanf(bar_Vhdr->dbuf.gid, "%8d", (int *)&Gen_bar_vol.g_gid);
6221	(void) sscanf(bar_Vhdr->dbuf.size, "%12llo",
6222	    (u_off_t *)&Gen_bar_vol.g_filesz);
6223	(void) sscanf(bar_Vhdr->dbuf.mtime, "%12lo", &Gen_bar_vol.g_mtime);
6224	(void) sscanf(bar_Vhdr->dbuf.chksum, "%8lo", &Gen_bar_vol.g_cksum);
6225
6226	/* set the compress flag */
6227	if (bar_Vhdr->dbuf.compressed == '1')
6228		Compressed = 1;
6229	else
6230		Compressed = 0;
6231
6232	Buffr.b_out_p += 512;
6233	Buffr.b_cnt -= 512;
6234
6235	/*
6236	 * not the first volume; exit
6237	 */
6238	if (strcmp(bar_Vhdr->dbuf.volume_num, "1") != 0) {
6239		(void) fprintf(stderr,
6240		    gettext("error: This is not volume 1.  "));
6241		(void) fprintf(stderr, gettext("This is volume %s.  "),
6242		    bar_Vhdr->dbuf.volume_num);
6243		(void) fprintf(stderr, gettext("Please insert volume 1.\n"));
6244		exit(1);
6245	}
6246
6247	read_bar_file_hdr();
6248}
6249
6250/*
6251 * read in the header that describes the current file to be extracted
6252 */
6253static void
6254read_bar_file_hdr(void)
6255{
6256	union b_block *tmp_hdr;
6257	char *start_of_name, *name_p;
6258	char *tmp;
6259
6260	if (*Buffr.b_out_p == '\0') {
6261		*Gen.g_nam_p = '\0';
6262		exit(0);
6263	}
6264
6265	tmp_hdr = (union b_block *)Buffr.b_out_p;
6266
6267	tmp = &tmp_hdr->dbuf.mode[1];
6268	(void) sscanf(tmp, "%8lo", &Gen.g_mode);
6269	(void) sscanf(tmp_hdr->dbuf.uid, "%8lo", &Gen.g_uid);
6270	(void) sscanf(tmp_hdr->dbuf.gid, "%8lo", &Gen.g_gid);
6271	(void) sscanf(tmp_hdr->dbuf.size, "%12llo",
6272	    (u_off_t *)&Gen.g_filesz);
6273	(void) sscanf(tmp_hdr->dbuf.mtime, "%12lo", &Gen.g_mtime);
6274	(void) sscanf(tmp_hdr->dbuf.chksum, "%8lo", &Gen.g_cksum);
6275	(void) sscanf(tmp_hdr->dbuf.rdev, "%8lo", &Gen.g_rdev);
6276
6277#define	to_new_major(x)	(int)((unsigned)((x) & OMAXMAJ) << NBITSMINOR)
6278#define	to_new_minor(x)	(int)((x) & OMAXMIN)
6279	Gen.g_rdev = to_new_major(Gen.g_rdev) | to_new_minor(Gen.g_rdev);
6280	bar_linkflag = tmp_hdr->dbuf.linkflag;
6281	start_of_name = &tmp_hdr->dbuf.start_of_name;
6282
6283
6284	name_p = Gen.g_nam_p;
6285	while (*name_p++ = *start_of_name++)
6286		;
6287	*name_p = '\0';
6288	if (bar_linkflag == LNKTYPE || bar_linkflag == SYMTYPE)
6289		(void) strcpy(bar_linkname, start_of_name);
6290
6291	Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
6292	(void) strcpy(nambuf, Gen.g_nam_p);
6293}
6294
6295/*
6296 * if the bar archive is compressed, set up a pipe and do the de-compression
6297 * as the compressed file is read in.
6298 */
6299static void
6300setup_uncompress(FILE **pipef)
6301{
6302	char *cmd_buf;
6303	size_t cmdlen;
6304
6305	cmd_buf = e_zalloc(E_EXIT, MAXPATHLEN * 2);
6306
6307	if (access(Gen.g_nam_p, W_OK) != 0) {
6308		cmdlen = snprintf(cmd_buf, MAXPATHLEN * 2,
6309		    "chmod +w '%s'; uncompress -c > '%s'; "
6310		    "chmod 0%o '%s'",
6311		    Gen.g_nam_p, Gen.g_nam_p, (int)G_p->g_mode, Gen.g_nam_p);
6312	} else {
6313		cmdlen = snprintf(cmd_buf, MAXPATHLEN * 2,
6314		    "uncompress -c > '%s'", Gen.g_nam_p);
6315	}
6316
6317	if (cmdlen >= MAXPATHLEN * 2 ||
6318	    (*pipef = popen(cmd_buf, "w")) == NULL) {
6319		(void) fprintf(stderr, gettext("error\n"));
6320		exit(1);
6321	}
6322
6323	if (close(Ofile) != 0)
6324		msg(EXTN, "close error");
6325	Ofile = fileno(*pipef);
6326
6327	free(cmd_buf);
6328}
6329
6330/*
6331 * if the bar archive spans multiple volumes, read in the header that
6332 * describes the next volume.
6333 */
6334static void
6335skip_bar_volhdr(void)
6336{
6337	char *buff;
6338	union b_block *tmp_hdr;
6339
6340	buff = e_zalloc(E_EXIT, (uint_t)Bufsize);
6341
6342	if (g_read(Device, Archive, buff, Bufsize) < 0) {
6343		(void) fprintf(stderr, gettext(
6344		    "error in skip_bar_volhdr\n"));
6345	} else {
6346
6347		tmp_hdr = (union b_block *)buff;
6348		if (tmp_hdr->dbuf.bar_magic[0] == BAR_VOLUME_MAGIC) {
6349
6350			if (bar_Vhdr == NULL) {
6351				bar_Vhdr = e_zalloc(E_EXIT, TBLOCK);
6352			}
6353			(void) memcpy(&(bar_Vhdr->dbuf),
6354			    &(tmp_hdr->dbuf), TBLOCK);
6355		} else {
6356			(void) fprintf(stderr,
6357			    gettext("cpio error: cannot read bar volume "
6358			    "header\n"));
6359			exit(1);
6360		}
6361
6362		(void) sscanf(bar_Vhdr->dbuf.mode, "%8lo",
6363		    &Gen_bar_vol.g_mode);
6364		(void) sscanf(bar_Vhdr->dbuf.uid, "%8lo",
6365		    &Gen_bar_vol.g_uid);
6366		(void) sscanf(bar_Vhdr->dbuf.gid, "%8lo",
6367		    &Gen_bar_vol.g_gid);
6368		(void) sscanf(bar_Vhdr->dbuf.size, "%12llo",
6369		    (u_off_t *)&Gen_bar_vol.g_filesz);
6370		(void) sscanf(bar_Vhdr->dbuf.mtime, "%12lo",
6371		    &Gen_bar_vol.g_mtime);
6372		(void) sscanf(bar_Vhdr->dbuf.chksum, "%8lo",
6373		    &Gen_bar_vol.g_cksum);
6374		if (bar_Vhdr->dbuf.compressed == '1')
6375			Compressed = 1;
6376		else
6377			Compressed = 0;
6378	}
6379
6380	/*
6381	 * Now put the rest of the bytes read in into the data buffer.
6382	 */
6383	(void) memcpy(Buffr.b_in_p, &buff[512], (Bufsize - 512));
6384	Buffr.b_in_p += (Bufsize - 512);
6385	Buffr.b_cnt += (long)(Bufsize - 512);
6386
6387	free(buff);
6388}
6389
6390/*
6391 * check the linkflag which indicates the type of the file to be extracted,
6392 * invoke the corresponding routine to extract the file.
6393 */
6394static void
6395bar_file_in(void)
6396{
6397	/*
6398	 * the file is a directory
6399	 */
6400	if (Adir) {
6401		if (ckname(1) != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
6402			VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
6403		}
6404		return;
6405	}
6406
6407	switch (bar_linkflag) {
6408	case REGTYPE:
6409		/* regular file */
6410		if ((ckname(1) == F_SKIP) ||
6411		    (Ofile = openout(G_p->g_dirfd)) < 0) {
6412			data_in(P_SKIP);
6413		} else {
6414			data_in(P_PROC);
6415		}
6416		break;
6417	case LNKTYPE:
6418		/* hard link */
6419		if (ckname(1) == F_SKIP) {
6420			break;
6421		}
6422		(void) creat_lnk(G_p->g_dirfd, bar_linkname, G_p->g_nam_p);
6423		break;
6424	case SYMTYPE:
6425		/* symbolic link */
6426		if ((ckname(1) == F_SKIP) ||
6427		    (Ofile = openout(G_p->g_dirfd)) < 0) {
6428			data_in(P_SKIP);
6429		} else {
6430			data_in(P_PROC);
6431		}
6432		break;
6433	case CHRTYPE:
6434		/* character device or FIFO */
6435		if (ckname(1) != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
6436			VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
6437		}
6438		break;
6439	default:
6440		(void) fprintf(stderr, gettext("error: unknown file type\n"));
6441		break;
6442	}
6443}
6444
6445
6446/*
6447 * This originally came from libgenIO/g_init.c
6448 * XXX	And it is very broken.
6449 */
6450
6451/* #include <sys/statvfs.h> */
6452#include <ftw.h>
6453/* #include <libgenIO.h> */
6454#define	G_TM_TAPE	1	/* Tapemaster controller    */
6455#define	G_XY_DISK	3	/* xy disks		*/
6456#define	G_SD_DISK	7	/* scsi sd disk		*/
6457#define	G_XT_TAPE	8	/* xt tapes		*/
6458#define	G_SF_FLOPPY	9	/* sf floppy		*/
6459#define	G_XD_DISK	10	/* xd disks		*/
6460#define	G_ST_TAPE	11	/* scsi tape		*/
6461#define	G_NS		12	/* noswap pseudo-dev	*/
6462#define	G_RAM		13	/* ram pseudo-dev	*/
6463#define	G_FT		14	/* tftp			*/
6464#define	G_HD		15	/* 386 network disk	*/
6465#define	G_FD		16	/* 386 AT disk		*/
6466#define	G_FILE		28	/* file, not a device	*/
6467#define	G_NO_DEV	29	/* device does not require special treatment */
6468#define	G_DEV_MAX	30	/* last valid device type */
6469
6470/*
6471 * g_init: Determine the device being accessed, set the buffer size,
6472 * and perform any device specific initialization. Since at this point
6473 * Sun has no system call to read the configuration, the major numbers
6474 * are assumed to be static and types are figured out as such. However,
6475 * as a rough estimate, the buffer size for all types is set to 512
6476 * as a default.
6477 */
6478
6479static int
6480g_init(int *devtype, int *fdes)
6481{
6482	int bufsize;
6483	struct stat st_buf;
6484	struct statvfs stfs_buf;
6485
6486	*devtype = G_NO_DEV;
6487	bufsize = -1;
6488	if (fstat(*fdes, &st_buf) == -1)
6489		return (-1);
6490	if (!S_ISCHR(st_buf.st_mode) && !S_ISBLK(st_buf.st_mode)) {
6491		if (S_ISFIFO(st_buf.st_mode)) {
6492			bufsize = 512;
6493		} else {
6494			/* find block size for this file system */
6495			*devtype = G_FILE;
6496			if (fstatvfs(*fdes, &stfs_buf) < 0) {
6497					bufsize = -1;
6498					errno = ENODEV;
6499			} else
6500				bufsize = stfs_buf.f_bsize;
6501		}
6502
6503		return (bufsize);
6504
6505	/*
6506	 * We'll have to add a remote attribute to stat but this
6507	 * should work for now.
6508	 */
6509	} else if (st_buf.st_dev & 0x8000)	/* if remote  rdev */
6510		return (512);
6511
6512	bufsize = 512;
6513
6514	if (Hdr_type == BAR) {
6515		if (is_tape(*fdes)) {
6516			bufsize = BAR_TAPE_SIZE;
6517			(void) fprintf(stderr, "Archiving to tape");
6518			(void) fprintf(stderr, " blocking factor 126\n");
6519		} else if (is_floppy(*fdes)) {
6520			bufsize = BAR_FLOPPY_SIZE;
6521			(void) fprintf(stderr, "Archiving to floppy");
6522			(void) fprintf(stderr, " blocking factor 18\n");
6523		}
6524	}
6525
6526	return (bufsize);
6527}
6528
6529/*
6530 * This originally came from libgenIO/g_read.c
6531 */
6532
6533/*
6534 * g_read: Read nbytes of data from fdes (of type devtype) and place
6535 * data in location pointed to by buf.  In case of end of medium,
6536 * translate (where necessary) device specific EOM indications into
6537 * the generic EOM indication of rv = -1, errno = ENOSPC.
6538 */
6539
6540static int
6541g_read(int devtype, int fdes, char *buf, unsigned nbytes)
6542{
6543	int rv;
6544
6545	if (devtype < 0 || devtype >= G_DEV_MAX) {
6546		errno = ENODEV;
6547		return (-1);
6548	}
6549
6550	rv = read(fdes, buf, nbytes);
6551
6552	/* st devices return 0 when no space left */
6553	if ((rv == 0 && errno == 0 && Hdr_type != BAR) ||
6554	    (rv == -1 && errno == EIO)) {
6555		errno = 0;
6556		rv = 0;
6557	}
6558
6559	return (rv);
6560}
6561
6562/*
6563 * This originally came from libgenIO/g_write.c
6564 */
6565
6566/*
6567 * g_write: Write nbytes of data to fdes (of type devtype) from
6568 * the location pointed to by buf.  In case of end of medium,
6569 * translate (where necessary) device specific EOM indications into
6570 * the generic EOM indication of rv = -1, errno = ENOSPC.
6571 */
6572
6573static int
6574g_write(int devtype, int fdes, char *buf, unsigned nbytes)
6575{
6576	int rv;
6577
6578	if (devtype < 0 || devtype >= G_DEV_MAX) {
6579		errno = ENODEV;
6580		return (-1);
6581	}
6582
6583	rv = write(fdes, buf, nbytes);
6584
6585	/* st devices return 0 when no more space left */
6586	if ((rv == 0 && errno == 0) || (rv == -1 && errno == EIO)) {
6587		errno = ENOSPC;
6588		rv = -1;
6589	}
6590
6591	return (rv);
6592}
6593
6594/*
6595 * Test for tape
6596 */
6597
6598static int
6599is_tape(int fd)
6600{
6601	struct mtget stuff;
6602
6603	/*
6604	 * try to do a generic tape ioctl, just to see if
6605	 * the thing is in fact a tape drive(er).
6606	 */
6607	if (ioctl(fd, MTIOCGET, &stuff) != -1) {
6608		/* the ioctl succeeded, must have been a tape */
6609		return (1);
6610	}
6611	return (0);
6612}
6613
6614/*
6615 * Test for floppy
6616 */
6617
6618static int
6619is_floppy(int fd)
6620{
6621	struct fd_char stuff;
6622
6623	/*
6624	 * try to get the floppy drive characteristics, just to see if
6625	 * the thing is in fact a floppy drive(er).
6626	 */
6627	if (ioctl(fd, FDIOGCHAR, &stuff) != -1) {
6628		/* the ioctl succeeded, must have been a floppy */
6629		return (1);
6630	}
6631
6632	return (0);
6633}
6634
6635/*
6636 * New functions for ACLs and other security attributes
6637 */
6638
6639/*
6640 * The function appends the new security attribute info to the end of
6641 * existing secinfo.
6642 */
6643static int
6644append_secattr(
6645	char		**secinfo,	/* existing security info */
6646	int		*secinfo_len,	/* length of existing security info */
6647	acl_t		*aclp) 	/* new attribute data pointer */
6648{
6649	char	*new_secinfo;
6650	char	*attrtext;
6651	size_t	newattrsize;
6652	int	oldsize;
6653
6654	/* no need to add */
6655	if (aclp == NULL) {
6656		return (0);
6657	}
6658
6659	switch (acl_type(aclp)) {
6660	case ACLENT_T:
6661	case ACE_T:
6662		/* LINTED alignment */
6663		attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT);
6664		if (attrtext == NULL) {
6665			(void) fprintf(stderr, "acltotext failed\n");
6666			return (-1);
6667		}
6668		/* header: type + size = 8 */
6669		newattrsize = 8 + strlen(attrtext) + 1;
6670		attr = e_zalloc(E_NORMAL, newattrsize);
6671		if (attr == NULL) {
6672			(void) fprintf(stderr, "can't allocate memory\n");
6673			return (-1);
6674		}
6675		attr->attr_type = (acl_type(aclp) == ACLENT_T) ?
6676		    UFSD_ACL : ACE_ACL;
6677		/* acl entry count */
6678		(void) sprintf(attr->attr_len, "%06o", acl_cnt(aclp));
6679		(void) strcpy((char *)&attr->attr_info[0], attrtext);
6680		free(attrtext);
6681		break;
6682
6683		/* SunFed's case goes here */
6684
6685	default:
6686		(void) fprintf(stderr, "unrecognized attribute type\n");
6687		return (-1);
6688	}
6689
6690	/* old security info + new attr header(8) + new attr */
6691	oldsize = *secinfo_len;
6692	*secinfo_len += newattrsize;
6693	new_secinfo = e_zalloc(E_NORMAL, (uint_t)*secinfo_len);
6694	if (new_secinfo == NULL) {
6695		(void) fprintf(stderr, "can't allocate memory\n");
6696		*secinfo_len -= newattrsize;
6697		return (-1);
6698	}
6699
6700	(void) memcpy(new_secinfo, *secinfo, oldsize);
6701	(void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6702
6703	free(*secinfo);
6704	*secinfo = new_secinfo;
6705	return (0);
6706}
6707
6708static void
6709write_ancillary(char *secinfo, int len)
6710{
6711	long    pad;
6712	long    cnt;
6713
6714	/* Just tranditional permissions or no security attribute info */
6715	if (len == 0) {
6716		return;
6717	}
6718
6719	/* write out security info */
6720	while (len > 0) {
6721		cnt = (unsigned)(len > CPIOBSZ) ? CPIOBSZ : len;
6722		FLUSH(cnt);
6723		errno = 0;
6724		(void) memcpy(Buffr.b_in_p, secinfo, (unsigned)cnt);
6725		Buffr.b_in_p += cnt;
6726		Buffr.b_cnt += (long)cnt;
6727		len -= (long)cnt;
6728	}
6729	pad = (Pad_val + 1 - (cnt & Pad_val)) & Pad_val;
6730	if (pad != 0) {
6731		FLUSH(pad);
6732		(void) memcpy(Buffr.b_in_p, Empty, pad);
6733		Buffr.b_in_p += pad;
6734		Buffr.b_cnt += pad;
6735	}
6736}
6737
6738static int
6739remove_dir(char *path)
6740{
6741	DIR		*name;
6742	struct dirent	*direct;
6743	struct stat	sbuf;
6744	char		*path_copy;
6745
6746#define	MSG1	"remove_dir() failed to stat(\"%s\") "
6747#define	MSG2	"remove_dir() failed to remove_dir(\"%s\") "
6748#define	MSG3	"remove_dir() failed to unlink(\"%s\") "
6749
6750	/*
6751	 * Open the directory for reading.
6752	 */
6753	if ((name = opendir(path)) == NULL) {
6754		msg(ERRN, "remove_dir() failed to opendir(\"%s\") ", path);
6755		return (-1);
6756	}
6757
6758	if (chdir(path) == -1) {
6759		msg(ERRN, "remove_dir() failed to chdir(\"%s\") ", path);
6760		return (-1);
6761	}
6762
6763	/*
6764	 * Read every directory entry.
6765	 */
6766	while ((direct = readdir(name)) != NULL) {
6767		/*
6768		 * Ignore "." and ".." entries.
6769		 */
6770		if (strcmp(direct->d_name, ".") == 0 ||
6771		    strcmp(direct->d_name, "..") == 0)
6772			continue;
6773
6774			if (lstat(direct->d_name, &sbuf) == -1) {
6775				msg(ERRN, MSG1, direct->d_name);
6776				(void) closedir(name);
6777			return (-1);
6778		}
6779
6780		if (S_ISDIR(sbuf.st_mode)) {
6781			if (remove_dir(direct->d_name) == -1) {
6782				msg(ERRN, MSG2, direct->d_name);
6783				(void) closedir(name);
6784				return (-1);
6785			}
6786		} else {
6787			if (unlink(direct->d_name) == -1) {
6788				msg(ERRN, MSG3, direct->d_name);
6789				(void) closedir(name);
6790				return (-1);
6791			}
6792		}
6793
6794	}
6795
6796	/*
6797	 * Close the directory we just finished reading.
6798	 */
6799	(void) closedir(name);
6800
6801	/*
6802	 * Change directory to the parent directory...
6803	 */
6804	if (chdir("..") == -1) {
6805		msg(ERRN, "remove_dir() failed to chdir(\"..\") ");
6806		return (-1);
6807	}
6808
6809	/*
6810	 * ...and finally remove the directory; note we have to
6811	 * make a copy since basename is free to modify its input.
6812	 */
6813	path_copy = e_strdup(E_NORMAL, path);
6814	if (path_copy == NULL) {
6815		msg(ERRN, "cannot strdup() the directory pathname ");
6816		return (-1);
6817	}
6818
6819	if (rmdir(basename(path_copy)) == -1) {
6820		free(path_copy);
6821		msg(ERRN, "remove_dir() failed to rmdir(\"%s\") ", path);
6822		return (-1);
6823	}
6824
6825	free(path_copy);
6826	return (0);
6827
6828}
6829
6830static int
6831save_cwd(void)
6832{
6833	return (open(".", O_RDONLY));
6834}
6835
6836static void
6837rest_cwd(int cwd)
6838{
6839	(void) fchdir(cwd);
6840	(void) close(cwd);
6841}
6842
6843#if defined(O_XATTR)
6844static void
6845xattrs_out(int (*func)())
6846{
6847	int dirpfd;
6848	int filefd;
6849	DIR *dirp;
6850	struct dirent *dp;
6851	int slen;
6852	char *namep, *savenamep;
6853
6854	if (pathconf(G_p->g_nam_p, _PC_XATTR_EXISTS) != 1) {
6855		return;
6856	}
6857
6858	/*
6859	 * If aclp still exists then free it since it is was set when base
6860	 * file was extracted.
6861	 */
6862	if (aclp != NULL) {
6863		acl_free(aclp);
6864		aclp = NULL;
6865		acl_is_set = 0;
6866	}
6867
6868	Gen.g_dirfd = attropen(G_p->g_nam_p, ".", O_RDONLY);
6869	if (Gen.g_dirfd == -1) {
6870		msg(ERRN, "Cannot open attribute directory of file \"%s\"",
6871		    G_p->g_nam_p);
6872		return;
6873
6874	}
6875	savenamep = G_p->g_nam_p;
6876
6877	if ((dirpfd = dup(Gen.g_dirfd)) == -1)  {
6878		msg(ERRN, "Cannot dup(2) attribute directory descriptor");
6879		return;
6880	}
6881
6882	if ((dirp = fdopendir(dirpfd)) == (DIR *)NULL) {
6883		msg(ERRN, "Cannot fdopendir(2) directory file descriptor");
6884		return;
6885	}
6886
6887	while ((dp = readdir(dirp)) != (struct dirent *)NULL) {
6888		if (strcmp(dp->d_name, "..") == 0) {
6889			continue;
6890		}
6891
6892		if (strcmp(dp->d_name, ".") == 0) {
6893			Hiddendir = 1;
6894		} else {
6895			Hiddendir = 0;
6896		}
6897
6898		Gen.g_attrnam_p = dp->d_name;
6899
6900		if (STAT(Gen.g_dirfd, Gen.g_nam_p, &SrcSt) == -1) {
6901			msg(ERRN,
6902			    "Could not fstatat(2) attribute \"%s\" of"
6903			    " file \"%s\"", dp->d_name, savenamep);
6904			continue;
6905		}
6906
6907		if (Use_old_stat) {
6908			OldSt = convert_to_old_stat(&SrcSt,
6909			    Gen.g_nam_p, Gen.g_attrnam_p);
6910
6911			if (OldSt == NULL) {
6912				msg(ERRN,
6913				    "Could not convert to old stat format");
6914				continue;
6915			}
6916		}
6917
6918		Gen.g_attrfnam_p = savenamep;
6919
6920		/*
6921		 * Set up dummy header name
6922		 *
6923		 * One piece is written with .hdr, which
6924		 * contains the actual xattr hdr or pathing information
6925		 * then the name is updated to drop the .hdr off
6926		 * and the actual file itself is archived.
6927		 */
6928		slen = strlen(Gen.g_attrnam_p) + strlen(DEVNULL) +
6929		    strlen(XATTRHDR) + 1;
6930		if ((namep = e_zalloc(E_NORMAL, slen)) == (char *)NULL) {
6931			msg(ERRN, "Could not calloc memory for attribute name");
6932			continue;
6933		}
6934		(void) sprintf(namep, "%s/%s%s",
6935		    DEVNULL, Gen.g_attrnam_p, XATTRHDR);
6936		Gen.g_nam_p = namep;
6937
6938		/*
6939		 * Get attribute's ACL info: don't bother allocating space
6940		 * if there are only standard permissions, i.e. ACL count < 4
6941		 */
6942		if (Pflag) {
6943			filefd = openat(Gen.g_dirfd, dp->d_name, O_RDONLY);
6944			if (filefd == -1) {
6945				msg(ERRN,
6946				    "Could not open attribute \"%s\" of"
6947				    " file \"%s\"", dp->d_name, savenamep);
6948				free(namep);
6949				continue;
6950			}
6951			if (facl_get(filefd, ACL_NO_TRIVIAL, &aclp) != 0) {
6952				msg(ERRN,
6953				    "Error with acl() on %s",
6954				    Gen.g_nam_p);
6955			}
6956			(void) close(filefd);
6957		}
6958		(void) creat_hdr();
6959		(void) (*func)();
6960		if (Gen.g_passdirfd != -1) {
6961			(void) close(Gen.g_passdirfd);
6962			Gen.g_passdirfd = -1;
6963		}
6964		Gen.g_attrnam_p = (char *)NULL;
6965		Gen.g_attrfnam_p = (char *)NULL;
6966		Gen.g_linktoattrfnam_p = (char *)NULL;
6967		Gen.g_linktoattrnam_p = (char *)NULL;
6968		if (aclp != NULL) {
6969			acl_free(aclp);
6970			aclp = NULL;
6971			acl_is_set = 0;
6972		}
6973		free(namep);
6974	}
6975
6976	(void) closedir(dirp);
6977	(void) close(Gen.g_dirfd);
6978	Gen.g_dirfd = -1;
6979}
6980#else
6981static void
6982xattrs_out(int (*func)())
6983{
6984}
6985#endif
6986
6987/*
6988 * Return the parent directory of a given path.
6989 *
6990 * Examples:
6991 * /usr/tmp return /usr
6992 * /usr/tmp/file return /usr/tmp
6993 * /  returns .
6994 * /usr returns /
6995 * file returns .
6996 *
6997 * dir is assumed to be at least as big as path.
6998 */
6999static void
7000get_parent(char *path, char *dir)
7001{
7002	char *s;
7003	char tmpdir[PATH_MAX + 1];
7004
7005	if (strlen(path) > PATH_MAX) {
7006		msg(EXT, "pathname is too long");
7007	}
7008	(void) strcpy(tmpdir, path);
7009	chop_endslashes(tmpdir);
7010
7011	if ((s = strrchr(tmpdir, '/')) == NULL) {
7012		(void) strcpy(dir, ".");
7013	} else {
7014		s = skipslashes(s, tmpdir);
7015		*s = '\0';
7016		if (s == tmpdir)
7017			(void) strcpy(dir, "/");
7018		else
7019			(void) strcpy(dir, tmpdir);
7020	}
7021}
7022
7023#if defined(O_XATTR)
7024#define	ROUNDTOTBLOCK(a)		((a + (TBLOCK -1)) & ~(TBLOCK -1))
7025
7026static void
7027prepare_xattr_hdr(
7028	char		**attrbuf,
7029	char		*filename,
7030	char		*attrname,
7031	char		typeflag,
7032	struct Lnk	*linkinfo,
7033	int		*rlen)
7034{
7035	char			*bufhead;	/* ptr to full buffer */
7036	struct xattr_hdr 	*hptr;		/* ptr to header in bufhead */
7037	struct xattr_buf	*tptr;		/* ptr to pathing pieces */
7038	int			totalen;	/* total buffer length */
7039	int			len;		/* length returned to user */
7040	int			stringlen;	/* length of filename + attr */
7041	int			linkstringlen;	/* ditto in link section */
7042	int			complen;	/* length of pathing section */
7043	int			linklen;	/* length of link section */
7044
7045
7046	/*
7047	 * Release previous buffer if any.
7048	 */
7049
7050	if (*attrbuf != (char *)NULL) {
7051		free(*attrbuf);
7052		*attrbuf = NULL;
7053	}
7054
7055	/*
7056	 * First add in fixed size stuff
7057	 */
7058	len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7059
7060	/*
7061	 * Add space for two nulls
7062	 */
7063	stringlen = strlen(attrname) + strlen(filename) + 2;
7064	complen = stringlen + sizeof (struct xattr_buf);
7065
7066	len += stringlen;
7067
7068	/*
7069	 * Now add on space for link info if any
7070	 */
7071
7072	if (linkinfo != NULL) {
7073		/*
7074		 * Again add space for two nulls
7075		 */
7076		linkstringlen = strlen(linkinfo->L_gen.g_attrfnam_p) +
7077		    strlen(linkinfo->L_gen.g_attrnam_p) + 2;
7078		len += linkstringlen;
7079	}
7080
7081	/*
7082	 * Now add padding to end to fill out TBLOCK
7083	 *
7084	 * Function returns size of real data and not size + padding.
7085	 */
7086
7087	totalen = ROUNDTOTBLOCK(len);
7088	bufhead = e_zalloc(E_EXIT, totalen);
7089
7090	/*
7091	 * Now we can fill in the necessary pieces
7092	 */
7093
7094	if (linkinfo != (struct Lnk *)NULL) {
7095		linklen = linkstringlen + (sizeof (struct xattr_buf));
7096	} else {
7097		linklen = 0;
7098	}
7099
7100	/*
7101	 * first fill in the fixed header
7102	 */
7103	hptr = (struct xattr_hdr *)bufhead;
7104	(void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7105	(void) sprintf(hptr->h_component_len, "%0*d",
7106	    sizeof (hptr->h_component_len) - 1, complen);
7107	(void) sprintf(hptr->h_link_component_len, "%0*d",
7108	    sizeof (hptr->h_link_component_len) - 1, linklen);
7109	(void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7110
7111	/*
7112	 * Now fill in the filename + attrnames section
7113	 */
7114
7115	tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7116	(void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7117	    stringlen);
7118	(void) strcpy(tptr->h_names, filename);
7119	(void) strcpy(&tptr->h_names[strlen(filename) + 1], attrname);
7120	tptr->h_typeflag = typeflag;
7121
7122	/*
7123	 * Now fill in the optional link section if we have one
7124	 */
7125
7126	if (linkinfo != (struct Lnk *)NULL) {
7127		tptr = (struct xattr_buf *)(bufhead +
7128		    sizeof (struct xattr_hdr) + complen);
7129
7130		(void) sprintf(tptr->h_namesz, "%0*d",
7131		    sizeof (tptr->h_namesz) - 1, linkstringlen);
7132		(void) strcpy(tptr->h_names, linkinfo->L_gen.g_attrfnam_p);
7133		(void) strcpy(
7134		    &tptr->h_names[strlen(linkinfo->L_gen.g_attrfnam_p) + 1],
7135		    linkinfo->L_gen.g_attrnam_p);
7136		tptr->h_typeflag = typeflag;
7137	}
7138	*attrbuf = (char *)bufhead;
7139	*rlen = len;
7140}
7141#endif /* O_XATTR */
7142
7143static char
7144tartype(int type)
7145{
7146	switch (type) {
7147
7148	case S_IFDIR:
7149		return (DIRTYPE);
7150
7151	case S_IFLNK:
7152		return (SYMTYPE);
7153
7154	case S_IFIFO:
7155		return (FIFOTYPE);
7156
7157	case S_IFCHR:
7158		return (CHRTYPE);
7159
7160	case S_IFBLK:
7161		return (BLKTYPE);
7162
7163	case S_IFREG:
7164		return (REGTYPE);
7165
7166	default:
7167		return ('\0');
7168	}
7169}
7170
7171#if defined(O_XATTR)
7172static int
7173openfile(int omode)
7174{
7175
7176	if (G_p->g_attrnam_p != (char *)NULL) {
7177		return (attropen(G_p->g_attrfnam_p, G_p->g_attrnam_p, omode));
7178	} else {
7179		return (openat(G_p->g_dirfd,
7180		    get_component(G_p->g_nam_p), omode));
7181	}
7182}
7183#else
7184static int
7185openfile(int omode)
7186{
7187	return (openat(G_p->g_dirfd, get_component(G_p->g_nam_p), omode));
7188}
7189#endif
7190
7191#if defined(O_XATTR)
7192static int
7193read_xattr_hdr()
7194{
7195	off_t		bytes;
7196	int		comp_len, link_len;
7197	int		namelen;
7198	int		cnt;
7199	char		*tp;
7200	int		pad;
7201
7202	/*
7203	 * Include any padding in the read.  We need to be positioned
7204	 * at beginning of next header.
7205	 */
7206
7207	bytes = Gen.g_filesz;
7208
7209	if ((xattrhead = e_zalloc(E_NORMAL, (size_t)bytes)) == NULL) {
7210		(void) fprintf(stderr, gettext(
7211		    "Insufficient memory for extended attribute\n"));
7212		return (1);
7213	}
7214
7215	tp = (char *)xattrhead;
7216	while (bytes > 0) {
7217		cnt = (int)(bytes > CPIOBSZ) ? CPIOBSZ : bytes;
7218		FILL(cnt);
7219		(void) memcpy(tp, Buffr.b_out_p, cnt);
7220		tp += cnt;
7221		Buffr.b_out_p += cnt;
7222		Buffr.b_cnt -= (off_t)cnt;
7223		bytes -= (off_t)cnt;
7224	}
7225
7226	pad = (Pad_val + 1 - (Gen.g_filesz & Pad_val)) &
7227	    Pad_val;
7228	if (pad != 0) {
7229		FILL(pad);
7230		Buffr.b_out_p += pad;
7231		Buffr.b_cnt -= (off_t)pad;
7232	}
7233
7234	/*
7235	 * Validate that we can handle header format
7236	 */
7237
7238	if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
7239		(void) fprintf(stderr,
7240		    gettext("Unknown extended attribute format encountered\n"));
7241		(void) fprintf(stderr,
7242		    gettext("Disabling extended attribute header parsing\n"));
7243		xattrbadhead = 1;
7244		return (1);
7245	}
7246	(void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
7247	(void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
7248	xattrp = (struct xattr_buf *)(((char *)xattrhead) +
7249	    sizeof (struct xattr_hdr));
7250	(void) sscanf(xattrp->h_namesz, "%7d", &namelen);
7251	if (link_len > 0) {
7252		xattr_linkp = (struct xattr_buf *)((int)xattrp + (int)comp_len);
7253	} else {
7254		xattr_linkp = NULL;
7255	}
7256
7257	return (0);
7258}
7259#endif
7260
7261static mode_t
7262attrmode(char type)
7263{
7264	mode_t mode;
7265
7266	switch (type) {
7267	case '\0':
7268	case REGTYPE:
7269	case LNKTYPE:
7270		mode = S_IFREG;
7271		break;
7272
7273	case SYMTYPE:
7274		mode = S_IFLNK;
7275		break;
7276
7277	case CHRTYPE:
7278		mode = S_IFCHR;
7279		break;
7280	case BLKTYPE:
7281		mode = S_IFBLK;
7282		break;
7283	case DIRTYPE:
7284		mode = S_IFDIR;
7285		break;
7286	case FIFOTYPE:
7287		mode = S_IFIFO;
7288		break;
7289	case CONTTYPE:
7290	default:
7291		mode = 0;
7292	}
7293
7294	return (mode);
7295}
7296
7297#if defined(O_XATTR)
7298static char *
7299get_component(char *path)
7300{
7301	char *ptr;
7302
7303	ptr = strrchr(path, '/');
7304	if (ptr == NULL) {
7305		return (path);
7306	} else {
7307		/*
7308		 * Handle trailing slash
7309		 */
7310		if (*(ptr + 1) == '\0')
7311			return (ptr);
7312		else
7313			return (ptr + 1);
7314	}
7315}
7316#else
7317static char *
7318get_component(char *path)
7319{
7320	return (path);
7321}
7322#endif
7323
7324static int
7325open_dir(char *name)
7326{
7327	int fd = -1;
7328	int cnt = 0;
7329	char *dir;
7330
7331	dir = e_zalloc(E_EXIT, strlen(name) + 1);
7332
7333	/*
7334	 * open directory; creating missing directories along the way.
7335	 */
7336	get_parent(name, dir);
7337	do {
7338		fd = open(dir, O_RDONLY);
7339		if (fd != -1) {
7340			free(dir);
7341			return (fd);
7342		}
7343		cnt++;
7344	} while (cnt <= 1 && missdir(name) == 0);
7345
7346	free(dir);
7347	return (-1);
7348}
7349
7350static int
7351open_dirfd()
7352{
7353#ifdef O_XATTR
7354	if ((Args & OCt) == 0) {
7355		close_dirfd();
7356		if (G_p->g_attrnam_p != (char *)NULL) {
7357			G_p->g_dirfd = attropen(G_p->g_attrfnam_p,
7358			    ".", O_RDONLY);
7359			if (G_p->g_dirfd == -1 && (Args & (OCi | OCp))) {
7360				G_p->g_dirfd =
7361				    retry_attrdir_open(G_p->g_attrfnam_p);
7362				if (G_p->g_dirfd == -1) {
7363					msg(ERRN,
7364					    "Cannot open attribute"
7365					    " directory of file %s",
7366					    G_p->g_attrfnam_p);
7367					return (1);
7368				}
7369			}
7370		} else {
7371			G_p->g_dirfd = open_dir(G_p->g_nam_p);
7372			if (G_p->g_dirfd == -1) {
7373				msg(ERRN,
7374				    "Cannot open/create %s", G_p->g_nam_p);
7375				return (1);
7376			}
7377		}
7378	} else {
7379		G_p->g_dirfd = -1;
7380	}
7381#else
7382	G_p->g_dirfd = -1;
7383#endif
7384	return (0);
7385}
7386
7387static void
7388close_dirfd()
7389{
7390	if (G_p->g_dirfd != -1) {
7391		(void) close(G_p->g_dirfd);
7392		G_p->g_dirfd = -1;
7393	}
7394}
7395
7396static void
7397write_xattr_hdr()
7398{
7399	char *attrbuf = NULL;
7400	int  attrlen = 0;
7401	char *namep;
7402	struct Lnk *tl_p, *linkinfo;
7403
7404
7405	/*
7406	 * namep was allocated in xattrs_out.  It is big enough to hold
7407	 * either the name + .hdr on the end or just the attr name
7408	 */
7409
7410#if defined(O_XATTR)
7411	namep = Gen.g_nam_p;
7412	(void) creat_hdr();
7413
7414
7415	if (Args & OCo) {
7416		linkinfo = NULL;
7417		tl_p = Lnk_hd.L_nxt_p;
7418		while (tl_p != &Lnk_hd) {
7419			if (tl_p->L_gen.g_ino == G_p->g_ino &&
7420			    tl_p->L_gen.g_dev == G_p->g_dev) {
7421					linkinfo = tl_p;
7422					break; /* found */
7423			}
7424			tl_p = tl_p->L_nxt_p;
7425		}
7426		prepare_xattr_hdr(&attrbuf, Gen.g_attrfnam_p,
7427		    Gen.g_attrnam_p,
7428		    (linkinfo == (struct Lnk *)NULL) ?
7429		    tartype(Gen.g_mode & Ftype) : LNKTYPE,
7430		    linkinfo, &attrlen);
7431		Gen.g_filesz = attrlen;
7432		write_hdr(ARCHIVE_XATTR, (off_t)attrlen);
7433		(void) sprintf(namep, "%s/%s", DEVNULL, Gen.g_attrnam_p);
7434		(void) write_ancillary(attrbuf, attrlen);
7435	}
7436
7437	(void) creat_hdr();
7438#endif
7439}
7440
7441static int
7442retry_attrdir_open(char *name)
7443{
7444	int dirfd = -1;
7445	struct timeval times[2];
7446	mode_t newmode;
7447	struct stat parentstat;
7448	acl_t *aclp = NULL;
7449	int error;
7450
7451	/*
7452	 * We couldn't get to attrdir. See if its
7453	 * just a mode problem on the parent file.
7454	 * for example: a mode such as r-xr--r--
7455	 * won't let us create an attribute dir
7456	 * if it doesn't already exist.
7457	 *
7458	 * If file has a non-trivial ACL, then save it
7459	 * off so that we can place it back on after doing
7460	 * chmod's.
7461	 */
7462
7463	if (stat(name, &parentstat) == -1) {
7464		msg(ERRN, "Cannot stat file %s", name);
7465		return (-1);
7466	}
7467
7468	if ((error = acl_get(name, ACL_NO_TRIVIAL, &aclp)) != 0) {
7469		msg(ERRN,
7470		    "Failed to retrieve ACL on %s %s", name, strerror(errno));
7471		return (-1);
7472	}
7473
7474	newmode = S_IWUSR | parentstat.st_mode;
7475	if (chmod(name, newmode) == -1) {
7476		msg(ERRN, "Cannot change mode of file %s to %o", name, newmode);
7477		if (aclp)
7478			acl_free(aclp);
7479		return (-1);
7480	}
7481
7482	dirfd = attropen(name, ".", O_RDONLY);
7483
7484	/*
7485	 * Don't print error here, caller will handle printing out
7486	 * can't open message.
7487	 */
7488
7489	/*
7490	 * Put mode back to original
7491	 */
7492	if (chmod(name, parentstat.st_mode) != 0) {
7493		msg(ERRN, "Cannot restore permissions of file %s to %o",
7494		    name, parentstat.st_mode);
7495	}
7496
7497	if (aclp) {
7498		error = acl_set(name, aclp);
7499		if (error) {
7500			msg(ERRN, "failed to set ACL on %s", name);
7501		}
7502		acl_free(aclp);
7503	}
7504	/*
7505	 * Put back time stamps
7506	 */
7507
7508	times[0].tv_sec = parentstat.st_atime;
7509	times[0].tv_usec = 0;
7510	times[1].tv_sec = parentstat.st_mtime;
7511	times[1].tv_usec = 0;
7512	if (utimes(name, times) != 0) {
7513		msg(ERRN, "Cannot reset timestamps on file %s");
7514	}
7515
7516	return (dirfd);
7517}
7518
7519/*
7520 * skip over extra slashes in string.
7521 *
7522 * For example:
7523 * /usr/tmp/////
7524 *
7525 * would return pointer at
7526 * /usr/tmp/////
7527 *         ^
7528 */
7529static char *
7530skipslashes(char *string, char *start)
7531{
7532	while ((string > start) && *(string - 1) == '/') {
7533		string--;
7534	}
7535
7536	return (string);
7537}
7538
7539static sl_info_t *
7540sl_info_alloc(void)
7541{
7542	static int num_left;
7543	static sl_info_t *slipool;
7544
7545	if (num_left > 0) {
7546		return (&slipool[--num_left]);
7547	}
7548	num_left = SL_INFO_ALLOC_CHUNK;
7549	slipool = e_zalloc(E_EXIT, sizeof (sl_info_t) * num_left);
7550	return (&slipool[--num_left]);
7551}
7552
7553/*
7554 * If a match for the key values was found in the tree, return a pointer to it.
7555 * If a match was not found, insert it and return a pointer to it.  This is
7556 * based on Knuth's Algorithm A in Vol 3, section 6.2.3.
7557 */
7558
7559sl_info_t *
7560sl_insert(dev_t device, ino_t inode)
7561{
7562	sl_info_t *p;		/* moves down the tree */
7563	sl_info_t *q;		/* scratch */
7564	sl_info_t *r;		/* scratch */
7565	sl_info_t *s;		/* pt where rebalancing may be needed */
7566	sl_info_t *t;		/* father of s */
7567	sl_info_t *head;
7568
7569	int a;			/* used to hold balance factors */
7570	int done;		/* loop control */
7571	int cmpflg;		/* used to hold the result of a comparison */
7572
7573	/* initialize */
7574
7575	head = sl_devhash_lookup(device);
7576
7577	if (head == NULL) {
7578		head = sl_info_alloc();
7579		head->llink = NULL;
7580		head->bal = 0;
7581
7582		p = head->rlink = sl_info_alloc();
7583		p->sl_ino = inode;
7584		p->sl_count = 0;
7585		p->bal = 0;
7586		p->llink = NULL;
7587		p->rlink = NULL;
7588		sl_devhash_insert(device, head);
7589		return (p);
7590	}
7591
7592	t = head;
7593	s = p = head->rlink;
7594
7595	/* compare */
7596
7597	for (done = 0; ! done; ) {
7598		switch (sl_compare(inode, p->sl_ino)) {
7599			case -1:
7600				/* move left */
7601
7602				q = p->llink;
7603
7604				if (q == NULL) {
7605					q = sl_info_alloc();
7606					p->llink = q;
7607					done = 1;
7608					continue;
7609				}
7610
7611				break;
7612
7613			case 0:
7614				/* found it */
7615				return (p);
7616				break;
7617
7618			case 1:
7619				/* move right */
7620
7621				q = p->rlink;
7622
7623				if (q == NULL) {
7624					q = sl_info_alloc();
7625					p->rlink = q;
7626					done = 1;
7627					continue;
7628				}
7629
7630				break;
7631		}
7632
7633		if (q->bal != 0) {
7634			t = p;
7635			s = q;
7636		}
7637
7638		p = q;
7639	}
7640
7641	/* insert */
7642
7643	q->sl_ino = inode;
7644	q->sl_count = 0;
7645	q->llink = q->rlink = NULL;
7646	q->bal = 0;
7647
7648	/* adjust balance factors */
7649
7650	if ((cmpflg = sl_compare(inode, s->sl_ino)) < 0) {
7651		r = p = s->llink;
7652	} else {
7653		r = p = s->rlink;
7654	}
7655
7656	while (p != q) {
7657		switch (sl_compare(inode, p->sl_ino)) {
7658			case -1:
7659				p->bal = -1;
7660				p = p->llink;
7661				break;
7662
7663			case 0:
7664				break;
7665
7666			case 1:
7667				p->bal = 1;
7668				p = p->rlink;
7669				break;
7670		}
7671	}
7672
7673	/* balancing act */
7674
7675	if (cmpflg < 0) {
7676		a = -1;
7677	} else {
7678		a = 1;
7679	}
7680
7681	if (s->bal == 0) {
7682		s->bal = a;
7683		head->llink = (sl_info_t *)((int)head->llink + 1);
7684		return (q);
7685	} else if (s->bal == -a) {
7686		s->bal = 0;
7687		return (q);
7688	}
7689
7690	/*
7691	 * (s->bal == a)
7692	 */
7693
7694	if (r->bal == a) {
7695		/* single rotation */
7696
7697		p = r;
7698
7699		if (a == -1) {
7700			s->llink = r->rlink;
7701			r->rlink = s;
7702		} else if (a == 1) {
7703			s->rlink = r->llink;
7704			r->llink = s;
7705		}
7706
7707		s->bal = r->bal = 0;
7708
7709	} else if (r->bal == -a) {
7710		/* double rotation */
7711
7712		if (a == -1) {
7713			p = r->rlink;
7714			r->rlink = p->llink;
7715			p->llink = r;
7716			s->llink = p->rlink;
7717			p->rlink = s;
7718		} else if (a == 1) {
7719			p = r->llink;
7720			r->llink = p->rlink;
7721			p->rlink = r;
7722			s->rlink = p->llink;
7723			p->llink = s;
7724		}
7725
7726		if (p->bal == 0) {
7727			s->bal = 0;
7728			r->bal = 0;
7729		} else if (p->bal == -a) {
7730			s->bal = 0;
7731			r->bal = a;
7732		} else if (p->bal == a) {
7733			s->bal = -a;
7734			r->bal = 0;
7735		}
7736
7737		p->bal = 0;
7738	}
7739
7740	/* finishing touch */
7741
7742	if (s == t->rlink) {
7743		t->rlink = p;
7744	} else {
7745		t->llink = p;
7746	}
7747
7748	return (q);
7749}
7750
7751/*
7752 * sl_numlinks: return the number of links that we saw during our preview.
7753 */
7754
7755static ulong_t
7756sl_numlinks(dev_t device, ino_t inode)
7757{
7758	sl_info_t *p = sl_search(device, inode);
7759
7760	if (p) {
7761		return (p->sl_count);
7762	} else {
7763		return (1);
7764	}
7765}
7766
7767/*
7768 * sl_preview_synonyms:  Read the file list from the input stream, remembering
7769 * each reference to each file.
7770 */
7771
7772static void
7773sl_preview_synonyms(void)
7774{
7775	char buf [APATH+1];
7776	char *s;
7777
7778	char *suffix = "/cpioXXXXXX";
7779	char *tmpdir = getenv("TMPDIR");
7780	int    tmpfd, islnk;
7781	FILE *tmpfile;
7782	char *tmpfname;
7783
7784	if (tmpdir == NULL || *tmpdir == '\0' ||
7785	    (strlen(tmpdir) + strlen(suffix)) > APATH) {
7786		struct statvfs tdsb;
7787
7788		tmpdir = "/var/tmp";
7789
7790		/* /var/tmp is read-only in the mini-root environment */
7791
7792		if (statvfs(tmpdir, &tdsb) == -1 || tdsb.f_flag & ST_RDONLY) {
7793			tmpdir = "/tmp";
7794		}
7795	}
7796
7797	tmpfname = e_zalloc(E_EXIT, strlen(tmpdir) + strlen(suffix) + 1);
7798
7799	(void) strcpy(tmpfname, tmpdir);
7800	(void) strcat(tmpfname, suffix);
7801
7802	if ((tmpfd = mkstemp(tmpfname)) == -1) {
7803		msg(EXTN, "cannot open tmpfile %s", tmpfname);
7804	}
7805
7806	if (unlink(tmpfname) == -1) {
7807		msg(EXTN, "cannot unlink tmpfile %s", tmpfname);
7808	}
7809
7810	if ((tmpfile = fdopen(tmpfd, "w+")) == NULL) {
7811		msg(EXTN, "cannot fdopen tmpfile %s", tmpfname);
7812	}
7813
7814	while ((s = fgets(buf, APATH+1, In_p)) != NULL) {
7815		size_t lastchar;
7816		struct stat sb;
7817
7818		if (fputs(buf, tmpfile) == EOF) {
7819			msg(EXTN, "problem writing to tmpfile %s", tmpfname);
7820		}
7821
7822		/* pre-process the name */
7823
7824		lastchar = strlen(s) - 1;
7825
7826		if (s[lastchar] != '\n' && lastchar == APATH - 1) {
7827			continue;
7828		} else {
7829			s[lastchar] = '\0';
7830		}
7831
7832		while (s[0] == '.' && s[1] == '/') {
7833			s += 2;
7834			while (s[0] == '/') {
7835				s++;
7836			}
7837		}
7838
7839		if (lstat(s, &sb) < 0) {
7840			continue;
7841		}
7842		islnk = 0;
7843		if (S_ISLNK(sb.st_mode)) {
7844			islnk = 1;
7845			if (Args & OCL) {
7846				if (stat(s, &sb) < 0) {
7847					continue;
7848				}
7849			}
7850		}
7851		sl_remember_tgt(&sb, islnk);
7852
7853#if defined(O_XATTR)
7854		if (Atflag) {
7855			int  dirfd;
7856			DIR  *dirp;
7857			struct dirent *dp;
7858
7859			if (pathconf(s, _PC_XATTR_EXISTS) != 1)
7860				continue;
7861
7862			dirfd = attropen(s, ".", O_RDONLY);
7863			if (dirfd == -1)
7864				continue;
7865
7866			tmpfd = dup(dirfd);
7867			if (tmpfd == -1) {
7868				(void) close(dirfd);
7869				continue;
7870			}
7871			dirp = fdopendir(tmpfd);
7872			if (dirp == NULL) {
7873				(void) close(dirfd);
7874				(void) close(tmpfd);
7875				continue;
7876			}
7877
7878			while (dp = readdir(dirp)) {
7879				if ((dp->d_name[0] == '.' &&
7880				    dp->d_name[1] == '\0') ||
7881				    (dp->d_name[0] == '.' &&
7882				    dp->d_name[1] == '.' &&
7883				    dp->d_name[2] == '\0'))
7884					continue;
7885
7886				if (fstatat(dirfd, dp->d_name, &sb,
7887				    AT_SYMLINK_NOFOLLOW) < 0) {
7888					continue;
7889				}
7890				islnk = 0;
7891				if (S_ISLNK(sb.st_mode)) {
7892					islnk = 1;
7893					if (Args & OCL) {
7894						if (fstatat(dirfd, dp->d_name,
7895						    &sb, 0) < 0) {
7896							continue;
7897						}
7898					}
7899				}
7900				sl_remember_tgt(&sb, islnk);
7901			}
7902			(void) closedir(dirp);
7903			(void) close(dirfd);
7904		}
7905#endif
7906	}
7907
7908	if (ferror(In_p)) {
7909		msg(EXTN, "error reading stdin");
7910	}
7911
7912	if (fseek(tmpfile, 0L, SEEK_SET) == -1) {
7913		msg(EXTN, "cannot fseek on tmpfile %s", tmpfname);
7914	}
7915
7916	In_p = tmpfile;
7917	free(tmpfname);
7918}
7919
7920/*
7921 * sl_remember_tgt: Add the device/inode for lstat or stat info to the list of
7922 * those we've seen before.
7923 *
7924 * This tree (rooted under head) is keyed by the device/inode of the file
7925 * being pointed to.  A count is kept of the number of references encountered
7926 * so far.
7927 */
7928
7929static void
7930sl_remember_tgt(const struct stat *sbp, int isSymlink)
7931{
7932	sl_info_t *p;
7933	dev_t device;
7934	ino_t inode;
7935
7936	device = sbp->st_dev;
7937	inode  = sbp->st_ino;
7938
7939	/* Determine whether we've seen this one before */
7940
7941	p = sl_insert(device, inode);
7942
7943	if (p->sl_count > 0) {
7944		/*
7945		 * We have seen this file before.
7946		 * Note that if we are not chasing symlinks, and this one is a
7947		 * symlink, it is identically the one we saw before (you cannot
7948		 * have hard links to symlinks); in this case, we leave the
7949		 * count alone, so that we don't wind up archiving a symlink to
7950		 * itself.
7951		 */
7952
7953		if ((Args & OCL) || (! isSymlink)) {
7954			p->sl_count++;
7955		}
7956	} else {
7957		/* We have not seen this file before */
7958
7959		p->sl_count = 1;
7960
7961		if (Use_old_stat) {
7962			/* -Hodc: remap inode (-1 on overflow) */
7963
7964			sl_remap_t  *q;
7965
7966			for (q = sl_remap_head; q && (q->dev != device);
7967			    q = q->next) {
7968				/* do nothing */
7969			}
7970
7971			if (q == NULL) {
7972				q = e_zalloc(E_EXIT, sizeof (sl_remap_t));
7973				q->dev = device;
7974				p->sl_ino2 = q->inode_count = 1;
7975
7976				q->next = (sl_remap_head) ?
7977				    sl_remap_head->next : NULL;
7978				sl_remap_head = q;
7979			} else {
7980				if ((size_t)q->inode_count <=
7981				    ((1 << (sizeof (o_ino_t) * 8)) - 1)) {
7982					/* fits in o_ino_t */
7983					p->sl_ino2 = ++(q->inode_count);
7984				} else {
7985					p->sl_ino2 = (ino_t)-1;
7986				}
7987			}
7988		}
7989	}
7990}
7991
7992/*
7993 * A faster search, which does not insert the key values into the tree.
7994 * If the a match was found in the tree, return a pointer to it.  If it was not
7995 * found, return NULL.
7996 */
7997
7998sl_info_t *
7999sl_search(dev_t device, ino_t inode)
8000{
8001	sl_info_t *p;		/* moves down the tree */
8002	int c;			/* comparison value */
8003	sl_info_t *retval = NULL; /* return value */
8004	sl_info_t *head;
8005
8006	head = sl_devhash_lookup(device);
8007	if (head != NULL) {
8008		for (p = head->rlink; p; ) {
8009			if ((c = sl_compare(inode, p->sl_ino)) == 0) {
8010				retval = p;
8011				break;
8012			} else if (c < 0) {
8013				p = p->llink;
8014			} else {
8015				p = p->rlink;
8016			}
8017		}
8018	}
8019
8020	return (retval);
8021}
8022
8023static sl_info_t *
8024sl_devhash_lookup(dev_t device)
8025{
8026	int key;
8027	sl_info_link_t *lp;
8028	static sl_info_link_t *devcache;
8029
8030	if (devcache != NULL && devcache->dev == device) {
8031		return (devcache->head);
8032	}
8033
8034	key = DEV_HASHKEY(device);
8035	for (lp = sl_devhash[key]; lp; lp = lp->next) {
8036		if (lp->dev == device) {
8037			devcache = lp;
8038			return (lp->head);
8039		}
8040	}
8041	return (NULL);
8042}
8043
8044static void
8045sl_devhash_insert(dev_t device, sl_info_t *head)
8046{
8047	int key = DEV_HASHKEY(device);
8048	sl_info_link_t *lp;
8049
8050	lp = e_zalloc(E_EXIT, sizeof (sl_info_link_t));
8051	lp->dev = device;
8052	lp->head = head;
8053	lp->next = sl_devhash[key];
8054	sl_devhash[key] = lp;
8055}
8056
8057static void
8058chop_endslashes(char *path)
8059{
8060	char *end, *ptr;
8061
8062	end = &path[strlen(path) -1];
8063	if (*end == '/' && end != path) {
8064		ptr = skipslashes(end, path);
8065		if (ptr != NULL && ptr != path) {
8066			*ptr = '\0';
8067		}
8068	}
8069}
8070
8071#if !defined(O_XATTR)
8072int
8073openat64(int fd, char *name, int oflag, mode_t cmode)
8074{
8075	return (open64(name, oflag, cmode));
8076}
8077
8078int
8079openat(int fd, char *name, int oflag, mode_t cmode)
8080{
8081	return (open(name, oflag, cmode));
8082}
8083
8084int
8085fchownat(int fd, char *name, uid_t owner, gid_t group, int flag)
8086{
8087	if (flag == AT_SYMLINK_NOFOLLOW)
8088		return (lchown(name, owner, group));
8089	else
8090		return (chown(name, owner, group));
8091}
8092
8093int
8094renameat(int fromfd, char *old, int tofd, char *new)
8095{
8096	return (rename(old, new));
8097}
8098
8099int
8100futimesat(int fd, char *path, struct timeval times[2])
8101{
8102	return (utimes(path, times));
8103}
8104
8105int
8106unlinkat(int dirfd, char *path, int flag)
8107{
8108	if (flag == AT_REMOVEDIR) {
8109		return (rmdir(path));
8110	} else {
8111		return (unlink(path));
8112	}
8113}
8114
8115int
8116fstatat(int fd, char *path, struct stat *buf, int flag)
8117{
8118	if (flag == AT_SYMLINK_NOFOLLOW)
8119		return (lstat(path, buf));
8120	else
8121		return (stat(path, buf));
8122}
8123
8124int
8125attropen(char *file, char *attr, int omode, mode_t cmode)
8126{
8127	errno = ENOTSUP;
8128	return (-1);
8129}
8130#endif
8131