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