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