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