xref: /illumos-gate/usr/src/cmd/cpio/cpio.c (revision 4c719f3b)
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  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <fcntl.h>
41 #include <memory.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <sys/stat.h>
45 #include <sys/statvfs.h>
46 #include <sys/mkdev.h>
47 #include <sys/param.h>
48 #include <utime.h>
49 #include <pwd.h>
50 #include <grp.h>
51 #include <signal.h>
52 #include <ctype.h>
53 #include <locale.h>
54 #include <sys/ioctl.h>
55 #include <sys/mtio.h>
56 #include <sys/fdio.h>
57 #include "cpio.h"
58 #include <sys/acl.h>
59 #include <sys/time.h>
60 #include <sys/resource.h>
61 #include <fnmatch.h>
62 #include <libgen.h>
63 #include <libintl.h>
64 #include <dirent.h>
65 #include <limits.h>
66 #include <aclutils.h>
67 #if defined(_PC_SATTR_ENABLED)
68 #include <libnvpair.h>
69 #include <attr.h>
70 #include <libcmdutils.h>
71 #endif	/* _PC_SATTR_ENABLED */
72 #ifdef SOLARIS_PRIVS
73 #include <priv.h>
74 #endif	/* SOLARIS_PRIVS */
75 
76 /*
77  * Special kludge for off_t being a signed quantity.
78  */
79 #if _FILE_OFFSET_BITS == 64
80 typedef	u_longlong_t	u_off_t;
81 #else
82 typedef	ulong_t		u_off_t;
83 #endif
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  *	These limits reflect the maximum size regular file that
121  *	can be archived, depending on the archive type. For archives
122  *	with character-format headers (odc, tar, ustar) we use
123  *	CHAR_OFFSET_MAX.  For archives with SVR4 ASCII headers (-c, -H crc)
124  *	we store filesize in an 8-char hexadecimal string and use
125  *	ASC_OFFSET_MAX.  Otherwise, we are limited to the size that will
126  *	fit in a signed long value.
127  */
128 #define	CHAR_OFFSET_MAX	077777777777ULL	/* 11 octal digits */
129 #define	ASC_OFFSET_MAX	0XFFFFFFFF	/* 8 hexadecimal digits */
130 #define	BIN_OFFSET_MAX	LONG_MAX	/* signed long max value */
131 
132 #define	POSIXMODES	07777
133 
134 static char	aclchar = ' ';
135 
136 static struct Lnk *add_lnk(struct Lnk **);
137 static int bfill(void);
138 static void bflush(void);
139 static int chgreel(int dir);
140 static int ckname(int);
141 static void ckopts(long mask);
142 static long cksum(char hdr, int byt_cnt, int *err);
143 static int creat_hdr(void);
144 static int creat_lnk(int dirfd, char *name1_p, char *name2_p);
145 static int creat_spec(int dirfd);
146 static int creat_tmp(char *nam_p);
147 static void data_in(int proc_mode);
148 static void data_out(void);
149 static void data_pass(void);
150 static void file_in(void);
151 static int file_out(void);
152 static int file_pass(void);
153 static void flush_lnks(void);
154 static int gethdr(void);
155 static int getname(void);
156 static void getpats(int largc, char **largv);
157 static void ioerror(int dir);
158 static int matched(void);
159 static int missdir(char *nam_p);
160 static long mklong(short v[]);
161 static void mkshort(short sval[], long v);
162 static int openout(int dirfd);
163 static int read_hdr(int hdr);
164 static void reclaim(struct Lnk *l_p);
165 static void rstbuf(void);
166 static void setpasswd(char *nam);
167 static void rstfiles(int over, int dirfd);
168 static void scan4trail(void);
169 static void setup(int largc, char **largv);
170 static void set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime);
171 static void sigint(int sig);
172 static void swap(char *buf_p, int cnt);
173 static void usage(void);
174 static void verbose(char *nam_p);
175 static void write_hdr(int arcflag, off_t len);
176 static void write_trail(void);
177 static int ustar_dir(void);
178 static int ustar_spec(void);
179 static struct stat *convert_to_old_stat(struct stat *, char *, char *);
180 static void read_bar_vol_hdr(void);
181 static void read_bar_file_hdr(void);
182 static void setup_uncompress(FILE **);
183 static void skip_bar_volhdr(void);
184 static void bar_file_in(void);
185 static int g_init(int *devtype, int *fdes);
186 static int g_read(int, int, char *, unsigned);
187 static int g_write(int, int, char *, unsigned);
188 static int is_floppy(int);
189 static int is_tape(int);
190 static void write_ancillary(char *buf, size_t len, boolean_t padding);
191 static int remove_dir(char *);
192 static int save_cwd(void);
193 static void rest_cwd(int cwd);
194 
195 static void xattrs_out(int (*func)());
196 static void get_parent(char *path, char *dir);
197 static void prepare_xattr_hdr(char **attrbuf, char *filename,
198     char *attrname, char typeflag, struct Lnk *linkinfo, int *rlen);
199 static char tartype(int type);
200 static int openfile(int omode);
201 static mode_t attrmode(char type);
202 static char *get_component(char *path);
203 static int open_dir(char *name);
204 static int open_dirfd();
205 static void close_dirfd();
206 static void write_xattr_hdr();
207 static char *skipslashes(char *string, char *start);
208 static int read_xattr_hdr();
209 static void chop_endslashes(char *path);
210 
211 
212 /* helpful types */
213 
214 static
215 struct passwd	*Curpw_p,	/* Current password entry for -t option */
216 		*Rpw_p,		/* Password entry for -R option */
217 		*dpasswd;
218 
219 static
220 struct group	*Curgr_p,	/* Current group entry for -t option */
221 		*dgroup;
222 
223 /* Data structure for buffered I/O. */
224 
225 static
226 struct buf_info {
227 	char	*b_base_p,	/* Pointer to base of buffer */
228 		*b_out_p,	/* Position to take bytes from buffer at */
229 		*b_in_p,	/* Position to put bytes into buffer at */
230 		*b_end_p;	/* Pointer to end of buffer */
231 	long	b_cnt,		/* Count of unprocessed bytes */
232 		b_size;		/* Size of buffer in bytes */
233 } Buffr;
234 
235 /* Generic header format */
236 
237 static
238 struct gen_hdr {
239 	ulong_t	g_magic,	/* Magic number field */
240 		g_ino,		/* Inode number of file */
241 		g_mode,		/* Mode of file */
242 		g_uid,		/* Uid of file */
243 		g_gid,		/* Gid of file */
244 		g_nlink,	/* Number of links */
245 		g_mtime;	/* Modification time */
246 	off_t	g_filesz;	/* Length of file */
247 	ulong_t	g_dev,		/* File system of file */
248 		g_rdev,		/* Major/minor numbers of special files */
249 		g_namesz,	/* Length of filename */
250 		g_cksum;	/* Checksum of file */
251 	char	g_gname[32],
252 		g_uname[32],
253 		g_version[2],
254 		g_tmagic[6],
255 		g_typeflag;
256 	char	*g_tname,
257 		*g_prefix,
258 		*g_nam_p,	/* Filename */
259 		*g_attrparent_p, /* attribute parent */
260 		*g_attrpath_p, /* attribute path */
261 		*g_attrnam_p,	/* attribute */
262 		*g_attrfnam_p,  /* Real file name attr belongs to */
263 		*g_linktoattrfnam_p, /* file linked attribute belongs to */
264 		*g_linktoattrnam_p,  /* attribute g_attrnam_p is linked to */
265 		*g_dirpath;	/* dirname currently opened */
266 	int	g_dirfd;	/* directory file descriptor */
267 	int	g_passdirfd;	/* directory fd to pass to */
268 	int	g_rw_sysattr;	/* read-write system attribute */
269 	int	g_baseparent_fd;	/* base file's parent fd */
270 	holes_info_t *g_holes;	/* sparse file information */
271 
272 } Gen, *G_p;
273 
274 /* Data structure for handling multiply-linked files */
275 static
276 char	prebuf[PRESIZ+1],
277 	nambuf[NAMSIZ+1],
278 	fullnam[MAXNAM+1];
279 
280 
281 static
282 struct Lnk {
283 	short	L_cnt,		/* Number of links encountered */
284 		L_data;		/* Data has been encountered if 1 */
285 	struct gen_hdr	L_gen;	/* gen_hdr information for this file */
286 	struct Lnk	*L_nxt_p,	/* Next file in list */
287 			*L_bck_p,	/* Previous file in list */
288 			*L_lnk_p;	/* Next link for this file */
289 } Lnk_hd;
290 
291 static
292 struct hdr_cpio	Hdr;
293 
294 /*
295  * -------------------------------------------------------------------------
296  *		   Stuff needed to pre-view the name stream
297  *
298  * issymlink is used to remember that the current file is a symlink between
299  * getname() and file_pass(); the former trashes this information immediately
300  * when -L is specified.
301  */
302 
303 static
304 int	issymlink = 0;
305 
306 static
307 FILE	*In_p = stdin;		/* Where the input comes from */
308 
309 typedef struct sl_info
310 {
311 	struct sl_info *llink;	/* Left subtree ptr (tree depth in *sl_head) */
312 	struct sl_info *rlink;	/* Right subtree ptr */
313 	int bal;		/* Subtree balance factor */
314 	ulong_t	sl_count;	/* Number of symlinks */
315 	int	sl_ftype;	/* file type of inode */
316 	ino_t	sl_ino;		/* Inode of file */
317 	ino_t	sl_ino2;	/* alternate inode for -Hodc */
318 } sl_info_t;
319 
320 typedef struct data_in
321 {
322 	int		data_in_errno;
323 	char		data_in_swapfile;
324 	char		data_in_proc_mode;
325 	char		data_in_rd_eof;
326 	char		data_in_wr_part;
327 	char		data_in_compress_flag;
328 	long		data_in_cksumval;
329 	FILE		*data_in_pipef;
330 } data_in_t;
331 
332 /*
333  * The following structure maintains a hash entry for the
334  * balancing trees which are allocated for each device nodes.
335  */
336 typedef struct sl_info_link
337 {
338 	dev_t		dev;
339 	sl_info_t	*head;
340 	struct sl_info_link *next;
341 } sl_info_link_t;
342 
343 #define	SL_INFO_ALLOC_CHUNK	1024
344 #define	NDEVHENTRY		0x40
345 #define	DEV_HASHKEY(x)		((x) & (NDEVHENTRY -1))
346 
347 /*
348  * For remapping dev,inode for -Hodc archives.
349  */
350 
351 typedef struct sl_remap
352 {
353 	dev_t			dev;		/* device */
354 	int			inode_count;	/* # inodes seen on dev */
355 	struct sl_remap		*next;		/* next in the chain */
356 } sl_remap_t;
357 
358 /* forward declarations */
359 
360 static sl_info_t	*sl_info_alloc(void);
361 static sl_info_t	*sl_insert(dev_t, ino_t, int);
362 static ulong_t		sl_numlinks(dev_t, ino_t, int);
363 static void		sl_preview_synonyms(void);
364 static void		sl_remember_tgt(const struct stat *, int, int);
365 static sl_info_t	*sl_search(dev_t, ino_t, int);
366 static sl_info_t	*sl_devhash_lookup(dev_t);
367 static void		sl_devhash_insert(dev_t, sl_info_t *);
368 
369 extern int		sl_compare(ino_t, int, ino_t, int);
370 #define	sl_compare(lino, lftype, rino, rftype)	(lino < rino ? -1 : \
371 	    (lino > rino ? 1 : (lftype < rftype ? -1 : \
372 	    (lftype > rftype ? 1 : 0))))
373 
374 /* global storage */
375 
376 static sl_remap_t  *sl_remap_head = NULL; /* head of the inode-remap list */
377 static sl_info_link_t	*sl_devhash[NDEVHENTRY]; /* hash table */
378 
379 /*
380  * -------------------------------------------------------------------------
381  */
382 
383 static
384 struct stat	ArchSt,	/* stat(2) information of the archive */
385 		SrcSt,	/* stat(2) information of source file */
386 		DesSt,	/* stat(2) of destination file */
387 		*OldSt = NULL;	/* stat info converted to svr32 format */
388 
389 /*
390  * bin_mag: Used to validate a binary magic number,
391  * by combining to bytes into an unsigned short.
392  */
393 
394 static
395 union bin_mag {
396 	unsigned char b_byte[2];
397 	ushort_t b_half;
398 } Binmag;
399 
400 static
401 union tblock *Thdr_p;	/* TAR header pointer */
402 
403 static union b_block *bar_Vhdr;
404 static struct gen_hdr Gen_bar_vol;
405 
406 /*
407  * swpbuf: Used in swap() to swap bytes within a halfword,
408  * halfwords within a word, or to reverse the order of the
409  * bytes within a word.  Also used in mklong() and mkshort().
410  */
411 
412 static
413 union swpbuf {
414 	unsigned char	s_byte[4];
415 	ushort_t	s_half[2];
416 	ulong_t	s_word;
417 } *Swp_p;
418 
419 static
420 char	*myname,		/* program name */
421 	Adir,			/* Flags object as a directory */
422 	Hiddendir,		/* Processing hidden attribute directory */
423 	Aspec,			/* Flags object as a special file */
424 	Do_rename,		/* Indicates rename() is to be used */
425 	Time[50],		/* Array to hold date and time */
426 	Ttyname[] = "/dev/tty",	/* Controlling console */
427 	T_lname[MAXPATHLEN],	/* Array to hold links name for tar */
428 	*Buf_p,			/* Buffer for file system I/O */
429 	*Full_p,		/* Pointer to full pathname */
430 	*Efil_p,		/* -E pattern file string */
431 	*Eom_p = "Change to part %d and press RETURN key. [q] ",
432 	*Fullnam_p,		/* Full pathname */
433 	*Attrfile_p,		/* attribute file */
434 	*Hdr_p,			/* -H header type string */
435 	*IOfil_p,		/* -I/-O input/output archive string */
436 	*Lnkend_p,		/* Pointer to end of Lnknam_p */
437 	*Lnknam_p,		/* Buffer for linking files with -p option */
438 	*Nam_p,			/* Array to hold filename */
439 	*Savenam_p,		/* copy of filename xattr belongs to */
440 	*Own_p,			/* New owner login id string */
441 	*Renam_p,		/* Buffer for renaming files */
442 	*Renam_attr_p,		/* Buffer for renaming attr with sys attrs */
443 	*Renametmp_p,		/* Tmp Buffer for renaming files */
444 	*Symlnk_p,		/* Buffer for holding symbolic link name */
445 	*Over_p,		/* Holds temporary filename when overwriting */
446 	**Pat_pp = 0,		/* Pattern strings */
447 	bar_linkflag,		/* flag to indicate if the file is a link */
448 	bar_linkname[MAXPATHLEN]; /* store the name of the link */
449 
450 static
451 int	Append = 0,	/* Flag set while searching to end of archive */
452 	Archive,	/* File descriptor of the archive */
453 	Buf_error = 0,	/* I/O error occurred during buffer fill */
454 	Compress_sparse = 0,	/* Compress sparse files */
455 	Def_mode = 0777,	/* Default file/directory protection modes */
456 	Device,		/* Device type being accessed (used with libgenIO) */
457 	Error_cnt = 0,	/* Cumulative count of I/O errors */
458 	Finished = 1,	/* Indicates that a file transfer has completed */
459 	Hdrsz = ASCSZ,	/* Fixed length portion of the header */
460 	Hdr_type,		/* Flag to indicate type of header selected */
461 	Ifile,		/* File des. of file being archived */
462 	Ofile,		/* File des. of file being extracted from archive */
463 	Use_old_stat = 0,    /* Create an old style -Hodc hdr (small dev's) */
464 	Onecopy = 0,	/* Flags old vs. new link handling */
465 	Pad_val = 0,	/* Indicates the number of bytes to pad (if any) */
466 	PageSize = 0,	/* The native page size, used for figuring block size */
467 	Volcnt = 1,	/* Number of archive volumes processed */
468 	Verbcnt = 0,	/* Count of number of dots '.' output */
469 	Eomflag = 0,
470 	Dflag = 0,
471 	Atflag = 0,	/* Archive/restore extended attributes */
472 	SysAtflag = 0,	/* Archive/restore extended system attributes */
473 	Compressed,	/* Flag to indicate if the bar archive is compressed */
474 	Bar_vol_num = 0, /* Volume number count for bar archive */
475 	privileged = 0,	/* Flag set if running with higher privileges */
476 	attr_baseparent_fd = -1;	/* attribute's base file descriptor */
477 
478 
479 static
480 gid_t	Lastgid = (gid_t)-1;	/* Used with -t & -v to record current gid */
481 
482 static
483 uid_t	Lastuid = (uid_t)-1;	/* Used with -t & -v to record current uid */
484 
485 static
486 long	Args,		/* Mask of selected options */
487 	Max_namesz = CPATH;	/* Maximum size of pathnames/filenames */
488 
489 static
490 int	Bufsize = BUFSZ;	/* Default block size */
491 
492 
493 static u_longlong_t    Blocks;	/* full blocks transferred */
494 static u_longlong_t    SBlocks;	/* cumulative char count from short reads */
495 
496 
497 static off_t	Max_offset = BIN_OFFSET_MAX;	/* largest file size */
498 static off_t	Max_filesz;			/* from getrlimit */
499 
500 static ulong_t	Savedev;
501 
502 static
503 FILE	*Ef_p,			/* File pointer of pattern input file */
504 	*Err_p = stderr,	/* File pointer for error reporting */
505 	*Out_p = stdout,	/* File pointer for non-archive output */
506 	*Rtty_p,		/* Input file pointer for interactive rename */
507 	*Wtty_p;		/* Output file ptr for interactive rename */
508 
509 static
510 ushort_t	Ftype = S_IFMT;	/* File type mask */
511 
512 /* ACL support */
513 static struct sec_attr {
514 	char	attr_type;
515 	char	attr_len[7];
516 	char	attr_info[1];
517 } *attr;
518 
519 static int	Pflag = 0;	/* flag indicates that acl is preserved */
520 static int	acl_is_set = 0; /* True if an acl was set on the file */
521 
522 acl_t *aclp;
523 
524 #if defined(O_XATTR)
525 typedef enum {
526 	ATTR_OK,
527 	ATTR_SKIP,
528 	ATTR_CHDIR_ERR,
529 	ATTR_OPEN_ERR,
530 	ATTR_XATTR_ERR,
531 	ATTR_SATTR_ERR
532 } attr_status_t;
533 #endif
534 
535 #if defined(O_XATTR)
536 typedef enum {
537 	ARC_CREATE,
538 	ARC_RESTORE
539 } arc_action_t;
540 #endif
541 
542 
543 /*
544  *
545  * cpio has been changed to support extended attributes.
546  *
547  * As part of this change cpio has been changed to use the new *at() syscalls
548  * such as openat, fchownat(), unlinkat()...
549  *
550  * This was done so that attributes can be handled with as few code changes
551  * as possible.
552  *
553  * What this means is that cpio now opens the directory that a file or directory
554  * resides in and then performs *at() functions to manipulate the entry.
555  *
556  * For example a new file is now created like this:
557  *
558  * dfd = open(<some dir path>)
559  * fd = openat(dfd, <name>,....);
560  *
561  * or in the case of an extended attribute
562  *
563  * dfd = attropen(<pathname>, ".", ....)
564  *
565  * Once we have a directory file descriptor all of the *at() functions can
566  * be applied to it.
567  *
568  * unlinkat(dfd, <component name>,...)
569  * fchownat(dfd, <component name>,..)
570  *
571  * This works for both normal namespace files and extended attribute file
572  *
573  */
574 
575 /*
576  * Extended attribute layout
577  *
578  * Extended attributes are stored in two pieces.
579  * 1. An attribute header which has information about
580  *    what file the attribute is for and what the attribute
581  *    is named.
582  * 2. The attribute record itself.  Stored as a normal file type
583  *    of entry.
584  * Both the header and attribute record have special modes/typeflags
585  * associated with them.
586  *
587  * The names of the header in the archive look like:
588  * /dev/null/attr.hdr
589  *
590  * The name of the attribute looks like:
591  * /dev/null/attr.
592  *
593  * This is done so that an archiver that doesn't understand these formats
594  * can just dispose of the attribute records unless the user chooses to
595  * rename them via cpio -r or pax -i
596  *
597  * The format is composed of a fixed size header followed
598  * by a variable sized xattr_buf. If the attribute is a hard link
599  * to another attribute, then another xattr_buf section is included
600  * for the link.
601  *
602  * The xattr_buf is used to define the necessary "pathing" steps
603  * to get to the extended attribute.  This is necessary to support
604  * a fully recursive attribute model where an attribute may itself
605  * have an attribute.
606  *
607  * The basic layout looks like this.
608  *
609  *     --------------------------------
610  *     |                              |
611  *     |         xattr_hdr            |
612  *     |                              |
613  *     --------------------------------
614  *     --------------------------------
615  *     |                              |
616  *     |        xattr_buf             |
617  *     |                              |
618  *     --------------------------------
619  *     --------------------------------
620  *     |                              |
621  *     |      (optional link info)    |
622  *     |                              |
623  *     --------------------------------
624  *     --------------------------------
625  *     |                              |
626  *     |      attribute itself        |
627  *     |      stored as normal tar    |
628  *     |      or cpio data with       |
629  *     |      special mode or         |
630  *     |      typeflag                |
631  *     |                              |
632  *     --------------------------------
633  *
634  */
635 
636 /*
637  * Extended attributes structures
638  *
639  * xattrhead is the complete extended attribute header, as read of off
640  * disk/tape. It includes the variable xattr_buf portion.
641  *
642  * xattrp is basically an offset into xattrhead that points to the
643  * "pathing" section which defines how to get to the attribute.
644  *
645  * xattr_linkp is identical to xattrp except that it is used for linked
646  * attributes.  It provides the pathing steps to get to the linked
647  * attribute.
648  *
649  * These structures are updated when an extended attribute header is read off
650  * of disk/tape.
651  */
652 static struct xattr_hdr	*xattrhead;
653 static struct xattr_buf	*xattrp;
654 static struct xattr_buf	*xattr_linkp;
655 static int		xattrbadhead;	/* is extended attribute header bad? */
656 
657 static int	append_secattr(char **, int *, acl_t *);
658 
659 /*
660  * Note regarding cpio and changes to ensure cpio doesn't try to second
661  * guess whether it runs with sufficient privileges or not:
662  *
663  * cpio has been changed so that it doesn't carry a second implementation of
664  * the kernel's policy with respect to privileges.  Instead of attempting
665  * to restore uid and gid from an archive only if cpio is run as uid 0,
666  * cpio now *always* tries to restore the uid and gid from the archive
667  * except when the -R option is specified.  When the -R is specified,
668  * the uid and gid of the restored file will be changed to those of the
669  * login id specified.  In addition, chown(), set_tym(), and chmod() should
670  * only be executed once during archive extraction, and to ensure
671  * setuid/setgid bits are restored properly, chown() should always be
672  * executed before chmod().
673  *
674  * Note regarding debugging mechanism for cpio:
675  *
676  * The following mechanism is provided to allow us to debug cpio in complicated
677  * situations, like when it is part of a pipe.  The idea is that you compile
678  * with -DWAITAROUND defined, and then add the "-z" command line option to the
679  * target cpio invocation.  If stderr is available, it will tell you to which
680  * pid to attach the debugger; otherwise, use ps to find it.  Attach to the
681  * process from the debugger, and, *PRESTO*, you are there!
682  *
683  * Simply assign "waitaround = 0" once you attach to the process, and then
684  * proceed from there as usual.
685  */
686 
687 #ifdef WAITAROUND
688 int waitaround = 0;		/* wait for rendezvous with the debugger */
689 #endif
690 
691 #define	EXIT_CODE	(Error_cnt > 255 ? 255 : Error_cnt)
692 
693 /*
694  * main: Call setup() to process options and perform initializations,
695  * and then select either copy in (-i), copy out (-o), or pass (-p) action.
696  */
697 
698 int
main(int argc,char ** argv)699 main(int argc, char **argv)
700 {
701 	int i;
702 	int passret;
703 
704 	(void) setlocale(LC_ALL, "");
705 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
706 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
707 #endif
708 	(void) textdomain(TEXT_DOMAIN);
709 
710 	(void) memset(&Gen, 0, sizeof (Gen));
711 	myname = e_strdup(E_EXIT, basename(argv[0]));
712 	setup(argc, argv);
713 
714 	if (signal(SIGINT, sigint) == SIG_IGN)
715 		(void) signal(SIGINT, SIG_IGN);
716 	switch (Args & (OCi | OCo | OCp)) {
717 	case OCi: /* COPY IN */
718 		Hdr_type = NONE;
719 		if (Atflag || SysAtflag) {
720 			/*
721 			 * Save the current working directory, so
722 			 * we can change back here after cd'ing into
723 			 * the attribute directory when processing
724 			 * attributes.
725 			 */
726 			if ((attr_baseparent_fd = save_cwd()) < 0) {
727 				msg(EXT, "Unable to open current directory.");
728 			}
729 		}
730 		while ((i = gethdr()) != 0) {
731 			Gen.g_dirfd = -1;
732 			if (i == 1) {
733 				file_in();
734 				/*
735 				 * Any ACL info for this file would or should
736 				 * have been used after file_in(); clear out
737 				 * aclp so it is is not erroneously used on
738 				 * the next file.
739 				 */
740 				if (aclp != NULL) {
741 					acl_free(aclp);
742 					aclp = NULL;
743 				}
744 				acl_is_set = 0;
745 			}
746 			(void) memset(&Gen, 0, sizeof (Gen));
747 		}
748 		/* Do not count "extra" "read-ahead" buffered data */
749 		if (Buffr.b_cnt > Bufsize)
750 			Blocks -=  (u_longlong_t)(Buffr.b_cnt / Bufsize);
751 		break;
752 	case OCo: /* COPY OUT */
753 		if (Args & OCA) {
754 			scan4trail();
755 		}
756 
757 		Gen.g_dirfd = -1;
758 		Gen.g_dirpath = NULL;
759 		sl_preview_synonyms();
760 
761 		while ((i = getname()) != 0) {
762 			if (i == 1) {
763 				(void) file_out();
764 				if (Atflag || SysAtflag) {
765 					if (Gen.g_dirfd != -1) {
766 						(void) close(Gen.g_dirfd);
767 					}
768 					Gen.g_dirfd = -1;
769 					xattrs_out(file_out);
770 				}
771 			}
772 			if (aclp != NULL) {
773 				acl_free(aclp);
774 				aclp = NULL;
775 				acl_is_set = 0;
776 			}
777 		}
778 		write_trail();
779 		break;
780 	case OCp: /* PASS */
781 		sl_preview_synonyms();
782 
783 		Gen.g_dirfd = -1;
784 		Gen.g_passdirfd = -1;
785 		Gen.g_dirpath = NULL;
786 		Compress_sparse = 1;
787 		while (getname()) {
788 			/*
789 			 * If file is a fully qualified path then
790 			 * file_pass will strip off the leading '/'
791 			 * and we need to save off the unstripped
792 			 * name for attribute traversal.
793 			 */
794 			if (Atflag || SysAtflag) {
795 				(void) strcpy(Savenam_p, Gen.g_nam_p);
796 			}
797 			passret = file_pass();
798 			if (aclp != NULL) {
799 				acl_free(aclp);
800 				aclp = NULL;
801 				acl_is_set = 0;
802 			}
803 			if (Gen.g_passdirfd != -1)
804 				(void) close(Gen.g_passdirfd);
805 			Gen.g_passdirfd = -1;
806 			if (Atflag || SysAtflag) {
807 				if (Gen.g_dirfd != -1) {
808 					(void) close(Gen.g_dirfd);
809 				}
810 				Gen.g_dirfd = -1;
811 				if (passret != FILE_LINKED) {
812 					Gen.g_nam_p = Savenam_p;
813 					xattrs_out(file_pass);
814 				}
815 			}
816 		}
817 		break;
818 	default:
819 		msg(EXT, "Impossible action.");
820 	}
821 	if (Ofile > 0) {
822 		if (close(Ofile) != 0)
823 			msg(EXTN, "close error");
824 	}
825 	if (Archive > 0) {
826 		if (close(Archive) != 0)
827 			msg(EXTN, "close error");
828 	}
829 	if ((Args & OCq) == 0) {
830 		Blocks = (u_longlong_t)(Blocks * Bufsize + SBlocks +
831 		    0x1FF) >> 9;
832 		msg(EPOST, "%lld blocks", Blocks);
833 	}
834 	if (Error_cnt)
835 		msg(EPOST, "%d error(s)", Error_cnt);
836 	return (EXIT_CODE);
837 }
838 
839 /*
840  * add_lnk: Add a linked file's header to the linked file data structure, by
841  * either adding it to the end of an existing sub-list or starting
842  * a new sub-list.  Each sub-list saves the links to a given file.
843  *
844  * Directly returns a pointer to the new entry; returns a pointer to the head
845  * of the sub-list in which that entry is located through the argument.
846  */
847 
848 static struct Lnk *
add_lnk(struct Lnk ** sublist_return)849 add_lnk(struct Lnk **sublist_return)
850 {
851 	struct Lnk *new_entry, *sublist;
852 
853 	for (sublist = Lnk_hd.L_nxt_p;
854 	    sublist != &Lnk_hd;
855 	    sublist = sublist->L_nxt_p) {
856 		if (sublist->L_gen.g_ino == G_p->g_ino &&
857 		    sublist->L_gen.g_dev == G_p->g_dev) {
858 			/* found */
859 			break;
860 		}
861 	}
862 
863 	new_entry = e_zalloc(E_EXIT, sizeof (struct Lnk));
864 
865 	new_entry->L_lnk_p = NULL;
866 	new_entry->L_gen = *G_p; /* structure copy */
867 
868 	new_entry->L_gen.g_nam_p = e_zalloc(E_EXIT, (size_t)G_p->g_namesz);
869 
870 	(void) strcpy(new_entry->L_gen.g_nam_p, G_p->g_nam_p);
871 
872 	if (sublist == &Lnk_hd) {
873 		/* start new sub-list */
874 		new_entry->L_nxt_p = &Lnk_hd;
875 		new_entry->L_bck_p = Lnk_hd.L_bck_p;
876 		Lnk_hd.L_bck_p = new_entry->L_bck_p->L_nxt_p = new_entry;
877 		new_entry->L_lnk_p = NULL;
878 		new_entry->L_cnt = 1;
879 		new_entry->L_data = Onecopy ? 0 : 1;
880 		sublist = new_entry;
881 	} else {
882 		/* add to existing sub-list */
883 		struct Lnk *ptr;
884 
885 		sublist->L_cnt++;
886 
887 		for (ptr = sublist;
888 		    ptr->L_lnk_p != NULL;
889 		    ptr = ptr->L_lnk_p) {
890 			ptr->L_gen.g_filesz = G_p->g_filesz;
891 		}
892 
893 		ptr->L_gen.g_filesz = G_p->g_filesz;
894 		ptr->L_lnk_p = new_entry;
895 	}
896 
897 	*sublist_return = sublist;
898 	return (new_entry);
899 }
900 
901 /*
902  * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
903  * moving them to rd_buf_p.  When there are no bytes left in the I/O buffer,
904  * Fillbuf is set and the I/O buffer is filled.  The variable dist is the
905  * distance to lseek if an I/O error is encountered with the -k option set
906  * (converted to a multiple of Bufsize).
907  */
908 
909 static int
bfill(void)910 bfill(void)
911 {
912 	int i = 0, rv;
913 	static int eof = 0;
914 
915 	if (!Dflag) {
916 	while ((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) {
917 		errno = 0;
918 		if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
919 			if (((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) &&
920 			    (Eomflag == 0)) {
921 				Eomflag = 1;
922 				return (1);
923 			}
924 			if (errno == ENOSPC) {
925 				(void) chgreel(INPUT);
926 				if (Hdr_type == BAR) {
927 					skip_bar_volhdr();
928 				}
929 				continue;
930 			} else if (Args & OCk) {
931 				if (i++ > MX_SEEKS)
932 					msg(EXT, "Cannot recover.");
933 				if (lseek(Archive, Bufsize, SEEK_REL) < 0)
934 					msg(EXTN, "Cannot lseek()");
935 				Error_cnt++;
936 				Buf_error++;
937 				rv = 0;
938 				continue;
939 			} else
940 				ioerror(INPUT);
941 		} /* (rv = g_read(Device, Archive ... */
942 		if (Hdr_type != BAR || rv == Bufsize) {
943 			Buffr.b_in_p += rv;
944 			Buffr.b_cnt += (long)rv;
945 		}
946 		if (rv == Bufsize) {
947 			eof = 0;
948 			Blocks++;
949 		} else if (rv == 0) {
950 			if (!eof) {
951 				eof = 1;
952 				break;
953 			}
954 			(void) chgreel(INPUT);
955 			eof = 0;	/* reset the eof after chgreel	*/
956 
957 			/*
958 			 * if spans multiple volume, skip the volume header of
959 			 * the next volume so that the file currently being
960 			 * extracted can continue to be extracted.
961 			 */
962 			if (Hdr_type == BAR) {
963 				skip_bar_volhdr();
964 			}
965 
966 			continue;
967 		} else {
968 			eof = 0;
969 			SBlocks += (u_longlong_t)rv;
970 		}
971 	} /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
972 
973 	} else {			/* Dflag */
974 		errno = 0;
975 		if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
976 			return (-1);
977 		} /* (rv = g_read(Device, Archive ... */
978 		Buffr.b_in_p += rv;
979 		Buffr.b_cnt += (long)rv;
980 		if (rv == Bufsize) {
981 			eof = 0;
982 			Blocks++;
983 		} else if (!rv) {
984 			if (!eof) {
985 				eof = 1;
986 				return (rv);
987 			}
988 			return (-1);
989 		} else {
990 			eof = 0;
991 			SBlocks += (u_longlong_t)rv;
992 		}
993 	}
994 	return (rv);
995 }
996 
997 /*
998  * bflush: Move wr_cnt bytes from data_p into the I/O buffer.  When the
999  * I/O buffer is full, Flushbuf is set and the buffer is written out.
1000  */
1001 
1002 static void
bflush(void)1003 bflush(void)
1004 {
1005 	int rv;
1006 
1007 	while (Buffr.b_cnt >= Bufsize) {
1008 		errno = 0;
1009 		if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1010 		    Bufsize)) < 0) {
1011 			if (errno == ENOSPC && !Dflag)
1012 				rv = chgreel(OUTPUT);
1013 			else
1014 				ioerror(OUTPUT);
1015 		}
1016 		Buffr.b_out_p += rv;
1017 		Buffr.b_cnt -= (long)rv;
1018 		if (rv == Bufsize)
1019 			Blocks++;
1020 		else if (rv > 0)
1021 			SBlocks += (u_longlong_t)rv;
1022 	}
1023 	rstbuf();
1024 }
1025 
1026 /*
1027  * chgreel: Determine if end-of-medium has been reached.  If it has,
1028  * close the current medium and prompt the user for the next medium.
1029  */
1030 
1031 static int
chgreel(int dir)1032 chgreel(int dir)
1033 {
1034 	int lastchar, tryagain, askagain, rv;
1035 	int tmpdev;
1036 	char str[APATH];
1037 	struct stat statb;
1038 
1039 	rv = 0;
1040 	if (fstat(Archive, &statb) < 0)
1041 		msg(EXTN, "Error during stat() of archive");
1042 	if ((statb.st_mode & S_IFMT) != S_IFCHR) {
1043 		if (dir == INPUT) {
1044 			msg(EXT, "%s%s\n",
1045 			    "Can't read input:  end of file encountered ",
1046 			    "prior to expected end of archive.");
1047 		}
1048 	}
1049 	msg(EPOST, "\007End of medium on \"%s\".", dir ? "output" : "input");
1050 	if (is_floppy(Archive))
1051 		(void) ioctl(Archive, FDEJECT, NULL);
1052 	if ((close(Archive) != 0) && (dir == OUTPUT))
1053 		msg(EXTN, "close error");
1054 	Archive = 0;
1055 	Volcnt++;
1056 	for (;;) {
1057 		if (Rtty_p == NULL)
1058 			Rtty_p = fopen(Ttyname, "r");
1059 		do { /* tryagain */
1060 			if (IOfil_p) {
1061 				do {
1062 					msg(EPOST, Eom_p, Volcnt);
1063 					if (!Rtty_p || fgets(str, sizeof (str),
1064 					    Rtty_p) == NULL)
1065 						msg(EXT, "Cannot read tty.");
1066 					askagain = 0;
1067 					switch (*str) {
1068 					case '\n':
1069 						(void) strcpy(str, IOfil_p);
1070 						break;
1071 					case 'q':
1072 						exit(EXIT_CODE);
1073 					default:
1074 						askagain = 1;
1075 					}
1076 				} while (askagain);
1077 			} else {
1078 
1079 				if (Hdr_type == BAR)
1080 					Bar_vol_num++;
1081 
1082 				msg(EPOST,
1083 				    "To continue, type device/file name when "
1084 				    "ready.");
1085 				if (!Rtty_p || fgets(str, sizeof (str),
1086 				    Rtty_p) == NULL)
1087 					msg(EXT, "Cannot read tty.");
1088 				lastchar = strlen(str) - 1;
1089 				if (*(str + lastchar) == '\n') /* remove '\n' */
1090 					*(str + lastchar) = '\0';
1091 				if (!*str)
1092 					exit(EXIT_CODE);
1093 			}
1094 			tryagain = 0;
1095 			if ((Archive = open(str, dir)) < 0) {
1096 				msg(ERRN, "Cannot open \"%s\"", str);
1097 				tryagain = 1;
1098 			}
1099 		} while (tryagain);
1100 		(void) g_init(&tmpdev, &Archive);
1101 		if (tmpdev != Device)
1102 			msg(EXT, "Cannot change media types in mid-stream.");
1103 		if (dir == INPUT)
1104 			break;
1105 		else { /* dir == OUTPUT */
1106 			errno = 0;
1107 			if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1108 			    Bufsize)) == Bufsize)
1109 				break;
1110 			else
1111 				msg(ERR,
1112 				    "Unable to write this medium, try "
1113 				    "another.");
1114 		}
1115 	} /* ;; */
1116 	Eomflag = 0;
1117 	return (rv);
1118 }
1119 
1120 /*
1121  * ckname: Check filenames against user specified patterns,
1122  * and/or ask the user for new name when -r is used.
1123  */
1124 
1125 static int
ckname(int flag)1126 ckname(int flag)
1127 {
1128 	int	lastchar;
1129 	size_t	rename_bufsz = Max_namesz + 1;
1130 
1131 	if (Hdr_type != TAR && Hdr_type != USTAR && Hdr_type != BAR) {
1132 		/* Re-visit tar size issues later */
1133 		if (G_p->g_namesz - 1 > Max_namesz) {
1134 			msg(ERR, "Name exceeds maximum length - skipped.");
1135 			return (F_SKIP);
1136 		}
1137 	}
1138 
1139 	if (Pat_pp && !matched())
1140 		return (F_SKIP);
1141 
1142 	/* rename interactively */
1143 	if ((Args & OCr) && !Adir && !G_p->g_rw_sysattr) {
1144 		(void) fprintf(Wtty_p, gettext("Rename \"%s%s%s\"? "),
1145 		    (G_p->g_attrnam_p == NULL) ? G_p->g_nam_p : Renam_p,
1146 		    (G_p->g_attrnam_p == NULL) ? "" : gettext(" Attribute "),
1147 		    (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
1148 		(void) fflush(Wtty_p);
1149 		if (fgets(Renametmp_p, rename_bufsz, Rtty_p) == NULL)
1150 			msg(EXT, "Cannot read tty.");
1151 		if (feof(Rtty_p))
1152 			exit(EXIT_CODE);
1153 		lastchar = strlen(Renametmp_p) - 1;
1154 
1155 		/* remove trailing '\n' */
1156 		if (*(Renametmp_p + lastchar) == '\n')
1157 			*(Renametmp_p + lastchar) = '\0';
1158 		if (*Renametmp_p == '\0') {
1159 			msg(POST, "%s%s%s Skipped.",
1160 			    (G_p->g_attrnam_p == NULL) ? G_p->g_nam_p :
1161 			    G_p->g_attrfnam_p,
1162 			    (G_p->g_attrnam_p == NULL) ? "" :
1163 			    gettext(" Attribute "),
1164 			    (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
1165 			if (G_p->g_attrparent_p == NULL) {
1166 				*G_p->g_nam_p = '\0';
1167 			}
1168 			if (Renam_attr_p) {
1169 				*Renam_attr_p = '\0';
1170 			}
1171 			return (F_SKIP);
1172 		} else if (strcmp(Renametmp_p, ".") != 0) {
1173 			if (G_p->g_attrnam_p == NULL) {
1174 				if (strlen(Renametmp_p) > strlen(
1175 				    G_p->g_nam_p)) {
1176 					if ((G_p->g_nam_p != &nambuf[0]) &&
1177 					    (G_p->g_nam_p != &fullnam[0])) {
1178 						free(G_p->g_nam_p);
1179 						G_p->g_nam_p = e_zalloc(E_EXIT,
1180 						    rename_bufsz);
1181 					}
1182 				}
1183 				if (Renam_attr_p) {
1184 					*Renam_attr_p = '\0';
1185 				}
1186 				if ((strlcpy(Renam_p, Renametmp_p,
1187 				    rename_bufsz) > rename_bufsz) ||
1188 				    (strlcpy(G_p->g_nam_p, Renametmp_p,
1189 				    rename_bufsz) > rename_bufsz)) {
1190 					msg(EXTN, "buffer overflow");
1191 				}
1192 			} else {
1193 				if (G_p->g_attrnam_p != NULL) {
1194 					free(G_p->g_attrnam_p);
1195 					G_p->g_attrnam_p = e_strdup(E_EXIT,
1196 					    Renametmp_p);
1197 					(void) strcpy(G_p->g_nam_p, Renam_p);
1198 					if (Renam_attr_p) {
1199 						if (strlcpy(Renam_attr_p,
1200 						    Renametmp_p, rename_bufsz) >
1201 						    rename_bufsz) {
1202 							msg(EXTN,
1203 							    "buffer overflow");
1204 						}
1205 					}
1206 				}
1207 			}
1208 		} else {
1209 			if (G_p->g_attrnam_p == NULL) {
1210 				*Renam_p = '\0';
1211 			}
1212 			if (Renam_attr_p) {
1213 				*Renam_attr_p = '\0';
1214 			}
1215 		}
1216 	}
1217 	if (flag != 0 || Onecopy == 0) {
1218 		VERBOSE((Args & OCt), G_p->g_nam_p);
1219 	}
1220 	if (Args & OCt)
1221 		return (F_SKIP);
1222 	return (F_EXTR);
1223 }
1224 
1225 /*
1226  * ckopts: Check the validity of all command line options.
1227  */
1228 
1229 static void
ckopts(long mask)1230 ckopts(long mask)
1231 {
1232 	int oflag;
1233 	char *t_p;
1234 	long errmsk;
1235 	uid_t	Euid = geteuid();	/* Effective uid of invoker */
1236 #ifdef SOLARIS_PRIVS
1237 	priv_set_t *privset;
1238 	priv_set_t *zones_privset;
1239 #endif	/* SOLARIS_PRIVS */
1240 
1241 	if (mask & OCi) {
1242 		errmsk = mask & INV_MSK4i;
1243 	} else if (mask & OCo) {
1244 		errmsk = mask & INV_MSK4o;
1245 	} else if (mask & OCp) {
1246 		errmsk = mask & INV_MSK4p;
1247 	} else {
1248 		msg(ERR, "One of -i, -o or -p must be specified.");
1249 		errmsk = 0;
1250 	}
1251 
1252 	if (errmsk) {
1253 		/* if non-zero, invalid options were specified */
1254 		Error_cnt++;
1255 	}
1256 
1257 	if ((mask & OCa) && (mask & OCm) && ((mask & OCi) ||
1258 	    (mask & OCo))) {
1259 		msg(ERR, "-a and -m are mutually exclusive.");
1260 	}
1261 
1262 	if ((mask & OCc) && (mask & OCH) &&
1263 	    (strcmp("odc", Hdr_p) != 0 && strcmp("odc_sparse", Hdr_p) != 0)) {
1264 		msg(ERR, "-c and -H are mutually exclusive.");
1265 	}
1266 
1267 	if ((mask & OCv) && (mask & OCV)) {
1268 		msg(ERR, "-v and -V are mutually exclusive.");
1269 	}
1270 
1271 	if ((mask & OCt) && (mask & OCV)) {
1272 		msg(ERR, "-t and -V are mutually exclusive.");
1273 	}
1274 
1275 	if ((mask & OCB) && (mask & OCC)) {
1276 		msg(ERR, "-B and -C are mutually exclusive.");
1277 	}
1278 
1279 	if ((mask & OCH) && (mask & OC6)) {
1280 		msg(ERR, "-H and -6 are mutually exclusive.");
1281 	}
1282 
1283 	if ((mask & OCM) && !((mask & OCI) || (mask & OCO))) {
1284 		msg(ERR, "-M not meaningful without -O or -I.");
1285 	}
1286 
1287 	if ((mask & OCA) && !(mask & OCO)) {
1288 		msg(ERR, "-A requires the -O option.");
1289 	}
1290 
1291 	if (Bufsize <= 0) {
1292 		msg(ERR, "Illegal size given for -C option.");
1293 	}
1294 
1295 	if (mask & OCH) {
1296 		t_p = Hdr_p;
1297 
1298 		while (*t_p != '\0') {
1299 			if (isupper(*t_p)) {
1300 				*t_p = 'a' + (*t_p - 'A');
1301 			}
1302 
1303 			t_p++;
1304 		}
1305 
1306 		if (!(strcmp("odc", Hdr_p))) {
1307 			Hdr_type = CHR;
1308 			Max_namesz = CPATH;
1309 			Onecopy = 0;
1310 			Use_old_stat = 1;
1311 		} else if (!(strcmp("odc_sparse", Hdr_p))) {
1312 			Hdr_type = CHR;
1313 			Max_namesz = CPATH;
1314 			Onecopy = 0;
1315 			Use_old_stat = 1;
1316 			Compress_sparse = 1;
1317 		} else if (!(strcmp("ascii_sparse", Hdr_p))) {
1318 			Hdr_type = ASC;
1319 			Max_namesz = APATH;
1320 			Onecopy = 1;
1321 			Compress_sparse = 1;
1322 		} else if (!(strcmp("crc", Hdr_p))) {
1323 			Hdr_type = CRC;
1324 			Max_namesz = APATH;
1325 			Onecopy = 1;
1326 		} else if (!(strcmp("tar", Hdr_p))) {
1327 			if (Args & OCo) {
1328 				Hdr_type = USTAR;
1329 				Max_namesz = HNAMLEN - 1;
1330 			} else {
1331 				Hdr_type = TAR;
1332 				Max_namesz = TNAMLEN - 1;
1333 			}
1334 			Onecopy = 0;
1335 		} else if (!(strcmp("ustar", Hdr_p))) {
1336 			Hdr_type = USTAR;
1337 			Max_namesz = HNAMLEN - 1;
1338 			Onecopy = 0;
1339 		} else if (!(strcmp("bar", Hdr_p))) {
1340 			if ((Args & OCo) || (Args & OCp)) {
1341 				msg(ERR,
1342 				    "Header type bar can only be used with -i");
1343 			}
1344 
1345 			if (Args & OCP) {
1346 				msg(ERR,
1347 				    "Can't preserve using bar header");
1348 			}
1349 
1350 			Hdr_type = BAR;
1351 			Max_namesz = TNAMLEN - 1;
1352 			Onecopy = 0;
1353 		} else {
1354 			msg(ERR, "Invalid header \"%s\" specified", Hdr_p);
1355 		}
1356 	}
1357 
1358 	if (mask & OCr) {
1359 		Rtty_p = fopen(Ttyname, "r");
1360 		Wtty_p = fopen(Ttyname, "w");
1361 
1362 		if (Rtty_p == NULL || Wtty_p == NULL) {
1363 			msg(ERR, "Cannot rename, \"%s\" missing", Ttyname);
1364 		}
1365 	}
1366 
1367 	if ((mask & OCE) && (Ef_p = fopen(Efil_p, "r")) == NULL) {
1368 		msg(ERR, "Cannot open \"%s\" to read patterns", Efil_p);
1369 	}
1370 
1371 	if ((mask & OCI) && (Archive = open(IOfil_p, O_RDONLY)) < 0) {
1372 		msg(ERR, "Cannot open \"%s\" for input", IOfil_p);
1373 	}
1374 
1375 	if (mask & OCO) {
1376 		if (mask & OCA) {
1377 			if ((Archive = open(IOfil_p, O_RDWR)) < 0) {
1378 				msg(ERR,
1379 				    "Cannot open \"%s\" for append",
1380 				    IOfil_p);
1381 			}
1382 		} else {
1383 			oflag = (O_WRONLY | O_CREAT | O_TRUNC);
1384 
1385 			if ((Archive = open(IOfil_p, oflag, 0777)) < 0) {
1386 				msg(ERR,
1387 				    "Cannot open \"%s\" for output",
1388 				    IOfil_p);
1389 			}
1390 		}
1391 	}
1392 
1393 #ifdef SOLARIS_PRIVS
1394 	if ((privset = priv_allocset()) == NULL) {
1395 		msg(ERR, "Unable to allocate privilege set");
1396 	} else if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1397 		msg(ERR, "Unable to obtain privilege set");
1398 	} else {
1399 		zones_privset = priv_str_to_set("zone", "", NULL);
1400 		if (zones_privset != NULL) {
1401 			privileged = (priv_issubset(zones_privset,
1402 			    privset) == B_TRUE);
1403 			priv_freeset(zones_privset);
1404 		} else {
1405 			msg(ERR, "Unable to map privilege to privilege set");
1406 		}
1407 	}
1408 	if (privset != NULL) {
1409 		priv_freeset(privset);
1410 	}
1411 #else
1412 	privileged = (Euid == 0);
1413 #endif	/* SOLARIS_PRIVS */
1414 
1415 	if (mask & OCR) {
1416 		if ((Rpw_p = getpwnam(Own_p)) == NULL) {
1417 			msg(ERR, "\"%s\" is not a valid user id", Own_p);
1418 		} else if ((Euid != Rpw_p->pw_uid) && !privileged) {
1419 			msg(ERR, "R option only valid for super-user or "
1420 			    "id matches login id of user executing cpio");
1421 		}
1422 	}
1423 
1424 	if ((mask & OCo) && !(mask & OCO)) {
1425 		Out_p = stderr;
1426 	}
1427 
1428 	if ((mask & OCp) && ((mask & (OCB|OCC)) == 0)) {
1429 		/*
1430 		 * We are in pass mode with no block size specified.  Use the
1431 		 * larger of the native page size and 8192.
1432 		 */
1433 
1434 		Bufsize = (PageSize > 8192) ? PageSize : 8192;
1435 	}
1436 }
1437 
1438 /*
1439  * cksum: Calculate the simple checksum of a file (CRC) or header
1440  * (TARTYP (TAR and USTAR)).  For -o and the CRC header, the file is opened and
1441  * the checksum is calculated.  For -i and the CRC header, the checksum
1442  * is calculated as each block is transferred from the archive I/O buffer
1443  * to the file system I/O buffer.  The TARTYP (TAR and USTAR) headers calculate
1444  * the simple checksum of the header (with the checksum field of the
1445  * header initialized to all spaces (\040).
1446  */
1447 
1448 static long
cksum(char hdr,int byt_cnt,int * err)1449 cksum(char hdr, int byt_cnt, int *err)
1450 {
1451 	char *crc_p, *end_p;
1452 	int cnt;
1453 	long checksum = 0L, have;
1454 	off_t lcnt;
1455 
1456 	if (err != NULL)
1457 		*err = 0;
1458 	switch (hdr) {
1459 	case CRC:
1460 		if (Args & OCi) { /* do running checksum */
1461 			end_p = Buffr.b_out_p + byt_cnt;
1462 			for (crc_p = Buffr.b_out_p; crc_p < end_p; crc_p++)
1463 				checksum += (long)*crc_p;
1464 			break;
1465 		}
1466 		/* OCo - do checksum of file */
1467 		lcnt = G_p->g_filesz;
1468 
1469 		while (lcnt > 0) {
1470 			have = (lcnt < Bufsize) ? lcnt : Bufsize;
1471 			errno = 0;
1472 			if (read(Ifile, Buf_p, have) != have) {
1473 				msg(ERR, "Error computing checksum.");
1474 				if (err != NULL)
1475 					*err = 1;
1476 				break;
1477 			}
1478 			end_p = Buf_p + have;
1479 			for (crc_p = Buf_p; crc_p < end_p; crc_p++)
1480 				checksum += (long)*crc_p;
1481 			lcnt -= have;
1482 		}
1483 		if (lseek(Ifile, (off_t)0, SEEK_ABS) < 0)
1484 			msg(ERRN, "Cannot reset file after checksum");
1485 		break;
1486 	case TARTYP: /* TAR and USTAR */
1487 		crc_p = Thdr_p->tbuf.t_cksum;
1488 		for (cnt = 0; cnt < TCRCLEN; cnt++) {
1489 			*crc_p = '\040';
1490 			crc_p++;
1491 		}
1492 		crc_p = (char *)Thdr_p;
1493 		for (cnt = 0; cnt < TARSZ; cnt++) {
1494 			/*
1495 			 * tar uses unsigned checksum, so we must use unsigned
1496 			 * here in order to be able to read tar archives.
1497 			 */
1498 			checksum += (long)((unsigned char)(*crc_p));
1499 			crc_p++;
1500 		}
1501 		break;
1502 	default:
1503 		msg(EXT, "Impossible header type.");
1504 	} /* hdr */
1505 	return (checksum);
1506 }
1507 
1508 /*
1509  * creat_hdr: Fill in the generic header structure with the specific
1510  *            header information based on the value of Hdr_type.
1511  *
1512  *            return (1) if this process was successful, and (0) otherwise.
1513  */
1514 
1515 static int
creat_hdr(void)1516 creat_hdr(void)
1517 {
1518 	ushort_t ftype;
1519 	int fullnamesize;
1520 	dev_t dev;
1521 	ino_t ino;
1522 
1523 	ftype = SrcSt.st_mode & Ftype;
1524 	Adir = (ftype == S_IFDIR);
1525 	Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO ||
1526 	    ftype == S_IFSOCK);
1527 	switch (Hdr_type) {
1528 		case BIN:
1529 			Gen.g_magic = CMN_BIN;
1530 			break;
1531 		case CHR:
1532 			Gen.g_magic = CMN_BIN;
1533 			break;
1534 		case ASC:
1535 			Gen.g_magic = CMN_ASC;
1536 			break;
1537 		case CRC:
1538 			Gen.g_magic = CMN_CRC;
1539 			break;
1540 		case USTAR:
1541 			/*
1542 			 * If the length of the full name is greater than 256,
1543 			 * print out a message and return.
1544 			 */
1545 			if ((fullnamesize = strlen(Gen.g_nam_p)) > MAXNAM) {
1546 				msg(ERR,
1547 				    "%s: file name too long", Gen.g_nam_p);
1548 				return (0);
1549 			} else if (fullnamesize > NAMSIZ) {
1550 				/*
1551 				 * The length of the full name is greater than
1552 				 * 100, so we must split the filename from the
1553 				 * path
1554 				 */
1555 				char namebuff[NAMSIZ+1];
1556 				char prebuff[PRESIZ+1];
1557 				char *lastslash;
1558 				int presize, namesize;
1559 
1560 				(void) memset(namebuff, '\0',
1561 				    sizeof (namebuff));
1562 				(void) memset(prebuff, '\0', sizeof (prebuff));
1563 
1564 				lastslash = strrchr(Gen.g_nam_p, '/');
1565 
1566 				if (lastslash != NULL) {
1567 					namesize = strlen(++lastslash);
1568 					presize = fullnamesize - namesize - 1;
1569 				} else {
1570 					namesize = fullnamesize;
1571 					lastslash = Gen.g_nam_p;
1572 					presize = 0;
1573 				}
1574 
1575 				/*
1576 				 * If the filename is greater than 100 we can't
1577 				 * archive the file
1578 				 */
1579 				if (namesize > NAMSIZ) {
1580 					msg(ERR,
1581 					    "%s: filename is greater than %d",
1582 					    lastslash, NAMSIZ);
1583 					return (0);
1584 				}
1585 				(void) strncpy(&namebuff[0], lastslash,
1586 				    namesize);
1587 				/*
1588 				 * If the prefix is greater than 155 we can't
1589 				 * archive the file.
1590 				 */
1591 				if (presize > PRESIZ) {
1592 					msg(ERR,
1593 					    "%s: prefix is greater than %d",
1594 					    Gen.g_nam_p, PRESIZ);
1595 					return (0);
1596 				}
1597 				(void) strncpy(&prebuff[0], Gen.g_nam_p,
1598 				    presize);
1599 
1600 				Gen.g_tname = e_zalloc(E_EXIT, namesize + 1);
1601 				(void) strcpy(Gen.g_tname, namebuff);
1602 
1603 				Gen.g_prefix = e_zalloc(E_EXIT, presize + 1);
1604 				(void) strcpy(Gen.g_prefix, prebuff);
1605 			} else {
1606 				Gen.g_tname = Gen.g_nam_p;
1607 			}
1608 			(void) strcpy(Gen.g_tmagic, "ustar");
1609 			(void) strcpy(Gen.g_version, "00");
1610 
1611 			dpasswd = getpwuid(SrcSt.st_uid);
1612 			if (dpasswd == NULL) {
1613 				msg(EPOST,
1614 				    "cpio: could not get passwd information "
1615 				    "for %s%s%s",
1616 				    (Gen.g_attrnam_p == NULL) ?
1617 				    Gen.g_nam_p : Gen.g_attrfnam_p,
1618 				    (Gen.g_attrnam_p == NULL) ?
1619 				    "" : Gen.g_rw_sysattr ?
1620 				    gettext(" System Attribute ") :
1621 				    gettext(" Attribute "),
1622 				    (Gen.g_attrnam_p == NULL) ?
1623 				    "" : Gen.g_attrnam_p);
1624 				/* make name null string */
1625 				Gen.g_uname[0] = '\0';
1626 			} else {
1627 				(void) strncpy(&Gen.g_uname[0],
1628 				    dpasswd->pw_name, 32);
1629 			}
1630 			dgroup = getgrgid(SrcSt.st_gid);
1631 			if (dgroup == NULL) {
1632 				msg(EPOST,
1633 				    "cpio: could not get group information "
1634 				    "for %s%s%s",
1635 				    (Gen.g_attrnam_p == NULL) ?
1636 				    Gen.g_nam_p : Gen.g_attrfnam_p,
1637 				    (Gen.g_attrnam_p == NULL) ?
1638 				    "" : Gen.g_rw_sysattr ?
1639 				    gettext(" System Attribute ") :
1640 				    gettext(" Attribute "),
1641 				    (Gen.g_attrnam_p == NULL) ?
1642 				    "" : Gen.g_attrnam_p);
1643 				/* make name null string */
1644 				Gen.g_gname[0] = '\0';
1645 			} else {
1646 				(void) strncpy(&Gen.g_gname[0],
1647 				    dgroup->gr_name, 32);
1648 			}
1649 			Gen.g_typeflag = tartype(ftype);
1650 			/* FALLTHROUGH */
1651 		case TAR:
1652 			(void) memset(T_lname, '\0', sizeof (T_lname));
1653 			break;
1654 		default:
1655 			msg(EXT, "Impossible header type.");
1656 	}
1657 
1658 	if (Use_old_stat && (Gen.g_attrnam_p != NULL)) {
1659 		/*
1660 		 * When processing extended attributes, creat_hdr()
1661 		 * can get called multiple times which means that
1662 		 * SrcSt.st.st_dev would have gotten converted to
1663 		 * -Hodc format.  We should always use the original
1664 		 * device here as we need to be able to match on
1665 		 * the original device id from the file that was
1666 		 * previewed in sl_preview_synonyms().
1667 		 */
1668 		dev = Savedev;
1669 	} else {
1670 		dev = SrcSt.st_dev;
1671 	}
1672 	ino = SrcSt.st_ino;
1673 
1674 	if (Use_old_stat) {
1675 		SrcSt = *OldSt;
1676 	}
1677 
1678 	Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
1679 	Gen.g_uid = SrcSt.st_uid;
1680 	Gen.g_gid = SrcSt.st_gid;
1681 	Gen.g_dev = SrcSt.st_dev;
1682 
1683 	if (Use_old_stat) {
1684 		/* -Hodc */
1685 
1686 		sl_info_t *p = sl_search(dev, ino, ftype);
1687 		Gen.g_ino = p ? p->sl_ino2 : -1;
1688 
1689 		if (Gen.g_ino == (ulong_t)-1) {
1690 			msg(ERR, "%s%s%s: cannot be archived - inode too big "
1691 			    "for -Hodc format",
1692 			    (Gen.g_attrnam_p == NULL) ?
1693 			    Gen.g_nam_p : Gen.g_attrfnam_p,
1694 			    (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
1695 			    gettext(" System Attribute ") :
1696 			    gettext(" Attribute "),
1697 			    (Gen.g_attrnam_p == NULL) ? "" : Gen.g_attrnam_p);
1698 			return (0);
1699 		}
1700 	} else {
1701 		Gen.g_ino = SrcSt.st_ino;
1702 	}
1703 
1704 	Gen.g_mode = SrcSt.st_mode;
1705 	Gen.g_mtime = SrcSt.st_mtime;
1706 	Gen.g_nlink = Adir ? SrcSt.st_nlink : sl_numlinks(dev, ino, ftype);
1707 
1708 	if (ftype == S_IFREG || ftype == S_IFLNK)
1709 		Gen.g_filesz = (off_t)SrcSt.st_size;
1710 	else
1711 		Gen.g_filesz = (off_t)0;
1712 	Gen.g_rdev = SrcSt.st_rdev;
1713 	return (1);
1714 }
1715 
1716 /*
1717  * creat_lnk: Create a link from the existing name1_p to name2_p.
1718  */
1719 
1720 static
1721 int
creat_lnk(int dirfd,char * name1_p,char * name2_p)1722 creat_lnk(int dirfd, char *name1_p, char *name2_p)
1723 {
1724 	int cnt = 0;
1725 
1726 	do {
1727 		errno = 0;
1728 		if (!link(name1_p, name2_p)) {
1729 			if (aclp != NULL) {
1730 				acl_free(aclp);
1731 				aclp = NULL;
1732 				acl_is_set = 0;
1733 			}
1734 			cnt = 0;
1735 			break;
1736 		} else if ((errno == EEXIST) && (cnt == 0)) {
1737 			struct stat lsb1;
1738 			struct stat lsb2;
1739 
1740 			/*
1741 			 * Check to see if we are trying to link this
1742 			 * file to itself.  If so, count the effort as
1743 			 * successful.  If the two files are different,
1744 			 * or if either lstat is unsuccessful, proceed
1745 			 * as we would have otherwise; the appropriate
1746 			 * error will be reported subsequently.
1747 			 */
1748 
1749 			if (lstat(name1_p, &lsb1) != 0) {
1750 				msg(ERR, "Cannot lstat source file %s",
1751 				    name1_p);
1752 			} else {
1753 				if (lstat(name2_p, &lsb2) != 0) {
1754 					msg(ERR, "Cannot lstat "
1755 					    "destination file %s", name2_p);
1756 				} else {
1757 					if (lsb1.st_dev == lsb2.st_dev &&
1758 					    lsb1.st_ino == lsb2.st_ino) {
1759 						VERBOSE((Args & (OCv | OCV)),
1760 						    name2_p);
1761 						return (0);
1762 					}
1763 				}
1764 			}
1765 
1766 			if (!(Args & OCu) && G_p->g_mtime <= DesSt.st_mtime)
1767 				msg(ERR, "Existing \"%s\" same age or newer",
1768 				    name2_p);
1769 			else if (unlinkat(dirfd, get_component(name2_p), 0) < 0)
1770 				msg(ERRN, "Error cannot unlink \"%s\"",
1771 				    name2_p);
1772 		}
1773 		cnt++;
1774 	} while ((cnt < 2) && missdir(name2_p) == 0);
1775 	if (!cnt) {
1776 		char *newname;
1777 		char *fromname;
1778 		char *attrname;
1779 
1780 		newname = name2_p;
1781 		fromname = name1_p;
1782 		attrname = Gen.g_attrnam_p;
1783 		if (attrname) {
1784 			if (Args & OCp) {
1785 				newname = fromname = Fullnam_p;
1786 			} else {
1787 				newname = Gen.g_attrfnam_p;
1788 			}
1789 		}
1790 		if (Args & OCv) {
1791 			(void) fprintf(Err_p,
1792 			    gettext("%s%s%s linked to %s%s%s\n"), newname,
1793 			    (attrname == NULL) ? "" : gettext(" attribute "),
1794 			    (attrname == NULL) ? "" : attrname,
1795 			    (attrname == NULL) ? fromname : newname,
1796 			    (attrname == NULL) ? "" : gettext(" attribute "),
1797 			    (attrname == NULL) ? "" : name1_p);
1798 		} else {
1799 			VERBOSE((Args & (OCv | OCV)), newname);
1800 		}
1801 	} else if (cnt == 1)
1802 		msg(ERRN,
1803 		    "Unable to create directory for \"%s\"", name2_p);
1804 	else if (cnt == 2)
1805 		msg(ERRN,
1806 		    "Cannot link \"%s\" and \"%s\"", name1_p, name2_p);
1807 	return (cnt);
1808 }
1809 
1810 /*
1811  * creat_spec:
1812  *   Create one of the following:
1813  *       directory
1814  *       character special file
1815  *       block special file
1816  *       fifo
1817  *	 socket
1818  */
1819 
1820 static int
creat_spec(int dirfd)1821 creat_spec(int dirfd)
1822 {
1823 	char *nam_p;
1824 	int cnt, result, rv = 0;
1825 	char *curdir;
1826 	char *lastslash;
1827 
1828 	Do_rename = 0;	/* creat_tmp() may reset this */
1829 
1830 	if (Args & OCp) {
1831 		nam_p = Fullnam_p;
1832 	} else {
1833 		nam_p = G_p->g_nam_p;
1834 	}
1835 
1836 	/*
1837 	 * Is this the extraction of the hidden attribute directory?
1838 	 * If we are processing the hidden attribute directory of an
1839 	 * attribute, then just return as modes and times cannot be set.
1840 	 * Otherwise, if we are processing a hidden attribute, just set
1841 	 * the mode/times correctly and return.
1842 	 */
1843 
1844 	if (Hiddendir) {
1845 		if (G_p->g_attrparent_p == NULL) {
1846 			if (Args & OCR) {
1847 				if (fchownat(dirfd, ".", Rpw_p->pw_uid,
1848 				    Rpw_p->pw_gid, 0) != 0) {
1849 					msg(ERRN,
1850 					    "Cannot chown() \"attribute "
1851 					    "directory of file %s\"",
1852 					    G_p->g_attrfnam_p);
1853 				}
1854 			} else if ((fchownat(dirfd, ".", G_p->g_uid,
1855 			    G_p->g_gid, 0) != 0) && privileged) {
1856 				msg(ERRN,
1857 				    "Cannot chown() \"attribute directory of "
1858 				    "file %s\"", G_p->g_attrfnam_p);
1859 			}
1860 
1861 			if (fchmod(dirfd, G_p->g_mode) != 0) {
1862 				msg(ERRN,
1863 				    "Cannot chmod() \"attribute directory of "
1864 				    "file %s\"", G_p->g_attrfnam_p);
1865 			}
1866 
1867 			acl_is_set = 0;
1868 			if (Pflag && aclp != NULL) {
1869 				if (facl_set(dirfd, aclp) < 0) {
1870 					msg(ERRN,
1871 					    "failed to set acl on attribute"
1872 					    " directory of %s ",
1873 					    G_p->g_attrfnam_p);
1874 				} else {
1875 					acl_is_set = 1;
1876 				}
1877 				acl_free(aclp);
1878 				aclp = NULL;
1879 			}
1880 		}
1881 
1882 		return (1);
1883 	}
1884 
1885 	result = stat(nam_p, &DesSt);
1886 
1887 	if (ustar_dir() || Adir) {
1888 		/*
1889 		 *  The archive file is a directory.
1890 		 *  Skip "." and ".."
1891 		 */
1892 
1893 		curdir = strrchr(nam_p, '.');
1894 
1895 		if (curdir != NULL && curdir[1] == '\0') {
1896 			lastslash = strrchr(nam_p, '/');
1897 
1898 			if (lastslash != NULL) {
1899 				lastslash++;
1900 			} else {
1901 				lastslash = nam_p;
1902 			}
1903 
1904 			if (!(strcmp(lastslash, ".")) ||
1905 			    !(strcmp(lastslash, ".."))) {
1906 				return (1);
1907 			}
1908 		}
1909 
1910 		if (result == 0) {
1911 			/* A file by the same name exists. */
1912 
1913 			/* Take care of ACLs */
1914 			acl_is_set = 0;
1915 
1916 			if (Pflag && aclp != NULL) {
1917 				if (acl_set(nam_p, aclp) < 0) {
1918 					msg(ERRN,
1919 					    "\"%s\": failed to set acl",
1920 					    nam_p);
1921 				} else {
1922 					acl_is_set = 1;
1923 				}
1924 
1925 				acl_free(aclp);
1926 				aclp = NULL;
1927 			}
1928 			if (Args & OCd) {
1929 				/*
1930 				 * We are creating directories.  Keep the
1931 				 * existing file.
1932 				 */
1933 
1934 				rstfiles(U_KEEP, dirfd);
1935 			}
1936 
1937 			/* Report success. */
1938 
1939 			return (1);
1940 		}
1941 	} else {
1942 		/* The archive file is not a directory. */
1943 
1944 		if (result == 0) {
1945 			/*
1946 			 * A file by the same name exists.  Move it to a
1947 			 * temporary file.
1948 			 */
1949 
1950 			if (creat_tmp(nam_p) < 0) {
1951 				/*
1952 				 * We weren't able to create the temp file.
1953 				 * Report failure.
1954 				 */
1955 
1956 				return (0);
1957 			}
1958 		}
1959 	}
1960 
1961 	/*
1962 	 * This pile tries to create the file directly, and, if there is a
1963 	 * problem, creates missing directories, and then tries to create the
1964 	 * file again.  Two strikes and you're out.
1965 	 */
1966 
1967 	cnt = 0;
1968 
1969 	do {
1970 		if (ustar_dir() || Adir) {
1971 			/* The archive file is a directory. */
1972 
1973 			result = mkdir(nam_p, G_p->g_mode);
1974 		} else if (ustar_spec() || Aspec) {
1975 			/*
1976 			 * The archive file is block special,
1977 			 * char special, socket, or a fifo.
1978 			 * Note that, for a socket, the third
1979 			 * parameter to mknod() is ignored.
1980 			 */
1981 
1982 			result = mknod(nam_p, (int)G_p->g_mode,
1983 			    (int)G_p->g_rdev);
1984 		}
1985 
1986 		if (result >= 0) {
1987 			/*
1988 			 * The file creation succeeded.  Take care of the ACLs.
1989 			 */
1990 
1991 			acl_is_set = 0;
1992 
1993 			if (Pflag && aclp != NULL) {
1994 				if (acl_set(nam_p, aclp) < 0) {
1995 					msg(ERRN,
1996 					    "\"%s\": failed to set acl", nam_p);
1997 				} else {
1998 					acl_is_set = 1;
1999 				}
2000 
2001 				acl_free(aclp);
2002 				aclp = NULL;
2003 			}
2004 
2005 			cnt = 0;
2006 			break;
2007 		}
2008 
2009 		cnt++;
2010 	} while (cnt < 2 && missdir(nam_p) == 0);
2011 
2012 	switch (cnt) {
2013 	case 0:
2014 		rv = 1;
2015 		rstfiles(U_OVER, dirfd);
2016 		break;
2017 
2018 	case 1:
2019 		msg(ERRN,
2020 		    "Cannot create directory for \"%s\"", nam_p);
2021 
2022 		if (*Over_p == '\0') {
2023 			rstfiles(U_KEEP, dirfd);
2024 		}
2025 
2026 		break;
2027 
2028 	case 2:
2029 		if (ustar_dir() || Adir) {
2030 			msg(ERRN, "Cannot create directory \"%s\"", nam_p);
2031 		} else if (ustar_spec() || Aspec) {
2032 			msg(ERRN, "Cannot mknod() \"%s\"", nam_p);
2033 		}
2034 
2035 		if (*Over_p == '\0') {
2036 			rstfiles(U_KEEP, dirfd);
2037 		}
2038 
2039 		break;
2040 
2041 	default:
2042 		msg(EXT, "Impossible case.");
2043 	}
2044 
2045 	return (rv);
2046 }
2047 
2048 /*
2049  * creat_tmp:
2050  */
2051 
2052 static int
creat_tmp(char * nam_p)2053 creat_tmp(char *nam_p)
2054 {
2055 	char *t_p;
2056 	int	cwd;
2057 
2058 	if ((Args & OCp) && G_p->g_ino == DesSt.st_ino &&
2059 	    G_p->g_dev == DesSt.st_dev) {
2060 		msg(ERR, "Attempt to pass a file to itself.");
2061 		return (-1);
2062 	}
2063 
2064 	if (G_p->g_mtime <= DesSt.st_mtime && !(Args & OCu)) {
2065 		msg(ERR, "Existing \"%s\" same age or newer", nam_p);
2066 		return (-1);
2067 	}
2068 
2069 	/* Make the temporary file name. */
2070 
2071 	(void) strcpy(Over_p, nam_p);
2072 	t_p = Over_p + strlen(Over_p);
2073 
2074 	while (t_p != Over_p) {
2075 		if (*(t_p - 1) == '/')
2076 			break;
2077 		t_p--;
2078 	}
2079 
2080 	(void) strcpy(t_p, "XXXXXX");
2081 
2082 	if (G_p->g_attrnam_p != NULL) {
2083 		/*
2084 		 * Save our current directory, so we can go into
2085 		 * the attribute directory to make the temp file
2086 		 * and then return.
2087 		 */
2088 
2089 		cwd = save_cwd();
2090 		(void) fchdir(G_p->g_dirfd);
2091 	}
2092 
2093 	(void) mktemp(Over_p);
2094 
2095 	if (G_p->g_attrnam_p != NULL) {
2096 		/* Return to the current directory. */
2097 
2098 		rest_cwd(cwd);
2099 	}
2100 
2101 	if (*Over_p == '\0') {
2102 		/* mktemp reports a failure. */
2103 
2104 		msg(ERR, "Cannot get temporary file name.");
2105 		return (-1);
2106 	}
2107 
2108 	/*
2109 	 * If it's a regular file, write to the temporary file, and then rename
2110 	 * in order to accommodate potential executables.
2111 	 *
2112 	 * Note: g_typeflag is only defined (set) for USTAR archive types.  It
2113 	 * defaults to 0 in the cpio-format-regular file case, so this test
2114 	 * succeeds.
2115 	 */
2116 
2117 	if (G_p->g_typeflag == 0 &&
2118 	    (DesSt.st_mode & (ulong_t)Ftype) == S_IFREG &&
2119 	    (G_p->g_mode & (ulong_t)Ftype) == S_IFREG) {
2120 		/*
2121 		 * The archive file and the filesystem file are both regular
2122 		 * files.  We write to the temporary file in this case.
2123 		 */
2124 
2125 		if (Args & OCp) {
2126 			if (G_p->g_attrnam_p == NULL) {
2127 				Fullnam_p = Over_p;
2128 			} else {
2129 				Attrfile_p = Over_p;
2130 			}
2131 		} else {
2132 			G_p->g_nam_p = Over_p;
2133 			if (G_p->g_attrnam_p != NULL) {
2134 				Attrfile_p = Over_p;
2135 			}
2136 		}
2137 
2138 		if (G_p->g_attrnam_p == NULL) {
2139 			Over_p = nam_p;
2140 		} else {
2141 			Over_p = G_p->g_attrnam_p;
2142 		}
2143 
2144 		Do_rename = 1;
2145 	} else {
2146 		/*
2147 		 * Either the archive file or the filesystem file is not a
2148 		 * regular file.
2149 		 */
2150 
2151 		Do_rename = 0;
2152 
2153 		if (S_ISDIR(DesSt.st_mode)) {
2154 			/*
2155 			 * The filesystem file is a directory.
2156 			 *
2157 			 * Save the current working directory because we will
2158 			 * want to restore it back just in case remove_dir()
2159 			 * fails or get confused about where we should be.
2160 			 */
2161 
2162 			*Over_p = '\0';
2163 			cwd = save_cwd();
2164 
2165 			if (remove_dir(nam_p) < 0) {
2166 				msg(ERRN,
2167 				    "Cannot remove the directory \"%s\"",
2168 				    nam_p);
2169 				/*
2170 				 * Restore working directory back to the one
2171 				 * saved earlier.
2172 				 */
2173 
2174 				rest_cwd(cwd);
2175 				return (-1);
2176 			}
2177 
2178 			/*
2179 			 * Restore working directory back to the one
2180 			 * saved earlier
2181 			 */
2182 
2183 			rest_cwd(cwd);
2184 		} else {
2185 			/*
2186 			 * The file is not a directory. Will use the original
2187 			 * link/unlink construct, however, if the file is
2188 			 * namefs, link would fail with EXDEV. Therefore, we
2189 			 * use rename() first to back up the file.
2190 			 */
2191 			if (rename(nam_p, Over_p) < 0) {
2192 				/*
2193 				 * If rename failed, try old construction
2194 				 * method.
2195 				 */
2196 				if (link(nam_p, Over_p) < 0) {
2197 					msg(ERRN,
2198 					    "Cannot rename temporary file "
2199 					    "\"%s\" to \"%s\"", Over_p, nam_p);
2200 					*Over_p = '\0';
2201 					return (-1);
2202 				}
2203 
2204 				if (unlink(nam_p) < 0) {
2205 					msg(ERRN,
2206 					    "Cannot unlink() current \"%s\"",
2207 					    nam_p);
2208 					(void) unlink(Over_p);
2209 					*Over_p = '\0';
2210 					return (-1);
2211 				}
2212 			}
2213 		}
2214 	}
2215 
2216 	return (1);
2217 }
2218 
2219 /*
2220  * Copy the datasize amount of data from the input file to buffer.
2221  *
2222  * ifd		- Input file descriptor.
2223  * buffer	- Buffer (allocated by caller) to copy data to.
2224  * datasize	- The amount of data to read from the input file
2225  *		and copy to the buffer.
2226  * error	- When reading from an Archive file, indicates unreadable
2227  *		data was encountered, otherwise indicates errno.
2228  * data_in_info	- Information needed when called from data_in().
2229  */
2230 static ssize_t
read_chunk(int ifd,char * buffer,size_t datasize,data_in_t * data_in_info)2231 read_chunk(int ifd, char *buffer, size_t datasize, data_in_t *data_in_info)
2232 {
2233 	if (Args & OCp) {
2234 		return (read(ifd, buffer, datasize));
2235 	} else {
2236 		FILL(datasize);
2237 		if (data_in_info->data_in_proc_mode != P_SKIP) {
2238 			if (Hdr_type == CRC)
2239 				data_in_info->data_in_cksumval += cksum(CRC,
2240 				    datasize, NULL);
2241 			if (data_in_info->data_in_swapfile)
2242 				swap(Buffr.b_out_p, datasize);
2243 
2244 
2245 			/*
2246 			 * if the bar archive is compressed, set up a pipe and
2247 			 * do the de-compression while reading in the file
2248 			 */
2249 			if (Hdr_type == BAR) {
2250 				if (data_in_info->data_in_compress_flag == 0 &&
2251 				    Compressed) {
2252 					setup_uncompress(
2253 					    &(data_in_info->data_in_pipef));
2254 					data_in_info->data_in_compress_flag++;
2255 				}
2256 			}
2257 		}
2258 		(void) memcpy(buffer, Buffr.b_out_p, datasize);
2259 		Buffr.b_out_p += datasize;
2260 		Buffr.b_cnt -= datasize;
2261 		return (datasize);
2262 	}
2263 }
2264 
2265 /*
2266  * Read as much data as we can.
2267  *
2268  * ifd		- input file descriptor.
2269  * buf		- Buffer (allocated by caller) to copy data to.
2270  * bytes	- The amount of data to read from the input file
2271  *		and copy to the buffer.
2272  * rdblocksz	- The size of the chunk of data to read.
2273  *
2274  * Return number of bytes failed to read.
2275  * Return -1 when buffer is empty and read failed.
2276  */
2277 static int
read_bytes(int ifd,char * buf,size_t bytes,size_t rdblocksz,data_in_t * data_in_info)2278 read_bytes(int ifd, char *buf, size_t bytes, size_t rdblocksz,
2279     data_in_t *data_in_info)
2280 {
2281 	size_t	bytesread;
2282 	ssize_t	got;
2283 
2284 	for (bytesread = 0; bytesread < bytes; bytesread += got) {
2285 		/*
2286 		 * Read the data from either the input file descriptor
2287 		 * or the archive file.  read_chunk() will only return
2288 		 * <= 0 if data_copy() was called from data_pass().
2289 		 */
2290 		if ((got = read_chunk(ifd, buf + bytesread,
2291 		    min(bytes - bytesread, rdblocksz),
2292 		    data_in_info)) <= 0) {
2293 			/*
2294 			 * We come here only in the pass mode.
2295 			 * If data couldn't be read from the input file
2296 			 * descriptor, return number of bytes in the buf.
2297 			 * If buffer is empty, return -1.
2298 			 */
2299 			if (bytesread == 0) {
2300 				if (got == 0) /* EOF */
2301 					data_in_info->data_in_rd_eof = 1;
2302 				return (-1);
2303 			}
2304 			return (bytes - bytesread);
2305 		}
2306 	}
2307 	return (0);
2308 }
2309 
2310 /*
2311  * Write as much data as we can.
2312  *
2313  * ofd		- output file descriptor.
2314  * buf		- Source buffer to output data from.
2315  * maxwrite	- The amount of data to write to the output.
2316  *
2317  * return 0 upon success.
2318  */
2319 static int
write_bytes(int ofd,char * buf,size_t maxwrite,data_in_t * data_in_info)2320 write_bytes(int ofd, char *buf, size_t maxwrite, data_in_t *data_in_info)
2321 {
2322 	ssize_t	cnt;
2323 
2324 	errno = 0;
2325 	if ((cnt = write(ofd, buf, maxwrite)) < (ssize_t)maxwrite) {
2326 		data_in_info->data_in_errno = errno;
2327 		/*
2328 		 * data_in() needs to know if it was an actual write(2)
2329 		 * failure, or if we just couldn't write all of the data
2330 		 * requested so that we know that the rest of the file's
2331 		 * data can be read but not written.
2332 		 */
2333 		if (cnt != -1)
2334 			data_in_info->data_in_wr_part = 1;
2335 		return (1);
2336 	} else if (Args & OCp) {
2337 		Blocks += (u_longlong_t)((cnt + (Bufsize - 1)) / Bufsize);
2338 	}
2339 	return (0);
2340 }
2341 
2342 /*
2343  * Perform I/O for given byte size with using limited i/o block size
2344  * and supplied buffer.
2345  *
2346  * ifd/ofd	- i/o file descriptor
2347  * buf		- buffer to be used for i/o
2348  * bytes	- Amount to read/write
2349  * wrblocksz	- Output block size.
2350  * rdblocksz	- Read block size.
2351  *
2352  * Return 0 upon success. Return negative if read failed.
2353  * Return positive non-zero if write failed.
2354  */
2355 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)2356 rdwr_bytes(int ifd, int ofd, char *buf, off_t bytes,
2357     size_t wrblocksz, size_t rdblocksz, data_in_t *data_in_info)
2358 {
2359 	int rv, sz;
2360 	int error = 0;
2361 	int write_it = (data_in_info->data_in_proc_mode != P_SKIP);
2362 
2363 	while (bytes > 0) {
2364 		/*
2365 		 * If the number of bytes left to write is smaller than
2366 		 * the preferred I/O size, then we're about to do our final
2367 		 * write to the file, so just set wrblocksz to the number of
2368 		 * bytes left to write.
2369 		 */
2370 		if (bytes < wrblocksz)
2371 			wrblocksz = bytes;
2372 
2373 		/* Read input till satisfy output block size */
2374 		sz = read_bytes(ifd, buf, wrblocksz, rdblocksz, data_in_info);
2375 		if (sz < 0)
2376 			return (sz);
2377 
2378 		if (write_it) {
2379 			rv = write_bytes(ofd, buf,
2380 			    wrblocksz - sz, data_in_info);
2381 			if (rv != 0) {
2382 				/*
2383 				 * If we wrote partial, we return and quits.
2384 				 * Otherwise, read through the rest of input
2385 				 * to go to the next file.
2386 				 */
2387 				if ((Args & OCp) ||
2388 				    data_in_info->data_in_wr_part) {
2389 					return (rv);
2390 				} else {
2391 					write_it = 0;
2392 				}
2393 				error = 1;
2394 			}
2395 		}
2396 		bytes -= (wrblocksz - sz);
2397 	}
2398 	return (error);
2399 }
2400 
2401 /*
2402  * Write zeros for give size.
2403  *
2404  * ofd		- output file descriptor
2405  * buf		- buffer to fill with zeros
2406  * bytes	- Amount to write
2407  * wrblocksz	- Write block size
2408  *
2409  * return 0 upon success.
2410  */
2411 static int
write_zeros(int ofd,char * buf,off_t bytes,size_t wrblocksz,data_in_t * data_in_info)2412 write_zeros(int ofd, char *buf, off_t bytes, size_t wrblocksz,
2413     data_in_t *data_in_info)
2414 {
2415 	int	rv;
2416 
2417 	(void) memset(buf, 0, min(bytes, wrblocksz));
2418 	while (bytes > 0) {
2419 		if (bytes < wrblocksz)
2420 			wrblocksz = bytes;
2421 		rv = write_bytes(ofd, buf, wrblocksz, data_in_info);
2422 		if (rv != 0)
2423 			return (rv);
2424 		bytes -= wrblocksz;
2425 	}
2426 	return (0);
2427 }
2428 
2429 /*
2430  * To figure out the size of the buffer used to accumulate data from
2431  * readtape() and to write to the file, we need to determine the largest
2432  * chunk of data to be written to the file at one time. This is determined
2433  * based on the following three things:
2434  *	1) The size of the archived file.
2435  *	2) The preferred I/O size of the file.
2436  *	3) If the file is a read-write system attribute file.
2437  * If the size of the file is less than the preferred I/O size or it's a
2438  * read-write system attribute file, which must be written in one operation,
2439  * then set the maximum write size to the size of the archived file.
2440  * Otherwise, the maximum write size is preferred I/O size.
2441  */
2442 static int
calc_maxwrite(int ofd,int rw_sysattr,off_t bytes,size_t blocksize)2443 calc_maxwrite(int ofd, int rw_sysattr, off_t bytes, size_t blocksize)
2444 {
2445 	struct stat tsbuf;
2446 	size_t maxwrite;
2447 	size_t piosize;		/* preferred I/O size */
2448 
2449 	if (rw_sysattr || bytes < blocksize) {
2450 		maxwrite = bytes;
2451 	} else {
2452 		if (fstat(ofd, &tsbuf) == 0) {
2453 			piosize = tsbuf.st_blksize;
2454 		} else {
2455 			piosize = blocksize;
2456 		}
2457 		maxwrite = min(bytes, piosize);
2458 	}
2459 	return (maxwrite);
2460 }
2461 /*
2462  * data_copy() and data_copy_with_holes() copy data from the input
2463  * file to output file descriptor. If ifd is -1, then the input file is
2464  * the archive file.
2465  *
2466  * Parameters
2467  *	ifd		- Input file descriptor to read from.
2468  *	ofd		- Output file descriptor of extracted file.
2469  *	rw_sysattr	- Flag indicating if a file is an extended
2470  *			system attribute file.
2471  *	bytes		- Amount of data (file size) of copy/write.
2472  *	blocksize	- Amount of data to read at a time from either
2473  *			the input file descriptor or from the archive.
2474  *	data_in_info	- information needed while reading data when
2475  *			called by data_in().
2476  *	holes		- Information of holes in the input file.
2477  *
2478  * Return code
2479  *	0		Success
2480  *	< 0		An error occurred during the read of the input
2481  *			file
2482  *	> 0		An error occurred during the write of the output
2483  *			file descriptor.
2484  */
2485 static int
data_copy(int ifd,int ofd,int rw_sysattr,off_t bytes,size_t blocksize,data_in_t * data_in_info)2486 data_copy(int ifd, int ofd, int rw_sysattr, off_t bytes,
2487     size_t blocksize, data_in_t *data_in_info)
2488 {
2489 	char *buf;
2490 	size_t maxwrite;
2491 	int rv;
2492 
2493 	/* No data to copy. */
2494 	if (bytes == 0)
2495 		return (0);
2496 
2497 	maxwrite = calc_maxwrite(ofd, rw_sysattr, bytes, blocksize);
2498 	buf = e_zalloc(E_EXIT, maxwrite);
2499 
2500 	rv = rdwr_bytes(ifd, ofd, buf, bytes, maxwrite,
2501 	    blocksize, data_in_info);
2502 
2503 	free(buf);
2504 	return (rv);
2505 }
2506 
2507 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)2508 data_copy_with_holes(int ifd, int ofd, int rw_sysattr, off_t bytes,
2509     size_t blocksize, data_in_t *data_in_info, holes_info_t *holes)
2510 {
2511 	holes_list_t	*hl;
2512 	off_t		curpos, noff, datasize;
2513 	char		*buf;
2514 	size_t		maxwrite;
2515 	int		rv, error;
2516 
2517 	if (bytes == 0)
2518 		return (0);
2519 
2520 	maxwrite = calc_maxwrite(ofd, rw_sysattr, bytes, blocksize);
2521 	buf = e_zalloc(E_EXIT, maxwrite);
2522 
2523 	error = 0;
2524 	curpos = 0;
2525 	for (hl = holes->holes_list; hl != NULL; hl = hl->hl_next) {
2526 		if (curpos != hl->hl_data) {
2527 			/* adjust output position */
2528 			noff = lseek(ofd, hl->hl_data, SEEK_SET);
2529 			if (noff != hl->hl_data) {
2530 				/*
2531 				 * Can't seek to the target, try to adjust
2532 				 * position by filling with zeros.
2533 				 */
2534 				datasize = hl->hl_data - curpos;
2535 				rv = write_zeros(ofd, buf, datasize,
2536 				    maxwrite, data_in_info);
2537 				if (rv != 0)
2538 					goto errout;
2539 			}
2540 			/*
2541 			 * Data is contiguous in the archive, but fragmented
2542 			 * in the regular file, so we also adjust the input
2543 			 * file position in pass mode.
2544 			 */
2545 			if (Args & OCp) {
2546 				/* adjust input position */
2547 				(void) lseek(ifd, hl->hl_data, SEEK_SET);
2548 			}
2549 			curpos = hl->hl_data;
2550 		}
2551 		datasize = hl->hl_hole - hl->hl_data;
2552 		if (datasize == 0) {
2553 			/*
2554 			 * There is a hole at the end of file. To create
2555 			 * such hole, we append one byte, and truncate the
2556 			 * last block. This is necessary because ftruncate(2)
2557 			 * alone allocates one block on the end of file.
2558 			 */
2559 			rv = write_zeros(ofd, buf, 1, maxwrite, data_in_info);
2560 			if (rv != 0)
2561 				goto errout;
2562 			(void) ftruncate(ofd, hl->hl_data);
2563 			break;
2564 		}
2565 		rv = rdwr_bytes(ifd, ofd, buf, datasize, maxwrite,
2566 		    blocksize, data_in_info);
2567 		if (rv != 0) {
2568 errout:
2569 			/*
2570 			 * Return if we got a read error or in pass mode,
2571 			 * or failed with partial write. Otherwise, we'll
2572 			 * read through the input stream till next file.
2573 			 */
2574 			if (rv < 0 || (Args & OCp) ||
2575 			    data_in_info->data_in_wr_part) {
2576 				free(buf);
2577 				return (rv);
2578 			}
2579 			error = 1;
2580 			hl = hl->hl_next;
2581 			break;
2582 		}
2583 		curpos += datasize;
2584 	}
2585 
2586 	/*
2587 	 * We should read through the input data to go to the next
2588 	 * header when non-fatal error occured.
2589 	 */
2590 	if (error && !(Args & OCp)) {
2591 		data_in_info->data_in_proc_mode = P_SKIP;
2592 		while (hl != NULL) {
2593 			datasize = hl->hl_hole - hl->hl_data;
2594 			rv = rdwr_bytes(ifd, ofd, buf, datasize, maxwrite,
2595 			    blocksize, data_in_info);
2596 			if (rv != 0)
2597 				break;
2598 			hl = hl->hl_next;
2599 		}
2600 	}
2601 
2602 	free(buf);
2603 	return (error);
2604 }
2605 
2606 /*
2607  * Strip off the sparse file information that is prepended to
2608  * the compressed sparse file. The information is in the following
2609  * format:
2610  *	<prepended info size><SP><orig file size><SP><holes info>
2611  * where prepended info size is long right justified in 10 bytes.
2612  * Holesdata consists of the series of offset pairs:
2613  *	<data offset><SP><hole offset><SP><data offset><SP><hole offset>...
2614  * prepended info size and original file size have been read in gethdr().
2615  * We read the rest of holes information here in this function.
2616  */
2617 static int
read_holesdata(holes_info_t * holes,off_t * fileszp,char * nam_p,data_in_t * data_in_info)2618 read_holesdata(holes_info_t *holes, off_t *fileszp,
2619     char *nam_p, data_in_t *data_in_info)
2620 {
2621 	char		*holesdata;
2622 	size_t		holesdata_sz;
2623 
2624 	/* We've already read the header. */
2625 	holesdata_sz = holes->holesdata_sz - MIN_HOLES_HDRSIZE;
2626 
2627 	if ((holesdata = e_zalloc(E_NORMAL, holesdata_sz)) == NULL) {
2628 		msg(ERRN, "Could not allocate memory for "
2629 		    "sparse file information", nam_p);
2630 		return (1);
2631 	}
2632 	/*
2633 	 * This function is called only in OCi mode. Therefore,
2634 	 * read_bytes() won't fail, and won't return if error occurs in
2635 	 * input stream. See rstbuf().
2636 	 */
2637 	(void) read_bytes(-1, holesdata, holesdata_sz, CPIOBSZ, data_in_info);
2638 	*fileszp -= holesdata_sz;
2639 
2640 	/* The string should be terminated. */
2641 	if (holesdata[holesdata_sz - 1] != '\0') {
2642 invalid:
2643 		free(holesdata);
2644 		msg(ERR, "invalid sparse file information", nam_p);
2645 		return (1);
2646 	}
2647 	if (parse_holesdata(holes, holesdata) != 0)
2648 		goto invalid;
2649 
2650 	/* sanity check */
2651 	if (*fileszp != holes->data_size)
2652 		goto invalid;
2653 
2654 	free(holesdata);
2655 	return (0);
2656 }
2657 
2658 /*
2659  * data_in:  If proc_mode == P_PROC, bread() the file's data from the archive
2660  * and write(2) it to the open fdes gotten from openout().  If proc_mode ==
2661  * P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data
2662  * and ignore it.  If the user specified any of the "swap" options (b, s or S),
2663  * and the length of the file is not appropriate for that action, do not
2664  * perform the "swap", otherwise perform the action on a buffer by buffer basis.
2665  * If the CRC header was selected, calculate a running checksum as each buffer
2666  * is processed.
2667  */
2668 static void
data_in(int proc_mode)2669 data_in(int proc_mode)
2670 {
2671 	char *nam_p;
2672 	int pad, rv;
2673 	int error = 0;
2674 	int swapfile = 0;
2675 	int cstatus = 0;
2676 	off_t	filesz;
2677 	data_in_t *data_in_info;
2678 
2679 	if (G_p->g_attrnam_p != NULL) {
2680 		nam_p = G_p->g_attrnam_p;
2681 	} else {
2682 		nam_p = G_p->g_nam_p;
2683 	}
2684 
2685 	if (((G_p->g_mode & Ftype) == S_IFLNK && proc_mode != P_SKIP) ||
2686 	    (Hdr_type == BAR && bar_linkflag == '2' && proc_mode != P_SKIP)) {
2687 		proc_mode = P_SKIP;
2688 		VERBOSE((Args & (OCv | OCV)), nam_p);
2689 	}
2690 	if (Args & (OCb | OCs | OCS)) { /* verfify that swapping is possible */
2691 		swapfile = 1;
2692 		if (Args & (OCs | OCb) && G_p->g_filesz % 2) {
2693 			msg(ERR,
2694 			    "Cannot swap bytes of \"%s\", odd number of bytes",
2695 			    nam_p);
2696 			swapfile = 0;
2697 		}
2698 		if (Args & (OCS | OCb) && G_p->g_filesz % 4) {
2699 			msg(ERR,
2700 			    "Cannot swap halfwords of \"%s\", odd number "
2701 			    "of halfwords", nam_p);
2702 			swapfile = 0;
2703 		}
2704 	}
2705 
2706 	data_in_info = e_zalloc(E_EXIT, sizeof (data_in_t));
2707 	data_in_info->data_in_swapfile = swapfile;
2708 	data_in_info->data_in_proc_mode = proc_mode;
2709 
2710 	filesz = G_p->g_filesz;
2711 
2712 	if (S_ISSPARSE(G_p->g_mode) && G_p->g_holes != NULL) {
2713 		/* We've already read the header in gethdr() */
2714 		filesz -= MIN_HOLES_HDRSIZE;
2715 
2716 		/*
2717 		 * Strip rest of the sparse file information. This includes
2718 		 * the data/hole offset pairs which will be used to restore
2719 		 * the holes in the file.
2720 		 */
2721 		if (proc_mode == P_SKIP) {
2722 			/* holes info isn't necessary to skip file */
2723 			free_holes_info(G_p->g_holes);
2724 			G_p->g_holes = NULL;
2725 		} else {
2726 			rv = read_holesdata(G_p->g_holes, &filesz,
2727 			    nam_p, data_in_info);
2728 			if (rv != 0) {
2729 				/*
2730 				 * We got an error. Skip this file. holes info
2731 				 * is no longer necessary.
2732 				 */
2733 				free_holes_info(G_p->g_holes);
2734 				G_p->g_holes = NULL;
2735 
2736 				data_in_info->data_in_proc_mode = P_SKIP;
2737 				error = 1;
2738 			}
2739 		}
2740 	}
2741 
2742 	if (G_p->g_holes != NULL) {
2743 		rv = data_copy_with_holes(-1, Ofile,
2744 		    (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
2745 		    G_p->g_holes->orig_size,
2746 		    CPIOBSZ, data_in_info, G_p->g_holes);
2747 
2748 		free_holes_info(G_p->g_holes);
2749 		G_p->g_holes = NULL;
2750 	} else {
2751 		rv = data_copy(-1, Ofile,
2752 		    (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
2753 		    filesz, CPIOBSZ, data_in_info);
2754 	}
2755 
2756 	/* This writes out the file from the archive */
2757 	if (rv != 0 || error) {
2758 		errno = data_in_info->data_in_errno;
2759 
2760 		if (!error) {
2761 			msg(data_in_info->data_in_wr_part ? EXTN : ERRN,
2762 			    "Cannot write \"%s%s%s\"",
2763 			    (G_p->g_attrnam_p == NULL) ? "" :
2764 			    G_p->g_attrfnam_p,
2765 			    (G_p->g_attrnam_p == NULL) ? "" :
2766 			    G_p->g_rw_sysattr ?
2767 			    gettext(" System Attribute ") :
2768 			    gettext(" Attribute "), nam_p);
2769 		}
2770 		/*
2771 		 * We've failed to write to the file, and input data
2772 		 * has been skiped to the next file. We'll need to restore
2773 		 * the original file, and skip the rest of work.
2774 		 */
2775 		proc_mode = P_SKIP;
2776 		rstfiles(U_KEEP, G_p->g_dirfd);
2777 		cstatus = close(Ofile);
2778 		Ofile = 0;
2779 		if (cstatus != 0) {
2780 			msg(EXTN, "close error");
2781 		}
2782 	}
2783 
2784 	/* we must use g_filesz for the amount of padding */
2785 	pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
2786 	if (pad != 0) {
2787 		FILL(pad);
2788 		Buffr.b_out_p += pad;
2789 		Buffr.b_cnt -= pad;
2790 	}
2791 	if (proc_mode != P_SKIP) {
2792 		if (Hdr_type == CRC &&
2793 		    Gen.g_cksum != data_in_info->data_in_cksumval) {
2794 			msg(ERR, "\"%s\" - checksum error", nam_p);
2795 			rstfiles(U_KEEP, G_p->g_dirfd);
2796 		} else
2797 			rstfiles(U_OVER, G_p->g_dirfd);
2798 		if (Hdr_type == BAR && data_in_info->data_in_compress_flag) {
2799 			(void) pclose(data_in_info->data_in_pipef);
2800 		} else {
2801 			cstatus = close(Ofile);
2802 		}
2803 		Ofile = 0;
2804 		if (cstatus != 0) {
2805 			msg(EXTN, "close error");
2806 		}
2807 	}
2808 	(void) free(data_in_info);
2809 
2810 	VERBOSE((proc_mode != P_SKIP && (Args & (OCv | OCV))),
2811 	    (G_p->g_attrparent_p == NULL) ? G_p->g_nam_p : G_p->g_attrpath_p);
2812 	Finished = 1;
2813 }
2814 
2815 /*
2816  * Read regular file. Return number of bytes which weren't read.
2817  * Upon return, real_filesz will be real file size of input file.
2818  * When read_exact is specified, read size is adjusted to the given
2819  * file size.
2820  */
2821 static off_t
read_file(char * nam_p,off_t file_size,off_t * real_filesz,boolean_t read_exact)2822 read_file(char *nam_p, off_t file_size, off_t *real_filesz,
2823     boolean_t read_exact)
2824 {
2825 	int	amount_read;
2826 	off_t	amt_to_read;
2827 	off_t	readsz;
2828 
2829 	if (file_size == 0)
2830 		return (0);
2831 
2832 	amt_to_read = file_size;
2833 	do {
2834 		if (read_exact && amt_to_read < CPIOBSZ)
2835 			readsz = amt_to_read;
2836 		else
2837 			readsz = CPIOBSZ;
2838 
2839 		FLUSH(readsz);
2840 		errno = 0;
2841 
2842 		if ((amount_read = read(Ifile, Buffr.b_in_p, readsz)) < 0) {
2843 			msg(EXTN, "Cannot read \"%s%s%s\"",
2844 			    (Gen.g_attrnam_p == NULL) ?
2845 			    nam_p : Gen.g_attrfnam_p,
2846 			    (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
2847 			    gettext(" System Attribute ") :
2848 			    gettext(" Attribute "),
2849 			    (Gen.g_attrnam_p == NULL) ? "" : nam_p);
2850 			break;
2851 		}
2852 
2853 		if (amount_read == 0) {
2854 			/* got EOF. the file has shrunk */
2855 			*real_filesz = file_size - amt_to_read;
2856 			break;
2857 		} else if (amount_read > amt_to_read) {
2858 			/* the file has grown */
2859 			*real_filesz = file_size +
2860 			    (amount_read - amt_to_read);
2861 			amount_read = amt_to_read;
2862 		} else if (amount_read == amt_to_read) {
2863 			/* the file is the same size */
2864 			*real_filesz = file_size;
2865 		}
2866 
2867 		Buffr.b_in_p += amount_read;
2868 		Buffr.b_cnt += (long)amount_read;
2869 
2870 		amt_to_read -= (off_t)amount_read;
2871 		if (!read_exact &&
2872 		    amt_to_read == 0 && amount_read == CPIOBSZ) {
2873 			/*
2874 			 * If the file size is multiple of CPIOBSZ, we may
2875 			 * be able to read more from the file even though
2876 			 * amt_to_read already gets 0.
2877 			 */
2878 			FLUSH(CPIOBSZ);
2879 			amount_read = read(Ifile, Buffr.b_in_p, CPIOBSZ);
2880 			if (amount_read != 0) {
2881 				/* the file has grown */
2882 				*real_filesz = file_size + amount_read;
2883 			}
2884 		}
2885 	} while (amt_to_read != 0);
2886 
2887 	return (amt_to_read);
2888 }
2889 
2890 /*
2891  * Read through the data in files skipping holes.
2892  */
2893 static off_t
read_compress_holes(char * nam_p,off_t file_size,off_t * real_filesz,holes_info_t * holes,int * hole_changed)2894 read_compress_holes(char *nam_p, off_t file_size, off_t *real_filesz,
2895     holes_info_t *holes, int *hole_changed)
2896 {
2897 	off_t		left;
2898 	off_t		datasize, realsz;
2899 	off_t		curpos, npos;
2900 	holes_list_t	*hl = holes->holes_list;
2901 
2902 	curpos = 0;
2903 	for (hl = holes->holes_list; hl != NULL; hl = hl->hl_next) {
2904 		datasize = hl->hl_hole - hl->hl_data;
2905 
2906 		npos = lseek(Ifile, curpos, SEEK_DATA);
2907 		if (npos == -1 && errno == ENXIO) {
2908 			/*
2909 			 * No more data. There are two cases.
2910 			 * - we have a hole toward the end of file.
2911 			 * - file has been shrunk, and we've reached EOF.
2912 			 */
2913 			*real_filesz = lseek(Ifile, 0, SEEK_END);
2914 			if (hl->hl_data == file_size)
2915 				return (0);
2916 			/*
2917 			 * File has been shrunk. Check the amount of data
2918 			 * left.
2919 			 */
2920 			left = 0;
2921 			while (hl != NULL) {
2922 				left += (hl->hl_hole - hl->hl_data);
2923 				hl = hl->hl_next;
2924 			}
2925 			return (left);
2926 		}
2927 
2928 		/* found data */
2929 		curpos = npos;
2930 		if (curpos != hl->hl_data) {
2931 			/*
2932 			 * File has been changed. We shouldn't read data
2933 			 * from different offset since we've already put
2934 			 * the holes data.
2935 			 */
2936 			*hole_changed = 1;
2937 			(void) lseek(Ifile, hl->hl_data, SEEK_SET);
2938 			curpos = hl->hl_data;
2939 		}
2940 		left = read_file(nam_p, datasize, &realsz, B_TRUE);
2941 		if (left != 0) {
2942 			/* file has been shrunk */
2943 			*real_filesz = curpos + datasize - left;
2944 			left = file_size - *real_filesz;
2945 			return (left);
2946 		}
2947 		curpos += datasize;
2948 	}
2949 	/*
2950 	 * We've read exact size of holes. We need to make sure
2951 	 * that file hasn't grown by reading from the EOF.
2952 	 */
2953 	realsz = 0;
2954 	(void) read_file(nam_p, CPIOBSZ, &realsz, B_FALSE);
2955 
2956 	*real_filesz = curpos + realsz;
2957 	return (0);
2958 }
2959 
2960 /*
2961  * data_out:  open(2) the file to be archived, compute the checksum
2962  * of it's data if the CRC header was specified and write the header.
2963  * read(2) each block of data and bwrite() it to the archive.  For TARTYP (TAR
2964  * and USTAR) archives, pad the data with NULLs to the next 512 byte boundary.
2965  */
2966 static void
data_out(void)2967 data_out(void)
2968 {
2969 	char		*nam_p;
2970 	int		cnt, pad;
2971 	off_t		amt_to_read;
2972 	off_t		real_filesz;
2973 	int		errret = 0;
2974 	int		hole_changed = 0;
2975 	off_t		orig_filesz;
2976 	holes_info_t	*holes = NULL;
2977 
2978 	nam_p = G_p->g_nam_p;
2979 	if (Aspec) {
2980 		if (Pflag && aclp != NULL) {
2981 			char    *secinfo = NULL;
2982 			int	len = 0;
2983 
2984 			/* append security attributes */
2985 			if (append_secattr(&secinfo, &len, aclp) == -1) {
2986 				msg(ERR,
2987 				    "can create security information");
2988 			}
2989 			/* call append_secattr() if more than one */
2990 
2991 			if (len > 0) {
2992 			/* write ancillary only if there is sec info */
2993 				write_hdr(ARCHIVE_ACL, (off_t)len);
2994 				write_ancillary(secinfo, len, B_TRUE);
2995 			}
2996 		}
2997 		write_hdr(ARCHIVE_NORMAL, (off_t)0);
2998 		rstfiles(U_KEEP, G_p->g_dirfd);
2999 		VERBOSE((Args & (OCv | OCV)), nam_p);
3000 		return;
3001 	}
3002 	if ((G_p->g_mode & Ftype) == S_IFLNK && (Hdr_type !=
3003 	    USTAR && Hdr_type != TAR)) { /* symbolic link */
3004 		int size;
3005 		write_hdr(ARCHIVE_NORMAL, (off_t)0);
3006 
3007 		FLUSH(G_p->g_filesz);
3008 		errno = 0;
3009 
3010 		/* Note that "size" and G_p->g_filesz are the same number */
3011 
3012 		if ((size = readlink(nam_p, Buffr.b_in_p, G_p->g_filesz)) <
3013 		    0) {
3014 			msg(ERRN, "Cannot read symbolic link \"%s\"", nam_p);
3015 			return;
3016 		}
3017 
3018 		/*
3019 		 * Note that it is OK not to add the NUL after the name read by
3020 		 * readlink, because it is not being used subsequently.
3021 		 */
3022 
3023 		Buffr.b_in_p += size;
3024 		Buffr.b_cnt += size;
3025 		pad = (Pad_val + 1 - (size & Pad_val)) & Pad_val;
3026 		if (pad != 0) {
3027 			FLUSH(pad);
3028 			(void) memset(Buffr.b_in_p, 0, pad);
3029 			Buffr.b_in_p += pad;
3030 			Buffr.b_cnt += pad;
3031 		}
3032 		VERBOSE((Args & (OCv | OCV)), nam_p);
3033 		return;
3034 	} else if ((G_p->g_mode & Ftype) == S_IFLNK &&
3035 	    (Hdr_type == USTAR || Hdr_type == TAR)) {
3036 		int size;
3037 
3038 		/*
3039 		 * G_p->g_filesz is the length of the right-hand side of
3040 		 * the symlink "x -> y".
3041 		 * The tar link field is only NAMSIZ long.
3042 		 */
3043 
3044 		if (G_p->g_filesz > NAMSIZ) {
3045 			msg(ERRN,
3046 			    "Symbolic link too long \"%s\"", nam_p);
3047 			return;
3048 		}
3049 		if ((size = readlink(nam_p, T_lname, G_p->g_filesz)) < 0) {
3050 			msg(ERRN,
3051 			    "Cannot read symbolic link \"%s\"", nam_p);
3052 			return;
3053 		}
3054 		T_lname[size] = '\0';
3055 		G_p->g_filesz = (off_t)0;
3056 		write_hdr(ARCHIVE_NORMAL, (off_t)0);
3057 		VERBOSE((Args & (OCv | OCV)), nam_p);
3058 		return;
3059 	}
3060 	if ((Ifile = openfile(O_RDONLY)) < 0) {
3061 		msg(ERR, "\"%s%s%s\" ?",
3062 		    (Gen.g_attrnam_p == NULL) ? nam_p : Gen.g_attrfnam_p,
3063 		    (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3064 		    gettext(" System Attribute ") : gettext(" Attribute "),
3065 		    (Gen.g_attrnam_p == NULL) ? "" :
3066 		    (Gen.g_attrparent_p == NULL) ? Gen.g_attrnam_p :
3067 		    Gen.g_attrparent_p);
3068 		return;
3069 	}
3070 
3071 	/* save original file size */
3072 	orig_filesz = G_p->g_filesz;
3073 
3074 	/*
3075 	 * Calculate the new compressed file size of a sparse file
3076 	 * before any of the header information is written
3077 	 * to the archive.
3078 	 */
3079 	if (Compress_sparse && S_ISREG(G_p->g_mode)) {
3080 		/*
3081 		 * If the file being processed is a sparse file, gather the
3082 		 * hole information and the compressed file size.
3083 		 * G_p->g_filesz will need to be changed to be the size of
3084 		 * the compressed sparse file plus the the size of the hole
3085 		 * information that will be prepended to the compressed file
3086 		 * in the archive.
3087 		 */
3088 		holes = get_holes_info(Ifile, G_p->g_filesz, B_FALSE);
3089 		if (holes != NULL)
3090 			G_p->g_filesz = holes->holesdata_sz + holes->data_size;
3091 
3092 		if (G_p->g_filesz > Max_offset) {
3093 			msg(ERR, "%s%s%s: too large to archive "
3094 			    "in current mode",
3095 			    G_p->g_nam_p,
3096 			    (G_p->g_attrnam_p == NULL) ? "" :
3097 			    G_p->g_rw_sysattr ?
3098 			    gettext(" System Attribute ") :
3099 			    gettext(" Attribute "),
3100 			    (G_p->g_attrnam_p == NULL) ? "" :
3101 			    ((G_p->g_attrparent_p == NULL) ?
3102 			    G_p->g_attrnam_p:
3103 			    G_p->g_attrpath_p));
3104 
3105 			(void) close(Ifile);
3106 			if (holes != NULL)
3107 				free_holes_info(holes);
3108 			return; /* do not archive if it's too big */
3109 		}
3110 	}
3111 
3112 	/*
3113 	 * Dump extended attribute header.
3114 	 */
3115 
3116 	if (Gen.g_attrnam_p != NULL) {
3117 		write_xattr_hdr();
3118 	}
3119 
3120 	if (Hdr_type == CRC) {
3121 		long csum = cksum(CRC, 0, &errret);
3122 		if (errret != 0) {
3123 			G_p->g_cksum = (ulong_t)-1;
3124 			msg(POST, "\"%s%s%s\" skipped",
3125 			    (Gen.g_attrnam_p == NULL) ?
3126 			    nam_p : Gen.g_attrfnam_p,
3127 			    (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3128 			    gettext(" System Attribute ") :
3129 			    gettext(" Attribute "),
3130 			    (Gen.g_attrnam_p == NULL) ? "" : nam_p);
3131 			if (holes != NULL)
3132 				free_holes_info(holes);
3133 			(void) close(Ifile);
3134 			return;
3135 		}
3136 		G_p->g_cksum = csum;
3137 	} else {
3138 		G_p->g_cksum = 0;
3139 	}
3140 
3141 	/*
3142 	 * ACL has been retrieved in getname().
3143 	 */
3144 	if (Pflag) {
3145 		char    *secinfo = NULL;
3146 		int	len = 0;
3147 
3148 		/* append security attributes */
3149 		if ((append_secattr(&secinfo, &len, aclp)) == -1)
3150 			msg(ERR, "can create security information");
3151 
3152 		/* call append_secattr() if more than one */
3153 
3154 		if (len > 0) {
3155 		/* write ancillary only if there is sec info */
3156 			write_hdr(ARCHIVE_ACL, (off_t)len);
3157 			write_ancillary(secinfo, len, B_TRUE);
3158 		}
3159 	}
3160 
3161 	if (holes != NULL) {
3162 		/*
3163 		 * Write the header info with a modified c_mode field to
3164 		 * indicate a compressed sparse file is being archived,
3165 		 * as well as the new file size, including the size of the
3166 		 * compressed file as well as all the prepended data.
3167 		 */
3168 		write_hdr(ARCHIVE_SPARSE, (off_t)0);
3169 		/* Prepend sparse file info */
3170 		write_ancillary(holes->holesdata,
3171 		    holes->holesdata_sz, B_FALSE);
3172 	} else {
3173 		write_hdr(ARCHIVE_NORMAL, (off_t)0);
3174 	}
3175 
3176 	real_filesz = 0;
3177 
3178 	if (holes != NULL) {
3179 		amt_to_read = read_compress_holes(nam_p, G_p->g_filesz,
3180 		    &real_filesz, holes, &hole_changed);
3181 	} else {
3182 		amt_to_read = read_file(nam_p, G_p->g_filesz,
3183 		    &real_filesz, B_FALSE);
3184 	}
3185 
3186 	while (amt_to_read > 0) {
3187 		cnt = (amt_to_read > CPIOBSZ) ? CPIOBSZ : (int)amt_to_read;
3188 		FLUSH(cnt);
3189 		(void) memset(Buffr.b_in_p, 0, cnt);
3190 		Buffr.b_in_p += cnt;
3191 		Buffr.b_cnt += cnt;
3192 		amt_to_read -= cnt;
3193 	}
3194 
3195 	pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
3196 	if (pad != 0) {
3197 		FLUSH(pad);
3198 		(void) memset(Buffr.b_in_p, 0, pad);
3199 		Buffr.b_in_p += pad;
3200 		Buffr.b_cnt += pad;
3201 	}
3202 
3203 	if (hole_changed == 1) {
3204 		msg(ERR,
3205 		    "File data and hole offsets of \"%s%s%s\" have changed",
3206 		    (Gen.g_attrnam_p == NULL) ?
3207 		    G_p->g_nam_p : Gen.g_attrfnam_p,
3208 		    (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3209 		    gettext(" System Attribute ") : gettext(" Attribute "),
3210 		    (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p);
3211 	}
3212 	if (real_filesz > orig_filesz) {
3213 		msg(ERR, "File size of \"%s%s%s\" has increased by %lld",
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 		    (real_filesz - orig_filesz));
3220 	}
3221 	if (real_filesz < orig_filesz) {
3222 		msg(ERR, "File size of \"%s%s%s\" has decreased by %lld",
3223 		    (Gen.g_attrnam_p == NULL) ?
3224 		    G_p->g_nam_p : Gen.g_attrfnam_p,
3225 		    (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3226 		    gettext(" System Attribute ") : gettext(" Attribute "),
3227 		    (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p,
3228 		    (orig_filesz - real_filesz));
3229 	}
3230 
3231 	if (holes != NULL)
3232 		free_holes_info(holes);
3233 
3234 	(void) close(Ifile);
3235 	rstfiles(U_KEEP, G_p->g_dirfd);
3236 	VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3237 }
3238 
3239 /*
3240  * data_pass:  If not a special file (Aspec), open(2) the file to be
3241  * transferred, read(2) each block of data and write(2) it to the output file
3242  * Ofile, which was opened in file_pass().
3243  */
3244 static void
data_pass(void)3245 data_pass(void)
3246 {
3247 	int rv;
3248 	int cstatus;
3249 	char *namep = Nam_p;
3250 	holes_info_t *holes = NULL;
3251 	data_in_t *data_in_info;
3252 
3253 	if (G_p->g_attrnam_p != NULL) {
3254 		namep = G_p->g_attrnam_p;
3255 	}
3256 	if (Aspec) {
3257 		rstfiles(U_KEEP, G_p->g_passdirfd);
3258 		cstatus = close(Ofile);
3259 		Ofile = 0;
3260 		VERBOSE((Args & (OCv | OCV)), Nam_p);
3261 		if (cstatus != 0) {
3262 			msg(EXTN, "close error");
3263 		}
3264 		return;
3265 	}
3266 	if ((Ifile = openat(G_p->g_dirfd, get_component(namep), 0)) < 0) {
3267 		msg(ERRN, "Cannot open \"%s%s%s\", skipped",
3268 		    (G_p->g_attrnam_p == NULL) ? Nam_p : G_p->g_attrfnam_p,
3269 		    (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
3270 		    gettext(" System Attribute ") : gettext(" Attribute "),
3271 		    (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3272 		rstfiles(U_KEEP, G_p->g_passdirfd);
3273 		cstatus = close(Ofile);
3274 		Ofile = 0;
3275 		if (cstatus != 0) {
3276 			msg(EXTN, "close error");
3277 		}
3278 		return;
3279 	}
3280 
3281 	data_in_info = e_zalloc(E_EXIT, sizeof (data_in_t));
3282 	data_in_info->data_in_proc_mode = P_PROC;
3283 
3284 	if (S_ISREG(G_p->g_mode))
3285 		holes = get_holes_info(Ifile, G_p->g_filesz, B_TRUE);
3286 
3287 	if (holes != NULL) {
3288 		rv = data_copy_with_holes(Ifile, Ofile,
3289 		    (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
3290 		    G_p->g_filesz, Bufsize, data_in_info, holes);
3291 
3292 		free_holes_info(holes);
3293 	} else {
3294 		rv = data_copy(Ifile, Ofile,
3295 		    (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
3296 		    G_p->g_filesz, Bufsize, data_in_info);
3297 	}
3298 
3299 	if (rv < 0) {
3300 		/* read error or unexpected EOF */
3301 		if (data_in_info->data_in_rd_eof) {
3302 			/*
3303 			 * read has reached EOF unexpectedly, but this isn't
3304 			 * an error since it's the latest shape of the file.
3305 			 */
3306 			msg(EPOST, "File size of \"%s%s%s\" has decreased",
3307 			    (G_p->g_attrnam_p == NULL) ?
3308 			    Nam_p : G_p->g_attrfnam_p,
3309 			    (G_p->g_attrnam_p == NULL) ? "" :
3310 			    G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3311 			    gettext(" Attribute "),
3312 			    (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3313 
3314 			/* It's not error. We'll use the new file */
3315 			rv = 0;
3316 		} else {
3317 			/* read error */
3318 			msg(ERRN, "Cannot read \"%s%s%s\"",
3319 			    (G_p->g_attrnam_p == NULL) ?
3320 			    Nam_p : G_p->g_attrfnam_p,
3321 			    (G_p->g_attrnam_p == NULL) ? "" :
3322 			    G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3323 			    gettext(" Attribute "),
3324 			    (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3325 		}
3326 	} else if (rv > 0) {
3327 		/* write error */
3328 		if (Do_rename) {
3329 			msg(ERRN, "Cannot write \"%s%s%s\"", Over_p,
3330 			    (G_p->g_attrnam_p == NULL) ? "" :
3331 			    G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3332 			    gettext(" Attribute "),
3333 			    (G_p->g_attrnam_p == NULL) ? "" : Over_p);
3334 		} else {
3335 			msg(ERRN, "Cannot write \"%s%s%s\"",
3336 			    Fullnam_p,
3337 			    (G_p->g_attrnam_p == NULL) ? "" :
3338 			    G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3339 			    gettext(" Attribute "),
3340 			    (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3341 		}
3342 	}
3343 
3344 	free(data_in_info);
3345 
3346 	if (rv == 0) {
3347 		rstfiles(U_OVER, G_p->g_passdirfd);
3348 	} else {
3349 		rstfiles(U_KEEP, G_p->g_passdirfd);
3350 	}
3351 
3352 	(void) close(Ifile);
3353 	cstatus = close(Ofile);
3354 	Ofile = 0;
3355 	if (cstatus != 0) {
3356 		msg(EXTN, "close error");
3357 	}
3358 	VERBOSE((Args & (OCv | OCV)), Fullnam_p);
3359 	Finished = 1;
3360 }
3361 
3362 /*
3363  * file_in:  Process an object from the archive.  If a TARTYP (TAR or USTAR)
3364  * archive and g_nlink == 1, link this file to the file name in t_linkname
3365  * and return.  Handle linked files in one of two ways.  If Onecopy == 0, this
3366  * is an old style (binary or -c) archive, create and extract the data for the
3367  * first link found, link all subsequent links to this file and skip their data.
3368  * If Oncecopy == 1, save links until all have been processed, and then
3369  * process the links first to last checking their names against the patterns
3370  * and/or asking the user to rename them.  The first link that is accepted
3371  * for xtraction is created and the data is read from the archive.
3372  * All subsequent links that are accepted are linked to this file.
3373  */
3374 static void
file_in(void)3375 file_in(void)
3376 {
3377 	struct Lnk *l_p, *tl_p;
3378 	int lnkem = 0, cleanup = 0;
3379 	int proc_file;
3380 	struct Lnk *ttl_p;
3381 	int typeflag;
3382 	char savacl;
3383 	int cwd;
3384 
3385 	G_p = &Gen;
3386 
3387 	/*
3388 	 * Now that we've read the extended header,
3389 	 * determine if we should restore attributes.
3390 	 * Don't restore the attribute if we are extracting
3391 	 * a file from an archive (as opposed to doing a table of
3392 	 * contents) and any of the following are true:
3393 	 * 1. neither -@ or -/ was specified.
3394 	 * 2. -@ was specified, -/ wasn't specified, and we're
3395 	 * processing a hidden attribute directory of an attribute
3396 	 * or we're processing a read-write system attribute file.
3397 	 * 3.  -@ wasn't specified, -/ was specified, and the file
3398 	 * we're processing it not a read-write system attribute file,
3399 	 * or we're processing the hidden attribute directory of an
3400 	 * attribute.
3401 	 *
3402 	 * We always process the attributes if we're just generating
3403 	 * generating a table of contents, or if both -@ and -/ were
3404 	 * specified.
3405 	 */
3406 	if (G_p->g_attrnam_p != NULL) {
3407 		if (((Args & OCt) == 0) &&
3408 		    ((!Atflag && !SysAtflag) ||
3409 		    (Atflag && !SysAtflag && ((G_p->g_attrparent_p != NULL) ||
3410 		    G_p->g_rw_sysattr)) ||
3411 		    (!Atflag && SysAtflag && ((G_p->g_attrparent_p != NULL) ||
3412 		    !G_p->g_rw_sysattr)))) {
3413 			proc_file = F_SKIP;
3414 			data_in(P_SKIP);
3415 			return;
3416 		}
3417 	}
3418 
3419 	/*
3420 	 * Open target directory if this isn't a skipped file
3421 	 * and g_nlink == 1
3422 	 *
3423 	 * Links are handled further down in this function.
3424 	 */
3425 
3426 	proc_file = ckname(0);
3427 
3428 	if (proc_file == F_SKIP && G_p->g_nlink == 1) {
3429 		/*
3430 		 * Normally ckname() prints out the file as a side
3431 		 * effect except for table of contents listing
3432 		 * when its parameter is zero and Onecopy isn't
3433 		 * Zero.  Due to this we need to force the name
3434 		 * to be printed here.
3435 		 */
3436 		if (Onecopy == 1) {
3437 			VERBOSE((Args & OCt), G_p->g_nam_p);
3438 		}
3439 		data_in(P_SKIP);
3440 		return;
3441 	}
3442 
3443 	if (proc_file != F_SKIP && open_dirfd() != 0) {
3444 		data_in(P_SKIP);
3445 		return;
3446 	}
3447 
3448 	if (Hdr_type == BAR) {
3449 		bar_file_in();
3450 		close_dirfd();
3451 		return;
3452 	}
3453 
3454 	/*
3455 	 * For archives in USTAR format, the files are extracted according
3456 	 * to the typeflag.
3457 	 */
3458 	if (Hdr_type == USTAR || Hdr_type == TAR) {
3459 		typeflag = Thdr_p->tbuf.t_typeflag;
3460 		if (G_p->g_nlink == 1) {		/* hard link */
3461 			if (proc_file != F_SKIP) {
3462 				int i;
3463 				char lname[NAMSIZ+1];
3464 				(void) memset(lname, '\0', sizeof (lname));
3465 
3466 				(void) strncpy(lname, Thdr_p->tbuf.t_linkname,
3467 				    NAMSIZ);
3468 				for (i = 0; i <= NAMSIZ && lname[i] != 0; i++)
3469 					;
3470 
3471 				lname[i] = 0;
3472 				(void) creat_lnk(G_p->g_dirfd,
3473 				    &lname[0], G_p->g_nam_p);
3474 			}
3475 			close_dirfd();
3476 			return;
3477 		}
3478 		if (typeflag == '3' || typeflag == '4' || typeflag == '5' ||
3479 		    typeflag == '6') {
3480 			if (proc_file != F_SKIP &&
3481 			    creat_spec(G_p->g_dirfd) > 0) {
3482 				VERBOSE((Args & (OCv | OCV)),
3483 				    (G_p->g_attrparent_p == NULL) ?
3484 				    G_p->g_nam_p : G_p->g_attrpath_p);
3485 			}
3486 			close_dirfd();
3487 			return;
3488 		} else if (Adir || Aspec) {
3489 			if ((proc_file == F_SKIP) ||
3490 			    (Ofile = openout(G_p->g_dirfd)) < 0) {
3491 				data_in(P_SKIP);
3492 			} else {
3493 				data_in(P_PROC);
3494 			}
3495 			close_dirfd();
3496 			return;
3497 		}
3498 	}
3499 
3500 	if (Adir) {
3501 		if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
3502 			VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3503 		}
3504 		close_dirfd();
3505 		if (Onecopy == 1) {
3506 			VERBOSE((Args & OCt), G_p->g_nam_p);
3507 		}
3508 		return;
3509 	}
3510 	if (G_p->g_nlink == 1 || (Hdr_type == TAR ||
3511 	    Hdr_type == USTAR)) {
3512 		if (Aspec) {
3513 			if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0)
3514 				VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3515 		} else {
3516 			if ((proc_file == F_SKIP) ||
3517 			    (Ofile = openout(G_p->g_dirfd)) < 0) {
3518 				data_in(P_SKIP);
3519 			} else {
3520 				data_in(P_PROC);
3521 			}
3522 		}
3523 		close_dirfd();
3524 		return;
3525 	}
3526 	close_dirfd();
3527 
3528 	tl_p = add_lnk(&ttl_p);
3529 	l_p = ttl_p;
3530 	if (l_p->L_cnt == l_p->L_gen.g_nlink)
3531 		cleanup = 1;
3532 	if (!Onecopy || G_p->g_attrnam_p != NULL) {
3533 		lnkem = (tl_p != l_p) ? 1 : 0;
3534 		G_p = &tl_p->L_gen;
3535 		if (proc_file == F_SKIP) {
3536 			data_in(P_SKIP);
3537 		} else {
3538 			if (open_dirfd() != 0)
3539 				return;
3540 			if (!lnkem) {
3541 				if (Aspec) {
3542 					if (creat_spec(G_p->g_dirfd) > 0)
3543 						VERBOSE((Args & (OCv | OCV)),
3544 						    G_p->g_nam_p);
3545 				} else if ((Ofile =
3546 				    openout(G_p->g_dirfd)) < 0) {
3547 					data_in(P_SKIP);
3548 					close_dirfd();
3549 					reclaim(l_p);
3550 				} else {
3551 					data_in(P_PROC);
3552 					close_dirfd();
3553 				}
3554 			} else {
3555 				/*
3556 				 * Are we linking an attribute?
3557 				 */
3558 				cwd = -1;
3559 				if (l_p->L_gen.g_attrnam_p != NULL) {
3560 					(void) strcpy(Lnkend_p,
3561 					    l_p->L_gen.g_attrnam_p);
3562 					(void) strcpy(Full_p,
3563 					    tl_p->L_gen.g_attrnam_p);
3564 					cwd = save_cwd();
3565 					(void) fchdir(G_p->g_dirfd);
3566 				} else {
3567 					(void) strcpy(Lnkend_p,
3568 					    l_p->L_gen.g_nam_p);
3569 					(void) strcpy(Full_p,
3570 					    tl_p->L_gen.g_nam_p);
3571 				}
3572 				(void) creat_lnk(G_p->g_dirfd,
3573 				    Lnkend_p, Full_p);
3574 				data_in(P_SKIP);
3575 				close_dirfd();
3576 				l_p->L_lnk_p = NULL;
3577 				free(tl_p->L_gen.g_nam_p);
3578 				free(tl_p);
3579 				if (cwd != -1)
3580 					rest_cwd(cwd);
3581 			}
3582 		}
3583 	} else { /* Onecopy */
3584 		if (tl_p->L_gen.g_filesz)
3585 			cleanup = 1;
3586 		if (!cleanup) {
3587 			close_dirfd();
3588 			return; /* don't do anything yet */
3589 		}
3590 		tl_p = l_p;
3591 		/*
3592 		 * ckname will clear aclchar. We need to keep aclchar for
3593 		 * all links.
3594 		 */
3595 		savacl = aclchar;
3596 		while (tl_p != NULL) {
3597 			G_p = &tl_p->L_gen;
3598 			aclchar = savacl;
3599 			if ((proc_file = ckname(1)) != F_SKIP) {
3600 				if (open_dirfd() != 0) {
3601 					return;
3602 				}
3603 				if (l_p->L_data) {
3604 					(void) creat_lnk(G_p->g_dirfd,
3605 					    l_p->L_gen.g_nam_p,
3606 					    G_p->g_nam_p);
3607 				} else if (Aspec) {
3608 					(void) creat_spec(G_p->g_dirfd);
3609 					l_p->L_data = 1;
3610 					VERBOSE((Args & (OCv | OCV)),
3611 					    G_p->g_nam_p);
3612 				} else if ((Ofile =
3613 				    openout(G_p->g_dirfd)) < 0) {
3614 					proc_file = F_SKIP;
3615 				} else {
3616 					data_in(P_PROC);
3617 					l_p->L_data = 1;
3618 				}
3619 			} /* (proc_file = ckname(1)) != F_SKIP */
3620 
3621 			tl_p = tl_p->L_lnk_p;
3622 
3623 			close_dirfd();
3624 
3625 			if (proc_file == F_SKIP && !cleanup) {
3626 				tl_p->L_nxt_p = l_p->L_nxt_p;
3627 				tl_p->L_bck_p = l_p->L_bck_p;
3628 				l_p->L_bck_p->L_nxt_p = tl_p;
3629 				l_p->L_nxt_p->L_bck_p = tl_p;
3630 				free(l_p->L_gen.g_nam_p);
3631 				free(l_p);
3632 			}
3633 		} /* tl_p->L_lnk_p != NULL */
3634 		if (l_p->L_data == 0) {
3635 			data_in(P_SKIP);
3636 		}
3637 	}
3638 	if (cleanup) {
3639 		reclaim(l_p);
3640 	}
3641 }
3642 
3643 /*
3644  * file_out:  If the current file is not a special file (!Aspec) and it
3645  * is identical to the archive, skip it (do not archive the archive if it
3646  * is a regular file).  If creating a TARTYP (TAR or USTAR) archive, the first
3647  * time a link to a file is encountered, write the header and file out normally.
3648  * Subsequent links to this file put this file name in their t_linkname field.
3649  * Otherwise, links are handled in one of two ways, for the old headers
3650  * (i.e. binary and -c), linked files are written out as they are encountered.
3651  * For the new headers (ASC and CRC), links are saved up until all the links
3652  * to each file are found.  For a file with n links, write n - 1 headers with
3653  * g_filesz set to 0, write the final (nth) header with the correct g_filesz
3654  * value and write the data for the file to the archive.
3655  */
3656 static
3657 int
file_out(void)3658 file_out(void)
3659 {
3660 	struct Lnk *l_p, *tl_p;
3661 	int cleanup = 0;
3662 	struct Lnk *ttl_p;
3663 
3664 	G_p = &Gen;
3665 	if (!Aspec && IDENT(SrcSt, ArchSt))
3666 		return (1); /* do not archive the archive if it's a reg file */
3667 	/*
3668 	 * If compressing sparse files, wait until the compressed file size
3669 	 * is known to check if file size is too big.
3670 	 */
3671 	if (Compress_sparse == 0 && G_p->g_filesz > Max_offset) {
3672 		msg(ERR, "%s%s%s: too large to archive in current mode",
3673 		    G_p->g_nam_p,
3674 		    (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
3675 		    gettext(" System Attribute ") : gettext(" Attribute "),
3676 		    (G_p->g_attrnam_p == NULL) ? "" :
3677 		    ((G_p->g_attrparent_p == NULL) ? G_p->g_attrnam_p:
3678 		    G_p->g_attrpath_p));
3679 		return (1); /* do not archive if it's too big */
3680 	}
3681 	if (Hdr_type == TAR || Hdr_type == USTAR) { /* TAR and USTAR */
3682 		if (Adir) {
3683 			if (Gen.g_attrnam_p != NULL) {
3684 				write_xattr_hdr();
3685 			}
3686 			write_hdr(ARCHIVE_NORMAL, 0);
3687 			return (0);
3688 		}
3689 		if (G_p->g_nlink == 1) {
3690 			data_out();
3691 			return (0);
3692 		}
3693 		tl_p = add_lnk(&ttl_p);
3694 		l_p = ttl_p;
3695 		if (tl_p == l_p) { /* first link to this file encountered */
3696 			data_out();
3697 			return (0);
3698 		}
3699 		(void) strncpy(T_lname, l_p->L_gen.g_nam_p,
3700 		    l_p->L_gen.g_namesz);
3701 
3702 		/*
3703 		 * check if linkname is greater than 100 characters
3704 		 */
3705 		if (strlen(T_lname) > NAMSIZ) {
3706 			msg(EPOST, "cpio: %s: linkname %s is greater than %d",
3707 			    G_p->g_nam_p, T_lname, NAMSIZ);
3708 			return (1);
3709 		}
3710 
3711 		write_hdr(ARCHIVE_NORMAL, (off_t)0);
3712 		VERBOSE((Args & (OCv | OCV)), tl_p->L_gen.g_nam_p);
3713 
3714 		/* find the lnk entry in sublist, unlink it, and free it */
3715 		for (; ttl_p->L_lnk_p != NULL;
3716 		    ttl_p = ttl_p->L_lnk_p) {
3717 			if (ttl_p->L_lnk_p == tl_p) {
3718 				ttl_p->L_lnk_p = tl_p->L_lnk_p;
3719 				free(tl_p->L_gen.g_nam_p);
3720 				free(tl_p);
3721 				break;
3722 			}
3723 		}
3724 
3725 		return (0);
3726 	}
3727 	if (Adir) {
3728 		/*
3729 		 * ACL has been retrieved in getname().
3730 		 */
3731 		if (Pflag) {
3732 			char    *secinfo = NULL;
3733 			int	len = 0;
3734 
3735 			/* append security attributes */
3736 			if ((append_secattr(&secinfo, &len, aclp)) == -1)
3737 				msg(ERR, "can create security information");
3738 
3739 			/* call append_secattr() if more than one */
3740 
3741 			if (len > 0) {
3742 			/* write ancillary */
3743 				write_hdr(ARCHIVE_ACL, (off_t)len);
3744 				write_ancillary(secinfo, len, B_TRUE);
3745 			}
3746 		}
3747 
3748 		if (Gen.g_attrnam_p != NULL) {
3749 			write_xattr_hdr();
3750 		}
3751 		write_hdr(ARCHIVE_NORMAL, (off_t)0);
3752 		VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3753 		return (0);
3754 	}
3755 	if (G_p->g_nlink == 1) {
3756 		data_out();
3757 		return (0);
3758 	} else {
3759 		tl_p = add_lnk(&ttl_p);
3760 		l_p = ttl_p;
3761 
3762 		if (l_p->L_cnt == l_p->L_gen.g_nlink)
3763 			cleanup = 1;
3764 		else if (Onecopy && G_p->g_attrnam_p == NULL) {
3765 			return (0); /* don't process data yet */
3766 		}
3767 	}
3768 	if (Onecopy && G_p->g_attrnam_p == NULL) {
3769 		tl_p = l_p;
3770 		while (tl_p->L_lnk_p != NULL) {
3771 			G_p = &tl_p->L_gen;
3772 			G_p->g_filesz = (off_t)0;
3773 			/* one link with the acl is sufficient */
3774 			write_hdr(ARCHIVE_NORMAL, (off_t)0);
3775 			VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3776 			tl_p = tl_p->L_lnk_p;
3777 		}
3778 		G_p = &tl_p->L_gen;
3779 		if (open_dirfd() != 0)
3780 			return (1);
3781 	}
3782 	/* old style: has acl and data for every link */
3783 	data_out();
3784 	if (cleanup)
3785 		reclaim(l_p);
3786 	return (0);
3787 }
3788 
3789 /*
3790  * Verify the underlying file system supports the attribute type.
3791  * Only archive extended attribute files when '-@' was specified.
3792  * Only archive system extended attribute files if '-/' was specified.
3793  */
3794 #if defined(O_XATTR)
3795 static attr_status_t
verify_attr_support(char * filename,int attrflg,arc_action_t actflag,int * ext_attrflg)3796 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
3797     int *ext_attrflg)
3798 {
3799 	/*
3800 	 * Verify extended attributes are supported/exist.  We only
3801 	 * need to check if we are processing a base file, not an
3802 	 * extended attribute.
3803 	 */
3804 	if (attrflg) {
3805 		*ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
3806 		    _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
3807 	}
3808 	if (Atflag) {
3809 #if defined(_PC_SATTR_ENABLED)
3810 		if (!*ext_attrflg) {
3811 			if (SysAtflag) {
3812 				/* Verify system attributes are supported */
3813 				if (sysattr_support(filename,
3814 				    (actflag == ARC_CREATE) ?_PC_SATTR_EXISTS :
3815 				    _PC_SATTR_ENABLED) != 1) {
3816 					return (ATTR_SATTR_ERR);
3817 				}
3818 			} else
3819 				return (ATTR_XATTR_ERR);
3820 #else
3821 				return (ATTR_XATTR_ERR);
3822 #endif  /* _PC_SATTR_ENABLED */
3823 		}
3824 
3825 #if defined(_PC_SATTR_ENABLED)
3826 	} else if (SysAtflag) {
3827 		/* Verify system attributes are supported */
3828 		if (sysattr_support(filename, (actflag == ARC_CREATE) ?
3829 		    _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
3830 			return (ATTR_SATTR_ERR);
3831 	}
3832 #endif  /* _PC_SATTR_ENABLED */
3833 	} else {
3834 		return (ATTR_SKIP);
3835 	}
3836 
3837 return (ATTR_OK);
3838 }
3839 #endif
3840 
3841 #if defined(O_XATTR)
3842 /*
3843  * Verify the attribute, attrname, is an attribute we want to restore.
3844  * Never restore read-only system attribute files.  Only restore read-write
3845  * system attributes files when -/ was specified, and only traverse into
3846  * the 2nd level attribute directory containing only system attributes if
3847  * -@ was specified.  This keeps us from archiving
3848  *	<attribute name>/<read-write system attribute file>
3849  * when -/ was specified without -@.
3850  *
3851  * attrname		- attribute file name
3852  * attrparent		- attribute's parent name within the base file's
3853  *			attribute digrectory hierarchy
3854  * arc_rwsysattr	- flag that indicates that read-write system attribute
3855  *			file should be archived as it contains other than
3856  *			the default system attributes.
3857  * rw_sysattr		- on return, flag will indicate if attrname is a
3858  *			read-write system attribute file.
3859  */
3860 static attr_status_t
verify_attr(char * attrname,char * attrparent,int arc_rwsysattr,int * rw_sysattr)3861 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
3862     int *rw_sysattr)
3863 {
3864 #if defined(_PC_SATTR_ENABLED)
3865 	int	attr_supported;
3866 
3867 	/* Never restore read-only system attribute files */
3868 	if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
3869 		*rw_sysattr = 0;
3870 		return (ATTR_SKIP);
3871 	} else {
3872 		*rw_sysattr = (attr_supported == _RW_SATTR);
3873 	}
3874 
3875 	/*
3876 	 * Don't archive a read-write system attribute file if
3877 	 * it contains only the default system attributes.
3878 	 */
3879 	if (*rw_sysattr && !arc_rwsysattr) {
3880 		return (ATTR_SKIP);
3881 	}
3882 
3883 #else
3884 	/* Never restore read-only system attribute files */
3885 	if ((*rw_sysattr = is_sysattr(attrname)) == 1) {
3886 		return (ATTR_SKIP);
3887 	}
3888 #endif	/* _PC_SATTR_ENABLED */
3889 
3890 	/*
3891 	 * Only restore read-write system attribute files
3892 	 * when -/ was specified.  Only restore extended
3893 	 * attributes when -@ was specified.
3894 	 */
3895 	if (Atflag) {
3896 		if (!SysAtflag) {
3897 			/*
3898 			 * Only archive/restore the hidden directory "." if
3899 			 * we're processing the top level hidden attribute
3900 			 * directory.  We don't want to process the
3901 			 * hidden attribute directory of the attribute
3902 			 * directory that contains only extended system
3903 			 * attributes.
3904 			 */
3905 			if (*rw_sysattr || (Hiddendir &&
3906 			    (attrparent != NULL))) {
3907 				return (ATTR_SKIP);
3908 			}
3909 		}
3910 	} else if (SysAtflag) {
3911 		/*
3912 		 * Only archive/restore read-write extended system attribute
3913 		 * files of the base file.
3914 		 */
3915 		if (!*rw_sysattr || (attrparent != NULL)) {
3916 			return (ATTR_SKIP);
3917 		}
3918 	} else {
3919 		return (ATTR_SKIP);
3920 	}
3921 
3922 	return (ATTR_OK);
3923 }
3924 #endif
3925 
3926 #if defined(O_XATTR)
3927 static int
retry_open_attr(int pdirfd,int cwd,char * fullname,char * pattr,char * name,int oflag,mode_t mode)3928 retry_open_attr(int pdirfd, int cwd, char *fullname, char *pattr, char *name,
3929     int oflag, mode_t mode)
3930 {
3931 	int dirfd;
3932 	int ofilefd = -1;
3933 	struct timeval times[2];
3934 	mode_t newmode;
3935 	struct stat parentstat;
3936 	acl_t *aclp = NULL;
3937 	int error;
3938 
3939 	/*
3940 	 * We couldn't get to attrdir. See if its
3941 	 * just a mode problem on the parent file.
3942 	 * for example: a mode such as r-xr--r--
3943 	 * on a ufs file system without extended
3944 	 * system attribute support won't let us
3945 	 * create an attribute dir if it doesn't
3946 	 * already exist, and on a ufs file system
3947 	 * with extended system attribute support
3948 	 * won't let us open the attribute for
3949 	 * write.
3950 	 *
3951 	 * If file has a non-trivial ACL, then save it
3952 	 * off so that we can place it back on after doing
3953 	 * chmod's.
3954 	 */
3955 	if ((dirfd = openat(cwd, (pattr == NULL) ? fullname : pattr,
3956 	    O_RDONLY)) == -1) {
3957 		return (-1);
3958 	}
3959 	if (fstat(dirfd, &parentstat) == -1) {
3960 		msg(ERRN, "Cannot stat %sfile %s",
3961 		    (pdirfd == -1) ? "" : gettext("parent of "),
3962 		    (pdirfd == -1) ? fullname : name);
3963 		(void) close(dirfd);
3964 		return (-1);
3965 	}
3966 	if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
3967 		msg(ERRN, "Failed to retrieve ACL on %sfile %s",
3968 		    (pdirfd == -1) ? "" : gettext("parent of "),
3969 		    (pdirfd == -1) ? fullname : name);
3970 		(void) close(dirfd);
3971 		return (-1);
3972 	}
3973 
3974 	newmode = S_IWUSR | parentstat.st_mode;
3975 	if (fchmod(dirfd, newmode) == -1) {
3976 		msg(ERRN, "Cannot change mode of %sfile %s to %o",
3977 		    (pdirfd == -1) ? "" : gettext("parent of "),
3978 		    (pdirfd == -1) ? fullname : name, newmode);
3979 		if (