xref: /illumos-gate/usr/src/cmd/tar/tar.c (revision 7014882c)
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  */
25 
26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
30 /*	  All Rights Reserved	*/
31 
32 /*
33  * Portions of this source code were derived from Berkeley 4.3 BSD
34  * under license from the Regents of the University of California.
35  */
36 
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/stat.h>
41 #include <sys/mkdev.h>
42 #include <sys/wait.h>
43 #include <dirent.h>
44 #include <errno.h>
45 #include <stdio.h>
46 #include <signal.h>
47 #include <ctype.h>
48 #include <locale.h>
49 #include <nl_types.h>
50 #include <langinfo.h>
51 #include <pwd.h>
52 #include <grp.h>
53 #include <fcntl.h>
54 #include <string.h>
55 #include <malloc.h>
56 #include <time.h>
57 #include <utime.h>
58 #include <stdlib.h>
59 #include <stdarg.h>
60 #include <widec.h>
61 #include <sys/mtio.h>
62 #include <sys/acl.h>
63 #include <strings.h>
64 #include <deflt.h>
65 #include <limits.h>
66 #include <iconv.h>
67 #include <assert.h>
68 #include <libgen.h>
69 #include <libintl.h>
70 #include <aclutils.h>
71 #include <libnvpair.h>
72 #include <archives.h>
73 
74 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
75 extern int defcntl();
76 #endif
77 #if defined(_PC_SATTR_ENABLED)
78 #include <attr.h>
79 #include <libcmdutils.h>
80 #endif
81 
82 /* Trusted Extensions */
83 #include <zone.h>
84 #include <tsol/label.h>
85 #include <sys/tsol/label_macro.h>
86 
87 #include "getresponse.h"
88 /*
89  * Source compatibility
90  */
91 
92 /*
93  * These constants come from archives.h and sys/fcntl.h
94  * and were introduced by the extended attributes project
95  * in Solaris 9.
96  */
97 #if !defined(O_XATTR)
98 #define	AT_SYMLINK_NOFOLLOW	0x1000
99 #define	AT_REMOVEDIR		0x1
100 #define	AT_FDCWD		0xffd19553
101 #define	_XATTR_HDRTYPE		'E'
102 static int attropen();
103 static int fstatat();
104 static int renameat();
105 static int unlinkat();
106 static int openat();
107 static int fchownat();
108 static int futimesat();
109 #endif
110 
111 /*
112  * Compiling with -D_XPG4_2 gets this but produces other problems, so
113  * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
114  * explicitly doing the declaration here.
115  */
116 int utimes(const char *path, const struct timeval timeval_ptr[]);
117 
118 #ifndef MINSIZE
119 #define	MINSIZE 250
120 #endif
121 #define	DEF_FILE "/etc/default/tar"
122 
123 #define	min(a, b)  ((a) < (b) ? (a) : (b))
124 #define	max(a, b)  ((a) > (b) ? (a) : (b))
125 
126 /* -DDEBUG	ONLY for debugging */
127 #ifdef	DEBUG
128 #undef	DEBUG
129 #define	DEBUG(a, b, c)\
130 	(void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c)
131 #endif
132 
133 #define	TBLOCK	512	/* tape block size--should be universal */
134 
135 #ifdef	BSIZE
136 #define	SYS_BLOCK BSIZE	/* from sys/param.h:  secondary block size */
137 #else	/* BSIZE */
138 #define	SYS_BLOCK 512	/* default if no BSIZE in param.h */
139 #endif	/* BSIZE */
140 
141 #define	NBLOCK	20
142 #define	NAMSIZ	100
143 #define	PRESIZ	155
144 #define	MAXNAM	256
145 #define	MODEMASK 0777777	/* file creation mode mask */
146 #define	POSIXMODES 07777	/* mask for POSIX mode bits */
147 #define	MAXEXT	9	/* reasonable max # extents for a file */
148 #define	EXTMIN	50	/* min blks left on floppy to split a file */
149 
150 /* max value dblock.dbuf.efsize can store */
151 #define	TAR_EFSIZE_MAX	 0777777777
152 
153 /*
154  * Symbols which specify the values at which the use of the 'E' function
155  * modifier is required to properly store a file.
156  *
157  *     TAR_OFFSET_MAX    - the largest file size we can archive
158  *     OCTAL7CHAR        - the limit for ustar gid, uid, dev
159  */
160 
161 #ifdef XHDR_DEBUG
162 /* tiny values which force the creation of extended header entries */
163 #define	TAR_OFFSET_MAX 9
164 #define	OCTAL7CHAR 2
165 #else
166 /* normal values */
167 #define	TAR_OFFSET_MAX	077777777777ULL
168 #define	OCTAL7CHAR	07777777
169 #endif
170 
171 #define	TBLOCKS(bytes)	(((bytes) + TBLOCK - 1) / TBLOCK)
172 #define	K(tblocks)	((tblocks+1)/2)	/* tblocks to Kbytes for printing */
173 
174 #define	MAXLEV	(PATH_MAX / 2)
175 #define	LEV0	1
176 #define	SYMLINK_LEV0	0
177 
178 #define	TRUE	1
179 #define	FALSE	0
180 
181 #define	XATTR_FILE	1
182 #define	NORMAL_FILE	0
183 
184 #define	PUT_AS_LINK	1
185 #define	PUT_NOTAS_LINK	0
186 
187 #ifndef VIEW_READONLY
188 #define	VIEW_READONLY	"SUNWattr_ro"
189 #endif
190 
191 #ifndef VIEW_READWRITE
192 #define	VIEW_READWRITE	"SUNWattr_rw"
193 #endif
194 
195 #if _FILE_OFFSET_BITS == 64
196 #define	FMT_off_t "lld"
197 #define	FMT_off_t_o "llo"
198 #define	FMT_blkcnt_t "lld"
199 #else
200 #define	FMT_off_t "ld"
201 #define	FMT_off_t_o "lo"
202 #define	FMT_blkcnt_t "ld"
203 #endif
204 
205 /* ACL support */
206 
207 static
208 struct	sec_attr {
209 	char	attr_type;
210 	char	attr_len[7];
211 	char	attr_info[1];
212 } *attr;
213 
214 #if defined(O_XATTR)
215 typedef enum {
216 	ATTR_OK,
217 	ATTR_SKIP,
218 	ATTR_CHDIR_ERR,
219 	ATTR_OPEN_ERR,
220 	ATTR_XATTR_ERR,
221 	ATTR_SATTR_ERR
222 } attr_status_t;
223 #endif
224 
225 #if defined(O_XATTR)
226 typedef enum {
227 	ARC_CREATE,
228 	ARC_RESTORE
229 } arc_action_t;
230 #endif
231 
232 typedef struct attr_data {
233 	char	*attr_parent;
234 	char	*attr_path;
235 	int	attr_parentfd;
236 	int	attr_rw_sysattr;
237 } attr_data_t;
238 
239 /*
240  *
241  * Tar has been changed to support extended attributes.
242  *
243  * As part of this change tar now uses the new *at() syscalls
244  * such as openat, fchownat(), unlinkat()...
245  *
246  * This was done so that attributes can be handled with as few code changes
247  * as possible.
248  *
249  * What this means is that tar now opens the directory that a file or directory
250  * resides in and then performs *at() functions to manipulate the entry.
251  *
252  * For example a new file is now created like this:
253  *
254  * dfd = open(<some dir path>)
255  * fd = openat(dfd, <name>,....);
256  *
257  * or in the case of an extended attribute
258  *
259  * dfd = attropen(<pathname>, ".", ....)
260  *
261  * Once we have a directory file descriptor all of the *at() functions can
262  * be applied to it.
263  *
264  * unlinkat(dfd, <component name>,...)
265  * fchownat(dfd, <component name>,..)
266  *
267  * This works for both normal namespace files and extended attribute file
268  *
269  */
270 
271 /*
272  *
273  * Extended attribute Format
274  *
275  * Extended attributes are stored in two pieces.
276  * 1. An attribute header which has information about
277  *    what file the attribute is for and what the attribute
278  *    is named.
279  * 2. The attribute record itself.  Stored as a normal file type
280  *    of entry.
281  * Both the header and attribute record have special modes/typeflags
282  * associated with them.
283  *
284  * The names of the header in the archive look like:
285  * /dev/null/attr.hdr
286  *
287  * The name of the attribute looks like:
288  * /dev/null/attr
289  *
290  * This is done so that an archiver that doesn't understand these formats
291  * can just dispose of the attribute records.
292  *
293  * The format is composed of a fixed size header followed
294  * by a variable sized xattr_buf. If the attribute is a hard link
295  * to another attribute then another xattr_buf section is included
296  * for the link.
297  *
298  * The xattr_buf is used to define the necessary "pathing" steps
299  * to get to the extended attribute.  This is necessary to support
300  * a fully recursive attribute model where an attribute may itself
301  * have an attribute.
302  *
303  * The basic layout looks like this.
304  *
305  *     --------------------------------
306  *     |                              |
307  *     |         xattr_hdr            |
308  *     |                              |
309  *     --------------------------------
310  *     --------------------------------
311  *     |                              |
312  *     |        xattr_buf             |
313  *     |                              |
314  *     --------------------------------
315  *     --------------------------------
316  *     |                              |
317  *     |      (optional link info)    |
318  *     |                              |
319  *     --------------------------------
320  *     --------------------------------
321  *     |                              |
322  *     |      attribute itself        |
323  *     |      stored as normal tar    |
324  *     |      or cpio data with       |
325  *     |      special mode or         |
326  *     |      typeflag                |
327  *     |                              |
328  *     --------------------------------
329  *
330  */
331 
332 /*
333  * xattrhead is a pointer to the xattr_hdr
334  *
335  * xattrp is a pointer to the xattr_buf structure
336  * which contains the "pathing" steps to get to attributes
337  *
338  * xattr_linkp is a pointer to another xattr_buf structure that is
339  * only used when an attribute is actually linked to another attribute
340  *
341  */
342 
343 static struct xattr_hdr *xattrhead;
344 static struct xattr_buf *xattrp;
345 static struct xattr_buf *xattr_linkp;	/* pointer to link info, if any */
346 static char *xattrapath;		/* attribute name */
347 static char *xattr_linkaname;		/* attribute attribute is linked to */
348 static char Hiddendir;			/* are we processing hidden xattr dir */
349 static char xattrbadhead;
350 
351 /* Was statically allocated tbuf[NBLOCK] */
352 static
353 union hblock {
354 	char dummy[TBLOCK];
355 	struct header {
356 		char name[NAMSIZ];	/* If non-null prefix, path is	*/
357 					/* <prefix>/<name>;  otherwise	*/
358 					/* <name>			*/
359 		char mode[8];
360 		char uid[8];
361 		char gid[8];
362 		char size[12];		/* size of this extent if file split */
363 		char mtime[12];
364 		char chksum[8];
365 		char typeflag;
366 		char linkname[NAMSIZ];
367 		char magic[6];
368 		char version[2];
369 		char uname[32];
370 		char gname[32];
371 		char devmajor[8];
372 		char devminor[8];
373 		char prefix[PRESIZ];	/* Together with "name", the path of */
374 					/* the file:  <prefix>/<name>	*/
375 		char extno;		/* extent #, null if not split */
376 		char extotal;		/* total extents */
377 		char efsize[10];	/* size of entire file */
378 	} dbuf;
379 } dblock, *tbuf, xhdr_buf;
380 
381 static
382 struct xtar_hdr {
383 	uid_t		x_uid,		/* Uid of file */
384 			x_gid;		/* Gid of file */
385 	major_t		x_devmajor;	/* Device major node */
386 	minor_t		x_devminor;	/* Device minor node */
387 	off_t		x_filesz;	/* Length of file */
388 	char		*x_uname,	/* Pointer to name of user */
389 			*x_gname,	/* Pointer to gid of user */
390 			*x_linkpath,	/* Path for a hard/symbolic link */
391 			*x_path;	/* Path of file */
392 	timestruc_t	x_mtime;	/* Seconds and nanoseconds */
393 } Xtarhdr;
394 
395 static
396 struct gen_hdr {
397 	ulong_t		g_mode;		/* Mode of file */
398 	uid_t		g_uid,		/* Uid of file */
399 			g_gid;		/* Gid of file */
400 	off_t		g_filesz;	/* Length of file */
401 	time_t		g_mtime;	/* Modification time */
402 	uint_t		g_cksum;	/* Checksum of file */
403 	ulong_t		g_devmajor,	/* File system of file */
404 			g_devminor;	/* Major/minor of special files */
405 } Gen;
406 
407 static
408 struct linkbuf {
409 	ino_t	inum;
410 	dev_t	devnum;
411 	int	count;
412 	char	pathname[MAXNAM+1];	/* added 1 for last NULL */
413 	char 	attrname[MAXNAM+1];
414 	struct	linkbuf *nextp;
415 } *ihead;
416 
417 /* see comments before build_table() */
418 #define	TABLE_SIZE 512
419 typedef struct	file_list	{
420 	char	*name;			/* Name of file to {in,ex}clude */
421 	struct	file_list	*next;	/* Linked list */
422 } file_list_t;
423 static	file_list_t	*exclude_tbl[TABLE_SIZE],
424 			*include_tbl[TABLE_SIZE];
425 
426 static int	append_secattr(char **, int *, int, char *, char);
427 static void	write_ancillary(union hblock *, char *, int, char);
428 
429 static void add_file_to_table(file_list_t *table[], char *str);
430 static void assert_string(char *s, char *msg);
431 static int istape(int fd, int type);
432 static void backtape(void);
433 static void build_table(file_list_t *table[], char *file);
434 static int check_prefix(char **namep, char **dirp, char **compp);
435 static void closevol(void);
436 static void copy(void *dst, void *src);
437 static int convtoreg(off_t);
438 static void delete_target(int fd, char *comp, char *namep);
439 static void doDirTimes(char *name, timestruc_t modTime);
440 static void done(int n);
441 static void dorep(char *argv[]);
442 static void dotable(char *argv[]);
443 static void doxtract(char *argv[]);
444 static int tar_chdir(const char *path);
445 static int is_directory(char *name);
446 static int has_dot_dot(char *name);
447 static int is_absolute(char *name);
448 static char *make_relative_name(char *name, char **stripped_prefix);
449 static void fatal(char *format, ...);
450 static void vperror(int exit_status, char *fmt, ...);
451 static void flushtape(void);
452 static void getdir(void);
453 static void *getmem(size_t);
454 static void longt(struct stat *st, char aclchar);
455 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
456 static int makeDir(char *name);
457 static void mterr(char *operation, int i, int exitcode);
458 static void newvol(void);
459 static void passtape(void);
460 static void putempty(blkcnt_t n);
461 static int putfile(char *longname, char *shortname, char *parent,
462     attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
463 static void readtape(char *buffer);
464 static void seekdisk(blkcnt_t blocks);
465 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
466 static void setbytes_to_skip(struct stat *st, int err);
467 static void splitfile(char *longname, int ifd, char *name,
468 	char *prefix, int filetype);
469 static void tomodes(struct stat *sp);
470 static void usage(void);
471 static int xblocks(int issysattr, off_t bytes, int ofile);
472 static int xsfile(int issysattr, int ofd);
473 static void resugname(int dirfd, char *name, int symflag);
474 static int bcheck(char *bstr);
475 static int checkdir(char *name);
476 static int checksum(union hblock *dblockp);
477 #ifdef	EUC
478 static int checksum_signed(union hblock *dblockp);
479 #endif	/* EUC */
480 static int checkupdate(char *arg);
481 static int checkw(char c, char *name);
482 static int cmp(char *b, char *s, int n);
483 static int defset(char *arch);
484 static int endtape(void);
485 static int is_in_table(file_list_t *table[], char *str);
486 static int notsame(void);
487 static int is_prefix(char *s1, char *s2);
488 static int response(void);
489 static int build_dblock(const char *, const char *, const char,
490 	const int filetype, const struct stat *, const dev_t, const char *);
491 static unsigned int hash(char *str);
492 
493 static blkcnt_t kcheck(char *kstr);
494 static off_t bsrch(char *s, int n, off_t l, off_t h);
495 static void onintr(int sig);
496 static void onquit(int sig);
497 static void onhup(int sig);
498 static uid_t getuidbyname(char *);
499 static gid_t getgidbyname(char *);
500 static char *getname(gid_t);
501 static char *getgroup(gid_t);
502 static int checkf(char *name, int mode, int howmuch);
503 static int writetbuf(char *buffer, int n);
504 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
505     attr_data_t **attrinfo);
506 static void append_ext_attr(char *shortname, char **secinfo, int *len);
507 static int get_xdata(void);
508 static void gen_num(const char *keyword, const u_longlong_t number);
509 static void gen_date(const char *keyword, const timestruc_t time_value);
510 static void gen_string(const char *keyword, const char *value);
511 static void get_xtime(char *value, timestruc_t *xtime);
512 static int chk_path_build(char *name, char *longname, char *linkname,
513     char *prefix, char type, int filetype);
514 static int gen_utf8_names(const char *filename);
515 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
516     const char *src, int max_val);
517 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
518     iconv_t iconv_cd, int xhdrflg, int max_val);
519 static int c_utf8(char *target, const char *source);
520 static int getstat(int dirfd, char *longname, char *shortname,
521     char *attrparent);
522 static void xattrs_put(char *, char *, char *, char *);
523 static void prepare_xattr(char **, char	*, char	*,
524     char, struct linkbuf *, int *);
525 static int put_link(char *name, char *longname, char *component,
526     char *longattrname, char *prefix, int filetype, char typeflag);
527 static int put_extra_attributes(char *longname, char *shortname,
528     char *longattrname, char *prefix, int filetype, char typeflag);
529 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
530     char *prefix, int typeflag, int filetype, struct linkbuf *lp);
531 static int read_xattr_hdr(attr_data_t **attrinfo);
532 
533 /* Trusted Extensions */
534 #define	AUTO_ZONE	"/zone"
535 
536 static void extract_attr(char **file_ptr, struct sec_attr *);
537 static int check_ext_attr(char *filename);
538 static void rebuild_comp_path(char *str, char **namep);
539 static int rebuild_lk_comp_path(char *str, char **namep);
540 
541 static void get_parent(char *path, char *dir);
542 static char *get_component(char *path);
543 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
544     char *name, int oflag, mode_t mode);
545 static char *skipslashes(char *string, char *start);
546 static void chop_endslashes(char *path);
547 static pid_t compress_file(void);
548 static void compress_back(void);
549 static void decompress_file(void);
550 static pid_t uncompress_file(void);
551 static void *compress_malloc(size_t);
552 static void check_compression(void);
553 static char *bz_suffix(void);
554 static char *gz_suffix(void);
555 static char *xz_suffix(void);
556 static char *add_suffix();
557 static void wait_pid(pid_t);
558 static void verify_compress_opt(const char *t);
559 static void detect_compress(void);
560 
561 static	struct stat stbuf;
562 
563 static	char	*myname;
564 static	int	checkflag = 0;
565 static	int	Xflag, Fflag, iflag, hflag, Bflag, Iflag;
566 static	int	rflag, xflag, vflag, tflag, mt, svmt, cflag, mflag, pflag;
567 static	int	uflag;
568 static	int	errflag;
569 static	int	oflag;
570 static	int	bflag, Aflag;
571 static 	int	Pflag;			/* POSIX conformant archive */
572 static	int	Eflag;			/* Allow files greater than 8GB */
573 static	int	atflag;			/* traverse extended attributes */
574 static	int	saflag;			/* traverse extended sys attributes */
575 static	int	Dflag;			/* Data change flag */
576 static	int	jflag;			/* flag to use 'bzip2' */
577 static	int	zflag;			/* flag to use 'gzip' */
578 static	int	Zflag;			/* flag to use 'compress' */
579 static	int	Jflag;			/* flag to use 'xz' */
580 static	int	aflag;			/* flag to use autocompression */
581 
582 /* Trusted Extensions */
583 static	int	Tflag;			/* Trusted Extensions attr flags */
584 static	int	dir_flag;		/* for attribute extract */
585 static	int	mld_flag;		/* for attribute extract */
586 static	char	*orig_namep;		/* original namep - unadorned */
587 static	int	rpath_flag;		/* MLD real path is rebuilt */
588 static	char	real_path[MAXPATHLEN];	/* MLD real path */
589 static	int	lk_rpath_flag;		/* linked to real path is rebuilt */
590 static	char	lk_real_path[MAXPATHLEN]; /* linked real path */
591 static	bslabel_t	bs_label;	/* for attribute extract */
592 static	bslabel_t	admin_low;
593 static	bslabel_t	admin_high;
594 static	int	ignored_aprivs = 0;
595 static	int	ignored_fprivs = 0;
596 static	int	ignored_fattrs = 0;
597 
598 static	int	term, chksum, wflag,
599 		first = TRUE, defaults_used = FALSE, linkerrok;
600 static	blkcnt_t	recno;
601 static	int	freemem = 1;
602 static	int	nblock = NBLOCK;
603 static	int	Errflg = 0;
604 static	int	exitflag = 0;
605 
606 static	dev_t	mt_dev;		/* device containing output file */
607 static	ino_t	mt_ino;		/* inode number of output file */
608 static	int	mt_devtype;	/* dev type of archive, from stat structure */
609 
610 static	int update = 1;		/* for `open' call */
611 
612 static	off_t	low;
613 static	off_t	high;
614 
615 static	FILE	*tfile;
616 static	FILE	*vfile = stdout;
617 static	char	*tmpdir;
618 static	char	*tmp_suffix = "/tarXXXXXX";
619 static	char	*tname;
620 static	char	archive[] = "archive0=";
621 static	char	*Xfile;
622 static	char	*usefile;
623 static	char	tfname[1024];
624 
625 static	int	mulvol;		/* multi-volume option selected */
626 static	blkcnt_t	blocklim; /* number of blocks to accept per volume */
627 static	blkcnt_t	tapepos; /* current block number to be written */
628 static	int	NotTape;	/* true if tape is a disk */
629 static	int	dumping;	/* true if writing a tape or other archive */
630 static	int	extno;		/* number of extent:  starts at 1 */
631 static	int	extotal;	/* total extents in this file */
632 static	off_t	extsize;	/* size of current extent during extraction */
633 static	ushort_t	Oumask = 0;	/* old umask value */
634 static 	int is_posix;	/* true if archive we're reading is POSIX-conformant */
635 static	const	char	*magic_type = "ustar";
636 static	size_t	xrec_size = 8 * PATH_MAX;	/* extended rec initial size */
637 static	char	*xrec_ptr;
638 static	off_t	xrec_offset = 0;
639 static	int	Xhdrflag;
640 static	int	charset_type = 0;
641 
642 static	u_longlong_t	xhdr_flgs;	/* Bits set determine which items */
643 					/*   need to be in extended header. */
644 #define	_X_DEVMAJOR	0x1
645 #define	_X_DEVMINOR	0x2
646 #define	_X_GID		0x4
647 #define	_X_GNAME	0x8
648 #define	_X_LINKPATH	0x10
649 #define	_X_PATH		0x20
650 #define	_X_SIZE		0x40
651 #define	_X_UID		0x80
652 #define	_X_UNAME	0x100
653 #define	_X_ATIME	0x200
654 #define	_X_CTIME	0x400
655 #define	_X_MTIME	0x800
656 #define	_X_XHDR		0x1000	/* Bit flag that determines whether 'X' */
657 				/* typeflag was followed by 'A' or non 'A' */
658 				/* typeflag. */
659 #define	_X_LAST		0x40000000
660 
661 #define	PID_MAX_DIGITS		(10 * sizeof (pid_t) / 4)
662 #define	TIME_MAX_DIGITS		(10 * sizeof (time_t) / 4)
663 #define	LONG_MAX_DIGITS		(10 * sizeof (long) / 4)
664 #define	ULONGLONG_MAX_DIGITS	(10 * sizeof (u_longlong_t) / 4)
665 /*
666  * UTF_8 encoding requires more space than the current codeset equivalent.
667  * Currently a factor of 2-3 would suffice, but it is possible for a factor
668  * of 6 to be needed in the future, so for saftey, we use that here.
669  */
670 #define	UTF_8_FACTOR	6
671 
672 static	u_longlong_t	xhdr_count = 0;
673 static char		xhdr_dirname[PRESIZ + 1];
674 static char		pidchars[PID_MAX_DIGITS + 1];
675 static char		*tchar = "";		/* null linkpath */
676 
677 static	char	local_path[UTF_8_FACTOR * PATH_MAX + 1];
678 static	char	local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
679 static	char	local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
680 static	char	local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
681 
682 /*
683  * The following mechanism is provided to allow us to debug tar in complicated
684  * situations, like when it is part of a pipe.  The idea is that you compile
685  * with -DWAITAROUND defined, and then add the 'D' function modifier to the
686  * target tar invocation, eg. "tar cDf tarfile file".  If stderr is available,
687  * it will tell you to which pid to attach the debugger; otherwise, use ps to
688  * find it.  Attach to the process from the debugger, and, *PRESTO*, you are
689  * there!
690  *
691  * Simply assign "waitaround = 0" once you attach to the process, and then
692  * proceed from there as usual.
693  */
694 
695 #ifdef WAITAROUND
696 int waitaround = 0;		/* wait for rendezvous with the debugger */
697 #endif
698 
699 #define	BZIP		"/usr/bin/bzip2"
700 #define	GZIP		"/usr/bin/gzip"
701 #define	COMPRESS	"/usr/bin/compress"
702 #define	XZ		"/usr/bin/xz"
703 #define	BZCAT		"/usr/bin/bzcat"
704 #define	GZCAT		"/usr/bin/gzcat"
705 #define	ZCAT		"/usr/bin/zcat"
706 #define	XZCAT		"/usr/bin/xzcat"
707 #define	GSUF		8	/* number of valid 'gzip' sufixes */
708 #define	BSUF		4	/* number of valid 'bzip2' sufixes */
709 #define	XSUF		1	/* number of valid 'xz' suffixes */
710 
711 static	char		*compress_opt; 	/* compression type */
712 
713 static	char		*gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
714 			".tgz", ".taz"};
715 static	char		*bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
716 static	char		*xsuffix[] = {".xz"};
717 static	char		*suffix;
718 
719 
720 int
721 main(int argc, char *argv[])
722 {
723 	char		*cp;
724 	char		*tmpdirp;
725 	pid_t		thispid;
726 	pid_t		pid;
727 	int		wstat;
728 
729 	(void) setlocale(LC_ALL, "");
730 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
731 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
732 #endif
733 	(void) textdomain(TEXT_DOMAIN);
734 	if (argc < 2)
735 		usage();
736 
737 	tfile = NULL;
738 	if ((myname = strdup(argv[0])) == NULL) {
739 		(void) fprintf(stderr, gettext(
740 		    "tar: cannot allocate program name\n"));
741 		exit(1);
742 	}
743 
744 	if (init_yes() < 0) {
745 		(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
746 		    strerror(errno));
747 		exit(2);
748 	}
749 
750 	/*
751 	 *  For XPG4 compatibility, we must be able to accept the "--"
752 	 *  argument normally recognized by getopt; it is used to delimit
753 	 *  the end opt the options section, and so can only appear in
754 	 *  the position of the first argument.  We simply skip it.
755 	 */
756 
757 	if (strcmp(argv[1], "--") == 0) {
758 		argv++;
759 		argc--;
760 		if (argc < 3)
761 			usage();
762 	}
763 
764 	argv[argc] = NULL;
765 	argv++;
766 
767 	/*
768 	 * Set up default values.
769 	 * Search the operand string looking for the first digit or an 'f'.
770 	 * If you find a digit, use the 'archive#' entry in DEF_FILE.
771 	 * If 'f' is given, bypass looking in DEF_FILE altogether.
772 	 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
773 	 */
774 	if ((usefile = getenv("TAPE")) == (char *)NULL) {
775 		for (cp = *argv; *cp; ++cp)
776 			if (isdigit(*cp) || *cp == 'f')
777 				break;
778 		if (*cp != 'f') {
779 			archive[7] = (*cp)? *cp: '0';
780 			if (!(defaults_used = defset(archive))) {
781 				usefile = NULL;
782 				nblock = 1;
783 				blocklim = 0;
784 				NotTape = 0;
785 			}
786 		}
787 	}
788 
789 	for (cp = *argv++; *cp; cp++)
790 		switch (*cp) {
791 #ifdef WAITAROUND
792 		case 'D':
793 			/* rendezvous with the debugger */
794 			waitaround = 1;
795 			break;
796 #endif
797 		case 'f':
798 			assert_string(*argv, gettext(
799 			    "tar: tarfile must be specified with 'f' "
800 			    "function modifier\n"));
801 			usefile = *argv++;
802 			break;
803 		case 'F':
804 			Fflag++;
805 			break;
806 		case 'c':
807 			cflag++;
808 			rflag++;
809 			update = 1;
810 			break;
811 #if defined(O_XATTR)
812 		case '@':
813 			atflag++;
814 			break;
815 #endif	/* O_XATTR */
816 #if defined(_PC_SATTR_ENABLED)
817 		case '/':
818 			saflag++;
819 			break;
820 #endif	/* _PC_SATTR_ENABLED */
821 		case 'u':
822 			uflag++;	/* moved code after signals caught */
823 			rflag++;
824 			update = 2;
825 			break;
826 		case 'r':
827 			rflag++;
828 			update = 2;
829 			break;
830 		case 'v':
831 			vflag++;
832 			break;
833 		case 'w':
834 			wflag++;
835 			break;
836 		case 'x':
837 			xflag++;
838 			break;
839 		case 'X':
840 			assert_string(*argv, gettext(
841 			    "tar: exclude file must be specified with 'X' "
842 			    "function modifier\n"));
843 			Xflag = 1;
844 			Xfile = *argv++;
845 			build_table(exclude_tbl, Xfile);
846 			break;
847 		case 't':
848 			tflag++;
849 			break;
850 		case 'm':
851 			mflag++;
852 			break;
853 		case 'p':
854 			pflag++;
855 			break;
856 		case 'D':
857 			Dflag++;
858 			break;
859 		case '-':
860 			/* ignore this silently */
861 			break;
862 		case '0':	/* numeric entries used only for defaults */
863 		case '1':
864 		case '2':
865 		case '3':
866 		case '4':
867 		case '5':
868 		case '6':
869 		case '7':
870 			break;
871 		case 'b':
872 			assert_string(*argv, gettext(
873 			    "tar: blocking factor must be specified "
874 			    "with 'b' function modifier\n"));
875 			bflag++;
876 			nblock = bcheck(*argv++);
877 			break;
878 		case 'n':		/* not a magtape (instead of 'k') */
879 			NotTape++;	/* assume non-magtape */
880 			break;
881 		case 'l':
882 			linkerrok++;
883 			break;
884 		case 'e':
885 			errflag++;
886 		case 'o':
887 			oflag++;
888 			break;
889 		case 'h':
890 			hflag++;
891 			break;
892 		case 'i':
893 			iflag++;
894 			break;
895 		case 'B':
896 			Bflag++;
897 			break;
898 		case 'P':
899 			Pflag++;
900 			break;
901 		case 'E':
902 			Eflag++;
903 			Pflag++;	/* Only POSIX archive made */
904 			break;
905 		case 'T':
906 			Tflag++;	/* Handle Trusted Extensions attrs */
907 			pflag++;	/* also set flag for ACL */
908 			break;
909 		case 'j':		/* compession "bzip2" */
910 			jflag = 1;
911 			break;
912 		case 'z':		/* compression "gzip" */
913 			zflag = 1;
914 			break;
915 		case 'Z':		/* compression "compress" */
916 			Zflag = 1;
917 			break;
918 		case 'J':		/* compression "xz" */
919 			Jflag = 1;
920 			break;
921 		case 'a':
922 			aflag = 1;	/* autocompression */
923 			break;
924 		default:
925 			(void) fprintf(stderr, gettext(
926 			"tar: %c: unknown function modifier\n"), *cp);
927 			usage();
928 		}
929 
930 	if (!rflag && !xflag && !tflag)
931 		usage();
932 	if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
933 		(void) fprintf(stderr, gettext(
934 		"tar: specify only one of [ctxru].\n"));
935 		usage();
936 	}
937 	if (cflag) {
938 		if ((jflag + zflag + Zflag + Jflag + aflag) > 1) {
939 			(void) fprintf(stderr, gettext(
940 			    "tar: specify only one of [ajJzZ] to "
941 			    "create a compressed file.\n"));
942 			usage();
943 		}
944 	}
945 	/* Trusted Extensions attribute handling */
946 	if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
947 	    !is_system_labeled())) {
948 		(void) fprintf(stderr, gettext(
949 		"tar: the 'T' option is only available with "
950 		    "Trusted Extensions\nand must be run from "
951 		    "the global zone.\n"));
952 		usage();
953 	}
954 	if (cflag && *argv == NULL)
955 		fatal(gettext("Missing filenames"));
956 	if (usefile == NULL)
957 		fatal(gettext("device argument required"));
958 
959 	/* alloc a buffer of the right size */
960 	if ((tbuf = (union hblock *)
961 	    calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
962 	    (union hblock *)NULL) {
963 		(void) fprintf(stderr, gettext(
964 		"tar: cannot allocate physio buffer\n"));
965 		exit(1);
966 	}
967 
968 	if ((xrec_ptr = malloc(xrec_size)) == NULL) {
969 		(void) fprintf(stderr, gettext(
970 		    "tar: cannot allocate extended header buffer\n"));
971 		exit(1);
972 	}
973 
974 #ifdef WAITAROUND
975 	if (waitaround) {
976 		(void) fprintf(stderr, gettext("Rendezvous with tar on pid"
977 		    " %d\n"), getpid());
978 
979 		while (waitaround) {
980 			(void) sleep(10);
981 		}
982 	}
983 #endif
984 
985 	thispid = getpid();
986 	(void) sprintf(pidchars, "%ld", thispid);
987 	thispid = strlen(pidchars);
988 
989 	if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
990 		(void) strcpy(xhdr_dirname, "/tmp");
991 	else {
992 		/*
993 		 * Make sure that dir is no longer than what can
994 		 * fit in the prefix part of the header.
995 		 */
996 		if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
997 			(void) strcpy(xhdr_dirname, "/tmp");
998 			if ((vflag > 0) && (Eflag > 0))
999 				(void) fprintf(stderr, gettext(
1000 				    "Ignoring TMPDIR\n"));
1001 		} else
1002 			(void) strcpy(xhdr_dirname, tmpdirp);
1003 	}
1004 	(void) strcat(xhdr_dirname, "/PaxHeaders.");
1005 	(void) strcat(xhdr_dirname, pidchars);
1006 
1007 	if (rflag) {
1008 		if (cflag && usefile != NULL)  {
1009 			/* Set the compression type */
1010 			if (aflag)
1011 				detect_compress();
1012 
1013 			if (jflag) {
1014 				compress_opt = compress_malloc(strlen(BZIP)
1015 				    + 1);
1016 				(void) strcpy(compress_opt, BZIP);
1017 			} else if (zflag) {
1018 				compress_opt = compress_malloc(strlen(GZIP)
1019 				    + 1);
1020 				(void) strcpy(compress_opt, GZIP);
1021 			} else if (Zflag) {
1022 				compress_opt =
1023 				    compress_malloc(strlen(COMPRESS) + 1);
1024 				(void) strcpy(compress_opt, COMPRESS);
1025 			} else if (Jflag) {
1026 				compress_opt = compress_malloc(strlen(XZ) + 1);
1027 				(void) strcpy(compress_opt, XZ);
1028 			}
1029 		} else {
1030 			/*
1031 			 * Decompress if the file is compressed for
1032 			 * an update or replace.
1033 			 */
1034 			if (strcmp(usefile, "-") != 0) {
1035 				check_compression();
1036 				if (compress_opt != NULL) {
1037 					decompress_file();
1038 				}
1039 			}
1040 		}
1041 
1042 		if (cflag && tfile != NULL)
1043 			usage();
1044 		if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1045 			(void) signal(SIGINT, onintr);
1046 		if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1047 			(void) signal(SIGHUP, onhup);
1048 		if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1049 			(void) signal(SIGQUIT, onquit);
1050 		if (uflag) {
1051 			int tnum;
1052 			struct stat sbuf;
1053 
1054 			tmpdir = getenv("TMPDIR");
1055 			/*
1056 			 * If the name is invalid or this isn't a directory,
1057 			 * or the directory is not writable, then reset to
1058 			 * a default temporary directory.
1059 			 */
1060 			if (tmpdir == NULL || *tmpdir == '\0' ||
1061 			    (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
1062 				tmpdir = "/tmp";
1063 			} else if (stat(tmpdir, &sbuf) < 0 ||
1064 			    (sbuf.st_mode & S_IFMT) != S_IFDIR ||
1065 			    (sbuf.st_mode & S_IWRITE) == 0) {
1066 				tmpdir = "/tmp";
1067 			}
1068 
1069 			if ((tname = calloc(1, strlen(tmpdir) +
1070 			    strlen(tmp_suffix) + 1)) == NULL) {
1071 				vperror(1, gettext("tar: out of memory, "
1072 				    "cannot create temporary file\n"));
1073 			}
1074 			(void) strcpy(tname, tmpdir);
1075 			(void) strcat(tname, tmp_suffix);
1076 
1077 			if ((tnum = mkstemp(tname)) == -1)
1078 				vperror(1, "%s", tname);
1079 			if ((tfile = fdopen(tnum, "w")) == NULL)
1080 				vperror(1, "%s", tname);
1081 		}
1082 		if (strcmp(usefile, "-") == 0) {
1083 			if (cflag == 0)
1084 				fatal(gettext(
1085 				"can only create standard output archives."));
1086 			vfile = stderr;
1087 			mt = dup(1);
1088 			++bflag;
1089 		} else {
1090 			if (cflag)
1091 				mt = open(usefile,
1092 				    O_RDWR|O_CREAT|O_TRUNC, 0666);
1093 			else
1094 				mt = open(usefile, O_RDWR);
1095 
1096 			if (mt < 0) {
1097 				if (cflag == 0 || (mt =  creat(usefile, 0666))
1098 				    < 0)
1099 				vperror(1, "%s", usefile);
1100 			}
1101 		}
1102 		/* Get inode and device number of output file */
1103 		(void) fstat(mt, &stbuf);
1104 		mt_ino = stbuf.st_ino;
1105 		mt_dev = stbuf.st_dev;
1106 		mt_devtype = stbuf.st_mode & S_IFMT;
1107 		NotTape = !istape(mt, mt_devtype);
1108 
1109 		if (rflag && !cflag && (mt_devtype == S_IFIFO))
1110 			fatal(gettext("cannot append to pipe or FIFO."));
1111 
1112 		if (Aflag && vflag)
1113 			(void) printf(
1114 			gettext("Suppressing absolute pathnames\n"));
1115 		if (cflag && compress_opt != NULL) {
1116 			pid = compress_file();
1117 			wait_pid(pid);
1118 		}
1119 		dorep(argv);
1120 		if (rflag && !cflag && (compress_opt != NULL))
1121 			compress_back();
1122 	} else if (xflag || tflag) {
1123 		/*
1124 		 * for each argument, check to see if there is a "-I file" pair.
1125 		 * if so, move the 3rd argument into "-I"'s place, build_table()
1126 		 * using "file"'s name and increment argc one (the second
1127 		 * increment appears in the for loop) which removes the two
1128 		 * args "-I" and "file" from the argument vector.
1129 		 */
1130 		for (argc = 0; argv[argc]; argc++) {
1131 			if (strcmp(argv[argc], "-I") == 0) {
1132 				if (!argv[argc+1]) {
1133 					(void) fprintf(stderr, gettext(
1134 					"tar: missing argument for -I flag\n"));
1135 					done(2);
1136 				} else {
1137 					Iflag = 1;
1138 					argv[argc] = argv[argc+2];
1139 					build_table(include_tbl, argv[++argc]);
1140 				}
1141 			}
1142 		}
1143 		if (strcmp(usefile, "-") == 0) {
1144 			mt = dup(0);
1145 			++bflag;
1146 			/* try to recover from short reads when reading stdin */
1147 			++Bflag;
1148 		} else if ((mt = open(usefile, 0)) < 0)
1149 			vperror(1, "%s", usefile);
1150 
1151 		/* Decompress if the file is compressed */
1152 
1153 		if (strcmp(usefile, "-") != 0) {
1154 			check_compression();
1155 			if (compress_opt != NULL) {
1156 				pid = uncompress_file();
1157 				wait_pid(pid);
1158 			}
1159 		}
1160 		if (xflag) {
1161 			if (Aflag && vflag)
1162 				(void) printf(gettext(
1163 				    "Suppressing absolute pathnames.\n"));
1164 
1165 			doxtract(argv);
1166 		} else if (tflag)
1167 			dotable(argv);
1168 	}
1169 	else
1170 		usage();
1171 
1172 	done(Errflg);
1173 
1174 	/* Not reached:  keep compiler quiet */
1175 	return (1);
1176 }
1177 
1178 static void
1179 usage(void)
1180 {
1181 	(void) fprintf(stderr, gettext(
1182 #if defined(O_XATTR)
1183 #if defined(_PC_SATTR_ENABLED)
1184 	    "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
1185 #else
1186 	    "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
1187 #endif	/* _PC_SATTR_ENABLED */
1188 #else
1189 	    "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
1190 #endif	/* O_XATTR */
1191 	    "[j|J|z|Z] "
1192 	    "[blocksize] [tarfile] [size] [exclude-file...] "
1193 	    "{file | -I include-file | -C directory file}...\n"));
1194 	done(1);
1195 }
1196 
1197 /*
1198  * dorep - do "replacements"
1199  *
1200  *	Dorep is responsible for creating ('c'),  appending ('r')
1201  *	and updating ('u');
1202  */
1203 
1204 static void
1205 dorep(char *argv[])
1206 {
1207 	char *cp, *cp2, *p;
1208 	char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1209 	char file[PATH_MAX*2], origdir[PATH_MAX+1];
1210 	FILE *fp = (FILE *)NULL;
1211 	int archtype;
1212 	int ret;
1213 
1214 
1215 	if (!cflag) {
1216 		xhdr_flgs = 0;
1217 		getdir();			/* read header for next file */
1218 		if (Xhdrflag > 0) {
1219 			if (!Eflag)
1220 				fatal(gettext("Archive contains extended"
1221 				    " header.  -E flag required.\n"));
1222 			ret = get_xdata();	/* Get extended header items */
1223 						/*   and regular header */
1224 		} else {
1225 			if (Eflag)
1226 				fatal(gettext("Archive contains no extended"
1227 				    " header.  -E flag not allowed.\n"));
1228 		}
1229 		while (!endtape()) {		/* changed from a do while */
1230 			setbytes_to_skip(&stbuf, ret);
1231 			passtape();		/* skip the file data */
1232 			if (term)
1233 				done(Errflg);	/* received signal to stop */
1234 			xhdr_flgs = 0;
1235 			getdir();
1236 			if (Xhdrflag > 0)
1237 				ret = get_xdata();
1238 		}
1239 		if (ret == 0) {
1240 			if ((dblock.dbuf.typeflag != 'A') &&
1241 			    (xhdr_flgs != 0)) {
1242 				load_info_from_xtarhdr(xhdr_flgs,
1243 				    &Xtarhdr);
1244 				xhdr_flgs |= _X_XHDR;
1245 			}
1246 		}
1247 		backtape();			/* was called by endtape */
1248 		if (tfile != NULL) {
1249 			/*
1250 			 * Buffer size is calculated to be the size of the
1251 			 * tmpdir string, plus 6 times the size of the tname
1252 			 * string, plus a value that is known to be greater
1253 			 * than the command pipeline string.
1254 			 */
1255 			int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1256 			char *buf;
1257 
1258 			if ((buf = (char *)calloc(1, buflen)) == NULL) {
1259 				vperror(1, gettext("tar: out of memory, "
1260 				    "cannot create sort command file\n"));
1261 			}
1262 
1263 			(void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1264 			    "sort +0 -1 +1nr %s -o %s; awk '$1 "
1265 			    "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1266 			    tmpdir, tname, tname, tname, tname, tname, tname);
1267 			(void) fflush(tfile);
1268 			(void) system(buf);
1269 			free(buf);
1270 			(void) freopen(tname, "r", tfile);
1271 			(void) fstat(fileno(tfile), &stbuf);
1272 			high = stbuf.st_size;
1273 		}
1274 	}
1275 
1276 	dumping = 1;
1277 	if (mulvol) {	/* SP-1 */
1278 		if (nblock && (blocklim%nblock) != 0)
1279 			fatal(gettext(
1280 			"Volume size not a multiple of block size."));
1281 		blocklim -= 2;			/* for trailer records */
1282 		if (vflag)
1283 			(void) fprintf(vfile, gettext("Volume ends at %"
1284 			    FMT_blkcnt_t "K, blocking factor = %dK\n"),
1285 			    K((blocklim - 1)), K(nblock));
1286 	}
1287 
1288 	/*
1289 	 * Save the original directory before it gets
1290 	 * changed.
1291 	 */
1292 	if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1293 		vperror(0, gettext("A parent directory cannot be read"));
1294 		exit(1);
1295 	}
1296 
1297 	(void) strcpy(wdir, origdir);
1298 
1299 	while ((*argv || fp) && !term) {
1300 		if (fp || (strcmp(*argv, "-I") == 0)) {
1301 			if (fp == NULL) {
1302 				if (*++argv == NULL)
1303 					fatal(gettext(
1304 					    "missing file name for -I flag."));
1305 				else if ((fp = fopen(*argv++, "r")) == NULL)
1306 					vperror(0, "%s", argv[-1]);
1307 				continue;
1308 			} else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1309 				(void) fclose(fp);
1310 				fp = NULL;
1311 				continue;
1312 			} else {
1313 				cp = cp2 = file;
1314 				if ((p = strchr(cp2, '\n')))
1315 					*p = 0;
1316 			}
1317 		} else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1318 			if (tar_chdir(*++argv) < 0)
1319 				vperror(0, gettext(
1320 				    "can't change directories to %s"), *argv);
1321 			else
1322 				(void) getcwd(wdir, (sizeof (wdir)));
1323 			argv++;
1324 			continue;
1325 		} else
1326 			cp = cp2 = strcpy(file, *argv++);
1327 
1328 		/*
1329 		 * point cp2 to the last '/' in file, but not
1330 		 * to a trailing '/'
1331 		 */
1332 		for (; *cp; cp++) {
1333 			if (*cp == '/') {
1334 				while (*(cp+1) == '/') {
1335 					++cp;
1336 				}
1337 				if (*(cp+1) != '\0') {
1338 					/* not trailing slash */
1339 					cp2 = cp;
1340 				}
1341 			}
1342 		}
1343 		if (cp2 != file) {
1344 			*cp2 = '\0';
1345 			if (tar_chdir(file) < 0) {
1346 				vperror(0, gettext(
1347 				    "can't change directories to %s"), file);
1348 				continue;
1349 			}
1350 			*cp2 = '/';
1351 			cp2++;
1352 		}
1353 
1354 		parent = getcwd(tempdir, (sizeof (tempdir)));
1355 
1356 		archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1357 		    LEV0, SYMLINK_LEV0);
1358 
1359 #if defined(O_XATTR)
1360 		if (!exitflag) {
1361 			if ((atflag || saflag) &&
1362 			    (archtype == PUT_NOTAS_LINK)) {
1363 				xattrs_put(file, cp2, parent, NULL);
1364 			}
1365 		}
1366 #endif
1367 
1368 		if (tar_chdir(origdir) < 0)
1369 			vperror(0, gettext("cannot change back?: %s"), origdir);
1370 
1371 		if (exitflag) {
1372 			/*
1373 			 * If e function modifier has been specified
1374 			 * write the files (that are listed before the
1375 			 * file causing the error) to tape.  exitflag is
1376 			 * used because only some of the error conditions
1377 			 * in putfile() recognize the e function modifier.
1378 			 */
1379 			break;
1380 		}
1381 	}
1382 
1383 	putempty((blkcnt_t)2);
1384 	flushtape();
1385 	closevol();	/* SP-1 */
1386 	if (linkerrok == 1)
1387 		for (; ihead != NULL; ihead = ihead->nextp) {
1388 			if (ihead->count == 0)
1389 				continue;
1390 			(void) fprintf(stderr, gettext(
1391 			"tar: missing links to %s\n"), ihead->pathname);
1392 			if (errflag)
1393 				done(1);
1394 			else
1395 				Errflg = 1;
1396 		}
1397 }
1398 
1399 
1400 /*
1401  * endtape - check for tape at end
1402  *
1403  *	endtape checks the entry in dblock.dbuf to see if its the
1404  *	special EOT entry.  Endtape is usually called after getdir().
1405  *
1406  *	endtape used to call backtape; it no longer does, he who
1407  *	wants it backed up must call backtape himself
1408  *	RETURNS:	0 if not EOT, tape position unaffected
1409  *			1 if	 EOT, tape position unaffected
1410  */
1411 
1412 static int
1413 endtape(void)
1414 {
1415 	if (dblock.dbuf.name[0] == '\0') {	/* null header = EOT */
1416 		return (1);
1417 	} else
1418 		return (0);
1419 }
1420 
1421 /*
1422  *	getdir - get directory entry from tar tape
1423  *
1424  *	getdir reads the next tarblock off the tape and cracks
1425  *	it as a directory. The checksum must match properly.
1426  *
1427  *	If tfile is non-null getdir writes the file name and mod date
1428  *	to tfile.
1429  */
1430 
1431 static void
1432 getdir(void)
1433 {
1434 	struct stat *sp;
1435 #ifdef EUC
1436 	static int warn_chksum_sign = 0;
1437 #endif /* EUC */
1438 
1439 top:
1440 	readtape((char *)&dblock);
1441 	if (dblock.dbuf.name[0] == '\0')
1442 		return;
1443 	sp = &stbuf;
1444 	(void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1445 	(void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1446 	(void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1447 	(void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1448 	(void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1449 	(void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1450 	(void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1451 	(void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1452 
1453 	is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1454 
1455 	sp->st_mode = Gen.g_mode;
1456 	if (is_posix && (sp->st_mode & S_IFMT) == 0)
1457 		switch (dblock.dbuf.typeflag) {
1458 		case '0': case 0: case _XATTR_HDRTYPE:
1459 			sp->st_mode |= S_IFREG;
1460 			break;
1461 		case '1':	/* hard link */
1462 			break;
1463 		case '2':
1464 			sp->st_mode |= S_IFLNK;
1465 			break;
1466 		case '3':
1467 			sp->st_mode |= S_IFCHR;
1468 			break;
1469 		case '4':
1470 			sp->st_mode |= S_IFBLK;
1471 			break;
1472 		case '5':
1473 			sp->st_mode |= S_IFDIR;
1474 			break;
1475 		case '6':
1476 			sp->st_mode |= S_IFIFO;
1477 			break;
1478 		default:
1479 			if (convtoreg(Gen.g_filesz))
1480 				sp->st_mode |= S_IFREG;
1481 			break;
1482 		}
1483 
1484 	if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1485 		Xhdrflag = 1;	/* Currently processing extended header */
1486 	} else {
1487 		Xhdrflag = 0;
1488 	}
1489 
1490 	sp->st_uid = Gen.g_uid;
1491 	sp->st_gid = Gen.g_gid;
1492 	sp->st_size = Gen.g_filesz;
1493 	sp->st_mtime = Gen.g_mtime;
1494 	chksum = Gen.g_cksum;
1495 
1496 	if (dblock.dbuf.extno != '\0') {	/* split file? */
1497 		extno = dblock.dbuf.extno;
1498 		extsize = Gen.g_filesz;
1499 		extotal = dblock.dbuf.extotal;
1500 	} else {
1501 		extno = 0;	/* tell others file not split */
1502 		extsize = 0;
1503 		extotal = 0;
1504 	}
1505 
1506 #ifdef	EUC
1507 	if (chksum != checksum(&dblock)) {
1508 		if (chksum != checksum_signed(&dblock)) {
1509 			(void) fprintf(stderr, gettext(
1510 			    "tar: directory checksum error\n"));
1511 			if (iflag) {
1512 				Errflg = 2;
1513 				goto top;
1514 			}
1515 			done(2);
1516 		} else {
1517 			if (! warn_chksum_sign) {
1518 				warn_chksum_sign = 1;
1519 				(void) fprintf(stderr, gettext(
1520 			"tar: warning: tar file made with signed checksum\n"));
1521 			}
1522 		}
1523 	}
1524 #else
1525 	if (chksum != checksum(&dblock)) {
1526 		(void) fprintf(stderr, gettext(
1527 		"tar: directory checksum error\n"));
1528 		if (iflag) {
1529 			Errflg = 2;
1530 			goto top;
1531 		}
1532 		done(2);
1533 	}
1534 #endif	/* EUC */
1535 	if (tfile != NULL && Xhdrflag == 0) {
1536 		/*
1537 		 * If an extended header is present, then time is available
1538 		 * in nanoseconds in the extended header data, so set it.
1539 		 * Otherwise, give an invalid value so that checkupdate will
1540 		 * not test beyond seconds.
1541 		 */
1542 		if ((xhdr_flgs & _X_MTIME))
1543 			sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1544 		else
1545 			sp->st_mtim.tv_nsec = -1;
1546 
1547 		if (xhdr_flgs & _X_PATH)
1548 			(void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1549 			    Xtarhdr.x_path, sp->st_mtim.tv_sec,
1550 			    sp->st_mtim.tv_nsec);
1551 		else
1552 			(void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1553 			    NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1554 			    sp->st_mtim.tv_nsec);
1555 	}
1556 
1557 #if defined(O_XATTR)
1558 	Hiddendir = 0;
1559 	if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1560 		if (xattrbadhead) {
1561 			free(xattrhead);
1562 			xattrp = NULL;
1563 			xattr_linkp = NULL;
1564 			xattrhead = NULL;
1565 		} else {
1566 			char	*aname = basename(xattrapath);
1567 			size_t	xindex  = aname - xattrapath;
1568 
1569 			if (xattrapath[xindex] == '.' &&
1570 			    xattrapath[xindex + 1] == '\0' &&
1571 			    xattrp->h_typeflag == '5') {
1572 				Hiddendir = 1;
1573 				sp->st_mode =
1574 				    (S_IFDIR | (sp->st_mode & POSIXMODES));
1575 			}
1576 			dblock.dbuf.typeflag = xattrp->h_typeflag;
1577 		}
1578 	}
1579 #endif
1580 }
1581 
1582 
1583 /*
1584  *	passtape - skip over a file on the tape
1585  *
1586  *	passtape skips over the next data file on the tape.
1587  *	The tape directory entry must be in dblock.dbuf. This
1588  *	routine just eats the number of blocks computed from the
1589  *	directory size entry; the tape must be (logically) positioned
1590  *	right after thee directory info.
1591  */
1592 
1593 static void
1594 passtape(void)
1595 {
1596 	blkcnt_t blocks;
1597 	char buf[TBLOCK];
1598 
1599 	/*
1600 	 * Types link(1), sym-link(2), char special(3), blk special(4),
1601 	 *  directory(5), and FIFO(6) do not have data blocks associated
1602 	 *  with them so just skip reading the data block.
1603 	 */
1604 	if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1605 	    dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1606 	    dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1607 		return;
1608 	blocks = TBLOCKS(stbuf.st_size);
1609 
1610 	/* if operating on disk, seek instead of reading */
1611 	if (NotTape)
1612 		seekdisk(blocks);
1613 	else
1614 		while (blocks-- > 0)
1615 			readtape(buf);
1616 }
1617 
1618 #if defined(O_XATTR)
1619 static int
1620 is_sysattr(char *name)
1621 {
1622 	return ((strcmp(name, VIEW_READONLY) == 0) ||
1623 	    (strcmp(name, VIEW_READWRITE) == 0));
1624 }
1625 #endif
1626 
1627 #if defined(O_XATTR)
1628 /*
1629  * Verify the attribute, attrname, is an attribute we want to restore.
1630  * Never restore read-only system attribute files.  Only restore read-write
1631  * system attributes files when -/ was specified, and only traverse into
1632  * the 2nd level attribute directory containing only system attributes if
1633  * -@ was specified.  This keeps us from archiving
1634  *	<attribute name>/<read-write system attribute file>
1635  * when -/ was specified without -@.
1636  *
1637  * attrname	- attribute file name
1638  * attrparent	- attribute's parent name within the base file's attribute
1639  *		directory hierarchy
1640  */
1641 static attr_status_t
1642 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1643     int *rw_sysattr)
1644 {
1645 #if defined(_PC_SATTR_ENABLED)
1646 	int	attr_supported;
1647 
1648 	/* Never restore read-only system attribute files */
1649 	if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1650 		*rw_sysattr = 0;
1651 		return (ATTR_SKIP);
1652 	} else {
1653 		*rw_sysattr = (attr_supported == _RW_SATTR);
1654 	}
1655 #else
1656 	/*
1657 	 * Only need to check if this attribute is an extended system
1658 	 * attribute.
1659 	 */
1660 	if (*rw_sysattr = is_sysattr(attrname)) {
1661 		return (ATTR_SKIP);
1662 	} else {
1663 		return (ATTR_OK);
1664 	}
1665 #endif	/* _PC_SATTR_ENABLED */
1666 
1667 	/*
1668 	 * If the extended system attribute file is specified with the
1669 	 * arc_rwsysattr flag, as being transient (default extended
1670 	 * attributes), then don't archive it.
1671 	 */
1672 	if (*rw_sysattr && !arc_rwsysattr) {
1673 		return (ATTR_SKIP);
1674 	}
1675 
1676 	/*
1677 	 * Only restore read-write system attribute files
1678 	 * when -/ was specified.  Only restore extended
1679 	 * attributes when -@ was specified.
1680 	 */
1681 	if (atflag) {
1682 		if (!saflag) {
1683 			/*
1684 			 * Only archive/restore the hidden directory "." if
1685 			 * we're processing the top level hidden attribute
1686 			 * directory.  We don't want to process the
1687 			 * hidden attribute directory of the attribute
1688 			 * directory that contains only extended system
1689 			 * attributes.
1690 			 */
1691 			if (*rw_sysattr || (Hiddendir &&
1692 			    (attrparent != NULL))) {
1693 				return (ATTR_SKIP);
1694 			}
1695 		}
1696 	} else if (saflag) {
1697 		/*
1698 		 * Only archive/restore read-write extended system attribute
1699 		 * files of the base file.
1700 		 */
1701 		if (!*rw_sysattr || (attrparent != NULL)) {
1702 			return (ATTR_SKIP);
1703 		}
1704 	} else {
1705 		return (ATTR_SKIP);
1706 	}
1707 
1708 	return (ATTR_OK);
1709 }
1710 #endif
1711 
1712 static void
1713 free_children(file_list_t *children)
1714 {
1715 	file_list_t	*child = children;
1716 	file_list_t	*cptr;
1717 
1718 	while (child != NULL) {
1719 		cptr = child->next;
1720 		if (child->name != NULL) {
1721 			free(child->name);
1722 		}
1723 		child = cptr;
1724 	}
1725 }
1726 
1727 static int
1728 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1729     int filetype, int lev, int symlink_lev)
1730 {
1731 	int infile = -1;	/* deliberately invalid */
1732 	blkcnt_t blocks;
1733 	char buf[PATH_MAX + 2];	/* Add trailing slash and null */
1734 	char *bigbuf;
1735 	int	maxread;
1736 	int	hint;		/* amount to write to get "in sync" */
1737 	char filetmp[PATH_MAX + 1];
1738 	char *cp;
1739 	char *name;
1740 	char *attrparent = NULL;
1741 	char *longattrname = NULL;
1742 	file_list_t	*child = NULL;
1743 	file_list_t	*child_end = NULL;
1744 	file_list_t	*cptr;
1745 	struct dirent *dp;
1746 	DIR *dirp;
1747 	int i;
1748 	int split;
1749 	int dirfd = -1;
1750 	int rc = PUT_NOTAS_LINK;
1751 	int archtype = 0;
1752 	int rw_sysattr = 0;
1753 	char newparent[PATH_MAX + MAXNAMLEN + 1];
1754 	char *prefix = "";
1755 	char *tmpbuf;
1756 	char goodbuf[PRESIZ + 2];
1757 	char junkbuf[MAXNAM+1];
1758 	char *lastslash;
1759 	int j;
1760 	struct stat sbuf;
1761 	int readlink_max;
1762 
1763 	(void) memset(goodbuf, '\0', sizeof (goodbuf));
1764 	(void) memset(junkbuf, '\0', sizeof (junkbuf));
1765 
1766 	xhdr_flgs = 0;
1767 
1768 	if (filetype == XATTR_FILE) {
1769 		attrparent = attrinfo->attr_parent;
1770 		longattrname = attrinfo->attr_path;
1771 		dirfd = attrinfo->attr_parentfd;
1772 		rw_sysattr = attrinfo->attr_rw_sysattr;
1773 	} else {
1774 		dirfd = open(".", O_RDONLY);
1775 	}
1776 
1777 	if (dirfd == -1) {
1778 		(void) fprintf(stderr, gettext(
1779 		    "tar: unable to open%sdirectory %s%s%s%s\n"),
1780 		    (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1781 		    (attrparent == NULL) ? "" : gettext("of attribute "),
1782 		    (attrparent == NULL) ? "" : attrparent,
1783 		    (attrparent == NULL) ? "" : gettext(" of "),
1784 		    (filetype == XATTR_FILE) ? longname : parent);
1785 		goto out;
1786 	}
1787 
1788 	if (lev > MAXLEV) {
1789 		(void) fprintf(stderr,
1790 		    gettext("tar: directory nesting too deep, %s not dumped\n"),
1791 		    longname);
1792 		goto out;
1793 	}
1794 
1795 	if (getstat(dirfd, longname, shortname, attrparent))
1796 		goto out;
1797 
1798 	if (hflag) {
1799 		/*
1800 		 * Catch nesting where a file is a symlink to its directory.
1801 		 */
1802 		j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1803 		if (S_ISLNK(sbuf.st_mode)) {
1804 			if (symlink_lev++ >= MAXSYMLINKS) {
1805 				(void) fprintf(stderr, gettext(
1806 				    "tar: %s: Number of symbolic links "
1807 				    "encountered during path name traversal "
1808 				    "exceeds MAXSYMLINKS\n"), longname);
1809 				Errflg = 1;
1810 				goto out;
1811 			}
1812 		}
1813 	}
1814 
1815 	/*
1816 	 * Check if the input file is the same as the tar file we
1817 	 * are creating
1818 	 */
1819 	if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1820 		(void) fprintf(stderr, gettext(
1821 		    "tar: %s%s%s%s%s same as archive file\n"),
1822 		    rw_sysattr ? gettext("system ") : "",
1823 		    (longattrname == NULL) ? "" : gettext("attribute "),
1824 		    (longattrname == NULL) ? "" : longattrname,
1825 		    (longattrname == NULL) ? "" : gettext(" of "),
1826 		    longname);
1827 		Errflg = 1;
1828 		goto out;
1829 	}
1830 	/*
1831 	 * Check size limit - we can't archive files that
1832 	 * exceed TAR_OFFSET_MAX bytes because of header
1833 	 * limitations. Exclude file types that set
1834 	 * st_size to zero below because they take no
1835 	 * archive space to represent contents.
1836 	 */
1837 	if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1838 	    !S_ISDIR(stbuf.st_mode) &&
1839 	    !S_ISCHR(stbuf.st_mode) &&
1840 	    !S_ISBLK(stbuf.st_mode) &&
1841 	    (Eflag == 0)) {
1842 		(void) fprintf(stderr, gettext(
1843 		    "tar: %s%s%s%s%s too large to archive.  "
1844 		    "Use E function modifier.\n"),
1845 		    rw_sysattr ? gettext("system ") : "",
1846 		    (longattrname == NULL) ? "" : gettext("attribute "),
1847 		    (longattrname == NULL) ? "" : longattrname,
1848 		    (longattrname == NULL) ? "" : gettext(" of "),
1849 		    longname);
1850 		if (errflag)
1851 			exitflag = 1;
1852 		Errflg = 1;
1853 		goto out;
1854 	}
1855 
1856 	if (tfile != NULL && checkupdate(longname) == 0) {
1857 		goto out;
1858 	}
1859 	if (checkw('r', longname) == 0) {
1860 		goto out;
1861 	}
1862 
1863 	if (Fflag &&
1864 	    checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1865 		goto out;
1866 
1867 	if (Xflag) {
1868 		if (is_in_table(exclude_tbl, longname)) {
1869 			if (vflag) {
1870 				(void) fprintf(vfile, gettext(
1871 				    "a %s excluded\n"), longname);
1872 			}
1873 			goto out;
1874 		}
1875 	}
1876 
1877 	/*
1878 	 * If the length of the fullname is greater than MAXNAM,
1879 	 * print out a message and return (unless extended headers are used,
1880 	 * in which case fullname is limited to PATH_MAX).
1881 	 */
1882 
1883 	if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1884 	    (split > PATH_MAX)) {
1885 		(void) fprintf(stderr, gettext(
1886 		    "tar: %s: file name too long\n"), longname);
1887 		if (errflag)
1888 			exitflag = 1;
1889 		Errflg = 1;
1890 		goto out;
1891 	}
1892 
1893 	/*
1894 	 * We split the fullname into prefix and name components if any one
1895 	 * of three conditions holds:
1896 	 *	-- the length of the fullname exceeds NAMSIZ,
1897 	 *	-- the length of the fullname equals NAMSIZ, and the shortname
1898 	 *	   is less than NAMSIZ, (splitting in this case preserves
1899 	 *	   compatibility with 5.6 and 5.5.1 tar), or
1900 	 * 	-- the length of the fullname equals NAMSIZ, the file is a
1901 	 *	   directory and we are not in POSIX-conformant mode (where
1902 	 *	   trailing slashes are removed from directories).
1903 	 */
1904 	if ((split > NAMSIZ) ||
1905 	    (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1906 	    (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1907 		/*
1908 		 * Since path is limited to PRESIZ characters, look for the
1909 		 * last slash within PRESIZ + 1 characters only.
1910 		 */
1911 		(void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
1912 		tmpbuf = goodbuf;
1913 		lastslash = strrchr(tmpbuf, '/');
1914 		if (lastslash == NULL) {
1915 			i = split;		/* Length of name */
1916 			j = 0;			/* Length of prefix */
1917 			goodbuf[0] = '\0';
1918 		} else {
1919 			*lastslash = '\0';	/* Terminate the prefix */
1920 			j = strlen(tmpbuf);
1921 			i = split - j - 1;
1922 		}
1923 		/*
1924 		 * If the filename is greater than NAMSIZ we can't
1925 		 * archive the file unless we are using extended headers.
1926 		 */
1927 		if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
1928 		    !Pflag)) {
1929 			/* Determine which (filename or path) is too long. */
1930 			lastslash = strrchr(longname, '/');
1931 			if (lastslash != NULL)
1932 				i = strlen(lastslash + 1);
1933 			if (Eflag > 0) {
1934 				xhdr_flgs |= _X_PATH;
1935 				Xtarhdr.x_path = longname;
1936 				if (i <= NAMSIZ)
1937 					(void) strcpy(junkbuf, lastslash + 1);
1938 				else
1939 					(void) sprintf(junkbuf, "%llu",
1940 					    xhdr_count + 1);
1941 				if (split - i - 1 > PRESIZ)
1942 					(void) strcpy(goodbuf, xhdr_dirname);
1943 			} else {
1944 				if ((i > NAMSIZ) || (i == NAMSIZ &&
1945 				    S_ISDIR(stbuf.st_mode) && !Pflag))
1946 					(void) fprintf(stderr, gettext(
1947 					    "tar: %s: filename is greater than "
1948 					    "%d\n"), lastslash == NULL ?
1949 					    longname : lastslash + 1, NAMSIZ);
1950 				else
1951 					(void) fprintf(stderr, gettext(
1952 					    "tar: %s: prefix is greater than %d"
1953 					    "\n"), longname, PRESIZ);
1954 				if (errflag)
1955 					exitflag = 1;
1956 				Errflg = 1;
1957 				goto out;
1958 			}
1959 		} else
1960 			(void) strncpy(&junkbuf[0], longname + j + 1,
1961 			    strlen(longname + j + 1));
1962 		name = junkbuf;
1963 		prefix = goodbuf;
1964 	} else {
1965 		name = longname;
1966 	}
1967 	if (Aflag) {
1968 		if ((prefix != NULL) && (*prefix != '\0'))
1969 			while (*prefix == '/')
1970 				++prefix;
1971 		else
1972 			while (*name == '/')
1973 				++name;
1974 	}
1975 
1976 	switch (stbuf.st_mode & S_IFMT) {
1977 	case S_IFDIR:
1978 		stbuf.st_size = (off_t)0;
1979 		blocks = TBLOCKS(stbuf.st_size);
1980 
1981 		if (filetype != XATTR_FILE && Hiddendir == 0) {
1982 			i = 0;
1983 			cp = buf;
1984 			while ((*cp++ = longname[i++]))
1985 				;
1986 			*--cp = '/';
1987 			*++cp = 0;
1988 		}
1989 		if (!oflag) {
1990 			tomodes(&stbuf);
1991 			if (build_dblock(name, tchar, '5', filetype,
1992 			    &stbuf, stbuf.st_dev, prefix) != 0) {
1993 				goto out;
1994 			}
1995 			if (!Pflag) {
1996 				/*
1997 				 * Old archives require a slash at the end
1998 				 * of a directory name.
1999 				 *
2000 				 * XXX
2001 				 * If directory name is too long, will
2002 				 * slash overfill field?
2003 				 */
2004 				if (strlen(name) > (unsigned)NAMSIZ-1) {
2005 					(void) fprintf(stderr, gettext(
2006 					    "tar: %s: filename is greater "
2007 					    "than %d\n"), name, NAMSIZ);
2008 					if (errflag)
2009 						exitflag = 1;
2010 					Errflg = 1;
2011 					goto out;
2012 				} else {
2013 					if (strlen(name) == (NAMSIZ - 1)) {
2014 						(void) memcpy(dblock.dbuf.name,
2015 						    name, NAMSIZ);
2016 						dblock.dbuf.name[NAMSIZ-1]
2017 						    = '/';
2018 					} else
2019 						(void) sprintf(dblock.dbuf.name,
2020 						    "%s/", name);
2021 
2022 					/*
2023 					 * need to recalculate checksum
2024 					 * because the name changed.
2025 					 */
2026 					(void) sprintf(dblock.dbuf.chksum,
2027 					    "%07o", checksum(&dblock));
2028 				}
2029 			}
2030 
2031 			if (put_extra_attributes(longname, shortname,
2032 			    longattrname, prefix, filetype, '5') != 0)
2033 				goto out;
2034 
2035 #if defined(O_XATTR)
2036 			/*
2037 			 * Reset header typeflag when archiving directory, since
2038 			 * build_dblock changed it on us.
2039 			 */
2040 			if (filetype == XATTR_FILE) {
2041 				dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2042 			} else {
2043 				dblock.dbuf.typeflag = '5';
2044 			}
2045 #else
2046 			dblock.dbuf.typeflag = '5';
2047 #endif
2048 
2049 			(void) sprintf(dblock.dbuf.chksum, "%07o",
2050 			    checksum(&dblock));
2051 
2052 			(void) writetbuf((char *)&dblock, 1);
2053 		}
2054 		if (vflag) {
2055 #ifdef DEBUG
2056 			if (NotTape)
2057 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2058 				    0);
2059 #endif
2060 			if (filetype == XATTR_FILE && Hiddendir) {
2061 				(void) fprintf(vfile,
2062 				    gettext("a %s attribute %s "),
2063 				    longname, longattrname);
2064 
2065 			} else {
2066 				(void) fprintf(vfile, "a %s/ ", longname);
2067 			}
2068 			if (NotTape)
2069 				(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2070 				    K(blocks));
2071 			else
2072 				(void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2073 				    " tape blocks\n"), blocks);
2074 		}
2075 
2076 		/*
2077 		 * If hidden dir then break now since xattrs_put() will do
2078 		 * the iterating of the directory.
2079 		 *
2080 		 * At the moment, there can only be system attributes on
2081 		 * attributes.  There can be no attributes on attributes or
2082 		 * directories within the attributes hidden directory hierarchy.
2083 		 */
2084 		if (filetype == XATTR_FILE)
2085 			break;
2086 
2087 		if (*shortname != '/')
2088 			(void) sprintf(newparent, "%s/%s", parent, shortname);
2089 		else
2090 			(void) sprintf(newparent, "%s", shortname);
2091 
2092 		if (tar_chdir(shortname) < 0) {
2093 			vperror(0, "%s", newparent);
2094 			goto out;
2095 		}
2096 
2097 		if ((dirp = opendir(".")) == NULL) {
2098 			vperror(0, gettext(
2099 			    "can't open directory %s"), longname);
2100 			if (tar_chdir(parent) < 0)
2101 				vperror(0, gettext("cannot change back?: %s"),
2102 				    parent);
2103 			goto out;
2104 		}
2105 
2106 		/*
2107 		 * Create a list of files (children) in this directory to avoid
2108 		 * having to perform telldir()/seekdir().
2109 		 */
2110 		while ((dp = readdir(dirp)) != NULL && !term) {
2111 			if ((strcmp(".", dp->d_name) == 0) ||
2112 			    (strcmp("..", dp->d_name) == 0))
2113 				continue;
2114 			if (((cptr = (file_list_t *)calloc(sizeof (char),
2115 			    sizeof (file_list_t))) == NULL) ||
2116 			    ((cptr->name = strdup(dp->d_name)) == NULL)) {
2117 				vperror(1, gettext(
2118 				    "Insufficient memory for directory "
2119 				    "list entry %s/%s\n"),
2120 				    newparent, dp->d_name);
2121 			}
2122 
2123 			/* Add the file to the list */
2124 			if (child == NULL) {
2125 				child = cptr;
2126 			} else {
2127 				child_end->next = cptr;
2128 			}
2129 			child_end = cptr;
2130 		}
2131 		(void) closedir(dirp);
2132 
2133 		/*
2134 		 * Archive each of the files in the current directory.
2135 		 * If a file is a directory, putfile() is called
2136 		 * recursively to archive the file hierarchy of the
2137 		 * directory before archiving the next file in the
2138 		 * current directory.
2139 		 */
2140 		while ((child != NULL) && !term) {
2141 			(void) strcpy(cp, child->name);
2142 			archtype = putfile(buf, cp, newparent, NULL,
2143 			    NORMAL_FILE, lev + 1, symlink_lev);
2144 
2145 			if (!exitflag) {
2146 				if ((atflag || saflag) &&
2147 				    (archtype == PUT_NOTAS_LINK)) {
2148 					xattrs_put(buf, cp, newparent, NULL);
2149 				}
2150 			}
2151 			if (exitflag)
2152 				break;
2153 
2154 			/* Free each child as we are done processing it. */
2155 			cptr = child;
2156 			child = child->next;
2157 			free(cptr->name);
2158 			free(cptr);
2159 		}
2160 		if ((child != NULL) && !term) {
2161 			free_children(child);
2162 		}
2163 
2164 		if (tar_chdir(parent) < 0) {
2165 			vperror(0, gettext("cannot change back?: %s"), parent);
2166 		}
2167 
2168 		break;
2169 
2170 	case S_IFLNK:
2171 		readlink_max = NAMSIZ;
2172 		if (stbuf.st_size > NAMSIZ) {
2173 			if (Eflag > 0) {
2174 				xhdr_flgs |= _X_LINKPATH;
2175 				readlink_max = PATH_MAX;
2176 			} else {
2177 				(void) fprintf(stderr, gettext(
2178 				    "tar: %s: symbolic link too long\n"),
2179 				    longname);
2180 				if (errflag)
2181 					exitflag = 1;
2182 				Errflg = 1;
2183 				goto out;
2184 			}
2185 		}
2186 		/*
2187 		 * Sym-links need header size of zero since you
2188 		 * don't store any data for this type.
2189 		 */
2190 		stbuf.st_size = (off_t)0;
2191 		tomodes(&stbuf);
2192 		i = readlink(shortname, filetmp, readlink_max);
2193 		if (i < 0) {
2194 			vperror(0, gettext(
2195 			    "can't read symbolic link %s"), longname);
2196 			goto out;
2197 		} else {
2198 			filetmp[i] = 0;
2199 		}
2200 		if (vflag)
2201 			(void) fprintf(vfile, gettext(
2202 			    "a %s symbolic link to %s\n"),
2203 			    longname, filetmp);
2204 		if (xhdr_flgs & _X_LINKPATH) {
2205 			Xtarhdr.x_linkpath = filetmp;
2206 			if (build_dblock(name, tchar, '2', filetype, &stbuf,
2207 			    stbuf.st_dev, prefix) != 0)
2208 				goto out;
2209 		} else
2210 			if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2211 			    stbuf.st_dev, prefix) != 0)
2212 				goto out;
2213 		(void) writetbuf((char *)&dblock, 1);
2214 		/*
2215 		 * No acls for symlinks: mode is always 777
2216 		 * dont call write ancillary
2217 		 */
2218 		rc = PUT_AS_LINK;
2219 		break;
2220 	case S_IFREG:
2221 		if ((infile = openat(dirfd, shortname, 0)) < 0) {
2222 			vperror(0, gettext("unable to open %s%s%s%s"), longname,
2223 			    rw_sysattr ? gettext(" system") : "",
2224 			    (filetype == XATTR_FILE) ?
2225 			    gettext(" attribute ") : "",
2226 			    (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2227 			    shortname : longattrname : "");
2228 			goto out;
2229 		}
2230 
2231 		blocks = TBLOCKS(stbuf.st_size);
2232 
2233 		if (put_link(name, longname, shortname, longattrname,
2234 		    prefix, filetype, '1') == 0) {
2235 			(void) close(infile);
2236 			rc = PUT_AS_LINK;
2237 			goto out;
2238 		}
2239 
2240 		tomodes(&stbuf);
2241 
2242 		/* correctly handle end of volume */
2243 		while (mulvol && tapepos + blocks + 1 > blocklim) {
2244 			/* split if floppy has some room and file is large */
2245 			if (((blocklim - tapepos) >= EXTMIN) &&
2246 			    ((blocks + 1) >= blocklim/10)) {
2247 				splitfile(longname, infile,
2248 				    name, prefix, filetype);
2249 				(void) close(dirfd);
2250 				(void) close(infile);
2251 				goto out;
2252 			}
2253 			newvol();	/* not worth it--just get new volume */
2254 		}
2255 #ifdef DEBUG
2256 		DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2257 		    blocks);
2258 #endif
2259 		if (build_dblock(name, tchar, '0', filetype,
2260 		    &stbuf, stbuf.st_dev, prefix) != 0) {
2261 			goto out;
2262 		}
2263 		if (vflag) {
2264 #ifdef DEBUG
2265 			if (NotTape)
2266 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2267 				    0);
2268 #endif
2269 			(void) fprintf(vfile, "a %s%s%s%s ", longname,
2270 			    rw_sysattr ? gettext(" system") : "",
2271 			    (filetype == XATTR_FILE) ? gettext(
2272 			    " attribute ") : "",
2273 			    (filetype == XATTR_FILE) ?
2274 			    longattrname : "");
2275 			if (NotTape)
2276 				(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2277 				    K(blocks));
2278 			else
2279 				(void) fprintf(vfile,
2280 				    gettext("%" FMT_blkcnt_t " tape blocks\n"),
2281 				    blocks);
2282 		}
2283 
2284 		if (put_extra_attributes(longname, shortname, longattrname,
2285 		    prefix, filetype, '0') != 0)
2286 			goto out;
2287 
2288 		/*
2289 		 * No need to reset typeflag for extended attribute here, since
2290 		 * put_extra_attributes already set it and we haven't called
2291 		 * build_dblock().
2292 		 */
2293 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2294 		hint = writetbuf((char *)&dblock, 1);
2295 		maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2296 		    (nblock * TBLOCK));
2297 		if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2298 			maxread = TBLOCK;
2299 			bigbuf = buf;
2300 		}
2301 
2302 		while (((i = (int)
2303 		    read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2304 		    blocks) {
2305 			blkcnt_t nblks;
2306 
2307 			nblks = ((i-1)/TBLOCK)+1;
2308 			if (nblks > blocks)
2309 				nblks = blocks;
2310 			hint = writetbuf(bigbuf, nblks);
2311 			blocks -= nblks;
2312 		}
2313 		(void) close(infile);
2314 		if (bigbuf != buf)
2315 			free(bigbuf);
2316 		if (i < 0)
2317 			vperror(0, gettext("Read error on %s"), longname);
2318 		else if (blocks != 0 || i != 0) {
2319 			(void) fprintf(stderr, gettext(
2320 			"tar: %s: file changed size\n"), longname);
2321 			if (errflag) {
2322 				exitflag = 1;
2323 				Errflg = 1;
2324 			} else if (!Dflag) {
2325 				Errflg = 1;
2326 			}
2327 		}
2328 		putempty(blocks);
2329 		break;
2330 	case S_IFIFO:
2331 		blocks = TBLOCKS(stbuf.st_size);
2332 		stbuf.st_size = (off_t)0;
2333 
2334 		if (put_link(name, longname, shortname, longattrname,
2335 		    prefix, filetype, '6') == 0) {
2336 			rc = PUT_AS_LINK;
2337 			goto out;
2338 		}
2339 		tomodes(&stbuf);
2340 
2341 		while (mulvol && tapepos + blocks + 1 > blocklim) {
2342 			if (((blocklim - tapepos) >= EXTMIN) &&
2343 			    ((blocks + 1) >= blocklim/10)) {
2344 				splitfile(longname, infile, name,
2345 				    prefix, filetype);
2346 				(void) close(dirfd);
2347 				(void) close(infile);
2348 				goto out;
2349 			}
2350 			newvol();
2351 		}
2352 #ifdef DEBUG
2353 		DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2354 		    blocks);
2355 #endif
2356 		if (vflag) {
2357 #ifdef DEBUG
2358 			if (NotTape)
2359 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2360 				    0);
2361 #endif
2362 			if (NotTape)
2363 				(void) fprintf(vfile, gettext("a %s %"
2364 				    FMT_blkcnt_t "K\n "), longname, K(blocks));
2365 			else
2366 				(void) fprintf(vfile, gettext(
2367 				    "a %s %" FMT_blkcnt_t " tape blocks\n"),
2368 				    longname, blocks);
2369 		}
2370 		if (build_dblock(name, tchar, '6', filetype,
2371 		    &stbuf, stbuf.st_dev, prefix) != 0)
2372 			goto out;
2373 
2374 		if (put_extra_attributes(longname, shortname, longattrname,
2375 		    prefix, filetype, '6') != 0)
2376 			goto out;
2377 
2378 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2379 		dblock.dbuf.typeflag = '6';
2380 
2381 		(void) writetbuf((char *)&dblock, 1);
2382 		break;
2383 	case S_IFCHR:
2384 		stbuf.st_size = (off_t)0;
2385 		blocks = TBLOCKS(stbuf.st_size);
2386 		if (put_link(name, longname, shortname, longattrname,
2387 		    prefix, filetype, '3') == 0) {
2388 			rc = PUT_AS_LINK;
2389 			goto out;
2390 		}
2391 		tomodes(&stbuf);
2392 
2393 		while (mulvol && tapepos + blocks + 1 > blocklim) {
2394 			if (((blocklim - tapepos) >= EXTMIN) &&
2395 			    ((blocks + 1) >= blocklim/10)) {
2396 				splitfile(longname, infile, name,
2397 				    prefix, filetype);
2398 				(void) close(dirfd);
2399 				goto out;
2400 			}
2401 			newvol();
2402 		}
2403 #ifdef DEBUG
2404 		DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2405 		    blocks);
2406 #endif
2407 		if (vflag) {
2408 #ifdef DEBUG
2409 			if (NotTape)
2410 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2411 				    0);
2412 #endif
2413 			if (NotTape)
2414 				(void) fprintf(vfile, gettext("a %s %"
2415 				    FMT_blkcnt_t "K\n"), longname, K(blocks));
2416 			else
2417 				(void) fprintf(vfile, gettext("a %s %"
2418 				    FMT_blkcnt_t " tape blocks\n"), longname,
2419 				    blocks);
2420 		}
2421 		if (build_dblock(name, tchar, '3',
2422 		    filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2423 			goto out;
2424 
2425 		if (put_extra_attributes(longname, shortname, longattrname,
2426 		    prefix, filetype, '3') != 0)
2427 			goto out;
2428 
2429 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2430 		dblock.dbuf.typeflag = '3';
2431 
2432 		(void) writetbuf((char *)&dblock, 1);
2433 		break;
2434 	case S_IFBLK:
2435 		stbuf.st_size = (off_t)0;
2436 		blocks = TBLOCKS(stbuf.st_size);
2437 		if (put_link(name, longname, shortname, longattrname,
2438 		    prefix, filetype, '4') == 0) {
2439 			rc = PUT_AS_LINK;
2440 			goto out;
2441 		}
2442 		tomodes(&stbuf);
2443 
2444 		while (mulvol && tapepos + blocks + 1 > blocklim) {
2445 			if (((blocklim - tapepos) >= EXTMIN) &&
2446 			    ((blocks + 1) >= blocklim/10)) {
2447 				splitfile(longname, infile,
2448 				    name, prefix, filetype);
2449 				(void) close(dirfd);
2450 				goto out;
2451 			}
2452 			newvol();
2453 		}
2454 #ifdef DEBUG
2455 		DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2456 		    blocks);
2457 #endif
2458 		if (vflag) {
2459 #ifdef DEBUG
2460 			if (NotTape)
2461 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2462 				    0);
2463 #endif
2464 			(void) fprintf(vfile, "a %s ", longname);
2465 			if (NotTape)
2466 				(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2467 				    K(blocks));
2468 			else
2469 				(void) fprintf(vfile, gettext("%"
2470 				    FMT_blkcnt_t " tape blocks\n"), blocks);
2471 		}
2472 		if (build_dblock(name, tchar, '4',
2473 		    filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2474 			goto out;
2475 
2476 		if (put_extra_attributes(longname, shortname, longattrname,
2477 		    prefix, filetype, '4') != 0)
2478 			goto out;
2479 
2480 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2481 		dblock.dbuf.typeflag = '4';
2482 
2483 		(void) writetbuf((char *)&dblock, 1);
2484 		break;
2485 	default:
2486 		(void) fprintf(stderr, gettext(
2487 		    "tar: %s is not a file. Not dumped\n"), longname);
2488 		if (errflag)
2489 			exitflag = 1;
2490 		Errflg = 1;
2491 		goto out;
2492 	}
2493 
2494 out:
2495 	if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2496 		(void) close(dirfd);
2497 	}
2498 	return (rc);
2499 }
2500 
2501 
2502 /*
2503  *	splitfile	dump a large file across volumes
2504  *
2505  *	splitfile(longname, fd);
2506  *		char *longname;		full name of file
2507  *		int ifd;		input file descriptor
2508  *
2509  *	NOTE:  only called by putfile() to dump a large file.
2510  */
2511 
2512 static void
2513 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2514 {
2515 	blkcnt_t blocks;
2516 	off_t bytes, s;
2517 	char buf[TBLOCK];
2518 	int i, extents;
2519 
2520 	blocks = TBLOCKS(stbuf.st_size);	/* blocks file needs */
2521 
2522 	/*
2523 	 * # extents =
2524 	 *	size of file after using up rest of this floppy
2525 	 *		blocks - (blocklim - tapepos) + 1	(for header)
2526 	 *	plus roundup value before divide by blocklim-1
2527 	 *		+ (blocklim - 1) - 1
2528 	 *	all divided by blocklim-1 (one block for each header).
2529 	 * this gives
2530 	 *	(blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2531 	 * which reduces to the expression used.
2532 	 * one is added to account for this first extent.
2533 	 *
2534 	 * When one is dealing with extremely large archives, one may want
2535 	 * to allow for a large number of extents.  This code should be
2536 	 * revisited to determine if extents should be changed to something
2537 	 * larger than an int.
2538 	 */
2539 	extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2540 
2541 	if (extents < 2 || extents > MAXEXT) {	/* let's be reasonable */
2542 		(void) fprintf(stderr, gettext(
2543 		    "tar: %s needs unusual number of volumes to split\n"
2544 		    "tar: %s not dumped\n"), longname, longname);
2545 		return;
2546 	}
2547 	if (build_dblock(name, tchar, '0', filetype,
2548 	    &stbuf, stbuf.st_dev, prefix) != 0)
2549 		return;
2550 
2551 	dblock.dbuf.extotal = extents;
2552 	bytes = stbuf.st_size;
2553 
2554 	/*
2555 	 * The value contained in dblock.dbuf.efsize was formerly used when the
2556 	 * v flag was specified in conjunction with the t flag. Although it is
2557 	 * no longer used, older versions of tar will expect the former
2558 	 * behaviour, so we must continue to write it to the archive.
2559 	 *
2560 	 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2561 	 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2562 	 * store 0.
2563 	 */
2564 	if (bytes <= TAR_EFSIZE_MAX)
2565 		(void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2566 	else
2567 		(void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2568 
2569 	(void) fprintf(stderr, gettext(
2570 	    "tar: large file %s needs %d extents.\n"
2571 	    "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2572 	    longname, extents, K(tapepos));
2573 
2574 	s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2575 	for (i = 1; i <= extents; i++) {
2576 		if (i > 1) {
2577 			newvol();
2578 			if (i == extents)
2579 				s = bytes;	/* last ext. gets true bytes */
2580 			else
2581 				s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2582 		}
2583 		bytes -= s;
2584 		blocks = TBLOCKS(s);
2585 
2586 		(void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2587 		dblock.dbuf.extno = i;
2588 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2589 		(void) writetbuf((char *)&dblock, 1);
2590 
2591 		if (vflag)
2592 			(void) fprintf(vfile,
2593 			    gettext("+++ a %s %" FMT_blkcnt_t
2594 			    "K [extent #%d of %d]\n"),
2595 			    longname, K(blocks), i, extents);
2596 		while (blocks && read(ifd, buf, TBLOCK) > 0) {
2597 			blocks--;
2598 			(void) writetbuf(buf, 1);
2599 		}
2600 		if (blocks != 0) {
2601 			(void) fprintf(stderr, gettext(
2602 			    "tar: %s: file changed size\n"), longname);
2603 			(void) fprintf(stderr, gettext(
2604 			    "tar: aborting split file %s\n"), longname);
2605 			(void) close(ifd);
2606 			return;
2607 		}
2608 	}
2609 	(void) close(ifd);
2610 	if (vflag)
2611 		(void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2612 		    "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2613 		    extents);
2614 }
2615 
2616 /*
2617  *	convtoreg - determines whether the file should be converted to a
2618  *	            regular file when extracted
2619  *
2620  *	Returns 1 when file size > 0 and typeflag is not recognized
2621  * 	Otherwise returns 0
2622  */
2623 static int
2624 convtoreg(off_t size)
2625 {
2626 	if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2627 	    (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') &&
2628 	    (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2629 	    (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2630 	    (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2631 	    (dblock.dbuf.typeflag != 'L') &&
2632 	    (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2633 	    (dblock.dbuf.typeflag != 'X')) {
2634 		return (1);
2635 	}
2636 	return (0);
2637 }
2638 
2639 #if defined(O_XATTR)
2640 static int
2641 save_cwd(void)
2642 {
2643 	return (open(".", O_RDONLY));
2644 }
2645 #endif
2646 
2647 #if defined(O_XATTR)
2648 static void
2649 rest_cwd(int *cwd)
2650 {
2651 	if (*cwd != -1) {
2652 		if (fchdir(*cwd) < 0) {
2653 			vperror(0, gettext(
2654 			    "Cannot fchdir to attribute directory"));
2655 			exit(1);
2656 		}
2657 		(void) close(*cwd);
2658 		*cwd = -1;
2659 	}
2660 }
2661 #endif
2662 
2663 /*
2664  * Verify the underlying file system supports the attribute type.
2665  * Only archive extended attribute files when '-@' was specified.
2666  * Only archive system extended attribute files if '-/' was specified.
2667  */
2668 #if defined(O_XATTR)
2669 static attr_status_t
2670 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2671     int *ext_attrflg)
2672 {
2673 	/*
2674 	 * Verify extended attributes are supported/exist.  We only
2675 	 * need to check if we are processing a base file, not an
2676 	 * extended attribute.
2677 	 */
2678 	if (attrflg) {
2679 		*ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2680 		    _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2681 	}
2682 
2683 	if (atflag) {
2684 		if (!*ext_attrflg) {
2685 #if defined(_PC_SATTR_ENABLED)
2686 			if (saflag) {
2687 				/* Verify system attributes are supported */
2688 				if (sysattr_support(filename,
2689 				    (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2690 				    _PC_SATTR_ENABLED) != 1) {
2691 					return (ATTR_SATTR_ERR);
2692 				}
2693 			} else
2694 				return (ATTR_XATTR_ERR);
2695 #else
2696 				return (ATTR_XATTR_ERR);
2697 #endif	/* _PC_SATTR_ENABLED */
2698 		}
2699 
2700 #if defined(_PC_SATTR_ENABLED)
2701 	} else if (saflag) {
2702 		/* Verify system attributes are supported */
2703 		if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2704 		    _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2705 			return (ATTR_SATTR_ERR);
2706 		}
2707 #endif	/* _PC_SATTR_ENABLED */
2708 	} else {
2709 		return (ATTR_SKIP);
2710 	}
2711 
2712 	return (ATTR_OK);
2713 }
2714 #endif
2715 
2716 #if defined(O_XATTR)
2717 /*
2718  * Recursively open attribute directories until the attribute directory
2719  * containing the specified attribute, attrname, is opened.
2720  *
2721  * Currently, only 2 directory levels of attributes are supported, (i.e.,
2722  * extended system attributes on extended attributes).  The following are
2723  * the possible input combinations:
2724  *	1.  Open the attribute directory of the base file (don't change
2725  *	    into it).
2726  *		attrinfo->parent = NULL
2727  *		attrname = '.'
2728  *	2.  Open the attribute directory of the base file and change into it.
2729  *		attrinfo->parent = NULL
2730  *		attrname = <attr> | <sys_attr>
2731  *	3.  Open the attribute directory of the base file, change into it,
2732  *	    then recursively call open_attr_dir() to open the attribute's
2733  *	    parent directory (don't change into it).
2734  *		attrinfo->parent = <attr>
2735  *		attrname = '.'
2736  *	4.  Open the attribute directory of the base file, change into it,
2737  *	    then recursively call open_attr_dir() to open the attribute's
2738  *	    parent directory and change into it.
2739  *		attrinfo->parent = <attr>
2740  *		attrname = <attr> | <sys_attr>
2741  *
2742  * An attribute directory will be opened only if the underlying file system
2743  * supports the attribute type, and if the command line specifications (atflag
2744  * and saflag) enable the processing of the attribute type.
2745  *
2746  * On succesful return, attrinfo->parentfd will be the file descriptor of the
2747  * opened attribute directory.  In addition, if the attribute is a read-write
2748  * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2749  * it will be set to 0.
2750  *
2751  * Possible return values:
2752  * 	ATTR_OK		Successfully opened and, if needed, changed into the
2753  *			attribute directory containing attrname.
2754  *	ATTR_SKIP	The command line specifications don't enable the
2755  *			processing of the attribute type.
2756  * 	ATTR_CHDIR_ERR	An error occurred while trying to change into an
2757  *			attribute directory.
2758  * 	ATTR_OPEN_ERR	An error occurred while trying to open an
2759  *			attribute directory.
2760  *	ATTR_XATTR_ERR	The underlying file system doesn't support extended
2761  *			attributes.
2762  *	ATTR_SATTR_ERR	The underlying file system doesn't support extended
2763  *			system attributes.
2764  */
2765 static int
2766 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2767 {
2768 	attr_status_t	rc;
2769 	int		firsttime = (attrinfo->attr_parentfd == -1);
2770 	int		saveerrno;
2771 	int		ext_attr;
2772 
2773 	/*
2774 	 * open_attr_dir() was recursively called (input combination number 4),
2775 	 * close the previously opened file descriptor as we've already changed
2776 	 * into it.
2777 	 */
2778 	if (!firsttime) {
2779 		(void) close(attrinfo->attr_parentfd);
2780 		attrinfo->attr_parentfd = -1;
2781 	}
2782 
2783 	/*
2784 	 * Verify that the underlying file system supports the restoration
2785 	 * of the attribute.
2786 	 */
2787 	if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2788 	    &ext_attr)) != ATTR_OK) {
2789 		return (rc);
2790 	}
2791 
2792 	/* Open the base file's attribute directory */
2793 	if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2794 		/*
2795 		 * Save the errno from the attropen so it can be reported
2796 		 * if the retry of the attropen fails.
2797 		 */
2798 		saveerrno = errno;
2799 		if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2800 		    NULL, ".", O_RDONLY, 0)) == -1) {
2801 			/*
2802 			 * Reset typeflag back to real value so passtape
2803 			 * will skip ahead correctly.
2804 			 */
2805 			dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2806 			(void) close(attrinfo->attr_parentfd);
2807 			attrinfo->attr_parentfd = -1;
2808 			errno = saveerrno;
2809 			return (ATTR_OPEN_ERR);
2810 		}
2811 	}
2812 
2813 	/*
2814 	 * Change into the parent attribute's directory unless we are
2815 	 * processing the hidden attribute directory of the base file itself.
2816 	 */
2817 	if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2818 		if (fchdir(attrinfo->attr_parentfd) != 0) {
2819 			saveerrno = errno;
2820 			(void) close(attrinfo->attr_parentfd);
2821 			attrinfo->attr_parentfd = -1;
2822 			errno = saveerrno;
2823 			return (ATTR_CHDIR_ERR);
2824 		}
2825 	}
2826 
2827 	/* Determine if the attribute should be processed */
2828 	if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2829 	    &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2830 		saveerrno = errno;
2831 		(void) close(attrinfo->attr_parentfd);
2832 		attrinfo->attr_parentfd = -1;
2833 		errno = saveerrno;
2834 		return (rc);
2835 	}
2836 
2837 	/*
2838 	 * If the attribute is an extended attribute, or extended system
2839 	 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2840 	 * recursively call open_attr_dir() to open the attribute directory
2841 	 * of the parent attribute.
2842 	 */
2843 	if (firsttime && (attrinfo->attr_parent != NULL)) {
2844 		return (open_attr_dir(attrname, attrinfo->attr_parent,
2845 		    attrinfo->attr_parentfd, attrinfo));
2846 	}
2847 
2848 	return (ATTR_OK);
2849 }
2850 #endif
2851 
2852 static void
2853 doxtract(char *argv[])
2854 {
2855 	struct	stat	xtractbuf;	/* stat on file after extracting */
2856 	blkcnt_t blocks;
2857 	off_t bytes;
2858 	int ofile;
2859 	int newfile;			/* Does the file already exist  */
2860 	int xcnt = 0;			/* count # files extracted */
2861 	int fcnt = 0;			/* count # files in argv list */
2862 	int dir;
2863 	int dirfd = -1;
2864 	int cwd = -1;
2865 	int rw_sysattr;
2866 	int saveerrno;
2867 	uid_t Uid;
2868 	char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2869 	char dirname[PATH_MAX+1];
2870 	char templink[PATH_MAX+1];	/* temp link with terminating NULL */
2871 	int once = 1;
2872 	int error;
2873 	int symflag;
2874 	int want;
2875 	attr_data_t *attrinfo = NULL;	/* attribute info */
2876 	acl_t	*aclp = NULL;	/* acl info */
2877 	char dot[] = ".";		/* dirp for using realpath */
2878 	timestruc_t	time_zero;	/* used for call to doDirTimes */
2879 	int		dircreate;
2880 	int convflag;
2881 	time_zero.tv_sec = 0;
2882 	time_zero.tv_nsec = 0;
2883 
2884 	/* reset Trusted Extensions variables */
2885 	rpath_flag = 0;
2886 	lk_rpath_flag = 0;
2887 	dir_flag = 0;
2888 	mld_flag = 0;
2889 	bslundef(&bs_label);
2890 	bsllow(&admin_low);
2891 	bslhigh(&admin_high);
2892 	orig_namep = 0;
2893 
2894 	dumping = 0;	/* for newvol(), et al:  we are not writing */
2895 
2896 	Uid = getuid();
2897 
2898 	for (;;) {
2899 		convflag = 0;
2900 		symflag = 0;
2901 		dir = 0;
2902 		Hiddendir = 0;
2903 		rw_sysattr = 0;
2904 		ofile = -1;
2905 
2906 		if (dirfd != -1) {
2907 			(void) close(dirfd);
2908 			dirfd = -1;
2909 		}
2910 		if (ofile != -1) {
2911 			if (close(ofile) != 0)
2912 				vperror(2, gettext("close error"));
2913 		}
2914 
2915 #if defined(O_XATTR)
2916 		if (cwd != -1) {
2917 			rest_cwd(&cwd);
2918 		}
2919 #endif
2920 
2921 		/* namep is set by wantit to point to the full name */
2922 		if ((want = wantit(argv, &namep, &dirp, &comp,
2923 		    &attrinfo)) == 0) {
2924 #if defined(O_XATTR)
2925 			if (xattrp != NULL) {
2926 				free(xattrhead);
2927 				xattrp = NULL;
2928 				xattr_linkp = NULL;
2929 				xattrhead = NULL;
2930 			}
2931 #endif
2932 			continue;
2933 		}
2934 		if (want == -1)
2935 			break;
2936 
2937 /* Trusted Extensions */
2938 		/*
2939 		 * During tar extract (x):
2940 		 * If the pathname of the restored file has been
2941 		 * reconstructed from the ancillary file,
2942 		 * use it to process the normal file.
2943 		 */
2944 		if (mld_flag) {		/* Skip over .MLD. directory */
2945 			mld_flag = 0;
2946 			passtape();
2947 			continue;
2948 		}
2949 		orig_namep = namep;	/* save original */
2950 		if (rpath_flag) {
2951 			namep = real_path;	/* use zone path */
2952 			comp = real_path;	/* use zone path */
2953 			dirp = dot;		/* work from the top */
2954 			rpath_flag = 0;		/* reset */
2955 		}
2956 
2957 		if (dirfd != -1)
2958 			(void) close(dirfd);
2959 
2960 		(void) strcpy(&dirname[0], namep);
2961 		dircreate = checkdir(&dirname[0]);
2962 
2963 #if defined(O_XATTR)
2964 		if (xattrp != NULL) {
2965 			int	rc;
2966 
2967 			if (((cwd = save_cwd()) == -1) ||
2968 			    ((rc = open_attr_dir(comp, dirp, cwd,
2969 			    attrinfo)) != ATTR_OK)) {
2970 				if (cwd == -1) {
2971 					vperror(0, gettext(
2972 					    "unable to save current working "
2973 					    "directory while processing "
2974 					    "attribute %s of %s"),
2975 					    dirp, attrinfo->attr_path);
2976 				} else if (rc != ATTR_SKIP) {
2977 					(void) fprintf(vfile,
2978 					    gettext("tar: cannot open "
2979 					    "%sattribute %s of file %s: %s\n"),
2980 					    attrinfo->attr_rw_sysattr ? gettext(
2981 					    "system ") : "",
2982 					    comp, dirp, strerror(errno));
2983 				}
2984 				free(xattrhead);
2985 				xattrp = NULL;
2986 				xattr_linkp = NULL;
2987 				xattrhead = NULL;
2988 
2989 				passtape();
2990 				continue;
2991 			} else {
2992 				dirfd = attrinfo->attr_parentfd;
2993 				rw_sysattr = attrinfo->attr_rw_sysattr;
2994 			}
2995 		} else {
2996 			dirfd = open(dirp, O_RDONLY);
2997 		}
2998 #else
2999 		dirfd = open(dirp, O_RDONLY);
3000 #endif
3001 		if (dirfd == -1) {
3002 			(void) fprintf(vfile, gettext(
3003 			    "tar: cannot open %s: %s\n"),
3004 			    dirp, strerror(errno));
3005 			passtape();
3006 			continue;
3007 		}
3008 
3009 		if (xhdr_flgs & _X_LINKPATH)
3010 			(void) strcpy(templink, Xtarhdr.x_linkpath);
3011 		else {
3012 #if defined(O_XATTR)
3013 			if (xattrp && dblock.dbuf.typeflag == '1') {
3014 				(void) sprintf(templink, "%.*s", NAMSIZ,
3015 				    xattrp->h_names);
3016 			} else {
3017 				(void) sprintf(templink, "%.*s", NAMSIZ,
3018 				    dblock.dbuf.linkname);
3019 			}
3020 #else
3021 			(void) sprintf(templink, "%.*s", NAMSIZ,
3022 			    dblock.dbuf.linkname);
3023 #endif
3024 		}
3025 
3026 		if (Fflag) {
3027 			if (checkf(namep, is_directory(namep), Fflag) == 0) {
3028 				passtape();
3029 				continue;
3030 			}
3031 		}
3032 
3033 		if (checkw('x', namep) == 0) {
3034 			passtape();
3035 			continue;
3036 		}
3037 		if (once) {
3038 			if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3039 				if (geteuid() == (uid_t)0) {
3040 					checkflag = 1;
3041 					pflag = 1;
3042 				} else {
3043 					/* get file creation mask */
3044 					Oumask = umask(0);
3045 					(void) umask(Oumask);
3046 				}
3047 				once = 0;
3048 			} else {
3049 				if (geteuid() == (uid_t)0) {
3050 					pflag = 1;
3051 					checkflag = 2;
3052 				}
3053 				if (!pflag) {
3054 					/* get file creation mask */
3055 					Oumask = umask(0);
3056 					(void) umask(Oumask);
3057 				}
3058 				once = 0;
3059 			}
3060 		}
3061 
3062 #if defined(O_XATTR)
3063 		/*
3064 		 * Handle extraction of hidden attr dir.
3065 		 * Dir is automatically created, we only
3066 		 * need to update mode and perm's.
3067 		 */
3068 		if ((xattrp != NULL) && Hiddendir == 1) {
3069 			bytes = stbuf.st_size;
3070 			blocks = TBLOCKS(bytes);
3071 			if (vflag) {
3072 				(void) fprintf(vfile,
3073 				    "x %s%s%s, %" FMT_off_t " %s, ", namep,
3074 				    gettext(" attribute "),
3075 				    xattrapath, bytes,
3076 				    gettext("bytes"));
3077 				if (NotTape)
3078 					(void) fprintf(vfile,
3079 					    "%" FMT_blkcnt_t "K\n", K(blocks));
3080 				else
3081 					(void) fprintf(vfile, gettext("%"
3082 					    FMT_blkcnt_t " tape blocks\n"),
3083 					    blocks);
3084 			}
3085 
3086 			/*
3087 			 * Set the permissions and mode of the attribute
3088 			 * unless the attribute is a system attribute (can't
3089 			 * successfully do this) or the hidden attribute
3090 			 * directory (".") of an attribute (when the attribute
3091 			 * is restored, the hidden attribute directory of an
3092 			 * attribute is transient).  Note:  when the permissions
3093 			 * and mode are set for the hidden attribute directory
3094 			 * of a file on a system supporting extended system
3095 			 * attributes, even though it returns successfully, it
3096 			 * will not have any affect since the attribute
3097 			 * directory is transient.
3098 			 */
3099 			if (attrinfo->attr_parent == NULL) {
3100 				if (fchownat(dirfd, ".", stbuf.st_uid,
3101 				    stbuf.st_gid, 0) != 0) {
3102 					vperror(0, gettext(
3103 					    "%s%s%s: failed to set ownership "
3104 					    "of attribute directory"), namep,
3105 					    gettext(" attribute "), xattrapath);
3106 				}
3107 
3108 				if (fchmod(dirfd, stbuf.st_mode) != 0) {
3109 					vperror(0, gettext(
3110 					    "%s%s%s: failed to set permissions "
3111 					    "of attribute directory"), namep,
3112 					    gettext(" attribute "), xattrapath);
3113 				}
3114 			}
3115 			goto filedone;
3116 		}
3117 #endif
3118 
3119 		if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3120 			dir = 1;
3121 			if (vflag) {
3122 				(void) fprintf(vfile, "x %s, 0 %s, ",
3123 				    &dirname[0], gettext("bytes"));
3124 				if (NotTape)
3125 					(void) fprintf(vfile, "0K\n");
3126 				else
3127 					(void) fprintf(vfile, gettext("%"
3128 					    FMT_blkcnt_t " tape blocks\n"),
3129 					    (blkcnt_t)0);
3130 			}
3131 			goto filedone;
3132 		}
3133 
3134 		if (dblock.dbuf.typeflag == '6') {	/* FIFO */
3135 			if (rmdir(namep) < 0) {
3136 				if (errno == ENOTDIR)
3137 					(void) unlink(namep);
3138 			}
3139 			linkp = templink;
3140 			if (*linkp !=  NULL) {
3141 				if (Aflag && *linkp == '/')
3142 					linkp++;
3143 				if (link(linkp, namep) < 0) {
3144 					(void) fprintf(stderr, gettext(
3145 					    "tar: %s: cannot link\n"), namep);
3146 					continue;
3147 				}
3148 				if (vflag)
3149 					(void) fprintf(vfile, gettext(
3150 					    "x %s linked to %s\n"), namep,
3151 					    linkp);
3152 				xcnt++;	 /* increment # files extracted */
3153 				continue;
3154 			}
3155 			if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3156 			    (int)Gen.g_devmajor) < 0) {
3157 				vperror(0, gettext("%s: mknod failed"), namep);
3158 				continue;
3159 			}
3160 			bytes = stbuf.st_size;
3161 			blocks = TBLOCKS(bytes);
3162 			if (vflag) {
3163 				(void) fprintf(vfile, "x %s, %" FMT_off_t
3164 				    " %s, ", namep, bytes, gettext("bytes"));
3165 				if (NotTape)
3166 					(void) fprintf(vfile, "%" FMT_blkcnt_t
3167 					    "K\n", K(blocks));
3168 				else
3169 					(void) fprintf(vfile, gettext("%"
3170 					    FMT_blkcnt_t " tape blocks\n"),
3171 					    blocks);
3172 			}
3173 			goto filedone;
3174 		}
3175 		if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3176 			if (rmdir(namep) < 0) {
3177 				if (errno == ENOTDIR)
3178 					(void) unlink(namep);
3179 			}
3180 			linkp = templink;
3181 			if (*linkp != NULL) {
3182 				if (Aflag && *linkp == '/')
3183 					linkp++;
3184 				if (link(linkp, namep) < 0) {
3185 					(void) fprintf(stderr, gettext(
3186 					    "tar: %s: cannot link\n"), namep);
3187 					continue;
3188 				}
3189 				if (vflag)
3190 					(void) fprintf(vfile, gettext(
3191 					    "x %s linked to %s\n"), namep,
3192 					    linkp);
3193 				xcnt++;	 /* increment # files extracted */
3194 				continue;
3195 			}
3196 			if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3197 			    (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3198 				vperror(0, gettext(
3199 				    "%s: mknod failed"), namep);
3200 				continue;
3201 			}
3202 			bytes = stbuf.st_size;
3203 			blocks = TBLOCKS(bytes);
3204 			if (vflag) {
3205 				(void) fprintf(vfile, "x %s, %" FMT_off_t
3206 				    " %s, ", namep, bytes, gettext("bytes"));
3207 				if (NotTape)
3208 					(void) fprintf(vfile, "%" FMT_blkcnt_t
3209 					    "K\n", K(blocks));
3210 				else
3211 					(void) fprintf(vfile, gettext("%"
3212 					    FMT_blkcnt_t " tape blocks\n"),
3213 					    blocks);
3214 			}
3215 			goto filedone;
3216 		} else if (dblock.dbuf.typeflag == '3' && Uid) {
3217 			(void) fprintf(stderr, gettext(
3218 			    "Can't create special %s\n"), namep);
3219 			continue;
3220 		}
3221 
3222 		/* BLOCK SPECIAL */
3223 
3224 		if (dblock.dbuf.typeflag == '4' && !Uid) {
3225 			if (rmdir(namep) < 0) {
3226 				if (errno == ENOTDIR)
3227 					(void) unlink(namep);
3228 			}
3229 			linkp = templink;
3230 			if (*linkp != NULL) {
3231 				if (Aflag && *linkp == '/')
3232 					linkp++;
3233 				if (link(linkp, namep) < 0) {
3234 					(void) fprintf(stderr, gettext(
3235 					    "tar: %s: cannot link\n"), namep);
3236 					continue;
3237 				}
3238 				if (vflag)
3239 					(void) fprintf(vfile, gettext(
3240 					    "x %s linked to %s\n"), namep,
3241 					    linkp);
3242 				xcnt++;	 /* increment # files extracted */
3243 				continue;
3244 			}
3245 			if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3246 			    (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3247 				vperror(0, gettext("%s: mknod failed"), namep);
3248 				continue;
3249 			}
3250 			bytes = stbuf.st_size;
3251 			blocks = TBLOCKS(bytes);
3252 			if (vflag) {
3253 				(void) fprintf(vfile, gettext("x %s, %"
3254 				    FMT_off_t " bytes, "), namep, bytes);
3255 				if (NotTape)
3256 					(void) fprintf(vfile, "%" FMT_blkcnt_t
3257 					    "K\n", K(blocks));
3258 				else
3259 					(void) fprintf(vfile, gettext("%"
3260 					    FMT_blkcnt_t " tape blocks\n"),
3261 					    blocks);
3262 			}
3263 			goto filedone;
3264 		} else if (dblock.dbuf.typeflag == '4' && Uid) {
3265 			(void) fprintf(stderr,
3266 			    gettext("Can't create special %s\n"), namep);
3267 			continue;
3268 		}
3269 		if (dblock.dbuf.typeflag == '2') {	/* symlink */
3270 			if ((Tflag) && (lk_rpath_flag == 1))
3271 				linkp = lk_real_path;
3272 			else
3273 				linkp = templink;
3274 			if (Aflag && *linkp == '/')
3275 				linkp++;
3276 			if (rmdir(namep) < 0) {
3277 				if (errno == ENOTDIR)
3278 					(void) unlink(namep);
3279 			}
3280 			if (symlink(linkp, namep) < 0) {
3281 				vperror(0, gettext("%s: symbolic link failed"),
3282 				    namep);
3283 				continue;
3284 			}
3285 			if (vflag)
3286 				(void) fprintf(vfile, gettext(
3287 				    "x %s symbolic link to %s\n"),
3288 				    namep, linkp);
3289 
3290 			symflag = AT_SYMLINK_NOFOLLOW;
3291 			goto filedone;
3292 		}
3293 		if (dblock.dbuf.typeflag == '1') {
3294 			linkp = templink;
3295 			if (Aflag && *linkp == '/')
3296 				linkp++;
3297 			if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3298 				if (errno == ENOTDIR)
3299 					(void) unlinkat(dirfd, comp, 0);
3300 			}
3301 #if defined(O_XATTR)
3302 			if (xattrp && xattr_linkp) {
3303 				if (fchdir(dirfd) < 0) {
3304 					vperror(0, gettext(
3305 					    "Cannot fchdir to attribute "
3306 					    "directory %s"),
3307 					    (attrinfo->attr_parent == NULL) ?
3308 					    dirp : attrinfo->attr_parent);
3309 					exit(1);
3310 				}
3311 
3312 				error = link(xattr_linkaname, xattrapath);
3313 			} else {
3314 				error = link(linkp, namep);
3315 			}
3316 #else
3317 			error = link(linkp, namep);
3318 #endif
3319 
3320 			if (error < 0) {
3321 				(void) fprintf(stderr, gettext(
3322 				    "tar: %s%s%s: cannot link\n"),
3323 				    namep, (xattr_linkp != NULL) ?
3324 				    gettext(" attribute ") : "",
3325 				    (xattr_linkp != NULL) ?
3326 				    xattrapath : "");
3327 				continue;
3328 			}
3329 			if (vflag)
3330 				(void) fprintf(vfile, gettext(
3331 				    "x %s%s%s linked to %s%s%s\n"), namep,
3332 				    (xattr_linkp != NULL) ?
3333 				    gettext(" attribute ") : "",
3334 				    (xattr_linkp != NULL) ?
3335 				    xattr_linkaname : "",
3336 				    linkp,
3337 				    (xattr_linkp != NULL) ?
3338 				    gettext(" attribute ") : "",
3339 				    (xattr_linkp != NULL) ? xattrapath : "");
3340 			xcnt++;		/* increment # files extracted */
3341 #if defined(O_XATTR)
3342 			if (xattrp != NULL) {
3343 				free(xattrhead);
3344 				xattrp = NULL;
3345 				xattr_linkp = NULL;
3346 				xattrhead = NULL;
3347 			}
3348 #endif
3349 			continue;
3350 		}
3351 
3352 		/* REGULAR FILES */
3353 
3354 		if (convtoreg(stbuf.st_size)) {
3355 			convflag = 1;
3356 			if (errflag) {
3357 				(void) fprintf(stderr, gettext(
3358 				    "tar: %s: typeflag '%c' not recognized\n"),
3359 				    namep, dblock.dbuf.typeflag);
3360 				done(1);
3361 			} else {
3362 				(void) fprintf(stderr, gettext(
3363 				    "tar: %s: typeflag '%c' not recognized, "
3364 				    "converting to regular file\n"), namep,
3365 				    dblock.dbuf.typeflag);
3366 				Errflg = 1;
3367 			}
3368 		}
3369 		if (dblock.dbuf.typeflag == '0' ||
3370 		    dblock.dbuf.typeflag == NULL || convflag) {
3371 			delete_target(dirfd, comp, namep);
3372 			linkp = templink;
3373 			if (*linkp != NULL) {
3374 				if (Aflag && *linkp == '/')
3375 					linkp++;
3376 				if (link(linkp, comp) < 0) {
3377 					(void) fprintf(stderr, gettext(
3378 					    "tar: %s: cannot link\n"), namep);
3379 					continue;
3380 				}
3381 				if (vflag)
3382 					(void) fprintf(vfile, gettext(
3383 					    "x %s linked to %s\n"), comp,
3384 					    linkp);
3385 				xcnt++;	 /* increment # files extracted */
3386 #if defined(O_XATTR)
3387 				if (xattrp != NULL) {
3388 					free(xattrhead);
3389 					xattrp = NULL;
3390 					xattr_linkp = NULL;
3391 					xattrhead = NULL;
3392 				}
3393 #endif
3394 				continue;
3395 			}
3396 		newfile = ((fstatat(dirfd, comp,
3397 		    &xtractbuf, 0) == -1) ? TRUE : FALSE);
3398 		ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3399 		    stbuf.st_mode & MODEMASK);
3400 		saveerrno = errno;
3401 
3402 #if defined(O_XATTR)
3403 		if (xattrp != NULL) {
3404 			if (ofile < 0) {
3405 				ofile = retry_open_attr(dirfd, cwd,
3406 				    dirp, attrinfo->attr_parent, comp,
3407 				    O_RDWR|O_CREAT|O_TRUNC,
3408 				    stbuf.st_mode & MODEMASK);
3409 			}
3410 		}
3411 #endif
3412 		if (ofile < 0) {
3413 			errno = saveerrno;
3414 			(void) fprintf(stderr, gettext(
3415 			    "tar: %s%s%s%s - cannot create\n"),
3416 			    (xattrp == NULL) ? "" : (rw_sysattr ?
3417 			    gettext("system attribute ") :
3418 			    gettext("attribute ")),
3419 			    (xattrp == NULL) ? "" : xattrapath,
3420 			    (xattrp == NULL) ? "" : gettext(" of "),
3421 			    (xattrp == NULL) ? comp : namep);
3422 			if (errflag)
3423 				done(1);
3424 			else
3425 				Errflg = 1;
3426 #if defined(O_XATTR)
3427 			if (xattrp != NULL) {
3428 				dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3429 				free(xattrhead);
3430 				xattrp = NULL;
3431 				xattr_linkp = NULL;
3432 				xattrhead = NULL;
3433 			}
3434 #endif
3435 			passtape();
3436 			continue;
3437 		}
3438 
3439 		if (Tflag && (check_ext_attr(namep) == 0)) {
3440 			if (errflag)
3441 				done(1);
3442 			else
3443 				Errflg = 1;
3444 			passtape();
3445 			continue;
3446 		}
3447 
3448 		if (extno != 0) {	/* file is in pieces */
3449 			if (extotal < 1 || extotal > MAXEXT)
3450 				(void) fprintf(stderr, gettext(
3451 				    "tar: ignoring bad extent info for "
3452 				    "%s%s%s%s\n"),
3453 				    (xattrp == NULL) ? "" : (rw_sysattr ?
3454 				    gettext("system attribute ") :
3455 				    gettext("attribute ")),
3456 				    (xattrp == NULL) ? "" : xattrapath,
3457 				    (xattrp == NULL) ? "" : gettext(" of "),
3458 				    (xattrp == NULL) ? comp : namep);
3459 			else {
3460 				/* extract it */
3461 				(void) xsfile(rw_sysattr, ofile);
3462 			}
3463 		}
3464 		extno = 0;	/* let everyone know file is not split */
3465 		bytes = stbuf.st_size;
3466 		blocks = TBLOCKS(bytes);
3467 		if (vflag) {
3468 			(void) fprintf(vfile,
3469 			    "x %s%s%s, %" FMT_off_t " %s, ",
3470 			    (xattrp == NULL) ? "" : dirp,
3471 			    (xattrp == NULL) ? "" : (rw_sysattr ?
3472 			    gettext(" system attribute ") :
3473 			    gettext(" attribute ")),
3474 			    (xattrp == NULL) ? namep : xattrapath, bytes,
3475 			    gettext("bytes"));
3476 			if (NotTape)
3477 				(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3478 				    K(blocks));
3479 			else
3480 				(void) fprintf(vfile, gettext("%"
3481 				    FMT_blkcnt_t " tape blocks\n"), blocks);
3482 		}
3483 
3484 		if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3485 #if defined(O_XATTR)
3486 			if (xattrp != NULL) {
3487 				free(xattrhead);
3488 				xattrp = NULL;
3489 				xattr_linkp = NULL;
3490 				xattrhead = NULL;
3491 			}
3492 #endif
3493 			continue;
3494 		}
3495 filedone:
3496 		if (mflag == 0 && !symflag) {
3497 			if (dir)
3498 				doDirTimes(namep, stbuf.st_mtim);
3499 
3500 			else
3501 #if defined(O_XATTR)
3502 				if (xattrp != NULL) {
3503 					/*
3504 					 * Set the time on the attribute unless
3505 					 * the attribute is a system attribute
3506 					 * (can't successfully do this) or the
3507 					 * hidden attribute directory, "." (the
3508 					 * time on the hidden attribute
3509 					 * directory will be updated when
3510 					 * attributes are restored, otherwise
3511 					 * it's transient).
3512 					 */
3513 					if (!rw_sysattr && (Hiddendir == 0)) {
3514 						setPathTimes(dirfd, comp,
3515 						    stbuf.st_mtim);
3516 					}
3517 				} else
3518 					setPathTimes(dirfd, comp,
3519 					    stbuf.st_mtim);
3520 #else
3521 				setPathTimes(dirfd, comp, stbuf.st_mtim);
3522 #endif
3523 		}
3524 
3525 		/* moved this code from above */
3526 		if (pflag && !symflag && Hiddendir == 0) {
3527 			if (xattrp != NULL)
3528 				(void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3529 			else
3530 				(void) chmod(namep, stbuf.st_mode & MODEMASK);
3531 		}
3532 
3533 
3534 		/*
3535 		 * Because ancillary file preceeds the normal file,
3536 		 * acl info may have been retrieved (in aclp).
3537 		 * All file types are directed here (go filedone).
3538 		 * Always restore ACLs if there are ACLs.
3539 		 */
3540 		if (aclp != NULL) {
3541 			int ret;
3542 
3543 #if defined(O_XATTR)
3544 			if (xattrp != NULL) {
3545 				if (Hiddendir)
3546 					ret = facl_set(dirfd, aclp);
3547 				else
3548 					ret = facl_set(ofile, aclp);
3549 			} else {
3550 				ret = acl_set(namep, aclp);
3551 			}
3552 #else
3553 			ret = acl_set(namep, aclp);
3554 #endif
3555 			if (ret < 0) {
3556 				if (pflag) {
3557 					(void) fprintf(stderr, gettext(
3558 					    "%s%s%s%s: failed to set acl "
3559 					    "entries\n"), namep,
3560 					    (xattrp == NULL) ? "" :
3561 					    (rw_sysattr ? gettext(
3562 					    " system attribute ") :
3563 					    gettext(" attribute ")),
3564 					    (xattrp == NULL) ? "" :
3565 					    xattrapath);
3566 				}
3567 				/* else: silent and continue */
3568 			}
3569 			acl_free(aclp);
3570 			aclp = NULL;
3571 		}
3572 
3573 		if (!oflag)
3574 			/* set file ownership */
3575 			resugname(dirfd, comp, symflag);
3576 
3577 		if (pflag && newfile == TRUE && !dir &&
3578 		    (dblock.dbuf.typeflag == '0' ||
3579 		    dblock.dbuf.typeflag == NULL ||
3580 		    convflag || dblock.dbuf.typeflag == '1')) {
3581 			if (fstat(ofile, &xtractbuf) == -1)
3582 				(void) fprintf(stderr, gettext(
3583 				    "tar: cannot stat extracted file "
3584 				    "%s%s%s%s\n"),
3585 				    (xattrp == NULL) ? "" : (rw_sysattr ?
3586 				    gettext("system attribute ") :
3587 				    gettext("attribute ")),
3588 				    (xattrp == NULL) ? "" : xattrapath,
3589 				    (xattrp == NULL) ? "" :
3590 				    gettext(" of "), namep);
3591 
3592 			else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3593 			    != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3594 				(void) fprintf(stderr, gettext(
3595 				    "tar: warning - file permissions have "
3596 				    "changed for %s%s%s%s (are 0%o, should be "
3597 				    "0%o)\n"),
3598 				    (xattrp == NULL) ? "" : (rw_sysattr ?
3599 				    gettext("system attribute ") :
3600 				    gettext("attribute ")),
3601 				    (xattrp == NULL) ? "" : xattrapath,
3602 				    (xattrp == NULL) ? "" :
3603 				    gettext(" of "), namep,
3604 				    xtractbuf.st_mode, stbuf.st_mode);
3605 
3606 			}
3607 		}
3608 #if defined(O_XATTR)
3609 		if (xattrp != NULL) {
3610 			free(xattrhead);
3611 			xattrp = NULL;
3612 			xattr_linkp = NULL;
3613 			xattrhead = NULL;
3614 		}
3615 #endif
3616 
3617 		if (ofile != -1) {
3618 			(void) close(dirfd);
3619 			dirfd = -1;
3620 			if (close(ofile) != 0)
3621 				vperror(2, gettext("close error"));
3622 			ofile = -1;
3623 		}
3624 		xcnt++;			/* increment # files extracted */
3625 		}
3626 
3627 		/*
3628 		 * Process ancillary file.
3629 		 *
3630 		 */
3631 
3632 		if (dblock.dbuf.typeflag == 'A') {	/* acl info */
3633 			char	buf[TBLOCK];
3634 			char	*secp;
3635 			char	*tp;
3636 			int	attrsize;
3637 			int	cnt;
3638 
3639 			/* reset Trusted Extensions flags */
3640 			dir_flag = 0;
3641 			mld_flag = 0;
3642 			lk_rpath_flag = 0;
3643 			rpath_flag = 0;
3644 
3645 			if (pflag) {
3646 				bytes = stbuf.st_size;
3647 				if ((secp = malloc((int)bytes)) == NULL) {
3648 					(void) fprintf(stderr, gettext(
3649 					    "Insufficient memory for acl\n"));
3650 					passtape();
3651 					continue;
3652 				}
3653 				tp = secp;
3654 				blocks = TBLOCKS(bytes);
3655 
3656 				/*
3657 				 * Display a line for each ancillary file.
3658 				 */
3659 				if (vflag && Tflag)
3660 					(void) fprintf(vfile, "x %s(A), %"
3661 					    FMT_blkcnt_t " %s, %"
3662 					    FMT_blkcnt_t " %s\n",
3663 					    namep, bytes, gettext("bytes"),
3664 					    blocks, gettext("tape blocks"));
3665 
3666 				while (blocks-- > 0) {
3667 					readtape(buf);
3668 					if (bytes <= TBLOCK) {
3669 						(void) memcpy(tp, buf,
3670 						    (size_t)bytes);
3671 						break;
3672 					} else {
3673 						(void) memcpy(tp, buf,
3674 						    TBLOCK);
3675 						tp += TBLOCK;
3676 					}
3677 					bytes -= TBLOCK;
3678 				}
3679 				bytes = stbuf.st_size;
3680 				/* got all attributes in secp */
3681 				tp = secp;
3682 				do {
3683 					attr = (struct sec_attr *)tp;
3684 					switch (attr->attr_type) {
3685 					case UFSD_ACL:
3686 					case ACE_ACL:
3687 						(void) sscanf(attr->attr_len,
3688 						    "%7o",
3689 						    (uint_t *)
3690 						    &cnt);
3691 						/* header is 8 */
3692 						attrsize = 8 + (int)strlen(
3693 						    &attr->attr_info[0]) + 1;
3694 						error =
3695 						    acl_fromtext(
3696 						    &attr->attr_info[0], &aclp);
3697 
3698 						if (error != 0) {
3699 							(void) fprintf(stderr,
3700 							    gettext(
3701 							    "aclfromtext "
3702 							    "failed: %s\n"),
3703 							    acl_strerror(
3704 							    error));
3705 							bytes -= attrsize;
3706 							break;
3707 						}
3708 						if (acl_cnt(aclp) != cnt) {
3709 							(void) fprintf(stderr,
3710 							    gettext(
3711 							    "aclcnt error\n"));
3712 							bytes -= attrsize;
3713 							break;
3714 						}
3715 						bytes -= attrsize;
3716 						break;
3717 
3718 					/* Trusted Extensions */
3719 
3720 					case DIR_TYPE:
3721 					case LBL_TYPE:
3722 					case APRIV_TYPE:
3723 					case FPRIV_TYPE:
3724 					case COMP_TYPE:
3725 					case LK_COMP_TYPE:
3726 					case ATTR_FLAG_TYPE:
3727 						attrsize =
3728 						    sizeof (struct sec_attr) +
3729 						    strlen(&attr->attr_info[0]);
3730 						bytes -= attrsize;
3731 						if (Tflag)
3732 							extract_attr(&namep,
3733 							    attr);
3734 						break;
3735 
3736 					default:
3737 						(void) fprintf(stderr, gettext(
3738 						    "unrecognized attr"
3739 						    " type\n"));
3740 						bytes = (off_t)0;
3741 						break;
3742 					}
3743 
3744 					/* next attributes */
3745 					tp += attrsize;
3746 				} while (bytes != 0);
3747 				free(secp);
3748 			} else {
3749 				passtape();
3750 			}
3751 		} /* acl */
3752 
3753 	} /* for */
3754 
3755 	/*
3756 	 *  Ensure that all the directories still on the directory stack
3757 	 *  get their modification times set correctly by flushing the
3758 	 *  stack.
3759 	 */
3760 
3761 	doDirTimes(NULL, time_zero);
3762 
3763 #if defined(O_XATTR)
3764 		if (xattrp != NULL) {
3765 			free(xattrhead);
3766 			xattrp = NULL;
3767 			xattr_linkp = NULL;
3768 			xattrhead = NULL;
3769 		}
3770 #endif
3771 
3772 	/*
3773 	 * Check if the number of files extracted is different from the
3774 	 * number of files listed on the command line
3775 	 */
3776 	if (fcnt > xcnt) {
3777 		(void) fprintf(stderr,
3778 		    gettext("tar: %d file(s) not extracted\n"),
3779 		    fcnt-xcnt);
3780 		Errflg = 1;
3781 	}
3782 }
3783 
3784 /*
3785  *	xblocks		extract file/extent from tape to output file
3786  *
3787  *	xblocks(issysattr, bytes, ofile);
3788  *
3789  *	issysattr			flag set if the files being extracted
3790  *					is an extended system attribute file.
3791  *	unsigned long long bytes	size of extent or file to be extracted
3792  *	ofile				output file
3793  *
3794  *	called by doxtract() and xsfile()
3795  */
3796 
3797 static int
3798 xblocks(int issysattr, off_t bytes, int ofile)
3799 {
3800 	char *buf;
3801 	char tempname[NAMSIZ+1];
3802 	size_t maxwrite;
3803 	size_t bytesread;
3804 	size_t piosize;		/* preferred I/O size */
3805 	struct stat tsbuf;
3806 
3807 	/* Don't need to do anything if this is a zero size file */
3808 	if (bytes <= 0) {
3809 		return (0);
3810 	}
3811 
3812 	/*
3813 	 * To figure out the size of the buffer used to accumulate data
3814 	 * from readtape() and to write to the file, we need to determine
3815 	 * the largest chunk of data to be written to the file at one time.
3816 	 * This is determined based on the smallest of the following two
3817 	 * things:
3818 	 *	1) The size of the archived file.
3819 	 *	2) The preferred I/O size of the file.
3820 	 */
3821 	if (issysattr || (bytes <= TBLOCK)) {
3822 		/*
3823 		 * Writes to system attribute files must be
3824 		 * performed in one operation.
3825 		 */
3826 		maxwrite = bytes;
3827 	} else {
3828 		/*
3829 		 * fstat() the file to get the preferred I/O size.
3830 		 * If it fails, then resort back to just writing
3831 		 * one block at a time.
3832 		 */
3833 		if (fstat(ofile, &tsbuf) == 0) {
3834 			piosize = tsbuf.st_blksize;
3835 		} else {
3836 			piosize = TBLOCK;
3837 		}
3838 		maxwrite = min(bytes, piosize);
3839 	}
3840 
3841 	/*
3842 	 * The buffer used to accumulate the data for the write operation
3843 	 * needs to be the maximum number of bytes to be written rounded up
3844 	 * to the nearest TBLOCK since readtape reads one block at a time.
3845 	 */
3846 	if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3847 		fatal(gettext("cannot allocate buffer"));
3848 	}
3849 
3850 	while (bytes > 0) {
3851 
3852 		/*
3853 		 * readtape() obtains one block (TBLOCK) of data at a time.
3854 		 * Accumulate as many blocks of data in buf as we can write
3855 		 * in one operation.
3856 		 */
3857 		for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3858 			readtape(buf + bytesread);
3859 		}
3860 
3861 		if (write(ofile, buf, maxwrite) < 0) {
3862 			int saveerrno = errno;
3863 
3864 			if (xhdr_flgs & _X_PATH)
3865 				(void) strlcpy(tempname, Xtarhdr.x_path,
3866 				    sizeof (tempname));
3867 			else
3868 				(void) sprintf(tempname, "%.*s", NAMSIZ,
3869 				    dblock.dbuf.name);
3870 			/*
3871 			 * If the extended system attribute being extracted
3872 			 * contains attributes that the user needs privileges
3873 			 * for, then just display a warning message, skip
3874 			 * the extraction of this file, and return.
3875 			 */
3876 			if ((saveerrno == EPERM) && issysattr) {
3877 				(void) fprintf(stderr, gettext(
3878 				    "tar: unable to extract system attribute "
3879 				    "%s: insufficient privileges\n"), tempname);
3880 				Errflg = 1;
3881 				(void) free(buf);
3882 				return (1);
3883 			} else {
3884 				(void) fprintf(stderr, gettext(
3885 				    "tar: %s: HELP - extract write error\n"),
3886 				    tempname);
3887 				done(2);
3888 			}
3889 		}
3890 		bytes -= maxwrite;
3891 
3892 		/*
3893 		 * If we've reached this point and there is still data
3894 		 * to be written, maxwrite had to have been determined
3895 		 * by the preferred I/O size.  If the number of bytes
3896 		 * left to write is smaller than the preferred I/O size,
3897 		 * then we're about to do our final write to the file, so
3898 		 * just set maxwrite to the number of bytes left to write.
3899 		 */
3900 		if ((bytes > 0) && (bytes < maxwrite)) {
3901 			maxwrite = bytes;
3902 		}
3903 	}
3904 	free(buf);
3905 
3906 	return (0);
3907 }
3908 
3909 /*
3910  * 	xsfile	extract split file
3911  *
3912  *	xsfile(ofd);	ofd = output file descriptor
3913  *
3914  *	file extracted and put in ofd via xblocks()
3915  *
3916  *	NOTE:  only called by doxtract() to extract one large file
3917  */
3918 
3919 static	union	hblock	savedblock;	/* to ensure same file across volumes */
3920 
3921 static int
3922 xsfile(int issysattr, int ofd)
3923 {
3924 	int i, c;
3925 	int sysattrerr = 0;
3926 	char name[PATH_MAX+1];	/* holds name for diagnostics */
3927 	int extents, totalext;
3928 	off_t bytes, totalbytes;
3929 
3930 	if (xhdr_flgs & _X_PATH)
3931 		(void) strcpy(name, Xtarhdr.x_path);
3932 	else
3933 		(void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
3934 
3935 	totalbytes = (off_t)0;		/* in case we read in half the file */
3936 	totalext = 0;		/* these keep count */
3937 
3938 	(void) fprintf(stderr, gettext(
3939 	    "tar: %s split across %d volumes\n"), name, extotal);
3940 
3941 	/* make sure we do extractions in order */
3942 	if (extno != 1) {	/* starting in middle of file? */
3943 		(void) printf(gettext(
3944 		    "tar: first extent read is not #1\n"
3945 		    "OK to read file beginning with extent #%d (%s/%s) ? "),
3946 		    extno, yesstr, nostr);
3947 		if (yes() == 0) {
3948 canit:
3949 			passtape();
3950 			if (close(ofd) != 0)
3951 				vperror(2, gettext("close error"));
3952 			if (sysattrerr) {
3953 				return (1);
3954 			} else {
3955 				return (0);
3956 			}
3957 		}
3958 	}
3959 	extents = extotal;
3960 	i = extno;
3961 	/*CONSTCOND*/
3962 	while (1) {
3963 		if (xhdr_flgs & _X_SIZE) {
3964 			bytes = extsize;
3965 		} else {
3966 			bytes = stbuf.st_size;
3967 		}
3968 
3969 		if (vflag)
3970 			(void) fprintf(vfile, "+++ x %s [%s #%d], %"
3971 			    FMT_off_t " %s, %ldK\n",
3972 			    name, gettext("extent"), extno,
3973 			    bytes, gettext("bytes"),
3974 			    (long)K(TBLOCKS(bytes)));
3975 		if (xblocks(issysattr, bytes, ofd) != 0) {
3976 			sysattrerr = 1;
3977 			goto canit;
3978 		}
3979 
3980 		totalbytes += bytes;
3981 		totalext++;
3982 		if (++i > extents)
3983 			break;
3984 
3985 		/* get next volume and verify it's the right one */
3986 		copy(&savedblock, &dblock);
3987 tryagain:
3988 		newvol();
3989 		xhdr_flgs = 0;
3990 		getdir();
3991 		if (Xhdrflag > 0)
3992 			(void) get_xdata();	/* Get x-header & regular hdr */
3993 		if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
3994 			load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
3995 			xhdr_flgs |= _X_XHDR;
3996 		}
3997 		if (endtape()) {	/* seemingly empty volume */
3998 			(void) fprintf(stderr, gettext(
3999 			    "tar: first record is null\n"));
4000 asknicely:
4001 			(void) fprintf(stderr, gettext(
4002 			    "tar: need volume with extent #%d of %s\n"),
4003 			    i, name);
4004 			goto tryagain;
4005 		}
4006 		if (notsame()) {
4007 			(void) fprintf(stderr, gettext(
4008 			    "tar: first file on that volume is not "
4009 			    "the same file\n"));
4010 			goto asknicely;
4011 		}
4012 		if (i != extno) {
4013 			(void) fprintf(stderr, gettext(
4014 			    "tar: extent #%d received out of order\ntar: "
4015 			    "should be #%d\n"), extno, i);
4016 			(void) fprintf(stderr, gettext(
4017 			    "Ignore error, Abort this file, or "
4018 			    "load New volume (i/a/n) ? "));
4019 			c = response();
4020 			if (c == 'a')
4021 				goto canit;
4022 			if (c != 'i')		/* default to new volume */
4023 				goto asknicely;
4024 			i = extno;		/* okay, start from there */
4025 		}
4026 	}
4027 	if (vflag)
4028 		(void) fprintf(vfile, gettext(
4029 		    "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
4030 		    name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
4031 
4032 	return (0);
4033 }
4034 
4035 
4036 /*
4037  *	notsame()	check if extract file extent is invalid
4038  *
4039  *	returns true if anything differs between savedblock and dblock
4040  *	except extno (extent number), checksum, or size (extent size).
4041  *	Determines if this header belongs to the same file as the one we're
4042  *	extracting.
4043  *
4044  *	NOTE:	though rather bulky, it is only called once per file
4045  *		extension, and it can withstand changes in the definition
4046  *		of the header structure.
4047  *
4048  *	WARNING:	this routine is local to xsfile() above
4049  */
4050 
4051 static int
4052 notsame(void)
4053 {
4054 	return (
4055 	    (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4056 	    (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4057 	    (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4058 	    (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4059 	    (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4060 	    (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4061 	    (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4062 	    (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4063 	    (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4064 }
4065 
4066 static void
4067 dotable(char *argv[])
4068 {
4069 	int tcnt = 0;			/* count # files tabled */
4070 	int fcnt = 0;			/* count # files in argv list */
4071 	char *namep, *dirp, *comp;
4072 	int want;
4073 	char aclchar = ' ';			/* either blank or '+' */
4074 	char templink[PATH_MAX+1];
4075 	attr_data_t *attrinfo = NULL;
4076 
4077 	dumping = 0;
4078 
4079 	/* if not on magtape, maximize seek speed */
4080 	if (NotTape && !bflag) {
4081 #if SYS_BLOCK > TBLOCK
4082 		nblock = SYS_BLOCK / TBLOCK;
4083 #else
4084 		nblock = 1;
4085 #endif
4086 	}
4087 
4088 	for (;;) {
4089 
4090 		/* namep is set by wantit to point to the full name */
4091 		if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4092 			continue;
4093 		if (want == -1)
4094 			break;
4095 		if (dblock.dbuf.typeflag != 'A')
4096 			++tcnt;
4097 
4098 		if (Fflag) {
4099 			if (checkf(namep, is_directory(namep), Fflag) == 0) {
4100 				passtape();
4101 				continue;
4102 			}
4103 		}
4104 		/*
4105 		 * ACL support:
4106 		 * aclchar is introduced to indicate if there are
4107 		 * acl entries. longt() now takes one extra argument.
4108 		 */
4109 		if (vflag) {
4110 			if (dblock.dbuf.typeflag == 'A') {
4111 				aclchar = '+';
4112 				passtape();
4113 				continue;
4114 			}
4115 			longt(&stbuf, aclchar);
4116 			aclchar = ' ';
4117 		}
4118 
4119 
4120 #if defined(O_XATTR)
4121 		if (xattrp != NULL) {
4122 			int	issysattr;
4123 			char	*bn = basename(attrinfo->attr_path);
4124 
4125 			/*
4126 			 * We could use sysattr_type() to test whether or not
4127 			 * the attribute we are processing is really an
4128 			 * extended system attribute, which as of this writing
4129 			 * just does a strcmp(), however, sysattr_type() may
4130 			 * be changed to issue a pathconf() call instead, which
4131 			 * would require being changed into the parent attribute
4132 			 * directory.  So instead, just do simple string
4133 			 * comparisons to see if we are processing an extended
4134 			 * system attribute.
4135 			 */
4136 			issysattr = is_sysattr(bn);
4137 
4138 			(void) printf(gettext("%s %sattribute %s"),
4139 			    xattrp->h_names,
4140 			    issysattr ? gettext("system ") : "",
4141 			    attrinfo->attr_path);
4142 		} else {
4143 			(void) printf("%s", namep);
4144 		}
4145 #else
4146 			(void) printf("%s", namep);
4147 #endif
4148 
4149 		if (extno != 0) {
4150 			if (vflag) {
4151 				/* keep the '\n' for backwards compatibility */
4152 				(void) fprintf(vfile, gettext(
4153 				    "\n [extent #%d of %d]"), extno, extotal);
4154 			} else {
4155 				(void) fprintf(vfile, gettext(
4156 				    " [extent #%d of %d]"), extno, extotal);
4157 			}
4158 		}
4159 		if (xhdr_flgs & _X_LINKPATH) {
4160 			(void) strcpy(templink, Xtarhdr.x_linkpath);
4161 		} else {
4162 #if defined(O_XATTR)
4163 			if (xattrp != NULL) {
4164 				(void) sprintf(templink,
4165 				    "file %.*s", NAMSIZ, xattrp->h_names);
4166 			} else {
4167 				(void) sprintf(templink, "%.*s", NAMSIZ,
4168 				    dblock.dbuf.linkname);
4169 			}
4170 #else
4171 			(void) sprintf(templink, "%.*s", NAMSIZ,
4172 			    dblock.dbuf.linkname);
4173 #endif
4174 			templink[NAMSIZ] = '\0';
4175 		}
4176 		if (dblock.dbuf.typeflag == '1') {
4177 			/*
4178 			 * TRANSLATION_NOTE
4179 			 *	Subject is omitted here.
4180 			 *	Translate this as if
4181 			 *		<subject> linked to %s
4182 			 */
4183 #if defined(O_XATTR)
4184 			if (xattrp != NULL) {
4185 				(void) printf(
4186 				    gettext(" linked to attribute %s"),
4187 				    xattr_linkp->h_names +
4188 				    strlen(xattr_linkp->h_names) + 1);
4189 			} else {
4190 				(void) printf(
4191 				    gettext(" linked to %s"), templink);
4192 			}
4193 #else
4194 				(void) printf(
4195 				    gettext(" linked to %s"), templink);
4196 
4197 #endif
4198 		}
4199 		if (dblock.dbuf.typeflag == '2')
4200 			(void) printf(gettext(
4201 			/*
4202 			 * TRANSLATION_NOTE
4203 			 *	Subject is omitted here.
4204 			 *	Translate this as if
4205 			 *		<subject> symbolic link to %s
4206 			 */
4207 			" symbolic link to %s"), templink);
4208 		(void) printf("\n");
4209 #if defined(O_XATTR)
4210 		if (xattrp != NULL) {
4211 			free(xattrhead);
4212 			xattrp = NULL;
4213 			xattrhead = NULL;
4214 		}
4215 #endif
4216 		passtape();
4217 	}
4218 	/*
4219 	 * Check if the number of files tabled is different from the
4220 	 * number of files listed on the command line
4221 	 */
4222 	if (fcnt > tcnt) {
4223 		(void) fprintf(stderr, gettext(
4224 		    "tar: %d file(s) not found\n"), fcnt-tcnt);
4225 		Errflg = 1;
4226 	}
4227 }
4228 
4229 static void
4230 putempty(blkcnt_t n)
4231 {
4232 	char buf[TBLOCK];
4233 	char *cp;
4234 
4235 	for (cp = buf; cp < &buf[TBLOCK]; )
4236 		*cp++ = '\0';
4237 	while (n-- > 0)
4238 		(void) writetbuf(buf, 1);
4239 }
4240 
4241 static	ushort_t	Ftype = S_IFMT;
4242 
4243 static	void
4244 verbose(struct stat *st, char aclchar)
4245 {
4246 	int i, j, temp;
4247 	mode_t mode;
4248 	char modestr[12];
4249 
4250 	for (i = 0; i < 11; i++)
4251 		modestr[i] = '-';
4252 	modestr[i] = '\0';
4253 
4254 	/* a '+' sign is printed if there is ACL */
4255 	modestr[i-1] = aclchar;
4256 
4257 	mode = st->st_mode;
4258 	for (i = 0; i < 3; i++) {
4259 		temp = (mode >> (6 - (i * 3)));
4260 		j = (i * 3) + 1;
4261 		if (S_IROTH & temp)
4262 			modestr[j] = 'r';
4263 		if (S_IWOTH & temp)
4264 			modestr[j + 1] = 'w';
4265 		if (S_IXOTH & temp)
4266 			modestr[j + 2] = 'x';
4267 	}
4268 	temp = st->st_mode & Ftype;
4269 	switch (temp) {
4270 	case (S_IFIFO):
4271 		modestr[0] = 'p';
4272 		break;
4273 	case (S_IFCHR):
4274 		modestr[0] = 'c';
4275 		break;
4276 	case (S_IFDIR):
4277 		modestr[0] = 'd';
4278 		break;
4279 	case (S_IFBLK):
4280 		modestr[0] = 'b';
4281 		break;
4282 	case (S_IFREG): /* was initialized to '-' */
4283 		break;
4284 	case (S_IFLNK):
4285 		modestr[0] = 'l';
4286 		break;
4287 	default:
4288 		/* This field may be zero in old archives. */
4289 		if (is_posix && dblock.dbuf.typeflag != '1') {
4290 			/*
4291 			 * For POSIX compliant archives, the mode field
4292 			 * consists of 12 bits, ie:  the file type bits
4293 			 * are not stored in dblock.dbuf.mode.
4294 			 * For files other than hard links, getdir() sets
4295 			 * the file type bits in the st_mode field of the
4296 			 * stat structure based upon dblock.dbuf.typeflag.
4297 			 */
4298 			(void) fprintf(stderr, gettext(
4299 			    "tar: impossible file type"));
4300 		}
4301 	}
4302 
4303 	if ((S_ISUID & Gen.g_mode) == S_ISUID)
4304 		modestr[3] = 's';
4305 	if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4306 		modestr[9] = 't';
4307 	if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4308 		modestr[6] = 's';
4309 	else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4310 		modestr[6] = 'l';
4311 	(void) fprintf(vfile, "%s", modestr);
4312 }
4313 
4314 static void
4315 longt(struct stat *st, char aclchar)
4316 {
4317 	char fileDate[30];
4318 	struct tm *tm;
4319 
4320 	verbose(st, aclchar);
4321 	(void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4322 
4323 	if (dblock.dbuf.typeflag == '2') {
4324 		if (xhdr_flgs & _X_LINKPATH)
4325 			st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4326 		else
4327 			st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4328 			    '\0', NAMSIZ) ?
4329 			    (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4330 	}
4331 	(void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4332 
4333 	tm = localtime(&(st->st_mtime));
4334 	(void) strftime(fileDate, sizeof (fileDate),
4335 	    dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4336 	(void) fprintf(vfile, " %s ", fileDate);
4337 }
4338 
4339 
4340 /*
4341  *  checkdir - Attempt to ensure that the path represented in name
4342  *             exists, and return 1 if this is true and name itself is a
4343  *             directory.
4344  *             Return 0 if this path cannot be created or if name is not
4345  *             a directory.
4346  */
4347 
4348 static int
4349 checkdir(char *name)
4350 {
4351 	char lastChar;		   /* the last character in name */
4352 	char *cp;		   /* scratch pointer into name */
4353 	char *firstSlash = NULL;   /* first slash in name */
4354 	char *lastSlash = NULL;	   /* last slash in name */
4355 	int  nameLen;		   /* length of name */
4356 	int  trailingSlash;	   /* true if name ends in slash */
4357 	int  leadingSlash;	   /* true if name begins with slash */
4358 	int  markedDir;		   /* true if name denotes a directory */
4359 	int  success;		   /* status of makeDir call */
4360 
4361 
4362 	/*
4363 	 *  Scan through the name, and locate first and last slashes.
4364 	 */
4365 
4366 	for (cp = name; *cp; cp++) {
4367 		if (*cp == '/') {
4368 			if (! firstSlash) {
4369 				firstSlash = cp;
4370 			}
4371 			lastSlash = cp;
4372 		}
4373 	}
4374 
4375 	/*
4376 	 *  Determine what you can from the proceeds of the scan.
4377 	 */
4378 
4379 	lastChar	= *(cp - 1);
4380 	nameLen		= (int)(cp - name);
4381 	trailingSlash	= (lastChar == '/');
4382 	leadingSlash	= (*name == '/');
4383 	markedDir	= (dblock.dbuf.typeflag == '5' || trailingSlash);
4384 
4385 	if (! lastSlash && ! markedDir) {
4386 		/*
4387 		 *  The named file does not have any subdrectory
4388 		 *  structure; just bail out.
4389 		 */
4390 
4391 		return (0);
4392 	}
4393 
4394 	/*
4395 	 *  Make sure that name doesn`t end with slash for the loop.
4396 	 *  This ensures that the makeDir attempt after the loop is
4397 	 *  meaningful.
4398 	 */
4399 
4400 	if (trailingSlash) {
4401 		name[nameLen-1] = '\0';
4402 	}
4403 
4404 	/*
4405 	 *  Make the path one component at a time.
4406 	 */
4407 
4408 	for (cp = strchr(leadingSlash ? name+1 : name, '/');
4409 	    cp;
4410 	    cp = strchr(cp+1, '/')) {
4411 		*cp = '\0';
4412 		success = makeDir(name);
4413 		*cp = '/';
4414 
4415 		if (!success) {
4416 			name[nameLen-1] = lastChar;
4417 			return (0);
4418 		}
4419 	}
4420 
4421 	/*
4422 	 *  This makes the last component of the name, if it is a
4423 	 *  directory.
4424 	 */
4425 
4426 	if (markedDir) {
4427 		if (! makeDir(name)) {
4428 			name[nameLen-1] = lastChar;
4429 			return (0);
4430 		}
4431 	}
4432 
4433 	name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4434 	return (markedDir);
4435 }
4436 
4437 /*
4438  * resugname - Restore the user name and group name.  Search the NIS
4439  *             before using the uid and gid.
4440  *             (It is presumed that an archive entry cannot be
4441  *	       simultaneously a symlink and some other type.)
4442  */
4443 
4444 static void
4445 resugname(int dirfd, 	/* dir fd file resides in */
4446 	char *name,	/* name of the file to be modified */
4447 	int symflag)	/* true if file is a symbolic link */
4448 {
4449 	uid_t duid;
4450 	gid_t dgid;
4451 	struct stat *sp = &stbuf;
4452 	char	*u_g_name;
4453 
4454 	if (checkflag == 1) { /* Extended tar format and euid == 0 */
4455 
4456 		/*
4457 		 * Try and extract the intended uid and gid from the name
4458 		 * service before believing the uid and gid in the header.
4459 		 *
4460 		 * In the case where we archived a setuid or setgid file
4461 		 * owned by someone with a large uid, then it will
4462 		 * have made it into the archive with a uid of nobody.  If
4463 		 * the corresponding username doesn't appear to exist, then we
4464 		 * want to make sure it *doesn't* end up as setuid nobody!
4465 		 *
4466 		 * Our caller will print an error message about the fact
4467 		 * that the restore didn't work out quite right ..
4468 		 */
4469 		if (xhdr_flgs & _X_UNAME)
4470 			u_g_name = Xtarhdr.x_uname;
4471 		else
4472 			u_g_name = dblock.dbuf.uname;
4473 		if ((duid = getuidbyname(u_g_name)) == -1) {
4474 			if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4475 			    (sp->st_mode & S_ISUID) == S_ISUID)
4476 				(void) chmod(name,
4477 				    MODEMASK & sp->st_mode & ~S_ISUID);
4478 			duid = sp->st_uid;
4479 		}
4480 
4481 		/* (Ditto for gids) */
4482 
4483 		if (xhdr_flgs & _X_GNAME)
4484 			u_g_name = Xtarhdr.x_gname;
4485 		else
4486 			u_g_name = dblock.dbuf.gname;
4487 		if ((dgid = getgidbyname(u_g_name)) == -1) {
4488 			if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4489 			    (sp->st_mode & S_ISGID) == S_ISGID)
4490 				(void) chmod(name,
4491 				    MODEMASK & sp->st_mode & ~S_ISGID);
4492 			dgid = sp->st_gid;
4493 		}
4494 	} else if (checkflag == 2) { /* tar format and euid == 0 */
4495 		duid = sp->st_uid;
4496 		dgid = sp->st_gid;
4497 	}
4498 	if ((checkflag == 1) || (checkflag == 2))
4499 		(void) fchownat(dirfd, name, duid, dgid, symflag);
4500 }
4501 
4502 /*ARGSUSED*/
4503 static void
4504 onintr(int sig)
4505 {
4506 	(void) signal(SIGINT, SIG_IGN);
4507 	term++;
4508 }
4509 
4510 /*ARGSUSED*/
4511 static void
4512 onquit(int sig)
4513 {
4514 	(void) signal(SIGQUIT, SIG_IGN);
4515 	term++;
4516 }
4517 
4518 /*ARGSUSED*/
4519 static void
4520 onhup(int sig)
4521 {
4522 	(void) signal(SIGHUP, SIG_IGN);
4523 	term++;
4524 }
4525 
4526 static void
4527 tomodes(struct stat *sp)
4528 {
4529 	uid_t uid;
4530 	gid_t gid;
4531 
4532 	bzero(dblock.dummy, TBLOCK);
4533 
4534 	/*
4535 	 * If the uid or gid is too large, we can't put it into
4536 	 * the archive.  We could fail to put anything in the
4537 	 * archive at all .. but most of the time the name service
4538 	 * will save the day when we do a lookup at restore time.
4539 	 *
4540 	 * Instead we choose a "safe" uid and gid, and fix up whether
4541 	 * or not the setuid and setgid bits are left set to extraction
4542 	 * time.
4543 	 */
4544 	if (Eflag) {
4545 		if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4546 			xhdr_flgs |= _X_UID;
4547 			Xtarhdr.x_uid = uid;
4548 		}
4549 		if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4550 			xhdr_flgs |= _X_GID;
4551 			Xtarhdr.x_gid = gid;
4552 		}
4553 		if (sp->st_size > TAR_OFFSET_MAX) {
4554 			xhdr_flgs |= _X_SIZE;
4555 			Xtarhdr.x_filesz = sp->st_size;
4556 			(void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4557 			    (off_t)0);
4558 		} else
4559 			(void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4560 			    sp->st_size);
4561 	} else {
4562 		(void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4563 		    sp->st_size);
4564 	}
4565 	if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4566 		uid = UID_NOBODY;
4567 	if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4568 		gid = GID_NOBODY;
4569 	(void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4570 	(void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4571 	(void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4572 	(void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4573 }
4574 
4575 static	int
4576 #ifdef	EUC
4577 /*
4578  * Warning:  the result of this function depends whether 'char' is a
4579  * signed or unsigned data type.  This a source of potential
4580  * non-portability among heterogeneous systems.  It is retained here
4581  * for backward compatibility.
4582  */
4583 checksum_signed(union hblock *dblockp)
4584 #else
4585 checksum(union hblock *dblockp)
4586 #endif	/* EUC */
4587 {
4588 	int i;
4589 	char *cp;
4590 
4591 	for (cp = dblockp->dbuf.chksum;
4592 	    cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4593 		*cp = ' ';
4594 	i = 0;
4595 	for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4596 		i += *cp;
4597 	return (i);
4598 }
4599 
4600 #ifdef	EUC
4601 /*
4602  * Generate unsigned checksum, regardless of what C compiler is
4603  * used.  Survives in the face of arbitrary 8-bit clean filenames,
4604  * e.g., internationalized filenames.
4605  */
4606 static int
4607 checksum(union hblock *dblockp)
4608 {
4609 	unsigned i;
4610 	unsigned char *cp;
4611 
4612 	for (cp = (unsigned char *) dblockp->dbuf.chksum;
4613 	    cp < (unsigned char *)
4614 	    &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4615 		*cp = ' ';
4616 	i = 0;
4617 	for (cp = (unsigned char *) dblockp->dummy;
4618 	    cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4619 		i += *cp;
4620 
4621 	return (i);
4622 }
4623 #endif	/* EUC */
4624 
4625 /*
4626  * If the w flag is set, output the action to be taken and the name of the
4627  * file.  Perform the action if the user response is affirmative.
4628  */
4629 
4630 static int
4631 checkw(char c, char *name)
4632 {
4633 	if (wflag) {
4634 		(void) fprintf(vfile, "%c ", c);
4635 		if (vflag)
4636 			longt(&stbuf, ' ');	/* do we have acl info here */
4637 		(void) fprintf(vfile, "%s: ", name);
4638 		if (yes() == 1) {
4639 			return (1);
4640 		}
4641 		return (0);
4642 	}
4643 	return (1);
4644 }
4645 
4646 /*
4647  * When the F flag is set, exclude RCS and SCCS directories (and any files
4648  * or directories under them).  If F is set twice, also exclude .o files,
4649  * and files names errs, core, and a.out.
4650  *
4651  * Return 0 if file should be excluded, 1 otherwise.
4652  */
4653 
4654 static int
4655 checkf(char *longname, int is_dir, int howmuch)
4656 {
4657 	static char fullname[PATH_MAX + 1];
4658 	char *dir, *name;
4659 
4660 #if defined(O_XATTR)
4661 	/*
4662 	 * If there is an xattr_buf structure associated with this file,
4663 	 * always return 1.
4664 	 */
4665 	if (xattrp) {
4666 		return (1);
4667 	}
4668 #endif
4669 
4670 	/*
4671 	 * First check to see if the base name is an RCS or SCCS directory.
4672 	 */
4673 	if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4674 		return (1);
4675 
4676 	name = basename(fullname);
4677 	if (is_dir) {
4678 		if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4679 			return (0);
4680 	}
4681 
4682 	/*
4683 	 * If two -F command line options were given then exclude .o files,
4684 	 * and files named errs, core, and a.out.
4685 	 */
4686 	if (howmuch > 1 && !is_dir) {
4687 		size_t l = strlen(name);
4688 
4689 		if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4690 			return (0);
4691 		if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4692 		    strcmp(name, "a.out") == 0)
4693 			return (0);
4694 	}
4695 
4696 	/*
4697 	 * At this point, check to see if this file has a parent directory
4698 	 * named RCS or SCCS.  If so, then this file should be excluded too.
4699 	 * The strcpy() operation is done again, because basename(3C) may
4700 	 * modify the path string passed to it.
4701 	 */
4702 	if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4703 		return (1);
4704 
4705 	dir = dirname(fullname);
4706 	while (strcmp(dir, ".") != 0) {
4707 		name = basename(dir);
4708 		if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4709 			return (0);
4710 		dir = dirname(dir);
4711 	}
4712 
4713 	return (1);
4714 }
4715 
4716 static int
4717 response(void)
4718 {
4719 	int c;
4720 
4721 	c = getchar();
4722 	if (c != '\n')
4723 		while (getchar() != '\n')
4724 			;
4725 	else c = 'n';
4726 	return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4727 }
4728 
4729 /* Has file been modified since being put into archive? If so, return > 0. */
4730 
4731 static off_t	lookup(char *);
4732 
4733 static int
4734 checkupdate(char *arg)
4735 {
4736 	char name[PATH_MAX+1];
4737 	time_t	mtime;
4738 	long nsecs;
4739 	off_t seekp;
4740 
4741 	rewind(tfile);
4742 	if ((seekp = lookup(arg)) < 0)
4743 		return (1);
4744 	(void) fseek(tfile, seekp, 0);
4745 	(void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4746 
4747 	/*
4748 	 * Unless nanoseconds were stored in the file, only use seconds for
4749 	 * comparison of time.  Nanoseconds are stored when -E is specified.
4750 	 */
4751 	if (Eflag == 0)
4752 		return (stbuf.st_mtime > mtime);
4753 
4754 	if ((stbuf.st_mtime < mtime) ||
4755 	    ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4756 		return (0);
4757 	return (1);
4758 }
4759 
4760 
4761 /*
4762  *	newvol	get new floppy (or tape) volume
4763  *
4764  *	newvol();		resets tapepos and first to TRUE, prompts for
4765  *				for new volume, and waits.
4766  *	if dumping, end-of-file is written onto the tape.
4767  */
4768 
4769 static void
4770 newvol(void)
4771 {
4772 	int c;
4773 
4774 	if (dumping) {
4775 #ifdef DEBUG
4776 		DEBUG("newvol called with 'dumping' set\n", 0, 0);
4777 #endif
4778 		putempty((blkcnt_t)2);	/* 2 EOT marks */
4779 		closevol();
4780 		flushtape();
4781 		sync();
4782 		tapepos = 0;
4783 	} else
4784 		first = TRUE;
4785 	if (close(mt) != 0)
4786 		vperror(2, gettext("close error"));
4787 	mt = 0;
4788 	(void) fprintf(stderr, gettext(
4789 	    "tar: \007please insert new volume, then press RETURN."));
4790 	(void) fseek(stdin, (off_t)0, 2);	/* scan over read-ahead */
4791 	while ((c = getchar()) != '\n' && ! term)
4792 		if (c == EOF)
4793 			done(Errflg);
4794 	if (term)
4795 		done(Errflg);
4796 
4797 	errno = 0;
4798 
4799 	if (strcmp(usefile, "-") == 0) {
4800 		mt = dup(1);
4801 	} else {
4802 		mt = open(usefile, dumping ? update : 0);
4803 	}
4804 
4805 	if (mt < 0) {
4806 		(void) fprintf(stderr, gettext(
4807 		    "tar: cannot reopen %s (%s)\n"),
4808 		    dumping ? gettext("output") : gettext("input"), usefile);
4809 
4810 #ifdef DEBUG
4811 		DEBUG("update=%d, usefile=%s ", update, usefile);
4812 		DEBUG("mt=%d, [%s]\n", mt, strerror(errno));
4813 #endif
4814 
4815 		done(2);
4816 	}
4817 }
4818 
4819 /*
4820  * Write a trailer portion to close out the current output volume.
4821  */
4822 
4823 static void
4824 closevol(void)
4825 {
4826 	if (mulvol) {
4827 		/*
4828 		 * blocklim does not count the 2 EOT marks;
4829 		 * tapepos  does count the 2 EOT marks;
4830 		 * therefore we need the +2 below.
4831 		 */
4832 		putempty(blocklim + (blkcnt_t)2 - tapepos);
4833 	}
4834 }
4835 
4836 static void
4837 done(int n)
4838 {
4839 	/*
4840 	 * If we were terminated in some way, and we would otherwise have
4841 	 * exited with a value of 0, adjust to 1, so that external callers
4842 	 * can determine this by looking at the exit status.
4843 	 */
4844 	if (term && n == 0)
4845 		n = 1;
4846 
4847 	if (tfile != NULL)
4848 		(void) unlink(tname);
4849 	if (compress_opt != NULL)
4850 		(void) free(compress_opt);
4851 	if (mt > 0) {
4852 		if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4853 			perror(gettext("tar: close error"));
4854 			exit(2);
4855 		}
4856 	}
4857 	exit(n);
4858 }
4859 
4860 /*
4861  * Determine if s1 is a prefix portion of s2 (or the same as s2).
4862  */
4863 
4864 static	int
4865 is_prefix(char *s1, char *s2)
4866 {
4867 	while (*s1)
4868 		if (*s1++ != *s2++)
4869 			return (0);
4870 	if (*s2)
4871 		return (*s2 == '/');
4872 	return (1);
4873 }
4874 
4875 /*
4876  * lookup and bsrch look through tfile entries to find a match for a name.
4877  * The name can be up to PATH_MAX bytes.  bsrch compares what it sees between
4878  * a pair of newline chars, so the buffer it uses must be long enough for
4879  * two lines:  name and modification time as well as period, newline and space.
4880  *
4881  * A kludge was added to bsrch to take care of matching on the first entry
4882  * in the file--there is no leading newline.  So, if we are reading from the
4883  * start of the file, read into byte two and set the first byte to a newline.
4884  * Otherwise, the first entry cannot be matched.
4885  *
4886  */
4887 
4888 #define	N	(2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4889 static	off_t
4890 lookup(char *s)
4891 {
4892 	int i;
4893 	off_t a;
4894 
4895 	for (i = 0; s[i]; i++)
4896 		if (s[i] == ' ')
4897 			break;
4898 	a = bsrch(s, i, low, high);
4899 	return (a);
4900 }
4901 
4902 static off_t
4903 bsrch(char *s, int n, off_t l, off_t h)
4904 {
4905 	int i, j;
4906 	char b[N];
4907 	off_t m, m1;
4908 
4909 
4910 loop:
4911 	if (l >= h)
4912 		return ((off_t)-1);
4913 	m = l + (h-l)/2 - N/2;
4914 	if (m < l)
4915 		m = l;
4916 	(void) fseek(tfile, m, 0);
4917 	if (m == 0) {
4918 		(void) fread(b+1, 1, N-1, tfile);
4919 		b[0] = '\n';
4920 		m--;
4921 	} else
4922 		(void) fread(b, 1, N, tfile);
4923 	for (i = 0; i < N; i++) {
4924 		if (b[i] == '\n')
4925 			break;
4926 		m++;
4927 	}
4928 	if (m >= h)
4929 		return ((off_t)-1);
4930 	m1 = m;
4931 	j = i;
4932 	for (i++; i < N; i++) {
4933 		m1++;
4934 		if (b[i] == '\n')
4935 			break;
4936 	}
4937 	i = cmp(b+j, s, n);
4938 	if (i < 0) {
4939 		h = m;
4940 		goto loop;
4941 	}
4942 	if (i > 0) {
4943 		l = m1;
4944 		goto loop;
4945 	}
4946 	if (m < 0)
4947 		m = 0;
4948 	return (m);
4949 }
4950 
4951 static int
4952 cmp(char *b, char *s, int n)
4953 {
4954 	int i;
4955 
4956 	assert(b[0] == '\n');
4957 
4958 	for (i = 0; i < n; i++) {
4959 		if (b[i+1] > s[i])
4960 			return (-1);
4961 		if (b[i+1] < s[i])
4962 			return (1);
4963 	}
4964 	return (b[i+1] == ' '? 0 : -1);
4965 }
4966 
4967 
4968 /*
4969  *	seekdisk	seek to next file on archive
4970  *
4971  *	called by passtape() only
4972  *
4973  *	WARNING: expects "nblock" to be set, that is, readtape() to have
4974  *		already been called.  Since passtape() is only called
4975  *		after a file header block has been read (why else would
4976  *		we skip to next file?), this is currently safe.
4977  *
4978  *	changed to guarantee SYS_BLOCK boundary
4979  */
4980 
4981 static void
4982 seekdisk(blkcnt_t blocks)
4983 {
4984 	off_t seekval;
4985 #if SYS_BLOCK > TBLOCK
4986 	/* handle non-multiple of SYS_BLOCK */
4987 	blkcnt_t nxb;	/* # extra blocks */
4988 #endif
4989 
4990 	tapepos += blocks;
4991 #ifdef DEBUG
4992 	DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0);
4993 #endif
4994 	if (recno + blocks <= nblock) {
4995 		recno += blocks;
4996 		return;
4997 	}
4998 	if (recno > nblock)
4999 		recno = nblock;
5000 	seekval = (off_t)blocks - (nblock - recno);
5001 	recno = nblock;	/* so readtape() reads next time through */
5002 #if SYS_BLOCK > TBLOCK
5003 	nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
5004 #ifdef DEBUG
5005 	DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
5006 	    nxb, seekval);
5007 #endif
5008 	if (nxb && nxb > seekval) /* don't seek--we'll read */
5009 		goto noseek;
5010 	seekval -=  nxb;	/* don't seek quite so far */
5011 #endif
5012 	if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
5013 		(void) fprintf(stderr, gettext(
5014 		    "tar: device seek error\n"));
5015 		done(3);
5016 	}
5017 #if SYS_BLOCK > TBLOCK
5018 	/* read those extra blocks */
5019 noseek:
5020 	if (nxb) {
5021 #ifdef DEBUG
5022 		DEBUG("reading extra blocks\n", 0, 0);
5023 #endif
5024 		if (read(mt, tbuf, TBLOCK*nblock) < 0) {
5025 			(void) fprintf(stderr, gettext(
5026 			    "tar: read error while skipping file\n"));
5027 			done(8);
5028 		}
5029 		recno = nxb;	/* so we don't read in next readtape() */
5030 	}
5031 #endif
5032 }
5033 
5034 static void
5035 readtape(char *buffer)
5036 {
5037 	int i, j;
5038 
5039 	++tapepos;
5040 	if (recno >= nblock || first) {
5041 		if (first) {
5042 			/*
5043 			 * set the number of blocks to read initially, based on
5044 			 * the defined defaults for the device, or on the
5045 			 * explicit block factor given.
5046 			 */
5047 			if (bflag || defaults_used || NotTape)
5048 				j = nblock;
5049 			else
5050 				j = NBLOCK;
5051 		} else
5052 			j = nblock;
5053 
5054 		if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5055 			(void) fprintf(stderr, gettext(
5056 			    "tar: tape read error\n"));
5057 			done(3);
5058 		/*
5059 		 * i == 0 and !rflag means that EOF is reached and we are
5060 		 * trying to update or replace an empty tar file, so exit
5061 		 * with an error.
5062 		 *
5063 		 * If i == 0 and !first and NotTape, it means the pointer
5064 		 * has gone past the EOF. It could happen if two processes
5065 		 * try to update the same tar file simultaneously. So exit
5066 		 * with an error.
5067 		 */
5068 
5069 		} else if (i == 0) {
5070 			if (first && !rflag) {
5071 				(void) fprintf(stderr, gettext(
5072 				    "tar: blocksize = %d\n"), i);
5073 				done(Errflg);
5074 			} else if (!first && (!rflag || NotTape)) {
5075 				mterr("read", 0, 2);
5076 			}
5077 		} else if ((!first || Bflag) && i != TBLOCK*j) {
5078 			/*
5079 			 * Short read - try to get the remaining bytes.
5080 			 */
5081 
5082 			int remaining = (TBLOCK * j) - i;
5083 			char *b = (char *)tbuf + i;
5084 			int r;
5085 
5086 			do {
5087 				if ((r = read(mt, b, remaining)) < 0) {
5088 					(void) fprintf(stderr,
5089 					    gettext("tar: tape read error\n"));
5090 					done(3);
5091 				}
5092 				b += r;
5093 				remaining -= r;
5094 				i += r;
5095 			} while (remaining > 0 && r != 0);
5096 		}
5097 		if (first) {
5098 			if ((i % TBLOCK) != 0) {
5099 				(void) fprintf(stderr, gettext(
5100 				    "tar: tape blocksize error\n"));
5101 				done(3);
5102 			}
5103 			i /= TBLOCK;
5104 			if (vflag && i != nblock && i != 1) {
5105 				if (!NotTape)
5106 					(void) fprintf(stderr, gettext(
5107 					    "tar: blocksize = %d\n"), i);
5108 			}
5109 
5110 			/*
5111 			 * If we are reading a tape, then a short read is
5112 			 * understood to signify that the amount read is
5113 			 * the tape's actual blocking factor.  We adapt
5114 			 * nblock accordingly.  There is no reason to do
5115 			 * this when the device is not blocked.
5116 			 */
5117 
5118 			if (!NotTape)
5119 				nblock = i;
5120 		}
5121 		recno = 0;
5122 	}
5123 
5124 	first = FALSE;
5125 	copy(buffer, &tbuf[recno++]);
5126 }
5127 
5128 
5129 /*
5130  * replacement for writetape.
5131  */
5132 
5133 static int
5134 writetbuf(char *buffer, int n)
5135 {
5136 	int i;
5137 
5138 	tapepos += n;		/* output block count */
5139 
5140 	if (recno >= nblock) {
5141 		i = write(mt, (char *)tbuf, TBLOCK*nblock);
5142 		if (i != TBLOCK*nblock)
5143 			mterr("write", i, 2);
5144 		recno = 0;
5145 	}
5146 
5147 	/*
5148 	 *  Special case:  We have an empty tape buffer, and the
5149 	 *  users data size is >= the tape block size:  Avoid
5150 	 *  the bcopy and dma direct to tape.  BIG WIN.  Add the
5151 	 *  residual to the tape buffer.
5152 	 */
5153 	while (recno == 0 && n >= nblock) {
5154 		i = (int)write(mt, buffer, TBLOCK*nblock);
5155 		if (i != TBLOCK*nblock)
5156 			mterr("write", i, 2);
5157 		n -= nblock;
5158 		buffer += (nblock * TBLOCK);
5159 	}
5160 
5161 	while (n-- > 0) {
5162 		(void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5163 		buffer += TBLOCK;
5164 		if (recno >= nblock) {
5165 			i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5166 			if (i != TBLOCK*nblock)
5167 				mterr("write", i, 2);
5168 			recno = 0;
5169 		}
5170 	}
5171 
5172 	/* Tell the user how much to write to get in sync */
5173 	return (nblock - recno);
5174 }
5175 
5176 /*
5177  *	backtape - reposition tape after reading soft "EOF" record
5178  *
5179  *	Backtape tries to reposition the tape back over the EOF
5180  *	record.  This is for the 'u' and 'r' function letters so that the
5181  *	tape can be extended.  This code is not well designed, but
5182  *	I'm confident that the only callers who care about the
5183  *	backspace-over-EOF feature are those involved in 'u' and 'r'.
5184  *
5185  *	The proper way to backup the tape is through the use of mtio.
5186  *	Earlier spins used lseek combined with reads in a confusing
5187  *	maneuver that only worked on 4.x, but shouldn't have, even
5188  *	there.  Lseeks are explicitly not supported for tape devices.
5189  */
5190 
5191 static void
5192 backtape(void)
5193 {
5194 	struct mtop mtcmd;
5195 #ifdef DEBUG
5196 	DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5197 	    nblock);
5198 #endif
5199 	/*
5200 	 * Backup to the position in the archive where the record
5201 	 * currently sitting in the tbuf buffer is situated.
5202 	 */
5203 
5204 	if (NotTape) {
5205 		/*
5206 		 * For non-tape devices, this means lseeking to the
5207 		 * correct position.  The absolute location tapepos-recno
5208 		 * should be the beginning of the current record.
5209 		 */
5210 
5211 		if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5212 		    (off_t)-1) {
5213 			(void) fprintf(stderr,
5214 			    gettext("tar: lseek to end of archive failed\n"));
5215 			done(4);
5216 		}
5217 	} else {
5218 		/*
5219 		 * For tape devices, we backup over the most recently
5220 		 * read record.
5221 		 */
5222 
5223 		mtcmd.mt_op = MTBSR;
5224 		mtcmd.mt_count = 1;
5225 
5226 		if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5227 			(void) fprintf(stderr,
5228 			    gettext("tar: backspace over record failed\n"));
5229 			done(4);
5230 		}
5231 	}
5232 
5233 	/*
5234 	 * Decrement the tape and tbuf buffer indices to prepare for the
5235 	 * coming write to overwrite the soft EOF record.
5236 	 */
5237 
5238 	recno--;
5239 	tapepos--;
5240 }
5241 
5242 
5243 /*
5244  *	flushtape  write buffered block(s) onto tape
5245  *
5246  *      recno points to next free block in tbuf.  If nonzero, a write is done.
5247  *	Care is taken to write in multiples of SYS_BLOCK when device is
5248  *	non-magtape in case raw i/o is used.
5249  *
5250  *	NOTE: this is called by writetape() to do the actual writing
5251  */
5252 
5253 static void
5254 flushtape(void)
5255 {
5256 #ifdef DEBUG
5257 	DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0);
5258 #endif
5259 	if (recno > 0) {	/* anything buffered? */
5260 		if (NotTape) {
5261 #if SYS_BLOCK > TBLOCK
5262 			int i;
5263 
5264 			/*
5265 			 * an odd-block write can only happen when
5266 			 * we are at the end of a volume that is not a tape.
5267 			 * Here we round recno up to an even SYS_BLOCK
5268 			 * boundary.
5269 			 */
5270 			if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5271 #ifdef DEBUG
5272 				DEBUG("flushtape() %d rounding blocks\n", i, 0);
5273 #endif
5274 				recno += i;	/* round up to even SYS_BLOCK */
5275 			}
5276 #endif
5277 			if (recno > nblock)
5278 				recno = nblock;
5279 		}
5280 #ifdef DEBUG
5281 		DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5282 		    " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5283 		    (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5284 #endif
5285 		if (write(mt, tbuf,
5286 		    (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5287 			(void) fprintf(stderr, gettext(
5288 			    "tar: tape write error\n"));
5289 			done(2);
5290 		}
5291 		recno = 0;
5292 	}
5293 }
5294 
5295 static void
5296 copy(void *dst, void *src)
5297 {
5298 	(void) memcpy(dst, src, TBLOCK);
5299 }
5300 
5301 /*
5302  * kcheck()
5303  *	- checks the validity of size values for non-tape devices
5304  *	- if size is zero, mulvol tar is disabled and size is
5305  *	  assumed to be infinite.
5306  *	- returns volume size in TBLOCKS
5307  */
5308 
5309 static blkcnt_t
5310 kcheck(char *kstr)
5311 {
5312 	blkcnt_t kval;
5313 
5314 	kval = strtoll(kstr, NULL, 0);
5315 	if (kval == (blkcnt_t)0) {	/* no multi-volume; size is infinity. */
5316 		mulvol = 0;	/* definitely not mulvol, but we must  */
5317 		return (0);	/* took out setting of NotTape */
5318 	}
5319 	if (kval < (blkcnt_t)MINSIZE) {
5320 		(void) fprintf(stderr, gettext(
5321 		    "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5322 		    ").\n"), (ulong_t)MINSIZE, kval);
5323 		(void) fprintf(stderr, gettext(
5324 		    "bad size entry for %s in %s.\n"),
5325 		    archive, DEF_FILE);
5326 		done(1);
5327 	}
5328 	mulvol++;
5329 	NotTape++;			/* implies non-tape */
5330 	return (kval * 1024 / TBLOCK);	/* convert to TBLOCKS */
5331 }
5332 
5333 
5334 /*
5335  * bcheck()
5336  *	- checks the validity of blocking factors
5337  *	- returns blocking factor
5338  */
5339 
5340 static int
5341 bcheck(char *bstr)
5342 {
5343 	blkcnt_t bval;
5344 
5345 	bval = strtoll(bstr, NULL, 0);
5346 	if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5347 		(void) fprintf(stderr, gettext(
5348 		    "tar: invalid blocksize \"%s\".\n"), bstr);
5349 		if (!bflag)
5350 			(void) fprintf(stderr, gettext(
5351 			    "bad blocksize entry for '%s' in %s.\n"),
5352 			    archive, DEF_FILE);
5353 		done(1);
5354 	}
5355 
5356 	return ((int)bval);
5357 }
5358 
5359 
5360 /*
5361  * defset()
5362  *	- reads DEF_FILE for the set of default values specified.
5363  *	- initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5364  *	- 'usefile' points to static data, so will be overwritten
5365  *	  if this routine is called a second time.
5366  *	- the pattern specified by 'arch' must be followed by four
5367  *	  blank-separated fields (1) device (2) blocking,
5368  *				 (3) size(K), and (4) tape
5369  *	  for example: archive0=/dev/fd 1 400 n
5370  */
5371 
5372 static int
5373 defset(char *arch)
5374 {
5375 	char *bp;
5376 
5377 	if (defopen(DEF_FILE) != 0)
5378 		return (FALSE);
5379 	if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5380 		(void) fprintf(stderr, gettext(
5381 		    "tar: error setting parameters for %s.\n"), DEF_FILE);
5382 		return (FALSE);			/* & following ones too */
5383 	}
5384 	if ((bp = defread(arch)) == NULL) {
5385 		(void) fprintf(stderr, gettext(
5386 		    "tar: missing or invalid '%s' entry in %s.\n"),
5387 		    arch, DEF_FILE);
5388 		return (FALSE);
5389 	}
5390 	if ((usefile = strtok(bp, " \t")) == NULL) {
5391 		(void) fprintf(stderr, gettext(
5392 		    "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5393 		return (FALSE);
5394 	}
5395 	if ((bp = strtok(NULL, " \t")) == NULL) {
5396 		(void) fprintf(stderr, gettext(
5397 		    "tar: block component missing in '%s' entry in %s.\n"),
5398 		    arch, DEF_FILE);
5399 		return (FALSE);
5400 	}
5401 	nblock = bcheck(bp);
5402 	if ((bp = strtok(NULL, " \t")) == NULL) {
5403 		(void) fprintf(stderr, gettext(
5404 		    "tar: size component missing in '%s' entry in %s.\n"),
5405 		    arch, DEF_FILE);
5406 		return (FALSE);
5407 	}
5408 	blocklim = kcheck(bp);
5409 	if ((bp = strtok(NULL, " \t")) != NULL)
5410 		NotTape = (*bp == 'n' || *bp == 'N');
5411 	else
5412 		NotTape = (blocklim != 0);
5413 	(void) defopen(NULL);
5414 #ifdef DEBUG
5415 	DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5416 	DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5417 	    nblock, blocklim);
5418 	DEBUG("defset: not tape = %d\n", NotTape, 0);
5419 #endif
5420 	return (TRUE);
5421 }
5422 
5423 
5424 /*
5425  * Following code handles excluded and included files.
5426  * A hash table of file names to be {in,ex}cluded is built.
5427  * For excluded files, before writing or extracting a file
5428  * check to see if it is in the exclude_tbl.
5429  * For included files, the wantit() procedure will check to
5430  * see if the named file is in the include_tbl.
5431  */
5432 
5433 static void
5434 build_table(file_list_t *table[], char *file)
5435 {
5436 	FILE	*fp;
5437 	char	buf[PATH_MAX + 1];
5438 
5439 	if ((fp = fopen(file, "r")) == (FILE *)NULL)
5440 		vperror(1, gettext("could not open %s"), file);
5441 	while (fgets(buf, sizeof (buf), fp) != NULL) {
5442 		if (buf[strlen(buf) - 1] == '\n')
5443 			buf[strlen(buf) - 1] = '\0';
5444 		/* Only add to table if line has something in it */
5445 		if (strspn(buf, " \t") != strlen(buf))
5446 			add_file_to_table(table, buf);
5447 	}
5448 	(void) fclose(fp);
5449 }
5450 
5451 
5452 /*
5453  * Add a file name to the the specified table, if the file name has any
5454  * trailing '/'s then delete them before inserting into the table
5455  */
5456 
5457 static void
5458 add_file_to_table(file_list_t *table[], char *str)
5459 {
5460 	char	name[PATH_MAX + 1];
5461 	unsigned int h;
5462 	file_list_t	*exp;
5463 
5464 	(void) strcpy(name, str);
5465 	while (name[strlen(name) - 1] == '/') {
5466 		name[strlen(name) - 1] = NULL;
5467 	}
5468 
5469 	h = hash(name);
5470 	if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5471 	    sizeof (char))) == NULL) {
5472 		(void) fprintf(stderr, gettext(
5473 		    "tar: out of memory, exclude/include table(entry)\n"));
5474 		exit(1);
5475 	}
5476 
5477 	if ((exp->name = strdup(name)) == NULL) {
5478 		(void) fprintf(stderr, gettext(
5479 		    "tar: out of memory, exclude/include table(file name)\n"));
5480 		exit(1);
5481 	}
5482 
5483 	exp->next = table[h];
5484 	table[h] = exp;
5485 }
5486 
5487 
5488 /*
5489  * See if a file name or any of the file's parent directories is in the
5490  * specified table, if the file name has any trailing '/'s then delete
5491  * them before searching the table
5492  */
5493 
5494 static int
5495 is_in_table(file_list_t *table[], char *str)
5496 {
5497 	char	name[PATH_MAX + 1];
5498 	unsigned int	h;
5499 	file_list_t	*exp;
5500 	char	*ptr;
5501 
5502 	(void) strcpy(name, str);
5503 	while (name[strlen(name) - 1] == '/') {
5504 		name[strlen(name) - 1] = NULL;
5505 	}
5506 
5507 	/*
5508 	 * check for the file name in the passed list
5509 	 */
5510 	h = hash(name);
5511 	exp = table[h];
5512 	while (exp != NULL) {
5513 		if (strcmp(name, exp->name) == 0) {
5514 			return (1);
5515 		}
5516 		exp = exp->next;
5517 	}
5518 
5519 	/*
5520 	 * check for any parent directories in the file list
5521 	 */
5522 	while ((ptr = strrchr(name, '/'))) {
5523 		*ptr = NULL;
5524 		h = hash(name);
5525 		exp = table[h];
5526 		while (exp != NULL) {
5527 			if (strcmp(name, exp->name) == 0) {
5528 				return (1);
5529 			}
5530 			exp = exp->next;
5531 		}
5532 	}
5533 
5534 	return (0);
5535 }
5536 
5537 
5538 /*
5539  * Compute a hash from a string.
5540  */
5541 
5542 static unsigned int
5543 hash(char *str)
5544 {
5545 	char	*cp;
5546 	unsigned int	h;
5547 
5548 	h = 0;
5549 	for (cp = str; *cp; cp++) {
5550 		h += *cp;
5551 	}
5552 	return (h % TABLE_SIZE);
5553 }
5554 
5555 static	void *
5556 getmem(size_t size)
5557 {
5558 	void *p = calloc((unsigned)size, sizeof (char));
5559 
5560 	if (p == NULL && freemem) {
5561 		(void) fprintf(stderr, gettext(
5562 		    "tar: out of memory, link and directory modtime "
5563 		    "info lost\n"));
5564 		freemem = 0;
5565 		if (errflag)
5566 			done(1);
5567 		else
5568 			Errflg = 1;
5569 	}
5570 	return (p);
5571 }
5572 
5573 /*
5574  * vperror() --variable argument perror.
5575  * Takes 3 args: exit_status, formats, args.  If exit_status is 0, then
5576  * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5577  * with the value of whatever "errno" is set to.  If exit_status is not
5578  * zero, then tar exits with that error status. If errflag and exit_status
5579  * are both zero, the routine returns to where it was called and sets Errflg
5580  * to errno.
5581  */
5582 
5583 static void
5584 vperror(int exit_status, char *fmt, ...)
5585 {
5586 	va_list	ap;
5587 
5588 	va_start(ap, fmt);
5589 	(void) fputs("tar: ", stderr);
5590 	(void) vfprintf(stderr, fmt, ap);
5591 	(void) fprintf(stderr, ": %s\n", strerror(errno));
5592 	va_end(ap);
5593 	if (exit_status)
5594 		done(exit_status);
5595 	else
5596 		if (errflag)
5597 			done(errno);
5598 		else
5599 			Errflg = errno;
5600 }
5601 
5602 
5603 static void
5604 fatal(char *format, ...)
5605 {
5606 	va_list	ap;
5607 
5608 	va_start(ap, format);
5609 	(void) fprintf(stderr, "tar: ");
5610 	(void) vfprintf(stderr, format, ap);
5611 	(void) fprintf(stderr, "\n");
5612 	va_end(ap);
5613 	done(1);
5614 }
5615 
5616 
5617 /*
5618  * Check to make sure that argument is a char * ptr.
5619  * Actually, we just check to see that it is non-null.
5620  * If it is null, print out the message and call usage(), bailing out.
5621  */
5622 
5623 static void
5624 assert_string(char *s, char *msg)
5625 {
5626 	if (s == NULL) {
5627 		(void) fprintf(stderr, msg);
5628 		usage();
5629 	}
5630 }
5631 
5632 
5633 static void
5634 mterr(char *operation, int i, int exitcode)
5635 {
5636 	(void) fprintf(stderr, gettext(
5637 	    "tar: %s error: "), operation);
5638 	if (i < 0)
5639 		perror("");
5640 	else
5641 		(void) fprintf(stderr, gettext("unexpected EOF\n"));
5642 	done(exitcode);
5643 }
5644 
5645 static int
5646 wantit(char *argv[], char **namep, char **dirp, char **component,
5647     attr_data_t **attrinfo)
5648 {
5649 	char **cp;
5650 	int gotit;		/* true if we've found a match */
5651 	int ret;
5652 
5653 top:
5654 	if (xhdr_flgs & _X_XHDR) {
5655 		xhdr_flgs = 0;
5656 	}
5657 	getdir();
5658 	if (Xhdrflag > 0) {
5659 		ret = get_xdata();
5660 		if (ret != 0) {	/* Xhdr items and regular header */
5661 			setbytes_to_skip(&stbuf, ret);
5662 			passtape();
5663 			return (0);	/* Error--don't want to extract  */
5664 		}
5665 	}
5666 
5667 	/*
5668 	 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5669 	 * of ancillary file is either over or ancillary file
5670 	 * processing is not required, load info from Xtarhdr and set
5671 	 * _X_XHDR bit in xhdr_flgs.
5672 	 */
5673 	if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5674 		load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5675 		xhdr_flgs |= _X_XHDR;
5676 	}
5677 
5678 #if defined(O_XATTR)
5679 	if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5680 		/*
5681 		 * Always needs to read the extended header.  If atflag, saflag,
5682 		 * or tflag isn't set, then we'll have the correct info for
5683 		 * passtape() later.
5684 		 */
5685 		(void) read_xattr_hdr(attrinfo);
5686 		goto top;
5687 	}
5688 	/*
5689 	 * Now that we've read the extended header, call passtape()
5690 	 * if we don't want to restore attributes or system attributes.
5691 	 * Don't restore the attribute if we are extracting
5692 	 * a file from an archive (as opposed to doing a table of
5693 	 * contents) and any of the following are true:
5694 	 * 1. neither -@ or -/ was specified.
5695 	 * 2. -@ was specified, -/ wasn't specified, and we're
5696 	 * processing a hidden attribute directory of an attribute
5697 	 * or we're processing a read-write system attribute file.
5698 	 * 3. -@ wasn't specified, -/ was specified, and the file
5699 	 * we're processing is not a read-write system attribute file,
5700 	 * or we're processing the hidden attribute directory of an
5701 	 * attribute.
5702 	 *
5703 	 * We always process the attributes if we're just generating
5704 	 * generating a table of contents, or if both -@ and -/ were
5705 	 * specified.
5706 	 */
5707 	if (xattrp != NULL) {
5708 		attr_data_t *ainfo = *attrinfo;
5709 
5710 		if (!tflag &&
5711 		    ((!atflag && !saflag) ||
5712 		    (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5713 		    ainfo->attr_rw_sysattr)) ||
5714 		    (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5715 		    !ainfo->attr_rw_sysattr)))) {
5716 			passtape();
5717 			return (0);
5718 		}
5719 	}
5720 #endif
5721 
5722 	/* sets *namep to point at the proper name */
5723 	if (check_prefix(namep, dirp, component) != 0) {
5724 		passtape();
5725 		return (0);
5726 	}
5727 
5728 	if (endtape()) {
5729 		if (Bflag) {
5730 			/*
5731 			 * Logically at EOT - consume any extra blocks
5732 			 * so that write to our stdin won't fail and
5733 			 * emit an error message; otherwise something
5734 			 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5735 			 * will produce a bogus error message from "dd".
5736 			 */
5737 
5738 			while (read(mt, tbuf, TBLOCK*nblock) > 0) {
5739 				/* empty body */
5740 			}
5741 		}
5742 		return (-1);
5743 	}
5744 
5745 	gotit = 0;
5746 
5747 	if ((Iflag && is_in_table(include_tbl, *namep)) ||
5748 	    (! Iflag && *argv == NULL)) {
5749 		gotit = 1;
5750 	} else {
5751 		for (cp = argv; *cp; cp++) {
5752 			if (is_prefix(*cp, *namep)) {
5753 				gotit = 1;
5754 				break;
5755 			}
5756 		}
5757 	}
5758 
5759 	if (! gotit) {
5760 		passtape();
5761 		return (0);
5762 	}
5763 
5764 	if (Xflag && is_in_table(exclude_tbl, *namep)) {
5765 		if (vflag) {
5766 			(void) fprintf(stderr, gettext("%s excluded\n"),
5767 			    *namep);
5768 		}
5769 		passtape();
5770 		return (0);
5771 	}
5772 
5773 	return (1);
5774 }
5775 
5776 
5777 static void
5778 setbytes_to_skip(struct stat *st, int err)
5779 {
5780 	/*
5781 	 * In a scenario where a typeflag 'X' was followed by
5782 	 * a typeflag 'A' and typeflag 'O', then the number of
5783 	 * bytes to skip should be the size of ancillary file,
5784 	 * plus the dblock for regular file, and the size
5785 	 * from Xtarhdr. However, if the typeflag was just 'X'
5786 	 * followed by typeflag 'O', then the number of bytes
5787 	 * to skip should be the size from Xtarhdr.
5788 	 */
5789 	if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5790 	    (xhdr_flgs & _X_SIZE)) {
5791 		st->st_size += TBLOCK + Xtarhdr.x_filesz;
5792 		xhdr_flgs |= _X_XHDR;
5793 	} else if ((dblock.dbuf.typeflag != 'A') &&
5794 	    (xhdr_flgs & _X_SIZE)) {
5795 		st->st_size += Xtarhdr.x_filesz;
5796 		xhdr_flgs |= _X_XHDR;
5797 	}
5798 }
5799 
5800 static int
5801 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5802     int rw_sysattr, attr_data_t **attrinfo)
5803 {
5804 	size_t	pathlen;
5805 	char	*tpath;
5806 	char	*tparent;
5807 
5808 	/* parent info */
5809 	if (attrparent != NULL) {
5810 		if ((tparent = strdup(attrparent)) == NULL) {
5811 			vperror(0, gettext(
5812 			    "unable to allocate memory for attribute parent "
5813 			    "name for %sattribute %s/%s of %s"),
5814 			    rw_sysattr ? gettext("system ") : "",
5815 			    attrparent, attr, longname);
5816 			return (1);
5817 		}
5818 	} else {
5819 		tparent = NULL;
5820 	}
5821 
5822 	/* path info */
5823 	pathlen = strlen(attr) + 1;
5824 	if (attrparent != NULL) {
5825 		pathlen += strlen(attrparent) + 1;	/* add 1 for '/' */
5826 	}
5827 	if ((tpath = calloc(1, pathlen)) == NULL) {
5828 		vperror(0, gettext(
5829 		    "unable to allocate memory for full "
5830 		    "attribute path name for %sattribute %s%s%s of %s"),
5831 		    rw_sysattr ? gettext("system ") : "",
5832 		    (attrparent == NULL) ? "" : attrparent,
5833 		    (attrparent == NULL) ? "" : "/",
5834 		    attr, longname);
5835 		if (tparent != NULL) {
5836 			free(tparent);
5837 		}
5838 		return (1);
5839 	}
5840 	(void) snprintf(tpath, pathlen, "%s%s%s",
5841 	    (attrparent == NULL) ? "" : attrparent,
5842 	    (attrparent == NULL) ? "" : "/",
5843 	    attr);
5844 
5845 	/* fill in the attribute info */
5846 	if (*attrinfo == NULL) {
5847 		if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5848 			vperror(0, gettext(
5849 			    "unable to allocate memory for attribute "
5850 			    "information for %sattribute %s%s%s of %s"),
5851 			    rw_sysattr ? gettext("system ") : "",
5852 			    (attrparent == NULL) ? "" : attrparent,
5853 			    (attrparent == NULL) ? "" : gettext("/"),
5854 			    attr, longname);
5855 			if (tparent != NULL) {
5856 				free(tparent);
5857 			}
5858 			free(tpath);
5859 			return (1);
5860 		}
5861 	} else {
5862 		if ((*attrinfo)->attr_parent != NULL) {
5863 			free((*attrinfo)->attr_parent);
5864 		}
5865 		if ((*attrinfo)->attr_path != NULL) {
5866 			free((*attrinfo)->attr_path);
5867 		}
5868 		/*
5869 		 * The parent file descriptor is passed in, so don't
5870 		 * close it here as it should be closed by the function
5871 		 * that opened it.
5872 		 */
5873 	}
5874 	(*attrinfo)->attr_parent = tparent;
5875 	(*attrinfo)->attr_path = tpath;
5876 	(*attrinfo)->attr_rw_sysattr = rw_sysattr;
5877 	(*attrinfo)->attr_parentfd = atparentfd;
5878 
5879 	return (0);
5880 }
5881 
5882 /*
5883  * Test to see if name is a directory.
5884  *
5885  * Return 1 if true, 0 otherwise.
5886  */
5887 
5888 static int
5889 is_directory(char *name)
5890 {
5891 #if defined(O_XATTR)
5892 	/*
5893 	 * If there is an xattr_buf structure associated with this file,
5894 	 * then the directory test is based on whether the name has a
5895 	 * trailing slash.
5896 	 */
5897 	if (xattrp)
5898 		return (name[strlen(name) - 1] == '/');
5899 #endif
5900 	if (is_posix)
5901 		return (dblock.dbuf.typeflag == '5');
5902 	else
5903 		return (name[strlen(name) - 1] == '/');
5904 }
5905 
5906 /*
5907  * Version of chdir that handles directory pathnames of greater than PATH_MAX
5908  * length, by changing the working directory to manageable portions of the
5909  * complete directory pathname. If any of these attempts fail, then it exits
5910  * non-zero.
5911  *
5912  * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5913  * pathname is greater than PATH_MAX, then this still won't work, and this
5914  * routine will return -1 with errno set to ENAMETOOLONG.
5915  *
5916  * NOTE: this routine is semantically different to the system chdir in
5917  * that it is remotely possible for the currently working directory to be
5918  * changed to a different directory, if a chdir call fails when processing
5919  * one of the segments of a path that is greater than PATH_MAX. This isn't
5920  * a problem as this is tar's own specific version of chdir.
5921  */
5922 
5923 static int
5924 tar_chdir(const char *path) {
5925 	const char *sep = "/";
5926 	char *path_copy = NULL;
5927 	char *ptr = NULL;
5928 
5929 	/* The trivial case. */
5930 	if (chdir(path) == 0) {
5931 		return (0);
5932 	}
5933 	if (errno == ENAMETOOLONG) {
5934 		if (path[0] == '/' && chdir(sep) != 0)
5935 			return (-1);
5936 
5937 		/* strtok(3C) modifies the string, so make a copy. */
5938 		if ((path_copy = strdup(path)) == NULL) {
5939 			return (-1);
5940 		}
5941 
5942 		/* chdir(2) for every path element. */
5943 		for (ptr = strtok(path_copy, sep);
5944 			ptr != NULL;
5945 			ptr = strtok(NULL, sep)) {
5946 			if (chdir(ptr) != 0) {
5947 				free(path_copy);
5948 				return (-1);
5949 			}
5950 		}
5951 		free(path_copy);
5952 		return (0);
5953 	}
5954 
5955 	/* If chdir fails for any reason except ENAMETOOLONG. */
5956 	return (-1);
5957 }
5958 
5959 /*
5960  * Test if name has a '..' sequence in it.
5961  *
5962  * Return 1 if found, 0 otherwise.
5963  */
5964 
5965 static int
5966 has_dot_dot(char *name)
5967 {
5968 	char *s;
5969 	size_t name_len = strlen(name);
5970 
5971 	for (s = name; s < (name + name_len - 2); s++) {
5972 		if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5973 			return (1);
5974 
5975 		while (! (*s == '/')) {
5976 			if (! *s++)
5977 				return (0);
5978 		}
5979 	}
5980 
5981 	return (0);
5982 }
5983 
5984 /*
5985  * Test if name is an absolute path name.
5986  *
5987  * Return 1 if true, 0 otherwise.
5988  */
5989 
5990 static int
5991 is_absolute(char *name)
5992 {
5993 #if defined(O_XATTR)
5994 	/*
5995 	 * If this is an extended attribute (whose name will begin with
5996 	 * "/dev/null/", always return 0 as they should be extracted with
5997 	 * the name intact, to allow other tar archiving programs that
5998 	 * don't understand extended attributes, to correctly throw them away.
5999 	 */
6000 	if (xattrp)
6001 		return (0);
6002 #endif
6003 
6004 	return (name[0] == '/');
6005 }
6006 
6007 /*
6008  * Adjust the pathname to make it a relative one. Strip off any leading
6009  * '/' characters and if the pathname contains any '..' sequences, strip
6010  * upto and including the last occurance of '../' (or '..' if found at
6011  * the very end of the pathname).
6012  *
6013  * Return the relative pathname. stripped_prefix will also return the
6014  * portion of name that was stripped off and should be freed by the
6015  * calling routine when no longer needed.
6016  */
6017 
6018 static char *
6019 make_relative_name(char *name, char **stripped_prefix)
6020 {
6021 	char *s;
6022 	size_t prefix_len = 0;
6023 	size_t name_len = strlen(name);
6024 
6025 	for (s = name + prefix_len; s < (name + name_len - 2); ) {
6026 		if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
6027 			prefix_len = s + 2 - name;
6028 
6029 		do {
6030 			char c = *s++;
6031 
6032 			if (c == '/')
6033 				break;
6034 		} while (*s);
6035 	}
6036 
6037 	for (s = name + prefix_len; *s == '/'; s++)
6038 		continue;
6039 	prefix_len = s - name;
6040 
6041 	/* Create the portion of the name that was stripped off. */
6042 	s = malloc(prefix_len + 1);
6043 	memcpy(s, name, prefix_len);
6044 	s[prefix_len] = 0;
6045 	*stripped_prefix = s;
6046 	s = &name[prefix_len];
6047 
6048 	return (s);
6049 }
6050 
6051 /*
6052  *  Return through *namep a pointer to the proper fullname (i.e  "<name> |
6053  *  <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6054  *
6055  * Returns 0 if successful, otherwise returns 1.
6056  */
6057 
6058 static int
6059 check_prefix(char **namep, char **dirp, char **compp)
6060 {
6061 	static char fullname[PATH_MAX + 1];
6062 	static char dir[PATH_MAX + 1];
6063 	static char component[PATH_MAX + 1];
6064 	static char savename[PATH_MAX + 1];
6065 	char *s;
6066 
6067 	(void) memset(dir, 0, sizeof (dir));
6068 	(void) memset(component, 0, sizeof (component));
6069 
6070 	if (xhdr_flgs & _X_PATH) {
6071 		(void) strcpy(fullname, Xtarhdr.x_path);
6072 	} else {
6073 		if (dblock.dbuf.prefix[0] != '\0')
6074 			(void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6075 			    dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6076 		else
6077 			(void) sprintf(fullname, "%.*s", NAMSIZ,
6078 			    dblock.dbuf.name);
6079 	}
6080 
6081 	/*
6082 	 * If we are printing a table of contents or extracting an archive,
6083 	 * make absolute pathnames relative and prohibit the unpacking of
6084 	 * files contain ".." in their name (unless the user has supplied
6085 	 * the -P option).
6086 	 */
6087 	if ((tflag || xflag) && !Pflag) {
6088 		if (is_absolute(fullname) || has_dot_dot(fullname)) {
6089 			char *stripped_prefix;
6090 			size_t prefix_len = 0;
6091 
6092 			(void) strcpy(savename, fullname);
6093 			strcpy(fullname,
6094 			    make_relative_name(savename, &stripped_prefix));
6095 			(void) fprintf(stderr,
6096 			    gettext("tar: Removing leading '%s' from '%s'\n"),
6097 			    stripped_prefix, savename);
6098 			free(stripped_prefix);
6099 		}
6100 	}
6101 
6102 	/*
6103 	 * Set dir and component names
6104 	 */
6105 
6106 	get_parent(fullname, dir);
6107 
6108 #if defined(O_XATTR)
6109 	if (xattrp == NULL) {
6110 #endif
6111 		/*
6112 		 * Save of real name since were going to chop off the
6113 		 * trailing slashes.
6114 		 */
6115 		(void) strcpy(savename, fullname);
6116 		/*
6117 		 * first strip of trailing slashes.
6118 		 */
6119 		chop_endslashes(savename);
6120 		s = get_component(savename);
6121 		(void) strcpy(component, s);
6122 
6123 #if defined(O_XATTR)
6124 	} else {
6125 		(void) strcpy(fullname, xattrp->h_names);
6126 		(void) strcpy(dir, fullname);
6127 		(void) strcpy(component, basename(xattrp->h_names +
6128 		    strlen(xattrp->h_names) + 1));
6129 	}
6130 #endif
6131 	*namep = fullname;
6132 	*dirp = dir;
6133 	*compp = component;
6134 
6135 	return (0);
6136 }
6137 
6138 /*
6139  * Return true if the object indicated by the file descriptor and type
6140  * is a tape device, false otherwise
6141  */
6142 
6143 static int
6144 istape(int fd, int type)
6145 {
6146 	int result = 0;
6147 
6148 	if (S_ISCHR(type)) {
6149 		struct mtget mtg;
6150 
6151 		if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6152 			result = 1;
6153 		}
6154 	}
6155 
6156 	return (result);
6157 }
6158 
6159 #include <utmpx.h>
6160 
6161 struct utmpx utmpx;
6162 
6163 #define	NMAX	(sizeof (utmpx.ut_name))
6164 
6165 typedef struct cachenode {	/* this struct must be zeroed before using */
6166 	struct cachenode *next;	/* next in hash chain */
6167 	int val;		/* the uid or gid of this entry */
6168 	int namehash;		/* name's hash signature */
6169 	char name[NMAX+1];	/* the string that val maps to */
6170 } cachenode_t;
6171 
6172 #define	HASHSIZE	256
6173 
6174 static cachenode_t *names[HASHSIZE];
6175 static cachenode_t *groups[HASHSIZE];
6176 static cachenode_t *uids[HASHSIZE];
6177 static cachenode_t *gids[HASHSIZE];
6178 
6179 static int
6180 hash_byname(char *name)
6181 {
6182 	int i, c, h = 0;
6183 
6184 	for (i = 0; i < NMAX; i++) {
6185 		c = name[i];
6186 		if (c == '\0')
6187 			break;
6188 		h = (h << 4) + h + c;
6189 	}
6190 	return (h);
6191 }
6192 
6193 static cachenode_t *
6194 hash_lookup_byval(cachenode_t *table[], int val)
6195 {
6196 	int h = val;
6197 	cachenode_t *c;
6198 
6199 	for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6200 		if (c->val == val)
6201 			return (c);
6202 	}
6203 	return (NULL);
6204 }
6205 
6206 static cachenode_t *
6207 hash_lookup_byname(cachenode_t *table[], char *name)
6208 {
6209 	int h = hash_byname(name);
6210 	cachenode_t *c;
6211 
6212 	for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6213 		if (c->namehash == h && strcmp(c->name, name) == 0)
6214 			return (c);
6215 	}
6216 	return (NULL);
6217 }
6218 
6219 static cachenode_t *
6220 hash_insert(cachenode_t *table[], char *name, int value)
6221 {
6222 	cachenode_t *c;
6223 	int signature;
6224 
6225 	c = calloc(1, sizeof (cachenode_t));
6226 	if (c == NULL) {
6227 		perror("malloc");
6228 		exit(1);
6229 	}
6230 	if (name != NULL) {
6231 		(void) strncpy(c->name, name, NMAX);
6232 		c->namehash = hash_byname(name);
6233 	}
6234 	c->val = value;
6235 	if (table == uids || table == gids)
6236 		signature = c->val;
6237 	else
6238 		signature = c->namehash;
6239 	c->next = table[signature & (HASHSIZE - 1)];
6240 	table[signature & (HASHSIZE - 1)] = c;
6241 	return (c);
6242 }
6243 
6244 static char *
6245 getname(uid_t uid)
6246 {
6247 	cachenode_t *c;
6248 
6249 	if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6250 		struct passwd *pwent = getpwuid(uid);
6251 		c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6252 	}
6253 	return (c->name);
6254 }
6255 
6256 static char *
6257 getgroup(gid_t gid)
6258 {
6259 	cachenode_t *c;
6260 
6261 	if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6262 		struct group *grent = getgrgid(gid);
6263 		c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6264 	}
6265 	return (c->name);
6266 }
6267 
6268 static uid_t
6269 getuidbyname(char *name)
6270 {
6271 	cachenode_t *c;
6272 
6273 	if ((c = hash_lookup_byname(names, name)) == NULL) {
6274 		struct passwd *pwent = getpwnam(name);
6275 		c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6276 	}
6277 	return ((uid_t)c->val);
6278 }
6279 
6280 static gid_t
6281 getgidbyname(char *group)
6282 {
6283 	cachenode_t *c;
6284 
6285 	if ((c = hash_lookup_byname(groups, group)) == NULL) {
6286 		struct group *grent = getgrnam(group);
6287 		c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6288 	}
6289 	return ((gid_t)c->val);
6290 }
6291 
6292 /*
6293  * Build the header.
6294  * Determine whether or not an extended header is also needed.  If needed,
6295  * create and write the extended header and its data.
6296  * Writing of the extended header assumes that "tomodes" has been called and
6297  * the relevant information has been placed in the header block.
6298  */
6299 
6300 static int
6301 build_dblock(
6302 	const char		*name,
6303 	const char		*linkname,
6304 	const char		typeflag,
6305 	const int		filetype,
6306 	const struct stat	*sp,
6307 	const dev_t		device,
6308 	const char		*prefix)
6309 {
6310 	int nblks;
6311 	major_t		dev;
6312 	const char	*filename;
6313 	const char	*lastslash;
6314 
6315 	if (filetype == XATTR_FILE)
6316 		dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6317 	else
6318 		dblock.dbuf.typeflag = typeflag;
6319 	(void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6320 	(void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6321 	(void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6322 
6323 	if (xhdr_flgs & _X_PATH)
6324 		filename = Xtarhdr.x_path;
6325 	else
6326 		filename = name;
6327 
6328 	if ((dev = major(device)) > OCTAL7CHAR) {
6329 		if (Eflag) {
6330 			xhdr_flgs |= _X_DEVMAJOR;
6331 			Xtarhdr.x_devmajor = dev;
6332 		} else {
6333 			(void) fprintf(stderr, gettext(
6334 			    "Device major too large for %s.  Use -E flag."),
6335 			    filename);
6336 			if (errflag)
6337 				done(1);
6338 			else
6339 				Errflg = 1;
6340 		}
6341 		dev = 0;
6342 	}
6343 	(void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6344 	if ((dev = minor(device)) > OCTAL7CHAR) {
6345 		if (Eflag) {
6346 			xhdr_flgs |= _X_DEVMINOR;
6347 			Xtarhdr.x_devminor = dev;
6348 		} else {
6349 			(void) fprintf(stderr, gettext(
6350 			    "Device minor too large for %s.  Use -E flag."),
6351 			    filename);
6352 			if (errflag)
6353 				done(1);
6354 			else
6355 				Errflg = 1;
6356 		}
6357 		dev = 0;
6358 	}
6359 	(void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6360 
6361 	(void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6362 	(void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6363 	(void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6364 	(void) sprintf(dblock.dbuf.version, "00");
6365 	(void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6366 	(void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6367 	(void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6368 	(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6369 
6370 	if (Eflag) {
6371 		(void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6372 		(void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6373 		lastslash = strrchr(name, '/');
6374 		if (lastslash == NULL)
6375 			lastslash = name;
6376 		else
6377 			lastslash++;
6378 		(void) strcpy(xhdr_buf.dbuf.name, lastslash);
6379 		(void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6380 		(void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6381 		(void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6382 		xhdr_count++;
6383 		xrec_offset = 0;
6384 		gen_date("mtime", sp->st_mtim);
6385 		xhdr_buf.dbuf.typeflag = 'X';
6386 		if (gen_utf8_names(filename) != 0)
6387 			return (1);
6388 
6389 #ifdef XHDR_DEBUG
6390 		Xtarhdr.x_uname = dblock.dbuf.uname;
6391 		Xtarhdr.x_gname = dblock.dbuf.gname;
6392 		xhdr_flgs |= (_X_UNAME | _X_GNAME);
6393 #endif
6394 		if (xhdr_flgs) {
6395 			if (xhdr_flgs & _X_DEVMAJOR)
6396 				gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6397 			if (xhdr_flgs & _X_DEVMINOR)
6398 				gen_num("SUN.devminor", Xtarhdr.x_devminor);
6399 			if (xhdr_flgs & _X_GID)
6400 				gen_num("gid", Xtarhdr.x_gid);
6401 			if (xhdr_flgs & _X_UID)
6402 				gen_num("uid", Xtarhdr.x_uid);
6403 			if (xhdr_flgs & _X_SIZE)
6404 				gen_num("size", Xtarhdr.x_filesz);
6405 			if (xhdr_flgs & _X_PATH)
6406 				gen_string("path", Xtarhdr.x_path);
6407 			if (xhdr_flgs & _X_LINKPATH)
6408 				gen_string("linkpath", Xtarhdr.x_linkpath);
6409 			if (xhdr_flgs & _X_GNAME)
6410 				gen_string("gname", Xtarhdr.x_gname);
6411 			if (xhdr_flgs & _X_UNAME)
6412 				gen_string("uname", Xtarhdr.x_uname);
6413 		}
6414 		(void) sprintf(xhdr_buf.dbuf.size,
6415 		    "%011" FMT_off_t_o, xrec_offset);
6416 		(void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6417 		    checksum(&xhdr_buf));
6418 		(void) writetbuf((char *)&xhdr_buf, 1);
6419 		nblks = TBLOCKS(xrec_offset);
6420 		(void) writetbuf(xrec_ptr, nblks);
6421 	}
6422 	return (0);
6423 }
6424 
6425 
6426 /*
6427  *  makeDir - ensure that a directory with the pathname denoted by name
6428  *            exists, and return 1 on success, and 0 on failure (e.g.,
6429  *	      read-only file system, exists but not-a-directory).
6430  */
6431 
6432 static int
6433 makeDir(char *name)
6434 {
6435 	struct stat buf;
6436 
6437 	if (access(name, 0) < 0) {  /* name doesn't exist */
6438 		if (mkdir(name, 0777) < 0) {
6439 			vperror(0, "%s", name);
6440 			return (0);
6441 		}
6442 	} else {		   /* name exists */
6443 		if (stat(name, &buf) < 0) {
6444 			vperror(0, "%s", name);
6445 			return (0);
6446 		}
6447 
6448 		return ((buf.st_mode & S_IFMT) == S_IFDIR);
6449 	}
6450 
6451 	return (1);
6452 }
6453 
6454 
6455 /*
6456  * Save this directory and its mtime on the stack, popping and setting
6457  * the mtimes of any stacked dirs which aren't parents of this one.
6458  * A null name causes the entire stack to be unwound and set.
6459  *
6460  * Since all the elements of the directory "stack" share a common
6461  * prefix, we can make do with one string.  We keep only the current
6462  * directory path, with an associated array of mtime's. A negative
6463  * mtime means no mtime.
6464  *
6465  * This stack algorithm is not guaranteed to work for tapes created
6466  * with the 'r' function letter, but the vast majority of tapes with
6467  * directories are not.  This avoids saving every directory record on
6468  * the tape and setting all the times at the end.
6469  *
6470  * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6471  *  environment)
6472  */
6473 
6474 static void
6475 doDirTimes(char *name, timestruc_t modTime)
6476 {
6477 	static char dirstack[PATH_MAX+2];
6478 			/* Add spaces for the last slash and last NULL */
6479 	static timestruc_t	modtimes[PATH_MAX+1]; /* hash table */
6480 	char *p = dirstack;
6481 	char *q = name;
6482 	char *savp;
6483 
6484 	if (q) {
6485 		/*
6486 		 * Find common prefix
6487 		 */
6488 
6489 		while (*p == *q && *p) {
6490 			p++; q++;
6491 		}
6492 	}
6493 
6494 	savp = p;
6495 	while (*p) {
6496 		/*
6497 		 * Not a child: unwind the stack, setting the times.
6498 		 * The order we do this doesn't matter, so we go "forward."
6499 		 */
6500 
6501 		if (*p == '/')
6502 			if (modtimes[p - dirstack].tv_sec >= 0) {
6503 				*p = '\0';	 /* zap the slash */
6504 				setPathTimes(AT_FDCWD, dirstack,
6505 				    modtimes[p - dirstack]);
6506 				*p = '/';
6507 			}
6508 		++p;
6509 	}
6510 
6511 	p = savp;
6512 
6513 	/*
6514 	 *  Push this one on the "stack"
6515 	 */
6516 
6517 	if (q) {
6518 
6519 		/*
6520 		 * Since the name parameter points the dir pathname
6521 		 * which is limited only to contain PATH_MAX chars
6522 		 * at maximum, we can ignore the overflow case of p.
6523 		 */
6524 
6525 		while ((*p = *q++)) {	/* append the rest of the new dir */
6526 			modtimes[p - dirstack].tv_sec = -1;
6527 			p++;
6528 		}
6529 
6530 		/*
6531 		 * If the tar file had used 'P' or 'E' function modifier,
6532 		 * append the last slash.
6533 		 */
6534 		if (*(p - 1) != '/') {
6535 			*p++ = '/';
6536 			*p = '\0';
6537 		}
6538 		/* overwrite the last one */
6539 		modtimes[p - dirstack - 1] = modTime;
6540 	}
6541 }
6542 
6543 
6544 /*
6545  *  setPathTimes - set the modification time for given path.  Return 1 if
6546  *                 successful and 0 if not successful.
6547  */
6548 
6549 static void
6550 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6551 
6552 {
6553 	struct timeval timebuf[2];
6554 
6555 	/*
6556 	 * futimesat takes an array of two timeval structs.
6557 	 * The first entry contains access time.
6558 	 * The second entry contains modification time.
6559 	 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6560 	 * microseconds.
6561 	 */
6562 	timebuf[0].tv_sec = time((time_t *)0);
6563 	timebuf[0].tv_usec = 0;
6564 	timebuf[1].tv_sec = modTime.tv_sec;
6565 
6566 	/* Extended header: use microseconds */
6567 	timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6568 
6569 	if (futimesat(dirfd, path, timebuf) < 0)
6570 		vperror(0, gettext("can't set time on %s"), path);
6571 }
6572 
6573 
6574 /*
6575  * If hflag is set then delete the symbolic link's target.
6576  * If !hflag then delete the target.
6577  */
6578 
6579 static void
6580 delete_target(int fd, char *comp, char *namep)
6581 {
6582 	struct	stat	xtractbuf;
6583 	char buf[PATH_MAX + 1];
6584 	int n;
6585 
6586 
6587 	if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6588 		if (errno == ENOTDIR && !hflag) {
6589 			(void) unlinkat(fd, comp, 0);
6590 		} else if (errno == ENOTDIR && hflag) {
6591 			if (!lstat(namep, &xtractbuf)) {
6592 				if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6593 					(void) unlinkat(fd, comp, 0);
6594 				} else if ((n = readlink(namep, buf,
6595 				    PATH_MAX)) != -1) {
6596 					buf[n] = (char)NULL;
6597 					(void) unlinkat(fd, buf,
6598 					    AT_REMOVEDIR);
6599 					if (errno == ENOTDIR)
6600 						(void) unlinkat(fd, buf, 0);
6601 				} else {
6602 					(void) unlinkat(fd, comp, 0);
6603 				}
6604 			} else {
6605 				(void) unlinkat(fd, comp, 0);
6606 			}
6607 		}
6608 	}
6609 }
6610 
6611 
6612 /*
6613  * ACL changes:
6614  *	putfile():
6615  *		Get acl info after stat. Write out ancillary file
6616  *		before the normal file, i.e. directory, regular, FIFO,
6617  *		link, special. If acl count is less than 4, no need to
6618  *		create ancillary file. (i.e. standard permission is in
6619  *		use.
6620  *	doxtract():
6621  *		Process ancillary file. Read it in and set acl info.
6622  *		watch out for 'o' function modifier.
6623  *	't' function letter to display table
6624  */
6625 
6626 /*
6627  * New functions for ACLs and other security attributes
6628  */
6629 
6630 /*
6631  * The function appends the new security attribute info to the end of
6632  * existing secinfo.
6633  */
6634 int
6635 append_secattr(
6636 	char	 **secinfo,	/* existing security info */
6637 	int	 *secinfo_len,	/* length of existing security info */
6638 	int	 size,		/* new attribute size: unit depends on type */
6639 	char	*attrtext,	/* new attribute text */
6640 	char	 attr_type)	/* new attribute type */
6641 {
6642 	char	*new_secinfo;
6643 	int	newattrsize;
6644 	int	oldsize;
6645 	struct sec_attr	*attr;
6646 
6647 	/* no need to add */
6648 	if (attr_type != DIR_TYPE) {
6649 		if (attrtext == NULL)
6650 			return (0);
6651 	}
6652 
6653 	switch (attr_type) {
6654 	case UFSD_ACL:
6655 	case ACE_ACL:
6656 		if (attrtext == NULL) {
6657 			(void) fprintf(stderr, gettext("acltotext failed\n"));
6658 			return (-1);
6659 		}
6660 		/* header: type + size = 8 */
6661 		newattrsize = 8 + (int)strlen(attrtext) + 1;
6662 		attr = (struct sec_attr *)malloc(newattrsize);
6663 		if (attr == NULL) {
6664 			(void) fprintf(stderr,
6665 			    gettext("can't allocate memory\n"));
6666 			return (-1);
6667 		}
6668 		attr->attr_type = attr_type;
6669 		(void) sprintf(attr->attr_len,
6670 		    "%06o", size); /* acl entry count */
6671 		(void) strcpy((char *)&attr->attr_info[0], attrtext);
6672 		free(attrtext);
6673 		break;
6674 
6675 	/* Trusted Extensions */
6676 	case DIR_TYPE:
6677 	case LBL_TYPE:
6678 		newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
6679 		attr = (struct sec_attr *)malloc(newattrsize);
6680 		if (attr == NULL) {
6681 			(void) fprintf(stderr,
6682 			gettext("can't allocate memory\n"));
6683 			return (-1);
6684 		}
6685 		attr->attr_type = attr_type;
6686 		(void) sprintf(attr->attr_len,
6687 		    "%06d", size); /* len of attr data */
6688 		(void) strcpy((char *)&attr->attr_info[0], attrtext);
6689 		break;
6690 
6691 	default:
6692 		(void) fprintf(stderr,
6693 		    gettext("unrecognized attribute type\n"));
6694 		return (-1);
6695 	}
6696 
6697 	/* old security info + new attr header(8) + new attr */
6698 	oldsize = *secinfo_len;
6699 	*secinfo_len += newattrsize;
6700 	new_secinfo = (char *)malloc(*secinfo_len);
6701 	if (new_secinfo == NULL) {
6702 		(void) fprintf(stderr, gettext("can't allocate memory\n"));
6703 		*secinfo_len -= newattrsize;
6704 		free(attr);
6705 		return (-1);
6706 	}
6707 
6708 	(void) memcpy(new_secinfo, *secinfo, oldsize);
6709 	(void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6710 
6711 	free(*secinfo);
6712 	free(attr);
6713 	*secinfo = new_secinfo;
6714 	return (0);
6715 }
6716 
6717 /*
6718  * write_ancillary(): write out an ancillary file.
6719  *      The file has the same header as normal file except the type and size
6720  *      fields. The type is 'A' and size is the sum of all attributes
6721  *	in bytes.
6722  *	The body contains a list of attribute type, size and info. Currently,
6723  *	there is only ACL info.  This file is put before the normal file.
6724  */
6725 void
6726 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6727 {
6728 	long    blocks;
6729 	int	savflag;
6730 	int	savsize;
6731 
6732 	/* Just tranditional permissions or no security attribute info */
6733 	if (len == 0 || secinfo == NULL)
6734 		return;
6735 
6736 	/* save flag and size */
6737 	savflag = (dblockp->dbuf).typeflag;
6738 	(void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6739 
6740 	/* special flag for ancillary file */
6741 	if (hdrtype == _XATTR_HDRTYPE)
6742 		dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6743 	else
6744 		dblockp->dbuf.typeflag = 'A';
6745 
6746 	/* for pre-2.5 versions of tar, need to make sure */
6747 	/* the ACL file is readable			  */
6748 	(void) sprintf(dblock.dbuf.mode, "%07lo",
6749 	    (stbuf.st_mode & POSIXMODES) | 0000200);
6750 	(void) sprintf(dblockp->dbuf.size, "%011o", len);
6751 	(void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6752 
6753 	/* write out the header */
6754 	(void) writetbuf((char *)dblockp, 1);
6755 
6756 	/* write out security info */
6757 	blocks = TBLOCKS(len);
6758 	(void) writetbuf((char *)secinfo, (int)blocks);
6759 
6760 	/* restore mode, flag and size */
6761 	(void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6762 	dblockp->dbuf.typeflag = savflag;
6763 	(void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6764 }
6765 
6766 /*
6767  * Read the data record for extended headers and then the regular header.
6768  * The data are read into the buffer and then null-terminated.  Entries
6769  * for typeflag 'X' extended headers are of the format:
6770  * 	"%d %s=%s\n"
6771  *
6772  * When an extended header record is found, the extended header must
6773  * be processed and its values used to override the values in the
6774  * normal header.  The way this is done is to process the extended
6775  * header data record and set the data values, then call getdir
6776  * to process the regular header, then then to reconcile the two
6777  * sets of data.
6778  */
6779 
6780 static int
6781 get_xdata(void)
6782 {
6783 	struct keylist_pair {
6784 		int keynum;
6785 		char *keylist;
6786 	}	keylist_pair[] = {	_X_DEVMAJOR, "SUN.devmajor",
6787 					_X_DEVMINOR, "SUN.devminor",
6788 					_X_GID, "gid",
6789 					_X_GNAME, "gname",
6790 					_X_LINKPATH, "linkpath",
6791 					_X_PATH, "path",
6792 					_X_SIZE, "size",
6793 					_X_UID, "uid",
6794 					_X_UNAME, "uname",
6795 					_X_MTIME, "mtime",
6796 					_X_LAST, "NULL" };
6797 	char		*lineloc;
6798 	int		length, i;
6799 	char		*keyword, *value;
6800 	blkcnt_t	nblocks;
6801 	int		bufneeded;
6802 	int		errors;
6803 
6804 	(void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6805 	xhdr_count++;
6806 	errors = 0;
6807 
6808 	nblocks = TBLOCKS(stbuf.st_size);
6809 	bufneeded = nblocks * TBLOCK;
6810 	if (bufneeded >= xrec_size) {
6811 		free(xrec_ptr);
6812 		xrec_size = bufneeded + 1;
6813 		if ((xrec_ptr = malloc(xrec_size)) == NULL)
6814 			fatal(gettext("cannot allocate buffer"));
6815 	}
6816 
6817 	lineloc = xrec_ptr;
6818 
6819 	while (nblocks-- > 0) {
6820 		readtape(lineloc);
6821 		lineloc += TBLOCK;
6822 	}
6823 	lineloc = xrec_ptr;
6824 	xrec_ptr[stbuf.st_size] = '\0';
6825 	while (lineloc < xrec_ptr + stbuf.st_size) {
6826 		if (dblock.dbuf.typeflag == 'L') {
6827 			length = xrec_size;
6828 			keyword = "path";
6829 			value = lineloc;
6830 		} else {
6831 			length = atoi(lineloc);
6832 			*(lineloc + length - 1) = '\0';
6833 			keyword = strchr(lineloc, ' ') + 1;
6834 			value = strchr(keyword, '=') + 1;
6835 			*(value - 1) = '\0';
6836 		}
6837 		i = 0;
6838 		lineloc += length;
6839 		while (keylist_pair[i].keynum != (int)_X_LAST) {
6840 			if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6841 				break;
6842 			i++;
6843 		}
6844 		errno = 0;
6845 		switch (keylist_pair[i].keynum) {
6846 		case _X_DEVMAJOR:
6847 			Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6848 			if (errno) {
6849 				(void) fprintf(stderr, gettext(
6850 				    "tar: Extended header major value error "
6851 				    "for file # %llu.\n"), xhdr_count);
6852 				errors++;
6853 			} else
6854 				xhdr_flgs |= _X_DEVMAJOR;
6855 			break;
6856 		case _X_DEVMINOR:
6857 			Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6858 			if (errno) {
6859 				(void) fprintf(stderr, gettext(
6860 				    "tar: Extended header minor value error "
6861 				    "for file # %llu.\n"), xhdr_count);
6862 				errors++;
6863 			} else
6864 				xhdr_flgs |= _X_DEVMINOR;
6865 			break;
6866 		case _X_GID:
6867 			xhdr_flgs |= _X_GID;
6868 			Xtarhdr.x_gid = strtol(value, NULL, 0);
6869 			if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6870 				(void) fprintf(stderr, gettext(
6871 				    "tar: Extended header gid value error "
6872 				    "for file # %llu.\n"), xhdr_count);
6873 				Xtarhdr.x_gid = GID_NOBODY;
6874 			}
6875 			break;
6876 		case _X_GNAME:
6877 			if (utf8_local("gname", &Xtarhdr.x_gname,
6878 			    local_gname, value, _POSIX_NAME_MAX) == 0)
6879 				xhdr_flgs |= _X_GNAME;
6880 			break;
6881 		case _X_LINKPATH:
6882 			if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6883 			    local_linkpath, value, PATH_MAX) == 0)
6884 				xhdr_flgs |= _X_LINKPATH;
6885 			else
6886 				errors++;
6887 			break;
6888 		case _X_PATH:
6889 			if (utf8_local("path", &Xtarhdr.x_path,
6890 			    local_path, value, PATH_MAX) == 0)
6891 				xhdr_flgs |= _X_PATH;
6892 			else
6893 				errors++;
6894 			break;
6895 		case _X_SIZE:
6896 			Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6897 			if (errno) {
6898 				(void) fprintf(stderr, gettext(
6899 				    "tar: Extended header invalid filesize "
6900 				    "for file # %llu.\n"), xhdr_count);
6901 				errors++;
6902 			} else
6903 				xhdr_flgs |= _X_SIZE;
6904 			break;
6905 		case _X_UID:
6906 			xhdr_flgs |= _X_UID;
6907 			Xtarhdr.x_uid = strtol(value, NULL, 0);
6908 			if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6909 				(void) fprintf(stderr, gettext(
6910 				    "tar: Extended header uid value error "
6911 				    "for file # %llu.\n"), xhdr_count);
6912 				Xtarhdr.x_uid = UID_NOBODY;
6913 			}
6914 			break;
6915 		case _X_UNAME:
6916 			if (utf8_local("uname", &Xtarhdr.x_uname,
6917 			    local_uname, value, _POSIX_NAME_MAX) == 0)
6918 				xhdr_flgs |= _X_UNAME;
6919 			break;
6920 		case _X_MTIME:
6921 			get_xtime(value, &(Xtarhdr.x_mtime));
6922 			if (errno)
6923 				(void) fprintf(stderr, gettext(
6924 				    "tar: Extended header modification time "
6925 				    "value error for file # %llu.\n"),
6926 				    xhdr_count);
6927 			else
6928 				xhdr_flgs |= _X_MTIME;
6929 			break;
6930 		default:
6931 			(void) fprintf(stderr,
6932 			    gettext("tar:  unrecognized extended"
6933 			    " header keyword '%s'.  Ignored.\n"), keyword);
6934 			break;
6935 		}
6936 	}
6937 
6938 	getdir();	/* get regular header */
6939 	if (errors && errflag)
6940 		done(1);
6941 	else
6942 		if (errors)
6943 			Errflg = 1;
6944 	return (errors);
6945 }
6946 
6947 /*
6948  * load_info_from_xtarhdr - sets Gen and stbuf variables from
6949  *	extended header
6950  *	load_info_from_xtarhdr(flag, xhdrp);
6951  *	u_longlong_t flag;	xhdr_flgs
6952  *	struct xtar_hdr *xhdrp; pointer to extended header
6953  *	NOTE:	called when typeflag is not 'A' and xhdr_flgs
6954  *		is set.
6955  */
6956 static void
6957 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
6958 {
6959 	if (flag & _X_DEVMAJOR) {
6960 		Gen.g_devmajor = xhdrp->x_devmajor;
6961 	}
6962 	if (flag & _X_DEVMINOR) {
6963 		Gen.g_devminor = xhdrp->x_devminor;
6964 	}
6965 	if (flag & _X_GID) {
6966 		Gen.g_gid = xhdrp->x_gid;
6967 		stbuf.st_gid = xhdrp->x_gid;
6968 	}
6969 	if (flag & _X_UID) {
6970 		Gen.g_uid = xhdrp->x_uid;
6971 		stbuf.st_uid  = xhdrp->x_uid;
6972 	}
6973 	if (flag & _X_SIZE) {
6974 		Gen.g_filesz = xhdrp->x_filesz;
6975 		stbuf.st_size = xhdrp->x_filesz;
6976 	}
6977 	if (flag & _X_MTIME) {
6978 		Gen.g_mtime = xhdrp->x_mtime.tv_sec;
6979 		stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
6980 		stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
6981 	}
6982 }
6983 
6984 /*
6985  * gen_num creates a string from a keyword and an usigned long long in the
6986  * format:  %d %s=%s\n
6987  * This is part of the extended header data record.
6988  */
6989 
6990 void
6991 gen_num(const char *keyword, const u_longlong_t number)
6992 {
6993 	char	save_val[ULONGLONG_MAX_DIGITS + 1];
6994 	int	len;
6995 	char	*curr_ptr;
6996 
6997 	(void) sprintf(save_val, "%llu", number);
6998 	/*
6999 	 * len = length of entire line, including itself.  len will be
7000 	 * two digits.  So, add the string lengths plus the length of len,
7001 	 * plus a blank, an equal sign, and a newline.
7002 	 */
7003 	len = strlen(save_val) + strlen(keyword) + 5;
7004 	if (xrec_offset + len > xrec_size) {
7005 		if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7006 			fatal(gettext(
7007 			    "cannot allocate extended header buffer"));
7008 		xrec_ptr = curr_ptr;
7009 		xrec_size *= 2;
7010 	}
7011 	(void) sprintf(&xrec_ptr[xrec_offset],
7012 	    "%d %s=%s\n", len, keyword, save_val);
7013 	xrec_offset += len;
7014 }
7015 
7016 /*
7017  * gen_date creates a string from a keyword and a timestruc_t in the
7018  * format:  %d %s=%s\n
7019  * This is part of the extended header data record.
7020  * Currently, granularity is only microseconds, so the low-order three digits
7021  * will be truncated.
7022  */
7023 
7024 void
7025 gen_date(const char *keyword, const timestruc_t time_value)
7026 {
7027 	/* Allow for <seconds>.<nanoseconds>\n */
7028 	char	save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
7029 	int	len;
7030 	char	*curr_ptr;
7031 
7032 	(void) sprintf(save_val, "%ld", time_value.tv_sec);
7033 	len = strlen(save_val);
7034 	save_val[len] = '.';
7035 	(void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
7036 
7037 	/*
7038 	 * len = length of entire line, including itself.  len will be
7039 	 * two digits.  So, add the string lengths plus the length of len,
7040 	 * plus a blank, an equal sign, and a newline.
7041 	 */
7042 	len = strlen(save_val) + strlen(keyword) + 5;
7043 	if (xrec_offset + len > xrec_size) {
7044 		if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7045 			fatal(gettext(
7046 			    "cannot allocate extended header buffer"));
7047 		xrec_ptr = curr_ptr;
7048 		xrec_size *= 2;
7049 	}
7050 	(void) sprintf(&xrec_ptr[xrec_offset],
7051 	    "%d %s=%s\n", len, keyword, save_val);
7052 	xrec_offset += len;
7053 }
7054 
7055 /*
7056  * gen_string creates a string from a keyword and a char * in the
7057  * format:  %d %s=%s\n
7058  * This is part of the extended header data record.
7059  */
7060 
7061 void
7062 gen_string(const char *keyword, const char *value)
7063 {
7064 	int	len;
7065 	char	*curr_ptr;
7066 
7067 	/*
7068 	 * len = length of entire line, including itself.  The character length
7069 	 * of len must be 1-4 characters, because the maximum size of the path
7070 	 * or the name is PATH_MAX, which is 1024.  So, assume 1 character
7071 	 * for len, one for the space, one for the "=", and one for the newline.
7072 	 * Then adjust as needed.
7073 	 */
7074 	/* LINTED constant expression */
7075 	assert(PATH_MAX <= 9996);
7076 	len = strlen(value) + strlen(keyword) + 4;
7077 	if (len > 997)
7078 		len += 3;
7079 	else if (len > 98)
7080 		len += 2;
7081 	else if (len > 9)
7082 		len += 1;
7083 	if (xrec_offset + len > xrec_size) {
7084 		if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7085 			fatal(gettext(
7086 			    "cannot allocate extended header buffer"));
7087 		xrec_ptr = curr_ptr;
7088 		xrec_size *= 2;
7089 	}
7090 #ifdef XHDR_DEBUG
7091 	if (strcmp(keyword+1, "name") != 0)
7092 #endif
7093 	(void) sprintf(&xrec_ptr[xrec_offset],
7094 	    "%d %s=%s\n", len, keyword, value);
7095 #ifdef XHDR_DEBUG
7096 	else {
7097 	len += 11;
7098 	(void) sprintf(&xrec_ptr[xrec_offset],
7099 	    "%d %s=%snametoolong\n", len, keyword, value);
7100 	}
7101 #endif
7102 	xrec_offset += len;
7103 }
7104 
7105 /*
7106  * Convert time found in the extended header data to seconds and nanoseconds.
7107  */
7108 
7109 void
7110 get_xtime(char *value, timestruc_t *xtime)
7111 {
7112 	char nanosec[10];
7113 	char *period;
7114 	int i;
7115 
7116 	(void) memset(nanosec, '0', 9);
7117 	nanosec[9] = '\0';
7118 
7119 	period = strchr(value, '.');
7120 	if (period != NULL)
7121 		period[0] = '\0';
7122 	xtime->tv_sec = strtol(value, NULL, 10);
7123 	if (period == NULL)
7124 		xtime->tv_nsec = 0;
7125 	else {
7126 		i = strlen(period +1);
7127 		(void) strncpy(nanosec, period + 1, min(i, 9));
7128 		xtime->tv_nsec = strtol(nanosec, NULL, 10);
7129 	}
7130 }
7131 
7132 /*
7133  *	Check linkpath for length.
7134  *	Emit an error message and return 1 if too long.
7135  */
7136 
7137 int
7138 chk_path_build(
7139 	char	*name,
7140 	char	*longname,
7141 	char	*linkname,
7142 	char	*prefix,
7143 	char	type,
7144 	int	filetype)
7145 {
7146 
7147 	if (strlen(linkname) > (size_t)NAMSIZ) {
7148 		if (Eflag > 0) {
7149 			xhdr_flgs |= _X_LINKPATH;
7150 			Xtarhdr.x_linkpath = linkname;
7151 		} else {
7152 			(void) fprintf(stderr, gettext(
7153 			    "tar: %s: linked to %s\n"), longname, linkname);
7154 			(void) fprintf(stderr, gettext(
7155 			    "tar: %s: linked name too long\n"), linkname);
7156 			if (errflag)
7157 				done(1);
7158 			else
7159 				Errflg = 1;
7160 			return (1);
7161 		}
7162 	}
7163 	if (xhdr_flgs & _X_LINKPATH)
7164 		return (build_dblock(name, tchar, type,
7165 		    filetype, &stbuf, stbuf.st_dev,
7166 		    prefix));
7167 	else
7168 		return (build_dblock(name, linkname, type,
7169 		    filetype, &stbuf, stbuf.st_dev, prefix));
7170 }
7171 
7172 /*
7173  * Convert from UTF-8 to local character set.
7174  */
7175 
7176 static int
7177 utf8_local(
7178 	char		*option,
7179 	char		**Xhdr_ptrptr,
7180 	char		*target,
7181 	const char	*source,
7182 	int		max_val)
7183 {
7184 	static	iconv_t	iconv_cd;
7185 	char		*nl_target;
7186 	const	char	*iconv_src;
7187 	char		*iconv_trg;
7188 	size_t		inlen;
7189 	size_t		outlen;
7190 
7191 	if (charset_type == -1) {	/* iconv_open failed in earlier try */
7192 		(void) fprintf(stderr, gettext(
7193 		    "tar:  file # %llu: (%s) UTF-8 conversion failed.\n"),
7194 		    xhdr_count, source);
7195 		return (1);
7196 	} else if (charset_type == 0) {	/* iconv_open has not yet been done */
7197 		nl_target = nl_langinfo(CODESET);
7198 		if (strlen(nl_target) == 0)	/* locale using 7-bit codeset */
7199 			nl_target = "646";
7200 		if (strcmp(nl_target, "646") == 0)
7201 			charset_type = 1;
7202 		else if (strcmp(nl_target, "UTF-8") == 0)
7203 			charset_type = 3;
7204 		else {
7205 			if (strncmp(nl_target, "ISO", 3) == 0)
7206 				nl_target += 3;
7207 			charset_type = 2;
7208 			errno = 0;
7209 			if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7210 			    (iconv_t)-1) {
7211 				if (errno == EINVAL)
7212 					(void) fprintf(stderr, gettext(
7213 					    "tar: conversion routines not "
7214 					    "available for current locale.  "));
7215 				(void) fprintf(stderr, gettext(
7216 				    "file # %llu: (%s) UTF-8 conversion"
7217 				    " failed.\n"), xhdr_count, source);
7218 				charset_type = -1;
7219 				return (1);
7220 			}
7221 		}
7222 	}
7223 
7224 	/* locale using 7-bit codeset or UTF-8 locale */
7225 	if (charset_type == 1 || charset_type == 3) {
7226 		if (strlen(source) > max_val) {
7227 			(void) fprintf(stderr, gettext(
7228 			    "tar: file # %llu: Extended header %s too long.\n"),
7229 			    xhdr_count, option);
7230 			return (1);
7231 		}
7232 		if (charset_type == 3)
7233 			(void) strcpy(target, source);
7234 		else if (c_utf8(target, source) != 0) {
7235 			(void) fprintf(stderr, gettext(
7236 			    "tar:  file # %llu: (%s) UTF-8 conversion"
7237 			    " failed.\n"), xhdr_count, source);
7238 			return (1);
7239 		}
7240 		*Xhdr_ptrptr = target;
7241 		return (0);
7242 	}
7243 
7244 	iconv_src = source;
7245 	iconv_trg = target;
7246 	inlen = strlen(source);
7247 	outlen = max_val * UTF_8_FACTOR;
7248 	if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7249 	    (size_t)-1) {	/* Error occurred:  didn't convert */
7250 		(void) fprintf(stderr, gettext(
7251 		    "tar:  file # %llu: (%s) UTF-8 conversion failed.\n"),
7252 		    xhdr_count, source);
7253 		/* Get remaining output; reinitialize conversion descriptor */
7254 		iconv_src = (const char *)NULL;
7255 		inlen = 0;
7256 		(void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7257 		return (1);
7258 	}
7259 	/* Get remaining output; reinitialize conversion descriptor */
7260 	iconv_src = (const char *)NULL;
7261 	inlen = 0;
7262 	if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7263 	    (size_t)-1) {	/* Error occurred:  didn't convert */
7264 		(void) fprintf(stderr, gettext(
7265 		    "tar:  file # %llu: (%s) UTF-8 conversion failed.\n"),
7266 		    xhdr_count, source);
7267 		return (1);
7268 	}
7269 
7270 	*iconv_trg = '\0';	/* Null-terminate iconv output string */
7271 	if (strlen(target) > max_val) {
7272 		(void) fprintf(stderr, gettext(
7273 		    "tar: file # %llu: Extended header %s too long.\n"),
7274 		    xhdr_count, option);
7275 		return (1);
7276 	}
7277 	*Xhdr_ptrptr = target;
7278 	return (0);
7279 }
7280 
7281 /*
7282  * Check gname, uname, path, and linkpath to see if they need to go in an
7283  * extended header.  If they are already slated to be in an extended header,
7284  * or if they are not ascii, then they need to be in the extended header.
7285  * Then, convert all extended names to UTF-8.
7286  */
7287 
7288 int
7289 gen_utf8_names(const char *filename)
7290 {
7291 	static	iconv_t	iconv_cd;
7292 	char		*nl_target;
7293 	char		tempbuf[MAXNAM + 1];
7294 	int		nbytes;
7295 	int		errors;
7296 
7297 	if (charset_type == -1)	{	/* Previous failure to open. */
7298 		(void) fprintf(stderr, gettext(
7299 		    "tar: file # %llu: UTF-8 conversion failed.\n"),
7300 		    xhdr_count);
7301 		return (1);
7302 	}
7303 
7304 	if (charset_type == 0) {	/* Need to get conversion descriptor */
7305 		nl_target = nl_langinfo(CODESET);
7306 		if (strlen(nl_target) == 0)	/* locale using 7-bit codeset */
7307 			nl_target = "646";
7308 		if (strcmp(nl_target, "646") == 0)
7309 			charset_type = 1;
7310 		else if (strcmp(nl_target, "UTF-8") == 0)
7311 			charset_type = 3;
7312 		else {
7313 			if (strncmp(nl_target, "ISO", 3) == 0)
7314 				nl_target += 3;
7315 			charset_type = 2;
7316 			errno = 0;
7317 #ifdef ICONV_DEBUG
7318 			(void) fprintf(stderr,
7319 			    gettext("Opening iconv_cd with target %s\n"),
7320 			    nl_target);
7321 #endif
7322 			if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7323 			    (iconv_t)-1) {
7324 				if (errno == EINVAL)
7325 					(void) fprintf(stderr, gettext(
7326 					    "tar: conversion routines not "
7327 					    "available for current locale.  "));
7328 				(void) fprintf(stderr, gettext(
7329 				    "file (%s): UTF-8 conversion failed.\n"),
7330 				    filename);
7331 				charset_type = -1;
7332 				return (1);
7333 			}
7334 		}
7335 	}
7336 
7337 	errors = 0;
7338 
7339 	errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7340 	    dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7341 	errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7342 	    dblock.dbuf.uname, iconv_cd, _X_UNAME,  _POSIX_NAME_MAX);
7343 	if ((xhdr_flgs & _X_LINKPATH) == 0) {	/* Need null-terminated str. */
7344 		(void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7345 		tempbuf[NAMSIZ] = '\0';
7346 	}
7347 	errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7348 	    tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7349 	if ((xhdr_flgs & _X_PATH) == 0) {	/* Concatenate prefix & name */
7350 		(void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7351 		tempbuf[PRESIZ] = '\0';
7352 		nbytes = strlen(tempbuf);
7353 		if (nbytes > 0) {
7354 			tempbuf[nbytes++] = '/';
7355 			tempbuf[nbytes] = '\0';
7356 		}
7357 		(void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7358 		    (MAXNAM - nbytes));
7359 		tempbuf[MAXNAM] = '\0';
7360 	}
7361 	errors += local_utf8(&Xtarhdr.x_path, local_path,
7362 	    tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7363 
7364 	if (errors > 0)
7365 		(void) fprintf(stderr, gettext(
7366 		    "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7367 
7368 	if (errors && errflag)
7369 		done(1);
7370 	else
7371 		if (errors)
7372 			Errflg = 1;
7373 	return (errors);
7374 }
7375 
7376 static int
7377 local_utf8(
7378 		char	**Xhdr_ptrptr,
7379 		char	*target,
7380 		const	char	*source,
7381 		iconv_t	iconv_cd,
7382 		int	xhdrflg,
7383 		int	max_val)
7384 {
7385 	const	char	*iconv_src;
7386 	const	char	*starting_src;
7387 	char		*iconv_trg;
7388 	size_t		inlen;
7389 	size_t		outlen;
7390 #ifdef ICONV_DEBUG
7391 	unsigned char	c_to_hex;
7392 #endif
7393 
7394 	/*
7395 	 * If the item is already slated for extended format, get the string
7396 	 * to convert from the extended header record.  Otherwise, get it from
7397 	 * the regular (dblock) area.
7398 	 */
7399 	if (xhdr_flgs & xhdrflg) {
7400 		if (charset_type == 3) {	/* Already UTF-8, just copy */
7401 			(void) strcpy(target, *Xhdr_ptrptr);
7402 			*Xhdr_ptrptr = target;
7403 			return (0);
7404 		} else
7405 			iconv_src = (const char *) *Xhdr_ptrptr;
7406 	} else {
7407 		if (charset_type == 3)		/* Already in UTF-8 format */
7408 			return (0);		/* Don't create xhdr record */
7409 		iconv_src = source;
7410 	}
7411 	starting_src = iconv_src;
7412 	iconv_trg = target;
7413 	if ((inlen = strlen(iconv_src)) == 0)
7414 		return (0);
7415 
7416 	if (charset_type == 1) {	/* locale using 7-bit codeset */
7417 		if (c_utf8(target, starting_src) != 0) {
7418 			(void) fprintf(stderr,
7419 			    gettext("tar: invalid character in"
7420 			    " UTF-8 conversion of '%s'\n"), starting_src);
7421 			return (1);
7422 		}
7423 		return (0);
7424 	}
7425 
7426 	outlen = max_val * UTF_8_FACTOR;
7427 	errno = 0;
7428 	if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7429 	    (size_t)-1) {
7430 		/* An error occurred, or not all characters were converted */
7431 		if (errno == EILSEQ)
7432 			(void) fprintf(stderr,
7433 			    gettext("tar: invalid character in"
7434 			    " UTF-8 conversion of '%s'\n"), starting_src);
7435 		else
7436 			(void) fprintf(stderr, gettext(
7437 			    "tar: conversion to UTF-8 aborted for '%s'.\n"),
7438 			    starting_src);
7439 		/* Get remaining output; reinitialize conversion descriptor */
7440 		iconv_src = (const char *)NULL;
7441 		inlen = 0;
7442 		(void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7443 		return (1);
7444 	}
7445 	/* Get remaining output; reinitialize conversion descriptor */
7446 	iconv_src = (const char *)NULL;
7447 	inlen = 0;
7448 	if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7449 	    (size_t)-1) {	/* Error occurred:  didn't convert */
7450 		if (errno == EILSEQ)
7451 			(void) fprintf(stderr,
7452 			    gettext("tar: invalid character in"
7453 			    " UTF-8 conversion of '%s'\n"), starting_src);
7454 		else
7455 			(void) fprintf(stderr, gettext(
7456 			    "tar: conversion to UTF-8 aborted for '%s'.\n"),
7457 			    starting_src);
7458 		return (1);
7459 	}
7460 
7461 	*iconv_trg = '\0';	/* Null-terminate iconv output string */
7462 	if (strcmp(starting_src, target) != 0) {
7463 		*Xhdr_ptrptr = target;
7464 		xhdr_flgs |= xhdrflg;
7465 #ifdef ICONV_DEBUG
7466 		(void) fprintf(stderr, "***  inlen: %d %d; outlen: %d %d\n",
7467 		    strlen(starting_src), inlen, max_val, outlen);
7468 		(void) fprintf(stderr, "Input string:\n  ");
7469 		for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7470 			c_to_hex = (unsigned char)starting_src[inlen];
7471 			(void) fprintf(stderr, " %2.2x", c_to_hex);
7472 			if (inlen % 20 == 19)
7473 				(void) fprintf(stderr, "\n  ");
7474 		}
7475 		(void) fprintf(stderr, "\nOutput string:\n  ");
7476 		for (inlen = 0; inlen < strlen(target); inlen++) {
7477 			c_to_hex = (unsigned char)target[inlen];
7478 			(void) fprintf(stderr, " %2.2x", c_to_hex);
7479 			if (inlen % 20 == 19)
7480 				(void) fprintf(stderr, "\n  ");
7481 		}
7482 		(void) fprintf(stderr, "\n");
7483 #endif
7484 	}
7485 
7486 	return (0);
7487 }
7488 
7489 /*
7490  *	Function to test each byte of the source string to make sure it is
7491  *	in within bounds (value between 0 and 127).
7492  *	If valid, copy source to target.
7493  */
7494 
7495 int
7496 c_utf8(char *target, const char *source)
7497 {
7498 	size_t		len;
7499 	const char	*thischar;
7500 
7501 	len = strlen(source);
7502 	thischar = source;
7503 	while (len-- > 0) {
7504 		if (!isascii((int)(*thischar++)))
7505 			return (1);
7506 	}
7507 
7508 	(void) strcpy(target, source);
7509 	return (0);
7510 }
7511 
7512 
7513 #if defined(O_XATTR)
7514 #define	ROUNDTOTBLOCK(a)	((a + (TBLOCK -1)) & ~(TBLOCK -1))
7515 
7516 static void
7517 prepare_xattr(
7518 	char		**attrbuf,
7519 	char		*filename,
7520 	char		*attrpath,
7521 	char		typeflag,
7522 	struct linkbuf	*linkinfo,
7523 	int		*rlen)
7524 {
7525 	char			*bufhead;	/* ptr to full buffer */
7526 	char			*aptr;
7527 	struct xattr_hdr 	*hptr;		/* ptr to header in bufhead */
7528 	struct xattr_buf	*tptr;		/* ptr to pathing pieces */
7529 	int			totalen;	/* total buffer length */
7530 	int			len;		/* length returned to user */
7531 	int			stringlen;	/* length of filename + attr */
7532 						/*
7533 						 * length of filename + attr
7534 						 * in link section
7535 						 */
7536 	int			linkstringlen;
7537 	int			complen;	/* length of pathing section */
7538 	int			linklen;	/* length of link section */
7539 	int			attrnames_index; /* attrnames starting index */
7540 
7541 	/*
7542 	 * Release previous buffer
7543 	 */
7544 
7545 	if (*attrbuf != (char *)NULL) {
7546 		free(*attrbuf);
7547 		*attrbuf = NULL;
7548 	}
7549 
7550 	/*
7551 	 * First add in fixed size stuff
7552 	 */
7553 	len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7554 
7555 	/*
7556 	 * Add space for two nulls
7557 	 */
7558 	stringlen = strlen(attrpath) + strlen(filename) + 2;
7559 	complen = stringlen + sizeof (struct xattr_buf);
7560 
7561 	len += stringlen;
7562 
7563 	/*
7564 	 * Now add on space for link info if any
7565 	 */
7566 
7567 	if (linkinfo != NULL) {
7568 		/*
7569 		 * Again add space for two nulls
7570 		 */
7571 		linkstringlen = strlen(linkinfo->pathname) +
7572 		    strlen(linkinfo->attrname) + 2;
7573 		linklen = linkstringlen + sizeof (struct xattr_buf);
7574 		len += linklen;
7575 	} else {
7576 		linklen = 0;
7577 	}
7578 
7579 	/*
7580 	 * Now add padding to end to fill out TBLOCK
7581 	 *
7582 	 * Function returns size of real data and not size + padding.
7583 	 */
7584 
7585 	totalen = ROUNDTOTBLOCK(len);
7586 
7587 	if ((bufhead = calloc(1, totalen)) == NULL) {
7588 		fatal(gettext("Out of memory."));
7589 	}
7590 
7591 
7592 	/*
7593 	 * Now we can fill in the necessary pieces
7594 	 */
7595 
7596 	/*
7597 	 * first fill in the fixed header
7598 	 */
7599 	hptr = (struct xattr_hdr *)bufhead;
7600 	(void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7601 	(void) sprintf(hptr->h_component_len, "%0*d",
7602 	    sizeof (hptr->h_component_len) - 1, complen);
7603 	(void) sprintf(hptr->h_link_component_len, "%0*d",
7604 	    sizeof (hptr->h_link_component_len) - 1, linklen);
7605 	(void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7606 
7607 	/*
7608 	 * Now fill in the filename + attrnames section
7609 	 * The filename and attrnames section can be composed of two or more
7610 	 * path segments separated by a null character.  The first segment
7611 	 * is the path to the parent file that roots the entire sequence in
7612 	 * the normal name space. The remaining segments describes a path
7613 	 * rooted at the hidden extended attribute directory of the leaf file of
7614 	 * the previous segment, making it possible to name attributes on
7615 	 * attributes.  Thus, if we are just archiving an extended attribute,
7616 	 * the second segment will contain the attribute name.  If we are
7617 	 * archiving a system attribute of an extended attribute, then the
7618 	 * second segment will contain the attribute name, and a third segment
7619 	 * will contain the system attribute name.  The attribute pathing
7620 	 * information is obtained from 'attrpath'.
7621 	 */
7622 
7623 	tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7624 	(void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7625 	    stringlen);
7626 	(void) strcpy(tptr->h_names, filename);
7627 	attrnames_index = strlen(filename) + 1;
7628 	(void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7629 	tptr->h_typeflag = typeflag;
7630 
7631 	/*
7632 	 * Split the attrnames section into two segments if 'attrpath'
7633 	 * contains pathing information for a system attribute of an
7634 	 * extended attribute.  We split them by replacing the '/' with
7635 	 * a '\0'.
7636 	 */
7637 	if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7638 		*aptr = '\0';
7639 	}
7640 
7641 	/*
7642 	 * Now fill in the optional link section if we have one
7643 	 */
7644 
7645 	if (linkinfo != (struct linkbuf *)NULL) {
7646 		tptr = (struct xattr_buf *)(bufhead +
7647 		    sizeof (struct xattr_hdr) + complen);
7648 
7649 		(void) sprintf(tptr->h_namesz, "%0*d",
7650 		    sizeof (tptr->h_namesz) - 1, linkstringlen);
7651 		(void) strcpy(tptr->h_names, linkinfo->pathname);
7652 		(void) strcpy(
7653 		    &tptr->h_names[strlen(linkinfo->pathname) + 1],
7654 		    linkinfo->attrname);
7655 		tptr->h_typeflag = typeflag;
7656 	}
7657 	*attrbuf = (char *)bufhead;
7658 	*rlen = len;
7659 }
7660 
7661 #else
7662 static void
7663 prepare_xattr(
7664 	char		**attrbuf,
7665 	char		*filename,
7666 	char		*attrname,
7667 	char		typeflag,
7668 	struct linkbuf	*linkinfo,
7669 	int		*rlen)
7670 {
7671 	*attrbuf = NULL;
7672 	*rlen = 0;
7673 }
7674 #endif
7675 
7676 int
7677 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7678 {
7679 
7680 	int i, j;
7681 	int	printerr;
7682 	int	slnkerr;
7683 	struct stat symlnbuf;
7684 
7685 	if (!hflag)
7686 		i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7687 	else
7688 		i = fstatat(dirfd, shortname, &stbuf, 0);
7689 
7690 	if (i < 0) {
7691 		/* Initialize flag to print error mesg. */
7692 		printerr = 1;
7693 		/*
7694 		 * If stat is done, then need to do lstat
7695 		 * to determine whether it's a sym link
7696 		 */
7697 		if (hflag) {
7698 			/* Save returned error */
7699 			slnkerr = errno;
7700 
7701 			j = fstatat(dirfd, shortname,
7702 			    &symlnbuf, AT_SYMLINK_NOFOLLOW);
7703 			/*
7704 			 * Suppress error message when file is a symbolic link
7705 			 * and function modifier 'l' is off.  Exception:  when
7706 			 * a symlink points to a symlink points to a
7707 			 * symlink ... and we get past MAXSYMLINKS.  That
7708 			 * error will cause a file not to be archived, and
7709 			 * needs to be printed.
7710 			 */
7711 			if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7712 			    (S_ISLNK(symlnbuf.st_mode)))
7713 				printerr = 0;
7714 
7715 			/*
7716 			 * Restore errno in case the lstat
7717 			 * on symbolic link change
7718 			 */
7719 			errno = slnkerr;
7720 		}
7721 
7722 		if (printerr) {
7723 			(void) fprintf(stderr, gettext(
7724 			    "tar: %s%s%s%s: %s\n"),
7725 			    (attrparent == NULL) ? "" : gettext("attribute "),
7726 			    (attrparent == NULL) ? "" : attrparent,
7727 			    (attrparent == NULL) ? "" : gettext(" of "),
7728 			    longname, strerror(errno));
7729 			Errflg = 1;
7730 		}
7731 		return (1);
7732 	}
7733 	return (0);
7734 }
7735 
7736 /*
7737  * Recursively archive the extended attributes and/or extended system attributes
7738  * of the base file, longname.  Note:  extended system attribute files will be
7739  * archived only if the extended system attributes are not transient (i.e. the
7740  * extended system attributes are other than the default values).
7741  *
7742  * If -@ was specified and the underlying file system supports it, archive the
7743  * extended attributes, and if there is a system attribute associated with the
7744  * extended attribute, then recursively call xattrs_put() to archive the
7745  * hidden attribute directory and the extended system attribute.  If -/ was
7746  * specified and the underlying file system supports it, archive the extended
7747  * system attributes.  Read-only extended system attributes are never archived.
7748  *
7749  * Currently, there cannot be attributes on attributes; only system
7750  * attributes on attributes.  In addition, there cannot be attributes on
7751  * system attributes.  A file and it's attribute directory hierarchy looks as
7752  * follows:
7753  *	longname ---->	.	("." is the hidden attribute directory)
7754  *			|
7755  *	     ----------------------------
7756  *	     |				|
7757  *	<sys_attr_name>		   <attr_name> ---->	.
7758  *							|
7759  *						  <sys_attr_name>
7760  *
7761  */
7762 #if defined(O_XATTR)
7763 static void
7764 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7765 {
7766 	char *filename = (attrparent == NULL) ? shortname : attrparent;
7767 	int arc_rwsysattr = 0;
7768 	int dirfd;
7769 	int fd = -1;
7770 	int rw_sysattr = 0;
7771 	int ext_attr = 0;
7772 	int rc;
7773 	DIR *dirp;
7774 	struct dirent *dp;
7775 	attr_data_t *attrinfo = NULL;
7776 
7777 	/*
7778 	 * If the underlying file system supports it, then archive the extended
7779 	 * attributes if -@ was specified, and the extended system attributes
7780 	 * if -/ was specified.
7781 	 */
7782 	if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7783 	    &ext_attr) != ATTR_OK) {
7784 		return;
7785 	}
7786 
7787 	/*
7788 	 * Only want to archive a read-write extended system attribute file
7789 	 * if it contains extended system attribute settings that are not the
7790 	 * default values.
7791 	 */
7792 #if defined(_PC_SATTR_ENABLED)
7793 	if (saflag) {
7794 		int	filefd;
7795 		nvlist_t *slist = NULL;
7796 
7797 		/* Determine if there are non-transient system attributes */
7798 		errno = 0;
7799 		if ((filefd = open(filename, O_RDONLY)) == -1) {
7800 			if (attrparent == NULL) {
7801 				vperror(0, gettext(
7802 				    "unable to open file %s"), longname);
7803 			}
7804 			return;
7805 		}
7806 		if (((slist = sysattr_list(basename(myname), filefd,
7807 		    filename)) != NULL) || (errno != 0)) {
7808 			arc_rwsysattr = 1;
7809 		}
7810 		if (slist != NULL) {
7811 			(void) nvlist_free(slist);
7812 			slist = NULL;
7813 		}
7814 		(void) close(filefd);
7815 	}
7816 
7817 	/*
7818 	 * If we aren't archiving extended system attributes, and we are
7819 	 * processing an attribute, or if we are archiving extended system
7820 	 * attributes, and there are are no extended attributes, then there's
7821 	 * no need to open up the attribute directory of the file unless the
7822 	 * extended system attributes are not transient (i.e, the system
7823 	 * attributes are not the default values).
7824 	 */
7825 	if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7826 	    (saflag && !ext_attr))) {
7827 		return;
7828 	}
7829 #endif	/* _PC_SATTR_ENABLED */
7830 
7831 	/* open the parent attribute directory */
7832 	fd = attropen(filename, ".", O_RDONLY);
7833 	if (fd < 0) {
7834 		vperror(0, gettext(
7835 		    "unable to open attribute directory for %s%s%sfile %s"),
7836 		    (attrparent == NULL) ? "" : gettext("attribute "),
7837 		    (attrparent == NULL) ? "" : attrparent,
7838 		    (attrparent == NULL) ? "" : gettext(" of "),
7839 		    longname);
7840 		return;
7841 	}
7842 
7843 	/*
7844 	 * We need to change into the parent's attribute directory to determine
7845 	 * if each of the attributes should be archived.
7846 	 */
7847 	if (fchdir(fd) < 0) {
7848 		vperror(0, gettext(
7849 		    "cannot change to attribute directory of %s%s%sfile %s"),
7850 		    (attrparent == NULL) ? "" : gettext("attribute "),
7851 		    (attrparent == NULL) ? "" : attrparent,
7852 		    (attrparent == NULL) ? "" : gettext(" of "),
7853 		    longname);
7854 		(void) close(fd);
7855 		return;
7856 	}
7857 
7858 	if (((dirfd = dup(fd)) == -1) ||
7859 	    ((dirp = fdopendir(dirfd)) == NULL)) {
7860 		(void) fprintf(stderr, gettext(
7861 		    "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7862 		    (attrparent == NULL) ? "" : gettext("attribute "),
7863 		    (attrparent == NULL) ? "" : attrparent,
7864 		    (attrparent == NULL) ? "" : gettext(" of "),
7865 		    longname);
7866 		if (fd > 0) {
7867 			(void) close(fd);
7868 		}
7869 		return;
7870 	}
7871 
7872 	while (dp = readdir(dirp)) {
7873 		if (strcmp(dp->d_name, "..") == 0) {
7874 			continue;
7875 		} else if (strcmp(dp->d_name, ".") == 0) {
7876 			Hiddendir = 1;
7877 		} else {
7878 			Hiddendir = 0;
7879 		}
7880 
7881 		/* Determine if this attribute should be archived */
7882 		if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7883 		    &rw_sysattr) != ATTR_OK) {
7884 			continue;
7885 		}
7886 
7887 		/* gather the attribute's information to pass to putfile() */
7888 		if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7889 		    fd, rw_sysattr, &attrinfo)) == 1) {
7890 			continue;
7891 		}
7892 
7893 		/* add the attribute to the archive */
7894 		rc = putfile(longname, dp->d_name, parent, attrinfo,
7895 		    XATTR_FILE, LEV0, SYMLINK_LEV0);
7896 
7897 		if (exitflag) {
7898 			break;
7899 		}
7900 
7901 #if defined(_PC_SATTR_ENABLED)
7902 		/*
7903 		 * If both -/ and -@ were specified, then archive the
7904 		 * attribute's extended system attributes and hidden directory
7905 		 * by making a recursive call to xattrs_put().
7906 		 */
7907 		if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7908 		    (Hiddendir == 0)) {
7909 
7910 			xattrs_put(longname, shortname, parent, dp->d_name);
7911 
7912 			/*
7913 			 * Change back to the parent's attribute directory
7914 			 * to process any further attributes.
7915 			 */
7916 			if (fchdir(fd) < 0) {
7917 				vperror(0, gettext(
7918 				    "cannot change back to attribute directory "
7919 				    "of file %s"), longname);
7920 				break;
7921 			}
7922 		}
7923 #endif	/* _PC_SATTR_ENABLED */
7924 	}
7925 
7926 	if (attrinfo != NULL) {
7927 		if (attrinfo->attr_parent != NULL) {
7928 			free(attrinfo->attr_parent);
7929 		}
7930 		free(attrinfo->attr_path);
7931 		free(attrinfo);
7932 	}
7933 	(void) closedir(dirp);
7934 	if (fd != -1) {
7935 		(void) close(fd);
7936 	}
7937 
7938 	/* Change back to the parent directory of the base file */
7939 	if (attrparent == NULL) {
7940 		(void) tar_chdir(parent);
7941 	}
7942 	Hiddendir = 0;
7943 }
7944 #else
7945 static void
7946 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
7947 {
7948 }
7949 #endif /* O_XATTR */
7950 
7951 static int
7952 put_link(char *name, char *longname, char *component, char *longattrname,
7953     char *prefix, int filetype, char type)
7954 {
7955 
7956 	if (stbuf.st_nlink > 1) {
7957 		struct linkbuf *lp;
7958 		int found = 0;
7959 
7960 		for (lp = ihead; lp != NULL; lp = lp->nextp)
7961 			if (lp->inum == stbuf.st_ino &&
7962 			    lp->devnum == stbuf.st_dev) {
7963 				found++;
7964 				break;
7965 			}
7966 		if (found) {
7967 #if defined(O_XATTR)
7968 			if (filetype == XATTR_FILE)
7969 				if (put_xattr_hdr(longname, component,
7970 				    longattrname, prefix, type, filetype, lp)) {
7971 					goto out;
7972 			}
7973 #endif
7974 			stbuf.st_size = (off_t)0;
7975 			if (filetype != XATTR_FILE) {
7976 				tomodes(&stbuf);
7977 				if (chk_path_build(name, longname, lp->pathname,
7978 				    prefix, type, filetype) > 0) {
7979 					goto out;
7980 				}
7981 			}
7982 
7983 			if (mulvol && tapepos + 1 >= blocklim)
7984 				newvol();
7985 			(void) writetbuf((char *)&dblock, 1);
7986 			/*
7987 			 * write_ancillary() is not needed here.
7988 			 * The first link is handled in the following
7989 			 * else statement. No need to process ACLs
7990 			 * for other hard links since they are the
7991 			 * same file.
7992 			 */
7993 
7994 			if (vflag) {
7995 #ifdef DEBUG
7996 				if (NotTape)
7997 					DEBUG("seek = %" FMT_blkcnt_t
7998 					    "K\t", K(tapepos), 0);
7999 #endif
8000 				if (filetype == XATTR_FILE) {
8001 					(void) fprintf(vfile, gettext(
8002 					    "a %s attribute %s link to "
8003 					    "%s attribute %s\n"),
8004 					    name, component, name,
8005 					    lp->attrname);
8006 				} else {
8007 					(void) fprintf(vfile, gettext(
8008 					    "a %s link to %s\n"),
8009 					    longname, lp->pathname);
8010 				}
8011 			}
8012 			lp->count--;
8013 			return (0);
8014 		} else {
8015 			lp = (struct linkbuf *)getmem(sizeof (*lp));
8016 			if (lp != (struct linkbuf *)NULL) {
8017 				lp->nextp = ihead;
8018 				ihead = lp;
8019 				lp->inum = stbuf.st_ino;
8020 				lp->devnum = stbuf.st_dev;
8021 				lp->count = stbuf.st_nlink - 1;
8022 				if (filetype == XATTR_FILE) {
8023 					(void) strcpy(lp->pathname, longname);
8024 					(void) strcpy(lp->attrname,
8025 					    component);
8026 				} else {
8027 					(void) strcpy(lp->pathname, longname);
8028 					(void) strcpy(lp->attrname, "");
8029 				}
8030 			}
8031 		}
8032 	}
8033 
8034 out:
8035 	return (1);
8036 }
8037 
8038 static int
8039 put_extra_attributes(char *longname, char *shortname, char *longattrname,
8040     char *prefix, int filetype, char typeflag)
8041 {
8042 	static acl_t *aclp = NULL;
8043 	int error;
8044 
8045 	if (aclp != NULL) {
8046 		acl_free(aclp);
8047 		aclp = NULL;
8048 	}
8049 #if defined(O_XATTR)
8050 	if ((atflag || saflag) && (filetype == XATTR_FILE)) {
8051 		if (put_xattr_hdr(longname, shortname, longattrname, prefix,
8052 		    typeflag, filetype, NULL)) {
8053 			return (1);
8054 		}
8055 	}
8056 #endif
8057 
8058 	/* ACL support */
8059 	if (pflag) {
8060 		char	*secinfo = NULL;
8061 		int	len = 0;
8062 
8063 		/* ACL support */
8064 		if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
8065 			/*
8066 			 * Get ACL info: dont bother allocating space if
8067 			 * there is only a trivial ACL.
8068 			 */
8069 			if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8070 			    &aclp)) != 0) {
8071 				(void) fprintf(stderr, gettext(
8072 				    "%s: failed to retrieve acl : %s\n"),
8073 				    longname, acl_strerror(error));
8074 				return (1);
8075 			}
8076 		}
8077 
8078 		/* append security attributes if any */
8079 		if (aclp != NULL) {
8080 			(void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8081 			    acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8082 			    ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8083 			    UFSD_ACL : ACE_ACL);
8084 		}
8085 
8086 		if (Tflag) {
8087 			/* append Trusted Extensions extended attributes */
8088 			append_ext_attr(shortname, &secinfo, &len);
8089 			(void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8090 
8091 		} else if (aclp != NULL) {
8092 			(void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8093 		}
8094 	}
8095 	return (0);
8096 }
8097 
8098 #if defined(O_XATTR)
8099 static int
8100 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8101 	int typeflag, int filetype, struct linkbuf *lp)
8102 {
8103 	char *lname = NULL;
8104 	char *sname = NULL;
8105 	int  error = 0;
8106 	static char *attrbuf = NULL;
8107 	int attrlen;
8108 
8109 	lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8110 	    strlen(shortname) + strlen(".hdr") + 1);
8111 
8112 	if (lname == NULL) {
8113 		fatal(gettext("Out of Memory."));
8114 	}
8115 	sname = malloc(sizeof (char) * strlen(shortname) +
8116 	    strlen(".hdr") + 1);
8117 	if (sname == NULL) {
8118 		fatal(gettext("Out of Memory."));
8119 	}
8120 
8121 	(void) sprintf(sname, "%s.hdr", shortname);
8122 	(void) sprintf(lname, "/dev/null/%s", sname);
8123 
8124 	if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8125 	    sizeof (dblock.dbuf.name)) {
8126 		fatal(gettext(
8127 		    "Buffer overflow writing extended attribute file name"));
8128 	}
8129 
8130 	/*
8131 	 * dump extended attr lookup info
8132 	 */
8133 	prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8134 	write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8135 
8136 	(void) sprintf(lname, "/dev/null/%s", shortname);
8137 	(void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8138 
8139 	/*
8140 	 * Set up filename for attribute
8141 	 */
8142 
8143 	error = build_dblock(lname, tchar, '0', filetype,
8144 	    &stbuf, stbuf.st_dev, prefix);
8145 	free(lname);
8146 	free(sname);
8147 
8148 	return (error);
8149 }
8150 #endif
8151 
8152 #if defined(O_XATTR)
8153 static int
8154 read_xattr_hdr(attr_data_t **attrinfo)
8155 {
8156 	char		buf[TBLOCK];
8157 	char		*attrparent = NULL;
8158 	blkcnt_t	blocks;
8159 	char		*tp;
8160 	off_t		bytes;
8161 	int		comp_len, link_len;
8162 	int		namelen;
8163 	int		attrparentlen;
8164 	int		parentfilelen;
8165 
8166 	if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8167 		return (1);
8168 
8169 	bytes = stbuf.st_size;
8170 	if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8171 		(void) fprintf(stderr, gettext(
8172 		    "Insufficient memory for extended attribute\n"));
8173 		return (1);
8174 	}
8175 
8176 	tp = (char *)xattrhead;
8177 	blocks = TBLOCKS(bytes);
8178 	while (blocks-- > 0) {
8179 		readtape(buf);
8180 		if (bytes <= TBLOCK) {
8181 			(void) memcpy(tp, buf, (size_t)bytes);
8182 			break;
8183 		} else {
8184 			(void) memcpy(tp, buf, TBLOCK);
8185 			tp += TBLOCK;
8186 		}
8187 		bytes -= TBLOCK;
8188 	}
8189 
8190 	/*
8191 	 * Validate that we can handle header format
8192 	 */
8193 	if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8194 		(void) fprintf(stderr,
8195 		    gettext("Unknown extended attribute format encountered\n"));
8196 		(void) fprintf(stderr,
8197 		    gettext("Disabling extended attribute parsing\n"));
8198 		xattrbadhead = 1;
8199 		return (0);
8200 	}
8201 	(void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8202 	(void) sscanf(xattrhead->h_link_component_len,	"%10d", &link_len);
8203 	xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8204 	    sizeof (struct xattr_hdr));
8205 	(void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8206 	if (link_len > 0)
8207 		xattr_linkp = (struct xattr_buf *)
8208 		    ((int)xattrp + (int)comp_len);
8209 	else
8210 		xattr_linkp = NULL;
8211 
8212 	/*
8213 	 * Gather the attribute path from the filename and attrnames section.
8214 	 * The filename and attrnames section can be composed of two or more
8215 	 * path segments separated by a null character.  The first segment
8216 	 * is the path to the parent file that roots the entire sequence in
8217 	 * the normal name space. The remaining segments describes a path
8218 	 * rooted at the hidden extended attribute directory of the leaf file of
8219 	 * the previous segment, making it possible to name attributes on
8220 	 * attributes.
8221 	 */
8222 	parentfilelen = strlen(xattrp->h_names);
8223 	xattrapath = xattrp->h_names + parentfilelen + 1;
8224 	if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8225 		/*
8226 		 * The attrnames section contains a system attribute on an
8227 		 * attribute.  Save the name of the attribute for use later,
8228 		 * and replace the null separating the attribute name from
8229 		 * the system attribute name with a '/' so that xattrapath can
8230 		 * be used to display messages with the full attribute path name
8231 		 * rooted at the hidden attribute directory of the base file
8232 		 * in normal name space.
8233 		 */
8234 		attrparent = strdup(xattrapath);
8235 		attrparentlen = strlen(attrparent);
8236 		xattrapath[attrparentlen] = '/';
8237 	}
8238 	if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8239 	    xattrapath + attrparentlen + 1, xattrapath, attrparent,
8240 	    -1, 0, attrinfo)) == 1) {
8241 		free(attrparent);
8242 		return (1);
8243 	}
8244 
8245 	/* Gather link info */
8246 	if (xattr_linkp) {
8247 		xattr_linkaname = xattr_linkp->h_names +
8248 		    strlen(xattr_linkp->h_names) + 1;
8249 	} else {
8250 		xattr_linkaname = NULL;
8251 	}
8252 
8253 	return (0);
8254 }
8255 #else
8256 static int
8257 read_xattr_hdr(attr_data_t **attrinfo)
8258 {
8259 	return (0);
8260 }
8261 #endif
8262 
8263 /*
8264  * skip over extra slashes in string.
8265  *
8266  * For example:
8267  * /usr/tmp/////
8268  *
8269  * would return pointer at
8270  * /usr/tmp/////
8271  *         ^
8272  */
8273 static char *
8274 skipslashes(char *string, char *start)
8275 {
8276 	while ((string > start) && *(string - 1) == '/') {
8277 		string--;
8278 	}
8279 
8280 	return (string);
8281 }
8282 
8283 /*
8284  * Return the parent directory of a given path.
8285  *
8286  * Examples:
8287  * /usr/tmp return /usr
8288  * /usr/tmp/file return /usr/tmp
8289  * /  returns .
8290  * /usr returns /
8291  * file returns .
8292  *
8293  * dir is assumed to be at least as big as path.
8294  */
8295 static void
8296 get_parent(char *path, char *dir)
8297 {
8298 	char *s;
8299 	char tmpdir[PATH_MAX + 1];
8300 
8301 	if (strlen(path) > PATH_MAX) {
8302 		fatal(gettext("pathname is too long"));
8303 	}
8304 	(void) strcpy(tmpdir, path);
8305 	chop_endslashes(tmpdir);
8306 
8307 	if ((s = strrchr(tmpdir, '/')) == NULL) {
8308 		(void) strcpy(dir, ".");
8309 	} else {
8310 		s = skipslashes(s, tmpdir);
8311 		*s = '\0';
8312 		if (s == tmpdir)
8313 			(void) strcpy(dir, "/");
8314 		else
8315 			(void) strcpy(dir, tmpdir);
8316 	}
8317 }
8318 
8319 #if defined(O_XATTR)
8320 static char *
8321 get_component(char *path)
8322 {
8323 	char *ptr;
8324 
8325 	ptr = strrchr(path, '/');
8326 	if (ptr == NULL) {
8327 		return (path);
8328 	} else {
8329 		/*
8330 		 * Handle trailing slash
8331 		 */
8332 		if (*(ptr + 1) == '\0')
8333 			return (ptr);
8334 		else
8335 			return (ptr + 1);
8336 	}
8337 }
8338 #else
8339 static char *
8340 get_component(char *path)
8341 {
8342 	return (path);
8343 }
8344 #endif
8345 
8346 #if defined(O_XATTR)
8347 static int
8348 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8349     int oflag, mode_t mode)
8350 {
8351 	int dirfd;
8352 	int ofilefd = -1;
8353 	struct timeval times[2];
8354 	mode_t newmode;
8355 	struct stat parentstat;
8356 	acl_t *aclp = NULL;
8357 	int error;
8358 
8359 	/*
8360 	 * We couldn't get to attrdir. See if its
8361 	 * just a mode problem on the parent file.
8362 	 * for example: a mode such as r-xr--r--
8363 	 * on a ufs file system without extended
8364 	 * system attribute support won't let us
8365 	 * create an attribute dir if it doesn't
8366 	 * already exist, and on a ufs file system
8367 	 * with extended system attribute support
8368 	 * won't let us open the attribute for
8369 	 * write.
8370 	 *
8371 	 * If file has a non-trivial ACL, then save it
8372 	 * off so that we can place it back on after doing
8373 	 * chmod's.
8374 	 */
8375 	if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8376 	    O_RDONLY)) == -1) {
8377 		return (-1);
8378 	}
8379 	if (fstat(dirfd, &parentstat) == -1) {
8380 		(void) fprintf(stderr, gettext(
8381 		    "tar: cannot stat %sfile %s: %s\n"),
8382 		    (pdirfd == -1) ? "" : gettext("parent of "),
8383 		    (pdirfd == -1) ? dirp : name, strerror(errno));
8384 			return (-1);
8385 	}
8386 	if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8387 		(void) fprintf(stderr, gettext(
8388 		    "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8389 		    (pdirfd == -1) ? "" : gettext("parent of "),
8390 		    (pdirfd == -1) ? dirp : name, strerror(errno));
8391 			return (-1);
8392 	}
8393 
8394 	newmode = S_IWUSR | parentstat.st_mode;
8395 	if (fchmod(dirfd, newmode) == -1) {
8396 		(void) fprintf(stderr,
8397 		    gettext(
8398 		    "tar: cannot fchmod %sfile %s to %o: %s\n"),
8399 		    (pdirfd == -1) ? "" : gettext("parent of "),
8400 		    (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8401 		if (aclp)
8402 			acl_free(aclp);
8403 		return (-1);
8404 	}
8405 
8406 
8407 	if (pdirfd == -1) {
8408 		/*
8409 		 * We weren't able to create the attribute directory before.
8410 		 * Now try again.
8411 		 */
8412 		ofilefd = attropen(dirp, ".", oflag);
8413 	} else {
8414 		/*
8415 		 * We weren't able to create open the attribute before.
8416 		 * Now try again.
8417 		 */
8418 		ofilefd = openat(pdirfd, name, oflag, mode);
8419 	}
8420 
8421 	/*
8422 	 * Put mode back to original
8423 	 */
8424 	if (fchmod(dirfd, parentstat.st_mode) == -1) {
8425 		(void) fprintf(stderr,
8426 		    gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8427 		    (pdirfd == -1) ? "" : gettext("parent of "),
8428 		    (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8429 	}
8430 
8431 	if (aclp) {
8432 		error = facl_set(dirfd, aclp);
8433 		if (error) {
8434 			(void) fprintf(stderr,
8435 			    gettext("tar: failed to set acl entries on "
8436 			    "%sfile %s\n"),
8437 			    (pdirfd == -1) ? "" : gettext("parent of "),
8438 			    (pdirfd == -1) ? dirp : name);
8439 		}
8440 		acl_free(aclp);
8441 	}
8442 
8443 	/*
8444 	 * Put back time stamps
8445 	 */
8446 
8447 	times[0].tv_sec = parentstat.st_atime;
8448 	times[0].tv_usec = 0;
8449 	times[1].tv_sec = parentstat.st_mtime;
8450 	times[1].tv_usec = 0;
8451 
8452 	(void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8453 
8454 	(void) close(dirfd);
8455 
8456 	return (ofilefd);
8457 }
8458 #endif
8459 
8460 #if !defined(O_XATTR)
8461 static int
8462 openat64(int fd, const char *name, int oflag, mode_t cmode)
8463 {
8464 	return (open64(name, oflag, cmode));
8465 }
8466 
8467 static int
8468 openat(int fd, const char *name, int oflag, mode_t cmode)
8469 {
8470 	return (open(name, oflag, cmode));
8471 }
8472 
8473 static int
8474 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8475 {
8476 	if (flag == AT_SYMLINK_NOFOLLOW)
8477 		return (lchown(name, owner, group));
8478 	else
8479 		return (chown(name, owner, group));
8480 }
8481 
8482 static int
8483 renameat(int fromfd, char *old, int tofd, char *new)
8484 {
8485 	return (rename(old, new));
8486 }
8487 
8488 static int
8489 futimesat(int fd, char *path, struct timeval times[2])
8490 {
8491 	return (utimes(path, times));
8492 }
8493 
8494 static int
8495 unlinkat(int dirfd, char *path, int flag)
8496 {
8497 	if (flag == AT_REMOVEDIR)
8498 		return (rmdir(path));
8499 	else
8500 		return (unlink(path));
8501 }
8502 
8503 static int
8504 fstatat(int fd, char *path, struct stat *buf, int flag)
8505 {
8506 	if (flag == AT_SYMLINK_NOFOLLOW)
8507 		return (lstat(path, buf));
8508 	else
8509 		return (stat(path, buf));
8510 }
8511 
8512 static int
8513 attropen(char *file, char *attr, int omode, mode_t cmode)
8514 {
8515 	errno = ENOTSUP;
8516 	return (-1);
8517 }
8518 #endif
8519 
8520 static void
8521 chop_endslashes(char *path)
8522 {
8523 	char *end, *ptr;
8524 
8525 	/*
8526 	 * Chop of slashes, but not if all we have is slashes
8527 	 * for example: ////
8528 	 * should make no changes, otherwise it will screw up
8529 	 * checkdir
8530 	 */
8531 	end = &path[strlen(path) -1];
8532 	if (*end == '/' && end != path) {
8533 		ptr = skipslashes(end, path);
8534 		if (ptr != NULL && ptr != path) {
8535 			*ptr = '\0';
8536 		}
8537 	}
8538 }
8539 /* Trusted Extensions */
8540 
8541 /*
8542  * append_ext_attr():
8543  *
8544  * Append extended attributes and other information into the buffer
8545  * that gets written to the ancillary file.
8546  *
8547  * With option 'T', we create a tarfile which
8548  * has an ancillary file each corresponding archived file.
8549  * Each ancillary file contains 1 or more of the
8550  * following attributes:
8551  *
8552  *	attribute type        attribute		process procedure
8553  *	----------------      ----------------  --------------------------
8554  *   	DIR_TYPE       = 'D'   directory flag	append if a directory
8555  *    	LBL_TYPE       = 'L'   SL[IL] or SL	append ascii label
8556  *
8557  *
8558  */
8559 static void
8560 append_ext_attr(char *shortname, char **secinfo, int *len)
8561 {
8562 	bslabel_t	b_slabel;	/* binary sensitvity label */
8563 	char		*ascii = NULL;	/* ascii label */
8564 
8565 	/*
8566 	 * For each attribute type, append it if it is
8567 	 * relevant to the file type.
8568 	 */
8569 
8570 	/*
8571 	 * For attribute type DIR_TYPE,
8572 	 * append it to the following file type:
8573 	 *
8574 	 *	S_IFDIR: directories
8575 	 */
8576 
8577 	/*
8578 	 * For attribute type LBL_TYPE,
8579 	 * append it to the following file type:
8580 	 *
8581 	 *	S_IFDIR: directories (including mld, sld)
8582 	 *	S_IFLNK: symbolic link
8583 	 *	S_IFREG: regular file but not hard link
8584 	 *	S_IFIFO: FIFO file but not hard link
8585 	 *	S_IFCHR: char special file but not hard link
8586 	 *	S_IFBLK: block special file but not hard link
8587 	 */
8588 	switch (stbuf.st_mode & S_IFMT) {
8589 
8590 	case S_IFDIR:
8591 
8592 		/*
8593 		 * append DIR_TYPE
8594 		 */
8595 		(void) append_secattr(secinfo, len, 1,
8596 		    "\0", DIR_TYPE);
8597 
8598 		/*
8599 		 * Get and append attribute types LBL_TYPE.
8600 		 * For directories, LBL_TYPE contains SL.
8601 		 */
8602 		/* get binary sensitivity label */
8603 		if (getlabel(shortname, &b_slabel) != 0) {
8604 			(void) fprintf(stderr,
8605 			    gettext("tar: can't get sensitvity label for "
8606 			    " %s, getlabel() error: %s\n"),
8607 			    shortname, strerror(errno));
8608 		} else {
8609 			/* get ascii SL */
8610 			if (bsltos(&b_slabel, &ascii,
8611 			    0, 0) <= 0) {
8612 				(void) fprintf(stderr,
8613 				    gettext("tar: can't get ascii SL for"
8614 				    " %s\n"), shortname);
8615 			} else {
8616 				/* append LBL_TYPE */
8617 				(void) append_secattr(secinfo, len,
8618 				    strlen(ascii) + 1, ascii,
8619 				    LBL_TYPE);
8620 
8621 				/* free storage */
8622 				if (ascii != NULL) {
8623 					free(ascii);
8624 					ascii = (char *)0;
8625 				}
8626 			}
8627 
8628 		}
8629 		break;
8630 
8631 	case S_IFLNK:
8632 	case S_IFREG:
8633 	case S_IFIFO:
8634 	case S_IFCHR:
8635 	case S_IFBLK:
8636 
8637 		/* get binary sensitivity label */
8638 		if (getlabel(shortname, &b_slabel) != 0) {
8639 			(void) fprintf(stderr,
8640 			    gettext("tar: can't get sensitivty label for %s, "
8641 			    "getlabel() error: %s\n"),
8642 			    shortname, strerror(errno));
8643 		} else {
8644 			/* get ascii IL[SL] */
8645 			if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
8646 				(void) fprintf(stderr,
8647 				    gettext("tar: can't translate sensitivity "
8648 				    " label for %s\n"), shortname);
8649 			} else {
8650 				char *cmw_label;
8651 				size_t  cmw_length;
8652 
8653 				cmw_length = strlen("ADMIN_LOW [] ") +
8654 				    strlen(ascii);
8655 				if ((cmw_label = malloc(cmw_length)) == NULL) {
8656 					(void) fprintf(stderr, gettext(
8657 					    "Insufficient memory for label\n"));
8658 					exit(1);
8659 				}
8660 				/* append LBL_TYPE */
8661 				(void) snprintf(cmw_label, cmw_length,
8662 				    "ADMIN_LOW [%s]", ascii);
8663 				(void) append_secattr(secinfo, len,
8664 				    strlen(cmw_label) + 1, cmw_label,
8665 				    LBL_TYPE);
8666 
8667 				/* free storage */
8668 				if (ascii != NULL) {
8669 					free(cmw_label);
8670 					free(ascii);
8671 					ascii = (char *)0;
8672 				}
8673 			}
8674 		}
8675 		break;
8676 
8677 	default:
8678 		break;
8679 	} /* end switch for LBL_TYPE */
8680 
8681 
8682 	/* DONE !! */
8683 	return;
8684 
8685 } /* end of append_ext_attr */
8686 
8687 
8688 /*
8689  *	Name: extract_attr()
8690  *
8691  *	Description:
8692  *		Process attributes from the ancillary file due to
8693  *		the T option.
8694  *
8695  *	Call by doxtract() as part of the switch case structure.
8696  *	Making this a separate routine because the nesting are too
8697  *	deep in doxtract, thus, leaving very little space
8698  *	on each line for instructions.
8699  *
8700  * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
8701  *
8702  * For option 'T', following are possible attributes in
8703  * a TS 8 ancillary file: (NOTE: No IL support)
8704  *
8705  *	attribute type        attribute		process procedure
8706  *	----------------      ----------------  -------------------------
8707  *    #	LBL_TYPE       = 'L'   SL               construct binary label
8708  *    #	APRIV_TYPE     = 'P'   allowed priv    	construct privileges
8709  *    #	FPRIV_TYPE     = 'p'   forced priv	construct privileges
8710  *    #	COMP_TYPE      = 'C'   path component	construct real path
8711  *    #	DIR_TYPE       = 'D'   directory flag	note it is a directory
8712  *    $	UFSD_ACL       = '1'   ACL data		construct ACL entries
8713  *	ATTR_FLAG_TYPE = 'F'   file attr flags  construct binary flags
8714  *	LK_COMP_TYPE   = 'K'   linked path comp construct linked real path
8715  *
8716  * note: # = attribute names common between TS 8 & TS 2.5 ancillary
8717  *           files.
8718  *       $ = ACL attribute is processed for the option 'p', it doesn't
8719  *           need option 'T'.
8720  *
8721  * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
8722  *
8723  */
8724 static void
8725 extract_attr(char **file_ptr, struct sec_attr *attr)
8726 {
8727 	int	reterr, err;
8728 	char	*dummy_buf;	/* for attribute extract */
8729 
8730 	dummy_buf = attr->attr_info;
8731 
8732 	switch (attr->attr_type) {
8733 
8734 	case DIR_TYPE:
8735 
8736 		dir_flag++;
8737 		break;
8738 
8739 	case LBL_TYPE:
8740 
8741 		/*
8742 		 * LBL_TYPE is used to indicate SL for directory, and
8743 		 * CMW label for other file types.
8744 		 */
8745 
8746 		if (!dir_flag) { /* not directory */
8747 			/* Skip over IL portion */
8748 			char *sl_ptr = strchr(dummy_buf, '[');
8749 
8750 			if (sl_ptr == NULL)
8751 				err = 0;
8752 			else
8753 				err = stobsl(sl_ptr, &bs_label,
8754 				    NEW_LABEL, &reterr);
8755 		} else { /* directory */
8756 			err = stobsl(dummy_buf, &bs_label,
8757 			    NEW_LABEL, &reterr);
8758 		}
8759 		if (err == 0) {
8760 			(void) fprintf(stderr, gettext("tar: "
8761 			    "can't convert %s to binary label\n"),
8762 			    dummy_buf);
8763 			bslundef(&bs_label);
8764 		} else if (!blequal(&bs_label, &admin_low) &&
8765 		    !blequal(&bs_label, &admin_high)) {
8766 			bslabel_t *from_label;
8767 			char *buf;
8768 			char tempbuf[MAXPATHLEN];
8769 
8770 			if (*orig_namep != '/') {
8771 				/* got relative linked to path */
8772 				(void) getcwd(tempbuf, (sizeof (tempbuf)));
8773 				(void) strncat(tempbuf, "/", MAXPATHLEN);
8774 			} else
8775 				*tempbuf = '\0';
8776 
8777 			buf = real_path;
8778 			(void) strncat(tempbuf, orig_namep, MAXPATHLEN);
8779 			from_label = getlabelbypath(tempbuf);
8780 			if (from_label != NULL) {
8781 				if (blequal(from_label, &admin_low)) {
8782 					if ((getpathbylabel(tempbuf, buf,
8783 					    MAXPATHLEN, &bs_label) == NULL)) {
8784 						(void) fprintf(stderr,
8785 						    gettext("tar: "
8786 						"can't get zone root path for "
8787 						"%s\n"), tempbuf);
8788 					} else
8789 						rpath_flag = 1;
8790 				}
8791 				free(from_label);
8792 			}
8793 		}
8794 		break;
8795 
8796 	case COMP_TYPE:
8797 
8798 		rebuild_comp_path(dummy_buf, file_ptr);
8799 		break;
8800 
8801 	case LK_COMP_TYPE:
8802 
8803 		if (rebuild_lk_comp_path(dummy_buf, file_ptr)
8804 		    == 0) {
8805 			lk_rpath_flag = 1;
8806 		} else {
8807 			(void) fprintf(stderr, gettext("tar: warning: link's "
8808 			    "target pathname might be invalid.\n"));
8809 			lk_rpath_flag = 0;
8810 		}
8811 		break;
8812 	case APRIV_TYPE:
8813 		ignored_aprivs++;
8814 		break;
8815 	case FPRIV_TYPE:
8816 		ignored_fprivs++;
8817 		break;
8818 	case ATTR_FLAG_TYPE:
8819 		ignored_fattrs++;
8820 		break;
8821 
8822 	default:
8823 
8824 		break;
8825 	}
8826 
8827 	/* done */
8828 	return;
8829 
8830 }	/* end extract_attr */
8831 
8832 
8833 
8834 /*
8835  *	Name:	rebuild_comp_path()
8836  *
8837  *	Description:
8838  *		Take the string of components passed down by the calling
8839  *		routine and parse the values and rebuild the path.
8840  *		This routine no longer needs to produce a new real_path
8841  *		string because it is produced when the 'L' LABEL_TYPE is
8842  *		interpreted. So the only thing done here is to distinguish
8843  *		between an SLD and an MLD entry. We only want one, so we
8844  *		ignore the MLD entry by setting the mld_flag.
8845  *
8846  *	return value:
8847  *		none
8848  */
8849 static void
8850 rebuild_comp_path(char *str, char **namep)
8851 {
8852 	char		*cp;
8853 
8854 	while (*str != '\0') {
8855 
8856 		switch (*str) {
8857 
8858 		case MLD_TYPE:
8859 
8860 			str++;
8861 			if ((cp = strstr(str, ";;")) != NULL) {
8862 				*cp = '\0';
8863 				str = cp + 2;
8864 				*cp = ';';
8865 			}
8866 			mld_flag = 1;
8867 			break;
8868 
8869 		case SLD_TYPE:
8870 
8871 			str++;
8872 			if ((cp = strstr(str, ";;")) != NULL) {
8873 				*cp = '\0';
8874 				str = cp + 2;
8875 				*cp = ';';
8876 			}
8877 			mld_flag = 0;
8878 			break;
8879 
8880 		case PATH_TYPE:
8881 
8882 			str++;
8883 			if ((cp = strstr(str, ";;")) != NULL) {
8884 				*cp = '\0';
8885 				str = cp + 2;
8886 				*cp = ';';
8887 			}
8888 			break;
8889 		}
8890 	}
8891 	if (rpath_flag)
8892 		*namep = real_path;
8893 	return;
8894 
8895 } /* end rebuild_comp_path() */
8896 
8897 /*
8898  *	Name:	rebuild_lk_comp_path()
8899  *
8900  *	Description:
8901  *		Take the string of components passed down by the calling
8902  *		routine and parse the values and rebuild the path.
8903  *
8904  *	return value:
8905  *		0 = succeeded
8906  *		-1 = failed
8907  */
8908 static int
8909 rebuild_lk_comp_path(char *str, char **namep)
8910 {
8911 	char		*cp;
8912 	int		reterr;
8913 	bslabel_t	bslabel;
8914 	char		*buf;
8915 	char		pbuf[MAXPATHLEN];
8916 	char		*ptr1, *ptr2;
8917 	int		plen;
8918 	int		use_pbuf;
8919 	char		tempbuf[MAXPATHLEN];
8920 	int		mismatch;
8921 	bslabel_t	*from_label;
8922 	char		zonename[ZONENAME_MAX];
8923 	zoneid_t	zoneid;
8924 
8925 	/* init stuff */
8926 	use_pbuf = 0;
8927 	mismatch = 0;
8928 
8929 	/*
8930 	 * For linked to pathname (LK_COMP_TYPE):
8931 	 *  - If the linked to pathname is absolute (start with /), we
8932 	 *    will use it as is.
8933 	 *  - If it is a relative pathname then it is relative to 1 of 2
8934 	 *    directories.  For a hardlink, it is relative to the current
8935 	 *    directory.  For a symbolic link, it is relative to the
8936 	 *    directory the symbolic link is in.  For the symbolic link
8937 	 *    case, set a flag to indicate we need to use the prefix of
8938 	 *    the restored file's pathname with the linked to pathname.
8939 	 *
8940 	 *    NOTE: At this point, we have no way to determine if we have
8941 	 *    a hardlink or a symbolic link.  We will compare the 1st
8942 	 *    component in the prefix portion of the restore file's
8943 	 *    pathname to the 1st component in the attribute data
8944 	 *    (the linked pathname).  If they are the same, we will assume
8945 	 *    the link pathname to reconstruct is relative to the current
8946 	 *    directory.  Otherwise, we will set a flag indicate we need
8947 	 *    to use a prefix with the reconstructed name.  Need to compare
8948 	 *    both the adorned and unadorned version before deciding a
8949 	 *    mismatch.
8950 	 */
8951 
8952 	buf = lk_real_path;
8953 	if (*(str + 1) != '/') { /* got relative linked to path */
8954 		ptr1 = orig_namep;
8955 		ptr2 = strrchr(ptr1, '/');
8956 		plen = ptr2 - ptr1;
8957 		if (plen > 0) {
8958 			pbuf[0] = '\0';
8959 			plen++;		/* include '/' */
8960 			(void) strncpy(pbuf, ptr1, plen);
8961 			*(pbuf + plen) = '\0';
8962 			ptr2 = strchr(pbuf, '/');
8963 			if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
8964 				mismatch = 1;
8965 		}
8966 
8967 		if (mismatch == 1)
8968 			use_pbuf = 1;
8969 	}
8970 
8971 	buf[0] = '\0';
8972 
8973 	while (*str != '\0') {
8974 
8975 		switch (*str) {
8976 
8977 		case MLD_TYPE:
8978 
8979 			str++;
8980 			if ((cp = strstr(str, ";;")) != NULL) {
8981 				*cp = '\0';
8982 
8983 				/*
8984 				 * Ignore attempts to backup over .MLD.
8985 				 */
8986 				if (strcmp(str, "../") != 0)
8987 					(void) strncat(buf, str, MAXPATHLEN);
8988 				str = cp + 2;
8989 				*cp = ';';
8990 			}
8991 			break;
8992 
8993 		case SLD_TYPE:
8994 
8995 			str++;
8996 			if ((cp = strstr(str, ";;")) != NULL) {
8997 				*cp = '\0';
8998 
8999 				/*
9000 				 * Use the path name in the header if
9001 				 * error occurs when processing the
9002 				 * SLD type.
9003 				 */
9004 
9005 				if (!stobsl(str, &bslabel,
9006 				    NO_CORRECTION, &reterr)) {
9007 					(void) fprintf(stderr, gettext(
9008 					    "tar: can't translate to binary"
9009 					    "SL for SLD, stobsl() error:"
9010 					    " %s\n"), strerror(errno));
9011 					return (-1);
9012 				}
9013 
9014 				str = cp + 2;
9015 				*cp = ';';
9016 
9017 				if (use_pbuf == 1) {
9018 					if (*pbuf != '/') {
9019 						/* relative linked to path */
9020 
9021 						(void) getcwd(tempbuf,
9022 						    (sizeof (tempbuf)));
9023 						(void) strncat(tempbuf, "/",
9024 						    MAXPATHLEN);
9025 						(void) strncat(tempbuf, pbuf,
9026 						    MAXPATHLEN);
9027 					}
9028 					else
9029 						(void) strcpy(tempbuf, pbuf);
9030 
9031 				} else if (*buf != '/') {
9032 					/* got relative linked to path */
9033 
9034 					(void) getcwd(tempbuf,
9035 					    (sizeof (tempbuf)));
9036 					(void) strncat(tempbuf, "/",
9037 					    MAXPATHLEN);
9038 				} else
9039 					*tempbuf = '\0';
9040 
9041 				(void) strncat(tempbuf, buf, MAXPATHLEN);
9042 				*buf = '\0';
9043 
9044 				if (blequal(&bslabel, &admin_high)) {
9045 					bslabel = admin_low;
9046 				}
9047 
9048 
9049 				/*
9050 				 * Check for cross-zone symbolic links
9051 				 */
9052 				from_label = getlabelbypath(real_path);
9053 				if (rpath_flag && (from_label != NULL) &&
9054 				    !blequal(&bslabel, from_label)) {
9055 					if ((zoneid =
9056 					    getzoneidbylabel(&bslabel)) == -1) {
9057 						(void) fprintf(stderr,
9058 						    gettext("tar: can't get "
9059 						    "zone ID for %s\n"),
9060 						    tempbuf);
9061 						return (-1);
9062 					}
9063 					if (zone_getattr(zoneid, ZONE_ATTR_NAME,
9064 					    &zonename, ZONENAME_MAX) == -1) {
9065 						/* Badly configured zone info */
9066 						(void) fprintf(stderr,
9067 						    gettext("tar: can't get "
9068 						    "zonename for %s\n"),
9069 						    tempbuf);
9070 						return (-1);
9071 					}
9072 					(void) strncpy(buf, AUTO_ZONE,
9073 					    MAXPATHLEN);
9074 					(void) strncat(buf, "/",
9075 					    MAXPATHLEN);
9076 					(void) strncat(buf, zonename,
9077 					    MAXPATHLEN);
9078 				}
9079 				if (from_label != NULL)
9080 					free(from_label);
9081 				(void) strncat(buf, tempbuf, MAXPATHLEN);
9082 				break;
9083 			}
9084 			mld_flag = 0;
9085 			break;
9086 
9087 		case PATH_TYPE:
9088 
9089 			str++;
9090 			if ((cp = strstr(str, ";;")) != NULL) {
9091 				*cp = '\0';
9092 				(void) strncat(buf, str, MAXPATHLEN);
9093 				str = cp + 2;
9094 				*cp = ';';
9095 			}
9096 			break;
9097 
9098 		default:
9099 
9100 			(void) fprintf(stderr, gettext(
9101 			    "tar: error rebuilding path %s\n"),
9102 			    *namep);
9103 			*buf = '\0';
9104 			str++;
9105 			return (-1);
9106 		}
9107 	}
9108 
9109 	/*
9110 	 * Done for LK_COMP_TYPE
9111 	 */
9112 
9113 	return (0);    /* component path is rebuilt successfully */
9114 
9115 } /* end rebuild_lk_comp_path() */
9116 
9117 /*
9118  *	Name: check_ext_attr()
9119  *
9120  *	Description:
9121  *		Check the extended attributes for a file being extracted.
9122  *		The attributes being checked here are CMW labels.
9123  *		ACLs are not set here because they are set by the
9124  *		pflag in doxtract().
9125  *
9126  *		If the label doesn't match, return 0
9127  *		else return 1
9128  */
9129 static int
9130 check_ext_attr(char *filename)
9131 {
9132 	bslabel_t	currentlabel;	/* label from zone */
9133 
9134 	if (bltype(&bs_label, SUN_SL_UN)) {
9135 		/* No label check possible */
9136 		return (0);
9137 	}
9138 	if (getlabel(filename, &currentlabel) != 0) {
9139 		(void) fprintf(stderr,
9140 		    gettext("tar: can't get label for "
9141 		    " %s, getlabel() error: %s\n"),
9142 		    filename, strerror(errno));
9143 		return (0);
9144 	} else if ((blequal(&currentlabel, &bs_label)) == 0) {
9145 		char	*src_label = NULL;	/* ascii label */
9146 
9147 		/* get current src SL */
9148 		if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
9149 			(void) fprintf(stderr,
9150 			    gettext("tar: can't interpret requested label for"
9151 			    " %s\n"), filename);
9152 		} else {
9153 			(void) fprintf(stderr,
9154 			    gettext("tar: can't apply label %s to %s\n"),
9155 			    src_label, filename);
9156 			free(src_label);
9157 		}
9158 		(void) fprintf(stderr,
9159 		    gettext("tar: %s not restored\n"), filename);
9160 		return (0);
9161 	}
9162 	return (1);
9163 
9164 }	/* end check_ext_attr */
9165 
9166 /* Compressing a tar file using compression method provided in 'opt' */
9167 
9168 static void
9169 compress_back()
9170 {
9171 	pid_t	pid;
9172 	int status;
9173 	int wret;
9174 	struct	stat statb;
9175 
9176 	if (vflag) {
9177 		(void) fprintf(vfile,
9178 		    gettext("Compressing '%s' with '%s'...\n"),
9179 		    usefile, compress_opt);
9180 	}
9181 	if ((pid = fork()) == 0) {
9182 		verify_compress_opt(compress_opt);
9183 		(void) execlp(compress_opt, compress_opt,
9184 		    usefile, NULL);
9185 	} else if (pid == -1) {
9186 		vperror(1, "%s", gettext("Could not fork"));
9187 	}
9188 	wait_pid(pid);
9189 	if (suffix == 0) {
9190 		(void) rename(tfname, usefile);
9191 	}
9192 }
9193 
9194 /* The magic numbers from /etc/magic */
9195 
9196 #define	GZIP_MAGIC	"\037\213"
9197 #define	BZIP_MAGIC	"BZh"
9198 #define	COMP_MAGIC	"\037\235"
9199 #define	XZ_MAGIC	"\375\067\172\130\132\000"
9200 
9201 void
9202 check_compression(void)
9203 {
9204 	char 	magic[16];
9205 	FILE	*fp;
9206 
9207 	if ((fp = fopen(usefile, "r")) != NULL) {
9208 		(void) fread(magic, sizeof (char), 6, fp);
9209 		(void) fclose(fp);
9210 	}
9211 
9212 	if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
9213 		if (xflag || tflag) {
9214 			compress_opt = compress_malloc(strlen(GZCAT) + 1);
9215 			(void) strcpy(compress_opt, GZCAT);
9216 		} else if (uflag || rflag) {
9217 			compress_opt = compress_malloc(strlen(GZIP) + 1);
9218 			(void) strcpy(compress_opt, GZIP);
9219 		}
9220 	} else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
9221 		if (xflag || tflag) {
9222 			compress_opt = compress_malloc(strlen(BZCAT) + 1);
9223 			(void) strcpy(compress_opt, BZCAT);
9224 		} else if (uflag || rflag) {
9225 			compress_opt = compress_malloc(strlen(BZIP) + 1);
9226 			(void) strcpy(compress_opt, BZIP);
9227 		}
9228 	} else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
9229 		if (xflag || tflag) {
9230 			compress_opt = compress_malloc(strlen(ZCAT) + 1);
9231 			(void) strcpy(compress_opt, ZCAT);
9232 		} else if (uflag || rflag) {
9233 			compress_opt = compress_malloc(strlen(COMPRESS) + 1);
9234 			(void) strcpy(compress_opt, COMPRESS);
9235 		}
9236 	} else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
9237 		if (xflag || tflag) {
9238 			compress_opt = compress_malloc(strlen(XZCAT) + 1);
9239 			(void) strcpy(compress_opt, XZCAT);
9240 		} else if (uflag || rflag) {
9241 			compress_opt = compress_malloc(strlen(XZ) + 1);
9242 			(void) strcpy(compress_opt, XZ);
9243 		}
9244 	}
9245 }
9246 
9247 char *
9248 add_suffix()
9249 {
9250 	(void) strcpy(tfname, usefile);
9251 	if (strcmp(compress_opt, GZIP) == 0) {
9252 		if ((suffix = gz_suffix()) == NULL) {
9253 			strlcat(tfname, gsuffix[0], sizeof (tfname));
9254 			return (gsuffix[0]);
9255 		}
9256 	} else if (strcmp(compress_opt, COMPRESS) == 0) {
9257 		if ((suffix = gz_suffix()) == NULL) {
9258 			strlcat(tfname, gsuffix[6], sizeof (tfname));
9259 			return (gsuffix[6]);
9260 		}
9261 	} else if (strcmp(compress_opt, BZIP) == 0) {
9262 		if ((suffix = bz_suffix()) == NULL) {
9263 			strlcat(tfname, bsuffix[0], sizeof (tfname));
9264 			return (bsuffix[0]);
9265 		}
9266 	} else if (strcmp(compress_opt, XZ) == 0) {
9267 		if ((suffix = xz_suffix()) == NULL) {
9268 			strlcat(tfname, xsuffix[0], sizeof (tfname));
9269 			return (xsuffix[0]);
9270 		}
9271 	}
9272 	return (NULL);
9273 }
9274 
9275 /* Decompressing a tar file using compression method from the file type */
9276 void
9277 decompress_file(void)
9278 {
9279 	pid_t 	pid;
9280 	int	status;
9281 	char	cmdstr[PATH_MAX];
9282 	char	fname[PATH_MAX];
9283 	char	*added_suffix;
9284 
9285 
9286 	added_suffix = add_suffix();
9287 	if (added_suffix != NULL)  {
9288 		(void) rename(usefile, tfname);
9289 	}
9290 	if ((pid = fork()) == 0) {
9291 		if (vflag) {
9292 			(void) fprintf(vfile,
9293 			    gettext("Decompressing '%s' with "
9294 			    "'%s'...\n"), usefile, compress_opt);
9295 		}
9296 		verify_compress_opt(compress_opt);
9297 		(void) execlp(compress_opt, compress_opt, "-df",
9298 		    tfname, NULL);
9299 		vperror(1, gettext("Could not exec %s"), compress_opt);
9300 	} else if (pid == -1) {
9301 		vperror(1, gettext("Could not fork"));
9302 	}
9303 	wait_pid(pid);
9304 	if (suffix != NULL) {
9305 		/* restore the file name - original file was without suffix */
9306 		*(usefile + strlen(usefile) - strlen(suffix)) = '\0';
9307 	}
9308 }
9309 
9310 /* Set the archive for writing and then compress the archive */
9311 pid_t
9312 compress_file(void)
9313 {
9314 	int fd[2];
9315 	pid_t pid;
9316 
9317 	if (vflag) {
9318 		(void) fprintf(vfile, gettext("Compressing '%s' with "
9319 		    "'%s'...\n"), usefile, compress_opt);
9320 	}
9321 
9322 	if (pipe(fd) < 0) {
9323 		vperror(1, gettext("Could not create pipe"));
9324 	}
9325 	if (pid = fork() > 0) {
9326 		mt = fd[1];
9327 		(void) close(fd[0]);
9328 		return (pid);
9329 	}
9330 	/* child */
9331 	(void) dup2(fd[0], STDIN_FILENO);
9332 	(void) close(fd[1]);
9333 	(void) dup2(mt, STDOUT_FILENO);
9334 	verify_compress_opt(compress_opt);
9335 	(void) execlp(compress_opt, compress_opt, NULL);
9336 	vperror(1, gettext("Could not exec %s"), compress_opt);
9337 	return (0);	/*NOTREACHED*/
9338 }
9339 
9340 pid_t
9341 uncompress_file(void)
9342 {
9343 	int fd[2];
9344 	pid_t pid;
9345 
9346 	if (vflag) {
9347 		(void) fprintf(vfile, gettext("Decompressing '%s' with "
9348 		    "'%s'...\n"), usefile, compress_opt);
9349 	}
9350 
9351 	if (pipe(fd) < 0) {
9352 		vperror(1, gettext("Could not create pipe"));
9353 	}
9354 	if (pid = fork() > 0) {
9355 		mt = fd[0];
9356 		(void) close(fd[1]);
9357 		return (pid);
9358 	}
9359 	/* child */
9360 	(void) dup2(fd[1], STDOUT_FILENO);
9361 	(void) close(fd[0]);
9362 	(void) dup2(mt, STDIN_FILENO);
9363 	verify_compress_opt(compress_opt);
9364 	(void) execlp(compress_opt, compress_opt, NULL);
9365 	vperror(1, gettext("Could not exec %s"), compress_opt);
9366 	return (0);	/*NOTREACHED*/
9367 }
9368 
9369 /* Checking suffix validity */
9370 char *
9371 check_suffix(char **suf, int size)
9372 {
9373 	int 	i;
9374 	int	slen;
9375 	int	nlen = strlen(usefile);
9376 
9377 	for (i = 0; i < size; i++) {
9378 		slen = strlen(suf[i]);
9379 		if (nlen < slen)
9380 			return (NULL);
9381 		if (strcmp(usefile + nlen - slen, suf[i]) == 0)
9382 			return (suf[i]);
9383 	}
9384 	return (NULL);
9385 }
9386 
9387 /* Checking valid 'bzip2' suffix */
9388 char *
9389 bz_suffix(void)
9390 {
9391 	return (check_suffix(bsuffix, BSUF));
9392 }
9393 
9394 /* Checking valid 'gzip' suffix */
9395 char *
9396 gz_suffix(void)
9397 {
9398 	return (check_suffix(gsuffix, GSUF));
9399 }
9400 
9401 /* Checking valid 'xz' suffix */
9402 char *
9403 xz_suffix(void)
9404 {
9405 	return (check_suffix(xsuffix, XSUF));
9406 }
9407 
9408 void *
9409 compress_malloc(size_t size)
9410 {
9411 	void *opt;
9412 
9413 	if ((opt = malloc(size)) == NULL) {
9414 		vperror(1, "%s",
9415 		    gettext("Could not allocate compress buffer\n"));
9416 	}
9417 	return (opt);
9418 }
9419 
9420 void
9421 wait_pid(pid_t pid)
9422 {
9423 	int status;
9424 
9425 	while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
9426 		;
9427 }
9428 
9429 static void
9430 verify_compress_opt(const char *t)
9431 {
9432 	struct stat statbuf;
9433 
9434 	if (stat(t, &statbuf) == -1)
9435 		vperror(1, "%s %s: %s\n", gettext("Could not stat"),
9436 		    t, strerror(errno));
9437 }
9438 
9439 static void
9440 detect_compress(void)
9441 {
9442 	char *zsuf[] = {".Z"};
9443 	if (check_suffix(zsuf, 1) != NULL) {
9444 		Zflag = 1;
9445 	} else if (check_suffix(bsuffix, BSUF) != NULL) {
9446 		jflag = 1;
9447 	} else if (check_suffix(gsuffix, GSUF) != NULL) {
9448 		zflag = 1;
9449 	} else if (check_suffix(xsuffix, XSUF) != NULL) {
9450 		Jflag = 1;
9451 	} else {
9452 		vperror(1, "%s\n", gettext("No compression method detected"));
9453 	}
9454 }
9455