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