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