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