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