xref: /onnv-gate/usr/src/cmd/tar/tar.c (revision 12836:0d0733997434)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212109SRalph.Turner@Sun.COM  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
260Sstevel@tonic-gate /*	  All Rights Reserved  	*/
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
290Sstevel@tonic-gate /*	  All Rights Reserved	*/
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
330Sstevel@tonic-gate  * under license from the Regents of the University of California.
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include <unistd.h>
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <sys/param.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <sys/mkdev.h>
410Sstevel@tonic-gate #include <sys/wait.h>
420Sstevel@tonic-gate #include <dirent.h>
430Sstevel@tonic-gate #include <errno.h>
440Sstevel@tonic-gate #include <stdio.h>
450Sstevel@tonic-gate #include <signal.h>
460Sstevel@tonic-gate #include <ctype.h>
470Sstevel@tonic-gate #include <locale.h>
480Sstevel@tonic-gate #include <nl_types.h>
490Sstevel@tonic-gate #include <langinfo.h>
500Sstevel@tonic-gate #include <pwd.h>
510Sstevel@tonic-gate #include <grp.h>
520Sstevel@tonic-gate #include <fcntl.h>
530Sstevel@tonic-gate #include <string.h>
540Sstevel@tonic-gate #include <malloc.h>
550Sstevel@tonic-gate #include <time.h>
560Sstevel@tonic-gate #include <utime.h>
570Sstevel@tonic-gate #include <stdlib.h>
580Sstevel@tonic-gate #include <stdarg.h>
590Sstevel@tonic-gate #include <widec.h>
600Sstevel@tonic-gate #include <sys/mtio.h>
610Sstevel@tonic-gate #include <sys/acl.h>
620Sstevel@tonic-gate #include <strings.h>
630Sstevel@tonic-gate #include <deflt.h>
640Sstevel@tonic-gate #include <limits.h>
650Sstevel@tonic-gate #include <iconv.h>
660Sstevel@tonic-gate #include <assert.h>
675331Samw #include <libgen.h>
685331Samw #include <libintl.h>
69789Sahrens #include <aclutils.h>
705331Samw #include <libnvpair.h>
715331Samw #include <archives.h>
724774Sas145665 
730Sstevel@tonic-gate #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
740Sstevel@tonic-gate extern int defcntl();
750Sstevel@tonic-gate #endif
765331Samw #if defined(_PC_SATTR_ENABLED)
775331Samw #include <attr.h>
785331Samw #include <libcmdutils.h>
795331Samw #endif
800Sstevel@tonic-gate 
811676Sjpk /* Trusted Extensions */
821676Sjpk #include <zone.h>
831676Sjpk #include <tsol/label.h>
841676Sjpk #include <sys/tsol/label_macro.h>
851676Sjpk 
865331Samw #include "getresponse.h"
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate  * Source compatibility
890Sstevel@tonic-gate  */
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate  * These constants come from archives.h and sys/fcntl.h
930Sstevel@tonic-gate  * and were introduced by the extended attributes project
940Sstevel@tonic-gate  * in Solaris 9.
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate #if !defined(O_XATTR)
970Sstevel@tonic-gate #define	AT_SYMLINK_NOFOLLOW	0x1000
980Sstevel@tonic-gate #define	AT_REMOVEDIR		0x1
990Sstevel@tonic-gate #define	AT_FDCWD		0xffd19553
1000Sstevel@tonic-gate #define	_XATTR_HDRTYPE		'E'
1010Sstevel@tonic-gate static int attropen();
1020Sstevel@tonic-gate static int fstatat();
1030Sstevel@tonic-gate static int renameat();
1040Sstevel@tonic-gate static int unlinkat();
1050Sstevel@tonic-gate static int openat();
1060Sstevel@tonic-gate static int fchownat();
1070Sstevel@tonic-gate static int futimesat();
1080Sstevel@tonic-gate #endif
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate  * Compiling with -D_XPG4_2 gets this but produces other problems, so
1120Sstevel@tonic-gate  * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
1130Sstevel@tonic-gate  * explicitly doing the declaration here.
1140Sstevel@tonic-gate  */
1150Sstevel@tonic-gate int utimes(const char *path, const struct timeval timeval_ptr[]);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate #ifndef MINSIZE
1180Sstevel@tonic-gate #define	MINSIZE 250
1190Sstevel@tonic-gate #endif
1200Sstevel@tonic-gate #define	DEF_FILE "/etc/default/tar"
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate #define	min(a, b)  ((a) < (b) ? (a) : (b))
1230Sstevel@tonic-gate #define	max(a, b)  ((a) > (b) ? (a) : (b))
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /* -DDEBUG	ONLY for debugging */
1260Sstevel@tonic-gate #ifdef	DEBUG
1270Sstevel@tonic-gate #undef	DEBUG
1280Sstevel@tonic-gate #define	DEBUG(a, b, c)\
1290Sstevel@tonic-gate 	(void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c)
1300Sstevel@tonic-gate #endif
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate #define	TBLOCK	512	/* tape block size--should be universal */
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate #ifdef	BSIZE
1350Sstevel@tonic-gate #define	SYS_BLOCK BSIZE	/* from sys/param.h:  secondary block size */
1360Sstevel@tonic-gate #else	/* BSIZE */
1370Sstevel@tonic-gate #define	SYS_BLOCK 512	/* default if no BSIZE in param.h */
1380Sstevel@tonic-gate #endif	/* BSIZE */
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate #define	NBLOCK	20
1410Sstevel@tonic-gate #define	NAMSIZ	100
1420Sstevel@tonic-gate #define	PRESIZ	155
1430Sstevel@tonic-gate #define	MAXNAM	256
1440Sstevel@tonic-gate #define	MODEMASK 0777777	/* file creation mode mask */
1450Sstevel@tonic-gate #define	POSIXMODES 07777	/* mask for POSIX mode bits */
1460Sstevel@tonic-gate #define	MAXEXT	9	/* reasonable max # extents for a file */
1470Sstevel@tonic-gate #define	EXTMIN	50	/* min blks left on floppy to split a file */
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /* max value dblock.dbuf.efsize can store */
1500Sstevel@tonic-gate #define	TAR_EFSIZE_MAX	 0777777777
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate  * Symbols which specify the values at which the use of the 'E' function
1540Sstevel@tonic-gate  * modifier is required to properly store a file.
1550Sstevel@tonic-gate  *
1560Sstevel@tonic-gate  *     TAR_OFFSET_MAX    - the largest file size we can archive
1570Sstevel@tonic-gate  *     OCTAL7CHAR        - the limit for ustar gid, uid, dev
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate #ifdef XHDR_DEBUG
1610Sstevel@tonic-gate /* tiny values which force the creation of extended header entries */
1620Sstevel@tonic-gate #define	TAR_OFFSET_MAX 9
1630Sstevel@tonic-gate #define	OCTAL7CHAR 2
1640Sstevel@tonic-gate #else
1650Sstevel@tonic-gate /* normal values */
166373Sceastha #define	TAR_OFFSET_MAX	077777777777ULL
1670Sstevel@tonic-gate #define	OCTAL7CHAR	07777777
1680Sstevel@tonic-gate #endif
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate #define	TBLOCKS(bytes)	(((bytes) + TBLOCK - 1) / TBLOCK)
1710Sstevel@tonic-gate #define	K(tblocks)	((tblocks+1)/2)	/* tblocks to Kbytes for printing */
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate #define	MAXLEV	(PATH_MAX / 2)
1740Sstevel@tonic-gate #define	LEV0	1
1750Sstevel@tonic-gate #define	SYMLINK_LEV0	0
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate #define	TRUE	1
1780Sstevel@tonic-gate #define	FALSE	0
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate #define	XATTR_FILE	1
1810Sstevel@tonic-gate #define	NORMAL_FILE	0
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate #define	PUT_AS_LINK	1
1840Sstevel@tonic-gate #define	PUT_NOTAS_LINK	0
1850Sstevel@tonic-gate 
1865331Samw #ifndef VIEW_READONLY
1875331Samw #define	VIEW_READONLY	"SUNWattr_ro"
1885331Samw #endif
1895331Samw 
1905331Samw #ifndef VIEW_READWRITE
1915331Samw #define	VIEW_READWRITE	"SUNWattr_rw"
1925331Samw #endif
1935331Samw 
1940Sstevel@tonic-gate #if _FILE_OFFSET_BITS == 64
1950Sstevel@tonic-gate #define	FMT_off_t "lld"
1960Sstevel@tonic-gate #define	FMT_off_t_o "llo"
1970Sstevel@tonic-gate #define	FMT_blkcnt_t "lld"
1980Sstevel@tonic-gate #else
1990Sstevel@tonic-gate #define	FMT_off_t "ld"
2000Sstevel@tonic-gate #define	FMT_off_t_o "lo"
2010Sstevel@tonic-gate #define	FMT_blkcnt_t "ld"
2020Sstevel@tonic-gate #endif
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate /* ACL support */
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate static
2070Sstevel@tonic-gate struct	sec_attr {
2080Sstevel@tonic-gate 	char	attr_type;
2090Sstevel@tonic-gate 	char	attr_len[7];
2100Sstevel@tonic-gate 	char	attr_info[1];
2110Sstevel@tonic-gate } *attr;
2120Sstevel@tonic-gate 
2135331Samw #if defined(O_XATTR)
2145331Samw typedef enum {
2155331Samw 	ATTR_OK,
2165331Samw 	ATTR_SKIP,
2175331Samw 	ATTR_CHDIR_ERR,
2185331Samw 	ATTR_OPEN_ERR,
2195331Samw 	ATTR_XATTR_ERR,
2205331Samw 	ATTR_SATTR_ERR
2215331Samw } attr_status_t;
2225331Samw #endif
2235331Samw 
2245331Samw #if defined(O_XATTR)
2255331Samw typedef enum {
2265331Samw 	ARC_CREATE,
2275331Samw 	ARC_RESTORE
2285331Samw } arc_action_t;
2295331Samw #endif
2305331Samw 
2315331Samw typedef struct attr_data {
2325331Samw 	char	*attr_parent;
2335331Samw 	char	*attr_path;
2345331Samw 	int	attr_parentfd;
2355331Samw 	int	attr_rw_sysattr;
2365331Samw } attr_data_t;
2375331Samw 
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate  *
2400Sstevel@tonic-gate  * Tar has been changed to support extended attributes.
2410Sstevel@tonic-gate  *
2420Sstevel@tonic-gate  * As part of this change tar now uses the new *at() syscalls
2430Sstevel@tonic-gate  * such as openat, fchownat(), unlinkat()...
2440Sstevel@tonic-gate  *
2450Sstevel@tonic-gate  * This was done so that attributes can be handled with as few code changes
2460Sstevel@tonic-gate  * as possible.
2470Sstevel@tonic-gate  *
2480Sstevel@tonic-gate  * What this means is that tar now opens the directory that a file or directory
2490Sstevel@tonic-gate  * resides in and then performs *at() functions to manipulate the entry.
2500Sstevel@tonic-gate  *
2510Sstevel@tonic-gate  * For example a new file is now created like this:
2520Sstevel@tonic-gate  *
2530Sstevel@tonic-gate  * dfd = open(<some dir path>)
2540Sstevel@tonic-gate  * fd = openat(dfd, <name>,....);
2550Sstevel@tonic-gate  *
2560Sstevel@tonic-gate  * or in the case of an extended attribute
2570Sstevel@tonic-gate  *
2580Sstevel@tonic-gate  * dfd = attropen(<pathname>, ".", ....)
2590Sstevel@tonic-gate  *
2600Sstevel@tonic-gate  * Once we have a directory file descriptor all of the *at() functions can
2610Sstevel@tonic-gate  * be applied to it.
2620Sstevel@tonic-gate  *
2630Sstevel@tonic-gate  * unlinkat(dfd, <component name>,...)
2640Sstevel@tonic-gate  * fchownat(dfd, <component name>,..)
2650Sstevel@tonic-gate  *
2660Sstevel@tonic-gate  * This works for both normal namespace files and extended attribute file
2670Sstevel@tonic-gate  *
2680Sstevel@tonic-gate  */
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate /*
2710Sstevel@tonic-gate  *
2720Sstevel@tonic-gate  * Extended attribute Format
2730Sstevel@tonic-gate  *
2740Sstevel@tonic-gate  * Extended attributes are stored in two pieces.
2750Sstevel@tonic-gate  * 1. An attribute header which has information about
2760Sstevel@tonic-gate  *    what file the attribute is for and what the attribute
2770Sstevel@tonic-gate  *    is named.
2780Sstevel@tonic-gate  * 2. The attribute record itself.  Stored as a normal file type
2790Sstevel@tonic-gate  *    of entry.
2800Sstevel@tonic-gate  * Both the header and attribute record have special modes/typeflags
2810Sstevel@tonic-gate  * associated with them.
2820Sstevel@tonic-gate  *
2830Sstevel@tonic-gate  * The names of the header in the archive look like:
2840Sstevel@tonic-gate  * /dev/null/attr.hdr
2850Sstevel@tonic-gate  *
2860Sstevel@tonic-gate  * The name of the attribute looks like:
2870Sstevel@tonic-gate  * /dev/null/attr
2880Sstevel@tonic-gate  *
2890Sstevel@tonic-gate  * This is done so that an archiver that doesn't understand these formats
2900Sstevel@tonic-gate  * can just dispose of the attribute records.
2910Sstevel@tonic-gate  *
2920Sstevel@tonic-gate  * The format is composed of a fixed size header followed
2930Sstevel@tonic-gate  * by a variable sized xattr_buf. If the attribute is a hard link
2940Sstevel@tonic-gate  * to another attribute then another xattr_buf section is included
2950Sstevel@tonic-gate  * for the link.
2960Sstevel@tonic-gate  *
2970Sstevel@tonic-gate  * The xattr_buf is used to define the necessary "pathing" steps
2980Sstevel@tonic-gate  * to get to the extended attribute.  This is necessary to support
2990Sstevel@tonic-gate  * a fully recursive attribute model where an attribute may itself
3000Sstevel@tonic-gate  * have an attribute.
3010Sstevel@tonic-gate  *
3020Sstevel@tonic-gate  * The basic layout looks like this.
3030Sstevel@tonic-gate  *
3040Sstevel@tonic-gate  *     --------------------------------
3050Sstevel@tonic-gate  *     |                              |
3060Sstevel@tonic-gate  *     |         xattr_hdr            |
3070Sstevel@tonic-gate  *     |                              |
3080Sstevel@tonic-gate  *     --------------------------------
3090Sstevel@tonic-gate  *     --------------------------------
3100Sstevel@tonic-gate  *     |                              |
3110Sstevel@tonic-gate  *     |        xattr_buf             |
3120Sstevel@tonic-gate  *     |                              |
3130Sstevel@tonic-gate  *     --------------------------------
3140Sstevel@tonic-gate  *     --------------------------------
3150Sstevel@tonic-gate  *     |                              |
3160Sstevel@tonic-gate  *     |      (optional link info)    |
3170Sstevel@tonic-gate  *     |                              |
3180Sstevel@tonic-gate  *     --------------------------------
3190Sstevel@tonic-gate  *     --------------------------------
3200Sstevel@tonic-gate  *     |                              |
3210Sstevel@tonic-gate  *     |      attribute itself        |
3220Sstevel@tonic-gate  *     |      stored as normal tar    |
3230Sstevel@tonic-gate  *     |      or cpio data with       |
3240Sstevel@tonic-gate  *     |      special mode or         |
3250Sstevel@tonic-gate  *     |      typeflag                |
3260Sstevel@tonic-gate  *     |                              |
3270Sstevel@tonic-gate  *     --------------------------------
3280Sstevel@tonic-gate  *
3290Sstevel@tonic-gate  */
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate /*
3320Sstevel@tonic-gate  * xattrhead is a pointer to the xattr_hdr
3330Sstevel@tonic-gate  *
3340Sstevel@tonic-gate  * xattrp is a pointer to the xattr_buf structure
3350Sstevel@tonic-gate  * which contains the "pathing" steps to get to attributes
3360Sstevel@tonic-gate  *
3370Sstevel@tonic-gate  * xattr_linkp is a pointer to another xattr_buf structure that is
3380Sstevel@tonic-gate  * only used when an attribute is actually linked to another attribute
3390Sstevel@tonic-gate  *
3400Sstevel@tonic-gate  */
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate static struct xattr_hdr *xattrhead;
3430Sstevel@tonic-gate static struct xattr_buf *xattrp;
3440Sstevel@tonic-gate static struct xattr_buf *xattr_linkp;	/* pointer to link info, if any */
3455331Samw static char *xattrapath;		/* attribute name */
3460Sstevel@tonic-gate static char *xattr_linkaname;		/* attribute attribute is linked to */
3470Sstevel@tonic-gate static char Hiddendir;			/* are we processing hidden xattr dir */
3480Sstevel@tonic-gate static char xattrbadhead;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate /* Was statically allocated tbuf[NBLOCK] */
3510Sstevel@tonic-gate static
3520Sstevel@tonic-gate union hblock {
3530Sstevel@tonic-gate 	char dummy[TBLOCK];
3540Sstevel@tonic-gate 	struct header {
3550Sstevel@tonic-gate 		char name[NAMSIZ];	/* If non-null prefix, path is	*/
3560Sstevel@tonic-gate 					/* <prefix>/<name>;  otherwise	*/
3570Sstevel@tonic-gate 					/* <name>			*/
3580Sstevel@tonic-gate 		char mode[8];
3590Sstevel@tonic-gate 		char uid[8];
3600Sstevel@tonic-gate 		char gid[8];
3610Sstevel@tonic-gate 		char size[12];		/* size of this extent if file split */
3620Sstevel@tonic-gate 		char mtime[12];
3630Sstevel@tonic-gate 		char chksum[8];
3640Sstevel@tonic-gate 		char typeflag;
3650Sstevel@tonic-gate 		char linkname[NAMSIZ];
3660Sstevel@tonic-gate 		char magic[6];
3670Sstevel@tonic-gate 		char version[2];
3680Sstevel@tonic-gate 		char uname[32];
3690Sstevel@tonic-gate 		char gname[32];
3700Sstevel@tonic-gate 		char devmajor[8];
3710Sstevel@tonic-gate 		char devminor[8];
3720Sstevel@tonic-gate 		char prefix[PRESIZ];	/* Together with "name", the path of */
3730Sstevel@tonic-gate 					/* the file:  <prefix>/<name>	*/
3740Sstevel@tonic-gate 		char extno;		/* extent #, null if not split */
3750Sstevel@tonic-gate 		char extotal;		/* total extents */
3760Sstevel@tonic-gate 		char efsize[10];	/* size of entire file */
3770Sstevel@tonic-gate 	} dbuf;
3780Sstevel@tonic-gate } dblock, *tbuf, xhdr_buf;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate static
3810Sstevel@tonic-gate struct xtar_hdr {
3820Sstevel@tonic-gate 	uid_t		x_uid,		/* Uid of file */
3830Sstevel@tonic-gate 			x_gid;		/* Gid of file */
3840Sstevel@tonic-gate 	major_t		x_devmajor;	/* Device major node */
3850Sstevel@tonic-gate 	minor_t		x_devminor;	/* Device minor node */
3860Sstevel@tonic-gate 	off_t		x_filesz;	/* Length of file */
3870Sstevel@tonic-gate 	char		*x_uname,	/* Pointer to name of user */
3880Sstevel@tonic-gate 			*x_gname,	/* Pointer to gid of user */
3890Sstevel@tonic-gate 			*x_linkpath,	/* Path for a hard/symbolic link */
3900Sstevel@tonic-gate 			*x_path;	/* Path of file */
3910Sstevel@tonic-gate 	timestruc_t	x_mtime;	/* Seconds and nanoseconds */
3920Sstevel@tonic-gate } Xtarhdr;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate static
3950Sstevel@tonic-gate struct gen_hdr {
3960Sstevel@tonic-gate 	ulong_t		g_mode;		/* Mode of file */
3970Sstevel@tonic-gate 	uid_t		g_uid,		/* Uid of file */
3980Sstevel@tonic-gate 			g_gid;		/* Gid of file */
3990Sstevel@tonic-gate 	off_t		g_filesz;	/* Length of file */
4000Sstevel@tonic-gate 	time_t		g_mtime;	/* Modification time */
4010Sstevel@tonic-gate 	uint_t		g_cksum;	/* Checksum of file */
4020Sstevel@tonic-gate 	ulong_t		g_devmajor,	/* File system of file */
4030Sstevel@tonic-gate 			g_devminor;	/* Major/minor of special files */
4040Sstevel@tonic-gate } Gen;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate static
4070Sstevel@tonic-gate struct linkbuf {
4080Sstevel@tonic-gate 	ino_t	inum;
4090Sstevel@tonic-gate 	dev_t	devnum;
4100Sstevel@tonic-gate 	int	count;
4110Sstevel@tonic-gate 	char	pathname[MAXNAM+1];	/* added 1 for last NULL */
4120Sstevel@tonic-gate 	char 	attrname[MAXNAM+1];
4130Sstevel@tonic-gate 	struct	linkbuf *nextp;
4140Sstevel@tonic-gate } *ihead;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate /* see comments before build_table() */
4170Sstevel@tonic-gate #define	TABLE_SIZE 512
4186525Sceastha typedef struct	file_list	{
4190Sstevel@tonic-gate 	char	*name;			/* Name of file to {in,ex}clude */
4200Sstevel@tonic-gate 	struct	file_list	*next;	/* Linked list */
4216525Sceastha } file_list_t;
4226525Sceastha static	file_list_t	*exclude_tbl[TABLE_SIZE],
4236525Sceastha 			*include_tbl[TABLE_SIZE];
4240Sstevel@tonic-gate 
4251676Sjpk static int	append_secattr(char **, int *, int, char *, char);
4260Sstevel@tonic-gate static void	write_ancillary(union hblock *, char *, int, char);
4270Sstevel@tonic-gate 
4286525Sceastha static void add_file_to_table(file_list_t *table[], char *str);
4290Sstevel@tonic-gate static void assert_string(char *s, char *msg);
4300Sstevel@tonic-gate static int istape(int fd, int type);
4310Sstevel@tonic-gate static void backtape(void);
4326525Sceastha static void build_table(file_list_t *table[], char *file);
4335331Samw static int check_prefix(char **namep, char **dirp, char **compp);
4340Sstevel@tonic-gate static void closevol(void);
4350Sstevel@tonic-gate static void copy(void *dst, void *src);
4360Sstevel@tonic-gate static int convtoreg(off_t);
4373805Slovely static void delete_target(int fd, char *comp, char *namep);
4380Sstevel@tonic-gate static void doDirTimes(char *name, timestruc_t modTime);
4390Sstevel@tonic-gate static void done(int n);
4400Sstevel@tonic-gate static void dorep(char *argv[]);
4410Sstevel@tonic-gate static void dotable(char *argv[]);
4420Sstevel@tonic-gate static void doxtract(char *argv[]);
44312554Srich.burridge@oracle.com static int tar_chdir(const char *path);
44412423Srich.burridge@oracle.com static int is_directory(char *name);
44512201Srich.burridge@sun.com static int has_dot_dot(char *name);
44612201Srich.burridge@sun.com static int is_absolute(char *name);
44712201Srich.burridge@sun.com static char *make_relative_name(char *name, char **stripped_prefix);
4480Sstevel@tonic-gate static void fatal(char *format, ...);
4490Sstevel@tonic-gate static void vperror(int exit_status, char *fmt, ...);
4500Sstevel@tonic-gate static void flushtape(void);
4510Sstevel@tonic-gate static void getdir(void);
4520Sstevel@tonic-gate static void *getmem(size_t);
4530Sstevel@tonic-gate static void longt(struct stat *st, char aclchar);
4545482Sas158974 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
4550Sstevel@tonic-gate static int makeDir(char *name);
4560Sstevel@tonic-gate static void mterr(char *operation, int i, int exitcode);
4570Sstevel@tonic-gate static void newvol(void);
4580Sstevel@tonic-gate static void passtape(void);
4590Sstevel@tonic-gate static void putempty(blkcnt_t n);
4600Sstevel@tonic-gate static int putfile(char *longname, char *shortname, char *parent,
4615331Samw     attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
4620Sstevel@tonic-gate static void readtape(char *buffer);
4630Sstevel@tonic-gate static void seekdisk(blkcnt_t blocks);
4640Sstevel@tonic-gate static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
4655482Sas158974 static void setbytes_to_skip(struct stat *st, int err);
4660Sstevel@tonic-gate static void splitfile(char *longname, int ifd, char *name,
4670Sstevel@tonic-gate 	char *prefix, int filetype);
4680Sstevel@tonic-gate static void tomodes(struct stat *sp);
4690Sstevel@tonic-gate static void usage(void);
4705331Samw static int xblocks(int issysattr, off_t bytes, int ofile);
4715331Samw static int xsfile(int issysattr, int ofd);
4720Sstevel@tonic-gate static void resugname(int dirfd, char *name, int symflag);
4730Sstevel@tonic-gate static int bcheck(char *bstr);
4740Sstevel@tonic-gate static int checkdir(char *name);
4750Sstevel@tonic-gate static int checksum(union hblock *dblockp);
4760Sstevel@tonic-gate #ifdef	EUC
4770Sstevel@tonic-gate static int checksum_signed(union hblock *dblockp);
4780Sstevel@tonic-gate #endif	/* EUC */
4790Sstevel@tonic-gate static int checkupdate(char *arg);
4800Sstevel@tonic-gate static int checkw(char c, char *name);
4810Sstevel@tonic-gate static int cmp(char *b, char *s, int n);
4820Sstevel@tonic-gate static int defset(char *arch);
4830Sstevel@tonic-gate static int endtape(void);
4846525Sceastha static int is_in_table(file_list_t *table[], char *str);
4850Sstevel@tonic-gate static int notsame(void);
4860Sstevel@tonic-gate static int is_prefix(char *s1, char *s2);
4870Sstevel@tonic-gate static int response(void);
4880Sstevel@tonic-gate static int build_dblock(const char *, const char *, const char,
4890Sstevel@tonic-gate 	const int filetype, const struct stat *, const dev_t, const char *);
4900Sstevel@tonic-gate static unsigned int hash(char *str);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate static blkcnt_t kcheck(char *kstr);
4930Sstevel@tonic-gate static off_t bsrch(char *s, int n, off_t l, off_t h);
4940Sstevel@tonic-gate static void onintr(int sig);
4950Sstevel@tonic-gate static void onquit(int sig);
4960Sstevel@tonic-gate static void onhup(int sig);
4970Sstevel@tonic-gate static uid_t getuidbyname(char *);
4980Sstevel@tonic-gate static gid_t getgidbyname(char *);
4990Sstevel@tonic-gate static char *getname(gid_t);
5000Sstevel@tonic-gate static char *getgroup(gid_t);
5010Sstevel@tonic-gate static int checkf(char *name, int mode, int howmuch);
5020Sstevel@tonic-gate static int writetbuf(char *buffer, int n);
5035331Samw static int wantit(char *argv[], char **namep, char **dirp, char **comp,
5045331Samw     attr_data_t **attrinfo);
5051676Sjpk static void append_ext_attr(char *shortname, char **secinfo, int *len);
5060Sstevel@tonic-gate static int get_xdata(void);
5070Sstevel@tonic-gate static void gen_num(const char *keyword, const u_longlong_t number);
5080Sstevel@tonic-gate static void gen_date(const char *keyword, const timestruc_t time_value);
5090Sstevel@tonic-gate static void gen_string(const char *keyword, const char *value);
5100Sstevel@tonic-gate static void get_xtime(char *value, timestruc_t *xtime);
5110Sstevel@tonic-gate static int chk_path_build(char *name, char *longname, char *linkname,
5120Sstevel@tonic-gate     char *prefix, char type, int filetype);
5130Sstevel@tonic-gate static int gen_utf8_names(const char *filename);
5140Sstevel@tonic-gate static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
5150Sstevel@tonic-gate     const char *src, int max_val);
5160Sstevel@tonic-gate static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
5170Sstevel@tonic-gate     iconv_t iconv_cd, int xhdrflg, int max_val);
5180Sstevel@tonic-gate static int c_utf8(char *target, const char *source);
5195331Samw static int getstat(int dirfd, char *longname, char *shortname,
5205331Samw     char *attrparent);
5215331Samw static void xattrs_put(char *, char *, char *, char *);
5220Sstevel@tonic-gate static void prepare_xattr(char **, char	*, char	*,
5230Sstevel@tonic-gate     char, struct linkbuf *, int *);
5245331Samw static int put_link(char *name, char *longname, char *component,
5255331Samw     char *longattrname, char *prefix, int filetype, char typeflag);
5260Sstevel@tonic-gate static int put_extra_attributes(char *longname, char *shortname,
5275331Samw     char *longattrname, char *prefix, int filetype, char typeflag);
5285331Samw static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
5295331Samw     char *prefix, int typeflag, int filetype, struct linkbuf *lp);
5305331Samw static int read_xattr_hdr(attr_data_t **attrinfo);
5311676Sjpk 
5321676Sjpk /* Trusted Extensions */
5331676Sjpk #define	AUTO_ZONE	"/zone"
5341676Sjpk 
5351676Sjpk static void extract_attr(char **file_ptr, struct sec_attr *);
5361676Sjpk static int check_ext_attr(char *filename);
5371676Sjpk static void rebuild_comp_path(char *str, char **namep);
5381676Sjpk static int rebuild_lk_comp_path(char *str, char **namep);
5391676Sjpk 
5400Sstevel@tonic-gate static void get_parent(char *path, char *dir);
5410Sstevel@tonic-gate static char *get_component(char *path);
5425331Samw static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
5435331Samw     char *name, int oflag, mode_t mode);
5440Sstevel@tonic-gate static char *skipslashes(char *string, char *start);
5450Sstevel@tonic-gate static void chop_endslashes(char *path);
54611990Srich.burridge@sun.com static pid_t compress_file(void);
54711990Srich.burridge@sun.com static void compress_back(void);
54811990Srich.burridge@sun.com static void decompress_file(void);
54911990Srich.burridge@sun.com static pid_t uncompress_file(void);
55011990Srich.burridge@sun.com static void *compress_malloc(size_t);
55111990Srich.burridge@sun.com static void check_compression();
55211990Srich.burridge@sun.com static char *bz_suffix();
55311990Srich.burridge@sun.com static char *gz_suffix();
55411990Srich.burridge@sun.com static char *add_suffix();
55511990Srich.burridge@sun.com static void wait_pid(pid_t);
556789Sahrens 
5570Sstevel@tonic-gate static	struct stat stbuf;
5580Sstevel@tonic-gate 
5595331Samw static	char	*myname;
5600Sstevel@tonic-gate static	int	checkflag = 0;
5610Sstevel@tonic-gate static	int	Xflag, Fflag, iflag, hflag, Bflag, Iflag;
56211990Srich.burridge@sun.com static	int	rflag, xflag, vflag, tflag, mt, svmt, cflag, mflag, pflag;
5630Sstevel@tonic-gate static	int	uflag;
564*12836Srich.burridge@oracle.com static	int	errflag;
5650Sstevel@tonic-gate static	int	oflag;
566*12836Srich.burridge@oracle.com static	int	bflag, Aflag;
5670Sstevel@tonic-gate static 	int	Pflag;			/* POSIX conformant archive */
5680Sstevel@tonic-gate static	int	Eflag;			/* Allow files greater than 8GB */
5690Sstevel@tonic-gate static	int	atflag;			/* traverse extended attributes */
5705331Samw static	int	saflag;			/* traverse extended sys attributes */
5710Sstevel@tonic-gate static	int	Dflag;			/* Data change flag */
57211990Srich.burridge@sun.com static	int	jflag;			/* flag to use 'bzip2' */
57311990Srich.burridge@sun.com static	int	zflag;			/* flag to use 'gzip' */
57411990Srich.burridge@sun.com static	int	Zflag;			/* flag to use 'compress' */
57511990Srich.burridge@sun.com 
5761676Sjpk /* Trusted Extensions */
5771676Sjpk static	int	Tflag;			/* Trusted Extensions attr flags */
5781676Sjpk static	int	dir_flag;		/* for attribute extract */
5791676Sjpk static	int	mld_flag;		/* for attribute extract */
5801676Sjpk static	char	*orig_namep;		/* original namep - unadorned */
5811676Sjpk static	int	rpath_flag;		/* MLD real path is rebuilt */
5821676Sjpk static	char	real_path[MAXPATHLEN];	/* MLD real path */
5831676Sjpk static	int	lk_rpath_flag;		/* linked to real path is rebuilt */
5841676Sjpk static	char	lk_real_path[MAXPATHLEN]; /* linked real path */
5851676Sjpk static	bslabel_t	bs_label;	/* for attribute extract */
5861676Sjpk static	bslabel_t	admin_low;
5871676Sjpk static	bslabel_t	admin_high;
5881676Sjpk static	int	ignored_aprivs = 0;
5891676Sjpk static	int	ignored_fprivs = 0;
5901676Sjpk static	int	ignored_fattrs = 0;
5911676Sjpk 
5920Sstevel@tonic-gate static	int	term, chksum, wflag,
5930Sstevel@tonic-gate 		first = TRUE, defaults_used = FALSE, linkerrok;
5940Sstevel@tonic-gate static	blkcnt_t	recno;
5950Sstevel@tonic-gate static	int	freemem = 1;
5960Sstevel@tonic-gate static	int	nblock = NBLOCK;
5970Sstevel@tonic-gate static	int	Errflg = 0;
5980Sstevel@tonic-gate static	int	exitflag = 0;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate static	dev_t	mt_dev;		/* device containing output file */
6010Sstevel@tonic-gate static	ino_t	mt_ino;		/* inode number of output file */
6020Sstevel@tonic-gate static	int	mt_devtype;	/* dev type of archive, from stat structure */
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate static	int update = 1;		/* for `open' call */
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate static	off_t	low;
6070Sstevel@tonic-gate static	off_t	high;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate static	FILE	*tfile;
6100Sstevel@tonic-gate static	FILE	*vfile = stdout;
61112422Srich.burridge@oracle.com static	char	*tmpdir;
61212422Srich.burridge@oracle.com static	char	*tmp_suffix = "/tarXXXXXX";
61312422Srich.burridge@oracle.com static	char	*tname;
6140Sstevel@tonic-gate static	char	archive[] = "archive0=";
6150Sstevel@tonic-gate static	char	*Xfile;
6160Sstevel@tonic-gate static	char	*usefile;
61711990Srich.burridge@sun.com static	char	tfname[1024];
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate static	int	mulvol;		/* multi-volume option selected */
6200Sstevel@tonic-gate static	blkcnt_t	blocklim; /* number of blocks to accept per volume */
6210Sstevel@tonic-gate static	blkcnt_t	tapepos; /* current block number to be written */
6220Sstevel@tonic-gate static	int	NotTape;	/* true if tape is a disk */
6230Sstevel@tonic-gate static	int	dumping;	/* true if writing a tape or other archive */
6240Sstevel@tonic-gate static	int	extno;		/* number of extent:  starts at 1 */
6250Sstevel@tonic-gate static	int	extotal;	/* total extents in this file */
6260Sstevel@tonic-gate static	off_t	extsize;	/* size of current extent during extraction */
6270Sstevel@tonic-gate static	ushort_t	Oumask = 0;	/* old umask value */
6280Sstevel@tonic-gate static 	int is_posix;	/* true if archive we're reading is POSIX-conformant */
6290Sstevel@tonic-gate static	const	char	*magic_type = "ustar";
6300Sstevel@tonic-gate static	size_t	xrec_size = 8 * PATH_MAX;	/* extended rec initial size */
6310Sstevel@tonic-gate static	char	*xrec_ptr;
6320Sstevel@tonic-gate static	off_t	xrec_offset = 0;
6330Sstevel@tonic-gate static	int	Xhdrflag;
6340Sstevel@tonic-gate static	int	charset_type = 0;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate static	u_longlong_t	xhdr_flgs;	/* Bits set determine which items */
6370Sstevel@tonic-gate 					/*   need to be in extended header. */
6380Sstevel@tonic-gate #define	_X_DEVMAJOR	0x1
6390Sstevel@tonic-gate #define	_X_DEVMINOR	0x2
6400Sstevel@tonic-gate #define	_X_GID		0x4
6410Sstevel@tonic-gate #define	_X_GNAME	0x8
6420Sstevel@tonic-gate #define	_X_LINKPATH	0x10
6430Sstevel@tonic-gate #define	_X_PATH		0x20
6440Sstevel@tonic-gate #define	_X_SIZE		0x40
6450Sstevel@tonic-gate #define	_X_UID		0x80
6460Sstevel@tonic-gate #define	_X_UNAME	0x100
6470Sstevel@tonic-gate #define	_X_ATIME	0x200
6480Sstevel@tonic-gate #define	_X_CTIME	0x400
6490Sstevel@tonic-gate #define	_X_MTIME	0x800
6505482Sas158974 #define	_X_XHDR		0x1000	/* Bit flag that determines whether 'X' */
6515482Sas158974 				/* typeflag was followed by 'A' or non 'A' */
6525482Sas158974 				/* typeflag. */
6530Sstevel@tonic-gate #define	_X_LAST		0x40000000
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate #define	PID_MAX_DIGITS		(10 * sizeof (pid_t) / 4)
6560Sstevel@tonic-gate #define	TIME_MAX_DIGITS		(10 * sizeof (time_t) / 4)
6570Sstevel@tonic-gate #define	LONG_MAX_DIGITS		(10 * sizeof (long) / 4)
6580Sstevel@tonic-gate #define	ULONGLONG_MAX_DIGITS	(10 * sizeof (u_longlong_t) / 4)
6590Sstevel@tonic-gate /*
6600Sstevel@tonic-gate  * UTF_8 encoding requires more space than the current codeset equivalent.
6610Sstevel@tonic-gate  * Currently a factor of 2-3 would suffice, but it is possible for a factor
6620Sstevel@tonic-gate  * of 6 to be needed in the future, so for saftey, we use that here.
6630Sstevel@tonic-gate  */
6640Sstevel@tonic-gate #define	UTF_8_FACTOR	6
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate static	u_longlong_t	xhdr_count = 0;
6670Sstevel@tonic-gate static char		xhdr_dirname[PRESIZ + 1];
6680Sstevel@tonic-gate static char		pidchars[PID_MAX_DIGITS + 1];
6690Sstevel@tonic-gate static char		*tchar = "";		/* null linkpath */
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate static	char	local_path[UTF_8_FACTOR * PATH_MAX + 1];
6720Sstevel@tonic-gate static	char	local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
6730Sstevel@tonic-gate static	char	local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
6740Sstevel@tonic-gate static	char	local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate  * The following mechanism is provided to allow us to debug tar in complicated
6780Sstevel@tonic-gate  * situations, like when it is part of a pipe.  The idea is that you compile
67911990Srich.burridge@sun.com  * with -DWAITAROUND defined, and then add the 'D' function modifier to the
68011990Srich.burridge@sun.com  * target tar invocation, eg. "tar cDf tarfile file".  If stderr is available,
6810Sstevel@tonic-gate  * it will tell you to which pid to attach the debugger; otherwise, use ps to
6820Sstevel@tonic-gate  * find it.  Attach to the process from the debugger, and, *PRESTO*, you are
6830Sstevel@tonic-gate  * there!
6840Sstevel@tonic-gate  *
6850Sstevel@tonic-gate  * Simply assign "waitaround = 0" once you attach to the process, and then
6860Sstevel@tonic-gate  * proceed from there as usual.
6870Sstevel@tonic-gate  */
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate #ifdef WAITAROUND
6900Sstevel@tonic-gate int waitaround = 0;		/* wait for rendezvous with the debugger */
6910Sstevel@tonic-gate #endif
6920Sstevel@tonic-gate 
69311990Srich.burridge@sun.com #define	BZIP		"/usr/bin/bzip2"
69411990Srich.burridge@sun.com #define	GZIP		"/usr/bin/gzip"
69511990Srich.burridge@sun.com #define	COMPRESS	"/usr/bin/compress"
69611990Srich.burridge@sun.com #define	BZCAT		"/usr/bin/bzcat"
69711990Srich.burridge@sun.com #define	GZCAT		"/usr/bin/gzcat"
69811990Srich.burridge@sun.com #define	ZCAT		"/usr/bin/zcat"
69911990Srich.burridge@sun.com #define	GS		8		/* number of valid 'gzip' sufixes */
70011990Srich.burridge@sun.com #define	BS		4		/* number of valid 'bzip2' sufixes */
70111990Srich.burridge@sun.com 
70211990Srich.burridge@sun.com static	char		*compress_opt; 	/* compression type */
70311990Srich.burridge@sun.com 
70411990Srich.burridge@sun.com static	char		*gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
70511990Srich.burridge@sun.com 			".tgz", ".taz"};
70611990Srich.burridge@sun.com static	char		*bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
70711990Srich.burridge@sun.com static	char		*suffix;
70811990Srich.burridge@sun.com 
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate int
main(int argc,char * argv[])7110Sstevel@tonic-gate main(int argc, char *argv[])
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate 	char		*cp;
7140Sstevel@tonic-gate 	char		*tmpdirp;
7150Sstevel@tonic-gate 	pid_t		thispid;
71611990Srich.burridge@sun.com 	pid_t		pid;
71711990Srich.burridge@sun.com 	int		wstat;
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
7200Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
7210Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
7220Sstevel@tonic-gate #endif
7230Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
7240Sstevel@tonic-gate 	if (argc < 2)
7250Sstevel@tonic-gate 		usage();
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	tfile = NULL;
7285331Samw 	if ((myname = strdup(argv[0])) == NULL) {
7295331Samw 		(void) fprintf(stderr, gettext(
7305331Samw 		    "tar: cannot allocate program name\n"));
7315331Samw 		exit(1);
7325331Samw 	}
7330Sstevel@tonic-gate 
7344774Sas145665 	if (init_yes() < 0) {
7354774Sas145665 		(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
7364774Sas145665 		    strerror(errno));
7374774Sas145665 		exit(2);
7384774Sas145665 	}
7394774Sas145665 
7400Sstevel@tonic-gate 	/*
7410Sstevel@tonic-gate 	 *  For XPG4 compatibility, we must be able to accept the "--"
7420Sstevel@tonic-gate 	 *  argument normally recognized by getopt; it is used to delimit
7430Sstevel@tonic-gate 	 *  the end opt the options section, and so can only appear in
7440Sstevel@tonic-gate 	 *  the position of the first argument.  We simply skip it.
7450Sstevel@tonic-gate 	 */
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	if (strcmp(argv[1], "--") == 0) {
7480Sstevel@tonic-gate 		argv++;
7490Sstevel@tonic-gate 		argc--;
7500Sstevel@tonic-gate 		if (argc < 3)
7510Sstevel@tonic-gate 			usage();
7520Sstevel@tonic-gate 	}
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	argv[argc] = NULL;
7550Sstevel@tonic-gate 	argv++;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	/*
7580Sstevel@tonic-gate 	 * Set up default values.
7590Sstevel@tonic-gate 	 * Search the operand string looking for the first digit or an 'f'.
7600Sstevel@tonic-gate 	 * If you find a digit, use the 'archive#' entry in DEF_FILE.
7610Sstevel@tonic-gate 	 * If 'f' is given, bypass looking in DEF_FILE altogether.
7620Sstevel@tonic-gate 	 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
7630Sstevel@tonic-gate 	 */
7640Sstevel@tonic-gate 	if ((usefile = getenv("TAPE")) == (char *)NULL) {
7650Sstevel@tonic-gate 		for (cp = *argv; *cp; ++cp)
7660Sstevel@tonic-gate 			if (isdigit(*cp) || *cp == 'f')
7670Sstevel@tonic-gate 				break;
7680Sstevel@tonic-gate 		if (*cp != 'f') {
7690Sstevel@tonic-gate 			archive[7] = (*cp)? *cp: '0';
7700Sstevel@tonic-gate 			if (!(defaults_used = defset(archive))) {
7710Sstevel@tonic-gate 				usefile = NULL;
7720Sstevel@tonic-gate 				nblock = 1;
7730Sstevel@tonic-gate 				blocklim = 0;
7740Sstevel@tonic-gate 				NotTape = 0;
7750Sstevel@tonic-gate 			}
7760Sstevel@tonic-gate 		}
7770Sstevel@tonic-gate 	}
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	for (cp = *argv++; *cp; cp++)
7800Sstevel@tonic-gate 		switch (*cp) {
7810Sstevel@tonic-gate #ifdef WAITAROUND
78211990Srich.burridge@sun.com 		case 'D':
7830Sstevel@tonic-gate 			/* rendezvous with the debugger */
7840Sstevel@tonic-gate 			waitaround = 1;
7850Sstevel@tonic-gate 			break;
7860Sstevel@tonic-gate #endif
7870Sstevel@tonic-gate 		case 'f':
7880Sstevel@tonic-gate 			assert_string(*argv, gettext(
7890Sstevel@tonic-gate 			    "tar: tarfile must be specified with 'f' "
7900Sstevel@tonic-gate 			    "function modifier\n"));
7910Sstevel@tonic-gate 			usefile = *argv++;
7920Sstevel@tonic-gate 			break;
7930Sstevel@tonic-gate 		case 'F':
794*12836Srich.burridge@oracle.com 			Fflag++;
7950Sstevel@tonic-gate 			break;
7960Sstevel@tonic-gate 		case 'c':
7970Sstevel@tonic-gate 			cflag++;
7980Sstevel@tonic-gate 			rflag++;
7990Sstevel@tonic-gate 			update = 1;
8000Sstevel@tonic-gate 			break;
8010Sstevel@tonic-gate #if defined(O_XATTR)
8020Sstevel@tonic-gate 		case '@':
8030Sstevel@tonic-gate 			atflag++;
8040Sstevel@tonic-gate 			break;
8055331Samw #endif	/* O_XATTR */
8065331Samw #if defined(_PC_SATTR_ENABLED)
8075331Samw 		case '/':
8085331Samw 			saflag++;
8095331Samw 			break;
8105331Samw #endif	/* _PC_SATTR_ENABLED */
8110Sstevel@tonic-gate 		case 'u':
8120Sstevel@tonic-gate 			uflag++;	/* moved code after signals caught */
8130Sstevel@tonic-gate 			rflag++;
8140Sstevel@tonic-gate 			update = 2;
8150Sstevel@tonic-gate 			break;
8160Sstevel@tonic-gate 		case 'r':
8170Sstevel@tonic-gate 			rflag++;
8180Sstevel@tonic-gate 			update = 2;
8190Sstevel@tonic-gate 			break;
8200Sstevel@tonic-gate 		case 'v':
8210Sstevel@tonic-gate 			vflag++;
8220Sstevel@tonic-gate 			break;
8230Sstevel@tonic-gate 		case 'w':
8240Sstevel@tonic-gate 			wflag++;
8250Sstevel@tonic-gate 			break;
8260Sstevel@tonic-gate 		case 'x':
8270Sstevel@tonic-gate 			xflag++;
8280Sstevel@tonic-gate 			break;
8290Sstevel@tonic-gate 		case 'X':
8300Sstevel@tonic-gate 			assert_string(*argv, gettext(
8310Sstevel@tonic-gate 			    "tar: exclude file must be specified with 'X' "
8320Sstevel@tonic-gate 			    "function modifier\n"));
8330Sstevel@tonic-gate 			Xflag = 1;
8340Sstevel@tonic-gate 			Xfile = *argv++;
8350Sstevel@tonic-gate 			build_table(exclude_tbl, Xfile);
8360Sstevel@tonic-gate 			break;
8370Sstevel@tonic-gate 		case 't':
8380Sstevel@tonic-gate 			tflag++;
8390Sstevel@tonic-gate 			break;
8400Sstevel@tonic-gate 		case 'm':
8410Sstevel@tonic-gate 			mflag++;
8420Sstevel@tonic-gate 			break;
8430Sstevel@tonic-gate 		case 'p':
8440Sstevel@tonic-gate 			pflag++;
8450Sstevel@tonic-gate 			break;
8460Sstevel@tonic-gate 		case 'D':
8470Sstevel@tonic-gate 			Dflag++;
8480Sstevel@tonic-gate 			break;
8490Sstevel@tonic-gate 		case '-':
8500Sstevel@tonic-gate 			/* ignore this silently */
8510Sstevel@tonic-gate 			break;
8520Sstevel@tonic-gate 		case '0':	/* numeric entries used only for defaults */
8530Sstevel@tonic-gate 		case '1':
8540Sstevel@tonic-gate 		case '2':
8550Sstevel@tonic-gate 		case '3':
8560Sstevel@tonic-gate 		case '4':
8570Sstevel@tonic-gate 		case '5':
8580Sstevel@tonic-gate 		case '6':
8590Sstevel@tonic-gate 		case '7':
8600Sstevel@tonic-gate 			break;
8610Sstevel@tonic-gate 		case 'b':
8620Sstevel@tonic-gate 			assert_string(*argv, gettext(
8630Sstevel@tonic-gate 			    "tar: blocking factor must be specified "
8640Sstevel@tonic-gate 			    "with 'b' function modifier\n"));
8650Sstevel@tonic-gate 			bflag++;
8660Sstevel@tonic-gate 			nblock = bcheck(*argv++);
8670Sstevel@tonic-gate 			break;
8680Sstevel@tonic-gate 		case 'n':		/* not a magtape (instead of 'k') */
8690Sstevel@tonic-gate 			NotTape++;	/* assume non-magtape */
8700Sstevel@tonic-gate 			break;
8710Sstevel@tonic-gate 		case 'l':
8720Sstevel@tonic-gate 			linkerrok++;
8730Sstevel@tonic-gate 			break;
8740Sstevel@tonic-gate 		case 'e':
875*12836Srich.burridge@oracle.com 			errflag++;
8760Sstevel@tonic-gate 		case 'o':
8770Sstevel@tonic-gate 			oflag++;
8780Sstevel@tonic-gate 			break;
8790Sstevel@tonic-gate 		case 'h':
8800Sstevel@tonic-gate 			hflag++;
8810Sstevel@tonic-gate 			break;
8820Sstevel@tonic-gate 		case 'i':
8830Sstevel@tonic-gate 			iflag++;
8840Sstevel@tonic-gate 			break;
8850Sstevel@tonic-gate 		case 'B':
8860Sstevel@tonic-gate 			Bflag++;
8870Sstevel@tonic-gate 			break;
8880Sstevel@tonic-gate 		case 'P':
8890Sstevel@tonic-gate 			Pflag++;
8900Sstevel@tonic-gate 			break;
8910Sstevel@tonic-gate 		case 'E':
8920Sstevel@tonic-gate 			Eflag++;
8930Sstevel@tonic-gate 			Pflag++;	/* Only POSIX archive made */
8940Sstevel@tonic-gate 			break;
8951676Sjpk 		case 'T':
8961676Sjpk 			Tflag++;	/* Handle Trusted Extensions attrs */
8971676Sjpk 			pflag++;	/* also set flag for ACL */
8981676Sjpk 			break;
89911990Srich.burridge@sun.com 		case 'j':		/* compession "bzip2" */
90011990Srich.burridge@sun.com 			jflag++;
90111990Srich.burridge@sun.com 			break;
90211990Srich.burridge@sun.com 		case 'z':		/* compression "gzip" */
90311990Srich.burridge@sun.com 			zflag++;
90411990Srich.burridge@sun.com 			break;
90511990Srich.burridge@sun.com 		case 'Z':		/* compression "compress" */
90611990Srich.burridge@sun.com 			Zflag++;
90711990Srich.burridge@sun.com 			break;
9080Sstevel@tonic-gate 		default:
9090Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
9100Sstevel@tonic-gate 			"tar: %c: unknown function modifier\n"), *cp);
9110Sstevel@tonic-gate 			usage();
9120Sstevel@tonic-gate 		}
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	if (!rflag && !xflag && !tflag)
9150Sstevel@tonic-gate 		usage();
9160Sstevel@tonic-gate 	if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
9170Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
9180Sstevel@tonic-gate 		"tar: specify only one of [ctxru].\n"));
9190Sstevel@tonic-gate 		usage();
9200Sstevel@tonic-gate 	}
92111990Srich.burridge@sun.com 	if (cflag) {
92211990Srich.burridge@sun.com 		if ((zflag && jflag) || (zflag && Zflag) ||
92311990Srich.burridge@sun.com 		    (jflag && Zflag)) {
92411990Srich.burridge@sun.com 			(void) fprintf(stderr, gettext(
92511990Srich.burridge@sun.com 			    "tar: specify only one of [jzZ] to "
92611990Srich.burridge@sun.com 			    "create a compressed file.\n"));
92711990Srich.burridge@sun.com 			usage();
92811990Srich.burridge@sun.com 		}
92911990Srich.burridge@sun.com 	}
9301676Sjpk 	/* Trusted Extensions attribute handling */
9311676Sjpk 	if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
9321676Sjpk 	    !is_system_labeled())) {
9331676Sjpk 		(void) fprintf(stderr, gettext(
9341676Sjpk 		"tar: the 'T' option is only available with "
9351676Sjpk 		    "Trusted Extensions\nand must be run from "
9361676Sjpk 		    "the global zone.\n"));
9371676Sjpk 		usage();
9381676Sjpk 	}
939*12836Srich.burridge@oracle.com 	if (cflag && *argv == NULL)
9400Sstevel@tonic-gate 		fatal(gettext("Missing filenames"));
9410Sstevel@tonic-gate 	if (usefile == NULL)
9420Sstevel@tonic-gate 		fatal(gettext("device argument required"));
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	/* alloc a buffer of the right size */
9450Sstevel@tonic-gate 	if ((tbuf = (union hblock *)
9461266Sceastha 	    calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
9471266Sceastha 	    (union hblock *)NULL) {
9480Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
9490Sstevel@tonic-gate 		"tar: cannot allocate physio buffer\n"));
9500Sstevel@tonic-gate 		exit(1);
9510Sstevel@tonic-gate 	}
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	if ((xrec_ptr = malloc(xrec_size)) == NULL) {
9540Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
9550Sstevel@tonic-gate 		    "tar: cannot allocate extended header buffer\n"));
9560Sstevel@tonic-gate 		exit(1);
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate #ifdef WAITAROUND
9600Sstevel@tonic-gate 	if (waitaround) {
9610Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Rendezvous with tar on pid"
9620Sstevel@tonic-gate 		    " %d\n"), getpid());
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 		while (waitaround) {
9650Sstevel@tonic-gate 			(void) sleep(10);
9660Sstevel@tonic-gate 		}
9670Sstevel@tonic-gate 	}
9680Sstevel@tonic-gate #endif
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	thispid = getpid();
9710Sstevel@tonic-gate 	(void) sprintf(pidchars, "%ld", thispid);
9720Sstevel@tonic-gate 	thispid = strlen(pidchars);
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
9750Sstevel@tonic-gate 		(void) strcpy(xhdr_dirname, "/tmp");
9760Sstevel@tonic-gate 	else {
9770Sstevel@tonic-gate 		/*
9780Sstevel@tonic-gate 		 * Make sure that dir is no longer than what can
9790Sstevel@tonic-gate 		 * fit in the prefix part of the header.
9800Sstevel@tonic-gate 		 */
9810Sstevel@tonic-gate 		if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
9820Sstevel@tonic-gate 			(void) strcpy(xhdr_dirname, "/tmp");
9830Sstevel@tonic-gate 			if ((vflag > 0) && (Eflag > 0))
9840Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
9850Sstevel@tonic-gate 				    "Ignoring TMPDIR\n"));
9860Sstevel@tonic-gate 		} else
9870Sstevel@tonic-gate 			(void) strcpy(xhdr_dirname, tmpdirp);
9880Sstevel@tonic-gate 	}
9890Sstevel@tonic-gate 	(void) strcat(xhdr_dirname, "/PaxHeaders.");
9900Sstevel@tonic-gate 	(void) strcat(xhdr_dirname, pidchars);
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	if (rflag) {
99311990Srich.burridge@sun.com 		if (cflag && usefile != NULL)  {
99411990Srich.burridge@sun.com 			/* Set the compression type */
99511990Srich.burridge@sun.com 			if (jflag) {
99611990Srich.burridge@sun.com 				compress_opt = compress_malloc(strlen(BZIP)
99711990Srich.burridge@sun.com 				    + 1);
99811990Srich.burridge@sun.com 				(void) strcpy(compress_opt, BZIP);
99911990Srich.burridge@sun.com 			} else if (zflag) {
100011990Srich.burridge@sun.com 				compress_opt = compress_malloc(strlen(GZIP)
100111990Srich.burridge@sun.com 				    + 1);
100211990Srich.burridge@sun.com 				(void) strcpy(compress_opt, GZIP);
100311990Srich.burridge@sun.com 			} else if (Zflag) {
100411990Srich.burridge@sun.com 				compress_opt =
100511990Srich.burridge@sun.com 				    compress_malloc(strlen(COMPRESS) + 1);
100611990Srich.burridge@sun.com 				(void) strcpy(compress_opt, COMPRESS);
100711990Srich.burridge@sun.com 			}
100811990Srich.burridge@sun.com 		} else {
100911990Srich.burridge@sun.com 			/*
101011990Srich.burridge@sun.com 			 * Decompress if the file is compressed for
101111990Srich.burridge@sun.com 			 * an update or replace.
101211990Srich.burridge@sun.com 			 */
101311990Srich.burridge@sun.com 			if (strcmp(usefile, "-") != 0) {
101411990Srich.burridge@sun.com 				check_compression();
101511990Srich.burridge@sun.com 				if (compress_opt != NULL) {
101611990Srich.burridge@sun.com 					decompress_file();
101711990Srich.burridge@sun.com 				}
101811990Srich.burridge@sun.com 			}
101911990Srich.burridge@sun.com 		}
102011990Srich.burridge@sun.com 
10210Sstevel@tonic-gate 		if (cflag && tfile != NULL)
10220Sstevel@tonic-gate 			usage();
10230Sstevel@tonic-gate 		if (signal(SIGINT, SIG_IGN) != SIG_IGN)
10240Sstevel@tonic-gate 			(void) signal(SIGINT, onintr);
10250Sstevel@tonic-gate 		if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
10260Sstevel@tonic-gate 			(void) signal(SIGHUP, onhup);
10270Sstevel@tonic-gate 		if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
10280Sstevel@tonic-gate 			(void) signal(SIGQUIT, onquit);
10290Sstevel@tonic-gate 		if (uflag) {
10300Sstevel@tonic-gate 			int tnum;
103112422Srich.burridge@oracle.com 			struct stat sbuf;
103212422Srich.burridge@oracle.com 
103312422Srich.burridge@oracle.com 			tmpdir = getenv("TMPDIR");
103412422Srich.burridge@oracle.com 			/*
103512422Srich.burridge@oracle.com 			 * If the name is invalid or this isn't a directory,
103612422Srich.burridge@oracle.com 			 * or the directory is not writable, then reset to
103712422Srich.burridge@oracle.com 			 * a default temporary directory.
103812422Srich.burridge@oracle.com 			 */
103912422Srich.burridge@oracle.com 			if (tmpdir == NULL || *tmpdir == '\0' ||
104012422Srich.burridge@oracle.com 			    (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
104112422Srich.burridge@oracle.com 				tmpdir = "/tmp";
104212422Srich.burridge@oracle.com 			} else if (stat(tmpdir, &sbuf) < 0 ||
104312422Srich.burridge@oracle.com 			    (sbuf.st_mode & S_IFMT) != S_IFDIR ||
104412422Srich.burridge@oracle.com 			    (sbuf.st_mode & S_IWRITE) == 0) {
104512422Srich.burridge@oracle.com 				tmpdir = "/tmp";
104612422Srich.burridge@oracle.com 			}
104712422Srich.burridge@oracle.com 
104812422Srich.burridge@oracle.com 			if ((tname = calloc(1, strlen(tmpdir) +
104912422Srich.burridge@oracle.com 			    strlen(tmp_suffix) + 1)) == NULL) {
105012422Srich.burridge@oracle.com 				vperror(1, gettext("tar: out of memory, "
105112422Srich.burridge@oracle.com 				    "cannot create temporary file\n"));
105212422Srich.burridge@oracle.com 			}
105312422Srich.burridge@oracle.com 			(void) strcpy(tname, tmpdir);
105412422Srich.burridge@oracle.com 			(void) strcat(tname, tmp_suffix);
105512422Srich.burridge@oracle.com 
10560Sstevel@tonic-gate 			if ((tnum = mkstemp(tname)) == -1)
10570Sstevel@tonic-gate 				vperror(1, "%s", tname);
10580Sstevel@tonic-gate 			if ((tfile = fdopen(tnum, "w")) == NULL)
10590Sstevel@tonic-gate 				vperror(1, "%s", tname);
10600Sstevel@tonic-gate 		}
10610Sstevel@tonic-gate 		if (strcmp(usefile, "-") == 0) {
10620Sstevel@tonic-gate 			if (cflag == 0)
10630Sstevel@tonic-gate 				fatal(gettext(
10640Sstevel@tonic-gate 				"can only create standard output archives."));
10650Sstevel@tonic-gate 			vfile = stderr;
10660Sstevel@tonic-gate 			mt = dup(1);
10670Sstevel@tonic-gate 			++bflag;
10680Sstevel@tonic-gate 		} else {
10690Sstevel@tonic-gate 			if (cflag)
10700Sstevel@tonic-gate 				mt = open(usefile,
10710Sstevel@tonic-gate 				    O_RDWR|O_CREAT|O_TRUNC, 0666);
10720Sstevel@tonic-gate 			else
10730Sstevel@tonic-gate 				mt = open(usefile, O_RDWR);
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 			if (mt < 0) {
10760Sstevel@tonic-gate 				if (cflag == 0 || (mt =  creat(usefile, 0666))
10771266Sceastha 				    < 0)
10780Sstevel@tonic-gate 				vperror(1, "%s", usefile);
10790Sstevel@tonic-gate 			}
10800Sstevel@tonic-gate 		}
10810Sstevel@tonic-gate 		/* Get inode and device number of output file */
10820Sstevel@tonic-gate 		(void) fstat(mt, &stbuf);
10830Sstevel@tonic-gate 		mt_ino = stbuf.st_ino;
10840Sstevel@tonic-gate 		mt_dev = stbuf.st_dev;
10850Sstevel@tonic-gate 		mt_devtype = stbuf.st_mode & S_IFMT;
10860Sstevel@tonic-gate 		NotTape = !istape(mt, mt_devtype);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 		if (rflag && !cflag && (mt_devtype == S_IFIFO))
10890Sstevel@tonic-gate 			fatal(gettext("cannot append to pipe or FIFO."));
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 		if (Aflag && vflag)
10920Sstevel@tonic-gate 			(void) printf(
10930Sstevel@tonic-gate 			gettext("Suppressing absolute pathnames\n"));
109411990Srich.burridge@sun.com 		if (cflag && compress_opt != NULL) {
109511990Srich.burridge@sun.com 			pid = compress_file();
109611990Srich.burridge@sun.com 			wait_pid(pid);
109711990Srich.burridge@sun.com 		}
10980Sstevel@tonic-gate 		dorep(argv);
109911990Srich.burridge@sun.com 		if (rflag && !cflag && (compress_opt != NULL))
110011990Srich.burridge@sun.com 			compress_back();
11010Sstevel@tonic-gate 	} else if (xflag || tflag) {
11020Sstevel@tonic-gate 		/*
11030Sstevel@tonic-gate 		 * for each argument, check to see if there is a "-I file" pair.
11040Sstevel@tonic-gate 		 * if so, move the 3rd argument into "-I"'s place, build_table()
11050Sstevel@tonic-gate 		 * using "file"'s name and increment argc one (the second
11060Sstevel@tonic-gate 		 * increment appears in the for loop) which removes the two
11070Sstevel@tonic-gate 		 * args "-I" and "file" from the argument vector.
11080Sstevel@tonic-gate 		 */
11090Sstevel@tonic-gate 		for (argc = 0; argv[argc]; argc++) {
11100Sstevel@tonic-gate 			if (strcmp(argv[argc], "-I") == 0) {
11110Sstevel@tonic-gate 				if (!argv[argc+1]) {
11120Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
11130Sstevel@tonic-gate 					"tar: missing argument for -I flag\n"));
11140Sstevel@tonic-gate 					done(2);
11150Sstevel@tonic-gate 				} else {
11160Sstevel@tonic-gate 					Iflag = 1;
11170Sstevel@tonic-gate 					argv[argc] = argv[argc+2];
11180Sstevel@tonic-gate 					build_table(include_tbl, argv[++argc]);
11190Sstevel@tonic-gate 				}
11200Sstevel@tonic-gate 			}
11210Sstevel@tonic-gate 		}
11220Sstevel@tonic-gate 		if (strcmp(usefile, "-") == 0) {
11230Sstevel@tonic-gate 			mt = dup(0);
11240Sstevel@tonic-gate 			++bflag;
11250Sstevel@tonic-gate 			/* try to recover from short reads when reading stdin */
11260Sstevel@tonic-gate 			++Bflag;
11270Sstevel@tonic-gate 		} else if ((mt = open(usefile, 0)) < 0)
11280Sstevel@tonic-gate 			vperror(1, "%s", usefile);
11290Sstevel@tonic-gate 
113011990Srich.burridge@sun.com 		/* Decompress if the file is compressed */
113111990Srich.burridge@sun.com 
113211990Srich.burridge@sun.com 		if (strcmp(usefile, "-") != 0) {
113311990Srich.burridge@sun.com 			check_compression();
113411990Srich.burridge@sun.com 			if (compress_opt != NULL) {
113511990Srich.burridge@sun.com 				pid = uncompress_file();
113611990Srich.burridge@sun.com 				wait_pid(pid);
113711990Srich.burridge@sun.com 			}
113811990Srich.burridge@sun.com 		}
11390Sstevel@tonic-gate 		if (xflag) {
11400Sstevel@tonic-gate 			if (Aflag && vflag)
11411266Sceastha 				(void) printf(gettext(
11421266Sceastha 				    "Suppressing absolute pathnames.\n"));
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 			doxtract(argv);
11450Sstevel@tonic-gate 		} else if (tflag)
11460Sstevel@tonic-gate 			dotable(argv);
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 	else
11490Sstevel@tonic-gate 		usage();
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	done(Errflg);
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	/* Not reached:  keep compiler quiet */
11540Sstevel@tonic-gate 	return (1);
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate static void
usage(void)11580Sstevel@tonic-gate usage(void)
11590Sstevel@tonic-gate {
1160*12836Srich.burridge@oracle.com 	(void) fprintf(stderr, gettext(
11610Sstevel@tonic-gate #if defined(O_XATTR)
11625331Samw #if defined(_PC_SATTR_ENABLED)
1163*12836Srich.burridge@oracle.com 	    "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
11645331Samw #else
1165*12836Srich.burridge@oracle.com 	    "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
11665331Samw #endif	/* _PC_SATTR_ENABLED */
11670Sstevel@tonic-gate #else
1168*12836Srich.burridge@oracle.com 	    "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
11695331Samw #endif	/* O_XATTR */
1170*12836Srich.burridge@oracle.com 	    "[j|z|Z] "
1171*12836Srich.burridge@oracle.com 	    "[blocksize] [tarfile] [size] [exclude-file...] "
1172*12836Srich.burridge@oracle.com 	    "{file | -I include-file | -C directory file}...\n"));
11730Sstevel@tonic-gate 	done(1);
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate /*
11770Sstevel@tonic-gate  * dorep - do "replacements"
11780Sstevel@tonic-gate  *
11790Sstevel@tonic-gate  *	Dorep is responsible for creating ('c'),  appending ('r')
11800Sstevel@tonic-gate  *	and updating ('u');
11810Sstevel@tonic-gate  */
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate static void
dorep(char * argv[])11840Sstevel@tonic-gate dorep(char *argv[])
11850Sstevel@tonic-gate {
11860Sstevel@tonic-gate 	char *cp, *cp2, *p;
11870Sstevel@tonic-gate 	char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
11880Sstevel@tonic-gate 	char file[PATH_MAX*2], origdir[PATH_MAX+1];
11890Sstevel@tonic-gate 	FILE *fp = (FILE *)NULL;
11900Sstevel@tonic-gate 	int archtype;
11915482Sas158974 	int ret;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	if (!cflag) {
11950Sstevel@tonic-gate 		xhdr_flgs = 0;
11960Sstevel@tonic-gate 		getdir();			/* read header for next file */
11970Sstevel@tonic-gate 		if (Xhdrflag > 0) {
11980Sstevel@tonic-gate 			if (!Eflag)
11990Sstevel@tonic-gate 				fatal(gettext("Archive contains extended"
12000Sstevel@tonic-gate 				    " header.  -E flag required.\n"));
12015482Sas158974 			ret = get_xdata();	/* Get extended header items */
12020Sstevel@tonic-gate 						/*   and regular header */
12030Sstevel@tonic-gate 		} else {
12040Sstevel@tonic-gate 			if (Eflag)
12050Sstevel@tonic-gate 				fatal(gettext("Archive contains no extended"
12060Sstevel@tonic-gate 				    " header.  -E flag not allowed.\n"));
12070Sstevel@tonic-gate 		}
12080Sstevel@tonic-gate 		while (!endtape()) {		/* changed from a do while */
12095482Sas158974 			setbytes_to_skip(&stbuf, ret);
12100Sstevel@tonic-gate 			passtape();		/* skip the file data */
12110Sstevel@tonic-gate 			if (term)
12120Sstevel@tonic-gate 				done(Errflg);	/* received signal to stop */
12130Sstevel@tonic-gate 			xhdr_flgs = 0;
12140Sstevel@tonic-gate 			getdir();
12150Sstevel@tonic-gate 			if (Xhdrflag > 0)
12165482Sas158974 				ret = get_xdata();
12175482Sas158974 		}
12185482Sas158974 		if (ret == 0) {
12195482Sas158974 			if ((dblock.dbuf.typeflag != 'A') &&
12205482Sas158974 			    (xhdr_flgs != 0)) {
12215482Sas158974 				load_info_from_xtarhdr(xhdr_flgs,
12225482Sas158974 				    &Xtarhdr);
12235482Sas158974 				xhdr_flgs |= _X_XHDR;
12245482Sas158974 			}
12250Sstevel@tonic-gate 		}
12260Sstevel@tonic-gate 		backtape();			/* was called by endtape */
12270Sstevel@tonic-gate 		if (tfile != NULL) {
122812422Srich.burridge@oracle.com 			/*
122912422Srich.burridge@oracle.com 			 * Buffer size is calculated to be the size of the
123012422Srich.burridge@oracle.com 			 * tmpdir string, plus 6 times the size of the tname
123112422Srich.burridge@oracle.com 			 * string, plus a value that is known to be greater
123212422Srich.burridge@oracle.com 			 * than the command pipeline string.
123312422Srich.burridge@oracle.com 			 */
123412422Srich.burridge@oracle.com 			int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
123512422Srich.burridge@oracle.com 			char *buf;
123612422Srich.burridge@oracle.com 
123712422Srich.burridge@oracle.com 			if ((buf = (char *)calloc(1, buflen)) == NULL) {
123812422Srich.burridge@oracle.com 				vperror(1, gettext("tar: out of memory, "
123912422Srich.burridge@oracle.com 				    "cannot create sort command file\n"));
124012422Srich.burridge@oracle.com 			}
124112422Srich.burridge@oracle.com 
124212422Srich.burridge@oracle.com 			(void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
124312422Srich.burridge@oracle.com 			    "sort +0 -1 +1nr %s -o %s; awk '$1 "
12440Sstevel@tonic-gate 			    "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
124512422Srich.burridge@oracle.com 			    tmpdir, tname, tname, tname, tname, tname, tname);
12460Sstevel@tonic-gate 			(void) fflush(tfile);
12470Sstevel@tonic-gate 			(void) system(buf);
124812422Srich.burridge@oracle.com 			free(buf);
12490Sstevel@tonic-gate 			(void) freopen(tname, "r", tfile);
12500Sstevel@tonic-gate 			(void) fstat(fileno(tfile), &stbuf);
12510Sstevel@tonic-gate 			high = stbuf.st_size;
12520Sstevel@tonic-gate 		}
12530Sstevel@tonic-gate 	}
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	dumping = 1;
12560Sstevel@tonic-gate 	if (mulvol) {	/* SP-1 */
12570Sstevel@tonic-gate 		if (nblock && (blocklim%nblock) != 0)
12580Sstevel@tonic-gate 			fatal(gettext(
12590Sstevel@tonic-gate 			"Volume size not a multiple of block size."));
12600Sstevel@tonic-gate 		blocklim -= 2;			/* for trailer records */
12610Sstevel@tonic-gate 		if (vflag)
12620Sstevel@tonic-gate 			(void) fprintf(vfile, gettext("Volume ends at %"
12630Sstevel@tonic-gate 			    FMT_blkcnt_t "K, blocking factor = %dK\n"),
12640Sstevel@tonic-gate 			    K((blocklim - 1)), K(nblock));
12650Sstevel@tonic-gate 	}
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	/*
12680Sstevel@tonic-gate 	 * Save the original directory before it gets
12690Sstevel@tonic-gate 	 * changed.
12700Sstevel@tonic-gate 	 */
12710Sstevel@tonic-gate 	if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
12720Sstevel@tonic-gate 		vperror(0, gettext("A parent directory cannot be read"));
12730Sstevel@tonic-gate 		exit(1);
12740Sstevel@tonic-gate 	}
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	(void) strcpy(wdir, origdir);
12770Sstevel@tonic-gate 
1278*12836Srich.burridge@oracle.com 	while ((*argv || fp) && !term) {
12790Sstevel@tonic-gate 		if (fp || (strcmp(*argv, "-I") == 0)) {
12800Sstevel@tonic-gate 			if (fp == NULL) {
12810Sstevel@tonic-gate 				if (*++argv == NULL)
12820Sstevel@tonic-gate 					fatal(gettext(
12830Sstevel@tonic-gate 					    "missing file name for -I flag."));
12840Sstevel@tonic-gate 				else if ((fp = fopen(*argv++, "r")) == NULL)
12850Sstevel@tonic-gate 					vperror(0, "%s", argv[-1]);
12860Sstevel@tonic-gate 				continue;
12870Sstevel@tonic-gate 			} else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
12880Sstevel@tonic-gate 				(void) fclose(fp);
12890Sstevel@tonic-gate 				fp = NULL;
12900Sstevel@tonic-gate 				continue;
12910Sstevel@tonic-gate 			} else {
12920Sstevel@tonic-gate 				cp = cp2 = file;
12930Sstevel@tonic-gate 				if ((p = strchr(cp2, '\n')))
12940Sstevel@tonic-gate 					*p = 0;
12950Sstevel@tonic-gate 			}
12960Sstevel@tonic-gate 		} else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
129712554Srich.burridge@oracle.com 			if (tar_chdir(*++argv) < 0)
12980Sstevel@tonic-gate 				vperror(0, gettext(
12995331Samw 				    "can't change directories to %s"), *argv);
13000Sstevel@tonic-gate 			else
13010Sstevel@tonic-gate 				(void) getcwd(wdir, (sizeof (wdir)));
13020Sstevel@tonic-gate 			argv++;
13030Sstevel@tonic-gate 			continue;
13040Sstevel@tonic-gate 		} else
13050Sstevel@tonic-gate 			cp = cp2 = strcpy(file, *argv++);
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 		/*
13080Sstevel@tonic-gate 		 * point cp2 to the last '/' in file, but not
13090Sstevel@tonic-gate 		 * to a trailing '/'
13100Sstevel@tonic-gate 		 */
13110Sstevel@tonic-gate 		for (; *cp; cp++) {
13120Sstevel@tonic-gate 			if (*cp == '/') {
13130Sstevel@tonic-gate 				while (*(cp+1) == '/') {
13140Sstevel@tonic-gate 					++cp;
13150Sstevel@tonic-gate 				}
13160Sstevel@tonic-gate 				if (*(cp+1) != '\0') {
13170Sstevel@tonic-gate 					/* not trailing slash */
13180Sstevel@tonic-gate 					cp2 = cp;
13190Sstevel@tonic-gate 				}
13200Sstevel@tonic-gate 			}
13210Sstevel@tonic-gate 		}
13220Sstevel@tonic-gate 		if (cp2 != file) {
13230Sstevel@tonic-gate 			*cp2 = '\0';
132412554Srich.burridge@oracle.com 			if (tar_chdir(file) < 0) {
13250Sstevel@tonic-gate 				vperror(0, gettext(
13265331Samw 				    "can't change directories to %s"), file);
13270Sstevel@tonic-gate 				continue;
13280Sstevel@tonic-gate 			}
13290Sstevel@tonic-gate 			*cp2 = '/';
13300Sstevel@tonic-gate 			cp2++;
13310Sstevel@tonic-gate 		}
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 		parent = getcwd(tempdir, (sizeof (tempdir)));
13345331Samw 
13355331Samw 		archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
13360Sstevel@tonic-gate 		    LEV0, SYMLINK_LEV0);
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate #if defined(O_XATTR)
13390Sstevel@tonic-gate 		if (!exitflag) {
13405331Samw 			if ((atflag || saflag) &&
13415331Samw 			    (archtype == PUT_NOTAS_LINK)) {
13425331Samw 				xattrs_put(file, cp2, parent, NULL);
13430Sstevel@tonic-gate 			}
13440Sstevel@tonic-gate 		}
13450Sstevel@tonic-gate #endif
13460Sstevel@tonic-gate 
134712554Srich.burridge@oracle.com 		if (tar_chdir(origdir) < 0)
13480Sstevel@tonic-gate 			vperror(0, gettext("cannot change back?: %s"), origdir);
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 		if (exitflag) {
13510Sstevel@tonic-gate 			/*
13520Sstevel@tonic-gate 			 * If e function modifier has been specified
13530Sstevel@tonic-gate 			 * write the files (that are listed before the
13540Sstevel@tonic-gate 			 * file causing the error) to tape.  exitflag is
13550Sstevel@tonic-gate 			 * used because only some of the error conditions
13560Sstevel@tonic-gate 			 * in putfile() recognize the e function modifier.
13570Sstevel@tonic-gate 			 */
13580Sstevel@tonic-gate 			break;
13590Sstevel@tonic-gate 		}
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	putempty((blkcnt_t)2);
13630Sstevel@tonic-gate 	flushtape();
13640Sstevel@tonic-gate 	closevol();	/* SP-1 */
13650Sstevel@tonic-gate 	if (linkerrok == 1)
13660Sstevel@tonic-gate 		for (; ihead != NULL; ihead = ihead->nextp) {
13670Sstevel@tonic-gate 			if (ihead->count == 0)
13680Sstevel@tonic-gate 				continue;
13690Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
13700Sstevel@tonic-gate 			"tar: missing links to %s\n"), ihead->pathname);
13710Sstevel@tonic-gate 			if (errflag)
13720Sstevel@tonic-gate 				done(1);
13730Sstevel@tonic-gate 			else
13740Sstevel@tonic-gate 				Errflg = 1;
13750Sstevel@tonic-gate 		}
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate /*
13800Sstevel@tonic-gate  * endtape - check for tape at end
13810Sstevel@tonic-gate  *
13820Sstevel@tonic-gate  *	endtape checks the entry in dblock.dbuf to see if its the
13830Sstevel@tonic-gate  *	special EOT entry.  Endtape is usually called after getdir().
13840Sstevel@tonic-gate  *
13850Sstevel@tonic-gate  *	endtape used to call backtape; it no longer does, he who
13860Sstevel@tonic-gate  *	wants it backed up must call backtape himself
13870Sstevel@tonic-gate  *	RETURNS:	0 if not EOT, tape position unaffected
13880Sstevel@tonic-gate  *			1 if	 EOT, tape position unaffected
13890Sstevel@tonic-gate  */
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate static int
endtape(void)13920Sstevel@tonic-gate endtape(void)
13930Sstevel@tonic-gate {
13940Sstevel@tonic-gate 	if (dblock.dbuf.name[0] == '\0') {	/* null header = EOT */
13950Sstevel@tonic-gate 		return (1);
13960Sstevel@tonic-gate 	} else
13970Sstevel@tonic-gate 		return (0);
13980Sstevel@tonic-gate }
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate /*
14010Sstevel@tonic-gate  *	getdir - get directory entry from tar tape
14020Sstevel@tonic-gate  *
14030Sstevel@tonic-gate  *	getdir reads the next tarblock off the tape and cracks
14040Sstevel@tonic-gate  *	it as a directory. The checksum must match properly.
14050Sstevel@tonic-gate  *
14060Sstevel@tonic-gate  *	If tfile is non-null getdir writes the file name and mod date
14070Sstevel@tonic-gate  *	to tfile.
14080Sstevel@tonic-gate  */
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate static void
getdir(void)14110Sstevel@tonic-gate getdir(void)
14120Sstevel@tonic-gate {
14130Sstevel@tonic-gate 	struct stat *sp;
14140Sstevel@tonic-gate #ifdef EUC
14150Sstevel@tonic-gate 	static int warn_chksum_sign = 0;
14160Sstevel@tonic-gate #endif /* EUC */
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate top:
14190Sstevel@tonic-gate 	readtape((char *)&dblock);
14200Sstevel@tonic-gate 	if (dblock.dbuf.name[0] == '\0')
14210Sstevel@tonic-gate 		return;
14220Sstevel@tonic-gate 	sp = &stbuf;
14230Sstevel@tonic-gate 	(void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
14240Sstevel@tonic-gate 	(void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
14250Sstevel@tonic-gate 	(void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
14260Sstevel@tonic-gate 	(void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
14270Sstevel@tonic-gate 	(void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
14280Sstevel@tonic-gate 	(void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
14290Sstevel@tonic-gate 	(void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
14300Sstevel@tonic-gate 	(void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 	is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	sp->st_mode = Gen.g_mode;
14350Sstevel@tonic-gate 	if (is_posix && (sp->st_mode & S_IFMT) == 0)
14360Sstevel@tonic-gate 		switch (dblock.dbuf.typeflag) {
14370Sstevel@tonic-gate 		case '0': case 0: case _XATTR_HDRTYPE:
14380Sstevel@tonic-gate 			sp->st_mode |= S_IFREG;
14390Sstevel@tonic-gate 			break;
14400Sstevel@tonic-gate 		case '1':	/* hard link */
14410Sstevel@tonic-gate 			break;
14420Sstevel@tonic-gate 		case '2':
14430Sstevel@tonic-gate 			sp->st_mode |= S_IFLNK;
14440Sstevel@tonic-gate 			break;
14450Sstevel@tonic-gate 		case '3':
14460Sstevel@tonic-gate 			sp->st_mode |= S_IFCHR;
14470Sstevel@tonic-gate 			break;
14480Sstevel@tonic-gate 		case '4':
14490Sstevel@tonic-gate 			sp->st_mode |= S_IFBLK;
14500Sstevel@tonic-gate 			break;
14510Sstevel@tonic-gate 		case '5':
14520Sstevel@tonic-gate 			sp->st_mode |= S_IFDIR;
14530Sstevel@tonic-gate 			break;
14540Sstevel@tonic-gate 		case '6':
14550Sstevel@tonic-gate 			sp->st_mode |= S_IFIFO;
14560Sstevel@tonic-gate 			break;
14570Sstevel@tonic-gate 		default:
14580Sstevel@tonic-gate 			if (convtoreg(Gen.g_filesz))
14590Sstevel@tonic-gate 				sp->st_mode |= S_IFREG;
14600Sstevel@tonic-gate 			break;
14610Sstevel@tonic-gate 		}
14620Sstevel@tonic-gate 
146311995Srich.burridge@sun.com 	if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
14640Sstevel@tonic-gate 		Xhdrflag = 1;	/* Currently processing extended header */
146511995Srich.burridge@sun.com 	} else {
14660Sstevel@tonic-gate 		Xhdrflag = 0;
146711995Srich.burridge@sun.com 	}
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	sp->st_uid = Gen.g_uid;
14700Sstevel@tonic-gate 	sp->st_gid = Gen.g_gid;
14710Sstevel@tonic-gate 	sp->st_size = Gen.g_filesz;
14720Sstevel@tonic-gate 	sp->st_mtime = Gen.g_mtime;
14730Sstevel@tonic-gate 	chksum = Gen.g_cksum;
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 	if (dblock.dbuf.extno != '\0') {	/* split file? */
14760Sstevel@tonic-gate 		extno = dblock.dbuf.extno;
14770Sstevel@tonic-gate 		extsize = Gen.g_filesz;
14780Sstevel@tonic-gate 		extotal = dblock.dbuf.extotal;
14790Sstevel@tonic-gate 	} else {
14800Sstevel@tonic-gate 		extno = 0;	/* tell others file not split */
14810Sstevel@tonic-gate 		extsize = 0;
14820Sstevel@tonic-gate 		extotal = 0;
14830Sstevel@tonic-gate 	}
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate #ifdef	EUC
14860Sstevel@tonic-gate 	if (chksum != checksum(&dblock)) {
14870Sstevel@tonic-gate 		if (chksum != checksum_signed(&dblock)) {
14880Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
14890Sstevel@tonic-gate 			    "tar: directory checksum error\n"));
149012535Srich.burridge@oracle.com 			if (iflag) {
149112535Srich.burridge@oracle.com 				Errflg = 2;
14920Sstevel@tonic-gate 				goto top;
149312535Srich.burridge@oracle.com 			}
14940Sstevel@tonic-gate 			done(2);
14950Sstevel@tonic-gate 		} else {
14960Sstevel@tonic-gate 			if (! warn_chksum_sign) {
14970Sstevel@tonic-gate 				warn_chksum_sign = 1;
14980Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
14990Sstevel@tonic-gate 			"tar: warning: tar file made with signed checksum\n"));
15000Sstevel@tonic-gate 			}
15010Sstevel@tonic-gate 		}
15020Sstevel@tonic-gate 	}
15030Sstevel@tonic-gate #else
15040Sstevel@tonic-gate 	if (chksum != checksum(&dblock)) {
15050Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
15060Sstevel@tonic-gate 		"tar: directory checksum error\n"));
150712535Srich.burridge@oracle.com 		if (iflag) {
150812535Srich.burridge@oracle.com 			Errflg = 2;
15090Sstevel@tonic-gate 			goto top;
151012535Srich.burridge@oracle.com 		}
15110Sstevel@tonic-gate 		done(2);
15120Sstevel@tonic-gate 	}
15130Sstevel@tonic-gate #endif	/* EUC */
15140Sstevel@tonic-gate 	if (tfile != NULL && Xhdrflag == 0) {
15150Sstevel@tonic-gate 		/*
15160Sstevel@tonic-gate 		 * If an extended header is present, then time is available
15170Sstevel@tonic-gate 		 * in nanoseconds in the extended header data, so set it.
15180Sstevel@tonic-gate 		 * Otherwise, give an invalid value so that checkupdate will
15190Sstevel@tonic-gate 		 * not test beyond seconds.
15200Sstevel@tonic-gate 		 */
15210Sstevel@tonic-gate 		if ((xhdr_flgs & _X_MTIME))
15220Sstevel@tonic-gate 			sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
15230Sstevel@tonic-gate 		else
15240Sstevel@tonic-gate 			sp->st_mtim.tv_nsec = -1;
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 		if (xhdr_flgs & _X_PATH)
15270Sstevel@tonic-gate 			(void) fprintf(tfile, "%s %10ld.%9.9ld\n",
15280Sstevel@tonic-gate 			    Xtarhdr.x_path, sp->st_mtim.tv_sec,
15290Sstevel@tonic-gate 			    sp->st_mtim.tv_nsec);
15300Sstevel@tonic-gate 		else
15310Sstevel@tonic-gate 			(void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
15320Sstevel@tonic-gate 			    NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
15330Sstevel@tonic-gate 			    sp->st_mtim.tv_nsec);
15340Sstevel@tonic-gate 	}
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate #if defined(O_XATTR)
15370Sstevel@tonic-gate 	Hiddendir = 0;
15380Sstevel@tonic-gate 	if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
15390Sstevel@tonic-gate 		if (xattrbadhead) {
15400Sstevel@tonic-gate 			free(xattrhead);
15410Sstevel@tonic-gate 			xattrp = NULL;
15420Sstevel@tonic-gate 			xattr_linkp = NULL;
15430Sstevel@tonic-gate 			xattrhead = NULL;
15440Sstevel@tonic-gate 		} else {
15455331Samw 			char	*aname = basename(xattrapath);
15465331Samw 			size_t	xindex  = aname - xattrapath;
15475331Samw 
15485331Samw 			if (xattrapath[xindex] == '.' &&
15495331Samw 			    xattrapath[xindex + 1] == '\0' &&
15500Sstevel@tonic-gate 			    xattrp->h_typeflag == '5') {
15510Sstevel@tonic-gate 				Hiddendir = 1;
15520Sstevel@tonic-gate 				sp->st_mode =
15531231Smarks 				    (S_IFDIR | (sp->st_mode & POSIXMODES));
15540Sstevel@tonic-gate 			}
15550Sstevel@tonic-gate 			dblock.dbuf.typeflag = xattrp->h_typeflag;
15560Sstevel@tonic-gate 		}
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate #endif
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate /*
15630Sstevel@tonic-gate  *	passtape - skip over a file on the tape
15640Sstevel@tonic-gate  *
15650Sstevel@tonic-gate  *	passtape skips over the next data file on the tape.
15660Sstevel@tonic-gate  *	The tape directory entry must be in dblock.dbuf. This
15670Sstevel@tonic-gate  *	routine just eats the number of blocks computed from the
15680Sstevel@tonic-gate  *	directory size entry; the tape must be (logically) positioned
15690Sstevel@tonic-gate  *	right after thee directory info.
15700Sstevel@tonic-gate  */
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate static void
passtape(void)15730Sstevel@tonic-gate passtape(void)
15740Sstevel@tonic-gate {
15750Sstevel@tonic-gate 	blkcnt_t blocks;
15760Sstevel@tonic-gate 	char buf[TBLOCK];
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	/*
15790Sstevel@tonic-gate 	 * Types link(1), sym-link(2), char special(3), blk special(4),
15800Sstevel@tonic-gate 	 *  directory(5), and FIFO(6) do not have data blocks associated
15810Sstevel@tonic-gate 	 *  with them so just skip reading the data block.
15820Sstevel@tonic-gate 	 */
15830Sstevel@tonic-gate 	if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
15841266Sceastha 	    dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
15851266Sceastha 	    dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
15860Sstevel@tonic-gate 		return;
15870Sstevel@tonic-gate 	blocks = TBLOCKS(stbuf.st_size);
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 	/* if operating on disk, seek instead of reading */
15900Sstevel@tonic-gate 	if (NotTape)
15910Sstevel@tonic-gate 		seekdisk(blocks);
15920Sstevel@tonic-gate 	else
15930Sstevel@tonic-gate 		while (blocks-- > 0)
15940Sstevel@tonic-gate 			readtape(buf);
15950Sstevel@tonic-gate }
15960Sstevel@tonic-gate 
15975331Samw #if defined(O_XATTR)
15985331Samw static int
is_sysattr(char * name)15995331Samw is_sysattr(char *name)
16005331Samw {
16015331Samw 	return ((strcmp(name, VIEW_READONLY) == 0) ||
16025331Samw 	    (strcmp(name, VIEW_READWRITE) == 0));
16035331Samw }
16045331Samw #endif
16055331Samw 
16065331Samw #if defined(O_XATTR)
16075331Samw /*
16085331Samw  * Verify the attribute, attrname, is an attribute we want to restore.
16095331Samw  * Never restore read-only system attribute files.  Only restore read-write
16105331Samw  * system attributes files when -/ was specified, and only traverse into
16115331Samw  * the 2nd level attribute directory containing only system attributes if
16125331Samw  * -@ was specified.  This keeps us from archiving
16135331Samw  *	<attribute name>/<read-write system attribute file>
16145331Samw  * when -/ was specified without -@.
16155331Samw  *
16165331Samw  * attrname	- attribute file name
16175331Samw  * attrparent	- attribute's parent name within the base file's attribute
16185331Samw  *		directory hierarchy
16195331Samw  */
16205331Samw static attr_status_t
verify_attr(char * attrname,char * attrparent,int arc_rwsysattr,int * rw_sysattr)16215331Samw verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
16225331Samw     int *rw_sysattr)
16235331Samw {
16245331Samw #if defined(_PC_SATTR_ENABLED)
16255331Samw 	int	attr_supported;
16265331Samw 
16275331Samw 	/* Never restore read-only system attribute files */
16285331Samw 	if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
16295331Samw 		*rw_sysattr = 0;
16305331Samw 		return (ATTR_SKIP);
16315331Samw 	} else {
16325331Samw 		*rw_sysattr = (attr_supported == _RW_SATTR);
16335331Samw 	}
16345331Samw #else
16355331Samw 	/*
16365331Samw 	 * Only need to check if this attribute is an extended system
16375331Samw 	 * attribute.
16385331Samw 	 */
16395331Samw 	if (*rw_sysattr = is_sysattr(attrname)) {
16405331Samw 		return (ATTR_SKIP);
16415331Samw 	} else {
16425331Samw 		return (ATTR_OK);
16435331Samw 	}
16445331Samw #endif	/* _PC_SATTR_ENABLED */
16455331Samw 
16465331Samw 	/*
16475331Samw 	 * If the extended system attribute file is specified with the
16485331Samw 	 * arc_rwsysattr flag, as being transient (default extended
16495331Samw 	 * attributes), then don't archive it.
16505331Samw 	 */
16515331Samw 	if (*rw_sysattr && !arc_rwsysattr) {
16525331Samw 		return (ATTR_SKIP);
16535331Samw 	}
16545331Samw 
16555331Samw 	/*
16565331Samw 	 * Only restore read-write system attribute files
16575331Samw 	 * when -/ was specified.  Only restore extended
16585331Samw 	 * attributes when -@ was specified.
16595331Samw 	 */
16605331Samw 	if (atflag) {
16615331Samw 		if (!saflag) {
16625331Samw 			/*
16635331Samw 			 * Only archive/restore the hidden directory "." if
16645331Samw 			 * we're processing the top level hidden attribute
16655331Samw 			 * directory.  We don't want to process the
16665331Samw 			 * hidden attribute directory of the attribute
16675331Samw 			 * directory that contains only extended system
16685331Samw 			 * attributes.
16695331Samw 			 */
16705331Samw 			if (*rw_sysattr || (Hiddendir &&
16715331Samw 			    (attrparent != NULL))) {
16725331Samw 				return (ATTR_SKIP);
16735331Samw 			}
16745331Samw 		}
16755331Samw 	} else if (saflag) {
16765331Samw 		/*
16775331Samw 		 * Only archive/restore read-write extended system attribute
16785331Samw 		 * files of the base file.
16795331Samw 		 */
16805331Samw 		if (!*rw_sysattr || (attrparent != NULL)) {
16815331Samw 			return (ATTR_SKIP);
16825331Samw 		}
16835331Samw 	} else {
16845331Samw 		return (ATTR_SKIP);
16855331Samw 	}
16865331Samw 
16875331Samw 	return (ATTR_OK);
16885331Samw }
16895331Samw #endif
16900Sstevel@tonic-gate 
16916525Sceastha static void
free_children(file_list_t * children)16926525Sceastha free_children(file_list_t *children)
16936525Sceastha {
16946525Sceastha 	file_list_t	*child = children;
16956525Sceastha 	file_list_t	*cptr;
16966525Sceastha 
16976525Sceastha 	while (child != NULL) {
16986525Sceastha 		cptr = child->next;
16996525Sceastha 		if (child->name != NULL) {
17006525Sceastha 			free(child->name);
17016525Sceastha 		}
17026525Sceastha 		child = cptr;
17036525Sceastha 	}
17046525Sceastha }
17056525Sceastha 
17060Sstevel@tonic-gate static int
putfile(char * longname,char * shortname,char * parent,attr_data_t * attrinfo,int filetype,int lev,int symlink_lev)17075331Samw putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
17080Sstevel@tonic-gate     int filetype, int lev, int symlink_lev)
17090Sstevel@tonic-gate {
17100Sstevel@tonic-gate 	int infile = -1;	/* deliberately invalid */
17110Sstevel@tonic-gate 	blkcnt_t blocks;
17120Sstevel@tonic-gate 	char buf[PATH_MAX + 2];	/* Add trailing slash and null */
17130Sstevel@tonic-gate 	char *bigbuf;
17140Sstevel@tonic-gate 	int	maxread;
17150Sstevel@tonic-gate 	int	hint;		/* amount to write to get "in sync" */
17160Sstevel@tonic-gate 	char filetmp[PATH_MAX + 1];
17170Sstevel@tonic-gate 	char *cp;
17180Sstevel@tonic-gate 	char *name;
17195331Samw 	char *attrparent = NULL;
17205331Samw 	char *longattrname = NULL;
17216525Sceastha 	file_list_t	*child = NULL;
17226525Sceastha 	file_list_t	*child_end = NULL;
17236525Sceastha 	file_list_t	*cptr;
17240Sstevel@tonic-gate 	struct dirent *dp;
17250Sstevel@tonic-gate 	DIR *dirp;
17260Sstevel@tonic-gate 	int i;
17270Sstevel@tonic-gate 	int split;
17280Sstevel@tonic-gate 	int dirfd = -1;
17290Sstevel@tonic-gate 	int rc = PUT_NOTAS_LINK;
17300Sstevel@tonic-gate 	int archtype = 0;
17315331Samw 	int rw_sysattr = 0;
17320Sstevel@tonic-gate 	char newparent[PATH_MAX + MAXNAMLEN + 1];
17330Sstevel@tonic-gate 	char *prefix = "";
17340Sstevel@tonic-gate 	char *tmpbuf;
17350Sstevel@tonic-gate 	char goodbuf[PRESIZ + 2];
17360Sstevel@tonic-gate 	char junkbuf[MAXNAM+1];
17370Sstevel@tonic-gate 	char *lastslash;
17380Sstevel@tonic-gate 	int j;
17390Sstevel@tonic-gate 	struct stat sbuf;
17400Sstevel@tonic-gate 	int readlink_max;
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	(void) memset(goodbuf, '\0', sizeof (goodbuf));
17430Sstevel@tonic-gate 	(void) memset(junkbuf, '\0', sizeof (junkbuf));
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	xhdr_flgs = 0;
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	if (filetype == XATTR_FILE) {
17485331Samw 		attrparent = attrinfo->attr_parent;
17495331Samw 		longattrname = attrinfo->attr_path;
17505331Samw 		dirfd = attrinfo->attr_parentfd;
17515750Sceastha 		rw_sysattr = attrinfo->attr_rw_sysattr;
17520Sstevel@tonic-gate 	} else {
17530Sstevel@tonic-gate 		dirfd = open(".", O_RDONLY);
17540Sstevel@tonic-gate 	}
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 	if (dirfd == -1) {
17570Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
17585331Samw 		    "tar: unable to open%sdirectory %s%s%s%s\n"),
17590Sstevel@tonic-gate 		    (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
17605331Samw 		    (attrparent == NULL) ? "" : gettext("of attribute "),
17615331Samw 		    (attrparent == NULL) ? "" : attrparent,
17625331Samw 		    (attrparent == NULL) ? "" : gettext(" of "),
17630Sstevel@tonic-gate 		    (filetype == XATTR_FILE) ? longname : parent);
17640Sstevel@tonic-gate 		goto out;
17650Sstevel@tonic-gate 	}
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 	if (lev > MAXLEV) {
17680Sstevel@tonic-gate 		(void) fprintf(stderr,
17690Sstevel@tonic-gate 		    gettext("tar: directory nesting too deep, %s not dumped\n"),
17700Sstevel@tonic-gate 		    longname);
17710Sstevel@tonic-gate 		goto out;
17720Sstevel@tonic-gate 	}
17730Sstevel@tonic-gate 
17745331Samw 	if (getstat(dirfd, longname, shortname, attrparent))
17750Sstevel@tonic-gate 		goto out;
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	if (hflag) {
17780Sstevel@tonic-gate 		/*
17790Sstevel@tonic-gate 		 * Catch nesting where a file is a symlink to its directory.
17800Sstevel@tonic-gate 		 */
17810Sstevel@tonic-gate 		j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
17820Sstevel@tonic-gate 		if (S_ISLNK(sbuf.st_mode)) {
17830Sstevel@tonic-gate 			if (symlink_lev++ >= MAXSYMLINKS) {
17840Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
17850Sstevel@tonic-gate 				    "tar: %s: Number of symbolic links "
17860Sstevel@tonic-gate 				    "encountered during path name traversal "
17870Sstevel@tonic-gate 				    "exceeds MAXSYMLINKS\n"), longname);
17880Sstevel@tonic-gate 				Errflg = 1;
17890Sstevel@tonic-gate 				goto out;
17900Sstevel@tonic-gate 			}
17910Sstevel@tonic-gate 		}
17920Sstevel@tonic-gate 	}
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 	/*
17950Sstevel@tonic-gate 	 * Check if the input file is the same as the tar file we
17960Sstevel@tonic-gate 	 * are creating
17970Sstevel@tonic-gate 	 */
17980Sstevel@tonic-gate 	if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
17990Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
18005331Samw 		    "tar: %s%s%s%s%s same as archive file\n"),
18015331Samw 		    rw_sysattr ? gettext("system ") : "",
18025331Samw 		    (longattrname == NULL) ? "" : gettext("attribute "),
18035331Samw 		    (longattrname == NULL) ? "" : longattrname,
18045331Samw 		    (longattrname == NULL) ? "" : gettext(" of "),
18055331Samw 		    longname);
18060Sstevel@tonic-gate 		Errflg = 1;
18070Sstevel@tonic-gate 		goto out;
18080Sstevel@tonic-gate 	}
18090Sstevel@tonic-gate 	/*
18100Sstevel@tonic-gate 	 * Check size limit - we can't archive files that
18110Sstevel@tonic-gate 	 * exceed TAR_OFFSET_MAX bytes because of header
18120Sstevel@tonic-gate 	 * limitations. Exclude file types that set
18130Sstevel@tonic-gate 	 * st_size to zero below because they take no
18140Sstevel@tonic-gate 	 * archive space to represent contents.
18150Sstevel@tonic-gate 	 */
18160Sstevel@tonic-gate 	if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
18170Sstevel@tonic-gate 	    !S_ISDIR(stbuf.st_mode) &&
18180Sstevel@tonic-gate 	    !S_ISCHR(stbuf.st_mode) &&
18190Sstevel@tonic-gate 	    !S_ISBLK(stbuf.st_mode) &&
18200Sstevel@tonic-gate 	    (Eflag == 0)) {
18210Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
18225331Samw 		    "tar: %s%s%s%s%s too large to archive.  "
18235331Samw 		    "Use E function modifier.\n"),
18245331Samw 		    rw_sysattr ? gettext("system ") : "",
18255331Samw 		    (longattrname == NULL) ? "" : gettext("attribute "),
18265331Samw 		    (longattrname == NULL) ? "" : longattrname,
18275331Samw 		    (longattrname == NULL) ? "" : gettext(" of "),
18285331Samw 		    longname);
18290Sstevel@tonic-gate 		if (errflag)
18300Sstevel@tonic-gate 			exitflag = 1;
18310Sstevel@tonic-gate 		Errflg = 1;
18320Sstevel@tonic-gate 		goto out;
18330Sstevel@tonic-gate 	}
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 	if (tfile != NULL && checkupdate(longname) == 0) {
18360Sstevel@tonic-gate 		goto out;
18370Sstevel@tonic-gate 	}
18380Sstevel@tonic-gate 	if (checkw('r', longname) == 0) {
18390Sstevel@tonic-gate 		goto out;
18400Sstevel@tonic-gate 	}
18410Sstevel@tonic-gate 
184212423Srich.burridge@oracle.com 	if (Fflag &&
184312423Srich.burridge@oracle.com 	    checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
18440Sstevel@tonic-gate 		goto out;
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 	if (Xflag) {
18470Sstevel@tonic-gate 		if (is_in_table(exclude_tbl, longname)) {
18480Sstevel@tonic-gate 			if (vflag) {
18490Sstevel@tonic-gate 				(void) fprintf(vfile, gettext(
18500Sstevel@tonic-gate 				    "a %s excluded\n"), longname);
18510Sstevel@tonic-gate 			}
18520Sstevel@tonic-gate 			goto out;
18530Sstevel@tonic-gate 		}
18540Sstevel@tonic-gate 	}
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate 	/*
18570Sstevel@tonic-gate 	 * If the length of the fullname is greater than MAXNAM,
18580Sstevel@tonic-gate 	 * print out a message and return (unless extended headers are used,
18590Sstevel@tonic-gate 	 * in which case fullname is limited to PATH_MAX).
18600Sstevel@tonic-gate 	 */
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
18630Sstevel@tonic-gate 	    (split > PATH_MAX)) {
18640Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
18650Sstevel@tonic-gate 		    "tar: %s: file name too long\n"), longname);
18660Sstevel@tonic-gate 		if (errflag)
18670Sstevel@tonic-gate 			exitflag = 1;
18680Sstevel@tonic-gate 		Errflg = 1;
18690Sstevel@tonic-gate 		goto out;
18700Sstevel@tonic-gate 	}
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	/*
18730Sstevel@tonic-gate 	 * We split the fullname into prefix and name components if any one
18740Sstevel@tonic-gate 	 * of three conditions holds:
18750Sstevel@tonic-gate 	 *	-- the length of the fullname exceeds NAMSIZ,
18760Sstevel@tonic-gate 	 *	-- the length of the fullname equals NAMSIZ, and the shortname
18770Sstevel@tonic-gate 	 *	   is less than NAMSIZ, (splitting in this case preserves
18780Sstevel@tonic-gate 	 *	   compatibility with 5.6 and 5.5.1 tar), or
18790Sstevel@tonic-gate 	 * 	-- the length of the fullname equals NAMSIZ, the file is a
18800Sstevel@tonic-gate 	 *	   directory and we are not in POSIX-conformant mode (where
18810Sstevel@tonic-gate 	 *	   trailing slashes are removed from directories).
18820Sstevel@tonic-gate 	 */
18830Sstevel@tonic-gate 	if ((split > NAMSIZ) ||
18840Sstevel@tonic-gate 	    (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1885871Scasper 	    (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
18860Sstevel@tonic-gate 		/*
18870Sstevel@tonic-gate 		 * Since path is limited to PRESIZ characters, look for the
18880Sstevel@tonic-gate 		 * last slash within PRESIZ + 1 characters only.
18890Sstevel@tonic-gate 		 */
18900Sstevel@tonic-gate 		(void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
18910Sstevel@tonic-gate 		tmpbuf = goodbuf;
18920Sstevel@tonic-gate 		lastslash = strrchr(tmpbuf, '/');
18930Sstevel@tonic-gate 		if (lastslash == NULL) {
18940Sstevel@tonic-gate 			i = split;		/* Length of name */
18950Sstevel@tonic-gate 			j = 0;			/* Length of prefix */
18960Sstevel@tonic-gate 			goodbuf[0] = '\0';
18970Sstevel@tonic-gate 		} else {
18980Sstevel@tonic-gate 			*lastslash = '\0';	/* Terminate the prefix */
18990Sstevel@tonic-gate 			j = strlen(tmpbuf);
19000Sstevel@tonic-gate 			i = split - j - 1;
19010Sstevel@tonic-gate 		}
19020Sstevel@tonic-gate 		/*
19030Sstevel@tonic-gate 		 * If the filename is greater than NAMSIZ we can't
19040Sstevel@tonic-gate 		 * archive the file unless we are using extended headers.
19050Sstevel@tonic-gate 		 */
1906871Scasper 		if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
19070Sstevel@tonic-gate 		    !Pflag)) {
19080Sstevel@tonic-gate 			/* Determine which (filename or path) is too long. */
19090Sstevel@tonic-gate 			lastslash = strrchr(longname, '/');
19100Sstevel@tonic-gate 			if (lastslash != NULL)
19110Sstevel@tonic-gate 				i = strlen(lastslash + 1);
19120Sstevel@tonic-gate 			if (Eflag > 0) {
19130Sstevel@tonic-gate 				xhdr_flgs |= _X_PATH;
19140Sstevel@tonic-gate 				Xtarhdr.x_path = longname;
19150Sstevel@tonic-gate 				if (i <= NAMSIZ)
19160Sstevel@tonic-gate 					(void) strcpy(junkbuf, lastslash + 1);
19170Sstevel@tonic-gate 				else
19180Sstevel@tonic-gate 					(void) sprintf(junkbuf, "%llu",
19190Sstevel@tonic-gate 					    xhdr_count + 1);
19200Sstevel@tonic-gate 				if (split - i - 1 > PRESIZ)
19210Sstevel@tonic-gate 					(void) strcpy(goodbuf, xhdr_dirname);
19220Sstevel@tonic-gate 			} else {
19230Sstevel@tonic-gate 				if ((i > NAMSIZ) || (i == NAMSIZ &&
1924871Scasper 				    S_ISDIR(stbuf.st_mode) && !Pflag))
19250Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
19260Sstevel@tonic-gate 					    "tar: %s: filename is greater than "
19270Sstevel@tonic-gate 					    "%d\n"), lastslash == NULL ?
19280Sstevel@tonic-gate 					    longname : lastslash + 1, NAMSIZ);
19290Sstevel@tonic-gate 				else
19300Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
19310Sstevel@tonic-gate 					    "tar: %s: prefix is greater than %d"
19320Sstevel@tonic-gate 					    "\n"), longname, PRESIZ);
19330Sstevel@tonic-gate 				if (errflag)
19340Sstevel@tonic-gate 					exitflag = 1;
19350Sstevel@tonic-gate 				Errflg = 1;
19360Sstevel@tonic-gate 				goto out;
19370Sstevel@tonic-gate 			}
19380Sstevel@tonic-gate 		} else
19390Sstevel@tonic-gate 			(void) strncpy(&junkbuf[0], longname + j + 1,
19400Sstevel@tonic-gate 			    strlen(longname + j + 1));
19410Sstevel@tonic-gate 		name = junkbuf;
19420Sstevel@tonic-gate 		prefix = goodbuf;
19430Sstevel@tonic-gate 	} else {
19440Sstevel@tonic-gate 		name = longname;
19450Sstevel@tonic-gate 	}
19460Sstevel@tonic-gate 	if (Aflag) {
19470Sstevel@tonic-gate 		if ((prefix != NULL) && (*prefix != '\0'))
19480Sstevel@tonic-gate 			while (*prefix == '/')
19490Sstevel@tonic-gate 				++prefix;
19500Sstevel@tonic-gate 		else
19510Sstevel@tonic-gate 			while (*name == '/')
19520Sstevel@tonic-gate 				++name;
19530Sstevel@tonic-gate 	}
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	switch (stbuf.st_mode & S_IFMT) {
19560Sstevel@tonic-gate 	case S_IFDIR:
19570Sstevel@tonic-gate 		stbuf.st_size = (off_t)0;
19580Sstevel@tonic-gate 		blocks = TBLOCKS(stbuf.st_size);
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 		if (filetype != XATTR_FILE && Hiddendir == 0) {
19610Sstevel@tonic-gate 			i = 0;
19620Sstevel@tonic-gate 			cp = buf;
19630Sstevel@tonic-gate 			while ((*cp++ = longname[i++]))
19640Sstevel@tonic-gate 				;
19650Sstevel@tonic-gate 			*--cp = '/';
19660Sstevel@tonic-gate 			*++cp = 0;
19670Sstevel@tonic-gate 		}
19680Sstevel@tonic-gate 		if (!oflag) {
19690Sstevel@tonic-gate 			tomodes(&stbuf);
19700Sstevel@tonic-gate 			if (build_dblock(name, tchar, '5', filetype,
19710Sstevel@tonic-gate 			    &stbuf, stbuf.st_dev, prefix) != 0) {
19720Sstevel@tonic-gate 				goto out;
19730Sstevel@tonic-gate 			}
19740Sstevel@tonic-gate 			if (!Pflag) {
19750Sstevel@tonic-gate 				/*
19760Sstevel@tonic-gate 				 * Old archives require a slash at the end
19770Sstevel@tonic-gate 				 * of a directory name.
19780Sstevel@tonic-gate 				 *
19790Sstevel@tonic-gate 				 * XXX
19800Sstevel@tonic-gate 				 * If directory name is too long, will
19810Sstevel@tonic-gate 				 * slash overfill field?
19820Sstevel@tonic-gate 				 */
19830Sstevel@tonic-gate 				if (strlen(name) > (unsigned)NAMSIZ-1) {
19840Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
19850Sstevel@tonic-gate 					    "tar: %s: filename is greater "
19860Sstevel@tonic-gate 					    "than %d\n"), name, NAMSIZ);
19870Sstevel@tonic-gate 					if (errflag)
19880Sstevel@tonic-gate 						exitflag = 1;
19890Sstevel@tonic-gate 					Errflg = 1;
19900Sstevel@tonic-gate 					goto out;
19910Sstevel@tonic-gate 				} else {
19920Sstevel@tonic-gate 					if (strlen(name) == (NAMSIZ - 1)) {
19930Sstevel@tonic-gate 						(void) memcpy(dblock.dbuf.name,
19940Sstevel@tonic-gate 						    name, NAMSIZ);
19950Sstevel@tonic-gate 						dblock.dbuf.name[NAMSIZ-1]
19960Sstevel@tonic-gate 						    = '/';
19970Sstevel@tonic-gate 					} else
19980Sstevel@tonic-gate 						(void) sprintf(dblock.dbuf.name,
19990Sstevel@tonic-gate 						    "%s/", name);
20000Sstevel@tonic-gate 
20010Sstevel@tonic-gate 					/*
20020Sstevel@tonic-gate 					 * need to recalculate checksum
20030Sstevel@tonic-gate 					 * because the name changed.
20040Sstevel@tonic-gate 					 */
20050Sstevel@tonic-gate 					(void) sprintf(dblock.dbuf.chksum,
20060Sstevel@tonic-gate 					    "%07o", checksum(&dblock));
20070Sstevel@tonic-gate 				}
20080Sstevel@tonic-gate 			}
20090Sstevel@tonic-gate 
20105331Samw 			if (put_extra_attributes(longname, shortname,
20115331Samw 			    longattrname, prefix, filetype, '5') != 0)
20120Sstevel@tonic-gate 				goto out;
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate #if defined(O_XATTR)
20150Sstevel@tonic-gate 			/*
20160Sstevel@tonic-gate 			 * Reset header typeflag when archiving directory, since
20170Sstevel@tonic-gate 			 * build_dblock changed it on us.
20180Sstevel@tonic-gate 			 */
20190Sstevel@tonic-gate 			if (filetype == XATTR_FILE) {
20200Sstevel@tonic-gate 				dblock.dbuf.typeflag = _XATTR_HDRTYPE;
20210Sstevel@tonic-gate 			} else {
20220Sstevel@tonic-gate 				dblock.dbuf.typeflag = '5';
20230Sstevel@tonic-gate 			}
20240Sstevel@tonic-gate #else
20250Sstevel@tonic-gate 			dblock.dbuf.typeflag = '5';
20260Sstevel@tonic-gate #endif
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 			(void) sprintf(dblock.dbuf.chksum, "%07o",
20290Sstevel@tonic-gate 			    checksum(&dblock));
20300Sstevel@tonic-gate 
20310Sstevel@tonic-gate 			(void) writetbuf((char *)&dblock, 1);
20320Sstevel@tonic-gate 		}
20330Sstevel@tonic-gate 		if (vflag) {
20340Sstevel@tonic-gate #ifdef DEBUG
20350Sstevel@tonic-gate 			if (NotTape)
20360Sstevel@tonic-gate 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
20370Sstevel@tonic-gate 				    0);
20380Sstevel@tonic-gate #endif
20390Sstevel@tonic-gate 			if (filetype == XATTR_FILE && Hiddendir) {
204012305Srich.burridge@sun.com 				(void) fprintf(vfile,
204112305Srich.burridge@sun.com 				    gettext("a %s attribute %s "),
20425331Samw 				    longname, longattrname);
20430Sstevel@tonic-gate 
20440Sstevel@tonic-gate 			} else {
20450Sstevel@tonic-gate 				(void) fprintf(vfile, "a %s/ ", longname);
20460Sstevel@tonic-gate 			}
20470Sstevel@tonic-gate 			if (NotTape)
20480Sstevel@tonic-gate 				(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
20490Sstevel@tonic-gate 				    K(blocks));
20500Sstevel@tonic-gate 			else
20510Sstevel@tonic-gate 				(void) fprintf(vfile, gettext("%" FMT_blkcnt_t
20520Sstevel@tonic-gate 				    " tape blocks\n"), blocks);
20530Sstevel@tonic-gate 		}
20540Sstevel@tonic-gate 
20550Sstevel@tonic-gate 		/*
20560Sstevel@tonic-gate 		 * If hidden dir then break now since xattrs_put() will do
20570Sstevel@tonic-gate 		 * the iterating of the directory.
20580Sstevel@tonic-gate 		 *
20595331Samw 		 * At the moment, there can only be system attributes on
20605331Samw 		 * attributes.  There can be no attributes on attributes or
20615331Samw 		 * directories within the attributes hidden directory hierarchy.
20620Sstevel@tonic-gate 		 */
20630Sstevel@tonic-gate 		if (filetype == XATTR_FILE)
20640Sstevel@tonic-gate 			break;
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate 		if (*shortname != '/')
20670Sstevel@tonic-gate 			(void) sprintf(newparent, "%s/%s", parent, shortname);
20680Sstevel@tonic-gate 		else
20690Sstevel@tonic-gate 			(void) sprintf(newparent, "%s", shortname);
20700Sstevel@tonic-gate 
207112554Srich.burridge@oracle.com 		if (tar_chdir(shortname) < 0) {
20720Sstevel@tonic-gate 			vperror(0, "%s", newparent);
20730Sstevel@tonic-gate 			goto out;
20740Sstevel@tonic-gate 		}
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate 		if ((dirp = opendir(".")) == NULL) {
20770Sstevel@tonic-gate 			vperror(0, gettext(
20785331Samw 			    "can't open directory %s"), longname);
207912554Srich.burridge@oracle.com 			if (tar_chdir(parent) < 0)
20800Sstevel@tonic-gate 				vperror(0, gettext("cannot change back?: %s"),
20810Sstevel@tonic-gate 				    parent);
20820Sstevel@tonic-gate 			goto out;
20830Sstevel@tonic-gate 		}
20840Sstevel@tonic-gate 
20856525Sceastha 		/*
20866525Sceastha 		 * Create a list of files (children) in this directory to avoid
20876525Sceastha 		 * having to perform telldir()/seekdir().
20886525Sceastha 		 */
20890Sstevel@tonic-gate 		while ((dp = readdir(dirp)) != NULL && !term) {
20900Sstevel@tonic-gate 			if ((strcmp(".", dp->d_name) == 0) ||
20910Sstevel@tonic-gate 			    (strcmp("..", dp->d_name) == 0))
20920Sstevel@tonic-gate 				continue;
20936525Sceastha 			if (((cptr = (file_list_t *)calloc(sizeof (char),
20946525Sceastha 			    sizeof (file_list_t))) == NULL) ||
20956525Sceastha 			    ((cptr->name = strdup(dp->d_name)) == NULL)) {
20966525Sceastha 				vperror(1, gettext(
20976525Sceastha 				    "Insufficient memory for directory "
20986525Sceastha 				    "list entry %s/%s\n"),
20996525Sceastha 				    newparent, dp->d_name);
21006525Sceastha 			}
21016525Sceastha 
21026525Sceastha 			/* Add the file to the list */
21036525Sceastha 			if (child == NULL) {
21046525Sceastha 				child = cptr;
21056525Sceastha 			} else {
21066525Sceastha 				child_end->next = cptr;
21076525Sceastha 			}
21086525Sceastha 			child_end = cptr;
21096525Sceastha 		}
21106525Sceastha 		(void) closedir(dirp);
21116525Sceastha 
21126525Sceastha 		/*
21136525Sceastha 		 * Archive each of the files in the current directory.
21146525Sceastha 		 * If a file is a directory, putfile() is called
21156525Sceastha 		 * recursively to archive the file hierarchy of the
21166525Sceastha 		 * directory before archiving the next file in the
21176525Sceastha 		 * current directory.
21186525Sceastha 		 */
21196525Sceastha 		while ((child != NULL) && !term) {
21206525Sceastha 			(void) strcpy(cp, child->name);
21215331Samw 			archtype = putfile(buf, cp, newparent, NULL,
21220Sstevel@tonic-gate 			    NORMAL_FILE, lev + 1, symlink_lev);
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 			if (!exitflag) {
21255331Samw 				if ((atflag || saflag) &&
21265331Samw 				    (archtype == PUT_NOTAS_LINK)) {
21275331Samw 					xattrs_put(buf, cp, newparent, NULL);
21280Sstevel@tonic-gate 				}
21290Sstevel@tonic-gate 			}
21300Sstevel@tonic-gate 			if (exitflag)
21310Sstevel@tonic-gate 				break;
21320Sstevel@tonic-gate 
21336525Sceastha 			/* Free each child as we are done processing it. */
21346525Sceastha 			cptr = child;
21356525Sceastha 			child = child->next;
21366525Sceastha 			free(cptr->name);
21376525Sceastha 			free(cptr);
21386525Sceastha 		}
21396525Sceastha 		if ((child != NULL) && !term) {
21406525Sceastha 			free_children(child);
21416525Sceastha 		}
21420Sstevel@tonic-gate 
214312554Srich.burridge@oracle.com 		if (tar_chdir(parent) < 0) {
21440Sstevel@tonic-gate 			vperror(0, gettext("cannot change back?: %s"), parent);
21450Sstevel@tonic-gate 		}
21460Sstevel@tonic-gate 
21470Sstevel@tonic-gate 		break;
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate 	case S_IFLNK:
21500Sstevel@tonic-gate 		readlink_max = NAMSIZ;
21510Sstevel@tonic-gate 		if (stbuf.st_size > NAMSIZ) {
21520Sstevel@tonic-gate 			if (Eflag > 0) {
21530Sstevel@tonic-gate 				xhdr_flgs |= _X_LINKPATH;
21540Sstevel@tonic-gate 				readlink_max = PATH_MAX;
21550Sstevel@tonic-gate 			} else {
21560Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
21570Sstevel@tonic-gate 				    "tar: %s: symbolic link too long\n"),
21580Sstevel@tonic-gate 				    longname);
21590Sstevel@tonic-gate 				if (errflag)
21600Sstevel@tonic-gate 					exitflag = 1;
21610Sstevel@tonic-gate 				Errflg = 1;
21620Sstevel@tonic-gate 				goto out;
21630Sstevel@tonic-gate 			}
21640Sstevel@tonic-gate 		}
21650Sstevel@tonic-gate 		/*
21660Sstevel@tonic-gate 		 * Sym-links need header size of zero since you
21670Sstevel@tonic-gate 		 * don't store any data for this type.
21680Sstevel@tonic-gate 		 */
21690Sstevel@tonic-gate 		stbuf.st_size = (off_t)0;
21700Sstevel@tonic-gate 		tomodes(&stbuf);
21710Sstevel@tonic-gate 		i = readlink(shortname, filetmp, readlink_max);
21720Sstevel@tonic-gate 		if (i < 0) {
21730Sstevel@tonic-gate 			vperror(0, gettext(
21740Sstevel@tonic-gate 			    "can't read symbolic link %s"), longname);
21750Sstevel@tonic-gate 			goto out;
21760Sstevel@tonic-gate 		} else {
21770Sstevel@tonic-gate 			filetmp[i] = 0;
21780Sstevel@tonic-gate 		}
21790Sstevel@tonic-gate 		if (vflag)
21800Sstevel@tonic-gate 			(void) fprintf(vfile, gettext(
21810Sstevel@tonic-gate 			    "a %s symbolic link to %s\n"),
21820Sstevel@tonic-gate 			    longname, filetmp);
21830Sstevel@tonic-gate 		if (xhdr_flgs & _X_LINKPATH) {
21840Sstevel@tonic-gate 			Xtarhdr.x_linkpath = filetmp;
21850Sstevel@tonic-gate 			if (build_dblock(name, tchar, '2', filetype, &stbuf,
21860Sstevel@tonic-gate 			    stbuf.st_dev, prefix) != 0)
21870Sstevel@tonic-gate 				goto out;
21880Sstevel@tonic-gate 		} else
21890Sstevel@tonic-gate 			if (build_dblock(name, filetmp, '2', filetype, &stbuf,
21900Sstevel@tonic-gate 			    stbuf.st_dev, prefix) != 0)
21910Sstevel@tonic-gate 				goto out;
21920Sstevel@tonic-gate 		(void) writetbuf((char *)&dblock, 1);
21930Sstevel@tonic-gate 		/*
21940Sstevel@tonic-gate 		 * No acls for symlinks: mode is always 777
21950Sstevel@tonic-gate 		 * dont call write ancillary
21960Sstevel@tonic-gate 		 */
21970Sstevel@tonic-gate 		rc = PUT_AS_LINK;
21980Sstevel@tonic-gate 		break;
21990Sstevel@tonic-gate 	case S_IFREG:
22000Sstevel@tonic-gate 		if ((infile = openat(dirfd, shortname, 0)) < 0) {
220112305Srich.burridge@sun.com 			vperror(0, gettext("unable to open %s%s%s%s"), longname,
22025331Samw 			    rw_sysattr ? gettext(" system") : "",
22030Sstevel@tonic-gate 			    (filetype == XATTR_FILE) ?
22040Sstevel@tonic-gate 			    gettext(" attribute ") : "",
22055331Samw 			    (filetype == XATTR_FILE) ? (longattrname == NULL) ?
22065331Samw 			    shortname : longattrname : "");
22070Sstevel@tonic-gate 			goto out;
22080Sstevel@tonic-gate 		}
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 		blocks = TBLOCKS(stbuf.st_size);
22110Sstevel@tonic-gate 
22125331Samw 		if (put_link(name, longname, shortname, longattrname,
22130Sstevel@tonic-gate 		    prefix, filetype, '1') == 0) {
22140Sstevel@tonic-gate 			(void) close(infile);
22150Sstevel@tonic-gate 			rc = PUT_AS_LINK;
22160Sstevel@tonic-gate 			goto out;
22170Sstevel@tonic-gate 		}
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 		tomodes(&stbuf);
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 		/* correctly handle end of volume */
22220Sstevel@tonic-gate 		while (mulvol && tapepos + blocks + 1 > blocklim) {
22230Sstevel@tonic-gate 			/* split if floppy has some room and file is large */
22240Sstevel@tonic-gate 			if (((blocklim - tapepos) >= EXTMIN) &&
22250Sstevel@tonic-gate 			    ((blocks + 1) >= blocklim/10)) {
22260Sstevel@tonic-gate 				splitfile(longname, infile,
22270Sstevel@tonic-gate 				    name, prefix, filetype);
22280Sstevel@tonic-gate 				(void) close(dirfd);
22290Sstevel@tonic-gate 				(void) close(infile);
22300Sstevel@tonic-gate 				goto out;
22310Sstevel@tonic-gate 			}
22320Sstevel@tonic-gate 			newvol();	/* not worth it--just get new volume */
22330Sstevel@tonic-gate 		}
22340Sstevel@tonic-gate #ifdef DEBUG
22350Sstevel@tonic-gate 		DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
22360Sstevel@tonic-gate 		    blocks);
22370Sstevel@tonic-gate #endif
22380Sstevel@tonic-gate 		if (build_dblock(name, tchar, '0', filetype,
22390Sstevel@tonic-gate 		    &stbuf, stbuf.st_dev, prefix) != 0) {
22400Sstevel@tonic-gate 			goto out;
22410Sstevel@tonic-gate 		}
22420Sstevel@tonic-gate 		if (vflag) {
22430Sstevel@tonic-gate #ifdef DEBUG
22440Sstevel@tonic-gate 			if (NotTape)
22450Sstevel@tonic-gate 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
22460Sstevel@tonic-gate 				    0);
22470Sstevel@tonic-gate #endif
22485331Samw 			(void) fprintf(vfile, "a %s%s%s%s ", longname,
22495331Samw 			    rw_sysattr ? gettext(" system") : "",
22505331Samw 			    (filetype == XATTR_FILE) ? gettext(
22515331Samw 			    " attribute ") : "",
22520Sstevel@tonic-gate 			    (filetype == XATTR_FILE) ?
22535331Samw 			    longattrname : "");
22540Sstevel@tonic-gate 			if (NotTape)
22550Sstevel@tonic-gate 				(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
22560Sstevel@tonic-gate 				    K(blocks));
22570Sstevel@tonic-gate 			else
22580Sstevel@tonic-gate 				(void) fprintf(vfile,
22590Sstevel@tonic-gate 				    gettext("%" FMT_blkcnt_t " tape blocks\n"),
22600Sstevel@tonic-gate 				    blocks);
22610Sstevel@tonic-gate 		}
22620Sstevel@tonic-gate 
22635331Samw 		if (put_extra_attributes(longname, shortname, longattrname,
22645331Samw 		    prefix, filetype, '0') != 0)
22650Sstevel@tonic-gate 			goto out;
22660Sstevel@tonic-gate 
22670Sstevel@tonic-gate 		/*
22680Sstevel@tonic-gate 		 * No need to reset typeflag for extended attribute here, since
22690Sstevel@tonic-gate 		 * put_extra_attributes already set it and we haven't called
22700Sstevel@tonic-gate 		 * build_dblock().
22710Sstevel@tonic-gate 		 */
22720Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
22730Sstevel@tonic-gate 		hint = writetbuf((char *)&dblock, 1);
22741266Sceastha 		maxread = max(min(stbuf.st_blksize, stbuf.st_size),
22751266Sceastha 		    (nblock * TBLOCK));
22760Sstevel@tonic-gate 		if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
22770Sstevel@tonic-gate 			maxread = TBLOCK;
22780Sstevel@tonic-gate 			bigbuf = buf;
22790Sstevel@tonic-gate 		}
22800Sstevel@tonic-gate 
22810Sstevel@tonic-gate 		while (((i = (int)
22820Sstevel@tonic-gate 		    read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
22830Sstevel@tonic-gate 		    blocks) {
22840Sstevel@tonic-gate 			blkcnt_t nblks;
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate 			nblks = ((i-1)/TBLOCK)+1;
22870Sstevel@tonic-gate 			if (nblks > blocks)
22880Sstevel@tonic-gate 				nblks = blocks;
22890Sstevel@tonic-gate 			hint = writetbuf(bigbuf, nblks);
22900Sstevel@tonic-gate 			blocks -= nblks;
22910Sstevel@tonic-gate 		}
22920Sstevel@tonic-gate 		(void) close(infile);
22930Sstevel@tonic-gate 		if (bigbuf != buf)
22940Sstevel@tonic-gate 			free(bigbuf);
22950Sstevel@tonic-gate 		if (i < 0)
22960Sstevel@tonic-gate 			vperror(0, gettext("Read error on %s"), longname);
22970Sstevel@tonic-gate 		else if (blocks != 0 || i != 0) {
22980Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
22990Sstevel@tonic-gate 			"tar: %s: file changed size\n"), longname);
23000Sstevel@tonic-gate 			if (errflag) {
23010Sstevel@tonic-gate 				exitflag = 1;
23020Sstevel@tonic-gate 				Errflg = 1;
23030Sstevel@tonic-gate 			} else if (!Dflag) {
23040Sstevel@tonic-gate 				Errflg = 1;
23050Sstevel@tonic-gate 			}
23060Sstevel@tonic-gate 		}
23070Sstevel@tonic-gate 		putempty(blocks);
23080Sstevel@tonic-gate 		break;
23090Sstevel@tonic-gate 	case S_IFIFO:
23100Sstevel@tonic-gate 		blocks = TBLOCKS(stbuf.st_size);
23110Sstevel@tonic-gate 		stbuf.st_size = (off_t)0;
23120Sstevel@tonic-gate 
23135331Samw 		if (put_link(name, longname, shortname, longattrname,
23140Sstevel@tonic-gate 		    prefix, filetype, '6') == 0) {
23150Sstevel@tonic-gate 			rc = PUT_AS_LINK;
23160Sstevel@tonic-gate 			goto out;
23170Sstevel@tonic-gate 		}
23180Sstevel@tonic-gate 		tomodes(&stbuf);
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 		while (mulvol && tapepos + blocks + 1 > blocklim) {
23210Sstevel@tonic-gate 			if (((blocklim - tapepos) >= EXTMIN) &&
23220Sstevel@tonic-gate 			    ((blocks + 1) >= blocklim/10)) {
23230Sstevel@tonic-gate 				splitfile(longname, infile, name,
23240Sstevel@tonic-gate 				    prefix, filetype);
23250Sstevel@tonic-gate 				(void) close(dirfd);
23260Sstevel@tonic-gate 				(void) close(infile);
23270Sstevel@tonic-gate 				goto out;
23280Sstevel@tonic-gate 			}
23290Sstevel@tonic-gate 			newvol();
23300Sstevel@tonic-gate 		}
23310Sstevel@tonic-gate #ifdef DEBUG
23320Sstevel@tonic-gate 		DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
23330Sstevel@tonic-gate 		    blocks);
23340Sstevel@tonic-gate #endif
23350Sstevel@tonic-gate 		if (vflag) {
23360Sstevel@tonic-gate #ifdef DEBUG
23370Sstevel@tonic-gate 			if (NotTape)
23380Sstevel@tonic-gate 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
23390Sstevel@tonic-gate 				    0);
23400Sstevel@tonic-gate #endif
23410Sstevel@tonic-gate 			if (NotTape)
23420Sstevel@tonic-gate 				(void) fprintf(vfile, gettext("a %s %"
23430Sstevel@tonic-gate 				    FMT_blkcnt_t "K\n "), longname, K(blocks));
23440Sstevel@tonic-gate 			else
23450Sstevel@tonic-gate 				(void) fprintf(vfile, gettext(
23460Sstevel@tonic-gate 				    "a %s %" FMT_blkcnt_t " tape blocks\n"),
23470Sstevel@tonic-gate 				    longname, blocks);
23480Sstevel@tonic-gate 		}
23490Sstevel@tonic-gate 		if (build_dblock(name, tchar, '6', filetype,
23500Sstevel@tonic-gate 		    &stbuf, stbuf.st_dev, prefix) != 0)
23510Sstevel@tonic-gate 			goto out;
23520Sstevel@tonic-gate 
23535331Samw 		if (put_extra_attributes(longname, shortname, longattrname,
23545331Samw 		    prefix, filetype, '6') != 0)
23550Sstevel@tonic-gate 			goto out;
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
23580Sstevel@tonic-gate 		dblock.dbuf.typeflag = '6';
23590Sstevel@tonic-gate 
23600Sstevel@tonic-gate 		(void) writetbuf((char *)&dblock, 1);
23610Sstevel@tonic-gate 		break;
23620Sstevel@tonic-gate 	case S_IFCHR:
23630Sstevel@tonic-gate 		stbuf.st_size = (off_t)0;
23640Sstevel@tonic-gate 		blocks = TBLOCKS(stbuf.st_size);
23655331Samw 		if (put_link(name, longname, shortname, longattrname,
23665331Samw 		    prefix, filetype, '3') == 0) {
23670Sstevel@tonic-gate 			rc = PUT_AS_LINK;
23680Sstevel@tonic-gate 			goto out;
23690Sstevel@tonic-gate 		}
23700Sstevel@tonic-gate 		tomodes(&stbuf);
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 		while (mulvol && tapepos + blocks + 1 > blocklim) {
23730Sstevel@tonic-gate 			if (((blocklim - tapepos) >= EXTMIN) &&
23740Sstevel@tonic-gate 			    ((blocks + 1) >= blocklim/10)) {
23750Sstevel@tonic-gate 				splitfile(longname, infile, name,
23760Sstevel@tonic-gate 				    prefix, filetype);
23770Sstevel@tonic-gate 				(void) close(dirfd);
23780Sstevel@tonic-gate 				goto out;
23790Sstevel@tonic-gate 			}
23800Sstevel@tonic-gate 			newvol();
23810Sstevel@tonic-gate 		}
23820Sstevel@tonic-gate #ifdef DEBUG
23830Sstevel@tonic-gate 		DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
23840Sstevel@tonic-gate 		    blocks);
23850Sstevel@tonic-gate #endif
23860Sstevel@tonic-gate 		if (vflag) {
23870Sstevel@tonic-gate #ifdef DEBUG
23880Sstevel@tonic-gate 			if (NotTape)
23890Sstevel@tonic-gate 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
23900Sstevel@tonic-gate 				    0);
23910Sstevel@tonic-gate #endif
23920Sstevel@tonic-gate 			if (NotTape)
23930Sstevel@tonic-gate 				(void) fprintf(vfile, gettext("a %s %"
23940Sstevel@tonic-gate 				    FMT_blkcnt_t "K\n"), longname, K(blocks));
23950Sstevel@tonic-gate 			else
23960Sstevel@tonic-gate 				(void) fprintf(vfile, gettext("a %s %"
23970Sstevel@tonic-gate 				    FMT_blkcnt_t " tape blocks\n"), longname,
23980Sstevel@tonic-gate 				    blocks);
23990Sstevel@tonic-gate 		}
24000Sstevel@tonic-gate 		if (build_dblock(name, tchar, '3',
24010Sstevel@tonic-gate 		    filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
24020Sstevel@tonic-gate 			goto out;
24030Sstevel@tonic-gate 
24045331Samw 		if (put_extra_attributes(longname, shortname, longattrname,
24050Sstevel@tonic-gate 		    prefix, filetype, '3') != 0)
24060Sstevel@tonic-gate 			goto out;
24070Sstevel@tonic-gate 
24080Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
24090Sstevel@tonic-gate 		dblock.dbuf.typeflag = '3';
24100Sstevel@tonic-gate 
24110Sstevel@tonic-gate 		(void) writetbuf((char *)&dblock, 1);
24120Sstevel@tonic-gate 		break;
24130Sstevel@tonic-gate 	case S_IFBLK:
24140Sstevel@tonic-gate 		stbuf.st_size = (off_t)0;
24150Sstevel@tonic-gate 		blocks = TBLOCKS(stbuf.st_size);
24165331Samw 		if (put_link(name, longname, shortname, longattrname,
24175331Samw 		    prefix, filetype, '4') == 0) {
24180Sstevel@tonic-gate 			rc = PUT_AS_LINK;
24190Sstevel@tonic-gate 			goto out;
24200Sstevel@tonic-gate 		}
24210Sstevel@tonic-gate 		tomodes(&stbuf);
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate 		while (mulvol && tapepos + blocks + 1 > blocklim) {
24240Sstevel@tonic-gate 			if (((blocklim - tapepos) >= EXTMIN) &&
24250Sstevel@tonic-gate 			    ((blocks + 1) >= blocklim/10)) {
24260Sstevel@tonic-gate 				splitfile(longname, infile,
24270Sstevel@tonic-gate 				    name, prefix, filetype);
24280Sstevel@tonic-gate 				(void) close(dirfd);
24290Sstevel@tonic-gate 				goto out;
24300Sstevel@tonic-gate 			}
24310Sstevel@tonic-gate 			newvol();
24320Sstevel@tonic-gate 		}
24330Sstevel@tonic-gate #ifdef DEBUG
24340Sstevel@tonic-gate 		DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
24350Sstevel@tonic-gate 		    blocks);
24360Sstevel@tonic-gate #endif
24370Sstevel@tonic-gate 		if (vflag) {
24380Sstevel@tonic-gate #ifdef DEBUG
24390Sstevel@tonic-gate 			if (NotTape)
24400Sstevel@tonic-gate 				DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
24410Sstevel@tonic-gate 				    0);
24420Sstevel@tonic-gate #endif
24430Sstevel@tonic-gate 			(void) fprintf(vfile, "a %s ", longname);
24440Sstevel@tonic-gate 			if (NotTape)
24450Sstevel@tonic-gate 				(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
24460Sstevel@tonic-gate 				    K(blocks));
24470Sstevel@tonic-gate 			else
24480Sstevel@tonic-gate 				(void) fprintf(vfile, gettext("%"
24490Sstevel@tonic-gate 				    FMT_blkcnt_t " tape blocks\n"), blocks);
24500Sstevel@tonic-gate 		}
24510Sstevel@tonic-gate 		if (build_dblock(name, tchar, '4',
24520Sstevel@tonic-gate 		    filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
24530Sstevel@tonic-gate 			goto out;
24540Sstevel@tonic-gate 
24555331Samw 		if (put_extra_attributes(longname, shortname, longattrname,
24560Sstevel@tonic-gate 		    prefix, filetype, '4') != 0)
24570Sstevel@tonic-gate 			goto out;
24580Sstevel@tonic-gate 
24590Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
24600Sstevel@tonic-gate 		dblock.dbuf.typeflag = '4';
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 		(void) writetbuf((char *)&dblock, 1);
24630Sstevel@tonic-gate 		break;
24640Sstevel@tonic-gate 	default:
24650Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
24660Sstevel@tonic-gate 		    "tar: %s is not a file. Not dumped\n"), longname);
24670Sstevel@tonic-gate 		if (errflag)
24680Sstevel@tonic-gate 			exitflag = 1;
24690Sstevel@tonic-gate 		Errflg = 1;
24700Sstevel@tonic-gate 		goto out;
24710Sstevel@tonic-gate 	}
24720Sstevel@tonic-gate 
24730Sstevel@tonic-gate out:
24745331Samw 	if ((dirfd != -1) && (filetype != XATTR_FILE)) {
24750Sstevel@tonic-gate 		(void) close(dirfd);
24760Sstevel@tonic-gate 	}
24770Sstevel@tonic-gate 	return (rc);
24780Sstevel@tonic-gate }
24790Sstevel@tonic-gate 
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate /*
24820Sstevel@tonic-gate  *	splitfile	dump a large file across volumes
24830Sstevel@tonic-gate  *
24840Sstevel@tonic-gate  *	splitfile(longname, fd);
24850Sstevel@tonic-gate  *		char *longname;		full name of file
24860Sstevel@tonic-gate  *		int ifd;		input file descriptor
24870Sstevel@tonic-gate  *
24880Sstevel@tonic-gate  *	NOTE:  only called by putfile() to dump a large file.
24890Sstevel@tonic-gate  */
24900Sstevel@tonic-gate 
24910Sstevel@tonic-gate static void
splitfile(char * longname,int ifd,char * name,char * prefix,int filetype)24920Sstevel@tonic-gate splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
24930Sstevel@tonic-gate {
24940Sstevel@tonic-gate 	blkcnt_t blocks;
24950Sstevel@tonic-gate 	off_t bytes, s;
24960Sstevel@tonic-gate 	char buf[TBLOCK];
24970Sstevel@tonic-gate 	int i, extents;
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	blocks = TBLOCKS(stbuf.st_size);	/* blocks file needs */
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate 	/*
25020Sstevel@tonic-gate 	 * # extents =
25030Sstevel@tonic-gate 	 *	size of file after using up rest of this floppy
25040Sstevel@tonic-gate 	 *		blocks - (blocklim - tapepos) + 1	(for header)
25050Sstevel@tonic-gate 	 *	plus roundup value before divide by blocklim-1
25060Sstevel@tonic-gate 	 *		+ (blocklim - 1) - 1
25070Sstevel@tonic-gate 	 *	all divided by blocklim-1 (one block for each header).
25080Sstevel@tonic-gate 	 * this gives
25090Sstevel@tonic-gate 	 *	(blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
25100Sstevel@tonic-gate 	 * which reduces to the expression used.
25110Sstevel@tonic-gate 	 * one is added to account for this first extent.
25120Sstevel@tonic-gate 	 *
25130Sstevel@tonic-gate 	 * When one is dealing with extremely large archives, one may want
25140Sstevel@tonic-gate 	 * to allow for a large number of extents.  This code should be
25150Sstevel@tonic-gate 	 * revisited to determine if extents should be changed to something
25160Sstevel@tonic-gate 	 * larger than an int.
25170Sstevel@tonic-gate 	 */
25180Sstevel@tonic-gate 	extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
25190Sstevel@tonic-gate 
25200Sstevel@tonic-gate 	if (extents < 2 || extents > MAXEXT) {	/* let's be reasonable */
25210Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
25220Sstevel@tonic-gate 		    "tar: %s needs unusual number of volumes to split\n"
25230Sstevel@tonic-gate 		    "tar: %s not dumped\n"), longname, longname);
25240Sstevel@tonic-gate 		return;
25250Sstevel@tonic-gate 	}
25260Sstevel@tonic-gate 	if (build_dblock(name, tchar, '0', filetype,
25270Sstevel@tonic-gate 	    &stbuf, stbuf.st_dev, prefix) != 0)
25280Sstevel@tonic-gate 		return;
25290Sstevel@tonic-gate 
25300Sstevel@tonic-gate 	dblock.dbuf.extotal = extents;
25310Sstevel@tonic-gate 	bytes = stbuf.st_size;
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 	/*
25340Sstevel@tonic-gate 	 * The value contained in dblock.dbuf.efsize was formerly used when the
25350Sstevel@tonic-gate 	 * v flag was specified in conjunction with the t flag. Although it is
25360Sstevel@tonic-gate 	 * no longer used, older versions of tar will expect the former
25370Sstevel@tonic-gate 	 * behaviour, so we must continue to write it to the archive.
25380Sstevel@tonic-gate 	 *
25390Sstevel@tonic-gate 	 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
25400Sstevel@tonic-gate 	 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
25410Sstevel@tonic-gate 	 * store 0.
25420Sstevel@tonic-gate 	 */
25430Sstevel@tonic-gate 	if (bytes <= TAR_EFSIZE_MAX)
25440Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
25450Sstevel@tonic-gate 	else
25460Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
25490Sstevel@tonic-gate 	    "tar: large file %s needs %d extents.\n"
25500Sstevel@tonic-gate 	    "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
25510Sstevel@tonic-gate 	    longname, extents, K(tapepos));
25520Sstevel@tonic-gate 
25530Sstevel@tonic-gate 	s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
25540Sstevel@tonic-gate 	for (i = 1; i <= extents; i++) {
25550Sstevel@tonic-gate 		if (i > 1) {
25560Sstevel@tonic-gate 			newvol();
25570Sstevel@tonic-gate 			if (i == extents)
25580Sstevel@tonic-gate 				s = bytes;	/* last ext. gets true bytes */
25590Sstevel@tonic-gate 			else
25600Sstevel@tonic-gate 				s = (off_t)(blocklim - 1)*TBLOCK; /* all */
25610Sstevel@tonic-gate 		}
25620Sstevel@tonic-gate 		bytes -= s;
25630Sstevel@tonic-gate 		blocks = TBLOCKS(s);
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
25660Sstevel@tonic-gate 		dblock.dbuf.extno = i;
25670Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
25680Sstevel@tonic-gate 		(void) writetbuf((char *)&dblock, 1);
25690Sstevel@tonic-gate 
25700Sstevel@tonic-gate 		if (vflag)
25710Sstevel@tonic-gate 			(void) fprintf(vfile,
257212305Srich.burridge@sun.com 			    gettext("+++ a %s %" FMT_blkcnt_t
257312305Srich.burridge@sun.com 			    "K [extent #%d of %d]\n"),
25740Sstevel@tonic-gate 			    longname, K(blocks), i, extents);
25750Sstevel@tonic-gate 		while (blocks && read(ifd, buf, TBLOCK) > 0) {
25760Sstevel@tonic-gate 			blocks--;
25770Sstevel@tonic-gate 			(void) writetbuf(buf, 1);
25780Sstevel@tonic-gate 		}
25790Sstevel@tonic-gate 		if (blocks != 0) {
25800Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
25810Sstevel@tonic-gate 			    "tar: %s: file changed size\n"), longname);
25820Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
25830Sstevel@tonic-gate 			    "tar: aborting split file %s\n"), longname);
25840Sstevel@tonic-gate 			(void) close(ifd);
25850Sstevel@tonic-gate 			return;
25860Sstevel@tonic-gate 		}
25870Sstevel@tonic-gate 	}
25880Sstevel@tonic-gate 	(void) close(ifd);
25890Sstevel@tonic-gate 	if (vflag)
25900Sstevel@tonic-gate 		(void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
25910Sstevel@tonic-gate 		    "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
25920Sstevel@tonic-gate 		    extents);
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate /*
25960Sstevel@tonic-gate  *	convtoreg - determines whether the file should be converted to a
25970Sstevel@tonic-gate  *	            regular file when extracted
25980Sstevel@tonic-gate  *
25990Sstevel@tonic-gate  *	Returns 1 when file size > 0 and typeflag is not recognized
26000Sstevel@tonic-gate  * 	Otherwise returns 0
26010Sstevel@tonic-gate  */
26020Sstevel@tonic-gate static int
convtoreg(off_t size)26030Sstevel@tonic-gate convtoreg(off_t size)
26040Sstevel@tonic-gate {
26050Sstevel@tonic-gate 	if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
26060Sstevel@tonic-gate 	    (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') &&
26070Sstevel@tonic-gate 	    (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
26080Sstevel@tonic-gate 	    (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
26090Sstevel@tonic-gate 	    (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
261011995Srich.burridge@sun.com 	    (dblock.dbuf.typeflag != 'L') &&
26110Sstevel@tonic-gate 	    (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
26120Sstevel@tonic-gate 	    (dblock.dbuf.typeflag != 'X')) {
26130Sstevel@tonic-gate 		return (1);
26140Sstevel@tonic-gate 	}
26150Sstevel@tonic-gate 	return (0);
26160Sstevel@tonic-gate }
26170Sstevel@tonic-gate 
26185331Samw #if defined(O_XATTR)
26195331Samw static int
save_cwd(void)26205331Samw save_cwd(void)
26215331Samw {
26225331Samw 	return (open(".", O_RDONLY));
26235331Samw }
26245331Samw #endif
26255331Samw 
26265331Samw #if defined(O_XATTR)
26275331Samw static void
rest_cwd(int * cwd)26285331Samw rest_cwd(int *cwd)
26295331Samw {
26305331Samw 	if (*cwd != -1) {
26315331Samw 		if (fchdir(*cwd) < 0) {
26325331Samw 			vperror(0, gettext(
26335331Samw 			    "Cannot fchdir to attribute directory"));
26345331Samw 			exit(1);
26355331Samw 		}
26365331Samw 		(void) close(*cwd);
26375331Samw 		*cwd = -1;
26385331Samw 	}
26395331Samw }
26405331Samw #endif
26415331Samw 
26425331Samw /*
26435331Samw  * Verify the underlying file system supports the attribute type.
26445331Samw  * Only archive extended attribute files when '-@' was specified.
26455331Samw  * Only archive system extended attribute files if '-/' was specified.
26465331Samw  */
26475331Samw #if defined(O_XATTR)
26485331Samw static attr_status_t
verify_attr_support(char * filename,int attrflg,arc_action_t actflag,int * ext_attrflg)26495750Sceastha verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
26505750Sceastha     int *ext_attrflg)
26515331Samw {
26525331Samw 	/*
26535750Sceastha 	 * Verify extended attributes are supported/exist.  We only
26545750Sceastha 	 * need to check if we are processing a base file, not an
26555750Sceastha 	 * extended attribute.
26565331Samw 	 */
26575750Sceastha 	if (attrflg) {
26585750Sceastha 		*ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
26595750Sceastha 		    _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
26605750Sceastha 	}
26615750Sceastha 
26625331Samw 	if (atflag) {
26635750Sceastha 		if (!*ext_attrflg) {
26645331Samw #if defined(_PC_SATTR_ENABLED)
26655331Samw 			if (saflag) {
26665331Samw 				/* Verify system attributes are supported */
26675331Samw 				if (sysattr_support(filename,
26685331Samw 				    (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
26695331Samw 				    _PC_SATTR_ENABLED) != 1) {
26705331Samw 					return (ATTR_SATTR_ERR);
26715331Samw 				}
26725331Samw 			} else
26735331Samw 				return (ATTR_XATTR_ERR);
26745331Samw #else
26755331Samw 				return (ATTR_XATTR_ERR);
26765331Samw #endif	/* _PC_SATTR_ENABLED */
26775331Samw 		}
26785331Samw 
26795331Samw #if defined(_PC_SATTR_ENABLED)
26805331Samw 	} else if (saflag) {
26815331Samw 		/* Verify system attributes are supported */
26825331Samw 		if (sysattr_support(filename, (actflag == ARC_CREATE) ?
26835331Samw 		    _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
26845331Samw 			return (ATTR_SATTR_ERR);
26855331Samw 		}
26865331Samw #endif	/* _PC_SATTR_ENABLED */
26875331Samw 	} else {
26885331Samw 		return (ATTR_SKIP);
26895331Samw 	}
26905331Samw 
26915331Samw 	return (ATTR_OK);
26925331Samw }
26935331Samw #endif
26945331Samw 
26955331Samw #if defined(O_XATTR)
26965331Samw /*
26975331Samw  * Recursively open attribute directories until the attribute directory
26985331Samw  * containing the specified attribute, attrname, is opened.
26995331Samw  *
27005331Samw  * Currently, only 2 directory levels of attributes are supported, (i.e.,
27015331Samw  * extended system attributes on extended attributes).  The following are
27025331Samw  * the possible input combinations:
27035331Samw  *	1.  Open the attribute directory of the base file (don't change
27045331Samw  *	    into it).
27055331Samw  *		attrinfo->parent = NULL
27065331Samw  *		attrname = '.'
27075331Samw  *	2.  Open the attribute directory of the base file and change into it.
27085331Samw  *		attrinfo->parent = NULL
27095331Samw  *		attrname = <attr> | <sys_attr>
27105331Samw  *	3.  Open the attribute directory of the base file, change into it,
27115331Samw  *	    then recursively call open_attr_dir() to open the attribute's
27125331Samw  *	    parent directory (don't change into it).
27135331Samw  *		attrinfo->parent = <attr>
27145331Samw  *		attrname = '.'
27155331Samw  *	4.  Open the attribute directory of the base file, change into it,
27165331Samw  *	    then recursively call open_attr_dir() to open the attribute's
27175331Samw  *	    parent directory and change into it.
27185331Samw  *		attrinfo->parent = <attr>
27195331Samw  *		attrname = <attr> | <sys_attr>
27205331Samw  *
27215331Samw  * An attribute directory will be opened only if the underlying file system
27225331Samw  * supports the attribute type, and if the command line specifications (atflag
27235331Samw  * and saflag) enable the processing of the attribute type.
27245331Samw  *
27255331Samw  * On succesful return, attrinfo->parentfd will be the file descriptor of the
27265331Samw  * opened attribute directory.  In addition, if the attribute is a read-write
27275331Samw  * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
27285331Samw  * it will be set to 0.
27295331Samw  *
27305331Samw  * Possible return values:
27315331Samw  * 	ATTR_OK		Successfully opened and, if needed, changed into the
27325331Samw  *			attribute directory containing attrname.
27335331Samw  *	ATTR_SKIP	The command line specifications don't enable the
27345331Samw  *			processing of the attribute type.
27355331Samw  * 	ATTR_CHDIR_ERR	An error occurred while trying to change into an
27365331Samw  *			attribute directory.
27375331Samw  * 	ATTR_OPEN_ERR	An error occurred while trying to open an
27385331Samw  *			attribute directory.
27395331Samw  *	ATTR_XATTR_ERR	The underlying file system doesn't support extended
27405331Samw  *			attributes.
27415331Samw  *	ATTR_SATTR_ERR	The underlying file system doesn't support extended
27425331Samw  *			system attributes.
27435331Samw  */
27445331Samw static int
open_attr_dir(char * attrname,char * dirp,int cwd,attr_data_t * attrinfo)27455331Samw open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
27465331Samw {
27475331Samw 	attr_status_t	rc;
27485331Samw 	int		firsttime = (attrinfo->attr_parentfd == -1);
27495331Samw 	int		saveerrno;
27505750Sceastha 	int		ext_attr;
27515331Samw 
27525331Samw 	/*
27535331Samw 	 * open_attr_dir() was recursively called (input combination number 4),
27545331Samw 	 * close the previously opened file descriptor as we've already changed
27555331Samw 	 * into it.
27565331Samw 	 */
27575331Samw 	if (!firsttime) {
27585331Samw 		(void) close(attrinfo->attr_parentfd);
27595331Samw 		attrinfo->attr_parentfd = -1;
27605331Samw 	}
27615331Samw 
27625331Samw 	/*
27635331Samw 	 * Verify that the underlying file system supports the restoration
27645331Samw 	 * of the attribute.
27655331Samw 	 */
27665750Sceastha 	if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
27675750Sceastha 	    &ext_attr)) != ATTR_OK) {
27685331Samw 		return (rc);
27695331Samw 	}
27705331Samw 
27715331Samw 	/* Open the base file's attribute directory */
27725331Samw 	if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
27735331Samw 		/*
27745331Samw 		 * Save the errno from the attropen so it can be reported
27755331Samw 		 * if the retry of the attropen fails.
27765331Samw 		 */
27775331Samw 		saveerrno = errno;
27785331Samw 		if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
27795331Samw 		    NULL, ".", O_RDONLY, 0)) == -1) {
27805331Samw 			/*
27815331Samw 			 * Reset typeflag back to real value so passtape
27825331Samw 			 * will skip ahead correctly.
27835331Samw 			 */
27845331Samw 			dblock.dbuf.typeflag = _XATTR_HDRTYPE;
27855331Samw 			(void) close(attrinfo->attr_parentfd);
27865331Samw 			attrinfo->attr_parentfd = -1;
27875331Samw 			errno = saveerrno;
27885331Samw 			return (ATTR_OPEN_ERR);
27895331Samw 		}
27905331Samw 	}
27915331Samw 
27925331Samw 	/*
27935331Samw 	 * Change into the parent attribute's directory unless we are
27945331Samw 	 * processing the hidden attribute directory of the base file itself.
27955331Samw 	 */
27965331Samw 	if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
27975331Samw 		if (fchdir(attrinfo->attr_parentfd) != 0) {
27985331Samw 			saveerrno = errno;
27995331Samw 			(void) close(attrinfo->attr_parentfd);
28005331Samw 			attrinfo->attr_parentfd = -1;
28015331Samw 			errno = saveerrno;
28025331Samw 			return (ATTR_CHDIR_ERR);
28035331Samw 		}
28045331Samw 	}
28055331Samw 
28065331Samw 	/* Determine if the attribute should be processed */
28075331Samw 	if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
28085331Samw 	    &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
28095331Samw 		saveerrno = errno;
28105331Samw 		(void) close(attrinfo->attr_parentfd);
28115331Samw 		attrinfo->attr_parentfd = -1;
28125331Samw 		errno = saveerrno;
28135331Samw 		return (rc);
28145331Samw 	}
28155331Samw 
28165331Samw 	/*
28175331Samw 	 * If the attribute is an extended attribute, or extended system
28185331Samw 	 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
28195331Samw 	 * recursively call open_attr_dir() to open the attribute directory
28205331Samw 	 * of the parent attribute.
28215331Samw 	 */
28225331Samw 	if (firsttime && (attrinfo->attr_parent != NULL)) {
28235331Samw 		return (open_attr_dir(attrname, attrinfo->attr_parent,
28245331Samw 		    attrinfo->attr_parentfd, attrinfo));
28255331Samw 	}
28265331Samw 
28275331Samw 	return (ATTR_OK);
28285331Samw }
28295331Samw #endif
28305331Samw 
28310Sstevel@tonic-gate static void
doxtract(char * argv[])28320Sstevel@tonic-gate doxtract(char *argv[])
28330Sstevel@tonic-gate {
28340Sstevel@tonic-gate 	struct	stat	xtractbuf;	/* stat on file after extracting */
28350Sstevel@tonic-gate 	blkcnt_t blocks;
28360Sstevel@tonic-gate 	off_t bytes;
28370Sstevel@tonic-gate 	int ofile;
28380Sstevel@tonic-gate 	int newfile;			/* Does the file already exist  */
28390Sstevel@tonic-gate 	int xcnt = 0;			/* count # files extracted */
28400Sstevel@tonic-gate 	int fcnt = 0;			/* count # files in argv list */
28410Sstevel@tonic-gate 	int dir;
28420Sstevel@tonic-gate 	int dirfd = -1;
28435331Samw 	int cwd = -1;
28445750Sceastha 	int rw_sysattr;
28455331Samw 	int saveerrno;
28460Sstevel@tonic-gate 	uid_t Uid;
28470Sstevel@tonic-gate 	char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
28480Sstevel@tonic-gate 	char dirname[PATH_MAX+1];
28490Sstevel@tonic-gate 	char templink[PATH_MAX+1];	/* temp link with terminating NULL */
28500Sstevel@tonic-gate 	int once = 1;
28510Sstevel@tonic-gate 	int error;
28520Sstevel@tonic-gate 	int symflag;
28530Sstevel@tonic-gate 	int want;
28545331Samw 	attr_data_t *attrinfo = NULL;	/* attribute info */
2855789Sahrens 	acl_t	*aclp = NULL;	/* acl info */
28561676Sjpk 	char dot[] = ".";		/* dirp for using realpath */
28570Sstevel@tonic-gate 	timestruc_t	time_zero;	/* used for call to doDirTimes */
28580Sstevel@tonic-gate 	int		dircreate;
28590Sstevel@tonic-gate 	int convflag;
28600Sstevel@tonic-gate 	time_zero.tv_sec = 0;
28610Sstevel@tonic-gate 	time_zero.tv_nsec = 0;
28620Sstevel@tonic-gate 
28631676Sjpk 	/* reset Trusted Extensions variables */
28641676Sjpk 	rpath_flag = 0;
28651676Sjpk 	lk_rpath_flag = 0;
28661676Sjpk 	dir_flag = 0;
28671676Sjpk 	mld_flag = 0;
28681676Sjpk 	bslundef(&bs_label);
28691676Sjpk 	bsllow(&admin_low);
28701676Sjpk 	bslhigh(&admin_high);
28711676Sjpk 	orig_namep = 0;
28721676Sjpk 
28730Sstevel@tonic-gate 	dumping = 0;	/* for newvol(), et al:  we are not writing */
28740Sstevel@tonic-gate 
28750Sstevel@tonic-gate 	Uid = getuid();
28760Sstevel@tonic-gate 
28770Sstevel@tonic-gate 	for (;;) {
28780Sstevel@tonic-gate 		convflag = 0;
28790Sstevel@tonic-gate 		symflag = 0;
28800Sstevel@tonic-gate 		dir = 0;
28815750Sceastha 		Hiddendir = 0;
28825750Sceastha 		rw_sysattr = 0;
28830Sstevel@tonic-gate 		ofile = -1;
28840Sstevel@tonic-gate 
28855331Samw 		if (dirfd != -1) {
28865331Samw 			(void) close(dirfd);
28875331Samw 			dirfd = -1;
28885331Samw 		}
28895331Samw 		if (ofile != -1) {
28905331Samw 			if (close(ofile) != 0)
28915331Samw 				vperror(2, gettext("close error"));
28925331Samw 		}
28935331Samw 
28945331Samw #if defined(O_XATTR)
28955331Samw 		if (cwd != -1) {
28965331Samw 			rest_cwd(&cwd);
28975331Samw 		}
28985331Samw #endif
28995331Samw 
29000Sstevel@tonic-gate 		/* namep is set by wantit to point to the full name */
29015331Samw 		if ((want = wantit(argv, &namep, &dirp, &comp,
29025331Samw 		    &attrinfo)) == 0) {
29030Sstevel@tonic-gate #if defined(O_XATTR)
29045331Samw 			if (xattrp != NULL) {
29050Sstevel@tonic-gate 				free(xattrhead);
29060Sstevel@tonic-gate 				xattrp = NULL;
29070Sstevel@tonic-gate 				xattr_linkp = NULL;
29080Sstevel@tonic-gate 				xattrhead = NULL;
29090Sstevel@tonic-gate 			}
29100Sstevel@tonic-gate #endif
29110Sstevel@tonic-gate 			continue;
29120Sstevel@tonic-gate 		}
29130Sstevel@tonic-gate 		if (want == -1)
29140Sstevel@tonic-gate 			break;
29150Sstevel@tonic-gate 
29161676Sjpk /* Trusted Extensions */
29171676Sjpk 		/*
29181676Sjpk 		 * During tar extract (x):
29191676Sjpk 		 * If the pathname of the restored file has been
29201676Sjpk 		 * reconstructed from the ancillary file,
29211676Sjpk 		 * use it to process the normal file.
29221676Sjpk 		 */
29231676Sjpk 		if (mld_flag) {		/* Skip over .MLD. directory */
29241676Sjpk 			mld_flag = 0;
29251676Sjpk 			passtape();
29261676Sjpk 			continue;
29271676Sjpk 		}
29281676Sjpk 		orig_namep = namep;	/* save original */
29291676Sjpk 		if (rpath_flag) {
29301676Sjpk 			namep = real_path;	/* use zone path */
29311676Sjpk 			comp = real_path;	/* use zone path */
29321676Sjpk 			dirp = dot;		/* work from the top */
29331676Sjpk 			rpath_flag = 0;		/* reset */
29341676Sjpk 		}
29351676Sjpk 
29360Sstevel@tonic-gate 		if (dirfd != -1)
29370Sstevel@tonic-gate 			(void) close(dirfd);
29380Sstevel@tonic-gate 
29390Sstevel@tonic-gate 		(void) strcpy(&dirname[0], namep);
29400Sstevel@tonic-gate 		dircreate = checkdir(&dirname[0]);
29410Sstevel@tonic-gate 
29420Sstevel@tonic-gate #if defined(O_XATTR)
29435331Samw 		if (xattrp != NULL) {
29445331Samw 			int	rc;
29455331Samw 
29465331Samw 			if (((cwd = save_cwd()) == -1) ||
29475331Samw 			    ((rc = open_attr_dir(comp, dirp, cwd,
29485331Samw 			    attrinfo)) != ATTR_OK)) {
29495331Samw 				if (cwd == -1) {
29505331Samw 					vperror(0, gettext(
29515331Samw 					    "unable to save current working "
29525331Samw 					    "directory while processing "
29535331Samw 					    "attribute %s of %s"),
29545331Samw 					    dirp, attrinfo->attr_path);
29555331Samw 				} else if (rc != ATTR_SKIP) {
29565331Samw 					(void) fprintf(vfile,
29575331Samw 					    gettext("tar: cannot open "
29585331Samw 					    "%sattribute %s of file %s: %s\n"),
29595331Samw 					    attrinfo->attr_rw_sysattr ? gettext(
29605331Samw 					    "system ") : "",
29615331Samw 					    comp, dirp, strerror(errno));
29625331Samw 				}
29635331Samw 				free(xattrhead);
29645331Samw 				xattrp = NULL;
29655331Samw 				xattr_linkp = NULL;
29665331Samw 				xattrhead = NULL;
29675331Samw 
29685331Samw 				passtape();
29695331Samw 				continue;
29705331Samw 			} else {
29715331Samw 				dirfd = attrinfo->attr_parentfd;
29725331Samw 				rw_sysattr = attrinfo->attr_rw_sysattr;
29735331Samw 			}
29740Sstevel@tonic-gate 		} else {
29750Sstevel@tonic-gate 			dirfd = open(dirp, O_RDONLY);
29760Sstevel@tonic-gate 		}
29770Sstevel@tonic-gate #else
29780Sstevel@tonic-gate 		dirfd = open(dirp, O_RDONLY);
29790Sstevel@tonic-gate #endif
29800Sstevel@tonic-gate 		if (dirfd == -1) {
29815331Samw 			(void) fprintf(vfile, gettext(
29825331Samw 			    "tar: cannot open %s: %s\n"),
29835331Samw 			    dirp, strerror(errno));
29845331Samw 			passtape();
29855331Samw 			continue;
29860Sstevel@tonic-gate 		}
29870Sstevel@tonic-gate 
29880Sstevel@tonic-gate 		if (xhdr_flgs & _X_LINKPATH)
29890Sstevel@tonic-gate 			(void) strcpy(templink, Xtarhdr.x_linkpath);
29900Sstevel@tonic-gate 		else {
29910Sstevel@tonic-gate #if defined(O_XATTR)
29920Sstevel@tonic-gate 			if (xattrp && dblock.dbuf.typeflag == '1') {
29930Sstevel@tonic-gate 				(void) sprintf(templink, "%.*s", NAMSIZ,
29940Sstevel@tonic-gate 				    xattrp->h_names);
29950Sstevel@tonic-gate 			} else {
29960Sstevel@tonic-gate 				(void) sprintf(templink, "%.*s", NAMSIZ,
29970Sstevel@tonic-gate 				    dblock.dbuf.linkname);
29980Sstevel@tonic-gate 			}
29990Sstevel@tonic-gate #else
30000Sstevel@tonic-gate 			(void) sprintf(templink, "%.*s", NAMSIZ,
30010Sstevel@tonic-gate 			    dblock.dbuf.linkname);
30020Sstevel@tonic-gate #endif
30030Sstevel@tonic-gate 		}
30040Sstevel@tonic-gate 
30050Sstevel@tonic-gate 		if (Fflag) {
300612423Srich.burridge@oracle.com 			if (checkf(namep, is_directory(namep), Fflag) == 0) {
30070Sstevel@tonic-gate 				passtape();
30080Sstevel@tonic-gate 				continue;
30090Sstevel@tonic-gate 			}
30100Sstevel@tonic-gate 		}
30110Sstevel@tonic-gate 
30120Sstevel@tonic-gate 		if (checkw('x', namep) == 0) {
30130Sstevel@tonic-gate 			passtape();
30140Sstevel@tonic-gate 			continue;
30150Sstevel@tonic-gate 		}
30160Sstevel@tonic-gate 		if (once) {
30170Sstevel@tonic-gate 			if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
30180Sstevel@tonic-gate 				if (geteuid() == (uid_t)0) {
30190Sstevel@tonic-gate 					checkflag = 1;
30200Sstevel@tonic-gate 					pflag = 1;
30210Sstevel@tonic-gate 				} else {
30220Sstevel@tonic-gate 					/* get file creation mask */
30230Sstevel@tonic-gate 					Oumask = umask(0);
30240Sstevel@tonic-gate 					(void) umask(Oumask);
30250Sstevel@tonic-gate 				}
30260Sstevel@tonic-gate 				once = 0;
30270Sstevel@tonic-gate 			} else {
30280Sstevel@tonic-gate 				if (geteuid() == (uid_t)0) {
30290Sstevel@tonic-gate 					pflag = 1;
30300Sstevel@tonic-gate 					checkflag = 2;
30310Sstevel@tonic-gate 				}
30320Sstevel@tonic-gate 				if (!pflag) {
30330Sstevel@tonic-gate 					/* get file creation mask */
30340Sstevel@tonic-gate 					Oumask = umask(0);
30350Sstevel@tonic-gate 					(void) umask(Oumask);
30360Sstevel@tonic-gate 				}
30370Sstevel@tonic-gate 				once = 0;
30380Sstevel@tonic-gate 			}
30390Sstevel@tonic-gate 		}
30400Sstevel@tonic-gate 
30410Sstevel@tonic-gate #if defined(O_XATTR)
30420Sstevel@tonic-gate 		/*
30430Sstevel@tonic-gate 		 * Handle extraction of hidden attr dir.
30440Sstevel@tonic-gate 		 * Dir is automatically created, we only
30450Sstevel@tonic-gate 		 * need to update mode and perm's.
30460Sstevel@tonic-gate 		 */
30475331Samw 		if ((xattrp != NULL) && Hiddendir == 1) {
30485331Samw 			bytes = stbuf.st_size;
30495331Samw 			blocks = TBLOCKS(bytes);
30505331Samw 			if (vflag) {
30515331Samw 				(void) fprintf(vfile,
305212305Srich.burridge@sun.com 				    "x %s%s%s, %" FMT_off_t " %s, ", namep,
30535331Samw 				    gettext(" attribute "),
305412305Srich.burridge@sun.com 				    xattrapath, bytes,
305512305Srich.burridge@sun.com 				    gettext("bytes"));
30565331Samw 				if (NotTape)
30575331Samw 					(void) fprintf(vfile,
30585331Samw 					    "%" FMT_blkcnt_t "K\n", K(blocks));
30595331Samw 				else
30605331Samw 					(void) fprintf(vfile, gettext("%"
30615331Samw 					    FMT_blkcnt_t " tape blocks\n"),
30625331Samw 					    blocks);
30630Sstevel@tonic-gate 			}
30640Sstevel@tonic-gate 
30655331Samw 			/*
30665331Samw 			 * Set the permissions and mode of the attribute
30675331Samw 			 * unless the attribute is a system attribute (can't
30685331Samw 			 * successfully do this) or the hidden attribute
30695331Samw 			 * directory (".") of an attribute (when the attribute
30705331Samw 			 * is restored, the hidden attribute directory of an
30715331Samw 			 * attribute is transient).  Note:  when the permissions
30725331Samw 			 * and mode are set for the hidden attribute directory
30735331Samw 			 * of a file on a system supporting extended system
30745331Samw 			 * attributes, even though it returns successfully, it
30755331Samw 			 * will not have any affect since the attribute
30765331Samw 			 * directory is transient.
30775331Samw 			 */
30785331Samw 			if (attrinfo->attr_parent == NULL) {
30795331Samw 				if (fchownat(dirfd, ".", stbuf.st_uid,
30805331Samw 				    stbuf.st_gid, 0) != 0) {
30815331Samw 					vperror(0, gettext(
30825331Samw 					    "%s%s%s: failed to set ownership "
30835331Samw 					    "of attribute directory"), namep,
30845331Samw 					    gettext(" attribute "), xattrapath);
30855331Samw 				}
30865331Samw 
30875331Samw 				if (fchmod(dirfd, stbuf.st_mode) != 0) {
30885331Samw 					vperror(0, gettext(
30895331Samw 					    "%s%s%s: failed to set permissions "
30905331Samw 					    "of attribute directory"), namep,
30915331Samw 					    gettext(" attribute "), xattrapath);
30925331Samw 				}
30930Sstevel@tonic-gate 			}
30940Sstevel@tonic-gate 			goto filedone;
30950Sstevel@tonic-gate 		}
30960Sstevel@tonic-gate #endif
30970Sstevel@tonic-gate 
30980Sstevel@tonic-gate 		if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
30990Sstevel@tonic-gate 			dir = 1;
31000Sstevel@tonic-gate 			if (vflag) {
310112305Srich.burridge@sun.com 				(void) fprintf(vfile, "x %s, 0 %s, ",
310212305Srich.burridge@sun.com 				    &dirname[0], gettext("bytes"));
31030Sstevel@tonic-gate 				if (NotTape)
31040Sstevel@tonic-gate 					(void) fprintf(vfile, "0K\n");
31050Sstevel@tonic-gate 				else
31060Sstevel@tonic-gate 					(void) fprintf(vfile, gettext("%"
31070Sstevel@tonic-gate 					    FMT_blkcnt_t " tape blocks\n"),
31080Sstevel@tonic-gate 					    (blkcnt_t)0);
31090Sstevel@tonic-gate 			}
31100Sstevel@tonic-gate 			goto filedone;
31110Sstevel@tonic-gate 		}
31120Sstevel@tonic-gate 
31130Sstevel@tonic-gate 		if (dblock.dbuf.typeflag == '6') {	/* FIFO */
31140Sstevel@tonic-gate 			if (rmdir(namep) < 0) {
31150Sstevel@tonic-gate 				if (errno == ENOTDIR)
31160Sstevel@tonic-gate 					(void) unlink(namep);
31170Sstevel@tonic-gate 			}
31180Sstevel@tonic-gate 			linkp = templink;
31190Sstevel@tonic-gate 			if (*linkp !=  NULL) {
31200Sstevel@tonic-gate 				if (Aflag && *linkp == '/')
31210Sstevel@tonic-gate 					linkp++;
31220Sstevel@tonic-gate 				if (link(linkp, namep) < 0) {
31230Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
31240Sstevel@tonic-gate 					    "tar: %s: cannot link\n"), namep);
31250Sstevel@tonic-gate 					continue;
31260Sstevel@tonic-gate 				}
31270Sstevel@tonic-gate 				if (vflag)
31280Sstevel@tonic-gate 					(void) fprintf(vfile, gettext(
31295331Samw 					    "x %s linked to %s\n"), namep,
31305331Samw 					    linkp);
31310Sstevel@tonic-gate 				xcnt++;	 /* increment # files extracted */
31320Sstevel@tonic-gate 				continue;
31330Sstevel@tonic-gate 			}
31340Sstevel@tonic-gate 			if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
31350Sstevel@tonic-gate 			    (int)Gen.g_devmajor) < 0) {
31360Sstevel@tonic-gate 				vperror(0, gettext("%s: mknod failed"), namep);
31370Sstevel@tonic-gate 				continue;
31380Sstevel@tonic-gate 			}
31390Sstevel@tonic-gate 			bytes = stbuf.st_size;
31400Sstevel@tonic-gate 			blocks = TBLOCKS(bytes);
31410Sstevel@tonic-gate 			if (vflag) {
31420Sstevel@tonic-gate 				(void) fprintf(vfile, "x %s, %" FMT_off_t
314312305Srich.burridge@sun.com 				    " %s, ", namep, bytes, gettext("bytes"));
31440Sstevel@tonic-gate 				if (NotTape)
31450Sstevel@tonic-gate 					(void) fprintf(vfile, "%" FMT_blkcnt_t
31460Sstevel@tonic-gate 					    "K\n", K(blocks));
31470Sstevel@tonic-gate 				else
31480Sstevel@tonic-gate 					(void) fprintf(vfile, gettext("%"
31490Sstevel@tonic-gate 					    FMT_blkcnt_t " tape blocks\n"),
31500Sstevel@tonic-gate 					    blocks);
31510Sstevel@tonic-gate 			}
31520Sstevel@tonic-gate 			goto filedone;
31530Sstevel@tonic-gate 		}
31540Sstevel@tonic-gate 		if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
31550Sstevel@tonic-gate 			if (rmdir(namep) < 0) {
31560Sstevel@tonic-gate 				if (errno == ENOTDIR)
31570Sstevel@tonic-gate 					(void) unlink(namep);
31580Sstevel@tonic-gate 			}
31590Sstevel@tonic-gate 			linkp = templink;
31600Sstevel@tonic-gate 			if (*linkp != NULL) {
31610Sstevel@tonic-gate 				if (Aflag && *linkp == '/')
31620Sstevel@tonic-gate 					linkp++;
31630Sstevel@tonic-gate 				if (link(linkp, namep) < 0) {
31640Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
31650Sstevel@tonic-gate 					    "tar: %s: cannot link\n"), namep);
31660Sstevel@tonic-gate 					continue;
31670Sstevel@tonic-gate 				}
31680Sstevel@tonic-gate 				if (vflag)
31690Sstevel@tonic-gate 					(void) fprintf(vfile, gettext(
31705331Samw 					    "x %s linked to %s\n"), namep,
31715331Samw 					    linkp);
31720Sstevel@tonic-gate 				xcnt++;	 /* increment # files extracted */
31730Sstevel@tonic-gate 				continue;
31740Sstevel@tonic-gate 			}
31750Sstevel@tonic-gate 			if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
31760Sstevel@tonic-gate 			    (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
31770Sstevel@tonic-gate 				vperror(0, gettext(
31785331Samw 				    "%s: mknod failed"), namep);
31790Sstevel@tonic-gate 				continue;
31800Sstevel@tonic-gate 			}
31810Sstevel@tonic-gate 			bytes = stbuf.st_size;
31820Sstevel@tonic-gate 			blocks = TBLOCKS(bytes);
31830Sstevel@tonic-gate 			if (vflag) {
31840Sstevel@tonic-gate 				(void) fprintf(vfile, "x %s, %" FMT_off_t
318512305Srich.burridge@sun.com 				    " %s, ", namep, bytes, gettext("bytes"));
31860Sstevel@tonic-gate 				if (NotTape)
31870Sstevel@tonic-gate 					(void) fprintf(vfile, "%" FMT_blkcnt_t
31880Sstevel@tonic-gate 					    "K\n", K(blocks));
31890Sstevel@tonic-gate 				else
31900Sstevel@tonic-gate 					(void) fprintf(vfile, gettext("%"
31910Sstevel@tonic-gate 					    FMT_blkcnt_t " tape blocks\n"),
31920Sstevel@tonic-gate 					    blocks);
31930Sstevel@tonic-gate 			}
31940Sstevel@tonic-gate 			goto filedone;
31950Sstevel@tonic-gate 		} else if (dblock.dbuf.typeflag == '3' && Uid) {
31960Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
31970Sstevel@tonic-gate 			    "Can't create special %s\n"), namep);
31980Sstevel@tonic-gate 			continue;
31990Sstevel@tonic-gate 		}
32000Sstevel@tonic-gate 
32010Sstevel@tonic-gate 		/* BLOCK SPECIAL */
32020Sstevel@tonic-gate 
32030Sstevel@tonic-gate 		if (dblock.dbuf.typeflag == '4' && !Uid) {
32040Sstevel@tonic-gate 			if (rmdir(namep) < 0) {
32050Sstevel@tonic-gate 				if (errno == ENOTDIR)
32060Sstevel@tonic-gate 					(void) unlink(namep);
32070Sstevel@tonic-gate 			}
32080Sstevel@tonic-gate 			linkp = templink;
32090Sstevel@tonic-gate 			if (*linkp != NULL) {
32100Sstevel@tonic-gate 				if (Aflag && *linkp == '/')
32110Sstevel@tonic-gate 					linkp++;
32120Sstevel@tonic-gate 				if (link(linkp, namep) < 0) {
32130Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
32140Sstevel@tonic-gate 					    "tar: %s: cannot link\n"), namep);
32150Sstevel@tonic-gate 					continue;
32160Sstevel@tonic-gate 				}
32170Sstevel@tonic-gate 				if (vflag)
32180Sstevel@tonic-gate 					(void) fprintf(vfile, gettext(
32195331Samw 					    "x %s linked to %s\n"), namep,
32205331Samw 					    linkp);
32210Sstevel@tonic-gate 				xcnt++;	 /* increment # files extracted */
32220Sstevel@tonic-gate 				continue;
32230Sstevel@tonic-gate 			}
32240Sstevel@tonic-gate 			if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
32250Sstevel@tonic-gate 			    (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
32260Sstevel@tonic-gate 				vperror(0, gettext("%s: mknod failed"), namep);
32270Sstevel@tonic-gate 				continue;
32280Sstevel@tonic-gate 			}
32290Sstevel@tonic-gate 			bytes = stbuf.st_size;
32300Sstevel@tonic-gate 			blocks = TBLOCKS(bytes);
32310Sstevel@tonic-gate 			if (vflag) {
32320Sstevel@tonic-gate 				(void) fprintf(vfile, gettext("x %s, %"
32330Sstevel@tonic-gate 				    FMT_off_t " bytes, "), namep, bytes);
32340Sstevel@tonic-gate 				if (NotTape)
32350Sstevel@tonic-gate 					(void) fprintf(vfile, "%" FMT_blkcnt_t
32360Sstevel@tonic-gate 					    "K\n", K(blocks));
32370Sstevel@tonic-gate 				else
32380Sstevel@tonic-gate 					(void) fprintf(vfile, gettext("%"
32390Sstevel@tonic-gate 					    FMT_blkcnt_t " tape blocks\n"),
32400Sstevel@tonic-gate 					    blocks);
32410Sstevel@tonic-gate 			}
32420Sstevel@tonic-gate 			goto filedone;
32430Sstevel@tonic-gate 		} else if (dblock.dbuf.typeflag == '4' && Uid) {
32440Sstevel@tonic-gate 			(void) fprintf(stderr,
32450Sstevel@tonic-gate 			    gettext("Can't create special %s\n"), namep);
32460Sstevel@tonic-gate 			continue;
32470Sstevel@tonic-gate 		}
32480Sstevel@tonic-gate 		if (dblock.dbuf.typeflag == '2') {	/* symlink */
32491676Sjpk 			if ((Tflag) && (lk_rpath_flag == 1))
32501676Sjpk 				linkp = lk_real_path;
32511676Sjpk 			else
32521676Sjpk 				linkp = templink;
32530Sstevel@tonic-gate 			if (Aflag && *linkp == '/')
32540Sstevel@tonic-gate 				linkp++;
32550Sstevel@tonic-gate 			if (rmdir(namep) < 0) {
32560Sstevel@tonic-gate 				if (errno == ENOTDIR)
32570Sstevel@tonic-gate 					(void) unlink(namep);
32580Sstevel@tonic-gate 			}
32590Sstevel@tonic-gate 			if (symlink(linkp, namep) < 0) {
32600Sstevel@tonic-gate 				vperror(0, gettext("%s: symbolic link failed"),
32610Sstevel@tonic-gate 				    namep);
32620Sstevel@tonic-gate 				continue;
32630Sstevel@tonic-gate 			}
32640Sstevel@tonic-gate 			if (vflag)
32650Sstevel@tonic-gate 				(void) fprintf(vfile, gettext(
32660Sstevel@tonic-gate 				    "x %s symbolic link to %s\n"),
32670Sstevel@tonic-gate 				    namep, linkp);
32680Sstevel@tonic-gate 
32690Sstevel@tonic-gate 			symflag = AT_SYMLINK_NOFOLLOW;
32700Sstevel@tonic-gate 			goto filedone;
32710Sstevel@tonic-gate 		}
32720Sstevel@tonic-gate 		if (dblock.dbuf.typeflag == '1') {
32730Sstevel@tonic-gate 			linkp = templink;
32740Sstevel@tonic-gate 			if (Aflag && *linkp == '/')
32750Sstevel@tonic-gate 				linkp++;
32760Sstevel@tonic-gate 			if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
32770Sstevel@tonic-gate 				if (errno == ENOTDIR)
32780Sstevel@tonic-gate 					(void) unlinkat(dirfd, comp, 0);
32790Sstevel@tonic-gate 			}
32800Sstevel@tonic-gate #if defined(O_XATTR)
32810Sstevel@tonic-gate 			if (xattrp && xattr_linkp) {
32820Sstevel@tonic-gate 				if (fchdir(dirfd) < 0) {
32830Sstevel@tonic-gate 					vperror(0, gettext(
32840Sstevel@tonic-gate 					    "Cannot fchdir to attribute "
32855331Samw 					    "directory %s"),
32865331Samw 					    (attrinfo->attr_parent == NULL) ?
32875331Samw 					    dirp : attrinfo->attr_parent);
32880Sstevel@tonic-gate 					exit(1);
32890Sstevel@tonic-gate 				}
32900Sstevel@tonic-gate 
32915331Samw 				error = link(xattr_linkaname, xattrapath);
32920Sstevel@tonic-gate 			} else {
32930Sstevel@tonic-gate 				error = link(linkp, namep);
32940Sstevel@tonic-gate 			}
32950Sstevel@tonic-gate #else
32960Sstevel@tonic-gate 			error = link(linkp, namep);
32970Sstevel@tonic-gate #endif
32980Sstevel@tonic-gate 
32990Sstevel@tonic-gate 			if (error < 0) {
33000Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
33010Sstevel@tonic-gate 				    "tar: %s%s%s: cannot link\n"),
33020Sstevel@tonic-gate 				    namep, (xattr_linkp != NULL) ?
33030Sstevel@tonic-gate 				    gettext(" attribute ") : "",
33040Sstevel@tonic-gate 				    (xattr_linkp != NULL) ?
33055331Samw 				    xattrapath : "");
33060Sstevel@tonic-gate 				continue;
33070Sstevel@tonic-gate 			}
33080Sstevel@tonic-gate 			if (vflag)
33090Sstevel@tonic-gate 				(void) fprintf(vfile, gettext(
33105331Samw 				    "x %s%s%s linked to %s%s%s\n"), namep,
33110Sstevel@tonic-gate 				    (xattr_linkp != NULL) ?
33120Sstevel@tonic-gate 				    gettext(" attribute ") : "",
33130Sstevel@tonic-gate 				    (xattr_linkp != NULL) ?
33140Sstevel@tonic-gate 				    xattr_linkaname : "",
33155331Samw 				    linkp,
33165331Samw 				    (xattr_linkp != NULL) ?
33170Sstevel@tonic-gate 				    gettext(" attribute ") : "",
33185331Samw 				    (xattr_linkp != NULL) ? xattrapath : "");
33190Sstevel@tonic-gate 			xcnt++;		/* increment # files extracted */
33200Sstevel@tonic-gate #if defined(O_XATTR)
33215331Samw 			if (xattrp != NULL) {
33220Sstevel@tonic-gate 				free(xattrhead);
33230Sstevel@tonic-gate 				xattrp = NULL;
33240Sstevel@tonic-gate 				xattr_linkp = NULL;
33250Sstevel@tonic-gate 				xattrhead = NULL;
33260Sstevel@tonic-gate 			}
33270Sstevel@tonic-gate #endif
33280Sstevel@tonic-gate 			continue;
33290Sstevel@tonic-gate 		}
33300Sstevel@tonic-gate 
33310Sstevel@tonic-gate 		/* REGULAR FILES */
33320Sstevel@tonic-gate 
33330Sstevel@tonic-gate 		if (convtoreg(stbuf.st_size)) {
33340Sstevel@tonic-gate 			convflag = 1;
33350Sstevel@tonic-gate 			if (errflag) {
33360Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
33370Sstevel@tonic-gate 				    "tar: %s: typeflag '%c' not recognized\n"),
33380Sstevel@tonic-gate 				    namep, dblock.dbuf.typeflag);
33390Sstevel@tonic-gate 				done(1);
33400Sstevel@tonic-gate 			} else {
33410Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
33420Sstevel@tonic-gate 				    "tar: %s: typeflag '%c' not recognized, "
33430Sstevel@tonic-gate 				    "converting to regular file\n"), namep,
33440Sstevel@tonic-gate 				    dblock.dbuf.typeflag);
33450Sstevel@tonic-gate 				Errflg = 1;
33460Sstevel@tonic-gate 			}
33470Sstevel@tonic-gate 		}
33480Sstevel@tonic-gate 		if (dblock.dbuf.typeflag == '0' ||
33490Sstevel@tonic-gate 		    dblock.dbuf.typeflag == NULL || convflag) {
33503805Slovely 			delete_target(dirfd, comp, namep);
33510Sstevel@tonic-gate 			linkp = templink;
33520Sstevel@tonic-gate 			if (*linkp != NULL) {
33530Sstevel@tonic-gate 				if (Aflag && *linkp == '/')
33540Sstevel@tonic-gate 					linkp++;
33550Sstevel@tonic-gate 				if (link(linkp, comp) < 0) {
33560Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
33570Sstevel@tonic-gate 					    "tar: %s: cannot link\n"), namep);
33580Sstevel@tonic-gate 					continue;
33590Sstevel@tonic-gate 				}
33600Sstevel@tonic-gate 				if (vflag)
33610Sstevel@tonic-gate 					(void) fprintf(vfile, gettext(
33625331Samw 					    "x %s linked to %s\n"), comp,
33635331Samw 					    linkp);
33640Sstevel@tonic-gate 				xcnt++;	 /* increment # files extracted */
33655331Samw #if defined(O_XATTR)
33665331Samw 				if (xattrp != NULL) {
33675331Samw 					free(xattrhead);
33685331Samw 					xattrp = NULL;
33695331Samw 					xattr_linkp = NULL;
33705331Samw 					xattrhead = NULL;
33715331Samw 				}
33725331Samw #endif
33730Sstevel@tonic-gate 				continue;
33740Sstevel@tonic-gate 			}
33750Sstevel@tonic-gate 		newfile = ((fstatat(dirfd, comp,
33760Sstevel@tonic-gate 		    &xtractbuf, 0) == -1) ? TRUE : FALSE);
33775331Samw 		ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
33785331Samw 		    stbuf.st_mode & MODEMASK);
33795331Samw 		saveerrno = errno;
33805331Samw 
33815331Samw #if defined(O_XATTR)
33825331Samw 		if (xattrp != NULL) {
33835331Samw 			if (ofile < 0) {
33845331Samw 				ofile = retry_open_attr(dirfd, cwd,
33855331Samw 				    dirp, attrinfo->attr_parent, comp,
33865331Samw 				    O_RDWR|O_CREAT|O_TRUNC,
33875331Samw 				    stbuf.st_mode & MODEMASK);
33885331Samw 			}
33895331Samw 		}
33905331Samw #endif
33915331Samw 		if (ofile < 0) {
33925331Samw 			errno = saveerrno;
33930Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
33945331Samw 			    "tar: %s%s%s%s - cannot create\n"),
33955331Samw 			    (xattrp == NULL) ? "" : (rw_sysattr ?
339612305Srich.burridge@sun.com 			    gettext("system attribute ") :
33975331Samw 			    gettext("attribute ")),
33985331Samw 			    (xattrp == NULL) ? "" : xattrapath,
33995331Samw 			    (xattrp == NULL) ? "" : gettext(" of "),
34005331Samw 			    (xattrp == NULL) ? comp : namep);
34010Sstevel@tonic-gate 			if (errflag)
34020Sstevel@tonic-gate 				done(1);
34030Sstevel@tonic-gate 			else
34040Sstevel@tonic-gate 				Errflg = 1;
34055331Samw #if defined(O_XATTR)
34065331Samw 			if (xattrp != NULL) {
34075331Samw 				dblock.dbuf.typeflag = _XATTR_HDRTYPE;
34085331Samw 				free(xattrhead);
34095331Samw 				xattrp = NULL;
34105331Samw 				xattr_linkp = NULL;
34115331Samw 				xattrhead = NULL;
34125331Samw 			}
34135331Samw #endif
34140Sstevel@tonic-gate 			passtape();
34150Sstevel@tonic-gate 			continue;
34160Sstevel@tonic-gate 		}
34170Sstevel@tonic-gate 
34181676Sjpk 		if (Tflag && (check_ext_attr(namep) == 0)) {
34191676Sjpk 			if (errflag)
34201676Sjpk 				done(1);
34211676Sjpk 			else
34221676Sjpk 				Errflg = 1;
34231676Sjpk 			passtape();
34241676Sjpk 			continue;
34251676Sjpk 		}
34261676Sjpk 
34270Sstevel@tonic-gate 		if (extno != 0) {	/* file is in pieces */
34280Sstevel@tonic-gate 			if (extotal < 1 || extotal > MAXEXT)
34290Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
34305331Samw 				    "tar: ignoring bad extent info for "
34315331Samw 				    "%s%s%s%s\n"),
34325331Samw 				    (xattrp == NULL) ? "" : (rw_sysattr ?
34335331Samw 				    gettext("system attribute ") :
34345331Samw 				    gettext("attribute ")),
34355331Samw 				    (xattrp == NULL) ? "" : xattrapath,
34365331Samw 				    (xattrp == NULL) ? "" : gettext(" of "),
34375331Samw 				    (xattrp == NULL) ? comp : namep);
34380Sstevel@tonic-gate 			else {
34395331Samw 				/* extract it */
34405331Samw 				(void) xsfile(rw_sysattr, ofile);
34410Sstevel@tonic-gate 			}
34420Sstevel@tonic-gate 		}
34430Sstevel@tonic-gate 		extno = 0;	/* let everyone know file is not split */
34440Sstevel@tonic-gate 		bytes = stbuf.st_size;
34450Sstevel@tonic-gate 		blocks = TBLOCKS(bytes);
34460Sstevel@tonic-gate 		if (vflag) {
34470Sstevel@tonic-gate 			(void) fprintf(vfile,
344812305Srich.burridge@sun.com 			    "x %s%s%s, %" FMT_off_t " %s, ",
34490Sstevel@tonic-gate 			    (xattrp == NULL) ? "" : dirp,
34505331Samw 			    (xattrp == NULL) ? "" : (rw_sysattr ?
34515331Samw 			    gettext(" system attribute ") :
34525331Samw 			    gettext(" attribute ")),
345312305Srich.burridge@sun.com 			    (xattrp == NULL) ? namep : xattrapath, bytes,
345412305Srich.burridge@sun.com 			    gettext("bytes"));
34550Sstevel@tonic-gate 			if (NotTape)
34560Sstevel@tonic-gate 				(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
34570Sstevel@tonic-gate 				    K(blocks));
34580Sstevel@tonic-gate 			else
34590Sstevel@tonic-gate 				(void) fprintf(vfile, gettext("%"
34600Sstevel@tonic-gate 				    FMT_blkcnt_t " tape blocks\n"), blocks);
34610Sstevel@tonic-gate 		}
34620Sstevel@tonic-gate 
34635331Samw 		if (xblocks(rw_sysattr, bytes, ofile) != 0) {
34645331Samw #if defined(O_XATTR)
34655331Samw 			if (xattrp != NULL) {
34665331Samw 				free(xattrhead);
34675331Samw 				xattrp = NULL;
34685331Samw 				xattr_linkp = NULL;
34695331Samw 				xattrhead = NULL;
34705331Samw 			}
34715331Samw #endif
34725331Samw 			continue;
34735331Samw 		}
34740Sstevel@tonic-gate filedone:
34750Sstevel@tonic-gate 		if (mflag == 0 && !symflag) {
34760Sstevel@tonic-gate 			if (dir)
34770Sstevel@tonic-gate 				doDirTimes(namep, stbuf.st_mtim);
34785331Samw 
34790Sstevel@tonic-gate 			else
34805331Samw #if defined(O_XATTR)
34815331Samw 				if (xattrp != NULL) {
34825331Samw 					/*
34835331Samw 					 * Set the time on the attribute unless
34845331Samw 					 * the attribute is a system attribute
34855331Samw 					 * (can't successfully do this) or the
34865331Samw 					 * hidden attribute directory, "." (the
34875331Samw 					 * time on the hidden attribute
34885331Samw 					 * directory will be updated when
34895331Samw 					 * attributes are restored, otherwise
34905331Samw 					 * it's transient).
34915331Samw 					 */
34925331Samw 					if (!rw_sysattr && (Hiddendir == 0)) {
34935331Samw 						setPathTimes(dirfd, comp,
34945331Samw 						    stbuf.st_mtim);
34955331Samw 					}
34965331Samw 				} else
34975331Samw 					setPathTimes(dirfd, comp,
34985331Samw 					    stbuf.st_mtim);
34995331Samw #else
35000Sstevel@tonic-gate 				setPathTimes(dirfd, comp, stbuf.st_mtim);
35015331Samw #endif
35020Sstevel@tonic-gate 		}
35030Sstevel@tonic-gate 
35040Sstevel@tonic-gate 		/* moved this code from above */
35050Sstevel@tonic-gate 		if (pflag && !symflag && Hiddendir == 0) {
35065331Samw 			if (xattrp != NULL)
35070Sstevel@tonic-gate 				(void) fchmod(ofile, stbuf.st_mode & MODEMASK);
35080Sstevel@tonic-gate 			else
35090Sstevel@tonic-gate 				(void) chmod(namep, stbuf.st_mode & MODEMASK);
35100Sstevel@tonic-gate 		}
35110Sstevel@tonic-gate 
35120Sstevel@tonic-gate 
35130Sstevel@tonic-gate 		/*
35140Sstevel@tonic-gate 		 * Because ancillary file preceeds the normal file,
35150Sstevel@tonic-gate 		 * acl info may have been retrieved (in aclp).
35160Sstevel@tonic-gate 		 * All file types are directed here (go filedone).
35170Sstevel@tonic-gate 		 * Always restore ACLs if there are ACLs.
35180Sstevel@tonic-gate 		 */
35190Sstevel@tonic-gate 		if (aclp != NULL) {
35200Sstevel@tonic-gate 			int ret;
35210Sstevel@tonic-gate 
35220Sstevel@tonic-gate #if defined(O_XATTR)
35235331Samw 			if (xattrp != NULL) {
35240Sstevel@tonic-gate 				if (Hiddendir)
3525789Sahrens 					ret = facl_set(dirfd, aclp);
35260Sstevel@tonic-gate 				else
3527789Sahrens 					ret = facl_set(ofile, aclp);
35280Sstevel@tonic-gate 			} else {
3529789Sahrens 				ret = acl_set(namep, aclp);
35300Sstevel@tonic-gate 			}
35310Sstevel@tonic-gate #else
35321676Sjpk 			ret = acl_set(namep, aclp);
35330Sstevel@tonic-gate #endif
35340Sstevel@tonic-gate 			if (ret < 0) {
35350Sstevel@tonic-gate 				if (pflag) {
35360Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
35375331Samw 					    "%s%s%s%s: failed to set acl "
35385331Samw 					    "entries\n"), namep,
35395331Samw 					    (xattrp == NULL) ? "" :
35405331Samw 					    (rw_sysattr ? gettext(
35415331Samw 					    " system attribute ") :
35425331Samw 					    gettext(" attribute ")),
35435331Samw 					    (xattrp == NULL) ? "" :
35445331Samw 					    xattrapath);
35450Sstevel@tonic-gate 				}
35460Sstevel@tonic-gate 				/* else: silent and continue */
35470Sstevel@tonic-gate 			}
3548789Sahrens 			acl_free(aclp);
35490Sstevel@tonic-gate 			aclp = NULL;
35500Sstevel@tonic-gate 		}
35510Sstevel@tonic-gate 
35520Sstevel@tonic-gate 		if (!oflag)
3553*12836Srich.burridge@oracle.com 			/* set file ownership */
3554*12836Srich.burridge@oracle.com 			resugname(dirfd, comp, symflag);
35550Sstevel@tonic-gate 
35560Sstevel@tonic-gate 		if (pflag && newfile == TRUE && !dir &&
35570Sstevel@tonic-gate 		    (dblock.dbuf.typeflag == '0' ||
35580Sstevel@tonic-gate 		    dblock.dbuf.typeflag == NULL ||
35590Sstevel@tonic-gate 		    convflag || dblock.dbuf.typeflag == '1')) {
35600Sstevel@tonic-gate 			if (fstat(ofile, &xtractbuf) == -1)
35610Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
35625331Samw 				    "tar: cannot stat extracted file "
35635331Samw 				    "%s%s%s%s\n"),
35645331Samw 				    (xattrp == NULL) ? "" : (rw_sysattr ?
35655331Samw 				    gettext("system attribute ") :
35665331Samw 				    gettext("attribute ")),
35675331Samw 				    (xattrp == NULL) ? "" : xattrapath,
35685331Samw 				    (xattrp == NULL) ? "" :
35695331Samw 				    gettext(" of "), namep);
35705331Samw 
35710Sstevel@tonic-gate 			else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
35720Sstevel@tonic-gate 			    != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
35730Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
35740Sstevel@tonic-gate 				    "tar: warning - file permissions have "
35755331Samw 				    "changed for %s%s%s%s (are 0%o, should be "
35760Sstevel@tonic-gate 				    "0%o)\n"),
35775331Samw 				    (xattrp == NULL) ? "" : (rw_sysattr ?
35785331Samw 				    gettext("system attribute ") :
35795331Samw 				    gettext("attribute ")),
35805331Samw 				    (xattrp == NULL) ? "" : xattrapath,
35815331Samw 				    (xattrp == NULL) ? "" :
35825331Samw 				    gettext(" of "), namep,
35835331Samw 				    xtractbuf.st_mode, stbuf.st_mode);
35845331Samw 
35850Sstevel@tonic-gate 			}
35860Sstevel@tonic-gate 		}
35875750Sceastha #if defined(O_XATTR)
35885750Sceastha 		if (xattrp != NULL) {
35895750Sceastha 			free(xattrhead);
35905750Sceastha 			xattrp = NULL;
35915750Sceastha 			xattr_linkp = NULL;
35925750Sceastha 			xattrhead = NULL;
35935750Sceastha 		}
35945750Sceastha #endif
35955750Sceastha 
35960Sstevel@tonic-gate 		if (ofile != -1) {
35970Sstevel@tonic-gate 			(void) close(dirfd);
35980Sstevel@tonic-gate 			dirfd = -1;
35990Sstevel@tonic-gate 			if (close(ofile) != 0)
36000Sstevel@tonic-gate 				vperror(2, gettext("close error"));
36015331Samw 			ofile = -1;
36020Sstevel@tonic-gate 		}
36030Sstevel@tonic-gate 		xcnt++;			/* increment # files extracted */
36040Sstevel@tonic-gate 		}
36051676Sjpk 
36061676Sjpk 		/*
36071676Sjpk 		 * Process ancillary file.
36081676Sjpk 		 *
36091676Sjpk 		 */
36101676Sjpk 
36111676Sjpk 		if (dblock.dbuf.typeflag == 'A') {	/* acl info */
36120Sstevel@tonic-gate 			char	buf[TBLOCK];
36130Sstevel@tonic-gate 			char	*secp;
36140Sstevel@tonic-gate 			char	*tp;
36150Sstevel@tonic-gate 			int	attrsize;
36160Sstevel@tonic-gate 			int	cnt;
36170Sstevel@tonic-gate 
36181676Sjpk 			/* reset Trusted Extensions flags */
36191676Sjpk 			dir_flag = 0;
36201676Sjpk 			mld_flag = 0;
36211676Sjpk 			lk_rpath_flag = 0;
36221676Sjpk 			rpath_flag = 0;
36230Sstevel@tonic-gate 
36240Sstevel@tonic-gate 			if (pflag) {
36250Sstevel@tonic-gate 				bytes = stbuf.st_size;
36260Sstevel@tonic-gate 				if ((secp = malloc((int)bytes)) == NULL) {
36270Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
36280Sstevel@tonic-gate 					    "Insufficient memory for acl\n"));
36290Sstevel@tonic-gate 					passtape();
36300Sstevel@tonic-gate 					continue;
36310Sstevel@tonic-gate 				}
36320Sstevel@tonic-gate 				tp = secp;
36330Sstevel@tonic-gate 				blocks = TBLOCKS(bytes);
36341676Sjpk 
36351676Sjpk 				/*
36361676Sjpk 				 * Display a line for each ancillary file.
36371676Sjpk 				 */
36381676Sjpk 				if (vflag && Tflag)
36391676Sjpk 					(void) fprintf(vfile, "x %s(A), %"
364012305Srich.burridge@sun.com 					    FMT_blkcnt_t " %s, %"
364112305Srich.burridge@sun.com 					    FMT_blkcnt_t " %s\n",
364212305Srich.burridge@sun.com 					    namep, bytes, gettext("bytes"),
364312305Srich.burridge@sun.com 					    blocks, gettext("tape blocks"));
36441676Sjpk 
36450Sstevel@tonic-gate 				while (blocks-- > 0) {
36460Sstevel@tonic-gate 					readtape(buf);
36470Sstevel@tonic-gate 					if (bytes <= TBLOCK) {
36480Sstevel@tonic-gate 						(void) memcpy(tp, buf,
36490Sstevel@tonic-gate 						    (size_t)bytes);
36500Sstevel@tonic-gate 						break;
36510Sstevel@tonic-gate 					} else {
36520Sstevel@tonic-gate 						(void) memcpy(tp, buf,
36530Sstevel@tonic-gate 						    TBLOCK);
36540Sstevel@tonic-gate 						tp += TBLOCK;
36550Sstevel@tonic-gate 					}
36560Sstevel@tonic-gate 					bytes -= TBLOCK;
36570Sstevel@tonic-gate 				}
3658789Sahrens 				bytes = stbuf.st_size;
36590Sstevel@tonic-gate 				/* got all attributes in secp */
36600Sstevel@tonic-gate 				tp = secp;
36610Sstevel@tonic-gate 				do {
36620Sstevel@tonic-gate 					attr = (struct sec_attr *)tp;
36630Sstevel@tonic-gate 					switch (attr->attr_type) {
36640Sstevel@tonic-gate 					case UFSD_ACL:
3665789Sahrens 					case ACE_ACL:
36660Sstevel@tonic-gate 						(void) sscanf(attr->attr_len,
3667789Sahrens 						    "%7o",
3668789Sahrens 						    (uint_t *)
3669789Sahrens 						    &cnt);
36700Sstevel@tonic-gate 						/* header is 8 */
36710Sstevel@tonic-gate 						attrsize = 8 + (int)strlen(
36720Sstevel@tonic-gate 						    &attr->attr_info[0]) + 1;
3673789Sahrens 						error =
3674789Sahrens 						    acl_fromtext(
3675789Sahrens 						    &attr->attr_info[0], &aclp);
3676789Sahrens 
3677789Sahrens 						if (error != 0) {
36780Sstevel@tonic-gate 							(void) fprintf(stderr,
36790Sstevel@tonic-gate 							    gettext(
36800Sstevel@tonic-gate 							    "aclfromtext "
3681789Sahrens 							    "failed: %s\n"),
3682789Sahrens 							    acl_strerror(
3683789Sahrens 							    error));
3684789Sahrens 							bytes -= attrsize;
36850Sstevel@tonic-gate 							break;
36860Sstevel@tonic-gate 						}
3687789Sahrens 						if (acl_cnt(aclp) != cnt) {
36880Sstevel@tonic-gate 							(void) fprintf(stderr,
36890Sstevel@tonic-gate 							    gettext(
36900Sstevel@tonic-gate 							    "aclcnt error\n"));
3691789Sahrens 							bytes -= attrsize;
36920Sstevel@tonic-gate 							break;
36930Sstevel@tonic-gate 						}
36940Sstevel@tonic-gate 						bytes -= attrsize;
36950Sstevel@tonic-gate 						break;
36960Sstevel@tonic-gate 
36971676Sjpk 					/* Trusted Extensions */
36981676Sjpk 
36991676Sjpk 					case DIR_TYPE:
37001676Sjpk 					case LBL_TYPE:
37011676Sjpk 					case APRIV_TYPE:
37021676Sjpk 					case FPRIV_TYPE:
37031676Sjpk 					case COMP_TYPE:
37041676Sjpk 					case LK_COMP_TYPE:
37051676Sjpk 					case ATTR_FLAG_TYPE:
37061676Sjpk 						attrsize =
37071676Sjpk 						    sizeof (struct sec_attr) +
37081676Sjpk 						    strlen(&attr->attr_info[0]);
37091676Sjpk 						bytes -= attrsize;
37101676Sjpk 						if (Tflag)
37111676Sjpk 							extract_attr(&namep,
37121676Sjpk 							    attr);
37131676Sjpk 						break;
37140Sstevel@tonic-gate 
37150Sstevel@tonic-gate 					default:
37160Sstevel@tonic-gate 						(void) fprintf(stderr, gettext(
37170Sstevel@tonic-gate 						    "unrecognized attr"
37180Sstevel@tonic-gate 						    " type\n"));
37190Sstevel@tonic-gate 						bytes = (off_t)0;
37200Sstevel@tonic-gate 						break;
37210Sstevel@tonic-gate 					}
37220Sstevel@tonic-gate 
37230Sstevel@tonic-gate 					/* next attributes */
37240Sstevel@tonic-gate 					tp += attrsize;
37250Sstevel@tonic-gate 				} while (bytes != 0);
37260Sstevel@tonic-gate 				free(secp);
37275331Samw 			} else {
37280Sstevel@tonic-gate 				passtape();
37295331Samw 			}
37300Sstevel@tonic-gate 		} /* acl */
37310Sstevel@tonic-gate 
37320Sstevel@tonic-gate 	} /* for */
37330Sstevel@tonic-gate 
37340Sstevel@tonic-gate 	/*
37350Sstevel@tonic-gate 	 *  Ensure that all the directories still on the directory stack
37360Sstevel@tonic-gate 	 *  get their modification times set correctly by flushing the
37370Sstevel@tonic-gate 	 *  stack.
37380Sstevel@tonic-gate 	 */
37390Sstevel@tonic-gate 
37400Sstevel@tonic-gate 	doDirTimes(NULL, time_zero);
37410Sstevel@tonic-gate 
37425331Samw #if defined(O_XATTR)
37435331Samw 		if (xattrp != NULL) {
37445331Samw 			free(xattrhead);
37455331Samw 			xattrp = NULL;
37465331Samw 			xattr_linkp = NULL;
37475331Samw 			xattrhead = NULL;
37485331Samw 		}
37495331Samw #endif
37505331Samw 
37510Sstevel@tonic-gate 	/*
37520Sstevel@tonic-gate 	 * Check if the number of files extracted is different from the
37530Sstevel@tonic-gate 	 * number of files listed on the command line
37540Sstevel@tonic-gate 	 */
37550Sstevel@tonic-gate 	if (fcnt > xcnt) {
37560Sstevel@tonic-gate 		(void) fprintf(stderr,
37570Sstevel@tonic-gate 		    gettext("tar: %d file(s) not extracted\n"),
3758*12836Srich.burridge@oracle.com 		    fcnt-xcnt);
37590Sstevel@tonic-gate 		Errflg = 1;
37600Sstevel@tonic-gate 	}
37610Sstevel@tonic-gate }
37620Sstevel@tonic-gate 
37630Sstevel@tonic-gate /*
37640Sstevel@tonic-gate  *	xblocks		extract file/extent from tape to output file
37650Sstevel@tonic-gate  *
37665750Sceastha  *	xblocks(issysattr, bytes, ofile);
37675750Sceastha  *
37685750Sceastha  *	issysattr			flag set if the files being extracted
37695750Sceastha  *					is an extended system attribute file.
37705750Sceastha  *	unsigned long long bytes	size of extent or file to be extracted
37715750Sceastha  *	ofile				output file
37720Sstevel@tonic-gate  *
37730Sstevel@tonic-gate  *	called by doxtract() and xsfile()
37740Sstevel@tonic-gate  */
37750Sstevel@tonic-gate 
37765331Samw static int
xblocks(int issysattr,off_t bytes,int ofile)37775331Samw xblocks(int issysattr, off_t bytes, int ofile)
37780Sstevel@tonic-gate {
37795750Sceastha 	char *buf;
37800Sstevel@tonic-gate 	char tempname[NAMSIZ+1];
37815750Sceastha 	size_t maxwrite;
37825750Sceastha 	size_t bytesread;
37835750Sceastha 	size_t piosize;		/* preferred I/O size */
37845750Sceastha 	struct stat tsbuf;
37855750Sceastha 
37865750Sceastha 	/* Don't need to do anything if this is a zero size file */
37875750Sceastha 	if (bytes <= 0) {
37885750Sceastha 		return (0);
37895750Sceastha 	}
37905750Sceastha 
37915750Sceastha 	/*
37925750Sceastha 	 * To figure out the size of the buffer used to accumulate data
37935750Sceastha 	 * from readtape() and to write to the file, we need to determine
37945750Sceastha 	 * the largest chunk of data to be written to the file at one time.
37955750Sceastha 	 * This is determined based on the smallest of the following two
37965750Sceastha 	 * things:
37975750Sceastha 	 *	1) The size of the archived file.
37985750Sceastha 	 *	2) The preferred I/O size of the file.
37995750Sceastha 	 */
38005750Sceastha 	if (issysattr || (bytes <= TBLOCK)) {
38015750Sceastha 		/*
38025750Sceastha 		 * Writes to system attribute files must be
38035750Sceastha 		 * performed in one operation.
38045750Sceastha 		 */
38055750Sceastha 		maxwrite = bytes;
38065750Sceastha 	} else {
38075750Sceastha 		/*
38085750Sceastha 		 * fstat() the file to get the preferred I/O size.
38095750Sceastha 		 * If it fails, then resort back to just writing
38105750Sceastha 		 * one block at a time.
38115750Sceastha 		 */
38125750Sceastha 		if (fstat(ofile, &tsbuf) == 0) {
38135750Sceastha 			piosize = tsbuf.st_blksize;
38145750Sceastha 		} else {
38155750Sceastha 			piosize = TBLOCK;
38165750Sceastha 		}
38175750Sceastha 		maxwrite = min(bytes, piosize);
38185750Sceastha 	}
38195750Sceastha 
38205750Sceastha 	/*
38215750Sceastha 	 * The buffer used to accumulate the data for the write operation
38225750Sceastha 	 * needs to be the maximum number of bytes to be written rounded up
38235750Sceastha 	 * to the nearest TBLOCK since readtape reads one block at a time.
38245750Sceastha 	 */
38255750Sceastha 	if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
38265750Sceastha 		fatal(gettext("cannot allocate buffer"));
38275750Sceastha 	}
38285750Sceastha 
38295750Sceastha 	while (bytes > 0) {
38305750Sceastha 
38315750Sceastha 		/*
38325750Sceastha 		 * readtape() obtains one block (TBLOCK) of data at a time.
38335750Sceastha 		 * Accumulate as many blocks of data in buf as we can write
38345750Sceastha 		 * in one operation.
38355750Sceastha 		 */
38365750Sceastha 		for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
38375750Sceastha 			readtape(buf + bytesread);
38385750Sceastha 		}
38395750Sceastha 
38405750Sceastha 		if (write(ofile, buf, maxwrite) < 0) {
38415331Samw 			int saveerrno = errno;
38425331Samw 
38430Sstevel@tonic-gate 			if (xhdr_flgs & _X_PATH)
38445750Sceastha 				(void) strlcpy(tempname, Xtarhdr.x_path,
38455750Sceastha 				    sizeof (tempname));
38460Sstevel@tonic-gate 			else
38470Sstevel@tonic-gate 				(void) sprintf(tempname, "%.*s", NAMSIZ,
38480Sstevel@tonic-gate 				    dblock.dbuf.name);
38495331Samw 			/*
38505331Samw 			 * If the extended system attribute being extracted
38515331Samw 			 * contains attributes that the user needs privileges
38525331Samw 			 * for, then just display a warning message, skip
38535331Samw 			 * the extraction of this file, and return.
38545331Samw 			 */
38555331Samw 			if ((saveerrno == EPERM) && issysattr) {
38565331Samw 				(void) fprintf(stderr, gettext(
38575331Samw 				    "tar: unable to extract system attribute "
38585331Samw 				    "%s: insufficient privileges\n"), tempname);
38595331Samw 				Errflg = 1;
38605750Sceastha 				(void) free(buf);
38615331Samw 				return (1);
38625331Samw 			} else {
38635331Samw 				(void) fprintf(stderr, gettext(
38645331Samw 				    "tar: %s: HELP - extract write error\n"),
38655331Samw 				    tempname);
38665331Samw 				done(2);
38675331Samw 			}
38680Sstevel@tonic-gate 		}
38695750Sceastha 		bytes -= maxwrite;
38705750Sceastha 
38715750Sceastha 		/*
38725750Sceastha 		 * If we've reached this point and there is still data
38735750Sceastha 		 * to be written, maxwrite had to have been determined
38745750Sceastha 		 * by the preferred I/O size.  If the number of bytes
38755750Sceastha 		 * left to write is smaller than the preferred I/O size,
38765750Sceastha 		 * then we're about to do our final write to the file, so
38775750Sceastha 		 * just set maxwrite to the number of bytes left to write.
38785750Sceastha 		 */
38795750Sceastha 		if ((bytes > 0) && (bytes < maxwrite)) {
38805750Sceastha 			maxwrite = bytes;
38815750Sceastha 		}
38825750Sceastha 	}
38835750Sceastha 	free(buf);
38845331Samw 
38855331Samw 	return (0);
38860Sstevel@tonic-gate }
38870Sstevel@tonic-gate 
38880Sstevel@tonic-gate /*
38890Sstevel@tonic-gate  * 	xsfile	extract split file
38900Sstevel@tonic-gate  *
38910Sstevel@tonic-gate  *	xsfile(ofd);	ofd = output file descriptor
38920Sstevel@tonic-gate  *
38930Sstevel@tonic-gate  *	file extracted and put in ofd via xblocks()
38940Sstevel@tonic-gate  *
38950Sstevel@tonic-gate  *	NOTE:  only called by doxtract() to extract one large file
38960Sstevel@tonic-gate  */
38970Sstevel@tonic-gate 
38980Sstevel@tonic-gate static	union	hblock	savedblock;	/* to ensure same file across volumes */
38990Sstevel@tonic-gate 
39005331Samw static int
xsfile(int issysattr,int ofd)39015331Samw xsfile(int issysattr, int ofd)
39020Sstevel@tonic-gate {
39030Sstevel@tonic-gate 	int i, c;
39045331Samw 	int sysattrerr = 0;
39050Sstevel@tonic-gate 	char name[PATH_MAX+1];	/* holds name for diagnostics */
39060Sstevel@tonic-gate 	int extents, totalext;
39070Sstevel@tonic-gate 	off_t bytes, totalbytes;
39080Sstevel@tonic-gate 
39090Sstevel@tonic-gate 	if (xhdr_flgs & _X_PATH)
39100Sstevel@tonic-gate 		(void) strcpy(name, Xtarhdr.x_path);
39110Sstevel@tonic-gate 	else
39120Sstevel@tonic-gate 		(void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
39130Sstevel@tonic-gate 
39140Sstevel@tonic-gate 	totalbytes = (off_t)0;		/* in case we read in half the file */
39150Sstevel@tonic-gate 	totalext = 0;		/* these keep count */
39160Sstevel@tonic-gate 
39170Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
39180Sstevel@tonic-gate 	    "tar: %s split across %d volumes\n"), name, extotal);
39190Sstevel@tonic-gate 
39200Sstevel@tonic-gate 	/* make sure we do extractions in order */
39210Sstevel@tonic-gate 	if (extno != 1) {	/* starting in middle of file? */
39220Sstevel@tonic-gate 		(void) printf(gettext(
39231266Sceastha 		    "tar: first extent read is not #1\n"
39244774Sas145665 		    "OK to read file beginning with extent #%d (%s/%s) ? "),
39254774Sas145665 		    extno, yesstr, nostr);
39264774Sas145665 		if (yes() == 0) {
39270Sstevel@tonic-gate canit:
39280Sstevel@tonic-gate 			passtape();
39290Sstevel@tonic-gate 			if (close(ofd) != 0)
39300Sstevel@tonic-gate 				vperror(2, gettext("close error"));
39315331Samw 			if (sysattrerr) {
39325331Samw 				return (1);
39335331Samw 			} else {
39345331Samw 				return (0);
39355331Samw 			}
39360Sstevel@tonic-gate 		}
39370Sstevel@tonic-gate 	}
39380Sstevel@tonic-gate 	extents = extotal;
39390Sstevel@tonic-gate 	i = extno;
39400Sstevel@tonic-gate 	/*CONSTCOND*/
39410Sstevel@tonic-gate 	while (1) {
39420Sstevel@tonic-gate 		if (xhdr_flgs & _X_SIZE) {
39430Sstevel@tonic-gate 			bytes = extsize;
39440Sstevel@tonic-gate 		} else {
39450Sstevel@tonic-gate 			bytes = stbuf.st_size;
39460Sstevel@tonic-gate 		}
39470Sstevel@tonic-gate 
39480Sstevel@tonic-gate 		if (vflag)
394912305Srich.burridge@sun.com 			(void) fprintf(vfile, "+++ x %s [%s #%d], %"
395012305Srich.burridge@sun.com 			    FMT_off_t " %s, %ldK\n",
395112305Srich.burridge@sun.com 			    name, gettext("extent"), extno,
395212305Srich.burridge@sun.com 			    bytes, gettext("bytes"),
39530Sstevel@tonic-gate 			    (long)K(TBLOCKS(bytes)));
39545331Samw 		if (xblocks(issysattr, bytes, ofd) != 0) {
39555331Samw 			sysattrerr = 1;
39565331Samw 			goto canit;
39575331Samw 		}
39580Sstevel@tonic-gate 
39590Sstevel@tonic-gate 		totalbytes += bytes;
39600Sstevel@tonic-gate 		totalext++;
39610Sstevel@tonic-gate 		if (++i > extents)
39620Sstevel@tonic-gate 			break;
39630Sstevel@tonic-gate 
39640Sstevel@tonic-gate 		/* get next volume and verify it's the right one */
39650Sstevel@tonic-gate 		copy(&savedblock, &dblock);
39660Sstevel@tonic-gate tryagain:
39670Sstevel@tonic-gate 		newvol();
39680Sstevel@tonic-gate 		xhdr_flgs = 0;
39690Sstevel@tonic-gate 		getdir();
39700Sstevel@tonic-gate 		if (Xhdrflag > 0)
39710Sstevel@tonic-gate 			(void) get_xdata();	/* Get x-header & regular hdr */
39725482Sas158974 		if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
39735482Sas158974 			load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
39745482Sas158974 			xhdr_flgs |= _X_XHDR;
39755482Sas158974 		}
39760Sstevel@tonic-gate 		if (endtape()) {	/* seemingly empty volume */
39770Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
39780Sstevel@tonic-gate 			    "tar: first record is null\n"));
39790Sstevel@tonic-gate asknicely:
39800Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
39810Sstevel@tonic-gate 			    "tar: need volume with extent #%d of %s\n"),
39820Sstevel@tonic-gate 			    i, name);
39830Sstevel@tonic-gate 			goto tryagain;
39840Sstevel@tonic-gate 		}
39850Sstevel@tonic-gate 		if (notsame()) {
39860Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
39870Sstevel@tonic-gate 			    "tar: first file on that volume is not "
39880Sstevel@tonic-gate 			    "the same file\n"));
39890Sstevel@tonic-gate 			goto asknicely;
39900Sstevel@tonic-gate 		}
39910Sstevel@tonic-gate 		if (i != extno) {
39920Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
39931266Sceastha 			    "tar: extent #%d received out of order\ntar: "
39941266Sceastha 			    "should be #%d\n"), extno, i);
39950Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
39960Sstevel@tonic-gate 			    "Ignore error, Abort this file, or "
39970Sstevel@tonic-gate 			    "load New volume (i/a/n) ? "));
39980Sstevel@tonic-gate 			c = response();
39990Sstevel@tonic-gate 			if (c == 'a')
40000Sstevel@tonic-gate 				goto canit;
40010Sstevel@tonic-gate 			if (c != 'i')		/* default to new volume */
40020Sstevel@tonic-gate 				goto asknicely;
40030Sstevel@tonic-gate 			i = extno;		/* okay, start from there */
40040Sstevel@tonic-gate 		}
40050Sstevel@tonic-gate 	}
40060Sstevel@tonic-gate 	if (vflag)
40070Sstevel@tonic-gate 		(void) fprintf(vfile, gettext(
40080Sstevel@tonic-gate 		    "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
40090Sstevel@tonic-gate 		    name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
40105331Samw 
40115331Samw 	return (0);
40120Sstevel@tonic-gate }
40130Sstevel@tonic-gate 
40140Sstevel@tonic-gate 
40150Sstevel@tonic-gate /*
40160Sstevel@tonic-gate  *	notsame()	check if extract file extent is invalid
40170Sstevel@tonic-gate  *
40180Sstevel@tonic-gate  *	returns true if anything differs between savedblock and dblock
40190Sstevel@tonic-gate  *	except extno (extent number), checksum, or size (extent size).
40200Sstevel@tonic-gate  *	Determines if this header belongs to the same file as the one we're
40210Sstevel@tonic-gate  *	extracting.
40220Sstevel@tonic-gate  *
40230Sstevel@tonic-gate  *	NOTE:	though rather bulky, it is only called once per file
40240Sstevel@tonic-gate  *		extension, and it can withstand changes in the definition
40250Sstevel@tonic-gate  *		of the header structure.
40260Sstevel@tonic-gate  *
40270Sstevel@tonic-gate  *	WARNING:	this routine is local to xsfile() above
40280Sstevel@tonic-gate  */
40290Sstevel@tonic-gate 
40300Sstevel@tonic-gate static int
notsame(void)40310Sstevel@tonic-gate notsame(void)
40320Sstevel@tonic-gate {
40330Sstevel@tonic-gate 	return (
40340Sstevel@tonic-gate 	    (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
40350Sstevel@tonic-gate 	    (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
40360Sstevel@tonic-gate 	    (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
40370Sstevel@tonic-gate 	    (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
40380Sstevel@tonic-gate 	    (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
40390Sstevel@tonic-gate 	    (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
40400Sstevel@tonic-gate 	    (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
40410Sstevel@tonic-gate 	    (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
40420Sstevel@tonic-gate 	    (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
40430Sstevel@tonic-gate }
40440Sstevel@tonic-gate 
40450Sstevel@tonic-gate static void
dotable(char * argv[])40460Sstevel@tonic-gate dotable(char *argv[])
4047*12836Srich.burridge@oracle.com {
4048*12836Srich.burridge@oracle.com 	int tcnt = 0;			/* count # files tabled */
4049*12836Srich.burridge@oracle.com 	int fcnt = 0;			/* count # files in argv list */
40500Sstevel@tonic-gate 	char *namep, *dirp, *comp;
40510Sstevel@tonic-gate 	int want;
40520Sstevel@tonic-gate 	char aclchar = ' ';			/* either blank or '+' */
40530Sstevel@tonic-gate 	char templink[PATH_MAX+1];
40545331Samw 	attr_data_t *attrinfo = NULL;
40550Sstevel@tonic-gate 
40560Sstevel@tonic-gate 	dumping = 0;
40570Sstevel@tonic-gate 
40580Sstevel@tonic-gate 	/* if not on magtape, maximize seek speed */
40590Sstevel@tonic-gate 	if (NotTape && !bflag) {
40600Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
40610Sstevel@tonic-gate 		nblock = SYS_BLOCK / TBLOCK;
40620Sstevel@tonic-gate #else
40630Sstevel@tonic-gate 		nblock = 1;
40640Sstevel@tonic-gate #endif
40650Sstevel@tonic-gate 	}
40660Sstevel@tonic-gate 
40670Sstevel@tonic-gate 	for (;;) {
40680Sstevel@tonic-gate 
40690Sstevel@tonic-gate 		/* namep is set by wantit to point to the full name */
40705331Samw 		if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
40710Sstevel@tonic-gate 			continue;
40720Sstevel@tonic-gate 		if (want == -1)
40730Sstevel@tonic-gate 			break;
40740Sstevel@tonic-gate 		if (dblock.dbuf.typeflag != 'A')
40750Sstevel@tonic-gate 			++tcnt;
40760Sstevel@tonic-gate 
407712423Srich.burridge@oracle.com 		if (Fflag) {
407812423Srich.burridge@oracle.com 			if (checkf(namep, is_directory(namep), Fflag) == 0) {
407912423Srich.burridge@oracle.com 				passtape();
408012423Srich.burridge@oracle.com 				continue;
408112423Srich.burridge@oracle.com 			}
408212423Srich.burridge@oracle.com 		}
40830Sstevel@tonic-gate 		/*
40840Sstevel@tonic-gate 		 * ACL support:
40850Sstevel@tonic-gate 		 * aclchar is introduced to indicate if there are
40860Sstevel@tonic-gate 		 * acl entries. longt() now takes one extra argument.
40870Sstevel@tonic-gate 		 */
40880Sstevel@tonic-gate 		if (vflag) {
40890Sstevel@tonic-gate 			if (dblock.dbuf.typeflag == 'A') {
40900Sstevel@tonic-gate 				aclchar = '+';
40910Sstevel@tonic-gate 				passtape();
40920Sstevel@tonic-gate 				continue;
40930Sstevel@tonic-gate 			}
40940Sstevel@tonic-gate 			longt(&stbuf, aclchar);
40950Sstevel@tonic-gate 			aclchar = ' ';
40960Sstevel@tonic-gate 		}
40970Sstevel@tonic-gate 
40980Sstevel@tonic-gate 
40990Sstevel@tonic-gate #if defined(O_XATTR)
41005331Samw 		if (xattrp != NULL) {
41015331Samw 			int	issysattr;
41025331Samw 			char	*bn = basename(attrinfo->attr_path);
41035331Samw 
41045331Samw 			/*
41055331Samw 			 * We could use sysattr_type() to test whether or not
41065331Samw 			 * the attribute we are processing is really an
41075331Samw 			 * extended system attribute, which as of this writing
41085331Samw 			 * just does a strcmp(), however, sysattr_type() may
41095331Samw 			 * be changed to issue a pathconf() call instead, which
41105331Samw 			 * would require being changed into the parent attribute
41115331Samw 			 * directory.  So instead, just do simple string
41125331Samw 			 * comparisons to see if we are processing an extended
41135331Samw 			 * system attribute.
41145331Samw 			 */
41155331Samw 			issysattr = is_sysattr(bn);
41165331Samw 
41175331Samw 			(void) printf(gettext("%s %sattribute %s"),
41185331Samw 			    xattrp->h_names,
41195331Samw 			    issysattr ? gettext("system ") : "",
41205331Samw 			    attrinfo->attr_path);
41210Sstevel@tonic-gate 		} else {
41220Sstevel@tonic-gate 			(void) printf("%s", namep);
41230Sstevel@tonic-gate 		}
41240Sstevel@tonic-gate #else
41250Sstevel@tonic-gate 			(void) printf("%s", namep);
41260Sstevel@tonic-gate #endif
41270Sstevel@tonic-gate 
41280Sstevel@tonic-gate 		if (extno != 0) {
41290Sstevel@tonic-gate 			if (vflag) {
41300Sstevel@tonic-gate 				/* keep the '\n' for backwards compatibility */
41310Sstevel@tonic-gate 				(void) fprintf(vfile, gettext(
41320Sstevel@tonic-gate 				    "\n [extent #%d of %d]"), extno, extotal);
41330Sstevel@tonic-gate 			} else {
41340Sstevel@tonic-gate 				(void) fprintf(vfile, gettext(
41350Sstevel@tonic-gate 				    " [extent #%d of %d]"), extno, extotal);
41360Sstevel@tonic-gate 			}
41370Sstevel@tonic-gate 		}
41380Sstevel@tonic-gate 		if (xhdr_flgs & _X_LINKPATH) {
41390Sstevel@tonic-gate 			(void) strcpy(templink, Xtarhdr.x_linkpath);
41400Sstevel@tonic-gate 		} else {
41410Sstevel@tonic-gate #if defined(O_XATTR)
41425331Samw 			if (xattrp != NULL) {
41430Sstevel@tonic-gate 				(void) sprintf(templink,
41440Sstevel@tonic-gate 				    "file %.*s", NAMSIZ, xattrp->h_names);
41450Sstevel@tonic-gate 			} else {
41460Sstevel@tonic-gate 				(void) sprintf(templink, "%.*s", NAMSIZ,
41470Sstevel@tonic-gate 				    dblock.dbuf.linkname);
41480Sstevel@tonic-gate 			}
41490Sstevel@tonic-gate #else
41500Sstevel@tonic-gate 			(void) sprintf(templink, "%.*s", NAMSIZ,
41510Sstevel@tonic-gate 			    dblock.dbuf.linkname);
41520Sstevel@tonic-gate #endif
41530Sstevel@tonic-gate 			templink[NAMSIZ] = '\0';
41540Sstevel@tonic-gate 		}
41550Sstevel@tonic-gate 		if (dblock.dbuf.typeflag == '1') {
41560Sstevel@tonic-gate 			/*
41570Sstevel@tonic-gate 			 * TRANSLATION_NOTE
41580Sstevel@tonic-gate 			 *	Subject is omitted here.
41590Sstevel@tonic-gate 			 *	Translate this as if
41600Sstevel@tonic-gate 			 *		<subject> linked to %s
41610Sstevel@tonic-gate 			 */
41620Sstevel@tonic-gate #if defined(O_XATTR)
41635331Samw 			if (xattrp != NULL) {
41640Sstevel@tonic-gate 				(void) printf(
41650Sstevel@tonic-gate 				    gettext(" linked to attribute %s"),
41660Sstevel@tonic-gate 				    xattr_linkp->h_names +
41670Sstevel@tonic-gate 				    strlen(xattr_linkp->h_names) + 1);
41680Sstevel@tonic-gate 			} else {
41690Sstevel@tonic-gate 				(void) printf(
41700Sstevel@tonic-gate 				    gettext(" linked to %s"), templink);
41710Sstevel@tonic-gate 			}
41720Sstevel@tonic-gate #else
41730Sstevel@tonic-gate 				(void) printf(
41740Sstevel@tonic-gate 				    gettext(" linked to %s"), templink);
41750Sstevel@tonic-gate 
41760Sstevel@tonic-gate #endif
41770Sstevel@tonic-gate 		}
41780Sstevel@tonic-gate 		if (dblock.dbuf.typeflag == '2')
41790Sstevel@tonic-gate 			(void) printf(gettext(
41800Sstevel@tonic-gate 			/*
41810Sstevel@tonic-gate 			 * TRANSLATION_NOTE
41820Sstevel@tonic-gate 			 *	Subject is omitted here.
41830Sstevel@tonic-gate 			 *	Translate this as if
41840Sstevel@tonic-gate 			 *		<subject> symbolic link to %s
41850Sstevel@tonic-gate 			 */
41860Sstevel@tonic-gate 			" symbolic link to %s"), templink);
41870Sstevel@tonic-gate 		(void) printf("\n");
41880Sstevel@tonic-gate #if defined(O_XATTR)
41895331Samw 		if (xattrp != NULL) {
41900Sstevel@tonic-gate 			free(xattrhead);
41910Sstevel@tonic-gate 			xattrp = NULL;
41920Sstevel@tonic-gate 			xattrhead = NULL;
41930Sstevel@tonic-gate 		}
41940Sstevel@tonic-gate #endif
41950Sstevel@tonic-gate 		passtape();
41960Sstevel@tonic-gate 	}
41970Sstevel@tonic-gate 	/*
41980Sstevel@tonic-gate 	 * Check if the number of files tabled is different from the
41990Sstevel@tonic-gate 	 * number of files listed on the command line
42000Sstevel@tonic-gate 	 */
42010Sstevel@tonic-gate 	if (fcnt > tcnt) {
42020Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
42030Sstevel@tonic-gate 		    "tar: %d file(s) not found\n"), fcnt-tcnt);
42040Sstevel@tonic-gate 		Errflg = 1;
42050Sstevel@tonic-gate 	}
42060Sstevel@tonic-gate }
42070Sstevel@tonic-gate 
42080Sstevel@tonic-gate static void
putempty(blkcnt_t n)42090Sstevel@tonic-gate putempty(blkcnt_t n)
42100Sstevel@tonic-gate {
42110Sstevel@tonic-gate 	char buf[TBLOCK];
42120Sstevel@tonic-gate 	char *cp;
42130Sstevel@tonic-gate 
42140Sstevel@tonic-gate 	for (cp = buf; cp < &buf[TBLOCK]; )
42150Sstevel@tonic-gate 		*cp++ = '\0';
42160Sstevel@tonic-gate 	while (n-- > 0)
42170Sstevel@tonic-gate 		(void) writetbuf(buf, 1);
42180Sstevel@tonic-gate }
42190Sstevel@tonic-gate 
42200Sstevel@tonic-gate static	ushort_t	Ftype = S_IFMT;
42210Sstevel@tonic-gate 
42220Sstevel@tonic-gate static	void
verbose(struct stat * st,char aclchar)42230Sstevel@tonic-gate verbose(struct stat *st, char aclchar)
42240Sstevel@tonic-gate {
42250Sstevel@tonic-gate 	int i, j, temp;
42260Sstevel@tonic-gate 	mode_t mode;
42270Sstevel@tonic-gate 	char modestr[12];
42280Sstevel@tonic-gate 
42290Sstevel@tonic-gate 	for (i = 0; i < 11; i++)
42300Sstevel@tonic-gate 		modestr[i] = '-';
42310Sstevel@tonic-gate 	modestr[i] = '\0';
42320Sstevel@tonic-gate 
42330Sstevel@tonic-gate 	/* a '+' sign is printed if there is ACL */
42340Sstevel@tonic-gate 	modestr[i-1] = aclchar;
42350Sstevel@tonic-gate 
42360Sstevel@tonic-gate 	mode = st->st_mode;
42370Sstevel@tonic-gate 	for (i = 0; i < 3; i++) {
42380Sstevel@tonic-gate 		temp = (mode >> (6 - (i * 3)));
42390Sstevel@tonic-gate 		j = (i * 3) + 1;
42400Sstevel@tonic-gate 		if (S_IROTH & temp)
42410Sstevel@tonic-gate 			modestr[j] = 'r';
42420Sstevel@tonic-gate 		if (S_IWOTH & temp)
42430Sstevel@tonic-gate 			modestr[j + 1] = 'w';
42440Sstevel@tonic-gate 		if (S_IXOTH & temp)
42450Sstevel@tonic-gate 			modestr[j + 2] = 'x';
42460Sstevel@tonic-gate 	}
42470Sstevel@tonic-gate 	temp = st->st_mode & Ftype;
42480Sstevel@tonic-gate 	switch (temp) {
42490Sstevel@tonic-gate 	case (S_IFIFO):
42500Sstevel@tonic-gate 		modestr[0] = 'p';
42510Sstevel@tonic-gate 		break;
42520Sstevel@tonic-gate 	case (S_IFCHR):
42530Sstevel@tonic-gate 		modestr[0] = 'c';
42540Sstevel@tonic-gate 		break;
42550Sstevel@tonic-gate 	case (S_IFDIR):
42560Sstevel@tonic-gate 		modestr[0] = 'd';
42570Sstevel@tonic-gate 		break;
42580Sstevel@tonic-gate 	case (S_IFBLK):
42590Sstevel@tonic-gate 		modestr[0] = 'b';
42600Sstevel@tonic-gate 		break;
42610Sstevel@tonic-gate 	case (S_IFREG): /* was initialized to '-' */
42620Sstevel@tonic-gate 		break;
42630Sstevel@tonic-gate 	case (S_IFLNK):
42640Sstevel@tonic-gate 		modestr[0] = 'l';
42650Sstevel@tonic-gate 		break;
42660Sstevel@tonic-gate 	default:
42670Sstevel@tonic-gate 		/* This field may be zero in old archives. */
42680Sstevel@tonic-gate 		if (is_posix && dblock.dbuf.typeflag != '1') {
42690Sstevel@tonic-gate 			/*
42700Sstevel@tonic-gate 			 * For POSIX compliant archives, the mode field
42710Sstevel@tonic-gate 			 * consists of 12 bits, ie:  the file type bits
42720Sstevel@tonic-gate 			 * are not stored in dblock.dbuf.mode.
42730Sstevel@tonic-gate 			 * For files other than hard links, getdir() sets
42740Sstevel@tonic-gate 			 * the file type bits in the st_mode field of the
42750Sstevel@tonic-gate 			 * stat structure based upon dblock.dbuf.typeflag.
42760Sstevel@tonic-gate 			 */
42770Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
42780Sstevel@tonic-gate 			    "tar: impossible file type"));
42790Sstevel@tonic-gate 		}
42800Sstevel@tonic-gate 	}
42810Sstevel@tonic-gate 
42820Sstevel@tonic-gate 	if ((S_ISUID & Gen.g_mode) == S_ISUID)
42830Sstevel@tonic-gate 		modestr[3] = 's';
42840Sstevel@tonic-gate 	if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
42850Sstevel@tonic-gate 		modestr[9] = 't';
42860Sstevel@tonic-gate 	if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
42870Sstevel@tonic-gate 		modestr[6] = 's';
42880Sstevel@tonic-gate 	else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
42890Sstevel@tonic-gate 		modestr[6] = 'l';
42900Sstevel@tonic-gate 	(void) fprintf(vfile, "%s", modestr);
42910Sstevel@tonic-gate }
42920Sstevel@tonic-gate 
42930Sstevel@tonic-gate static void
longt(struct stat * st,char aclchar)42940Sstevel@tonic-gate longt(struct stat *st, char aclchar)
42950Sstevel@tonic-gate {
42960Sstevel@tonic-gate 	char fileDate[30];
42970Sstevel@tonic-gate 	struct tm *tm;
42980Sstevel@tonic-gate 
42990Sstevel@tonic-gate 	verbose(st, aclchar);
43000Sstevel@tonic-gate 	(void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
43010Sstevel@tonic-gate 
43020Sstevel@tonic-gate 	if (dblock.dbuf.typeflag == '2') {
43030Sstevel@tonic-gate 		if (xhdr_flgs & _X_LINKPATH)
43040Sstevel@tonic-gate 			st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
43050Sstevel@tonic-gate 		else
43060Sstevel@tonic-gate 			st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
43070Sstevel@tonic-gate 			    '\0', NAMSIZ) ?
43080Sstevel@tonic-gate 			    (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
43090Sstevel@tonic-gate 	}
43100Sstevel@tonic-gate 	(void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
43110Sstevel@tonic-gate 
43120Sstevel@tonic-gate 	tm = localtime(&(st->st_mtime));
43130Sstevel@tonic-gate 	(void) strftime(fileDate, sizeof (fileDate),
43140Sstevel@tonic-gate 	    dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
43150Sstevel@tonic-gate 	(void) fprintf(vfile, " %s ", fileDate);
43160Sstevel@tonic-gate }
43170Sstevel@tonic-gate 
43180Sstevel@tonic-gate 
43190Sstevel@tonic-gate /*
43200Sstevel@tonic-gate  *  checkdir - Attempt to ensure that the path represented in name
43210Sstevel@tonic-gate  *             exists, and return 1 if this is true and name itself is a
43220Sstevel@tonic-gate  *             directory.
43230Sstevel@tonic-gate  *             Return 0 if this path cannot be created or if name is not
43240Sstevel@tonic-gate  *             a directory.
43250Sstevel@tonic-gate  */
43260Sstevel@tonic-gate 
43270Sstevel@tonic-gate static int
checkdir(char * name)43280Sstevel@tonic-gate checkdir(char *name)
43290Sstevel@tonic-gate {
43300Sstevel@tonic-gate 	char lastChar;		   /* the last character in name */
43310Sstevel@tonic-gate 	char *cp;		   /* scratch pointer into name */
43320Sstevel@tonic-gate 	char *firstSlash = NULL;   /* first slash in name */
43330Sstevel@tonic-gate 	char *lastSlash = NULL;	   /* last slash in name */
43340Sstevel@tonic-gate 	int  nameLen;		   /* length of name */
43350Sstevel@tonic-gate 	int  trailingSlash;	   /* true if name ends in slash */
43360Sstevel@tonic-gate 	int  leadingSlash;	   /* true if name begins with slash */
43370Sstevel@tonic-gate 	int  markedDir;		   /* true if name denotes a directory */
43380Sstevel@tonic-gate 	int  success;		   /* status of makeDir call */
43390Sstevel@tonic-gate 
43400Sstevel@tonic-gate 
43410Sstevel@tonic-gate 	/*
43420Sstevel@tonic-gate 	 *  Scan through the name, and locate first and last slashes.
43430Sstevel@tonic-gate 	 */
43440Sstevel@tonic-gate 
43450Sstevel@tonic-gate 	for (cp = name; *cp; cp++) {
43460Sstevel@tonic-gate 		if (*cp == '/') {
43470Sstevel@tonic-gate 			if (! firstSlash) {
43480Sstevel@tonic-gate 				firstSlash = cp;
43490Sstevel@tonic-gate 			}
43500Sstevel@tonic-gate 			lastSlash = cp;
43510Sstevel@tonic-gate 		}
43520Sstevel@tonic-gate 	}
43530Sstevel@tonic-gate 
43540Sstevel@tonic-gate 	/*
43550Sstevel@tonic-gate 	 *  Determine what you can from the proceeds of the scan.
43560Sstevel@tonic-gate 	 */
43570Sstevel@tonic-gate 
43580Sstevel@tonic-gate 	lastChar	= *(cp - 1);
43590Sstevel@tonic-gate 	nameLen		= (int)(cp - name);
43600Sstevel@tonic-gate 	trailingSlash	= (lastChar == '/');
43610Sstevel@tonic-gate 	leadingSlash	= (*name == '/');
43620Sstevel@tonic-gate 	markedDir	= (dblock.dbuf.typeflag == '5' || trailingSlash);
43630Sstevel@tonic-gate 
43640Sstevel@tonic-gate 	if (! lastSlash && ! markedDir) {
43650Sstevel@tonic-gate 		/*
43660Sstevel@tonic-gate 		 *  The named file does not have any subdrectory
43670Sstevel@tonic-gate 		 *  structure; just bail out.
43680Sstevel@tonic-gate 		 */
43690Sstevel@tonic-gate 
43700Sstevel@tonic-gate 		return (0);
43710Sstevel@tonic-gate 	}
43720Sstevel@tonic-gate 
43730Sstevel@tonic-gate 	/*
43740Sstevel@tonic-gate 	 *  Make sure that name doesn`t end with slash for the loop.
43750Sstevel@tonic-gate 	 *  This ensures that the makeDir attempt after the loop is
43760Sstevel@tonic-gate 	 *  meaningful.
43770Sstevel@tonic-gate 	 */
43780Sstevel@tonic-gate 
43790Sstevel@tonic-gate 	if (trailingSlash) {
43800Sstevel@tonic-gate 		name[nameLen-1] = '\0';
43810Sstevel@tonic-gate 	}
43820Sstevel@tonic-gate 
43830Sstevel@tonic-gate 	/*
43840Sstevel@tonic-gate 	 *  Make the path one component at a time.
43850Sstevel@tonic-gate 	 */
43860Sstevel@tonic-gate 
43870Sstevel@tonic-gate 	for (cp = strchr(leadingSlash ? name+1 : name, '/');
43880Sstevel@tonic-gate 	    cp;
43890Sstevel@tonic-gate 	    cp = strchr(cp+1, '/')) {
43900Sstevel@tonic-gate 		*cp = '\0';
43910Sstevel@tonic-gate 		success = makeDir(name);
43920Sstevel@tonic-gate 		*cp = '/';
43930Sstevel@tonic-gate 
43940Sstevel@tonic-gate 		if (!success) {
43950Sstevel@tonic-gate 			name[nameLen-1] = lastChar;
43960Sstevel@tonic-gate 			return (0);
43970Sstevel@tonic-gate 		}
43980Sstevel@tonic-gate 	}
43990Sstevel@tonic-gate 
44000Sstevel@tonic-gate 	/*
44010Sstevel@tonic-gate 	 *  This makes the last component of the name, if it is a
44020Sstevel@tonic-gate 	 *  directory.
44030Sstevel@tonic-gate 	 */
44040Sstevel@tonic-gate 
44050Sstevel@tonic-gate 	if (markedDir) {
44060Sstevel@tonic-gate 		if (! makeDir(name)) {
44070Sstevel@tonic-gate 			name[nameLen-1] = lastChar;
44080Sstevel@tonic-gate 			return (0);
44090Sstevel@tonic-gate 		}
44100Sstevel@tonic-gate 	}
44110Sstevel@tonic-gate 
44120Sstevel@tonic-gate 	name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
44130Sstevel@tonic-gate 	return (markedDir);
44140Sstevel@tonic-gate }
44150Sstevel@tonic-gate 
44160Sstevel@tonic-gate /*
44170Sstevel@tonic-gate  * resugname - Restore the user name and group name.  Search the NIS
44180Sstevel@tonic-gate  *             before using the uid and gid.
44190Sstevel@tonic-gate  *             (It is presumed that an archive entry cannot be
44200Sstevel@tonic-gate  *	       simultaneously a symlink and some other type.)
44210Sstevel@tonic-gate  */
44220Sstevel@tonic-gate 
44230Sstevel@tonic-gate static void
resugname(int dirfd,char * name,int symflag)44240Sstevel@tonic-gate resugname(int dirfd, 	/* dir fd file resides in */
44250Sstevel@tonic-gate 	char *name,	/* name of the file to be modified */
44260Sstevel@tonic-gate 	int symflag)	/* true if file is a symbolic link */
44270Sstevel@tonic-gate {
44280Sstevel@tonic-gate 	uid_t duid;
44290Sstevel@tonic-gate 	gid_t dgid;
44300Sstevel@tonic-gate 	struct stat *sp = &stbuf;
44310Sstevel@tonic-gate 	char	*u_g_name;
44320Sstevel@tonic-gate 
44330Sstevel@tonic-gate 	if (checkflag == 1) { /* Extended tar format and euid == 0 */
44340Sstevel@tonic-gate 
44350Sstevel@tonic-gate 		/*
44360Sstevel@tonic-gate 		 * Try and extract the intended uid and gid from the name
44370Sstevel@tonic-gate 		 * service before believing the uid and gid in the header.
44380Sstevel@tonic-gate 		 *
44390Sstevel@tonic-gate 		 * In the case where we archived a setuid or setgid file
44400Sstevel@tonic-gate 		 * owned by someone with a large uid, then it will
44410Sstevel@tonic-gate 		 * have made it into the archive with a uid of nobody.  If
44420Sstevel@tonic-gate 		 * the corresponding username doesn't appear to exist, then we
44430Sstevel@tonic-gate 		 * want to make sure it *doesn't* end up as setuid nobody!
44440Sstevel@tonic-gate 		 *
44450Sstevel@tonic-gate 		 * Our caller will print an error message about the fact
44460Sstevel@tonic-gate 		 * that the restore didn't work out quite right ..
44470Sstevel@tonic-gate 		 */
44480Sstevel@tonic-gate 		if (xhdr_flgs & _X_UNAME)
44490Sstevel@tonic-gate 			u_g_name = Xtarhdr.x_uname;
44500Sstevel@tonic-gate 		else
44510Sstevel@tonic-gate 			u_g_name = dblock.dbuf.uname;
44520Sstevel@tonic-gate 		if ((duid = getuidbyname(u_g_name)) == -1) {
44530Sstevel@tonic-gate 			if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
44540Sstevel@tonic-gate 			    (sp->st_mode & S_ISUID) == S_ISUID)
44550Sstevel@tonic-gate 				(void) chmod(name,
44561266Sceastha 				    MODEMASK & sp->st_mode & ~S_ISUID);
44570Sstevel@tonic-gate 			duid = sp->st_uid;
44580Sstevel@tonic-gate 		}
44590Sstevel@tonic-gate 
44600Sstevel@tonic-gate 		/* (Ditto for gids) */
44610Sstevel@tonic-gate 
44620Sstevel@tonic-gate 		if (xhdr_flgs & _X_GNAME)
44630Sstevel@tonic-gate 			u_g_name = Xtarhdr.x_gname;
44640Sstevel@tonic-gate 		else
44650Sstevel@tonic-gate 			u_g_name = dblock.dbuf.gname;
44660Sstevel@tonic-gate 		if ((dgid = getgidbyname(u_g_name)) == -1) {
44670Sstevel@tonic-gate 			if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
44680Sstevel@tonic-gate 			    (sp->st_mode & S_ISGID) == S_ISGID)
44690Sstevel@tonic-gate 				(void) chmod(name,
44701266Sceastha 				    MODEMASK & sp->st_mode & ~S_ISGID);
44710Sstevel@tonic-gate 			dgid = sp->st_gid;
44720Sstevel@tonic-gate 		}
44730Sstevel@tonic-gate 	} else if (checkflag == 2) { /* tar format and euid == 0 */
44740Sstevel@tonic-gate 		duid = sp->st_uid;
44750Sstevel@tonic-gate 		dgid = sp->st_gid;
44760Sstevel@tonic-gate 	}
44770Sstevel@tonic-gate 	if ((checkflag == 1) || (checkflag == 2))
44780Sstevel@tonic-gate 		(void) fchownat(dirfd, name, duid, dgid, symflag);
44790Sstevel@tonic-gate }
44800Sstevel@tonic-gate 
44810Sstevel@tonic-gate /*ARGSUSED*/
44820Sstevel@tonic-gate static void
onintr(int sig)44830Sstevel@tonic-gate onintr(int sig)
44840Sstevel@tonic-gate {
44850Sstevel@tonic-gate 	(void) signal(SIGINT, SIG_IGN);
44860Sstevel@tonic-gate 	term++;
44870Sstevel@tonic-gate }
44880Sstevel@tonic-gate 
44890Sstevel@tonic-gate /*ARGSUSED*/
44900Sstevel@tonic-gate static void
onquit(int sig)44910Sstevel@tonic-gate onquit(int sig)
44920Sstevel@tonic-gate {
44930Sstevel@tonic-gate 	(void) signal(SIGQUIT, SIG_IGN);
44940Sstevel@tonic-gate 	term++;
44950Sstevel@tonic-gate }
44960Sstevel@tonic-gate 
44970Sstevel@tonic-gate /*ARGSUSED*/
44980Sstevel@tonic-gate static void
onhup(int sig)44990Sstevel@tonic-gate onhup(int sig)
45000Sstevel@tonic-gate {
45010Sstevel@tonic-gate 	(void) signal(SIGHUP, SIG_IGN);
45020Sstevel@tonic-gate 	term++;
45030Sstevel@tonic-gate }
45040Sstevel@tonic-gate 
45050Sstevel@tonic-gate static void
tomodes(struct stat * sp)45060Sstevel@tonic-gate tomodes(struct stat *sp)
45070Sstevel@tonic-gate {
45080Sstevel@tonic-gate 	uid_t uid;
45090Sstevel@tonic-gate 	gid_t gid;
45100Sstevel@tonic-gate 
45110Sstevel@tonic-gate 	bzero(dblock.dummy, TBLOCK);
45120Sstevel@tonic-gate 
45130Sstevel@tonic-gate 	/*
45140Sstevel@tonic-gate 	 * If the uid or gid is too large, we can't put it into
45150Sstevel@tonic-gate 	 * the archive.  We could fail to put anything in the
45160Sstevel@tonic-gate 	 * archive at all .. but most of the time the name service
45170Sstevel@tonic-gate 	 * will save the day when we do a lookup at restore time.
45180Sstevel@tonic-gate 	 *
45190Sstevel@tonic-gate 	 * Instead we choose a "safe" uid and gid, and fix up whether
45200Sstevel@tonic-gate 	 * or not the setuid and setgid bits are left set to extraction
45210Sstevel@tonic-gate 	 * time.
45220Sstevel@tonic-gate 	 */
45230Sstevel@tonic-gate 	if (Eflag) {
45240Sstevel@tonic-gate 		if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
45250Sstevel@tonic-gate 			xhdr_flgs |= _X_UID;
45260Sstevel@tonic-gate 			Xtarhdr.x_uid = uid;
45270Sstevel@tonic-gate 		}
45280Sstevel@tonic-gate 		if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
45290Sstevel@tonic-gate 			xhdr_flgs |= _X_GID;
45300Sstevel@tonic-gate 			Xtarhdr.x_gid = gid;
45310Sstevel@tonic-gate 		}
45320Sstevel@tonic-gate 		if (sp->st_size > TAR_OFFSET_MAX) {
45330Sstevel@tonic-gate 			xhdr_flgs |= _X_SIZE;
45340Sstevel@tonic-gate 			Xtarhdr.x_filesz = sp->st_size;
45350Sstevel@tonic-gate 			(void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
45360Sstevel@tonic-gate 			    (off_t)0);
45370Sstevel@tonic-gate 		} else
45380Sstevel@tonic-gate 			(void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
45390Sstevel@tonic-gate 			    sp->st_size);
45400Sstevel@tonic-gate 	} else {
45410Sstevel@tonic-gate 		(void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
45420Sstevel@tonic-gate 		    sp->st_size);
45430Sstevel@tonic-gate 	}
45440Sstevel@tonic-gate 	if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
45450Sstevel@tonic-gate 		uid = UID_NOBODY;
45460Sstevel@tonic-gate 	if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
45470Sstevel@tonic-gate 		gid = GID_NOBODY;
45480Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.gid, "%07lo", gid);
45490Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.uid, "%07lo", uid);
45500Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
45510Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
45520Sstevel@tonic-gate }
45530Sstevel@tonic-gate 
45540Sstevel@tonic-gate static	int
45550Sstevel@tonic-gate #ifdef	EUC
45560Sstevel@tonic-gate /*
45570Sstevel@tonic-gate  * Warning:  the result of this function depends whether 'char' is a
45580Sstevel@tonic-gate  * signed or unsigned data type.  This a source of potential
45590Sstevel@tonic-gate  * non-portability among heterogeneous systems.  It is retained here
45600Sstevel@tonic-gate  * for backward compatibility.
45610Sstevel@tonic-gate  */
checksum_signed(union hblock * dblockp)45620Sstevel@tonic-gate checksum_signed(union hblock *dblockp)
45630Sstevel@tonic-gate #else
45640Sstevel@tonic-gate checksum(union hblock *dblockp)
45650Sstevel@tonic-gate #endif	/* EUC */
45660Sstevel@tonic-gate {
45670Sstevel@tonic-gate 	int i;
45680Sstevel@tonic-gate 	char *cp;
45690Sstevel@tonic-gate 
45700Sstevel@tonic-gate 	for (cp = dblockp->dbuf.chksum;
45710Sstevel@tonic-gate 	    cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
45720Sstevel@tonic-gate 		*cp = ' ';
45730Sstevel@tonic-gate 	i = 0;
45740Sstevel@tonic-gate 	for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
45750Sstevel@tonic-gate 		i += *cp;
45760Sstevel@tonic-gate 	return (i);
45770Sstevel@tonic-gate }
45780Sstevel@tonic-gate 
45790Sstevel@tonic-gate #ifdef	EUC
45800Sstevel@tonic-gate /*
45810Sstevel@tonic-gate  * Generate unsigned checksum, regardless of what C compiler is
45820Sstevel@tonic-gate  * used.  Survives in the face of arbitrary 8-bit clean filenames,
45830Sstevel@tonic-gate  * e.g., internationalized filenames.
45840Sstevel@tonic-gate  */
45850Sstevel@tonic-gate static int
checksum(union hblock * dblockp)45860Sstevel@tonic-gate checksum(union hblock *dblockp)
45870Sstevel@tonic-gate {
45880Sstevel@tonic-gate 	unsigned i;
45890Sstevel@tonic-gate 	unsigned char *cp;
45900Sstevel@tonic-gate 
45910Sstevel@tonic-gate 	for (cp = (unsigned char *) dblockp->dbuf.chksum;
45920Sstevel@tonic-gate 	    cp < (unsigned char *)
45930Sstevel@tonic-gate 	    &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
45940Sstevel@tonic-gate 		*cp = ' ';
45950Sstevel@tonic-gate 	i = 0;
45960Sstevel@tonic-gate 	for (cp = (unsigned char *) dblockp->dummy;
45970Sstevel@tonic-gate 	    cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
45980Sstevel@tonic-gate 		i += *cp;
45990Sstevel@tonic-gate 
46000Sstevel@tonic-gate 	return (i);
46010Sstevel@tonic-gate }
46020Sstevel@tonic-gate #endif	/* EUC */
46030Sstevel@tonic-gate 
46040Sstevel@tonic-gate /*
46050Sstevel@tonic-gate  * If the w flag is set, output the action to be taken and the name of the
46060Sstevel@tonic-gate  * file.  Perform the action if the user response is affirmative.
46070Sstevel@tonic-gate  */
46080Sstevel@tonic-gate 
46090Sstevel@tonic-gate static int
checkw(char c,char * name)46100Sstevel@tonic-gate checkw(char c, char *name)
46110Sstevel@tonic-gate {
46120Sstevel@tonic-gate 	if (wflag) {
46130Sstevel@tonic-gate 		(void) fprintf(vfile, "%c ", c);
46140Sstevel@tonic-gate 		if (vflag)
46150Sstevel@tonic-gate 			longt(&stbuf, ' ');	/* do we have acl info here */
46160Sstevel@tonic-gate 		(void) fprintf(vfile, "%s: ", name);
46174774Sas145665 		if (yes() == 1) {
46180Sstevel@tonic-gate 			return (1);
46190Sstevel@tonic-gate 		}
46200Sstevel@tonic-gate 		return (0);
46210Sstevel@tonic-gate 	}
46220Sstevel@tonic-gate 	return (1);
46230Sstevel@tonic-gate }
46240Sstevel@tonic-gate 
46250Sstevel@tonic-gate /*
462612423Srich.burridge@oracle.com  * When the F flag is set, exclude RCS and SCCS directories (and any files
462712423Srich.burridge@oracle.com  * or directories under them).  If F is set twice, also exclude .o files,
462812423Srich.burridge@oracle.com  * and files names errs, core, and a.out.
462912423Srich.burridge@oracle.com  *
463012423Srich.burridge@oracle.com  * Return 0 if file should be excluded, 1 otherwise.
46310Sstevel@tonic-gate  */
46320Sstevel@tonic-gate 
46330Sstevel@tonic-gate static int
checkf(char * longname,int is_dir,int howmuch)463412423Srich.burridge@oracle.com checkf(char *longname, int is_dir, int howmuch)
463512423Srich.burridge@oracle.com {
463612423Srich.burridge@oracle.com 	static char fullname[PATH_MAX + 1];
463712423Srich.burridge@oracle.com 	char *dir, *name;
463812423Srich.burridge@oracle.com 
463912423Srich.burridge@oracle.com #if defined(O_XATTR)
464012423Srich.burridge@oracle.com 	/*
464112423Srich.burridge@oracle.com 	 * If there is an xattr_buf structure associated with this file,
464212423Srich.burridge@oracle.com 	 * always return 1.
464312423Srich.burridge@oracle.com 	 */
464412423Srich.burridge@oracle.com 	if (xattrp) {
464512423Srich.burridge@oracle.com 		return (1);
464612423Srich.burridge@oracle.com 	}
464712423Srich.burridge@oracle.com #endif
464812423Srich.burridge@oracle.com 
464912423Srich.burridge@oracle.com 	/*
465012423Srich.burridge@oracle.com 	 * First check to see if the base name is an RCS or SCCS directory.
465112423Srich.burridge@oracle.com 	 */
465212423Srich.burridge@oracle.com 	if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
465312423Srich.burridge@oracle.com 		return (1);
465412423Srich.burridge@oracle.com 
465512423Srich.burridge@oracle.com 	name = basename(fullname);
465612423Srich.burridge@oracle.com 	if (is_dir) {
46570Sstevel@tonic-gate 		if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
46580Sstevel@tonic-gate 			return (0);
465912423Srich.burridge@oracle.com 	}
466012423Srich.burridge@oracle.com 
466112423Srich.burridge@oracle.com 	/*
466212423Srich.burridge@oracle.com 	 * If two -F command line options were given then exclude .o files,
466312423Srich.burridge@oracle.com 	 * and files named errs, core, and a.out.
466412423Srich.burridge@oracle.com 	 */
466512423Srich.burridge@oracle.com 	if (howmuch > 1 && !is_dir) {
466612423Srich.burridge@oracle.com 		size_t l = strlen(name);
466712423Srich.burridge@oracle.com 
466812423Srich.burridge@oracle.com 		if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
466912423Srich.burridge@oracle.com 			return (0);
46700Sstevel@tonic-gate 		if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
46710Sstevel@tonic-gate 		    strcmp(name, "a.out") == 0)
46720Sstevel@tonic-gate 			return (0);
46730Sstevel@tonic-gate 	}
46740Sstevel@tonic-gate 
467512423Srich.burridge@oracle.com 	/*
467612423Srich.burridge@oracle.com 	 * At this point, check to see if this file has a parent directory
467712423Srich.burridge@oracle.com 	 * named RCS or SCCS.  If so, then this file should be excluded too.
467812423Srich.burridge@oracle.com 	 * The strcpy() operation is done again, because basename(3C) may
467912423Srich.burridge@oracle.com 	 * modify the path string passed to it.
468012423Srich.burridge@oracle.com 	 */
468112423Srich.burridge@oracle.com 	if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
468212423Srich.burridge@oracle.com 		return (1);
468312423Srich.burridge@oracle.com 
468412423Srich.burridge@oracle.com 	dir = dirname(fullname);
468512423Srich.burridge@oracle.com 	while (strcmp(dir, ".") != 0) {
468612423Srich.burridge@oracle.com 		name = basename(dir);
468712423Srich.burridge@oracle.com 		if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
468812423Srich.burridge@oracle.com 			return (0);
468912423Srich.burridge@oracle.com 		dir = dirname(dir);
469012423Srich.burridge@oracle.com 	}
469112423Srich.burridge@oracle.com 
46920Sstevel@tonic-gate 	return (1);
46930Sstevel@tonic-gate }
46940Sstevel@tonic-gate 
46950Sstevel@tonic-gate static int
response(void)46960Sstevel@tonic-gate response(void)
46970Sstevel@tonic-gate {
46980Sstevel@tonic-gate 	int c;
46990Sstevel@tonic-gate 
47000Sstevel@tonic-gate 	c = getchar();
47010Sstevel@tonic-gate 	if (c != '\n')
47021266Sceastha 		while (getchar() != '\n')
47031266Sceastha 			;
47040Sstevel@tonic-gate 	else c = 'n';
47050Sstevel@tonic-gate 	return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
47060Sstevel@tonic-gate }
47070Sstevel@tonic-gate 
47080Sstevel@tonic-gate /* Has file been modified since being put into archive? If so, return > 0. */
47090Sstevel@tonic-gate 
47109694SScott.Rotondo@Sun.COM static off_t	lookup(char *);
47119694SScott.Rotondo@Sun.COM 
47120Sstevel@tonic-gate static int
checkupdate(char * arg)47130Sstevel@tonic-gate checkupdate(char *arg)
47140Sstevel@tonic-gate {
47150Sstevel@tonic-gate 	char name[PATH_MAX+1];
47160Sstevel@tonic-gate 	time_t	mtime;
47170Sstevel@tonic-gate 	long nsecs;
47180Sstevel@tonic-gate 	off_t seekp;
47190Sstevel@tonic-gate 
47200Sstevel@tonic-gate 	rewind(tfile);
47210Sstevel@tonic-gate 	if ((seekp = lookup(arg)) < 0)
47220Sstevel@tonic-gate 		return (1);
47230Sstevel@tonic-gate 	(void) fseek(tfile, seekp, 0);
47240Sstevel@tonic-gate 	(void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
47250Sstevel@tonic-gate 
47260Sstevel@tonic-gate 	/*
47270Sstevel@tonic-gate 	 * Unless nanoseconds were stored in the file, only use seconds for
47280Sstevel@tonic-gate 	 * comparison of time.  Nanoseconds are stored when -E is specified.
47290Sstevel@tonic-gate 	 */
47300Sstevel@tonic-gate 	if (Eflag == 0)
47310Sstevel@tonic-gate 		return (stbuf.st_mtime > mtime);
47320Sstevel@tonic-gate 
47330Sstevel@tonic-gate 	if ((stbuf.st_mtime < mtime) ||
47340Sstevel@tonic-gate 	    ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
47350Sstevel@tonic-gate 		return (0);
47360Sstevel@tonic-gate 	return (1);
47370Sstevel@tonic-gate }
47380Sstevel@tonic-gate 
47390Sstevel@tonic-gate 
47400Sstevel@tonic-gate /*
47410Sstevel@tonic-gate  *	newvol	get new floppy (or tape) volume
47420Sstevel@tonic-gate  *
47430Sstevel@tonic-gate  *	newvol();		resets tapepos and first to TRUE, prompts for
47440Sstevel@tonic-gate  *				for new volume, and waits.
47450Sstevel@tonic-gate  *	if dumping, end-of-file is written onto the tape.
47460Sstevel@tonic-gate  */
47470Sstevel@tonic-gate 
47480Sstevel@tonic-gate static void
newvol(void)47490Sstevel@tonic-gate newvol(void)
47500Sstevel@tonic-gate {
47510Sstevel@tonic-gate 	int c;
47520Sstevel@tonic-gate 
47530Sstevel@tonic-gate 	if (dumping) {
47540Sstevel@tonic-gate #ifdef DEBUG
47550Sstevel@tonic-gate 		DEBUG("newvol called with 'dumping' set\n", 0, 0);
47560Sstevel@tonic-gate #endif
47570Sstevel@tonic-gate 		putempty((blkcnt_t)2);	/* 2 EOT marks */
47580Sstevel@tonic-gate 		closevol();
47590Sstevel@tonic-gate 		flushtape();
47600Sstevel@tonic-gate 		sync();
47610Sstevel@tonic-gate 		tapepos = 0;
47620Sstevel@tonic-gate 	} else
47630Sstevel@tonic-gate 		first = TRUE;
47640Sstevel@tonic-gate 	if (close(mt) != 0)
47650Sstevel@tonic-gate 		vperror(2, gettext("close error"));
47660Sstevel@tonic-gate 	mt = 0;
47670Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
47680Sstevel@tonic-gate 	    "tar: \007please insert new volume, then press RETURN."));
47690Sstevel@tonic-gate 	(void) fseek(stdin, (off_t)0, 2);	/* scan over read-ahead */
47700Sstevel@tonic-gate 	while ((c = getchar()) != '\n' && ! term)
47710Sstevel@tonic-gate 		if (c == EOF)
47720Sstevel@tonic-gate 			done(Errflg);
47730Sstevel@tonic-gate 	if (term)
47740Sstevel@tonic-gate 		done(Errflg);
47750Sstevel@tonic-gate 
47760Sstevel@tonic-gate 	errno = 0;
47770Sstevel@tonic-gate 
47780Sstevel@tonic-gate 	if (strcmp(usefile, "-") == 0) {
47790Sstevel@tonic-gate 		mt = dup(1);
47800Sstevel@tonic-gate 	} else {
47810Sstevel@tonic-gate 		mt = open(usefile, dumping ? update : 0);
47820Sstevel@tonic-gate 	}
47830Sstevel@tonic-gate 
47840Sstevel@tonic-gate 	if (mt < 0) {
47850Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
47860Sstevel@tonic-gate 		    "tar: cannot reopen %s (%s)\n"),
47870Sstevel@tonic-gate 		    dumping ? gettext("output") : gettext("input"), usefile);
47880Sstevel@tonic-gate 
478912305Srich.burridge@sun.com #ifdef DEBUG
479012305Srich.burridge@sun.com 		DEBUG("update=%d, usefile=%s ", update, usefile);
479112305Srich.burridge@sun.com 		DEBUG("mt=%d, [%s]\n", mt, strerror(errno));
479212305Srich.burridge@sun.com #endif
47930Sstevel@tonic-gate 
47940Sstevel@tonic-gate 		done(2);
47950Sstevel@tonic-gate 	}
47960Sstevel@tonic-gate }
47970Sstevel@tonic-gate 
47980Sstevel@tonic-gate /*
47990Sstevel@tonic-gate  * Write a trailer portion to close out the current output volume.
48000Sstevel@tonic-gate  */
48010Sstevel@tonic-gate 
48020Sstevel@tonic-gate static void
closevol(void)48030Sstevel@tonic-gate closevol(void)
48040Sstevel@tonic-gate {
48050Sstevel@tonic-gate 	if (mulvol) {
48060Sstevel@tonic-gate 		/*
48070Sstevel@tonic-gate 		 * blocklim does not count the 2 EOT marks;
48080Sstevel@tonic-gate 		 * tapepos  does count the 2 EOT marks;
48090Sstevel@tonic-gate 		 * therefore we need the +2 below.
48100Sstevel@tonic-gate 		 */
48110Sstevel@tonic-gate 		putempty(blocklim + (blkcnt_t)2 - tapepos);
48120Sstevel@tonic-gate 	}
48130Sstevel@tonic-gate }
48140Sstevel@tonic-gate 
48150Sstevel@tonic-gate static void
done(int n)48160Sstevel@tonic-gate done(int n)
48170Sstevel@tonic-gate {
481812476Srich.burridge@oracle.com 	/*
481912476Srich.burridge@oracle.com 	 * If we were terminated in some way, and we would otherwise have
482012476Srich.burridge@oracle.com 	 * exited with a value of 0, adjust to 1, so that external callers
482112476Srich.burridge@oracle.com 	 * can determine this by looking at the exit status.
482212476Srich.burridge@oracle.com 	 */
482312476Srich.burridge@oracle.com 	if (term && n == 0)
482412476Srich.burridge@oracle.com 		n = 1;
482512476Srich.burridge@oracle.com 
482612275Srich.burridge@sun.com 	if (tfile != NULL)
482712275Srich.burridge@sun.com 		(void) unlink(tname);
482811990Srich.burridge@sun.com 	if (compress_opt != NULL)
482911990Srich.burridge@sun.com 		(void) free(compress_opt);
48300Sstevel@tonic-gate 	if (mt > 0) {
48310Sstevel@tonic-gate 		if ((close(mt) != 0) || (fclose(stdout) != 0)) {
48320Sstevel@tonic-gate 			perror(gettext("tar: close error"));
48330Sstevel@tonic-gate 			exit(2);
48340Sstevel@tonic-gate 		}
48350Sstevel@tonic-gate 	}
48360Sstevel@tonic-gate 	exit(n);
48370Sstevel@tonic-gate }
48380Sstevel@tonic-gate 
48390Sstevel@tonic-gate /*
48400Sstevel@tonic-gate  * Determine if s1 is a prefix portion of s2 (or the same as s2).
48410Sstevel@tonic-gate  */
48420Sstevel@tonic-gate 
48430Sstevel@tonic-gate static	int
is_prefix(char * s1,char * s2)48440Sstevel@tonic-gate is_prefix(char *s1, char *s2)
48450Sstevel@tonic-gate {
48460Sstevel@tonic-gate 	while (*s1)
48470Sstevel@tonic-gate 		if (*s1++ != *s2++)
48480Sstevel@tonic-gate 			return (0);
48490Sstevel@tonic-gate 	if (*s2)
48500Sstevel@tonic-gate 		return (*s2 == '/');
48510Sstevel@tonic-gate 	return (1);
48520Sstevel@tonic-gate }
48530Sstevel@tonic-gate 
48540Sstevel@tonic-gate /*
48550Sstevel@tonic-gate  * lookup and bsrch look through tfile entries to find a match for a name.
48560Sstevel@tonic-gate  * The name can be up to PATH_MAX bytes.  bsrch compares what it sees between
48570Sstevel@tonic-gate  * a pair of newline chars, so the buffer it uses must be long enough for
48580Sstevel@tonic-gate  * two lines:  name and modification time as well as period, newline and space.
48590Sstevel@tonic-gate  *
48600Sstevel@tonic-gate  * A kludge was added to bsrch to take care of matching on the first entry
48610Sstevel@tonic-gate  * in the file--there is no leading newline.  So, if we are reading from the
48620Sstevel@tonic-gate  * start of the file, read into byte two and set the first byte to a newline.
48630Sstevel@tonic-gate  * Otherwise, the first entry cannot be matched.
48640Sstevel@tonic-gate  *
48650Sstevel@tonic-gate  */
48660Sstevel@tonic-gate 
48670Sstevel@tonic-gate #define	N	(2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
48680Sstevel@tonic-gate static	off_t
lookup(char * s)48690Sstevel@tonic-gate lookup(char *s)
48700Sstevel@tonic-gate {
48710Sstevel@tonic-gate 	int i;
48720Sstevel@tonic-gate 	off_t a;
48730Sstevel@tonic-gate 
48740Sstevel@tonic-gate 	for (i = 0; s[i]; i++)
48750Sstevel@tonic-gate 		if (s[i] == ' ')
48760Sstevel@tonic-gate 			break;
48770Sstevel@tonic-gate 	a = bsrch(s, i, low, high);
48780Sstevel@tonic-gate 	return (a);
48790Sstevel@tonic-gate }
48800Sstevel@tonic-gate 
48810Sstevel@tonic-gate static off_t
bsrch(char * s,int n,off_t l,off_t h)48820Sstevel@tonic-gate bsrch(char *s, int n, off_t l, off_t h)
48830Sstevel@tonic-gate {
48840Sstevel@tonic-gate 	int i, j;
48850Sstevel@tonic-gate 	char b[N];
48860Sstevel@tonic-gate 	off_t m, m1;
48870Sstevel@tonic-gate 
48880Sstevel@tonic-gate 
48890Sstevel@tonic-gate loop:
48900Sstevel@tonic-gate 	if (l >= h)
48910Sstevel@tonic-gate 		return ((off_t)-1);
48920Sstevel@tonic-gate 	m = l + (h-l)/2 - N/2;
48930Sstevel@tonic-gate 	if (m < l)
48940Sstevel@tonic-gate 		m = l;
48950Sstevel@tonic-gate 	(void) fseek(tfile, m, 0);
48960Sstevel@tonic-gate 	if (m == 0) {
48970Sstevel@tonic-gate 		(void) fread(b+1, 1, N-1, tfile);
48980Sstevel@tonic-gate 		b[0] = '\n';
48990Sstevel@tonic-gate 		m--;
49000Sstevel@tonic-gate 	} else
49010Sstevel@tonic-gate 		(void) fread(b, 1, N, tfile);
49020Sstevel@tonic-gate 	for (i = 0; i < N; i++) {
49030Sstevel@tonic-gate 		if (b[i] == '\n')
49040Sstevel@tonic-gate 			break;
49050Sstevel@tonic-gate 		m++;
49060Sstevel@tonic-gate 	}
49070Sstevel@tonic-gate 	if (m >= h)
49080Sstevel@tonic-gate 		return ((off_t)-1);
49090Sstevel@tonic-gate 	m1 = m;
49100Sstevel@tonic-gate 	j = i;
49110Sstevel@tonic-gate 	for (i++; i < N; i++) {
49120Sstevel@tonic-gate 		m1++;
49130Sstevel@tonic-gate 		if (b[i] == '\n')
49140Sstevel@tonic-gate 			break;
49150Sstevel@tonic-gate 	}
49160Sstevel@tonic-gate 	i = cmp(b+j, s, n);
49170Sstevel@tonic-gate 	if (i < 0) {
49180Sstevel@tonic-gate 		h = m;
49190Sstevel@tonic-gate 		goto loop;
49200Sstevel@tonic-gate 	}
49210Sstevel@tonic-gate 	if (i > 0) {
49220Sstevel@tonic-gate 		l = m1;
49230Sstevel@tonic-gate 		goto loop;
49240Sstevel@tonic-gate 	}
49250Sstevel@tonic-gate 	if (m < 0)
49260Sstevel@tonic-gate 		m = 0;
49270Sstevel@tonic-gate 	return (m);
49280Sstevel@tonic-gate }
49290Sstevel@tonic-gate 
49300Sstevel@tonic-gate static int
cmp(char * b,char * s,int n)49310Sstevel@tonic-gate cmp(char *b, char *s, int n)
49320Sstevel@tonic-gate {
49330Sstevel@tonic-gate 	int i;
49340Sstevel@tonic-gate 
49350Sstevel@tonic-gate 	assert(b[0] == '\n');
49360Sstevel@tonic-gate 
49370Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
49380Sstevel@tonic-gate 		if (b[i+1] > s[i])
49390Sstevel@tonic-gate 			return (-1);
49400Sstevel@tonic-gate 		if (b[i+1] < s[i])
49410Sstevel@tonic-gate 			return (1);
49420Sstevel@tonic-gate 	}
49430Sstevel@tonic-gate 	return (b[i+1] == ' '? 0 : -1);
49440Sstevel@tonic-gate }
49450Sstevel@tonic-gate 
49460Sstevel@tonic-gate 
49470Sstevel@tonic-gate /*
49480Sstevel@tonic-gate  *	seekdisk	seek to next file on archive
49490Sstevel@tonic-gate  *
49500Sstevel@tonic-gate  *	called by passtape() only
49510Sstevel@tonic-gate  *
49520Sstevel@tonic-gate  *	WARNING: expects "nblock" to be set, that is, readtape() to have
49530Sstevel@tonic-gate  *		already been called.  Since passtape() is only called
49540Sstevel@tonic-gate  *		after a file header block has been read (why else would
49550Sstevel@tonic-gate  *		we skip to next file?), this is currently safe.
49560Sstevel@tonic-gate  *
49570Sstevel@tonic-gate  *	changed to guarantee SYS_BLOCK boundary
49580Sstevel@tonic-gate  */
49590Sstevel@tonic-gate 
49600Sstevel@tonic-gate static void
seekdisk(blkcnt_t blocks)49610Sstevel@tonic-gate seekdisk(blkcnt_t blocks)
49620Sstevel@tonic-gate {
49630Sstevel@tonic-gate 	off_t seekval;
49640Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
49650Sstevel@tonic-gate 	/* handle non-multiple of SYS_BLOCK */
49660Sstevel@tonic-gate 	blkcnt_t nxb;	/* # extra blocks */
49670Sstevel@tonic-gate #endif
49680Sstevel@tonic-gate 
49690Sstevel@tonic-gate 	tapepos += blocks;
49700Sstevel@tonic-gate #ifdef DEBUG
49710Sstevel@tonic-gate 	DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0);
49720Sstevel@tonic-gate #endif
49730Sstevel@tonic-gate 	if (recno + blocks <= nblock) {
49740Sstevel@tonic-gate 		recno += blocks;
49750Sstevel@tonic-gate 		return;
49760Sstevel@tonic-gate 	}
49770Sstevel@tonic-gate 	if (recno > nblock)
49780Sstevel@tonic-gate 		recno = nblock;
49790Sstevel@tonic-gate 	seekval = (off_t)blocks - (nblock - recno);
49800Sstevel@tonic-gate 	recno = nblock;	/* so readtape() reads next time through */
49810Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
49820Sstevel@tonic-gate 	nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
49830Sstevel@tonic-gate #ifdef DEBUG
49840Sstevel@tonic-gate 	DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
49850Sstevel@tonic-gate 	    nxb, seekval);
49860Sstevel@tonic-gate #endif
49870Sstevel@tonic-gate 	if (nxb && nxb > seekval) /* don't seek--we'll read */
49880Sstevel@tonic-gate 		goto noseek;
49890Sstevel@tonic-gate 	seekval -=  nxb;	/* don't seek quite so far */
49900Sstevel@tonic-gate #endif
49910Sstevel@tonic-gate 	if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
49920Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
49930Sstevel@tonic-gate 		    "tar: device seek error\n"));
49940Sstevel@tonic-gate 		done(3);
49950Sstevel@tonic-gate 	}
49960Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
49970Sstevel@tonic-gate 	/* read those extra blocks */
49980Sstevel@tonic-gate noseek:
49990Sstevel@tonic-gate 	if (nxb) {
50000Sstevel@tonic-gate #ifdef DEBUG
50010Sstevel@tonic-gate 		DEBUG("reading extra blocks\n", 0, 0);
50020Sstevel@tonic-gate #endif
50030Sstevel@tonic-gate 		if (read(mt, tbuf, TBLOCK*nblock) < 0) {
50040Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
50050Sstevel@tonic-gate 			    "tar: read error while skipping file\n"));
50060Sstevel@tonic-gate 			done(8);
50070Sstevel@tonic-gate 		}
50080Sstevel@tonic-gate 		recno = nxb;	/* so we don't read in next readtape() */
50090Sstevel@tonic-gate 	}
50100Sstevel@tonic-gate #endif
50110Sstevel@tonic-gate }
50120Sstevel@tonic-gate 
50130Sstevel@tonic-gate static void
readtape(char * buffer)50140Sstevel@tonic-gate readtape(char *buffer)
50150Sstevel@tonic-gate {
50160Sstevel@tonic-gate 	int i, j;
50170Sstevel@tonic-gate 
50180Sstevel@tonic-gate 	++tapepos;
50190Sstevel@tonic-gate 	if (recno >= nblock || first) {
50200Sstevel@tonic-gate 		if (first) {
50210Sstevel@tonic-gate 			/*
50220Sstevel@tonic-gate 			 * set the number of blocks to read initially, based on
50230Sstevel@tonic-gate 			 * the defined defaults for the device, or on the
50240Sstevel@tonic-gate 			 * explicit block factor given.
50250Sstevel@tonic-gate 			 */
502612350Srich.burridge@sun.com 			if (bflag || defaults_used || NotTape)
50270Sstevel@tonic-gate 				j = nblock;
50280Sstevel@tonic-gate 			else
50290Sstevel@tonic-gate 				j = NBLOCK;
50300Sstevel@tonic-gate 		} else
50310Sstevel@tonic-gate 			j = nblock;
50320Sstevel@tonic-gate 
50330Sstevel@tonic-gate 		if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
50340Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
50350Sstevel@tonic-gate 			    "tar: tape read error\n"));
50360Sstevel@tonic-gate 			done(3);
50370Sstevel@tonic-gate 		/*
50382512Sss161016 		 * i == 0 and !rflag means that EOF is reached and we are
50392512Sss161016 		 * trying to update or replace an empty tar file, so exit
50402512Sss161016 		 * with an error.
50412512Sss161016 		 *
50422512Sss161016 		 * If i == 0 and !first and NotTape, it means the pointer
50432512Sss161016 		 * has gone past the EOF. It could happen if two processes
50442512Sss161016 		 * try to update the same tar file simultaneously. So exit
50452512Sss161016 		 * with an error.
50460Sstevel@tonic-gate 		 */
50472512Sss161016 
50482512Sss161016 		} else if (i == 0) {
50492512Sss161016 			if (first && !rflag) {
50502512Sss161016 				(void) fprintf(stderr, gettext(
50512512Sss161016 				    "tar: blocksize = %d\n"), i);
50522512Sss161016 				done(Errflg);
50532512Sss161016 			} else if (!first && (!rflag || NotTape)) {
50542512Sss161016 				mterr("read", 0, 2);
50552512Sss161016 			}
50560Sstevel@tonic-gate 		} else if ((!first || Bflag) && i != TBLOCK*j) {
50570Sstevel@tonic-gate 			/*
50580Sstevel@tonic-gate 			 * Short read - try to get the remaining bytes.
50590Sstevel@tonic-gate 			 */
50600Sstevel@tonic-gate 
50610Sstevel@tonic-gate 			int remaining = (TBLOCK * j) - i;
50620Sstevel@tonic-gate 			char *b = (char *)tbuf + i;
50630Sstevel@tonic-gate 			int r;
50640Sstevel@tonic-gate 
50650Sstevel@tonic-gate 			do {
50660Sstevel@tonic-gate 				if ((r = read(mt, b, remaining)) < 0) {
50670Sstevel@tonic-gate 					(void) fprintf(stderr,
50680Sstevel@tonic-gate 					    gettext("tar: tape read error\n"));
50690Sstevel@tonic-gate 					done(3);
50700Sstevel@tonic-gate 				}
50710Sstevel@tonic-gate 				b += r;
50720Sstevel@tonic-gate 				remaining -= r;
50730Sstevel@tonic-gate 				i += r;
50740Sstevel@tonic-gate 			} while (remaining > 0 && r != 0);
50750Sstevel@tonic-gate 		}
50760Sstevel@tonic-gate 		if (first) {
50770Sstevel@tonic-gate 			if ((i % TBLOCK) != 0) {
50780Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
50790Sstevel@tonic-gate 				    "tar: tape blocksize error\n"));
50800Sstevel@tonic-gate 				done(3);
50810Sstevel@tonic-gate 			}
50820Sstevel@tonic-gate 			i /= TBLOCK;
50830Sstevel@tonic-gate 			if (vflag && i != nblock && i != 1) {
50840Sstevel@tonic-gate 				if (!NotTape)
50850Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
50860Sstevel@tonic-gate 					    "tar: blocksize = %d\n"), i);
50870Sstevel@tonic-gate 			}
50880Sstevel@tonic-gate 
50890Sstevel@tonic-gate 			/*
50900Sstevel@tonic-gate 			 * If we are reading a tape, then a short read is
50910Sstevel@tonic-gate 			 * understood to signify that the amount read is
50920Sstevel@tonic-gate 			 * the tape's actual blocking factor.  We adapt
50930Sstevel@tonic-gate 			 * nblock accordingly.  There is no reason to do
50940Sstevel@tonic-gate 			 * this when the device is not blocked.
50950Sstevel@tonic-gate 			 */
50960Sstevel@tonic-gate 
50970Sstevel@tonic-gate 			if (!NotTape)
50980Sstevel@tonic-gate 				nblock = i;
50990Sstevel@tonic-gate 		}
51000Sstevel@tonic-gate 		recno = 0;
51010Sstevel@tonic-gate 	}
51020Sstevel@tonic-gate 
51030Sstevel@tonic-gate 	first = FALSE;
51040Sstevel@tonic-gate 	copy(buffer, &tbuf[recno++]);
51050Sstevel@tonic-gate }
51060Sstevel@tonic-gate 
51070Sstevel@tonic-gate 
51080Sstevel@tonic-gate /*
51090Sstevel@tonic-gate  * replacement for writetape.
51100Sstevel@tonic-gate  */
51110Sstevel@tonic-gate 
51120Sstevel@tonic-gate static int
writetbuf(char * buffer,int n)51130Sstevel@tonic-gate writetbuf(char *buffer, int n)
51140Sstevel@tonic-gate {
51150Sstevel@tonic-gate 	int i;
51160Sstevel@tonic-gate 
51170Sstevel@tonic-gate 	tapepos += n;		/* output block count */
51180Sstevel@tonic-gate 
51190Sstevel@tonic-gate 	if (recno >= nblock) {
51200Sstevel@tonic-gate 		i = write(mt, (char *)tbuf, TBLOCK*nblock);
51210Sstevel@tonic-gate 		if (i != TBLOCK*nblock)
51220Sstevel@tonic-gate 			mterr("write", i, 2);
51230Sstevel@tonic-gate 		recno = 0;
51240Sstevel@tonic-gate 	}
51250Sstevel@tonic-gate 
51260Sstevel@tonic-gate 	/*
51270Sstevel@tonic-gate 	 *  Special case:  We have an empty tape buffer, and the
51280Sstevel@tonic-gate 	 *  users data size is >= the tape block size:  Avoid
51290Sstevel@tonic-gate 	 *  the bcopy and dma direct to tape.  BIG WIN.  Add the
51300Sstevel@tonic-gate 	 *  residual to the tape buffer.
51310Sstevel@tonic-gate 	 */
51320Sstevel@tonic-gate 	while (recno == 0 && n >= nblock) {
51330Sstevel@tonic-gate 		i = (int)write(mt, buffer, TBLOCK*nblock);
51340Sstevel@tonic-gate 		if (i != TBLOCK*nblock)
51350Sstevel@tonic-gate 			mterr("write", i, 2);
51360Sstevel@tonic-gate 		n -= nblock;
51370Sstevel@tonic-gate 		buffer += (nblock * TBLOCK);
51380Sstevel@tonic-gate 	}
51390Sstevel@tonic-gate 
51400Sstevel@tonic-gate 	while (n-- > 0) {
51410Sstevel@tonic-gate 		(void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
51420Sstevel@tonic-gate 		buffer += TBLOCK;
51430Sstevel@tonic-gate 		if (recno >= nblock) {
51440Sstevel@tonic-gate 			i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
51450Sstevel@tonic-gate 			if (i != TBLOCK*nblock)
51460Sstevel@tonic-gate 				mterr("write", i, 2);
51470Sstevel@tonic-gate 			recno = 0;
51480Sstevel@tonic-gate 		}
51490Sstevel@tonic-gate 	}
51500Sstevel@tonic-gate 
51510Sstevel@tonic-gate 	/* Tell the user how much to write to get in sync */
51520Sstevel@tonic-gate 	return (nblock - recno);
51530Sstevel@tonic-gate }
51540Sstevel@tonic-gate 
51550Sstevel@tonic-gate /*
51560Sstevel@tonic-gate  *	backtape - reposition tape after reading soft "EOF" record
51570Sstevel@tonic-gate  *
51580Sstevel@tonic-gate  *	Backtape tries to reposition the tape back over the EOF
51590Sstevel@tonic-gate  *	record.  This is for the 'u' and 'r' function letters so that the
51600Sstevel@tonic-gate  *	tape can be extended.  This code is not well designed, but
51610Sstevel@tonic-gate  *	I'm confident that the only callers who care about the
51620Sstevel@tonic-gate  *	backspace-over-EOF feature are those involved in 'u' and 'r'.
51630Sstevel@tonic-gate  *
51640Sstevel@tonic-gate  *	The proper way to backup the tape is through the use of mtio.
51650Sstevel@tonic-gate  *	Earlier spins used lseek combined with reads in a confusing
51660Sstevel@tonic-gate  *	maneuver that only worked on 4.x, but shouldn't have, even
51670Sstevel@tonic-gate  *	there.  Lseeks are explicitly not supported for tape devices.
51680Sstevel@tonic-gate  */
51690Sstevel@tonic-gate 
51700Sstevel@tonic-gate static void
backtape(void)51710Sstevel@tonic-gate backtape(void)
51720Sstevel@tonic-gate {
51730Sstevel@tonic-gate 	struct mtop mtcmd;
51740Sstevel@tonic-gate #ifdef DEBUG
51750Sstevel@tonic-gate 	DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
51760Sstevel@tonic-gate 	    nblock);
51770Sstevel@tonic-gate #endif
51780Sstevel@tonic-gate 	/*
51790Sstevel@tonic-gate 	 * Backup to the position in the archive where the record
51800Sstevel@tonic-gate 	 * currently sitting in the tbuf buffer is situated.
51810Sstevel@tonic-gate 	 */
51820Sstevel@tonic-gate 
51830Sstevel@tonic-gate 	if (NotTape) {
51840Sstevel@tonic-gate 		/*
51850Sstevel@tonic-gate 		 * For non-tape devices, this means lseeking to the
51860Sstevel@tonic-gate 		 * correct position.  The absolute location tapepos-recno
51870Sstevel@tonic-gate 		 * should be the beginning of the current record.
51880Sstevel@tonic-gate 		 */
51890Sstevel@tonic-gate 
51900Sstevel@tonic-gate 		if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
51910Sstevel@tonic-gate 		    (off_t)-1) {
51920Sstevel@tonic-gate 			(void) fprintf(stderr,
51930Sstevel@tonic-gate 			    gettext("tar: lseek to end of archive failed\n"));
51940Sstevel@tonic-gate 			done(4);
51950Sstevel@tonic-gate 		}
51960Sstevel@tonic-gate 	} else {
51970Sstevel@tonic-gate 		/*
51980Sstevel@tonic-gate 		 * For tape devices, we backup over the most recently
51990Sstevel@tonic-gate 		 * read record.
52000Sstevel@tonic-gate 		 */
52010Sstevel@tonic-gate 
52020Sstevel@tonic-gate 		mtcmd.mt_op = MTBSR;
52030Sstevel@tonic-gate 		mtcmd.mt_count = 1;
52040Sstevel@tonic-gate 
52050Sstevel@tonic-gate 		if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
52060Sstevel@tonic-gate 			(void) fprintf(stderr,
52071266Sceastha 			    gettext("tar: backspace over record failed\n"));
52080Sstevel@tonic-gate 			done(4);
52090Sstevel@tonic-gate 		}
52100Sstevel@tonic-gate 	}
52110Sstevel@tonic-gate 
52120Sstevel@tonic-gate 	/*
52130Sstevel@tonic-gate 	 * Decrement the tape and tbuf buffer indices to prepare for the
52140Sstevel@tonic-gate 	 * coming write to overwrite the soft EOF record.
52150Sstevel@tonic-gate 	 */
52160Sstevel@tonic-gate 
52170Sstevel@tonic-gate 	recno--;
52180Sstevel@tonic-gate 	tapepos--;
52190Sstevel@tonic-gate }
52200Sstevel@tonic-gate 
52210Sstevel@tonic-gate 
52220Sstevel@tonic-gate /*
52230Sstevel@tonic-gate  *	flushtape  write buffered block(s) onto tape
52240Sstevel@tonic-gate  *
52250Sstevel@tonic-gate  *      recno points to next free block in tbuf.  If nonzero, a write is done.
52260Sstevel@tonic-gate  *	Care is taken to write in multiples of SYS_BLOCK when device is
52270Sstevel@tonic-gate  *	non-magtape in case raw i/o is used.
52280Sstevel@tonic-gate  *
52290Sstevel@tonic-gate  *	NOTE: this is called by writetape() to do the actual writing
52300Sstevel@tonic-gate  */
52310Sstevel@tonic-gate 
52320Sstevel@tonic-gate static void
flushtape(void)52330Sstevel@tonic-gate flushtape(void)
52340Sstevel@tonic-gate {
52350Sstevel@tonic-gate #ifdef DEBUG
52360Sstevel@tonic-gate 	DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0);
52370Sstevel@tonic-gate #endif
52380Sstevel@tonic-gate 	if (recno > 0) {	/* anything buffered? */
52390Sstevel@tonic-gate 		if (NotTape) {
52400Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
52410Sstevel@tonic-gate 			int i;
52420Sstevel@tonic-gate 
52430Sstevel@tonic-gate 			/*
52440Sstevel@tonic-gate 			 * an odd-block write can only happen when
52450Sstevel@tonic-gate 			 * we are at the end of a volume that is not a tape.
52460Sstevel@tonic-gate 			 * Here we round recno up to an even SYS_BLOCK
52470Sstevel@tonic-gate 			 * boundary.
52480Sstevel@tonic-gate 			 */
52490Sstevel@tonic-gate 			if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
52500Sstevel@tonic-gate #ifdef DEBUG
52510Sstevel@tonic-gate 				DEBUG("flushtape() %d rounding blocks\n", i, 0);
52520Sstevel@tonic-gate #endif
52530Sstevel@tonic-gate 				recno += i;	/* round up to even SYS_BLOCK */
52540Sstevel@tonic-gate 			}
52550Sstevel@tonic-gate #endif
52560Sstevel@tonic-gate 			if (recno > nblock)
52570Sstevel@tonic-gate 				recno = nblock;
52580Sstevel@tonic-gate 		}
52590Sstevel@tonic-gate #ifdef DEBUG
52600Sstevel@tonic-gate 		DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
52610Sstevel@tonic-gate 		    " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
52620Sstevel@tonic-gate 		    (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
52630Sstevel@tonic-gate #endif
52640Sstevel@tonic-gate 		if (write(mt, tbuf,
52650Sstevel@tonic-gate 		    (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
52660Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
52670Sstevel@tonic-gate 			    "tar: tape write error\n"));
52680Sstevel@tonic-gate 			done(2);
52690Sstevel@tonic-gate 		}
52700Sstevel@tonic-gate 		recno = 0;
52710Sstevel@tonic-gate 	}
52720Sstevel@tonic-gate }
52730Sstevel@tonic-gate 
52740Sstevel@tonic-gate static void
copy(void * dst,void * src)52750Sstevel@tonic-gate copy(void *dst, void *src)
52760Sstevel@tonic-gate {
52770Sstevel@tonic-gate 	(void) memcpy(dst, src, TBLOCK);
52780Sstevel@tonic-gate }
52790Sstevel@tonic-gate 
52800Sstevel@tonic-gate /*
52810Sstevel@tonic-gate  * kcheck()
52820Sstevel@tonic-gate  *	- checks the validity of size values for non-tape devices
52830Sstevel@tonic-gate  *	- if size is zero, mulvol tar is disabled and size is
52840Sstevel@tonic-gate  *	  assumed to be infinite.
52850Sstevel@tonic-gate  *	- returns volume size in TBLOCKS
52860Sstevel@tonic-gate  */
52870Sstevel@tonic-gate 
52880Sstevel@tonic-gate static blkcnt_t
kcheck(char * kstr)52890Sstevel@tonic-gate kcheck(char *kstr)
52900Sstevel@tonic-gate {
52910Sstevel@tonic-gate 	blkcnt_t kval;
52920Sstevel@tonic-gate 
52930Sstevel@tonic-gate 	kval = strtoll(kstr, NULL, 0);
52940Sstevel@tonic-gate 	if (kval == (blkcnt_t)0) {	/* no multi-volume; size is infinity. */
52950Sstevel@tonic-gate 		mulvol = 0;	/* definitely not mulvol, but we must  */
52960Sstevel@tonic-gate 		return (0);	/* took out setting of NotTape */
52970Sstevel@tonic-gate 	}
52980Sstevel@tonic-gate 	if (kval < (blkcnt_t)MINSIZE) {
52990Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
53000Sstevel@tonic-gate 		    "tar: sizes below %luK not supported (%" FMT_blkcnt_t
53010Sstevel@tonic-gate 		    ").\n"), (ulong_t)MINSIZE, kval);
5302*12836Srich.burridge@oracle.com 		(void) fprintf(stderr, gettext(
5303*12836Srich.burridge@oracle.com 		    "bad size entry for %s in %s.\n"),
5304*12836Srich.burridge@oracle.com 		    archive, DEF_FILE);
53050Sstevel@tonic-gate 		done(1);
53060Sstevel@tonic-gate 	}
53070Sstevel@tonic-gate 	mulvol++;
53080Sstevel@tonic-gate 	NotTape++;			/* implies non-tape */
53090Sstevel@tonic-gate 	return (kval * 1024 / TBLOCK);	/* convert to TBLOCKS */
53100Sstevel@tonic-gate }
53110Sstevel@tonic-gate 
53120Sstevel@tonic-gate 
53130Sstevel@tonic-gate /*
53140Sstevel@tonic-gate  * bcheck()
53150Sstevel@tonic-gate  *	- checks the validity of blocking factors
53160Sstevel@tonic-gate  *	- returns blocking factor
53170Sstevel@tonic-gate  */
53180Sstevel@tonic-gate 
53190Sstevel@tonic-gate static int
bcheck(char * bstr)53200Sstevel@tonic-gate bcheck(char *bstr)
53210Sstevel@tonic-gate {
53220Sstevel@tonic-gate 	blkcnt_t bval;
53230Sstevel@tonic-gate 
53240Sstevel@tonic-gate 	bval = strtoll(bstr, NULL, 0);
53250Sstevel@tonic-gate 	if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
53260Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
53270Sstevel@tonic-gate 		    "tar: invalid blocksize \"%s\".\n"), bstr);
53280Sstevel@tonic-gate 		if (!bflag)
53290Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
53300Sstevel@tonic-gate 			    "bad blocksize entry for '%s' in %s.\n"),
53310Sstevel@tonic-gate 			    archive, DEF_FILE);
53320Sstevel@tonic-gate 		done(1);
53330Sstevel@tonic-gate 	}
53340Sstevel@tonic-gate 
53350Sstevel@tonic-gate 	return ((int)bval);
53360Sstevel@tonic-gate }
53370Sstevel@tonic-gate 
53380Sstevel@tonic-gate 
53390Sstevel@tonic-gate /*
53400Sstevel@tonic-gate  * defset()
53410Sstevel@tonic-gate  *	- reads DEF_FILE for the set of default values specified.
53420Sstevel@tonic-gate  *	- initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
53430Sstevel@tonic-gate  *	- 'usefile' points to static data, so will be overwritten
53440Sstevel@tonic-gate  *	  if this routine is called a second time.
53450Sstevel@tonic-gate  *	- the pattern specified by 'arch' must be followed by four
53460Sstevel@tonic-gate  *	  blank-separated fields (1) device (2) blocking,
53470Sstevel@tonic-gate  *				 (3) size(K), and (4) tape
53480Sstevel@tonic-gate  *	  for example: archive0=/dev/fd 1 400 n
53490Sstevel@tonic-gate  */
53500Sstevel@tonic-gate 
53510Sstevel@tonic-gate static int
defset(char * arch)53520Sstevel@tonic-gate defset(char *arch)
53530Sstevel@tonic-gate {
53540Sstevel@tonic-gate 	char *bp;
53550Sstevel@tonic-gate 
53560Sstevel@tonic-gate 	if (defopen(DEF_FILE) != 0)
53570Sstevel@tonic-gate 		return (FALSE);
53580Sstevel@tonic-gate 	if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
53590Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
53600Sstevel@tonic-gate 		    "tar: error setting parameters for %s.\n"), DEF_FILE);
53610Sstevel@tonic-gate 		return (FALSE);			/* & following ones too */
53620Sstevel@tonic-gate 	}
53630Sstevel@tonic-gate 	if ((bp = defread(arch)) == NULL) {
53640Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
53650Sstevel@tonic-gate 		    "tar: missing or invalid '%s' entry in %s.\n"),
53661266Sceastha 		    arch, DEF_FILE);
53670Sstevel@tonic-gate 		return (FALSE);
53680Sstevel@tonic-gate 	}
53690Sstevel@tonic-gate 	if ((usefile = strtok(bp, " \t")) == NULL) {
53700Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
53710Sstevel@tonic-gate 		    "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
53720Sstevel@tonic-gate 		return (FALSE);
53730Sstevel@tonic-gate 	}
53740Sstevel@tonic-gate 	if ((bp = strtok(NULL, " \t")) == NULL) {
53750Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
53760Sstevel@tonic-gate 		    "tar: block component missing in '%s' entry in %s.\n"),
53770Sstevel@tonic-gate 		    arch, DEF_FILE);
53780Sstevel@tonic-gate 		return (FALSE);
53790Sstevel@tonic-gate 	}
53800Sstevel@tonic-gate 	nblock = bcheck(bp);
53810Sstevel@tonic-gate 	if ((bp = strtok(NULL, " \t")) == NULL) {
53820Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
53830Sstevel@tonic-gate 		    "tar: size component missing in '%s' entry in %s.\n"),
53840Sstevel@tonic-gate 		    arch, DEF_FILE);
53850Sstevel@tonic-gate 		return (FALSE);
53860Sstevel@tonic-gate 	}
53870Sstevel@tonic-gate 	blocklim = kcheck(bp);
53880Sstevel@tonic-gate 	if ((bp = strtok(NULL, " \t")) != NULL)
53890Sstevel@tonic-gate 		NotTape = (*bp == 'n' || *bp == 'N');
53900Sstevel@tonic-gate 	else
53910Sstevel@tonic-gate 		NotTape = (blocklim != 0);
53920Sstevel@tonic-gate 	(void) defopen(NULL);
53930Sstevel@tonic-gate #ifdef DEBUG
53940Sstevel@tonic-gate 	DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile);
53950Sstevel@tonic-gate 	DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
53960Sstevel@tonic-gate 	    nblock, blocklim);
53970Sstevel@tonic-gate 	DEBUG("defset: not tape = %d\n", NotTape, 0);
53980Sstevel@tonic-gate #endif
53990Sstevel@tonic-gate 	return (TRUE);
54000Sstevel@tonic-gate }
54010Sstevel@tonic-gate 
54020Sstevel@tonic-gate 
54030Sstevel@tonic-gate /*
54040Sstevel@tonic-gate  * Following code handles excluded and included files.
54050Sstevel@tonic-gate  * A hash table of file names to be {in,ex}cluded is built.
54060Sstevel@tonic-gate  * For excluded files, before writing or extracting a file
54070Sstevel@tonic-gate  * check to see if it is in the exclude_tbl.
54080Sstevel@tonic-gate  * For included files, the wantit() procedure will check to
54090Sstevel@tonic-gate  * see if the named file is in the include_tbl.
54100Sstevel@tonic-gate  */
54110Sstevel@tonic-gate 
54120Sstevel@tonic-gate static void
build_table(file_list_t * table[],char * file)54136525Sceastha build_table(file_list_t *table[], char *file)
54140Sstevel@tonic-gate {
54150Sstevel@tonic-gate 	FILE	*fp;
54160Sstevel@tonic-gate 	char	buf[PATH_MAX + 1];
54170Sstevel@tonic-gate 
54180Sstevel@tonic-gate 	if ((fp = fopen(file, "r")) == (FILE *)NULL)
54190Sstevel@tonic-gate 		vperror(1, gettext("could not open %s"), file);
54200Sstevel@tonic-gate 	while (fgets(buf, sizeof (buf), fp) != NULL) {
54210Sstevel@tonic-gate 		if (buf[strlen(buf) - 1] == '\n')
54220Sstevel@tonic-gate 			buf[strlen(buf) - 1] = '\0';
54230Sstevel@tonic-gate 		/* Only add to table if line has something in it */
54240Sstevel@tonic-gate 		if (strspn(buf, " \t") != strlen(buf))
54250Sstevel@tonic-gate 			add_file_to_table(table, buf);
54260Sstevel@tonic-gate 	}
54270Sstevel@tonic-gate 	(void) fclose(fp);
54280Sstevel@tonic-gate }
54290Sstevel@tonic-gate 
54300Sstevel@tonic-gate 
54310Sstevel@tonic-gate /*
54320Sstevel@tonic-gate  * Add a file name to the the specified table, if the file name has any
54330Sstevel@tonic-gate  * trailing '/'s then delete them before inserting into the table
54340Sstevel@tonic-gate  */
54350Sstevel@tonic-gate 
54360Sstevel@tonic-gate static void
add_file_to_table(file_list_t * table[],char * str)54376525Sceastha add_file_to_table(file_list_t *table[], char *str)
54380Sstevel@tonic-gate {
54390Sstevel@tonic-gate 	char	name[PATH_MAX + 1];
54400Sstevel@tonic-gate 	unsigned int h;
54416525Sceastha 	file_list_t	*exp;
54420Sstevel@tonic-gate 
54430Sstevel@tonic-gate 	(void) strcpy(name, str);
54440Sstevel@tonic-gate 	while (name[strlen(name) - 1] == '/') {
54450Sstevel@tonic-gate 		name[strlen(name) - 1] = NULL;
54460Sstevel@tonic-gate 	}
54470Sstevel@tonic-gate 
54480Sstevel@tonic-gate 	h = hash(name);
54496525Sceastha 	if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
54500Sstevel@tonic-gate 	    sizeof (char))) == NULL) {
54510Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
54520Sstevel@tonic-gate 		    "tar: out of memory, exclude/include table(entry)\n"));
54530Sstevel@tonic-gate 		exit(1);
54540Sstevel@tonic-gate 	}
54550Sstevel@tonic-gate 
54560Sstevel@tonic-gate 	if ((exp->name = strdup(name)) == NULL) {
54570Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
54580Sstevel@tonic-gate 		    "tar: out of memory, exclude/include table(file name)\n"));
54590Sstevel@tonic-gate 		exit(1);
54600Sstevel@tonic-gate 	}
54610Sstevel@tonic-gate 
54620Sstevel@tonic-gate 	exp->next = table[h];
54630Sstevel@tonic-gate 	table[h] = exp;
54640Sstevel@tonic-gate }
54650Sstevel@tonic-gate 
54660Sstevel@tonic-gate 
54670Sstevel@tonic-gate /*
54680Sstevel@tonic-gate  * See if a file name or any of the file's parent directories is in the
54690Sstevel@tonic-gate  * specified table, if the file name has any trailing '/'s then delete
54700Sstevel@tonic-gate  * them before searching the table
54710Sstevel@tonic-gate  */
54720Sstevel@tonic-gate 
54730Sstevel@tonic-gate static int
is_in_table(file_list_t * table[],char * str)54746525Sceastha is_in_table(file_list_t *table[], char *str)
54750Sstevel@tonic-gate {
54760Sstevel@tonic-gate 	char	name[PATH_MAX + 1];
54770Sstevel@tonic-gate 	unsigned int	h;
54786525Sceastha 	file_list_t	*exp;
54790Sstevel@tonic-gate 	char	*ptr;
54800Sstevel@tonic-gate 
54810Sstevel@tonic-gate 	(void) strcpy(name, str);
54820Sstevel@tonic-gate 	while (name[strlen(name) - 1] == '/') {
54830Sstevel@tonic-gate 		name[strlen(name) - 1] = NULL;
54840Sstevel@tonic-gate 	}
54850Sstevel@tonic-gate 
54860Sstevel@tonic-gate 	/*
54870Sstevel@tonic-gate 	 * check for the file name in the passed list
54880Sstevel@tonic-gate 	 */
54890Sstevel@tonic-gate 	h = hash(name);
54900Sstevel@tonic-gate 	exp = table[h];
54910Sstevel@tonic-gate 	while (exp != NULL) {
54920Sstevel@tonic-gate 		if (strcmp(name, exp->name) == 0) {
54930Sstevel@tonic-gate 			return (1);
54940Sstevel@tonic-gate 		}
54950Sstevel@tonic-gate 		exp = exp->next;
54960Sstevel@tonic-gate 	}
54970Sstevel@tonic-gate 
54980Sstevel@tonic-gate 	/*
54990Sstevel@tonic-gate 	 * check for any parent directories in the file list
55000Sstevel@tonic-gate 	 */
55010Sstevel@tonic-gate 	while ((ptr = strrchr(name, '/'))) {
55020Sstevel@tonic-gate 		*ptr = NULL;
55030Sstevel@tonic-gate 		h = hash(name);
55040Sstevel@tonic-gate 		exp = table[h];
55050Sstevel@tonic-gate 		while (exp != NULL) {
55060Sstevel@tonic-gate 			if (strcmp(name, exp->name) == 0) {
55070Sstevel@tonic-gate 				return (1);
55080Sstevel@tonic-gate 			}
55090Sstevel@tonic-gate 			exp = exp->next;
55100Sstevel@tonic-gate 		}
55110Sstevel@tonic-gate 	}
55120Sstevel@tonic-gate 
55130Sstevel@tonic-gate 	return (0);
55140Sstevel@tonic-gate }
55150Sstevel@tonic-gate 
55160Sstevel@tonic-gate 
55170Sstevel@tonic-gate /*
55180Sstevel@tonic-gate  * Compute a hash from a string.
55190Sstevel@tonic-gate  */
55200Sstevel@tonic-gate 
55210Sstevel@tonic-gate static unsigned int
hash(char * str)55220Sstevel@tonic-gate hash(char *str)
55230Sstevel@tonic-gate {
55240Sstevel@tonic-gate 	char	*cp;
55250Sstevel@tonic-gate 	unsigned int	h;
55260Sstevel@tonic-gate 
55270Sstevel@tonic-gate 	h = 0;
55280Sstevel@tonic-gate 	for (cp = str; *cp; cp++) {
55290Sstevel@tonic-gate 		h += *cp;
55300Sstevel@tonic-gate 	}
55310Sstevel@tonic-gate 	return (h % TABLE_SIZE);
55320Sstevel@tonic-gate }
55330Sstevel@tonic-gate 
55340Sstevel@tonic-gate static	void *
getmem(size_t size)55350Sstevel@tonic-gate getmem(size_t size)
55360Sstevel@tonic-gate {
55370Sstevel@tonic-gate 	void *p = calloc((unsigned)size, sizeof (char));
55380Sstevel@tonic-gate 
55390Sstevel@tonic-gate 	if (p == NULL && freemem) {
55400Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
55410Sstevel@tonic-gate 		    "tar: out of memory, link and directory modtime "
55420Sstevel@tonic-gate 		    "info lost\n"));
55430Sstevel@tonic-gate 		freemem = 0;
55440Sstevel@tonic-gate 		if (errflag)
55450Sstevel@tonic-gate 			done(1);
55460Sstevel@tonic-gate 		else
55470Sstevel@tonic-gate 			Errflg = 1;
55480Sstevel@tonic-gate 	}
55490Sstevel@tonic-gate 	return (p);
55500Sstevel@tonic-gate }
55510Sstevel@tonic-gate 
55520Sstevel@tonic-gate /*
55530Sstevel@tonic-gate  * vperror() --variable argument perror.
55540Sstevel@tonic-gate  * Takes 3 args: exit_status, formats, args.  If exit_status is 0, then
55550Sstevel@tonic-gate  * the errflag (exit on error) is checked -- if it is non-zero, tar exits
55560Sstevel@tonic-gate  * with the value of whatever "errno" is set to.  If exit_status is not
55570Sstevel@tonic-gate  * zero, then tar exits with that error status. If errflag and exit_status
55580Sstevel@tonic-gate  * are both zero, the routine returns to where it was called and sets Errflg
55590Sstevel@tonic-gate  * to errno.
55600Sstevel@tonic-gate  */
55610Sstevel@tonic-gate 
55620Sstevel@tonic-gate static void
vperror(int exit_status,char * fmt,...)55630Sstevel@tonic-gate vperror(int exit_status, char *fmt, ...)
55640Sstevel@tonic-gate {
55650Sstevel@tonic-gate 	va_list	ap;
55660Sstevel@tonic-gate 
55670Sstevel@tonic-gate 	va_start(ap, fmt);
55680Sstevel@tonic-gate 	(void) fputs("tar: ", stderr);
55690Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
55700Sstevel@tonic-gate 	(void) fprintf(stderr, ": %s\n", strerror(errno));
55710Sstevel@tonic-gate 	va_end(ap);
55720Sstevel@tonic-gate 	if (exit_status)
55730Sstevel@tonic-gate 		done(exit_status);
55740Sstevel@tonic-gate 	else
55750Sstevel@tonic-gate 		if (errflag)
55760Sstevel@tonic-gate 			done(errno);
55770Sstevel@tonic-gate 		else
55780Sstevel@tonic-gate 			Errflg = errno;
55790Sstevel@tonic-gate }
55800Sstevel@tonic-gate 
55810Sstevel@tonic-gate 
55820Sstevel@tonic-gate static void
fatal(char * format,...)55830Sstevel@tonic-gate fatal(char *format, ...)
55840Sstevel@tonic-gate {
55850Sstevel@tonic-gate 	va_list	ap;
55860Sstevel@tonic-gate 
55870Sstevel@tonic-gate 	va_start(ap, format);
55880Sstevel@tonic-gate 	(void) fprintf(stderr, "tar: ");
55890Sstevel@tonic-gate 	(void) vfprintf(stderr, format, ap);
55900Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
55910Sstevel@tonic-gate 	va_end(ap);
55920Sstevel@tonic-gate 	done(1);
55930Sstevel@tonic-gate }
55940Sstevel@tonic-gate 
55950Sstevel@tonic-gate 
55960Sstevel@tonic-gate /*
55970Sstevel@tonic-gate  * Check to make sure that argument is a char * ptr.
55980Sstevel@tonic-gate  * Actually, we just check to see that it is non-null.
55990Sstevel@tonic-gate  * If it is null, print out the message and call usage(), bailing out.
56000Sstevel@tonic-gate  */
56010Sstevel@tonic-gate 
56020Sstevel@tonic-gate static void
assert_string(char * s,char * msg)56030Sstevel@tonic-gate assert_string(char *s, char *msg)
56040Sstevel@tonic-gate {
56050Sstevel@tonic-gate 	if (s == NULL) {
56060Sstevel@tonic-gate 		(void) fprintf(stderr, msg);
56070Sstevel@tonic-gate 		usage();
56080Sstevel@tonic-gate 	}
56090Sstevel@tonic-gate }
56100Sstevel@tonic-gate 
56110Sstevel@tonic-gate 
56120Sstevel@tonic-gate static void
mterr(char * operation,int i,int exitcode)56130Sstevel@tonic-gate mterr(char *operation, int i, int exitcode)
56140Sstevel@tonic-gate {
56150Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
56160Sstevel@tonic-gate 	    "tar: %s error: "), operation);
56170Sstevel@tonic-gate 	if (i < 0)
56180Sstevel@tonic-gate 		perror("");
56190Sstevel@tonic-gate 	else
56200Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("unexpected EOF\n"));
56210Sstevel@tonic-gate 	done(exitcode);
56220Sstevel@tonic-gate }
56230Sstevel@tonic-gate 
56240Sstevel@tonic-gate static int
wantit(char * argv[],char ** namep,char ** dirp,char ** component,attr_data_t ** attrinfo)56255331Samw wantit(char *argv[], char **namep, char **dirp, char **component,
56265331Samw     attr_data_t **attrinfo)
56270Sstevel@tonic-gate {
56280Sstevel@tonic-gate 	char **cp;
56290Sstevel@tonic-gate 	int gotit;		/* true if we've found a match */
56305482Sas158974 	int ret;
56310Sstevel@tonic-gate 
56320Sstevel@tonic-gate top:
56335482Sas158974 	if (xhdr_flgs & _X_XHDR) {
56345482Sas158974 		xhdr_flgs = 0;
56355482Sas158974 	}
56360Sstevel@tonic-gate 	getdir();
56370Sstevel@tonic-gate 	if (Xhdrflag > 0) {
56385482Sas158974 		ret = get_xdata();
56395482Sas158974 		if (ret != 0) {	/* Xhdr items and regular header */
56405482Sas158974 			setbytes_to_skip(&stbuf, ret);
56410Sstevel@tonic-gate 			passtape();
56420Sstevel@tonic-gate 			return (0);	/* Error--don't want to extract  */
56430Sstevel@tonic-gate 		}
56440Sstevel@tonic-gate 	}
56450Sstevel@tonic-gate 
56465482Sas158974 	/*
56475482Sas158974 	 * If typeflag is not 'A' and xhdr_flgs is set, then processing
56485482Sas158974 	 * of ancillary file is either over or ancillary file
56495482Sas158974 	 * processing is not required, load info from Xtarhdr and set
56505482Sas158974 	 * _X_XHDR bit in xhdr_flgs.
56515482Sas158974 	 */
56525482Sas158974 	if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
56535482Sas158974 		load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
56545482Sas158974 		xhdr_flgs |= _X_XHDR;
56555482Sas158974 	}
56565482Sas158974 
56570Sstevel@tonic-gate #if defined(O_XATTR)
56580Sstevel@tonic-gate 	if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
56595331Samw 		/*
56605331Samw 		 * Always needs to read the extended header.  If atflag, saflag,
56615331Samw 		 * or tflag isn't set, then we'll have the correct info for
56625331Samw 		 * passtape() later.
56635331Samw 		 */
56645331Samw 		(void) read_xattr_hdr(attrinfo);
56650Sstevel@tonic-gate 		goto top;
56660Sstevel@tonic-gate 	}
56675331Samw 	/*
56685750Sceastha 	 * Now that we've read the extended header, call passtape()
56695750Sceastha 	 * if we don't want to restore attributes or system attributes.
56705750Sceastha 	 * Don't restore the attribute if we are extracting
56715750Sceastha 	 * a file from an archive (as opposed to doing a table of
56725750Sceastha 	 * contents) and any of the following are true:
56735750Sceastha 	 * 1. neither -@ or -/ was specified.
56745750Sceastha 	 * 2. -@ was specified, -/ wasn't specified, and we're
56755750Sceastha 	 * processing a hidden attribute directory of an attribute
56765750Sceastha 	 * or we're processing a read-write system attribute file.
56775750Sceastha 	 * 3. -@ wasn't specified, -/ was specified, and the file
56785750Sceastha 	 * we're processing is not a read-write system attribute file,
56795750Sceastha 	 * or we're processing the hidden attribute directory of an
56805750Sceastha 	 * attribute.
56815750Sceastha 	 *
56825750Sceastha 	 * We always process the attributes if we're just generating
56835750Sceastha 	 * generating a table of contents, or if both -@ and -/ were
56845750Sceastha 	 * specified.
56855331Samw 	 */
56865750Sceastha 	if (xattrp != NULL) {
56875750Sceastha 		attr_data_t *ainfo = *attrinfo;
56885750Sceastha 
56895750Sceastha 		if (!tflag &&
56905750Sceastha 		    ((!atflag && !saflag) ||
56915750Sceastha 		    (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
56925750Sceastha 		    ainfo->attr_rw_sysattr)) ||
56935750Sceastha 		    (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
56945750Sceastha 		    !ainfo->attr_rw_sysattr)))) {
56955750Sceastha 			passtape();
56965750Sceastha 			return (0);
56975750Sceastha 		}
56985331Samw 	}
56990Sstevel@tonic-gate #endif
57000Sstevel@tonic-gate 
57010Sstevel@tonic-gate 	/* sets *namep to point at the proper name */
57025331Samw 	if (check_prefix(namep, dirp, component) != 0) {
57035331Samw 		passtape();
57045331Samw 		return (0);
57055331Samw 	}
57060Sstevel@tonic-gate 
57070Sstevel@tonic-gate 	if (endtape()) {
57080Sstevel@tonic-gate 		if (Bflag) {
57090Sstevel@tonic-gate 			/*
57100Sstevel@tonic-gate 			 * Logically at EOT - consume any extra blocks
57110Sstevel@tonic-gate 			 * so that write to our stdin won't fail and
57120Sstevel@tonic-gate 			 * emit an error message; otherwise something
57130Sstevel@tonic-gate 			 * like "dd if=foo.tar | (cd bar; tar xvf -)"
57140Sstevel@tonic-gate 			 * will produce a bogus error message from "dd".
57150Sstevel@tonic-gate 			 */
57160Sstevel@tonic-gate 
57170Sstevel@tonic-gate 			while (read(mt, tbuf, TBLOCK*nblock) > 0) {
57180Sstevel@tonic-gate 				/* empty body */
57190Sstevel@tonic-gate 			}
57200Sstevel@tonic-gate 		}
57210Sstevel@tonic-gate 		return (-1);
57220Sstevel@tonic-gate 	}
57230Sstevel@tonic-gate 
57240Sstevel@tonic-gate 	gotit = 0;
57250Sstevel@tonic-gate 
57260Sstevel@tonic-gate 	if ((Iflag && is_in_table(include_tbl, *namep)) ||
57270Sstevel@tonic-gate 	    (! Iflag && *argv == NULL)) {
57280Sstevel@tonic-gate 		gotit = 1;
57290Sstevel@tonic-gate 	} else {
57300Sstevel@tonic-gate 		for (cp = argv; *cp; cp++) {
57310Sstevel@tonic-gate 			if (is_prefix(*cp, *namep)) {
57320Sstevel@tonic-gate 				gotit = 1;
57330Sstevel@tonic-gate 				break;
57340Sstevel@tonic-gate 			}
57350Sstevel@tonic-gate 		}
57360Sstevel@tonic-gate 	}
57370Sstevel@tonic-gate 
57380Sstevel@tonic-gate 	if (! gotit) {
57390Sstevel@tonic-gate 		passtape();
57400Sstevel@tonic-gate 		return (0);
57410Sstevel@tonic-gate 	}
57420Sstevel@tonic-gate 
57430Sstevel@tonic-gate 	if (Xflag && is_in_table(exclude_tbl, *namep)) {
57440Sstevel@tonic-gate 		if (vflag) {
57450Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s excluded\n"),
57460Sstevel@tonic-gate 			    *namep);
57470Sstevel@tonic-gate 		}
57480Sstevel@tonic-gate 		passtape();
57490Sstevel@tonic-gate 		return (0);
57500Sstevel@tonic-gate 	}
57510Sstevel@tonic-gate 
57520Sstevel@tonic-gate 	return (1);
57530Sstevel@tonic-gate }
57540Sstevel@tonic-gate 
57555482Sas158974 
57565482Sas158974 static void
setbytes_to_skip(struct stat * st,int err)57575482Sas158974 setbytes_to_skip(struct stat *st, int err)
57585482Sas158974 {
57595482Sas158974 	/*
57605482Sas158974 	 * In a scenario where a typeflag 'X' was followed by
57615482Sas158974 	 * a typeflag 'A' and typeflag 'O', then the number of
57625482Sas158974 	 * bytes to skip should be the size of ancillary file,
57635482Sas158974 	 * plus the dblock for regular file, and the size
57645482Sas158974 	 * from Xtarhdr. However, if the typeflag was just 'X'
57655482Sas158974 	 * followed by typeflag 'O', then the number of bytes
57665482Sas158974 	 * to skip should be the size from Xtarhdr.
57675482Sas158974 	 */
57685482Sas158974 	if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
576912109SRalph.Turner@Sun.COM 	    (xhdr_flgs & _X_SIZE)) {
57705750Sceastha 		st->st_size += TBLOCK + Xtarhdr.x_filesz;
57715482Sas158974 		xhdr_flgs |= _X_XHDR;
57725482Sas158974 	} else if ((dblock.dbuf.typeflag != 'A') &&
577312109SRalph.Turner@Sun.COM 	    (xhdr_flgs & _X_SIZE)) {
577412109SRalph.Turner@Sun.COM 		st->st_size += Xtarhdr.x_filesz;
57755482Sas158974 		xhdr_flgs |= _X_XHDR;
57765482Sas158974 	}
57775482Sas158974 }
57785482Sas158974 
57795331Samw static int
fill_in_attr_info(char * attr,char * longname,char * attrparent,int atparentfd,int rw_sysattr,attr_data_t ** attrinfo)57805331Samw fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
57815331Samw     int rw_sysattr, attr_data_t **attrinfo)
57825331Samw {
57835331Samw 	size_t	pathlen;
57845331Samw 	char	*tpath;
57855331Samw 	char	*tparent;
57865331Samw 
57875331Samw 	/* parent info */
57885331Samw 	if (attrparent != NULL) {
57895331Samw 		if ((tparent = strdup(attrparent)) == NULL) {
57905331Samw 			vperror(0, gettext(
57915331Samw 			    "unable to allocate memory for attribute parent "
57925331Samw 			    "name for %sattribute %s/%s of %s"),
57935331Samw 			    rw_sysattr ? gettext("system ") : "",
57945331Samw 			    attrparent, attr, longname);
57955331Samw 			return (1);
57965331Samw 		}
57975331Samw 	} else {
57985331Samw 		tparent = NULL;
57995331Samw 	}
58005331Samw 
58015331Samw 	/* path info */
58025331Samw 	pathlen = strlen(attr) + 1;
58035331Samw 	if (attrparent != NULL) {
58045331Samw 		pathlen += strlen(attrparent) + 1;	/* add 1 for '/' */
58055331Samw 	}
58065331Samw 	if ((tpath = calloc(1, pathlen)) == NULL) {
58075331Samw 		vperror(0, gettext(
58085331Samw 		    "unable to allocate memory for full "
58095331Samw 		    "attribute path name for %sattribute %s%s%s of %s"),
58105331Samw 		    rw_sysattr ? gettext("system ") : "",
58115331Samw 		    (attrparent == NULL) ? "" : attrparent,
58125331Samw 		    (attrparent == NULL) ? "" : "/",
58135331Samw 		    attr, longname);
58145331Samw 		if (tparent != NULL) {
58155331Samw 			free(tparent);
58165331Samw 		}
58175331Samw 		return (1);
58185331Samw 	}
58195331Samw 	(void) snprintf(tpath, pathlen, "%s%s%s",
58205331Samw 	    (attrparent == NULL) ? "" : attrparent,
58215331Samw 	    (attrparent == NULL) ? "" : "/",
58225331Samw 	    attr);
58235331Samw 
58245331Samw 	/* fill in the attribute info */
58255331Samw 	if (*attrinfo == NULL) {
58265331Samw 		if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
58275331Samw 			vperror(0, gettext(
58285331Samw 			    "unable to allocate memory for attribute "
58295331Samw 			    "information for %sattribute %s%s%s of %s"),
58305331Samw 			    rw_sysattr ? gettext("system ") : "",
58315331Samw 			    (attrparent == NULL) ? "" : attrparent,
58325331Samw 			    (attrparent == NULL) ? "" : gettext("/"),
58335331Samw 			    attr, longname);
58345331Samw 			if (tparent != NULL) {
58355331Samw 				free(tparent);
58365331Samw 			}
58375331Samw 			free(tpath);
58385331Samw 			return (1);
58395331Samw 		}
58405331Samw 	} else {
58415331Samw 		if ((*attrinfo)->attr_parent != NULL) {
58425331Samw 			free((*attrinfo)->attr_parent);
58435331Samw 		}
58445331Samw 		if ((*attrinfo)->attr_path != NULL) {
58455331Samw 			free((*attrinfo)->attr_path);
58465331Samw 		}
58475331Samw 		/*
58485331Samw 		 * The parent file descriptor is passed in, so don't
58495331Samw 		 * close it here as it should be closed by the function
58505331Samw 		 * that opened it.
58515331Samw 		 */
58525331Samw 	}
58535331Samw 	(*attrinfo)->attr_parent = tparent;
58545331Samw 	(*attrinfo)->attr_path = tpath;
58555331Samw 	(*attrinfo)->attr_rw_sysattr = rw_sysattr;
58565331Samw 	(*attrinfo)->attr_parentfd = atparentfd;
58575331Samw 
58585331Samw 	return (0);
58595331Samw }
58600Sstevel@tonic-gate 
58610Sstevel@tonic-gate /*
586212423Srich.burridge@oracle.com  * Test to see if name is a directory.
586312423Srich.burridge@oracle.com  *
586412423Srich.burridge@oracle.com  * Return 1 if true, 0 otherwise.
586512423Srich.burridge@oracle.com  */
586612423Srich.burridge@oracle.com 
586712423Srich.burridge@oracle.com static int
is_directory(char * name)586812423Srich.burridge@oracle.com is_directory(char *name)
586912423Srich.burridge@oracle.com {
587012423Srich.burridge@oracle.com #if defined(O_XATTR)
587112423Srich.burridge@oracle.com 	/*
587212423Srich.burridge@oracle.com 	 * If there is an xattr_buf structure associated with this file,
587312423Srich.burridge@oracle.com 	 * then the directory test is based on whether the name has a
587412423Srich.burridge@oracle.com 	 * trailing slash.
587512423Srich.burridge@oracle.com 	 */
587612423Srich.burridge@oracle.com 	if (xattrp)
587712423Srich.burridge@oracle.com 		return (name[strlen(name) - 1] == '/');
587812423Srich.burridge@oracle.com #endif
587912423Srich.burridge@oracle.com 	if (is_posix)
588012423Srich.burridge@oracle.com 		return (dblock.dbuf.typeflag == '5');
588112423Srich.burridge@oracle.com 	else
588212423Srich.burridge@oracle.com 		return (name[strlen(name) - 1] == '/');
588312423Srich.burridge@oracle.com }
588412423Srich.burridge@oracle.com 
588512423Srich.burridge@oracle.com /*
588612554Srich.burridge@oracle.com  * Version of chdir that handles directory pathnames of greater than PATH_MAX
588712554Srich.burridge@oracle.com  * length, by changing the working directory to manageable portions of the
588812554Srich.burridge@oracle.com  * complete directory pathname. If any of these attempts fail, then it exits
588912554Srich.burridge@oracle.com  * non-zero.
589012554Srich.burridge@oracle.com  *
589112554Srich.burridge@oracle.com  * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
589212554Srich.burridge@oracle.com  * pathname is greater than PATH_MAX, then this still won't work, and this
589312554Srich.burridge@oracle.com  * routine will return -1 with errno set to ENAMETOOLONG.
589412554Srich.burridge@oracle.com  *
589512554Srich.burridge@oracle.com  * NOTE: this routine is semantically different to the system chdir in
589612554Srich.burridge@oracle.com  * that it is remotely possible for the currently working directory to be
589712554Srich.burridge@oracle.com  * changed to a different directory, if a chdir call fails when processing
589812554Srich.burridge@oracle.com  * one of the segments of a path that is greater than PATH_MAX. This isn't
589912554Srich.burridge@oracle.com  * a problem as this is tar's own specific version of chdir.
590012554Srich.burridge@oracle.com  */
590112554Srich.burridge@oracle.com 
590212554Srich.burridge@oracle.com static int
tar_chdir(const char * path)590312554Srich.burridge@oracle.com tar_chdir(const char *path) {
590412554Srich.burridge@oracle.com 	const char *sep = "/";
590512554Srich.burridge@oracle.com 	char *path_copy = NULL;
590612554Srich.burridge@oracle.com 	char *ptr = NULL;
590712554Srich.burridge@oracle.com 
590812554Srich.burridge@oracle.com 	/* The trivial case. */
590912554Srich.burridge@oracle.com 	if (chdir(path) == 0) {
591012554Srich.burridge@oracle.com 		return (0);
591112554Srich.burridge@oracle.com 	}
591212554Srich.burridge@oracle.com 	if (errno == ENAMETOOLONG) {
591312554Srich.burridge@oracle.com 		if (path[0] == '/' && chdir(sep) != 0)
591412554Srich.burridge@oracle.com 			return (-1);
591512554Srich.burridge@oracle.com 
591612554Srich.burridge@oracle.com 		/* strtok(3C) modifies the string, so make a copy. */
591712554Srich.burridge@oracle.com 		if ((path_copy = strdup(path)) == NULL) {
591812554Srich.burridge@oracle.com 			return (-1);
591912554Srich.burridge@oracle.com 		}
592012554Srich.burridge@oracle.com 
592112554Srich.burridge@oracle.com 		/* chdir(2) for every path element. */
592212554Srich.burridge@oracle.com 		for (ptr = strtok(path_copy, sep);
592312554Srich.burridge@oracle.com 			ptr != NULL;
592412554Srich.burridge@oracle.com 			ptr = strtok(NULL, sep)) {
592512554Srich.burridge@oracle.com 			if (chdir(ptr) != 0) {
592612554Srich.burridge@oracle.com 				free(path_copy);
592712554Srich.burridge@oracle.com 				return (-1);
592812554Srich.burridge@oracle.com 			}
592912554Srich.burridge@oracle.com 		}
593012554Srich.burridge@oracle.com 		free(path_copy);
593112554Srich.burridge@oracle.com 		return (0);
593212554Srich.burridge@oracle.com 	}
593312554Srich.burridge@oracle.com 
593412554Srich.burridge@oracle.com 	/* If chdir fails for any reason except ENAMETOOLONG. */
593512554Srich.burridge@oracle.com 	return (-1);
593612554Srich.burridge@oracle.com }
593712554Srich.burridge@oracle.com 
593812554Srich.burridge@oracle.com /*
593912201Srich.burridge@sun.com  * Test if name has a '..' sequence in it.
594012201Srich.burridge@sun.com  *
594112201Srich.burridge@sun.com  * Return 1 if found, 0 otherwise.
594212201Srich.burridge@sun.com  */
594312201Srich.burridge@sun.com 
594412201Srich.burridge@sun.com static int
has_dot_dot(char * name)594512201Srich.burridge@sun.com has_dot_dot(char *name)
594612201Srich.burridge@sun.com {
594712201Srich.burridge@sun.com 	char *s;
594812201Srich.burridge@sun.com 	size_t name_len = strlen(name);
594912201Srich.burridge@sun.com 
595012201Srich.burridge@sun.com 	for (s = name; s < (name + name_len - 2); s++) {
595112201Srich.burridge@sun.com 		if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
595212201Srich.burridge@sun.com 			return (1);
595312201Srich.burridge@sun.com 
595412201Srich.burridge@sun.com 		while (! (*s == '/')) {
595512201Srich.burridge@sun.com 			if (! *s++)
595612201Srich.burridge@sun.com 				return (0);
595712201Srich.burridge@sun.com 		}
595812201Srich.burridge@sun.com 	}
595912201Srich.burridge@sun.com 
596012201Srich.burridge@sun.com 	return (0);
596112201Srich.burridge@sun.com }
596212201Srich.burridge@sun.com 
596312201Srich.burridge@sun.com /*
596412201Srich.burridge@sun.com  * Test if name is an absolute path name.
596512201Srich.burridge@sun.com  *
596612201Srich.burridge@sun.com  * Return 1 if true, 0 otherwise.
596712201Srich.burridge@sun.com  */
596812201Srich.burridge@sun.com 
596912201Srich.burridge@sun.com static int
is_absolute(char * name)597012201Srich.burridge@sun.com is_absolute(char *name)
597112201Srich.burridge@sun.com {
597212436Srich.burridge@oracle.com #if defined(O_XATTR)
597312436Srich.burridge@oracle.com 	/*
597412436Srich.burridge@oracle.com 	 * If this is an extended attribute (whose name will begin with
597512436Srich.burridge@oracle.com 	 * "/dev/null/", always return 0 as they should be extracted with
597612436Srich.burridge@oracle.com 	 * the name intact, to allow other tar archiving programs that
597712436Srich.burridge@oracle.com 	 * don't understand extended attributes, to correctly throw them away.
597812436Srich.burridge@oracle.com 	 */
597912436Srich.burridge@oracle.com 	if (xattrp)
598012436Srich.burridge@oracle.com 		return (0);
598112436Srich.burridge@oracle.com #endif
598212436Srich.burridge@oracle.com 
598312201Srich.burridge@sun.com 	return (name[0] == '/');
598412201Srich.burridge@sun.com }
598512201Srich.burridge@sun.com 
598612201Srich.burridge@sun.com /*
598712201Srich.burridge@sun.com  * Adjust the pathname to make it a relative one. Strip off any leading
598812201Srich.burridge@sun.com  * '/' characters and if the pathname contains any '..' sequences, strip
598912201Srich.burridge@sun.com  * upto and including the last occurance of '../' (or '..' if found at
599012201Srich.burridge@sun.com  * the very end of the pathname).
599112201Srich.burridge@sun.com  *
599212201Srich.burridge@sun.com  * Return the relative pathname. stripped_prefix will also return the
599312201Srich.burridge@sun.com  * portion of name that was stripped off and should be freed by the
599412201Srich.burridge@sun.com  * calling routine when no longer needed.
599512201Srich.burridge@sun.com  */
599612201Srich.burridge@sun.com 
599712201Srich.burridge@sun.com static char *
make_relative_name(char * name,char ** stripped_prefix)599812201Srich.burridge@sun.com make_relative_name(char *name, char **stripped_prefix)
599912201Srich.burridge@sun.com {
600012201Srich.burridge@sun.com 	char *s;
600112201Srich.burridge@sun.com 	size_t prefix_len = 0;
600212201Srich.burridge@sun.com 	size_t name_len = strlen(name);
600312201Srich.burridge@sun.com 
600412201Srich.burridge@sun.com 	for (s = name + prefix_len; s < (name + name_len - 2); ) {
600512201Srich.burridge@sun.com 		if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
600612201Srich.burridge@sun.com 			prefix_len = s + 2 - name;
600712201Srich.burridge@sun.com 
600812201Srich.burridge@sun.com 		do {
600912201Srich.burridge@sun.com 			char c = *s++;
601012201Srich.burridge@sun.com 
601112201Srich.burridge@sun.com 			if (c == '/')
601212201Srich.burridge@sun.com 				break;
601312201Srich.burridge@sun.com 		} while (*s);
601412201Srich.burridge@sun.com 	}
601512201Srich.burridge@sun.com 
601612201Srich.burridge@sun.com 	for (s = name + prefix_len; *s == '/'; s++)
601712201Srich.burridge@sun.com 		continue;
601812201Srich.burridge@sun.com 	prefix_len = s - name;
601912201Srich.burridge@sun.com 
602012201Srich.burridge@sun.com 	/* Create the portion of the name that was stripped off. */
602112201Srich.burridge@sun.com 	s = malloc(prefix_len + 1);
602212201Srich.burridge@sun.com 	memcpy(s, name, prefix_len);
602312201Srich.burridge@sun.com 	s[prefix_len] = 0;
602412201Srich.burridge@sun.com 	*stripped_prefix = s;
602512201Srich.burridge@sun.com 	s = &name[prefix_len];
602612201Srich.burridge@sun.com 
602712201Srich.burridge@sun.com 	return (s);
602812201Srich.burridge@sun.com }
602912201Srich.burridge@sun.com 
603012201Srich.burridge@sun.com /*
60310Sstevel@tonic-gate  *  Return through *namep a pointer to the proper fullname (i.e  "<name> |
60320Sstevel@tonic-gate  *  <prefix>/<name>"), as represented in the header entry dblock.dbuf.
60335331Samw  *
60345331Samw  * Returns 0 if successful, otherwise returns 1.
60350Sstevel@tonic-gate  */
60360Sstevel@tonic-gate 
60375331Samw static int
check_prefix(char ** namep,char ** dirp,char ** compp)60380Sstevel@tonic-gate check_prefix(char **namep, char **dirp, char **compp)
60390Sstevel@tonic-gate {
60400Sstevel@tonic-gate 	static char fullname[PATH_MAX + 1];
60410Sstevel@tonic-gate 	static char dir[PATH_MAX + 1];
60420Sstevel@tonic-gate 	static char component[PATH_MAX + 1];
60430Sstevel@tonic-gate 	static char savename[PATH_MAX + 1];
60440Sstevel@tonic-gate 	char *s;
60450Sstevel@tonic-gate 
60460Sstevel@tonic-gate 	(void) memset(dir, 0, sizeof (dir));
60470Sstevel@tonic-gate 	(void) memset(component, 0, sizeof (component));
60480Sstevel@tonic-gate 
60490Sstevel@tonic-gate 	if (xhdr_flgs & _X_PATH) {
60500Sstevel@tonic-gate 		(void) strcpy(fullname, Xtarhdr.x_path);
60510Sstevel@tonic-gate 	} else {
60520Sstevel@tonic-gate 		if (dblock.dbuf.prefix[0] != '\0')
60530Sstevel@tonic-gate 			(void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
60540Sstevel@tonic-gate 			    dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
60550Sstevel@tonic-gate 		else
60560Sstevel@tonic-gate 			(void) sprintf(fullname, "%.*s", NAMSIZ,
60570Sstevel@tonic-gate 			    dblock.dbuf.name);
60580Sstevel@tonic-gate 	}
60590Sstevel@tonic-gate 
60600Sstevel@tonic-gate 	/*
606112201Srich.burridge@sun.com 	 * If we are printing a table of contents or extracting an archive,
606212201Srich.burridge@sun.com 	 * make absolute pathnames relative and prohibit the unpacking of
606312201Srich.burridge@sun.com 	 * files contain ".." in their name (unless the user has supplied
606412201Srich.burridge@sun.com 	 * the -P option).
606512201Srich.burridge@sun.com 	 */
606612201Srich.burridge@sun.com 	if ((tflag || xflag) && !Pflag) {
606712201Srich.burridge@sun.com 		if (is_absolute(fullname) || has_dot_dot(fullname)) {
606812201Srich.burridge@sun.com 			char *stripped_prefix;
606912201Srich.burridge@sun.com 			size_t prefix_len = 0;
607012201Srich.burridge@sun.com 
607112201Srich.burridge@sun.com 			(void) strcpy(savename, fullname);
607212201Srich.burridge@sun.com 			strcpy(fullname,
607312201Srich.burridge@sun.com 			    make_relative_name(savename, &stripped_prefix));
607412201Srich.burridge@sun.com 			(void) fprintf(stderr,
607512201Srich.burridge@sun.com 			    gettext("tar: Removing leading '%s' from '%s'\n"),
607612201Srich.burridge@sun.com 			    stripped_prefix, savename);
607712201Srich.burridge@sun.com 			free(stripped_prefix);
607812201Srich.burridge@sun.com 		}
607912201Srich.burridge@sun.com 	}
608012201Srich.burridge@sun.com 
608112201Srich.burridge@sun.com 	/*
60820Sstevel@tonic-gate 	 * Set dir and component names
60830Sstevel@tonic-gate 	 */
60840Sstevel@tonic-gate 
60850Sstevel@tonic-gate 	get_parent(fullname, dir);
60860Sstevel@tonic-gate 
60870Sstevel@tonic-gate #if defined(O_XATTR)
60885331Samw 	if (xattrp == NULL) {
60890Sstevel@tonic-gate #endif
60900Sstevel@tonic-gate 		/*
60910Sstevel@tonic-gate 		 * Save of real name since were going to chop off the
60920Sstevel@tonic-gate 		 * trailing slashes.
60930Sstevel@tonic-gate 		 */
60940Sstevel@tonic-gate 		(void) strcpy(savename, fullname);
60950Sstevel@tonic-gate 		/*
60960Sstevel@tonic-gate 		 * first strip of trailing slashes.
60970Sstevel@tonic-gate 		 */
60980Sstevel@tonic-gate 		chop_endslashes(savename);
60990Sstevel@tonic-gate 		s = get_component(savename);
61000Sstevel@tonic-gate 		(void) strcpy(component, s);
61010Sstevel@tonic-gate 
61020Sstevel@tonic-gate #if defined(O_XATTR)
61030Sstevel@tonic-gate 	} else {
61040Sstevel@tonic-gate 		(void) strcpy(fullname, xattrp->h_names);
61050Sstevel@tonic-gate 		(void) strcpy(dir, fullname);
61065331Samw 		(void) strcpy(component, basename(xattrp->h_names +
61075331Samw 		    strlen(xattrp->h_names) + 1));
61080Sstevel@tonic-gate 	}
61090Sstevel@tonic-gate #endif
61100Sstevel@tonic-gate 	*namep = fullname;
61110Sstevel@tonic-gate 	*dirp = dir;
61120Sstevel@tonic-gate 	*compp = component;
61135331Samw 
61145331Samw 	return (0);
61150Sstevel@tonic-gate }
61160Sstevel@tonic-gate 
61170Sstevel@tonic-gate /*
61180Sstevel@tonic-gate  * Return true if the object indicated by the file descriptor and type
61190Sstevel@tonic-gate  * is a tape device, false otherwise
61200Sstevel@tonic-gate  */
61210Sstevel@tonic-gate 
61220Sstevel@tonic-gate static int
istape(int fd,int type)61230Sstevel@tonic-gate istape(int fd, int type)
61240Sstevel@tonic-gate {
61250Sstevel@tonic-gate 	int result = 0;
61260Sstevel@tonic-gate 
6127871Scasper 	if (S_ISCHR(type)) {
61280Sstevel@tonic-gate 		struct mtget mtg;
61290Sstevel@tonic-gate 
61300Sstevel@tonic-gate 		if (ioctl(fd, MTIOCGET, &mtg) != -1) {
61310Sstevel@tonic-gate 			result = 1;
61320Sstevel@tonic-gate 		}
61330Sstevel@tonic-gate 	}
61340Sstevel@tonic-gate 
61350Sstevel@tonic-gate 	return (result);
61360Sstevel@tonic-gate }
61370Sstevel@tonic-gate 
61380Sstevel@tonic-gate #include <utmpx.h>
61390Sstevel@tonic-gate 
61400Sstevel@tonic-gate struct utmpx utmpx;
61410Sstevel@tonic-gate 
61420Sstevel@tonic-gate #define	NMAX	(sizeof (utmpx.ut_name))
61430Sstevel@tonic-gate 
61440Sstevel@tonic-gate typedef struct cachenode {	/* this struct must be zeroed before using */
61450Sstevel@tonic-gate 	struct cachenode *next;	/* next in hash chain */
61460Sstevel@tonic-gate 	int val;		/* the uid or gid of this entry */
61470Sstevel@tonic-gate 	int namehash;		/* name's hash signature */
61480Sstevel@tonic-gate 	char name[NMAX+1];	/* the string that val maps to */
61490Sstevel@tonic-gate } cachenode_t;
61500Sstevel@tonic-gate 
61510Sstevel@tonic-gate #define	HASHSIZE	256
61520Sstevel@tonic-gate 
61530Sstevel@tonic-gate static cachenode_t *names[HASHSIZE];
61540Sstevel@tonic-gate static cachenode_t *groups[HASHSIZE];
61550Sstevel@tonic-gate static cachenode_t *uids[HASHSIZE];
61560Sstevel@tonic-gate static cachenode_t *gids[HASHSIZE];
61570Sstevel@tonic-gate 
61580Sstevel@tonic-gate static int
hash_byname(char * name)61590Sstevel@tonic-gate hash_byname(char *name)
61600Sstevel@tonic-gate {
61610Sstevel@tonic-gate 	int i, c, h = 0;
61620Sstevel@tonic-gate 
61630Sstevel@tonic-gate 	for (i = 0; i < NMAX; i++) {
61640Sstevel@tonic-gate 		c = name[i];
61650Sstevel@tonic-gate 		if (c == '\0')
61660Sstevel@tonic-gate 			break;
61670Sstevel@tonic-gate 		h = (h << 4) + h + c;
61680Sstevel@tonic-gate 	}
61690Sstevel@tonic-gate 	return (h);
61700Sstevel@tonic-gate }
61710Sstevel@tonic-gate 
61720Sstevel@tonic-gate static cachenode_t *
hash_lookup_byval(cachenode_t * table[],int val)61730Sstevel@tonic-gate hash_lookup_byval(cachenode_t *table[], int val)
61740Sstevel@tonic-gate {
61750Sstevel@tonic-gate 	int h = val;
61760Sstevel@tonic-gate 	cachenode_t *c;
61770Sstevel@tonic-gate 
61780Sstevel@tonic-gate 	for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
61790Sstevel@tonic-gate 		if (c->val == val)
61800Sstevel@tonic-gate 			return (c);
61810Sstevel@tonic-gate 	}
61820Sstevel@tonic-gate 	return (NULL);
61830Sstevel@tonic-gate }
61840Sstevel@tonic-gate 
61850Sstevel@tonic-gate static cachenode_t *
hash_lookup_byname(cachenode_t * table[],char * name)61860Sstevel@tonic-gate hash_lookup_byname(cachenode_t *table[], char *name)
61870Sstevel@tonic-gate {
61880Sstevel@tonic-gate 	int h = hash_byname(name);
61890Sstevel@tonic-gate 	cachenode_t *c;
61900Sstevel@tonic-gate 
61910Sstevel@tonic-gate 	for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
61920Sstevel@tonic-gate 		if (c->namehash == h && strcmp(c->name, name) == 0)
61930Sstevel@tonic-gate 			return (c);
61940Sstevel@tonic-gate 	}
61950Sstevel@tonic-gate 	return (NULL);
61960Sstevel@tonic-gate }
61970Sstevel@tonic-gate 
61980Sstevel@tonic-gate static cachenode_t *
hash_insert(cachenode_t * table[],char * name,int value)61990Sstevel@tonic-gate hash_insert(cachenode_t *table[], char *name, int value)
62000Sstevel@tonic-gate {
62010Sstevel@tonic-gate 	cachenode_t *c;
62020Sstevel@tonic-gate 	int signature;
62030Sstevel@tonic-gate 
62040Sstevel@tonic-gate 	c = calloc(1, sizeof (cachenode_t));
62050Sstevel@tonic-gate 	if (c == NULL) {
62060Sstevel@tonic-gate 		perror("malloc");
62070Sstevel@tonic-gate 		exit(1);
62080Sstevel@tonic-gate 	}
62090Sstevel@tonic-gate 	if (name != NULL) {
62100Sstevel@tonic-gate 		(void) strncpy(c->name, name, NMAX);
62110Sstevel@tonic-gate 		c->namehash = hash_byname(name);
62120Sstevel@tonic-gate 	}
62130Sstevel@tonic-gate 	c->val = value;
62140Sstevel@tonic-gate 	if (table == uids || table == gids)
62150Sstevel@tonic-gate 		signature = c->val;
62160Sstevel@tonic-gate 	else
62170Sstevel@tonic-gate 		signature = c->namehash;
62180Sstevel@tonic-gate 	c->next = table[signature & (HASHSIZE - 1)];
62190Sstevel@tonic-gate 	table[signature & (HASHSIZE - 1)] = c;
62200Sstevel@tonic-gate 	return (c);
62210Sstevel@tonic-gate }
62220Sstevel@tonic-gate 
62230Sstevel@tonic-gate static char *
getname(uid_t uid)62240Sstevel@tonic-gate getname(uid_t uid)
62250Sstevel@tonic-gate {
62260Sstevel@tonic-gate 	cachenode_t *c;
62270Sstevel@tonic-gate 
62280Sstevel@tonic-gate 	if ((c = hash_lookup_byval(uids, uid)) == NULL) {
62290Sstevel@tonic-gate 		struct passwd *pwent = getpwuid(uid);
62300Sstevel@tonic-gate 		c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
62310Sstevel@tonic-gate 	}
62320Sstevel@tonic-gate 	return (c->name);
62330Sstevel@tonic-gate }
62340Sstevel@tonic-gate 
62350Sstevel@tonic-gate static char *
getgroup(gid_t gid)62360Sstevel@tonic-gate getgroup(gid_t gid)
62370Sstevel@tonic-gate {
62380Sstevel@tonic-gate 	cachenode_t *c;
62390Sstevel@tonic-gate 
62400Sstevel@tonic-gate 	if ((c = hash_lookup_byval(gids, gid)) == NULL) {
62410Sstevel@tonic-gate 		struct group *grent = getgrgid(gid);
62420Sstevel@tonic-gate 		c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
62430Sstevel@tonic-gate 	}
62440Sstevel@tonic-gate 	return (c->name);
62450Sstevel@tonic-gate }
62460Sstevel@tonic-gate 
62470Sstevel@tonic-gate static uid_t
getuidbyname(char * name)62480Sstevel@tonic-gate getuidbyname(char *name)
62490Sstevel@tonic-gate {
62500Sstevel@tonic-gate 	cachenode_t *c;
62510Sstevel@tonic-gate 
62520Sstevel@tonic-gate 	if ((c = hash_lookup_byname(names, name)) == NULL) {
62530Sstevel@tonic-gate 		struct passwd *pwent = getpwnam(name);
62540Sstevel@tonic-gate 		c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
62550Sstevel@tonic-gate 	}
62560Sstevel@tonic-gate 	return ((uid_t)c->val);
62570Sstevel@tonic-gate }
62580Sstevel@tonic-gate 
62590Sstevel@tonic-gate static gid_t
getgidbyname(char * group)62600Sstevel@tonic-gate getgidbyname(char *group)
62610Sstevel@tonic-gate {
62620Sstevel@tonic-gate 	cachenode_t *c;
62630Sstevel@tonic-gate 
62640Sstevel@tonic-gate 	if ((c = hash_lookup_byname(groups, group)) == NULL) {
62650Sstevel@tonic-gate 		struct group *grent = getgrnam(group);
62660Sstevel@tonic-gate 		c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
62670Sstevel@tonic-gate 	}
62680Sstevel@tonic-gate 	return ((gid_t)c->val);
62690Sstevel@tonic-gate }
62700Sstevel@tonic-gate 
62710Sstevel@tonic-gate /*
62720Sstevel@tonic-gate  * Build the header.
62730Sstevel@tonic-gate  * Determine whether or not an extended header is also needed.  If needed,
62740Sstevel@tonic-gate  * create and write the extended header and its data.
62750Sstevel@tonic-gate  * Writing of the extended header assumes that "tomodes" has been called and
62760Sstevel@tonic-gate  * the relevant information has been placed in the header block.
62770Sstevel@tonic-gate  */
62780Sstevel@tonic-gate 
62790Sstevel@tonic-gate static int
build_dblock(const char * name,const char * linkname,const char typeflag,const int filetype,const struct stat * sp,const dev_t device,const char * prefix)62800Sstevel@tonic-gate build_dblock(
62810Sstevel@tonic-gate 	const char		*name,
62820Sstevel@tonic-gate 	const char		*linkname,
62830Sstevel@tonic-gate 	const char		typeflag,
62840Sstevel@tonic-gate 	const int		filetype,
62850Sstevel@tonic-gate 	const struct stat	*sp,
62860Sstevel@tonic-gate 	const dev_t		device,
62870Sstevel@tonic-gate 	const char		*prefix)
62880Sstevel@tonic-gate {
62890Sstevel@tonic-gate 	int nblks;
62900Sstevel@tonic-gate 	major_t		dev;
62910Sstevel@tonic-gate 	const char	*filename;
62920Sstevel@tonic-gate 	const char	*lastslash;
62930Sstevel@tonic-gate 
62940Sstevel@tonic-gate 	if (filetype == XATTR_FILE)
62950Sstevel@tonic-gate 		dblock.dbuf.typeflag = _XATTR_HDRTYPE;
62960Sstevel@tonic-gate 	else
62970Sstevel@tonic-gate 		dblock.dbuf.typeflag = typeflag;
62980Sstevel@tonic-gate 	(void) memset(dblock.dbuf.name, '\0', NAMSIZ);
62990Sstevel@tonic-gate 	(void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
63000Sstevel@tonic-gate 	(void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
63010Sstevel@tonic-gate 
63020Sstevel@tonic-gate 	if (xhdr_flgs & _X_PATH)
63030Sstevel@tonic-gate 		filename = Xtarhdr.x_path;
63040Sstevel@tonic-gate 	else
63050Sstevel@tonic-gate 		filename = name;
63060Sstevel@tonic-gate 
63070Sstevel@tonic-gate 	if ((dev = major(device)) > OCTAL7CHAR) {
63080Sstevel@tonic-gate 		if (Eflag) {
63090Sstevel@tonic-gate 			xhdr_flgs |= _X_DEVMAJOR;
63100Sstevel@tonic-gate 			Xtarhdr.x_devmajor = dev;
63110Sstevel@tonic-gate 		} else {
63120Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
63130Sstevel@tonic-gate 			    "Device major too large for %s.  Use -E flag."),
63140Sstevel@tonic-gate 			    filename);
63150Sstevel@tonic-gate 			if (errflag)
63160Sstevel@tonic-gate 				done(1);
63170Sstevel@tonic-gate 			else
63180Sstevel@tonic-gate 				Errflg = 1;
63190Sstevel@tonic-gate 		}
63200Sstevel@tonic-gate 		dev = 0;
63210Sstevel@tonic-gate 	}
63220Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
63230Sstevel@tonic-gate 	if ((dev = minor(device)) > OCTAL7CHAR) {
63240Sstevel@tonic-gate 		if (Eflag) {
63250Sstevel@tonic-gate 			xhdr_flgs |= _X_DEVMINOR;
63260Sstevel@tonic-gate 			Xtarhdr.x_devminor = dev;
63270Sstevel@tonic-gate 		} else {
63280Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
63290Sstevel@tonic-gate 			    "Device minor too large for %s.  Use -E flag."),
63300Sstevel@tonic-gate 			    filename);
63310Sstevel@tonic-gate 			if (errflag)
63320Sstevel@tonic-gate 				done(1);
63330Sstevel@tonic-gate 			else
63340Sstevel@tonic-gate 				Errflg = 1;
63350Sstevel@tonic-gate 		}
63360Sstevel@tonic-gate 		dev = 0;
63370Sstevel@tonic-gate 	}
63380Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
63390Sstevel@tonic-gate 
63400Sstevel@tonic-gate 	(void) strncpy(dblock.dbuf.name, name, NAMSIZ);
63410Sstevel@tonic-gate 	(void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
63420Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
63430Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.version, "00");
63440Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
63450Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
63460Sstevel@tonic-gate 	(void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
63470Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
63480Sstevel@tonic-gate 
63490Sstevel@tonic-gate 	if (Eflag) {
63500Sstevel@tonic-gate 		(void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
63510Sstevel@tonic-gate 		(void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
63520Sstevel@tonic-gate 		lastslash = strrchr(name, '/');
63530Sstevel@tonic-gate 		if (lastslash == NULL)
63540Sstevel@tonic-gate 			lastslash = name;
63550Sstevel@tonic-gate 		else
63560Sstevel@tonic-gate 			lastslash++;
63570Sstevel@tonic-gate 		(void) strcpy(xhdr_buf.dbuf.name, lastslash);
63580Sstevel@tonic-gate 		(void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
63590Sstevel@tonic-gate 		(void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
63600Sstevel@tonic-gate 		(void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
63610Sstevel@tonic-gate 		xhdr_count++;
63620Sstevel@tonic-gate 		xrec_offset = 0;
63630Sstevel@tonic-gate 		gen_date("mtime", sp->st_mtim);
63640Sstevel@tonic-gate 		xhdr_buf.dbuf.typeflag = 'X';
63650Sstevel@tonic-gate 		if (gen_utf8_names(filename) != 0)
63660Sstevel@tonic-gate 			return (1);
63670Sstevel@tonic-gate 
63680Sstevel@tonic-gate #ifdef XHDR_DEBUG
63690Sstevel@tonic-gate 		Xtarhdr.x_uname = dblock.dbuf.uname;
63700Sstevel@tonic-gate 		Xtarhdr.x_gname = dblock.dbuf.gname;
63710Sstevel@tonic-gate 		xhdr_flgs |= (_X_UNAME | _X_GNAME);
63720Sstevel@tonic-gate #endif
63730Sstevel@tonic-gate 		if (xhdr_flgs) {
63740Sstevel@tonic-gate 			if (xhdr_flgs & _X_DEVMAJOR)
63750Sstevel@tonic-gate 				gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
63760Sstevel@tonic-gate 			if (xhdr_flgs & _X_DEVMINOR)
63770Sstevel@tonic-gate 				gen_num("SUN.devminor", Xtarhdr.x_devminor);
63780Sstevel@tonic-gate 			if (xhdr_flgs & _X_GID)
63790Sstevel@tonic-gate 				gen_num("gid", Xtarhdr.x_gid);
63800Sstevel@tonic-gate 			if (xhdr_flgs & _X_UID)
63810Sstevel@tonic-gate 				gen_num("uid", Xtarhdr.x_uid);
63820Sstevel@tonic-gate 			if (xhdr_flgs & _X_SIZE)
63830Sstevel@tonic-gate 				gen_num("size", Xtarhdr.x_filesz);
63840Sstevel@tonic-gate 			if (xhdr_flgs & _X_PATH)
63850Sstevel@tonic-gate 				gen_string("path", Xtarhdr.x_path);
63860Sstevel@tonic-gate 			if (xhdr_flgs & _X_LINKPATH)
63870Sstevel@tonic-gate 				gen_string("linkpath", Xtarhdr.x_linkpath);
63880Sstevel@tonic-gate 			if (xhdr_flgs & _X_GNAME)
63890Sstevel@tonic-gate 				gen_string("gname", Xtarhdr.x_gname);
63900Sstevel@tonic-gate 			if (xhdr_flgs & _X_UNAME)
63910Sstevel@tonic-gate 				gen_string("uname", Xtarhdr.x_uname);
63920Sstevel@tonic-gate 		}
63930Sstevel@tonic-gate 		(void) sprintf(xhdr_buf.dbuf.size,
63940Sstevel@tonic-gate 		    "%011" FMT_off_t_o, xrec_offset);
63950Sstevel@tonic-gate 		(void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
63960Sstevel@tonic-gate 		    checksum(&xhdr_buf));
63970Sstevel@tonic-gate 		(void) writetbuf((char *)&xhdr_buf, 1);
63980Sstevel@tonic-gate 		nblks = TBLOCKS(xrec_offset);
63990Sstevel@tonic-gate 		(void) writetbuf(xrec_ptr, nblks);
64000Sstevel@tonic-gate 	}
64010Sstevel@tonic-gate 	return (0);
64020Sstevel@tonic-gate }
64030Sstevel@tonic-gate 
64040Sstevel@tonic-gate 
64050Sstevel@tonic-gate /*
64060Sstevel@tonic-gate  *  makeDir - ensure that a directory with the pathname denoted by name
64070Sstevel@tonic-gate  *            exists, and return 1 on success, and 0 on failure (e.g.,
64080Sstevel@tonic-gate  *	      read-only file system, exists but not-a-directory).
64090Sstevel@tonic-gate  */
64100Sstevel@tonic-gate 
64110Sstevel@tonic-gate static int
makeDir(char * name)64120Sstevel@tonic-gate makeDir(char *name)
64130Sstevel@tonic-gate {
64140Sstevel@tonic-gate 	struct stat buf;
64150Sstevel@tonic-gate 
64160Sstevel@tonic-gate 	if (access(name, 0) < 0) {  /* name doesn't exist */
64170Sstevel@tonic-gate 		if (mkdir(name, 0777) < 0) {
64180Sstevel@tonic-gate 			vperror(0, "%s", name);
64190Sstevel@tonic-gate 			return (0);
64200Sstevel@tonic-gate 		}
64210Sstevel@tonic-gate 	} else {		   /* name exists */
64220Sstevel@tonic-gate 		if (stat(name, &buf) < 0) {
64230Sstevel@tonic-gate 			vperror(0, "%s", name);
64240Sstevel@tonic-gate 			return (0);
64250Sstevel@tonic-gate 		}
64260Sstevel@tonic-gate 
64270Sstevel@tonic-gate 		return ((buf.st_mode & S_IFMT) == S_IFDIR);
64280Sstevel@tonic-gate 	}
64290Sstevel@tonic-gate 
64300Sstevel@tonic-gate 	return (1);
64310Sstevel@tonic-gate }
64320Sstevel@tonic-gate 
64330Sstevel@tonic-gate 
64340Sstevel@tonic-gate /*
64350Sstevel@tonic-gate  * Save this directory and its mtime on the stack, popping and setting
64360Sstevel@tonic-gate  * the mtimes of any stacked dirs which aren't parents of this one.
64370Sstevel@tonic-gate  * A null name causes the entire stack to be unwound and set.
64380Sstevel@tonic-gate  *
64390Sstevel@tonic-gate  * Since all the elements of the directory "stack" share a common
64400Sstevel@tonic-gate  * prefix, we can make do with one string.  We keep only the current
64410Sstevel@tonic-gate  * directory path, with an associated array of mtime's. A negative
64420Sstevel@tonic-gate  * mtime means no mtime.
64430Sstevel@tonic-gate  *
64440Sstevel@tonic-gate  * This stack algorithm is not guaranteed to work for tapes created
64450Sstevel@tonic-gate  * with the 'r' function letter, but the vast majority of tapes with
64460Sstevel@tonic-gate  * directories are not.  This avoids saving every directory record on
64470Sstevel@tonic-gate  * the tape and setting all the times at the end.
64480Sstevel@tonic-gate  *
64490Sstevel@tonic-gate  * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
64500Sstevel@tonic-gate  *  environment)
64510Sstevel@tonic-gate  */
64520Sstevel@tonic-gate 
64530Sstevel@tonic-gate static void
doDirTimes(char * name,timestruc_t modTime)64540Sstevel@tonic-gate doDirTimes(char *name, timestruc_t modTime)
64550Sstevel@tonic-gate {
64560Sstevel@tonic-gate 	static char dirstack[PATH_MAX+2];
64570Sstevel@tonic-gate 			/* Add spaces for the last slash and last NULL */
64580Sstevel@tonic-gate 	static timestruc_t	modtimes[PATH_MAX+1]; /* hash table */
64590Sstevel@tonic-gate 	char *p = dirstack;
64600Sstevel@tonic-gate 	char *q = name;
64610Sstevel@tonic-gate 	char *savp;
64620Sstevel@tonic-gate 
64630Sstevel@tonic-gate 	if (q) {
64640Sstevel@tonic-gate 		/*
64650Sstevel@tonic-gate 		 * Find common prefix
64660Sstevel@tonic-gate 		 */
64670Sstevel@tonic-gate 
64680Sstevel@tonic-gate 		while (*p == *q && *p) {
64690Sstevel@tonic-gate 			p++; q++;
64700Sstevel@tonic-gate 		}
64710Sstevel@tonic-gate 	}
64720Sstevel@tonic-gate 
64730Sstevel@tonic-gate 	savp = p;
64740Sstevel@tonic-gate 	while (*p) {
64750Sstevel@tonic-gate 		/*
64760Sstevel@tonic-gate 		 * Not a child: unwind the stack, setting the times.
64770Sstevel@tonic-gate 		 * The order we do this doesn't matter, so we go "forward."
64780Sstevel@tonic-gate 		 */
64790Sstevel@tonic-gate 
64800Sstevel@tonic-gate 		if (*p == '/')
64810Sstevel@tonic-gate 			if (modtimes[p - dirstack].tv_sec >= 0) {
64820Sstevel@tonic-gate 				*p = '\0';	 /* zap the slash */
64830Sstevel@tonic-gate 				setPathTimes(AT_FDCWD, dirstack,
64841266Sceastha 				    modtimes[p - dirstack]);
64850Sstevel@tonic-gate 				*p = '/';
64860Sstevel@tonic-gate 			}
64870Sstevel@tonic-gate 		++p;
64880Sstevel@tonic-gate 	}
64890Sstevel@tonic-gate 
64900Sstevel@tonic-gate 	p = savp;
64910Sstevel@tonic-gate 
64920Sstevel@tonic-gate 	/*
64930Sstevel@tonic-gate 	 *  Push this one on the "stack"
64940Sstevel@tonic-gate 	 */
64950Sstevel@tonic-gate 
64960Sstevel@tonic-gate 	if (q) {
64970Sstevel@tonic-gate 
64980Sstevel@tonic-gate 		/*
64990Sstevel@tonic-gate 		 * Since the name parameter points the dir pathname
65000Sstevel@tonic-gate 		 * which is limited only to contain PATH_MAX chars
65010Sstevel@tonic-gate 		 * at maximum, we can ignore the overflow case of p.
65020Sstevel@tonic-gate 		 */
65030Sstevel@tonic-gate 
65040Sstevel@tonic-gate 		while ((*p = *q++)) {	/* append the rest of the new dir */
65050Sstevel@tonic-gate 			modtimes[p - dirstack].tv_sec = -1;
65060Sstevel@tonic-gate 			p++;
65070Sstevel@tonic-gate 		}
65080Sstevel@tonic-gate 
65090Sstevel@tonic-gate 		/*
65100Sstevel@tonic-gate 		 * If the tar file had used 'P' or 'E' function modifier,
65110Sstevel@tonic-gate 		 * append the last slash.
65120Sstevel@tonic-gate 		 */
65130Sstevel@tonic-gate 		if (*(p - 1) != '/') {
65140Sstevel@tonic-gate 			*p++ = '/';
65150Sstevel@tonic-gate 			*p = '\0';
65160Sstevel@tonic-gate 		}
65170Sstevel@tonic-gate 		/* overwrite the last one */
65180Sstevel@tonic-gate 		modtimes[p - dirstack - 1] = modTime;
65190Sstevel@tonic-gate 	}
65200Sstevel@tonic-gate }
65210Sstevel@tonic-gate 
65220Sstevel@tonic-gate 
65230Sstevel@tonic-gate /*
65240Sstevel@tonic-gate  *  setPathTimes - set the modification time for given path.  Return 1 if
65250Sstevel@tonic-gate  *                 successful and 0 if not successful.
65260Sstevel@tonic-gate  */
65270Sstevel@tonic-gate 
65280Sstevel@tonic-gate static void
setPathTimes(int dirfd,char * path,timestruc_t modTime)65290Sstevel@tonic-gate setPathTimes(int dirfd, char *path, timestruc_t modTime)
65300Sstevel@tonic-gate 
65310Sstevel@tonic-gate {
65320Sstevel@tonic-gate 	struct timeval timebuf[2];
65330Sstevel@tonic-gate 
65340Sstevel@tonic-gate 	/*
65350Sstevel@tonic-gate 	 * futimesat takes an array of two timeval structs.
65360Sstevel@tonic-gate 	 * The first entry contains access time.
65370Sstevel@tonic-gate 	 * The second entry contains modification time.
65380Sstevel@tonic-gate 	 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
65390Sstevel@tonic-gate 	 * microseconds.
65400Sstevel@tonic-gate 	 */
65410Sstevel@tonic-gate 	timebuf[0].tv_sec = time((time_t *)0);
65420Sstevel@tonic-gate 	timebuf[0].tv_usec = 0;
65430Sstevel@tonic-gate 	timebuf[1].tv_sec = modTime.tv_sec;
65440Sstevel@tonic-gate 
65450Sstevel@tonic-gate 	/* Extended header: use microseconds */
65460Sstevel@tonic-gate 	timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
65470Sstevel@tonic-gate 
65480Sstevel@tonic-gate 	if (futimesat(dirfd, path, timebuf) < 0)
654912305Srich.burridge@sun.com 		vperror(0, gettext("can't set time on %s"), path);
65500Sstevel@tonic-gate }
65510Sstevel@tonic-gate 
65520Sstevel@tonic-gate 
65530Sstevel@tonic-gate /*
65540Sstevel@tonic-gate  * If hflag is set then delete the symbolic link's target.
65550Sstevel@tonic-gate  * If !hflag then delete the target.
65560Sstevel@tonic-gate  */
65570Sstevel@tonic-gate 
65580Sstevel@tonic-gate static void
delete_target(int fd,char * comp,char * namep)65593805Slovely delete_target(int fd, char *comp, char *namep)
65600Sstevel@tonic-gate {
65610Sstevel@tonic-gate 	struct	stat	xtractbuf;
65620Sstevel@tonic-gate 	char buf[PATH_MAX + 1];
65630Sstevel@tonic-gate 	int n;
65640Sstevel@tonic-gate 
65650Sstevel@tonic-gate 
65663805Slovely 	if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
65670Sstevel@tonic-gate 		if (errno == ENOTDIR && !hflag) {
65683805Slovely 			(void) unlinkat(fd, comp, 0);
65690Sstevel@tonic-gate 		} else if (errno == ENOTDIR && hflag) {
65700Sstevel@tonic-gate 			if (!lstat(namep, &xtractbuf)) {
65710Sstevel@tonic-gate 				if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
65723805Slovely 					(void) unlinkat(fd, comp, 0);
65730Sstevel@tonic-gate 				} else if ((n = readlink(namep, buf,
65741266Sceastha 				    PATH_MAX)) != -1) {
65750Sstevel@tonic-gate 					buf[n] = (char)NULL;
65760Sstevel@tonic-gate 					(void) unlinkat(fd, buf,
65771266Sceastha 					    AT_REMOVEDIR);
65780Sstevel@tonic-gate 					if (errno == ENOTDIR)
65790Sstevel@tonic-gate 						(void) unlinkat(fd, buf, 0);
65800Sstevel@tonic-gate 				} else {
65813805Slovely 					(void) unlinkat(fd, comp, 0);
65820Sstevel@tonic-gate 				}
65830Sstevel@tonic-gate 			} else {
65843805Slovely 				(void) unlinkat(fd, comp, 0);
65850Sstevel@tonic-gate 			}
65860Sstevel@tonic-gate 		}
65870Sstevel@tonic-gate 	}
65880Sstevel@tonic-gate }
65890Sstevel@tonic-gate 
65900Sstevel@tonic-gate 
65910Sstevel@tonic-gate /*
65920Sstevel@tonic-gate  * ACL changes:
65930Sstevel@tonic-gate  *	putfile():
65940Sstevel@tonic-gate  *		Get acl info after stat. Write out ancillary file
65950Sstevel@tonic-gate  *		before the normal file, i.e. directory, regular, FIFO,
65960Sstevel@tonic-gate  *		link, special. If acl count is less than 4, no need to
65970Sstevel@tonic-gate  *		create ancillary file. (i.e. standard permission is in
65980Sstevel@tonic-gate  *		use.
65990Sstevel@tonic-gate  *	doxtract():
66000Sstevel@tonic-gate  *		Process ancillary file. Read it in and set acl info.
66010Sstevel@tonic-gate  *		watch out for 'o' function modifier.
66020Sstevel@tonic-gate  *	't' function letter to display table
66030Sstevel@tonic-gate  */
66040Sstevel@tonic-gate 
66050Sstevel@tonic-gate /*
66060Sstevel@tonic-gate  * New functions for ACLs and other security attributes
66070Sstevel@tonic-gate  */
66080Sstevel@tonic-gate 
66090Sstevel@tonic-gate /*
66100Sstevel@tonic-gate  * The function appends the new security attribute info to the end of
66110Sstevel@tonic-gate  * existing secinfo.
66120Sstevel@tonic-gate  */
66130Sstevel@tonic-gate int
append_secattr(char ** secinfo,int * secinfo_len,int size,char * attrtext,char attr_type)66140Sstevel@tonic-gate append_secattr(
66150Sstevel@tonic-gate 	char	 **secinfo,	/* existing security info */
66160Sstevel@tonic-gate 	int	 *secinfo_len,	/* length of existing security info */
66171676Sjpk 	int	 size,		/* new attribute size: unit depends on type */
66181676Sjpk 	char	*attrtext,	/* new attribute text */
66191676Sjpk 	char	 attr_type)	/* new attribute type */
66200Sstevel@tonic-gate {
66210Sstevel@tonic-gate 	char	*new_secinfo;
66220Sstevel@tonic-gate 	int	newattrsize;
66230Sstevel@tonic-gate 	int	oldsize;
66241676Sjpk 	struct sec_attr	*attr;
66250Sstevel@tonic-gate 
66260Sstevel@tonic-gate 	/* no need to add */
66271676Sjpk 	if (attr_type != DIR_TYPE) {
66281676Sjpk 		if (attrtext == NULL)
66291676Sjpk 			return (0);
66301676Sjpk 	}
66311676Sjpk 
66321676Sjpk 	switch (attr_type) {
66331676Sjpk 	case UFSD_ACL:
66341676Sjpk 	case ACE_ACL:
66350Sstevel@tonic-gate 		if (attrtext == NULL) {
663612305Srich.burridge@sun.com 			(void) fprintf(stderr, gettext("acltotext failed\n"));
66370Sstevel@tonic-gate 			return (-1);
66380Sstevel@tonic-gate 		}
66390Sstevel@tonic-gate 		/* header: type + size = 8 */
66400Sstevel@tonic-gate 		newattrsize = 8 + (int)strlen(attrtext) + 1;
66410Sstevel@tonic-gate 		attr = (struct sec_attr *)malloc(newattrsize);
66420Sstevel@tonic-gate 		if (attr == NULL) {
664312305Srich.burridge@sun.com 			(void) fprintf(stderr,
664412305Srich.burridge@sun.com 			    gettext("can't allocate memory\n"));
66450Sstevel@tonic-gate 			return (-1);
66460Sstevel@tonic-gate 		}
66471676Sjpk 		attr->attr_type = attr_type;
66480Sstevel@tonic-gate 		(void) sprintf(attr->attr_len,
66491676Sjpk 		    "%06o", size); /* acl entry count */
66500Sstevel@tonic-gate 		(void) strcpy((char *)&attr->attr_info[0], attrtext);
66510Sstevel@tonic-gate 		free(attrtext);
66520Sstevel@tonic-gate 		break;
66530Sstevel@tonic-gate 
66541676Sjpk 	/* Trusted Extensions */
66551676Sjpk 	case DIR_TYPE:
66561676Sjpk 	case LBL_TYPE:
66571676Sjpk 		newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
66581676Sjpk 		attr = (struct sec_attr *)malloc(newattrsize);
66591676Sjpk 		if (attr == NULL) {
66601676Sjpk 			(void) fprintf(stderr,
66611676Sjpk 			gettext("can't allocate memory\n"));
66621676Sjpk 			return (-1);
66631676Sjpk 		}
66641676Sjpk 		attr->attr_type = attr_type;
66651676Sjpk 		(void) sprintf(attr->attr_len,
66661676Sjpk 		    "%06d", size); /* len of attr data */
66671676Sjpk 		(void) strcpy((char *)&attr->attr_info[0], attrtext);
66681676Sjpk 		break;
66690Sstevel@tonic-gate 
66700Sstevel@tonic-gate 	default:
667112305Srich.burridge@sun.com 		(void) fprintf(stderr,
667212305Srich.burridge@sun.com 		    gettext("unrecognized attribute type\n"));
66730Sstevel@tonic-gate 		return (-1);
66740Sstevel@tonic-gate 	}
66750Sstevel@tonic-gate 
66760Sstevel@tonic-gate 	/* old security info + new attr header(8) + new attr */
66770Sstevel@tonic-gate 	oldsize = *secinfo_len;
66780Sstevel@tonic-gate 	*secinfo_len += newattrsize;
66790Sstevel@tonic-gate 	new_secinfo = (char *)malloc(*secinfo_len);
66800Sstevel@tonic-gate 	if (new_secinfo == NULL) {
668112305Srich.burridge@sun.com 		(void) fprintf(stderr, gettext("can't allocate memory\n"));
66820Sstevel@tonic-gate 		*secinfo_len -= newattrsize;
66831676Sjpk 		free(attr);
66840Sstevel@tonic-gate 		return (-1);
66850Sstevel@tonic-gate 	}
66860Sstevel@tonic-gate 
66870Sstevel@tonic-gate 	(void) memcpy(new_secinfo, *secinfo, oldsize);
66880Sstevel@tonic-gate 	(void) memcpy(new_secinfo + oldsize, attr, newattrsize);
66890Sstevel@tonic-gate 
66900Sstevel@tonic-gate 	free(*secinfo);
66911676Sjpk 	free(attr);
66920Sstevel@tonic-gate 	*secinfo = new_secinfo;
66930Sstevel@tonic-gate 	return (0);
66940Sstevel@tonic-gate }
66950Sstevel@tonic-gate 
66960Sstevel@tonic-gate /*
66970Sstevel@tonic-gate  * write_ancillary(): write out an ancillary file.
66980Sstevel@tonic-gate  *      The file has the same header as normal file except the type and size
66990Sstevel@tonic-gate  *      fields. The type is 'A' and size is the sum of all attributes
67000Sstevel@tonic-gate  *	in bytes.
67010Sstevel@tonic-gate  *	The body contains a list of attribute type, size and info. Currently,
67020Sstevel@tonic-gate  *	there is only ACL info.  This file is put before the normal file.
67030Sstevel@tonic-gate  */
67040Sstevel@tonic-gate void
write_ancillary(union hblock * dblockp,char * secinfo,int len,char hdrtype)67050Sstevel@tonic-gate write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
67060Sstevel@tonic-gate {
67070Sstevel@tonic-gate 	long    blocks;
67080Sstevel@tonic-gate 	int	savflag;
67090Sstevel@tonic-gate 	int	savsize;
67100Sstevel@tonic-gate 
67110Sstevel@tonic-gate 	/* Just tranditional permissions or no security attribute info */
67120Sstevel@tonic-gate 	if (len == 0 || secinfo == NULL)
67130Sstevel@tonic-gate 		return;
67140Sstevel@tonic-gate 
67150Sstevel@tonic-gate 	/* save flag and size */
67160Sstevel@tonic-gate 	savflag = (dblockp->dbuf).typeflag;
67170Sstevel@tonic-gate 	(void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
67180Sstevel@tonic-gate 
67190Sstevel@tonic-gate 	/* special flag for ancillary file */
67200Sstevel@tonic-gate 	if (hdrtype == _XATTR_HDRTYPE)
67210Sstevel@tonic-gate 		dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
67220Sstevel@tonic-gate 	else
67230Sstevel@tonic-gate 		dblockp->dbuf.typeflag = 'A';
67240Sstevel@tonic-gate 
67250Sstevel@tonic-gate 	/* for pre-2.5 versions of tar, need to make sure */
67260Sstevel@tonic-gate 	/* the ACL file is readable			  */
67270Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.mode, "%07lo",
67281266Sceastha 	    (stbuf.st_mode & POSIXMODES) | 0000200);
67290Sstevel@tonic-gate 	(void) sprintf(dblockp->dbuf.size, "%011o", len);
67300Sstevel@tonic-gate 	(void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
67310Sstevel@tonic-gate 
67320Sstevel@tonic-gate 	/* write out the header */
67330Sstevel@tonic-gate 	(void) writetbuf((char *)dblockp, 1);
67340Sstevel@tonic-gate 
67350Sstevel@tonic-gate 	/* write out security info */
67360Sstevel@tonic-gate 	blocks = TBLOCKS(len);
67370Sstevel@tonic-gate 	(void) writetbuf((char *)secinfo, (int)blocks);
67380Sstevel@tonic-gate 
67390Sstevel@tonic-gate 	/* restore mode, flag and size */
67400Sstevel@tonic-gate 	(void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
67410Sstevel@tonic-gate 	dblockp->dbuf.typeflag = savflag;
67420Sstevel@tonic-gate 	(void) sprintf(dblockp->dbuf.size, "%011o", savsize);
67430Sstevel@tonic-gate }
67440Sstevel@tonic-gate 
67450Sstevel@tonic-gate /*
67460Sstevel@tonic-gate  * Read the data record for extended headers and then the regular header.
67470Sstevel@tonic-gate  * The data are read into the buffer and then null-terminated.  Entries
674811995Srich.burridge@sun.com  * for typeflag 'X' extended headers are of the format:
67490Sstevel@tonic-gate  * 	"%d %s=%s\n"
67500Sstevel@tonic-gate  *
67510Sstevel@tonic-gate  * When an extended header record is found, the extended header must
67520Sstevel@tonic-gate  * be processed and its values used to override the values in the
67530Sstevel@tonic-gate  * normal header.  The way this is done is to process the extended
67540Sstevel@tonic-gate  * header data record and set the data values, then call getdir
67550Sstevel@tonic-gate  * to process the regular header, then then to reconcile the two
67560Sstevel@tonic-gate  * sets of data.
67570Sstevel@tonic-gate  */
67580Sstevel@tonic-gate 
67590Sstevel@tonic-gate static int
get_xdata(void)67600Sstevel@tonic-gate get_xdata(void)
67610Sstevel@tonic-gate {
67620Sstevel@tonic-gate 	struct keylist_pair {
67630Sstevel@tonic-gate 		int keynum;
67640Sstevel@tonic-gate 		char *keylist;
67650Sstevel@tonic-gate 	}	keylist_pair[] = {	_X_DEVMAJOR, "SUN.devmajor",
67660Sstevel@tonic-gate 					_X_DEVMINOR, "SUN.devminor",
67670Sstevel@tonic-gate 					_X_GID, "gid",
67680Sstevel@tonic-gate 					_X_GNAME, "gname",
67690Sstevel@tonic-gate 					_X_LINKPATH, "linkpath",
67700Sstevel@tonic-gate 					_X_PATH, "path",
67710Sstevel@tonic-gate 					_X_SIZE, "size",
67720Sstevel@tonic-gate 					_X_UID, "uid",
67730Sstevel@tonic-gate 					_X_UNAME, "uname",
67740Sstevel@tonic-gate 					_X_MTIME, "mtime",
67750Sstevel@tonic-gate 					_X_LAST, "NULL" };
67760Sstevel@tonic-gate 	char		*lineloc;
67770Sstevel@tonic-gate 	int		length, i;
67780Sstevel@tonic-gate 	char		*keyword, *value;
67790Sstevel@tonic-gate 	blkcnt_t	nblocks;
67800Sstevel@tonic-gate 	int		bufneeded;
67810Sstevel@tonic-gate 	int		errors;
67820Sstevel@tonic-gate 
67835482Sas158974 	(void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
67840Sstevel@tonic-gate 	xhdr_count++;
67850Sstevel@tonic-gate 	errors = 0;
67860Sstevel@tonic-gate 
67870Sstevel@tonic-gate 	nblocks = TBLOCKS(stbuf.st_size);
67880Sstevel@tonic-gate 	bufneeded = nblocks * TBLOCK;
67890Sstevel@tonic-gate 	if (bufneeded >= xrec_size) {
67900Sstevel@tonic-gate 		free(xrec_ptr);
67910Sstevel@tonic-gate 		xrec_size = bufneeded + 1;
67920Sstevel@tonic-gate 		if ((xrec_ptr = malloc(xrec_size)) == NULL)
67930Sstevel@tonic-gate 			fatal(gettext("cannot allocate buffer"));
67940Sstevel@tonic-gate 	}
67950Sstevel@tonic-gate 
67960Sstevel@tonic-gate 	lineloc = xrec_ptr;
67970Sstevel@tonic-gate 
67980Sstevel@tonic-gate 	while (nblocks-- > 0) {
67990Sstevel@tonic-gate 		readtape(lineloc);
68000Sstevel@tonic-gate 		lineloc += TBLOCK;
68010Sstevel@tonic-gate 	}
68020Sstevel@tonic-gate 	lineloc = xrec_ptr;
68030Sstevel@tonic-gate 	xrec_ptr[stbuf.st_size] = '\0';
68040Sstevel@tonic-gate 	while (lineloc < xrec_ptr + stbuf.st_size) {
680511995Srich.burridge@sun.com 		if (dblock.dbuf.typeflag == 'L') {
680611995Srich.burridge@sun.com 			length = xrec_size;
680711995Srich.burridge@sun.com 			keyword = "path";
680811995Srich.burridge@sun.com 			value = lineloc;
680911995Srich.burridge@sun.com 		} else {
681011995Srich.burridge@sun.com 			length = atoi(lineloc);
681111995Srich.burridge@sun.com 			*(lineloc + length - 1) = '\0';
681211995Srich.burridge@sun.com 			keyword = strchr(lineloc, ' ') + 1;
681311995Srich.burridge@sun.com 			value = strchr(keyword, '=') + 1;
681411995Srich.burridge@sun.com 			*(value - 1) = '\0';
681511995Srich.burridge@sun.com 		}
68160Sstevel@tonic-gate 		i = 0;
68170Sstevel@tonic-gate 		lineloc += length;
68180Sstevel@tonic-gate 		while (keylist_pair[i].keynum != (int)_X_LAST) {
68190Sstevel@tonic-gate 			if (strcmp(keyword, keylist_pair[i].keylist) == 0)
68200Sstevel@tonic-gate 				break;
68210Sstevel@tonic-gate 			i++;
68220Sstevel@tonic-gate 		}
68230Sstevel@tonic-gate 		errno = 0;
68240Sstevel@tonic-gate 		switch (keylist_pair[i].keynum) {
68250Sstevel@tonic-gate 		case _X_DEVMAJOR:
68260Sstevel@tonic-gate 			Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
68270Sstevel@tonic-gate 			if (errno) {
68280Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
68290Sstevel@tonic-gate 				    "tar: Extended header major value error "
68300Sstevel@tonic-gate 				    "for file # %llu.\n"), xhdr_count);
68310Sstevel@tonic-gate 				errors++;
68320Sstevel@tonic-gate 			} else
68330Sstevel@tonic-gate 				xhdr_flgs |= _X_DEVMAJOR;
68340Sstevel@tonic-gate 			break;
68350Sstevel@tonic-gate 		case _X_DEVMINOR:
68360Sstevel@tonic-gate 			Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
68370Sstevel@tonic-gate 			if (errno) {
68380Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
68390Sstevel@tonic-gate 				    "tar: Extended header minor value error "
68400Sstevel@tonic-gate 				    "for file # %llu.\n"), xhdr_count);
68410Sstevel@tonic-gate 				errors++;
68420Sstevel@tonic-gate 			} else
68430Sstevel@tonic-gate 				xhdr_flgs |= _X_DEVMINOR;
68440Sstevel@tonic-gate 			break;
68450Sstevel@tonic-gate 		case _X_GID:
68460Sstevel@tonic-gate 			xhdr_flgs |= _X_GID;
68470Sstevel@tonic-gate 			Xtarhdr.x_gid = strtol(value, NULL, 0);
68480Sstevel@tonic-gate 			if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
68490Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
68500Sstevel@tonic-gate 				    "tar: Extended header gid value error "
68510Sstevel@tonic-gate 				    "for file # %llu.\n"), xhdr_count);
68520Sstevel@tonic-gate 				Xtarhdr.x_gid = GID_NOBODY;
68530Sstevel@tonic-gate 			}
68540Sstevel@tonic-gate 			break;
68550Sstevel@tonic-gate 		case _X_GNAME:
68560Sstevel@tonic-gate 			if (utf8_local("gname", &Xtarhdr.x_gname,
68570Sstevel@tonic-gate 			    local_gname, value, _POSIX_NAME_MAX) == 0)
68580Sstevel@tonic-gate 				xhdr_flgs |= _X_GNAME;
68590Sstevel@tonic-gate 			break;
68600Sstevel@tonic-gate 		case _X_LINKPATH:
68610Sstevel@tonic-gate 			if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
68620Sstevel@tonic-gate 			    local_linkpath, value, PATH_MAX) == 0)
68630Sstevel@tonic-gate 				xhdr_flgs |= _X_LINKPATH;
68640Sstevel@tonic-gate 			else
68650Sstevel@tonic-gate 				errors++;
68660Sstevel@tonic-gate 			break;
68670Sstevel@tonic-gate 		case _X_PATH:
68680Sstevel@tonic-gate 			if (utf8_local("path", &Xtarhdr.x_path,
68690Sstevel@tonic-gate 			    local_path, value, PATH_MAX) == 0)
68700Sstevel@tonic-gate 				xhdr_flgs |= _X_PATH;
68710Sstevel@tonic-gate 			else
68720Sstevel@tonic-gate 				errors++;
68730Sstevel@tonic-gate 			break;
68740Sstevel@tonic-gate 		case _X_SIZE:
68750Sstevel@tonic-gate 			Xtarhdr.x_filesz = strtoull(value, NULL, 0);
68760Sstevel@tonic-gate 			if (errno) {
68770Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
68780Sstevel@tonic-gate 				    "tar: Extended header invalid filesize "
68790Sstevel@tonic-gate 				    "for file # %llu.\n"), xhdr_count);
68800Sstevel@tonic-gate 				errors++;
68810Sstevel@tonic-gate 			} else
68820Sstevel@tonic-gate 				xhdr_flgs |= _X_SIZE;
68830Sstevel@tonic-gate 			break;
68840Sstevel@tonic-gate 		case _X_UID:
68850Sstevel@tonic-gate 			xhdr_flgs |= _X_UID;
68860Sstevel@tonic-gate 			Xtarhdr.x_uid = strtol(value, NULL, 0);
68870Sstevel@tonic-gate 			if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
68880Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
68890Sstevel@tonic-gate 				    "tar: Extended header uid value error "
68900Sstevel@tonic-gate 				    "for file # %llu.\n"), xhdr_count);
68910Sstevel@tonic-gate 				Xtarhdr.x_uid = UID_NOBODY;
68920Sstevel@tonic-gate 			}
68930Sstevel@tonic-gate 			break;
68940Sstevel@tonic-gate 		case _X_UNAME:
68950Sstevel@tonic-gate 			if (utf8_local("uname", &Xtarhdr.x_uname,
68960Sstevel@tonic-gate 			    local_uname, value, _POSIX_NAME_MAX) == 0)
68970Sstevel@tonic-gate 				xhdr_flgs |= _X_UNAME;
68980Sstevel@tonic-gate 			break;
68990Sstevel@tonic-gate 		case _X_MTIME:
69000Sstevel@tonic-gate 			get_xtime(value, &(Xtarhdr.x_mtime));
69010Sstevel@tonic-gate 			if (errno)
69020Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
69030Sstevel@tonic-gate 				    "tar: Extended header modification time "
69040Sstevel@tonic-gate 				    "value error for file # %llu.\n"),
69050Sstevel@tonic-gate 				    xhdr_count);
69060Sstevel@tonic-gate 			else
69070Sstevel@tonic-gate 				xhdr_flgs |= _X_MTIME;
69080Sstevel@tonic-gate 			break;
69090Sstevel@tonic-gate 		default:
69100Sstevel@tonic-gate 			(void) fprintf(stderr,
69110Sstevel@tonic-gate 			    gettext("tar:  unrecognized extended"
69120Sstevel@tonic-gate 			    " header keyword '%s'.  Ignored.\n"), keyword);
69130Sstevel@tonic-gate 			break;
69140Sstevel@tonic-gate 		}
69150Sstevel@tonic-gate 	}
69160Sstevel@tonic-gate 
69170Sstevel@tonic-gate 	getdir();	/* get regular header */
69180Sstevel@tonic-gate 	if (errors && errflag)
69190Sstevel@tonic-gate 		done(1);
69200Sstevel@tonic-gate 	else
69210Sstevel@tonic-gate 		if (errors)
69220Sstevel@tonic-gate 			Errflg = 1;
69230Sstevel@tonic-gate 	return (errors);
69240Sstevel@tonic-gate }
69250Sstevel@tonic-gate 
69260Sstevel@tonic-gate /*
69275482Sas158974  * load_info_from_xtarhdr - sets Gen and stbuf variables from
69285482Sas158974  *	extended header
69295482Sas158974  *	load_info_from_xtarhdr(flag, xhdrp);
69305482Sas158974  *	u_longlong_t flag;	xhdr_flgs
69315482Sas158974  *	struct xtar_hdr *xhdrp; pointer to extended header
69325482Sas158974  *	NOTE:	called when typeflag is not 'A' and xhdr_flgs
69335482Sas158974  *		is set.
69345482Sas158974  */
69355482Sas158974 static void
load_info_from_xtarhdr(u_longlong_t flag,struct xtar_hdr * xhdrp)69365482Sas158974 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
69375482Sas158974 {
69385482Sas158974 	if (flag & _X_DEVMAJOR) {
69395482Sas158974 		Gen.g_devmajor = xhdrp->x_devmajor;
69405482Sas158974 	}
69415482Sas158974 	if (flag & _X_DEVMINOR) {
69425482Sas158974 		Gen.g_devminor = xhdrp->x_devminor;
69435482Sas158974 	}
69445482Sas158974 	if (flag & _X_GID) {
69455482Sas158974 		Gen.g_gid = xhdrp->x_gid;
69465482Sas158974 		stbuf.st_gid = xhdrp->x_gid;
69475482Sas158974 	}
69485482Sas158974 	if (flag & _X_UID) {
69495482Sas158974 		Gen.g_uid = xhdrp->x_uid;
69505482Sas158974 		stbuf.st_uid  = xhdrp->x_uid;
69515482Sas158974 	}
69525482Sas158974 	if (flag & _X_SIZE) {
69535482Sas158974 		Gen.g_filesz = xhdrp->x_filesz;
69545482Sas158974 		stbuf.st_size = xhdrp->x_filesz;
69555482Sas158974 	}
69565482Sas158974 	if (flag & _X_MTIME) {
69575482Sas158974 		Gen.g_mtime = xhdrp->x_mtime.tv_sec;
69585482Sas158974 		stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
69595482Sas158974 		stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
69605482Sas158974 	}
69615482Sas158974 }
69625482Sas158974 
69635482Sas158974 /*
69640Sstevel@tonic-gate  * gen_num creates a string from a keyword and an usigned long long in the
69650Sstevel@tonic-gate  * format:  %d %s=%s\n
69660Sstevel@tonic-gate  * This is part of the extended header data record.
69670Sstevel@tonic-gate  */
69680Sstevel@tonic-gate 
69690Sstevel@tonic-gate void
gen_num(const char * keyword,const u_longlong_t number)69700Sstevel@tonic-gate gen_num(const char *keyword, const u_longlong_t number)
69710Sstevel@tonic-gate {
69720Sstevel@tonic-gate 	char	save_val[ULONGLONG_MAX_DIGITS + 1];
69730Sstevel@tonic-gate 	int	len;
69740Sstevel@tonic-gate 	char	*curr_ptr;
69750Sstevel@tonic-gate 
69760Sstevel@tonic-gate 	(void) sprintf(save_val, "%llu", number);
69770Sstevel@tonic-gate 	/*
69780Sstevel@tonic-gate 	 * len = length of entire line, including itself.  len will be
69790Sstevel@tonic-gate 	 * two digits.  So, add the string lengths plus the length of len,
69800Sstevel@tonic-gate 	 * plus a blank, an equal sign, and a newline.
69810Sstevel@tonic-gate 	 */
69820Sstevel@tonic-gate 	len = strlen(save_val) + strlen(keyword) + 5;
69830Sstevel@tonic-gate 	if (xrec_offset + len > xrec_size) {
69840Sstevel@tonic-gate 		if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
69850Sstevel@tonic-gate 			fatal(gettext(
69860Sstevel@tonic-gate 			    "cannot allocate extended header buffer"));
69870Sstevel@tonic-gate 		xrec_ptr = curr_ptr;
69880Sstevel@tonic-gate 		xrec_size *= 2;
69890Sstevel@tonic-gate 	}
69900Sstevel@tonic-gate 	(void) sprintf(&xrec_ptr[xrec_offset],
69910Sstevel@tonic-gate 	    "%d %s=%s\n", len, keyword, save_val);
69920Sstevel@tonic-gate 	xrec_offset += len;
69930Sstevel@tonic-gate }
69940Sstevel@tonic-gate 
69950Sstevel@tonic-gate /*
69960Sstevel@tonic-gate  * gen_date creates a string from a keyword and a timestruc_t in the
69970Sstevel@tonic-gate  * format:  %d %s=%s\n
69980Sstevel@tonic-gate  * This is part of the extended header data record.
69990Sstevel@tonic-gate  * Currently, granularity is only microseconds, so the low-order three digits
70000Sstevel@tonic-gate  * will be truncated.
70010Sstevel@tonic-gate  */
70020Sstevel@tonic-gate 
70030Sstevel@tonic-gate void
gen_date(const char * keyword,const timestruc_t time_value)70040Sstevel@tonic-gate gen_date(const char *keyword, const timestruc_t time_value)
70050Sstevel@tonic-gate {
70060Sstevel@tonic-gate 	/* Allow for <seconds>.<nanoseconds>\n */
70070Sstevel@tonic-gate 	char	save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
70080Sstevel@tonic-gate 	int	len;
70090Sstevel@tonic-gate 	char	*curr_ptr;
70100Sstevel@tonic-gate 
70110Sstevel@tonic-gate 	(void) sprintf(save_val, "%ld", time_value.tv_sec);
70120Sstevel@tonic-gate 	len = strlen(save_val);
70130Sstevel@tonic-gate 	save_val[len] = '.';
70140Sstevel@tonic-gate 	(void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
70150Sstevel@tonic-gate 
70160Sstevel@tonic-gate 	/*
70170Sstevel@tonic-gate 	 * len = length of entire line, including itself.  len will be
70180Sstevel@tonic-gate 	 * two digits.  So, add the string lengths plus the length of len,
70190Sstevel@tonic-gate 	 * plus a blank, an equal sign, and a newline.
70200Sstevel@tonic-gate 	 */
70210Sstevel@tonic-gate 	len = strlen(save_val) + strlen(keyword) + 5;
70220Sstevel@tonic-gate 	if (xrec_offset + len > xrec_size) {
70230Sstevel@tonic-gate 		if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
70240Sstevel@tonic-gate 			fatal(gettext(
70250Sstevel@tonic-gate 			    "cannot allocate extended header buffer"));
70260Sstevel@tonic-gate 		xrec_ptr = curr_ptr;
70270Sstevel@tonic-gate 		xrec_size *= 2;
70280Sstevel@tonic-gate 	}
70290Sstevel@tonic-gate 	(void) sprintf(&xrec_ptr[xrec_offset],
70300Sstevel@tonic-gate 	    "%d %s=%s\n", len, keyword, save_val);
70310Sstevel@tonic-gate 	xrec_offset += len;
70320Sstevel@tonic-gate }
70330Sstevel@tonic-gate 
70340Sstevel@tonic-gate /*
70350Sstevel@tonic-gate  * gen_string creates a string from a keyword and a char * in the
70360Sstevel@tonic-gate  * format:  %d %s=%s\n
70370Sstevel@tonic-gate  * This is part of the extended header data record.
70380Sstevel@tonic-gate  */
70390Sstevel@tonic-gate 
70400Sstevel@tonic-gate void
gen_string(const char * keyword,const char * value)70410Sstevel@tonic-gate gen_string(const char *keyword, const char *value)
70420Sstevel@tonic-gate {
70430Sstevel@tonic-gate 	int	len;
70440Sstevel@tonic-gate 	char	*curr_ptr;
70450Sstevel@tonic-gate 
70460Sstevel@tonic-gate 	/*
70470Sstevel@tonic-gate 	 * len = length of entire line, including itself.  The character length
70480Sstevel@tonic-gate 	 * of len must be 1-4 characters, because the maximum size of the path
70490Sstevel@tonic-gate 	 * or the name is PATH_MAX, which is 1024.  So, assume 1 character
70500Sstevel@tonic-gate 	 * for len, one for the space, one for the "=", and one for the newline.
70510Sstevel@tonic-gate 	 * Then adjust as needed.
70520Sstevel@tonic-gate 	 */
70530Sstevel@tonic-gate 	/* LINTED constant expression */
70540Sstevel@tonic-gate 	assert(PATH_MAX <= 9996);
70550Sstevel@tonic-gate 	len = strlen(value) + strlen(keyword) + 4;
70560Sstevel@tonic-gate 	if (len > 997)
70570Sstevel@tonic-gate 		len += 3;
70580Sstevel@tonic-gate 	else if (len > 98)
70590Sstevel@tonic-gate 		len += 2;
70600Sstevel@tonic-gate 	else if (len > 9)
70610Sstevel@tonic-gate 		len += 1;
70620Sstevel@tonic-gate 	if (xrec_offset + len > xrec_size) {
70630Sstevel@tonic-gate 		if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
70640Sstevel@tonic-gate 			fatal(gettext(
70650Sstevel@tonic-gate 			    "cannot allocate extended header buffer"));
70660Sstevel@tonic-gate 		xrec_ptr = curr_ptr;
70670Sstevel@tonic-gate 		xrec_size *= 2;
70680Sstevel@tonic-gate 	}
70690Sstevel@tonic-gate #ifdef XHDR_DEBUG
70700Sstevel@tonic-gate 	if (strcmp(keyword+1, "name") != 0)
70710Sstevel@tonic-gate #endif
70720Sstevel@tonic-gate 	(void) sprintf(&xrec_ptr[xrec_offset],
70730Sstevel@tonic-gate 	    "%d %s=%s\n", len, keyword, value);
70740Sstevel@tonic-gate #ifdef XHDR_DEBUG
70750Sstevel@tonic-gate 	else {
70760Sstevel@tonic-gate 	len += 11;
70770Sstevel@tonic-gate 	(void) sprintf(&xrec_ptr[xrec_offset],
70780Sstevel@tonic-gate 	    "%d %s=%snametoolong\n", len, keyword, value);
70790Sstevel@tonic-gate 	}
70800Sstevel@tonic-gate #endif
70810Sstevel@tonic-gate 	xrec_offset += len;
70820Sstevel@tonic-gate }
70830Sstevel@tonic-gate 
70840Sstevel@tonic-gate /*
70850Sstevel@tonic-gate  * Convert time found in the extended header data to seconds and nanoseconds.
70860Sstevel@tonic-gate  */
70870Sstevel@tonic-gate 
70880Sstevel@tonic-gate void
get_xtime(char * value,timestruc_t * xtime)70890Sstevel@tonic-gate get_xtime(char *value, timestruc_t *xtime)
70900Sstevel@tonic-gate {
70910Sstevel@tonic-gate 	char nanosec[10];
70920Sstevel@tonic-gate 	char *period;
70930Sstevel@tonic-gate 	int i;
70940Sstevel@tonic-gate 
70950Sstevel@tonic-gate 	(void) memset(nanosec, '0', 9);
70960Sstevel@tonic-gate 	nanosec[9] = '\0';
70970Sstevel@tonic-gate 
70980Sstevel@tonic-gate 	period = strchr(value, '.');
70990Sstevel@tonic-gate 	if (period != NULL)
71000Sstevel@tonic-gate 		period[0] = '\0';
71010Sstevel@tonic-gate 	xtime->tv_sec = strtol(value, NULL, 10);
71020Sstevel@tonic-gate 	if (period == NULL)
71030Sstevel@tonic-gate 		xtime->tv_nsec = 0;
71040Sstevel@tonic-gate 	else {
71050Sstevel@tonic-gate 		i = strlen(period +1);
71060Sstevel@tonic-gate 		(void) strncpy(nanosec, period + 1, min(i, 9));
71070Sstevel@tonic-gate 		xtime->tv_nsec = strtol(nanosec, NULL, 10);
71080Sstevel@tonic-gate 	}
71090Sstevel@tonic-gate }
71100Sstevel@tonic-gate 
71110Sstevel@tonic-gate /*
71120Sstevel@tonic-gate  *	Check linkpath for length.
71130Sstevel@tonic-gate  *	Emit an error message and return 1 if too long.
71140Sstevel@tonic-gate  */
71150Sstevel@tonic-gate 
71160Sstevel@tonic-gate int
chk_path_build(char * name,char * longname,char * linkname,char * prefix,char type,int filetype)71170Sstevel@tonic-gate chk_path_build(
71180Sstevel@tonic-gate 	char	*name,
71190Sstevel@tonic-gate 	char	*longname,
71200Sstevel@tonic-gate 	char	*linkname,
71210Sstevel@tonic-gate 	char	*prefix,
71220Sstevel@tonic-gate 	char	type,
71230Sstevel@tonic-gate 	int	filetype)
71240Sstevel@tonic-gate {
71250Sstevel@tonic-gate 
71260Sstevel@tonic-gate 	if (strlen(linkname) > (size_t)NAMSIZ) {
71270Sstevel@tonic-gate 		if (Eflag > 0) {
71280Sstevel@tonic-gate 			xhdr_flgs |= _X_LINKPATH;
71290Sstevel@tonic-gate 			Xtarhdr.x_linkpath = linkname;
71300Sstevel@tonic-gate 		} else {
71310Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
71320Sstevel@tonic-gate 			    "tar: %s: linked to %s\n"), longname, linkname);
71330Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
71340Sstevel@tonic-gate 			    "tar: %s: linked name too long\n"), linkname);
71350Sstevel@tonic-gate 			if (errflag)
71360Sstevel@tonic-gate 				done(1);
71370Sstevel@tonic-gate 			else
71380Sstevel@tonic-gate 				Errflg = 1;
71390Sstevel@tonic-gate 			return (1);
71400Sstevel@tonic-gate 		}
71410Sstevel@tonic-gate 	}
71420Sstevel@tonic-gate 	if (xhdr_flgs & _X_LINKPATH)
71430Sstevel@tonic-gate 		return (build_dblock(name, tchar, type,
71441266Sceastha 		    filetype, &stbuf, stbuf.st_dev,
71450Sstevel@tonic-gate 		    prefix));
71460Sstevel@tonic-gate 	else
71470Sstevel@tonic-gate 		return (build_dblock(name, linkname, type,
71481266Sceastha 		    filetype, &stbuf, stbuf.st_dev, prefix));
71490Sstevel@tonic-gate }
71500Sstevel@tonic-gate 
71510Sstevel@tonic-gate /*
71520Sstevel@tonic-gate  * Convert from UTF-8 to local character set.
71530Sstevel@tonic-gate  */
71540Sstevel@tonic-gate 
71550Sstevel@tonic-gate static int
utf8_local(char * option,char ** Xhdr_ptrptr,char * target,const char * source,int max_val)71560Sstevel@tonic-gate utf8_local(
71570Sstevel@tonic-gate 	char		*option,
71580Sstevel@tonic-gate 	char		**Xhdr_ptrptr,
71590Sstevel@tonic-gate 	char		*target,
71600Sstevel@tonic-gate 	const char	*source,
71610Sstevel@tonic-gate 	int		max_val)
71620Sstevel@tonic-gate {
71630Sstevel@tonic-gate 	static	iconv_t	iconv_cd;
71640Sstevel@tonic-gate 	char		*nl_target;
71650Sstevel@tonic-gate 	const	char	*iconv_src;
71660Sstevel@tonic-gate 	char		*iconv_trg;
71671266Sceastha 	size_t		inlen;
71681266Sceastha 	size_t		outlen;
71690Sstevel@tonic-gate 
71700Sstevel@tonic-gate 	if (charset_type == -1) {	/* iconv_open failed in earlier try */
71710Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
71720Sstevel@tonic-gate 		    "tar:  file # %llu: (%s) UTF-8 conversion failed.\n"),
71730Sstevel@tonic-gate 		    xhdr_count, source);
71740Sstevel@tonic-gate 		return (1);
71750Sstevel@tonic-gate 	} else if (charset_type == 0) {	/* iconv_open has not yet been done */
71760Sstevel@tonic-gate 		nl_target = nl_langinfo(CODESET);
71770Sstevel@tonic-gate 		if (strlen(nl_target) == 0)	/* locale using 7-bit codeset */
71780Sstevel@tonic-gate 			nl_target = "646";
71790Sstevel@tonic-gate 		if (strcmp(nl_target, "646") == 0)
71800Sstevel@tonic-gate 			charset_type = 1;
71810Sstevel@tonic-gate 		else if (strcmp(nl_target, "UTF-8") == 0)
71820Sstevel@tonic-gate 			charset_type = 3;
71830Sstevel@tonic-gate 		else {
71840Sstevel@tonic-gate 			if (strncmp(nl_target, "ISO", 3) == 0)
71850Sstevel@tonic-gate 				nl_target += 3;
71860Sstevel@tonic-gate 			charset_type = 2;
71870Sstevel@tonic-gate 			errno = 0;
71880Sstevel@tonic-gate 			if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
71890Sstevel@tonic-gate 			    (iconv_t)-1) {
71900Sstevel@tonic-gate 				if (errno == EINVAL)
71910Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
71920Sstevel@tonic-gate 					    "tar: conversion routines not "
71930Sstevel@tonic-gate 					    "available for current locale.  "));
71940Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
71950Sstevel@tonic-gate 				    "file # %llu: (%s) UTF-8 conversion"
71960Sstevel@tonic-gate 				    " failed.\n"), xhdr_count, source);
71970Sstevel@tonic-gate 				charset_type = -1;
71980Sstevel@tonic-gate 				return (1);
71990Sstevel@tonic-gate 			}
72000Sstevel@tonic-gate 		}
72010Sstevel@tonic-gate 	}
72020Sstevel@tonic-gate 
72030Sstevel@tonic-gate 	/* locale using 7-bit codeset or UTF-8 locale */
72040Sstevel@tonic-gate 	if (charset_type == 1 || charset_type == 3) {
72050Sstevel@tonic-gate 		if (strlen(source) > max_val) {
72060Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
72070Sstevel@tonic-gate 			    "tar: file # %llu: Extended header %s too long.\n"),
72080Sstevel@tonic-gate 			    xhdr_count, option);
72090Sstevel@tonic-gate 			return (1);
72100Sstevel@tonic-gate 		}
72110Sstevel@tonic-gate 		if (charset_type == 3)
72120Sstevel@tonic-gate 			(void) strcpy(target, source);
72130Sstevel@tonic-gate 		else if (c_utf8(target, source) != 0) {
72140Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
72150Sstevel@tonic-gate 			    "tar:  file # %llu: (%s) UTF-8 conversion"
72160Sstevel@tonic-gate 			    " failed.\n"), xhdr_count, source);
72170Sstevel@tonic-gate 			return (1);
72180Sstevel@tonic-gate 		}
72190Sstevel@tonic-gate 		*Xhdr_ptrptr = target;
72200Sstevel@tonic-gate 		return (0);
72210Sstevel@tonic-gate 	}
72220Sstevel@tonic-gate 
72230Sstevel@tonic-gate 	iconv_src = source;
72240Sstevel@tonic-gate 	iconv_trg = target;
72250Sstevel@tonic-gate 	inlen = strlen(source);
72260Sstevel@tonic-gate 	outlen = max_val * UTF_8_FACTOR;
72270Sstevel@tonic-gate 	if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
72280Sstevel@tonic-gate 	    (size_t)-1) {	/* Error occurred:  didn't convert */
72290Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
72300Sstevel@tonic-gate 		    "tar:  file # %llu: (%s) UTF-8 conversion failed.\n"),
72310Sstevel@tonic-gate 		    xhdr_count, source);
72320Sstevel@tonic-gate 		/* Get remaining output; reinitialize conversion descriptor */
72330Sstevel@tonic-gate 		iconv_src = (const char *)NULL;
72340Sstevel@tonic-gate 		inlen = 0;
72350Sstevel@tonic-gate 		(void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
72360Sstevel@tonic-gate 		return (1);
72370Sstevel@tonic-gate 	}
72380Sstevel@tonic-gate 	/* Get remaining output; reinitialize conversion descriptor */
72390Sstevel@tonic-gate 	iconv_src = (const char *)NULL;
72400Sstevel@tonic-gate 	inlen = 0;
72410Sstevel@tonic-gate 	if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
72420Sstevel@tonic-gate 	    (size_t)-1) {	/* Error occurred:  didn't convert */
72430Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
72440Sstevel@tonic-gate 		    "tar:  file # %llu: (%s) UTF-8 conversion failed.\n"),
72450Sstevel@tonic-gate 		    xhdr_count, source);
72460Sstevel@tonic-gate 		return (1);
72470Sstevel@tonic-gate 	}
72480Sstevel@tonic-gate 
72490Sstevel@tonic-gate 	*iconv_trg = '\0';	/* Null-terminate iconv output string */
72500Sstevel@tonic-gate 	if (strlen(target) > max_val) {
72510Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
72520Sstevel@tonic-gate 		    "tar: file # %llu: Extended header %s too long.\n"),
72530Sstevel@tonic-gate 		    xhdr_count, option);
72540Sstevel@tonic-gate 		return (1);
72550Sstevel@tonic-gate 	}
72560Sstevel@tonic-gate 	*Xhdr_ptrptr = target;
72570Sstevel@tonic-gate 	return (0);
72580Sstevel@tonic-gate }
72590Sstevel@tonic-gate 
72600Sstevel@tonic-gate /*
72610Sstevel@tonic-gate  * Check gname, uname, path, and linkpath to see if they need to go in an
72620Sstevel@tonic-gate  * extended header.  If they are already slated to be in an extended header,
72630Sstevel@tonic-gate  * or if they are not ascii, then they need to be in the extended header.
72640Sstevel@tonic-gate  * Then, convert all extended names to UTF-8.
72650Sstevel@tonic-gate  */
72660Sstevel@tonic-gate 
72670Sstevel@tonic-gate int
gen_utf8_names(const char * filename)72680Sstevel@tonic-gate gen_utf8_names(const char *filename)
72690Sstevel@tonic-gate {
72700Sstevel@tonic-gate 	static	iconv_t	iconv_cd;
72710Sstevel@tonic-gate 	char		*nl_target;
72720Sstevel@tonic-gate 	char		tempbuf[MAXNAM + 1];
72731266Sceastha 	int		nbytes;
72741266Sceastha 	int		errors;
72750Sstevel@tonic-gate 
72760Sstevel@tonic-gate 	if (charset_type == -1)	{	/* Previous failure to open. */
72770Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
72780Sstevel@tonic-gate 		    "tar: file # %llu: UTF-8 conversion failed.\n"),
72790Sstevel@tonic-gate 		    xhdr_count);
72800Sstevel@tonic-gate 		return (1);
72810Sstevel@tonic-gate 	}
72820Sstevel@tonic-gate 
72830Sstevel@tonic-gate 	if (charset_type == 0) {	/* Need to get conversion descriptor */
72840Sstevel@tonic-gate 		nl_target = nl_langinfo(CODESET);
72850Sstevel@tonic-gate 		if (strlen(nl_target) == 0)	/* locale using 7-bit codeset */
72860Sstevel@tonic-gate 			nl_target = "646";
72870Sstevel@tonic-gate 		if (strcmp(nl_target, "646") == 0)
72880Sstevel@tonic-gate 			charset_type = 1;
72890Sstevel@tonic-gate 		else if (strcmp(nl_target, "UTF-8") == 0)
72900Sstevel@tonic-gate 			charset_type = 3;
72910Sstevel@tonic-gate 		else {
72920Sstevel@tonic-gate 			if (strncmp(nl_target, "ISO", 3) == 0)
72930Sstevel@tonic-gate 				nl_target += 3;
72940Sstevel@tonic-gate 			charset_type = 2;
72950Sstevel@tonic-gate 			errno = 0;
72960Sstevel@tonic-gate #ifdef ICONV_DEBUG
72970Sstevel@tonic-gate 			(void) fprintf(stderr,
729812305Srich.burridge@sun.com 			    gettext("Opening iconv_cd with target %s\n"),
72990Sstevel@tonic-gate 			    nl_target);
73000Sstevel@tonic-gate #endif
73010Sstevel@tonic-gate 			if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
73020Sstevel@tonic-gate 			    (iconv_t)-1) {
73030Sstevel@tonic-gate 				if (errno == EINVAL)
73040Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
73050Sstevel@tonic-gate 					    "tar: conversion routines not "
73060Sstevel@tonic-gate 					    "available for current locale.  "));
73070Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
73080Sstevel@tonic-gate 				    "file (%s): UTF-8 conversion failed.\n"),
73090Sstevel@tonic-gate 				    filename);
73100Sstevel@tonic-gate 				charset_type = -1;
73110Sstevel@tonic-gate 				return (1);
73120Sstevel@tonic-gate 			}
73130Sstevel@tonic-gate 		}
73140Sstevel@tonic-gate 	}
73150Sstevel@tonic-gate 
73160Sstevel@tonic-gate 	errors = 0;
73170Sstevel@tonic-gate 
73180Sstevel@tonic-gate 	errors += local_utf8(&Xtarhdr.x_gname, local_gname,
73190Sstevel@tonic-gate 	    dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
73200Sstevel@tonic-gate 	errors += local_utf8(&Xtarhdr.x_uname, local_uname,
73210Sstevel@tonic-gate 	    dblock.dbuf.uname, iconv_cd, _X_UNAME,  _POSIX_NAME_MAX);
73220Sstevel@tonic-gate 	if ((xhdr_flgs & _X_LINKPATH) == 0) {	/* Need null-terminated str. */
73230Sstevel@tonic-gate 		(void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
73240Sstevel@tonic-gate 		tempbuf[NAMSIZ] = '\0';
73250Sstevel@tonic-gate 	}
73260Sstevel@tonic-gate 	errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
73270Sstevel@tonic-gate 	    tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
73280Sstevel@tonic-gate 	if ((xhdr_flgs & _X_PATH) == 0) {	/* Concatenate prefix & name */
73290Sstevel@tonic-gate 		(void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
73301221Ssr161167 		tempbuf[PRESIZ] = '\0';
73310Sstevel@tonic-gate 		nbytes = strlen(tempbuf);
73320Sstevel@tonic-gate 		if (nbytes > 0) {
73330Sstevel@tonic-gate 			tempbuf[nbytes++] = '/';
73340Sstevel@tonic-gate 			tempbuf[nbytes] = '\0';
73350Sstevel@tonic-gate 		}
73361221Ssr161167 		(void) strncat(tempbuf + nbytes, dblock.dbuf.name,
73371221Ssr161167 		    (MAXNAM - nbytes));
73381221Ssr161167 		tempbuf[MAXNAM] = '\0';
73390Sstevel@tonic-gate 	}
73400Sstevel@tonic-gate 	errors += local_utf8(&Xtarhdr.x_path, local_path,
73410Sstevel@tonic-gate 	    tempbuf, iconv_cd, _X_PATH, PATH_MAX);
73420Sstevel@tonic-gate 
73430Sstevel@tonic-gate 	if (errors > 0)
73440Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
73450Sstevel@tonic-gate 		    "tar: file (%s): UTF-8 conversion failed.\n"), filename);
73460Sstevel@tonic-gate 
73470Sstevel@tonic-gate 	if (errors && errflag)
73480Sstevel@tonic-gate 		done(1);
73490Sstevel@tonic-gate 	else
73500Sstevel@tonic-gate 		if (errors)
73510Sstevel@tonic-gate 			Errflg = 1;
73520Sstevel@tonic-gate 	return (errors);
73530Sstevel@tonic-gate }
73540Sstevel@tonic-gate 
73550Sstevel@tonic-gate static int
local_utf8(char ** Xhdr_ptrptr,char * target,const char * source,iconv_t iconv_cd,int xhdrflg,int max_val)73560Sstevel@tonic-gate local_utf8(
73570Sstevel@tonic-gate 		char	**Xhdr_ptrptr,
73580Sstevel@tonic-gate 		char	*target,
73590Sstevel@tonic-gate 		const	char	*source,
73600Sstevel@tonic-gate 		iconv_t	iconv_cd,
73610Sstevel@tonic-gate 		int	xhdrflg,
73620Sstevel@tonic-gate 		int	max_val)
73630Sstevel@tonic-gate {
73640Sstevel@tonic-gate 	const	char	*iconv_src;
73650Sstevel@tonic-gate 	const	char	*starting_src;
73660Sstevel@tonic-gate 	char		*iconv_trg;
73671266Sceastha 	size_t		inlen;
73681266Sceastha 	size_t		outlen;
73690Sstevel@tonic-gate #ifdef ICONV_DEBUG
73700Sstevel@tonic-gate 	unsigned char	c_to_hex;
73710Sstevel@tonic-gate #endif
73720Sstevel@tonic-gate 
73730Sstevel@tonic-gate 	/*
73740Sstevel@tonic-gate 	 * If the item is already slated for extended format, get the string
73750Sstevel@tonic-gate 	 * to convert from the extended header record.  Otherwise, get it from
73760Sstevel@tonic-gate 	 * the regular (dblock) area.
73770Sstevel@tonic-gate 	 */
73780Sstevel@tonic-gate 	if (xhdr_flgs & xhdrflg) {
73790Sstevel@tonic-gate 		if (charset_type == 3) {	/* Already UTF-8, just copy */
73800Sstevel@tonic-gate 			(void) strcpy(target, *Xhdr_ptrptr);
73810Sstevel@tonic-gate 			*Xhdr_ptrptr = target;
73820Sstevel@tonic-gate 			return (0);
73830Sstevel@tonic-gate 		} else
73840Sstevel@tonic-gate 			iconv_src = (const char *) *Xhdr_ptrptr;
73850Sstevel@tonic-gate 	} else {
73860Sstevel@tonic-gate 		if (charset_type == 3)		/* Already in UTF-8 format */
73870Sstevel@tonic-gate 			return (0);		/* Don't create xhdr record */
73880Sstevel@tonic-gate 		iconv_src = source;
73890Sstevel@tonic-gate 	}
73900Sstevel@tonic-gate 	starting_src = iconv_src;
73910Sstevel@tonic-gate 	iconv_trg = target;
73920Sstevel@tonic-gate 	if ((inlen = strlen(iconv_src)) == 0)
73930Sstevel@tonic-gate 		return (0);
73940Sstevel@tonic-gate 
73950Sstevel@tonic-gate 	if (charset_type == 1) {	/* locale using 7-bit codeset */
73960Sstevel@tonic-gate 		if (c_utf8(target, starting_src) != 0) {
73970Sstevel@tonic-gate 			(void) fprintf(stderr,
73980Sstevel@tonic-gate 			    gettext("tar: invalid character in"
73990Sstevel@tonic-gate 			    " UTF-8 conversion of '%s'\n"), starting_src);
74000Sstevel@tonic-gate 			return (1);
74010Sstevel@tonic-gate 		}
74020Sstevel@tonic-gate 		return (0);
74030Sstevel@tonic-gate 	}
74040Sstevel@tonic-gate 
74050Sstevel@tonic-gate 	outlen = max_val * UTF_8_FACTOR;
74060Sstevel@tonic-gate 	errno = 0;
74070Sstevel@tonic-gate 	if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
74080Sstevel@tonic-gate 	    (size_t)-1) {
74090Sstevel@tonic-gate 		/* An error occurred, or not all characters were converted */
74100Sstevel@tonic-gate 		if (errno == EILSEQ)
74110Sstevel@tonic-gate 			(void) fprintf(stderr,
74120Sstevel@tonic-gate 			    gettext("tar: invalid character in"
74130Sstevel@tonic-gate 			    " UTF-8 conversion of '%s'\n"), starting_src);
74140Sstevel@tonic-gate 		else
74150Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
74160Sstevel@tonic-gate 			    "tar: conversion to UTF-8 aborted for '%s'.\n"),
74170Sstevel@tonic-gate 			    starting_src);
74180Sstevel@tonic-gate 		/* Get remaining output; reinitialize conversion descriptor */
74190Sstevel@tonic-gate 		iconv_src = (const char *)NULL;
74200Sstevel@tonic-gate 		inlen = 0;
74210Sstevel@tonic-gate 		(void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
74220Sstevel@tonic-gate 		return (1);
74230Sstevel@tonic-gate 	}
74240Sstevel@tonic-gate 	/* Get remaining output; reinitialize conversion descriptor */
74250Sstevel@tonic-gate 	iconv_src = (const char *)NULL;
74260Sstevel@tonic-gate 	inlen = 0;
74270Sstevel@tonic-gate 	if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
74280Sstevel@tonic-gate 	    (size_t)-1) {	/* Error occurred:  didn't convert */
74290Sstevel@tonic-gate 		if (errno == EILSEQ)
74300Sstevel@tonic-gate 			(void) fprintf(stderr,
74310Sstevel@tonic-gate 			    gettext("tar: invalid character in"
74320Sstevel@tonic-gate 			    " UTF-8 conversion of '%s'\n"), starting_src);
74330Sstevel@tonic-gate 		else
74340Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
74350Sstevel@tonic-gate 			    "tar: conversion to UTF-8 aborted for '%s'.\n"),
74360Sstevel@tonic-gate 			    starting_src);
74370Sstevel@tonic-gate 		return (1);
74380Sstevel@tonic-gate 	}
74390Sstevel@tonic-gate 
74400Sstevel@tonic-gate 	*iconv_trg = '\0';	/* Null-terminate iconv output string */
74410Sstevel@tonic-gate 	if (strcmp(starting_src, target) != 0) {
74420Sstevel@tonic-gate 		*Xhdr_ptrptr = target;
74430Sstevel@tonic-gate 		xhdr_flgs |= xhdrflg;
74440Sstevel@tonic-gate #ifdef ICONV_DEBUG
74450Sstevel@tonic-gate 		(void) fprintf(stderr, "***  inlen: %d %d; outlen: %d %d\n",
74460Sstevel@tonic-gate 		    strlen(starting_src), inlen, max_val, outlen);
74470Sstevel@tonic-gate 		(void) fprintf(stderr, "Input string:\n  ");
74480Sstevel@tonic-gate 		for (inlen = 0; inlen < strlen(starting_src); inlen++) {
74490Sstevel@tonic-gate 			c_to_hex = (unsigned char)starting_src[inlen];
74500Sstevel@tonic-gate 			(void) fprintf(stderr, " %2.2x", c_to_hex);
74510Sstevel@tonic-gate 			if (inlen % 20 == 19)
74520Sstevel@tonic-gate 				(void) fprintf(stderr, "\n  ");
74530Sstevel@tonic-gate 		}
74540Sstevel@tonic-gate 		(void) fprintf(stderr, "\nOutput string:\n  ");
74550Sstevel@tonic-gate 		for (inlen = 0; inlen < strlen(target); inlen++) {
74560Sstevel@tonic-gate 			c_to_hex = (unsigned char)target[inlen];
74570Sstevel@tonic-gate 			(void) fprintf(stderr, " %2.2x", c_to_hex);
74580Sstevel@tonic-gate 			if (inlen % 20 == 19)
74590Sstevel@tonic-gate 				(void) fprintf(stderr, "\n  ");
74600Sstevel@tonic-gate 		}
74610Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
74620Sstevel@tonic-gate #endif
74630Sstevel@tonic-gate 	}
74640Sstevel@tonic-gate 
74650Sstevel@tonic-gate 	return (0);
74660Sstevel@tonic-gate }
74670Sstevel@tonic-gate 
74680Sstevel@tonic-gate /*
74690Sstevel@tonic-gate  *	Function to test each byte of the source string to make sure it is
74700Sstevel@tonic-gate  *	in within bounds (value between 0 and 127).
74710Sstevel@tonic-gate  *	If valid, copy source to target.
74720Sstevel@tonic-gate  */
74730Sstevel@tonic-gate 
74740Sstevel@tonic-gate int
c_utf8(char * target,const char * source)74750Sstevel@tonic-gate c_utf8(char *target, const char *source)
74760Sstevel@tonic-gate {
74770Sstevel@tonic-gate 	size_t		len;
74780Sstevel@tonic-gate 	const char	*thischar;
74790Sstevel@tonic-gate 
74800Sstevel@tonic-gate 	len = strlen(source);
74810Sstevel@tonic-gate 	thischar = source;
74820Sstevel@tonic-gate 	while (len-- > 0) {
74830Sstevel@tonic-gate 		if (!isascii((int)(*thischar++)))
74840Sstevel@tonic-gate 			return (1);
74850Sstevel@tonic-gate 	}
74860Sstevel@tonic-gate 
74870Sstevel@tonic-gate 	(void) strcpy(target, source);
74880Sstevel@tonic-gate 	return (0);
74890Sstevel@tonic-gate }
74900Sstevel@tonic-gate 
74910Sstevel@tonic-gate 
74920Sstevel@tonic-gate #if defined(O_XATTR)
74930Sstevel@tonic-gate #define	ROUNDTOTBLOCK(a)	((a + (TBLOCK -1)) & ~(TBLOCK -1))
74940Sstevel@tonic-gate 
74950Sstevel@tonic-gate static void
prepare_xattr(char ** attrbuf,char * filename,char * attrpath,char typeflag,struct linkbuf * linkinfo,int * rlen)74960Sstevel@tonic-gate prepare_xattr(
74970Sstevel@tonic-gate 	char		**attrbuf,
74980Sstevel@tonic-gate 	char		*filename,
74995331Samw 	char		*attrpath,
75000Sstevel@tonic-gate 	char		typeflag,
75010Sstevel@tonic-gate 	struct linkbuf	*linkinfo,
75020Sstevel@tonic-gate 	int		*rlen)
75030Sstevel@tonic-gate {
75040Sstevel@tonic-gate 	char			*bufhead;	/* ptr to full buffer */
75055331Samw 	char			*aptr;
75060Sstevel@tonic-gate 	struct xattr_hdr 	*hptr;		/* ptr to header in bufhead */
75070Sstevel@tonic-gate 	struct xattr_buf	*tptr;		/* ptr to pathing pieces */
75080Sstevel@tonic-gate 	int			totalen;	/* total buffer length */
75090Sstevel@tonic-gate 	int			len;		/* length returned to user */
75100Sstevel@tonic-gate 	int			stringlen;	/* length of filename + attr */
75110Sstevel@tonic-gate 						/*
75120Sstevel@tonic-gate 						 * length of filename + attr
75130Sstevel@tonic-gate 						 * in link section
75140Sstevel@tonic-gate 						 */
75150Sstevel@tonic-gate 	int			linkstringlen;
75160Sstevel@tonic-gate 	int			complen;	/* length of pathing section */
75170Sstevel@tonic-gate 	int			linklen;	/* length of link section */
75185331Samw 	int			attrnames_index; /* attrnames starting index */
75190Sstevel@tonic-gate 
75200Sstevel@tonic-gate 	/*
75210Sstevel@tonic-gate 	 * Release previous buffer
75220Sstevel@tonic-gate 	 */
75230Sstevel@tonic-gate 
75240Sstevel@tonic-gate 	if (*attrbuf != (char *)NULL) {
75250Sstevel@tonic-gate 		free(*attrbuf);
75260Sstevel@tonic-gate 		*attrbuf = NULL;
75270Sstevel@tonic-gate 	}
75280Sstevel@tonic-gate 
75290Sstevel@tonic-gate 	/*
75300Sstevel@tonic-gate 	 * First add in fixed size stuff
75310Sstevel@tonic-gate 	 */
75320Sstevel@tonic-gate 	len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
75330Sstevel@tonic-gate 
75340Sstevel@tonic-gate 	/*
75350Sstevel@tonic-gate 	 * Add space for two nulls
75360Sstevel@tonic-gate 	 */
75375331Samw 	stringlen = strlen(attrpath) + strlen(filename) + 2;
75380Sstevel@tonic-gate 	complen = stringlen + sizeof (struct xattr_buf);
75390Sstevel@tonic-gate 
75400Sstevel@tonic-gate 	len += stringlen;
75410Sstevel@tonic-gate 
75420Sstevel@tonic-gate 	/*
75430Sstevel@tonic-gate 	 * Now add on space for link info if any
75440Sstevel@tonic-gate 	 */
75450Sstevel@tonic-gate 
75460Sstevel@tonic-gate 	if (linkinfo != NULL) {
75470Sstevel@tonic-gate 		/*
75480Sstevel@tonic-gate 		 * Again add space for two nulls
75490Sstevel@tonic-gate 		 */
75500Sstevel@tonic-gate 		linkstringlen = strlen(linkinfo->pathname) +
75510Sstevel@tonic-gate 		    strlen(linkinfo->attrname) + 2;
75525331Samw 		linklen = linkstringlen + sizeof (struct xattr_buf);
75535331Samw 		len += linklen;
75545331Samw 	} else {
75555331Samw 		linklen = 0;
75560Sstevel@tonic-gate 	}
75570Sstevel@tonic-gate 
75580Sstevel@tonic-gate 	/*
75590Sstevel@tonic-gate 	 * Now add padding to end to fill out TBLOCK
75600Sstevel@tonic-gate 	 *
75610Sstevel@tonic-gate 	 * Function returns size of real data and not size + padding.
75620Sstevel@tonic-gate 	 */
75630Sstevel@tonic-gate 
75640Sstevel@tonic-gate 	totalen = ROUNDTOTBLOCK(len);
75650Sstevel@tonic-gate 
75660Sstevel@tonic-gate 	if ((bufhead = calloc(1, totalen)) == NULL) {
75670Sstevel@tonic-gate 		fatal(gettext("Out of memory."));
75680Sstevel@tonic-gate 	}
75690Sstevel@tonic-gate 
75700Sstevel@tonic-gate 
75710Sstevel@tonic-gate 	/*
75720Sstevel@tonic-gate 	 * Now we can fill in the necessary pieces
75730Sstevel@tonic-gate 	 */
75740Sstevel@tonic-gate 
75750Sstevel@tonic-gate 	/*
75760Sstevel@tonic-gate 	 * first fill in the fixed header
75770Sstevel@tonic-gate 	 */
75780Sstevel@tonic-gate 	hptr = (struct xattr_hdr *)bufhead;
75790Sstevel@tonic-gate 	(void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
75800Sstevel@tonic-gate 	(void) sprintf(hptr->h_component_len, "%0*d",
75810Sstevel@tonic-gate 	    sizeof (hptr->h_component_len) - 1, complen);
75820Sstevel@tonic-gate 	(void) sprintf(hptr->h_link_component_len, "%0*d",
75830Sstevel@tonic-gate 	    sizeof (hptr->h_link_component_len) - 1, linklen);
75840Sstevel@tonic-gate 	(void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
75850Sstevel@tonic-gate 
75860Sstevel@tonic-gate 	/*
75870Sstevel@tonic-gate 	 * Now fill in the filename + attrnames section
75885331Samw 	 * The filename and attrnames section can be composed of two or more
75895331Samw 	 * path segments separated by a null character.  The first segment
75905331Samw 	 * is the path to the parent file that roots the entire sequence in
75915331Samw 	 * the normal name space. The remaining segments describes a path
75925331Samw 	 * rooted at the hidden extended attribute directory of the leaf file of
75935331Samw 	 * the previous segment, making it possible to name attributes on
75945331Samw 	 * attributes.  Thus, if we are just archiving an extended attribute,
75955331Samw 	 * the second segment will contain the attribute name.  If we are
75965331Samw 	 * archiving a system attribute of an extended attribute, then the
75975331Samw 	 * second segment will contain the attribute name, and a third segment
75985331Samw 	 * will contain the system attribute name.  The attribute pathing
75995331Samw 	 * information is obtained from 'attrpath'.
76000Sstevel@tonic-gate 	 */
76010Sstevel@tonic-gate 
76020Sstevel@tonic-gate 	tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
76030Sstevel@tonic-gate 	(void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
76040Sstevel@tonic-gate 	    stringlen);
76050Sstevel@tonic-gate 	(void) strcpy(tptr->h_names, filename);
76065331Samw 	attrnames_index = strlen(filename) + 1;
76075331Samw 	(void) strcpy(&tptr->h_names[attrnames_index], attrpath);
76080Sstevel@tonic-gate 	tptr->h_typeflag = typeflag;
76090Sstevel@tonic-gate 
76100Sstevel@tonic-gate 	/*
76115331Samw 	 * Split the attrnames section into two segments if 'attrpath'
76125331Samw 	 * contains pathing information for a system attribute of an
76135331Samw 	 * extended attribute.  We split them by replacing the '/' with
76145331Samw 	 * a '\0'.
76155331Samw 	 */
76165331Samw 	if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
76175331Samw 		*aptr = '\0';
76185331Samw 	}
76195331Samw 
76205331Samw 	/*
76210Sstevel@tonic-gate 	 * Now fill in the optional link section if we have one
76220Sstevel@tonic-gate 	 */
76230Sstevel@tonic-gate 
76240Sstevel@tonic-gate 	if (linkinfo != (struct linkbuf *)NULL) {
76250Sstevel@tonic-gate 		tptr = (struct xattr_buf *)(bufhead +
76260Sstevel@tonic-gate 		    sizeof (struct xattr_hdr) + complen);
76270Sstevel@tonic-gate 
76280Sstevel@tonic-gate 		(void) sprintf(tptr->h_namesz, "%0*d",
76290Sstevel@tonic-gate 		    sizeof (tptr->h_namesz) - 1, linkstringlen);
76300Sstevel@tonic-gate 		(void) strcpy(tptr->h_names, linkinfo->pathname);
76310Sstevel@tonic-gate 		(void) strcpy(
76320Sstevel@tonic-gate 		    &tptr->h_names[strlen(linkinfo->pathname) + 1],
76330Sstevel@tonic-gate 		    linkinfo->attrname);
76340Sstevel@tonic-gate 		tptr->h_typeflag = typeflag;
76350Sstevel@tonic-gate 	}
76360Sstevel@tonic-gate 	*attrbuf = (char *)bufhead;
76370Sstevel@tonic-gate 	*rlen = len;
76380Sstevel@tonic-gate }
76390Sstevel@tonic-gate 
76400Sstevel@tonic-gate #else
76410Sstevel@tonic-gate static void
prepare_xattr(char ** attrbuf,char * filename,char * attrname,char typeflag,struct linkbuf * linkinfo,int * rlen)76420Sstevel@tonic-gate prepare_xattr(
76430Sstevel@tonic-gate 	char		**attrbuf,
76440Sstevel@tonic-gate 	char		*filename,
76450Sstevel@tonic-gate 	char		*attrname,
76460Sstevel@tonic-gate 	char		typeflag,
76470Sstevel@tonic-gate 	struct linkbuf	*linkinfo,
76480Sstevel@tonic-gate 	int		*rlen)
76490Sstevel@tonic-gate {
76500Sstevel@tonic-gate 	*attrbuf = NULL;
76510Sstevel@tonic-gate 	*rlen = 0;
76520Sstevel@tonic-gate }
76530Sstevel@tonic-gate #endif
76540Sstevel@tonic-gate 
76550Sstevel@tonic-gate int
getstat(int dirfd,char * longname,char * shortname,char * attrparent)76565331Samw getstat(int dirfd, char *longname, char *shortname, char *attrparent)
76570Sstevel@tonic-gate {
76580Sstevel@tonic-gate 
76590Sstevel@tonic-gate 	int i, j;
76600Sstevel@tonic-gate 	int	printerr;
76610Sstevel@tonic-gate 	int	slnkerr;
76620Sstevel@tonic-gate 	struct stat symlnbuf;
76630Sstevel@tonic-gate 
76640Sstevel@tonic-gate 	if (!hflag)
76650Sstevel@tonic-gate 		i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
76660Sstevel@tonic-gate 	else
76670Sstevel@tonic-gate 		i = fstatat(dirfd, shortname, &stbuf, 0);
76680Sstevel@tonic-gate 
76690Sstevel@tonic-gate 	if (i < 0) {
76700Sstevel@tonic-gate 		/* Initialize flag to print error mesg. */
76710Sstevel@tonic-gate 		printerr = 1;
76720Sstevel@tonic-gate 		/*
76730Sstevel@tonic-gate 		 * If stat is done, then need to do lstat
76740Sstevel@tonic-gate 		 * to determine whether it's a sym link
76750Sstevel@tonic-gate 		 */
76760Sstevel@tonic-gate 		if (hflag) {
76770Sstevel@tonic-gate 			/* Save returned error */
76780Sstevel@tonic-gate 			slnkerr = errno;
76790Sstevel@tonic-gate 
76800Sstevel@tonic-gate 			j = fstatat(dirfd, shortname,
76810Sstevel@tonic-gate 			    &symlnbuf, AT_SYMLINK_NOFOLLOW);
76820Sstevel@tonic-gate 			/*
76830Sstevel@tonic-gate 			 * Suppress error message when file is a symbolic link
76840Sstevel@tonic-gate 			 * and function modifier 'l' is off.  Exception:  when
76850Sstevel@tonic-gate 			 * a symlink points to a symlink points to a
76860Sstevel@tonic-gate 			 * symlink ... and we get past MAXSYMLINKS.  That
76870Sstevel@tonic-gate 			 * error will cause a file not to be archived, and
76880Sstevel@tonic-gate 			 * needs to be printed.
76890Sstevel@tonic-gate 			 */
76900Sstevel@tonic-gate 			if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
76910Sstevel@tonic-gate 			    (S_ISLNK(symlnbuf.st_mode)))
76920Sstevel@tonic-gate 				printerr = 0;
76930Sstevel@tonic-gate 
76940Sstevel@tonic-gate 			/*
76950Sstevel@tonic-gate 			 * Restore errno in case the lstat
76960Sstevel@tonic-gate 			 * on symbolic link change
76970Sstevel@tonic-gate 			 */
76980Sstevel@tonic-gate 			errno = slnkerr;
76990Sstevel@tonic-gate 		}
77000Sstevel@tonic-gate 
77010Sstevel@tonic-gate 		if (printerr) {
77020Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
77035331Samw 			    "tar: %s%s%s%s: %s\n"),
77045331Samw 			    (attrparent == NULL) ? "" : gettext("attribute "),
77055331Samw 			    (attrparent == NULL) ? "" : attrparent,
77065331Samw 			    (attrparent == NULL) ? "" : gettext(" of "),
77075331Samw 			    longname, strerror(errno));
77080Sstevel@tonic-gate 			Errflg = 1;
77090Sstevel@tonic-gate 		}
77100Sstevel@tonic-gate 		return (1);
77110Sstevel@tonic-gate 	}
77120Sstevel@tonic-gate 	return (0);
77130Sstevel@tonic-gate }
77140Sstevel@tonic-gate 
77155331Samw /*
77165331Samw  * Recursively archive the extended attributes and/or extended system attributes
77175331Samw  * of the base file, longname.  Note:  extended system attribute files will be
77185331Samw  * archived only if the extended system attributes are not transient (i.e. the
77195331Samw  * extended system attributes are other than the default values).
77205331Samw  *
77215331Samw  * If -@ was specified and the underlying file system supports it, archive the
77225331Samw  * extended attributes, and if there is a system attribute associated with the
77235331Samw  * extended attribute, then recursively call xattrs_put() to archive the
77245331Samw  * hidden attribute directory and the extended system attribute.  If -/ was
77255331Samw  * specified and the underlying file system supports it, archive the extended
77265331Samw  * system attributes.  Read-only extended system attributes are never archived.
77275331Samw  *
77285331Samw  * Currently, there cannot be attributes on attributes; only system
77295331Samw  * attributes on attributes.  In addition, there cannot be attributes on
77305331Samw  * system attributes.  A file and it's attribute directory hierarchy looks as
77315331Samw  * follows:
77325331Samw  *	longname ---->	.	("." is the hidden attribute directory)
77335331Samw  *			|
77345331Samw  *	     ----------------------------
77355331Samw  *	     |				|
77365331Samw  *	<sys_attr_name>		   <attr_name> ---->	.
77375331Samw  *							|
77385331Samw  *						  <sys_attr_name>
77395331Samw  *
77405331Samw  */
77410Sstevel@tonic-gate #if defined(O_XATTR)
77420Sstevel@tonic-gate static void
xattrs_put(char * longname,char * shortname,char * parent,char * attrparent)77435331Samw xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
77445331Samw {
77455331Samw 	char *filename = (attrparent == NULL) ? shortname : attrparent;
77465331Samw 	int arc_rwsysattr = 0;
77470Sstevel@tonic-gate 	int dirfd;
77485331Samw 	int fd = -1;
77495331Samw 	int rw_sysattr = 0;
77505750Sceastha 	int ext_attr = 0;
77515331Samw 	int rc;
77520Sstevel@tonic-gate 	DIR *dirp;
77530Sstevel@tonic-gate 	struct dirent *dp;
77545331Samw 	attr_data_t *attrinfo = NULL;
77555331Samw 
77565331Samw 	/*
77575331Samw 	 * If the underlying file system supports it, then archive the extended
77585331Samw 	 * attributes if -@ was specified, and the extended system attributes
77595331Samw 	 * if -/ was specified.
77605331Samw 	 */
77615750Sceastha 	if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
77625750Sceastha 	    &ext_attr) != ATTR_OK) {
77630Sstevel@tonic-gate 		return;
77640Sstevel@tonic-gate 	}
77650Sstevel@tonic-gate 
77665331Samw 	/*
77675331Samw 	 * Only want to archive a read-write extended system attribute file
77685331Samw 	 * if it contains extended system attribute settings that are not the
77695331Samw 	 * default values.
77705331Samw 	 */
77715331Samw #if defined(_PC_SATTR_ENABLED)
77725331Samw 	if (saflag) {
77735331Samw 		int	filefd;
77745331Samw 		nvlist_t *slist = NULL;
77755331Samw 
77765331Samw 		/* Determine if there are non-transient system attributes */
77775331Samw 		errno = 0;
77785331Samw 		if ((filefd = open(filename, O_RDONLY)) == -1) {
77795331Samw 			if (attrparent == NULL) {
77805331Samw 				vperror(0, gettext(
77815331Samw 				    "unable to open file %s"), longname);
77825331Samw 			}
77835331Samw 			return;
77845331Samw 		}
77855331Samw 		if (((slist = sysattr_list(basename(myname), filefd,
77865331Samw 		    filename)) != NULL) || (errno != 0)) {
77875331Samw 			arc_rwsysattr = 1;
77885331Samw 		}
77895331Samw 		if (slist != NULL) {
77905331Samw 			(void) nvlist_free(slist);
77915331Samw 			slist = NULL;
77925331Samw 		}
77935331Samw 		(void) close(filefd);
77945331Samw 	}
77955750Sceastha 
77965750Sceastha 	/*
77975750Sceastha 	 * If we aren't archiving extended system attributes, and we are
77985750Sceastha 	 * processing an attribute, or if we are archiving extended system
77995750Sceastha 	 * attributes, and there are are no extended attributes, then there's
78005750Sceastha 	 * no need to open up the attribute directory of the file unless the
78015750Sceastha 	 * extended system attributes are not transient (i.e, the system
78025750Sceastha 	 * attributes are not the default values).
78035750Sceastha 	 */
78045750Sceastha 	if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
78055750Sceastha 	    (saflag && !ext_attr))) {
78065750Sceastha 		return;
78075750Sceastha 	}
78085331Samw #endif	/* _PC_SATTR_ENABLED */
78095331Samw 
78105331Samw 	/* open the parent attribute directory */
78115331Samw 	fd = attropen(filename, ".", O_RDONLY);
78125331Samw 	if (fd < 0) {
78135331Samw 		vperror(0, gettext(
78145331Samw 		    "unable to open attribute directory for %s%s%sfile %s"),
78155331Samw 		    (attrparent == NULL) ? "" : gettext("attribute "),
78165331Samw 		    (attrparent == NULL) ? "" : attrparent,
78175331Samw 		    (attrparent == NULL) ? "" : gettext(" of "),
78180Sstevel@tonic-gate 		    longname);
78190Sstevel@tonic-gate 		return;
78200Sstevel@tonic-gate 	}
78210Sstevel@tonic-gate 
78225331Samw 	/*
78235331Samw 	 * We need to change into the parent's attribute directory to determine
78245331Samw 	 * if each of the attributes should be archived.
78255331Samw 	 */
78265331Samw 	if (fchdir(fd) < 0) {
78275331Samw 		vperror(0, gettext(
78285331Samw 		    "cannot change to attribute directory of %s%s%sfile %s"),
78295331Samw 		    (attrparent == NULL) ? "" : gettext("attribute "),
78305331Samw 		    (attrparent == NULL) ? "" : attrparent,
78315331Samw 		    (attrparent == NULL) ? "" : gettext(" of "),
78325331Samw 		    longname);
78335331Samw 		(void) close(fd);
78345331Samw 		return;
78355331Samw 	}
78365331Samw 
78375331Samw 	if (((dirfd = dup(fd)) == -1) ||
78385331Samw 	    ((dirp = fdopendir(dirfd)) == NULL)) {
78390Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
78405331Samw 		    "tar: unable to open dir pointer for %s%s%sfile %s\n"),
78415331Samw 		    (attrparent == NULL) ? "" : gettext("attribute "),
78425331Samw 		    (attrparent == NULL) ? "" : attrparent,
78435331Samw 		    (attrparent == NULL) ? "" : gettext(" of "),
78445331Samw 		    longname);
78455331Samw 		if (fd > 0) {
78465331Samw 			(void) close(fd);
78475331Samw 		}
78480Sstevel@tonic-gate 		return;
78490Sstevel@tonic-gate 	}
78500Sstevel@tonic-gate 
78510Sstevel@tonic-gate 	while (dp = readdir(dirp)) {
78525331Samw 		if (strcmp(dp->d_name, "..") == 0) {
78530Sstevel@tonic-gate 			continue;
78545331Samw 		} else if (strcmp(dp->d_name, ".") == 0) {
78550Sstevel@tonic-gate 			Hiddendir = 1;
78565331Samw 		} else {
78570Sstevel@tonic-gate 			Hiddendir = 0;
78585331Samw 		}
78595331Samw 
78605331Samw 		/* Determine if this attribute should be archived */
78615331Samw 		if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
78625331Samw 		    &rw_sysattr) != ATTR_OK) {
78635331Samw 			continue;
78645331Samw 		}
78655331Samw 
78665331Samw 		/* gather the attribute's information to pass to putfile() */
78675331Samw 		if ((fill_in_attr_info(dp->d_name, longname, attrparent,
78685331Samw 		    fd, rw_sysattr, &attrinfo)) == 1) {
78695331Samw 			continue;
78705331Samw 		}
78715331Samw 
78725331Samw 		/* add the attribute to the archive */
78735331Samw 		rc = putfile(longname, dp->d_name, parent, attrinfo,
78740Sstevel@tonic-gate 		    XATTR_FILE, LEV0, SYMLINK_LEV0);
78750Sstevel@tonic-gate 
78765331Samw 		if (exitflag) {
78770Sstevel@tonic-gate 			break;
78785331Samw 		}
78795331Samw 
78805331Samw #if defined(_PC_SATTR_ENABLED)
78815331Samw 		/*
78825331Samw 		 * If both -/ and -@ were specified, then archive the
78835331Samw 		 * attribute's extended system attributes and hidden directory
78845331Samw 		 * by making a recursive call to xattrs_put().
78855331Samw 		 */
78865331Samw 		if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
78875331Samw 		    (Hiddendir == 0)) {
78885331Samw 
78895331Samw 			xattrs_put(longname, shortname, parent, dp->d_name);
78905331Samw 
78915331Samw 			/*
78925331Samw 			 * Change back to the parent's attribute directory
78935331Samw 			 * to process any further attributes.
78945331Samw 			 */
78955331Samw 			if (fchdir(fd) < 0) {
78965331Samw 				vperror(0, gettext(
78975331Samw 				    "cannot change back to attribute directory "
78985331Samw 				    "of file %s"), longname);
78995331Samw 				break;
79005331Samw 			}
79015331Samw 		}
79025331Samw #endif	/* _PC_SATTR_ENABLED */
79035331Samw 	}
79045331Samw 
79055331Samw 	if (attrinfo != NULL) {
79065331Samw 		if (attrinfo->attr_parent != NULL) {
79075331Samw 			free(attrinfo->attr_parent);
79085331Samw 		}
79095331Samw 		free(attrinfo->attr_path);
79105331Samw 		free(attrinfo);
79115331Samw 	}
79120Sstevel@tonic-gate 	(void) closedir(dirp);
79135331Samw 	if (fd != -1) {
79145331Samw 		(void) close(fd);
79155331Samw 	}
79165331Samw 
79175331Samw 	/* Change back to the parent directory of the base file */
79185331Samw 	if (attrparent == NULL) {
791912554Srich.burridge@oracle.com 		(void) tar_chdir(parent);
79205331Samw 	}
79215750Sceastha 	Hiddendir = 0;
79220Sstevel@tonic-gate }
79230Sstevel@tonic-gate #else
79240Sstevel@tonic-gate static void
xattrs_put(char * longname,char * shortname,char * parent,char * attrppath)79255331Samw xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
79260Sstevel@tonic-gate {
79270Sstevel@tonic-gate }
79280Sstevel@tonic-gate #endif /* O_XATTR */
79290Sstevel@tonic-gate 
79300Sstevel@tonic-gate static int
put_link(char * name,char * longname,char * component,char * longattrname,char * prefix,int filetype,char type)79315331Samw put_link(char *name, char *longname, char *component, char *longattrname,
79325331Samw     char *prefix, int filetype, char type)
79330Sstevel@tonic-gate {
79340Sstevel@tonic-gate 
79350Sstevel@tonic-gate 	if (stbuf.st_nlink > 1) {
79360Sstevel@tonic-gate 		struct linkbuf *lp;
79370Sstevel@tonic-gate 		int found = 0;
79380Sstevel@tonic-gate 
79390Sstevel@tonic-gate 		for (lp = ihead; lp != NULL; lp = lp->nextp)
79400Sstevel@tonic-gate 			if (lp->inum == stbuf.st_ino &&
79410Sstevel@tonic-gate 			    lp->devnum == stbuf.st_dev) {
79420Sstevel@tonic-gate 				found++;
79430Sstevel@tonic-gate 				break;
79440Sstevel@tonic-gate 			}
79450Sstevel@tonic-gate 		if (found) {
79460Sstevel@tonic-gate #if defined(O_XATTR)
79470Sstevel@tonic-gate 			if (filetype == XATTR_FILE)
79485331Samw 				if (put_xattr_hdr(longname, component,
79495331Samw 				    longattrname, prefix, type, filetype, lp)) {
79500Sstevel@tonic-gate 					goto out;
79510Sstevel@tonic-gate 			}
79520Sstevel@tonic-gate #endif
79530Sstevel@tonic-gate 			stbuf.st_size = (off_t)0;
79540Sstevel@tonic-gate 			if (filetype != XATTR_FILE) {
79550Sstevel@tonic-gate 				tomodes(&stbuf);
79560Sstevel@tonic-gate 				if (chk_path_build(name, longname, lp->pathname,
79570Sstevel@tonic-gate 				    prefix, type, filetype) > 0) {
79580Sstevel@tonic-gate 					goto out;
79590Sstevel@tonic-gate 				}
79600Sstevel@tonic-gate 			}
79610Sstevel@tonic-gate 
79620Sstevel@tonic-gate 			if (mulvol && tapepos + 1 >= blocklim)
79630Sstevel@tonic-gate 				newvol();
79640Sstevel@tonic-gate 			(void) writetbuf((char *)&dblock, 1);
79650Sstevel@tonic-gate 			/*
79660Sstevel@tonic-gate 			 * write_ancillary() is not needed here.
79670Sstevel@tonic-gate 			 * The first link is handled in the following
79680Sstevel@tonic-gate 			 * else statement. No need to process ACLs
79690Sstevel@tonic-gate 			 * for other hard links since they are the
79700Sstevel@tonic-gate 			 * same file.
79710Sstevel@tonic-gate 			 */
79720Sstevel@tonic-gate 
79730Sstevel@tonic-gate 			if (vflag) {
79740Sstevel@tonic-gate #ifdef DEBUG
79750Sstevel@tonic-gate 				if (NotTape)
79760Sstevel@tonic-gate 					DEBUG("seek = %" FMT_blkcnt_t
79770Sstevel@tonic-gate 					    "K\t", K(tapepos), 0);
79780Sstevel@tonic-gate #endif
79790Sstevel@tonic-gate 				if (filetype == XATTR_FILE) {
79800Sstevel@tonic-gate 					(void) fprintf(vfile, gettext(
79810Sstevel@tonic-gate 					    "a %s attribute %s link to "
79825331Samw 					    "%s attribute %s\n"),
79835331Samw 					    name, component, name,
79845331Samw 					    lp->attrname);
79850Sstevel@tonic-gate 				} else {
79860Sstevel@tonic-gate 					(void) fprintf(vfile, gettext(
79870Sstevel@tonic-gate 					    "a %s link to %s\n"),
79880Sstevel@tonic-gate 					    longname, lp->pathname);
79890Sstevel@tonic-gate 				}
79900Sstevel@tonic-gate 			}
79910Sstevel@tonic-gate 			lp->count--;
79920Sstevel@tonic-gate 			return (0);
79930Sstevel@tonic-gate 		} else {
79940Sstevel@tonic-gate 			lp = (struct linkbuf *)getmem(sizeof (*lp));
79950Sstevel@tonic-gate 			if (lp != (struct linkbuf *)NULL) {
79960Sstevel@tonic-gate 				lp->nextp = ihead;
79970Sstevel@tonic-gate 				ihead = lp;
79980Sstevel@tonic-gate 				lp->inum = stbuf.st_ino;
79990Sstevel@tonic-gate 				lp->devnum = stbuf.st_dev;
80000Sstevel@tonic-gate 				lp->count = stbuf.st_nlink - 1;
80010Sstevel@tonic-gate 				if (filetype == XATTR_FILE) {
80020Sstevel@tonic-gate 					(void) strcpy(lp->pathname, longname);
80035331Samw 					(void) strcpy(lp->attrname,
80045331Samw 					    component);
80050Sstevel@tonic-gate 				} else {
80060Sstevel@tonic-gate 					(void) strcpy(lp->pathname, longname);
80070Sstevel@tonic-gate 					(void) strcpy(lp->attrname, "");
80080Sstevel@tonic-gate 				}
80090Sstevel@tonic-gate 			}
80100Sstevel@tonic-gate 		}
80110Sstevel@tonic-gate 	}
80120Sstevel@tonic-gate 
80130Sstevel@tonic-gate out:
80140Sstevel@tonic-gate 	return (1);
80150Sstevel@tonic-gate }
80160Sstevel@tonic-gate 
80170Sstevel@tonic-gate static int
put_extra_attributes(char * longname,char * shortname,char * longattrname,char * prefix,int filetype,char typeflag)80185331Samw put_extra_attributes(char *longname, char *shortname, char *longattrname,
80195331Samw     char *prefix, int filetype, char typeflag)
80200Sstevel@tonic-gate {
8021789Sahrens 	static acl_t *aclp = NULL;
8022789Sahrens 	int error;
8023789Sahrens 
8024789Sahrens 	if (aclp != NULL) {
8025789Sahrens 		acl_free(aclp);
80260Sstevel@tonic-gate 		aclp = NULL;
80270Sstevel@tonic-gate 	}
80280Sstevel@tonic-gate #if defined(O_XATTR)
80295331Samw 	if ((atflag || saflag) && (filetype == XATTR_FILE)) {
80305331Samw 		if (put_xattr_hdr(longname, shortname, longattrname, prefix,
80310Sstevel@tonic-gate 		    typeflag, filetype, NULL)) {
80320Sstevel@tonic-gate 			return (1);
80330Sstevel@tonic-gate 		}
80340Sstevel@tonic-gate 	}
80350Sstevel@tonic-gate #endif
80360Sstevel@tonic-gate 
80370Sstevel@tonic-gate 	/* ACL support */
80380Sstevel@tonic-gate 	if (pflag) {
80390Sstevel@tonic-gate 		char	*secinfo = NULL;
80400Sstevel@tonic-gate 		int	len = 0;
80410Sstevel@tonic-gate 
80420Sstevel@tonic-gate 		/* ACL support */
80430Sstevel@tonic-gate 		if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
80440Sstevel@tonic-gate 			/*
80450Sstevel@tonic-gate 			 * Get ACL info: dont bother allocating space if
8046789Sahrens 			 * there is only a trivial ACL.
80470Sstevel@tonic-gate 			 */
8048789Sahrens 			if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8049789Sahrens 			    &aclp)) != 0) {
80500Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
8051789Sahrens 				    "%s: failed to retrieve acl : %s\n"),
8052789Sahrens 				    longname, acl_strerror(error));
80530Sstevel@tonic-gate 				return (1);
80540Sstevel@tonic-gate 			}
80550Sstevel@tonic-gate 		}
80560Sstevel@tonic-gate 
80570Sstevel@tonic-gate 		/* append security attributes if any */
8058789Sahrens 		if (aclp != NULL) {
80591676Sjpk 			(void) append_secattr(&secinfo, &len, acl_cnt(aclp),
80607057Smarks 			    acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
80617057Smarks 			    ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
80627057Smarks 			    UFSD_ACL : ACE_ACL);
80631676Sjpk 		}
80641676Sjpk 
80651676Sjpk 		if (Tflag) {
80661676Sjpk 			/* append Trusted Extensions extended attributes */
80671676Sjpk 			append_ext_attr(shortname, &secinfo, &len);
80681676Sjpk 			(void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
80691676Sjpk 
80701676Sjpk 		} else if (aclp != NULL) {
80710Sstevel@tonic-gate 			(void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
80720Sstevel@tonic-gate 		}
80730Sstevel@tonic-gate 	}
80740Sstevel@tonic-gate 	return (0);
80750Sstevel@tonic-gate }
80760Sstevel@tonic-gate 
80770Sstevel@tonic-gate #if defined(O_XATTR)
80780Sstevel@tonic-gate static int
put_xattr_hdr(char * longname,char * shortname,char * longattrname,char * prefix,int typeflag,int filetype,struct linkbuf * lp)80795331Samw put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
80800Sstevel@tonic-gate 	int typeflag, int filetype, struct linkbuf *lp)
80810Sstevel@tonic-gate {
80820Sstevel@tonic-gate 	char *lname = NULL;
80830Sstevel@tonic-gate 	char *sname = NULL;
80840Sstevel@tonic-gate 	int  error = 0;
80850Sstevel@tonic-gate 	static char *attrbuf = NULL;
80860Sstevel@tonic-gate 	int attrlen;
80870Sstevel@tonic-gate 
80880Sstevel@tonic-gate 	lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
80890Sstevel@tonic-gate 	    strlen(shortname) + strlen(".hdr") + 1);
80900Sstevel@tonic-gate 
80910Sstevel@tonic-gate 	if (lname == NULL) {
80920Sstevel@tonic-gate 		fatal(gettext("Out of Memory."));
80930Sstevel@tonic-gate 	}
80940Sstevel@tonic-gate 	sname = malloc(sizeof (char) * strlen(shortname) +
80955331Samw 	    strlen(".hdr") + 1);
80960Sstevel@tonic-gate 	if (sname == NULL) {
80970Sstevel@tonic-gate 		fatal(gettext("Out of Memory."));
80980Sstevel@tonic-gate 	}
80990Sstevel@tonic-gate 
81000Sstevel@tonic-gate 	(void) sprintf(sname, "%s.hdr", shortname);
81010Sstevel@tonic-gate 	(void) sprintf(lname, "/dev/null/%s", sname);
81020Sstevel@tonic-gate 
81030Sstevel@tonic-gate 	if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
81040Sstevel@tonic-gate 	    sizeof (dblock.dbuf.name)) {
81050Sstevel@tonic-gate 		fatal(gettext(
81060Sstevel@tonic-gate 		    "Buffer overflow writing extended attribute file name"));
81070Sstevel@tonic-gate 	}
81080Sstevel@tonic-gate 
81090Sstevel@tonic-gate 	/*
81100Sstevel@tonic-gate 	 * dump extended attr lookup info
81110Sstevel@tonic-gate 	 */
81125331Samw 	prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
81130Sstevel@tonic-gate 	write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
81140Sstevel@tonic-gate 
81150Sstevel@tonic-gate 	(void) sprintf(lname, "/dev/null/%s", shortname);
81160Sstevel@tonic-gate 	(void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
81170Sstevel@tonic-gate 
81180Sstevel@tonic-gate 	/*
81190Sstevel@tonic-gate 	 * Set up filename for attribute
81200Sstevel@tonic-gate 	 */
81210Sstevel@tonic-gate 
81220Sstevel@tonic-gate 	error = build_dblock(lname, tchar, '0', filetype,
81230Sstevel@tonic-gate 	    &stbuf, stbuf.st_dev, prefix);
81240Sstevel@tonic-gate 	free(lname);
81250Sstevel@tonic-gate 	free(sname);
81260Sstevel@tonic-gate 
81270Sstevel@tonic-gate 	return (error);
81280Sstevel@tonic-gate }
81290Sstevel@tonic-gate #endif
81300Sstevel@tonic-gate 
81310Sstevel@tonic-gate #if defined(O_XATTR)
81320Sstevel@tonic-gate static int
read_xattr_hdr(attr_data_t ** attrinfo)81335331Samw read_xattr_hdr(attr_data_t **attrinfo)
81340Sstevel@tonic-gate {
81350Sstevel@tonic-gate 	char		buf[TBLOCK];
81365331Samw 	char		*attrparent = NULL;
81370Sstevel@tonic-gate 	blkcnt_t	blocks;
81380Sstevel@tonic-gate 	char		*tp;
81390Sstevel@tonic-gate 	off_t		bytes;
81400Sstevel@tonic-gate 	int		comp_len, link_len;
81410Sstevel@tonic-gate 	int		namelen;
81425331Samw 	int		attrparentlen;
81435331Samw 	int		parentfilelen;
81440Sstevel@tonic-gate 
81450Sstevel@tonic-gate 	if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
81460Sstevel@tonic-gate 		return (1);
81470Sstevel@tonic-gate 
81480Sstevel@tonic-gate 	bytes = stbuf.st_size;
81490Sstevel@tonic-gate 	if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
81500Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
81510Sstevel@tonic-gate 		    "Insufficient memory for extended attribute\n"));
81520Sstevel@tonic-gate 		return (1);
81530Sstevel@tonic-gate 	}
81540Sstevel@tonic-gate 
81550Sstevel@tonic-gate 	tp = (char *)xattrhead;
81560Sstevel@tonic-gate 	blocks = TBLOCKS(bytes);
81570Sstevel@tonic-gate 	while (blocks-- > 0) {
81580Sstevel@tonic-gate 		readtape(buf);
81590Sstevel@tonic-gate 		if (bytes <= TBLOCK) {
81600Sstevel@tonic-gate 			(void) memcpy(tp, buf, (size_t)bytes);
81610Sstevel@tonic-gate 			break;
81620Sstevel@tonic-gate 		} else {
81630Sstevel@tonic-gate 			(void) memcpy(tp, buf, TBLOCK);
81640Sstevel@tonic-gate 			tp += TBLOCK;
81650Sstevel@tonic-gate 		}
81660Sstevel@tonic-gate 		bytes -= TBLOCK;
81670Sstevel@tonic-gate 	}
81680Sstevel@tonic-gate 
81690Sstevel@tonic-gate 	/*
81700Sstevel@tonic-gate 	 * Validate that we can handle header format
81710Sstevel@tonic-gate 	 */
81720Sstevel@tonic-gate 	if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
81730Sstevel@tonic-gate 		(void) fprintf(stderr,
81740Sstevel@tonic-gate 		    gettext("Unknown extended attribute format encountered\n"));
81750Sstevel@tonic-gate 		(void) fprintf(stderr,
81760Sstevel@tonic-gate 		    gettext("Disabling extended attribute parsing\n"));
81770Sstevel@tonic-gate 		xattrbadhead = 1;
81780Sstevel@tonic-gate 		return (0);
81790Sstevel@tonic-gate 	}
81800Sstevel@tonic-gate 	(void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
81810Sstevel@tonic-gate 	(void) sscanf(xattrhead->h_link_component_len,	"%10d", &link_len);
81820Sstevel@tonic-gate 	xattrp = (struct xattr_buf *)(((char *)xattrhead) +
81830Sstevel@tonic-gate 	    sizeof (struct xattr_hdr));
81840Sstevel@tonic-gate 	(void) sscanf(xattrp->h_namesz, "%7d", &namelen);
81850Sstevel@tonic-gate 	if (link_len > 0)
81860Sstevel@tonic-gate 		xattr_linkp = (struct xattr_buf *)
81870Sstevel@tonic-gate 		    ((int)xattrp + (int)comp_len);
81880Sstevel@tonic-gate 	else
81890Sstevel@tonic-gate 		xattr_linkp = NULL;
81900Sstevel@tonic-gate 
81915331Samw 	/*
81925331Samw 	 * Gather the attribute path from the filename and attrnames section.
81935331Samw 	 * The filename and attrnames section can be composed of two or more
81945331Samw 	 * path segments separated by a null character.  The first segment
81955331Samw 	 * is the path to the parent file that roots the entire sequence in
81965331Samw 	 * the normal name space. The remaining segments describes a path
81975331Samw 	 * rooted at the hidden extended attribute directory of the leaf file of
81985331Samw 	 * the previous segment, making it possible to name attributes on
81995331Samw 	 * attributes.
82005331Samw 	 */
82015331Samw 	parentfilelen = strlen(xattrp->h_names);
82025331Samw 	xattrapath = xattrp->h_names + parentfilelen + 1;
82035331Samw 	if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
82045331Samw 		/*
82055331Samw 		 * The attrnames section contains a system attribute on an
82065331Samw 		 * attribute.  Save the name of the attribute for use later,
82075331Samw 		 * and replace the null separating the attribute name from
82085331Samw 		 * the system attribute name with a '/' so that xattrapath can
82095331Samw 		 * be used to display messages with the full attribute path name
82105331Samw 		 * rooted at the hidden attribute directory of the base file
82115331Samw 		 * in normal name space.
82125331Samw 		 */
82135331Samw 		attrparent = strdup(xattrapath);
82145331Samw 		attrparentlen = strlen(attrparent);
82155331Samw 		xattrapath[attrparentlen] = '/';
82165331Samw 	}
82175331Samw 	if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
82185331Samw 	    xattrapath + attrparentlen + 1, xattrapath, attrparent,
82195331Samw 	    -1, 0, attrinfo)) == 1) {
82205331Samw 		free(attrparent);
82215331Samw 		return (1);
82225331Samw 	}
82235331Samw 
82245331Samw 	/* Gather link info */
82250Sstevel@tonic-gate 	if (xattr_linkp) {
82260Sstevel@tonic-gate 		xattr_linkaname = xattr_linkp->h_names +
82270Sstevel@tonic-gate 		    strlen(xattr_linkp->h_names) + 1;
82280Sstevel@tonic-gate 	} else {
82290Sstevel@tonic-gate 		xattr_linkaname = NULL;
82300Sstevel@tonic-gate 	}
82311231Smarks 
82320Sstevel@tonic-gate 	return (0);
82330Sstevel@tonic-gate }
82340Sstevel@tonic-gate #else
82350Sstevel@tonic-gate static int
read_xattr_hdr(attr_data_t ** attrinfo)82365331Samw read_xattr_hdr(attr_data_t **attrinfo)
82370Sstevel@tonic-gate {
82380Sstevel@tonic-gate 	return (0);
82390Sstevel@tonic-gate }
82400Sstevel@tonic-gate #endif
82410Sstevel@tonic-gate 
82420Sstevel@tonic-gate /*
82430Sstevel@tonic-gate  * skip over extra slashes in string.
82440Sstevel@tonic-gate  *
82450Sstevel@tonic-gate  * For example:
82460Sstevel@tonic-gate  * /usr/tmp/////
82470Sstevel@tonic-gate  *
82480Sstevel@tonic-gate  * would return pointer at
82490Sstevel@tonic-gate  * /usr/tmp/////
82500Sstevel@tonic-gate  *         ^
82510Sstevel@tonic-gate  */
82520Sstevel@tonic-gate static char *
skipslashes(char * string,char * start)82530Sstevel@tonic-gate skipslashes(char *string, char *start)
82540Sstevel@tonic-gate {
82550Sstevel@tonic-gate 	while ((string > start) && *(string - 1) == '/') {
82560Sstevel@tonic-gate 		string--;
82570Sstevel@tonic-gate 	}
82580Sstevel@tonic-gate 
82590Sstevel@tonic-gate 	return (string);
82600Sstevel@tonic-gate }
82610Sstevel@tonic-gate 
82620Sstevel@tonic-gate /*
82630Sstevel@tonic-gate  * Return the parent directory of a given path.
82640Sstevel@tonic-gate  *
82650Sstevel@tonic-gate  * Examples:
82660Sstevel@tonic-gate  * /usr/tmp return /usr
82670Sstevel@tonic-gate  * /usr/tmp/file return /usr/tmp
82680Sstevel@tonic-gate  * /  returns .
82690Sstevel@tonic-gate  * /usr returns /
82700Sstevel@tonic-gate  * file returns .
82710Sstevel@tonic-gate  *
82720Sstevel@tonic-gate  * dir is assumed to be at least as big as path.
82730Sstevel@tonic-gate  */
82740Sstevel@tonic-gate static void
get_parent(char * path,char * dir)82750Sstevel@tonic-gate get_parent(char *path, char *dir)
82760Sstevel@tonic-gate {
82770Sstevel@tonic-gate 	char *s;
82780Sstevel@tonic-gate 	char tmpdir[PATH_MAX + 1];
82790Sstevel@tonic-gate 
82800Sstevel@tonic-gate 	if (strlen(path) > PATH_MAX) {
82810Sstevel@tonic-gate 		fatal(gettext("pathname is too long"));
82820Sstevel@tonic-gate 	}
82830Sstevel@tonic-gate 	(void) strcpy(tmpdir, path);
82840Sstevel@tonic-gate 	chop_endslashes(tmpdir);
82850Sstevel@tonic-gate 
82860Sstevel@tonic-gate 	if ((s = strrchr(tmpdir, '/')) == NULL) {
82870Sstevel@tonic-gate 		(void) strcpy(dir, ".");
82880Sstevel@tonic-gate 	} else {
82890Sstevel@tonic-gate 		s = skipslashes(s, tmpdir);
82900Sstevel@tonic-gate 		*s = '\0';
82910Sstevel@tonic-gate 		if (s == tmpdir)
82920Sstevel@tonic-gate 			(void) strcpy(dir, "/");
82930Sstevel@tonic-gate 		else
82940Sstevel@tonic-gate 			(void) strcpy(dir, tmpdir);
82950Sstevel@tonic-gate 	}
82960Sstevel@tonic-gate }
82970Sstevel@tonic-gate 
82980Sstevel@tonic-gate #if defined(O_XATTR)
82990Sstevel@tonic-gate static char *
get_component(char * path)83000Sstevel@tonic-gate get_component(char *path)
83010Sstevel@tonic-gate {
83020Sstevel@tonic-gate 	char *ptr;
83030Sstevel@tonic-gate 
83040Sstevel@tonic-gate 	ptr = strrchr(path, '/');
83050Sstevel@tonic-gate 	if (ptr == NULL) {
83060Sstevel@tonic-gate 		return (path);
83070Sstevel@tonic-gate 	} else {
83080Sstevel@tonic-gate 		/*
83090Sstevel@tonic-gate 		 * Handle trailing slash
83100Sstevel@tonic-gate 		 */
83110Sstevel@tonic-gate 		if (*(ptr + 1) == '\0')
83120Sstevel@tonic-gate 			return (ptr);
83130Sstevel@tonic-gate 		else
83140Sstevel@tonic-gate 			return (ptr + 1);
83150Sstevel@tonic-gate 	}
83160Sstevel@tonic-gate }
83170Sstevel@tonic-gate #else
83180Sstevel@tonic-gate static char *
get_component(char * path)83190Sstevel@tonic-gate get_component(char *path)
83200Sstevel@tonic-gate {
83210Sstevel@tonic-gate 	return (path);
83220Sstevel@tonic-gate }
83230Sstevel@tonic-gate #endif
83240Sstevel@tonic-gate 
83255331Samw #if defined(O_XATTR)
83260Sstevel@tonic-gate static int
retry_open_attr(int pdirfd,int cwd,char * dirp,char * pattr,char * name,int oflag,mode_t mode)83275331Samw retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
83285331Samw     int oflag, mode_t mode)
83295331Samw {
83305331Samw 	int dirfd;
83315331Samw 	int ofilefd = -1;
83320Sstevel@tonic-gate 	struct timeval times[2];
83330Sstevel@tonic-gate 	mode_t newmode;
83340Sstevel@tonic-gate 	struct stat parentstat;
83351231Smarks 	acl_t *aclp = NULL;
83361231Smarks 	int error;
83370Sstevel@tonic-gate 
83380Sstevel@tonic-gate 	/*
83390Sstevel@tonic-gate 	 * We couldn't get to attrdir. See if its
83400Sstevel@tonic-gate 	 * just a mode problem on the parent file.
83410Sstevel@tonic-gate 	 * for example: a mode such as r-xr--r--
83425331Samw 	 * on a ufs file system without extended
83435331Samw 	 * system attribute support won't let us
83445331Samw 	 * create an attribute dir if it doesn't
83455331Samw 	 * already exist, and on a ufs file system
83465331Samw 	 * with extended system attribute support
83475331Samw 	 * won't let us open the attribute for
83485331Samw 	 * write.
83491231Smarks 	 *
83501231Smarks 	 * If file has a non-trivial ACL, then save it
83511231Smarks 	 * off so that we can place it back on after doing
83521231Smarks 	 * chmod's.
83530Sstevel@tonic-gate 	 */
83545331Samw 	if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
83555331Samw 	    O_RDONLY)) == -1) {
83565331Samw 		return (-1);
83575331Samw 	}
83585331Samw 	if (fstat(dirfd, &parentstat) == -1) {
83595331Samw 		(void) fprintf(stderr, gettext(
83605331Samw 		    "tar: cannot stat %sfile %s: %s\n"),
83615331Samw 		    (pdirfd == -1) ? "" : gettext("parent of "),
83625331Samw 		    (pdirfd == -1) ? dirp : name, strerror(errno));
83631231Smarks 			return (-1);
83641231Smarks 	}
83655331Samw 	if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
83665331Samw 		(void) fprintf(stderr, gettext(
83675331Samw 		    "tar: failed to retrieve ACL on %sfile %s: %s\n"),
83685331Samw 		    (pdirfd == -1) ? "" : gettext("parent of "),
83695331Samw 		    (pdirfd == -1) ? dirp : name, strerror(errno));
83701231Smarks 			return (-1);
83711231Smarks 	}
83721231Smarks 
83730Sstevel@tonic-gate 	newmode = S_IWUSR | parentstat.st_mode;
83745331Samw 	if (fchmod(dirfd, newmode) == -1) {
83750Sstevel@tonic-gate 		(void) fprintf(stderr,
83765331Samw 		    gettext(
83775331Samw 		    "tar: cannot fchmod %sfile %s to %o: %s\n"),
83785331Samw 		    (pdirfd == -1) ? "" : gettext("parent of "),
83795331Samw 		    (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
83801231Smarks 		if (aclp)
83811231Smarks 			acl_free(aclp);
83821231Smarks 		return (-1);
83830Sstevel@tonic-gate 	}
83840Sstevel@tonic-gate 
83855331Samw 
83865331Samw 	if (pdirfd == -1) {
83875331Samw 		/*
83885331Samw 		 * We weren't able to create the attribute directory before.
83895331Samw 		 * Now try again.
83905331Samw 		 */
83915331Samw 		ofilefd = attropen(dirp, ".", oflag);
83925331Samw 	} else {
83935331Samw 		/*
83945331Samw 		 * We weren't able to create open the attribute before.
83955331Samw 		 * Now try again.
83965331Samw 		 */
83975331Samw 		ofilefd = openat(pdirfd, name, oflag, mode);
83985331Samw 	}
83991231Smarks 
84001231Smarks 	/*
84011231Smarks 	 * Put mode back to original
84021231Smarks 	 */
84035331Samw 	if (fchmod(dirfd, parentstat.st_mode) == -1) {
84040Sstevel@tonic-gate 		(void) fprintf(stderr,
84055331Samw 		    gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
84065331Samw 		    (pdirfd == -1) ? "" : gettext("parent of "),
84075331Samw 		    (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
84081231Smarks 	}
84091231Smarks 
84101231Smarks 	if (aclp) {
84115331Samw 		error = facl_set(dirfd, aclp);
84121231Smarks 		if (error) {
84131231Smarks 			(void) fprintf(stderr,
84145331Samw 			    gettext("tar: failed to set acl entries on "
84155331Samw 			    "%sfile %s\n"),
84165331Samw 			    (pdirfd == -1) ? "" : gettext("parent of "),
84175331Samw 			    (pdirfd == -1) ? dirp : name);
84181231Smarks 		}
84191231Smarks 		acl_free(aclp);
84201231Smarks 	}
84211231Smarks 
84221231Smarks 	/*
84231231Smarks 	 * Put back time stamps
84241231Smarks 	 */
84251231Smarks 
84261231Smarks 	times[0].tv_sec = parentstat.st_atime;
84271231Smarks 	times[0].tv_usec = 0;
84281231Smarks 	times[1].tv_sec = parentstat.st_mtime;
84291231Smarks 	times[1].tv_usec = 0;
84305331Samw 
84315331Samw 	(void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
84325331Samw 
84335331Samw 	(void) close(dirfd);
84345331Samw 
84355331Samw 	return (ofilefd);
84365331Samw }
84375331Samw #endif
84380Sstevel@tonic-gate 
84390Sstevel@tonic-gate #if !defined(O_XATTR)
84400Sstevel@tonic-gate static int
openat64(int fd,const char * name,int oflag,mode_t cmode)84410Sstevel@tonic-gate openat64(int fd, const char *name, int oflag, mode_t cmode)
84420Sstevel@tonic-gate {
84430Sstevel@tonic-gate 	return (open64(name, oflag, cmode));
84440Sstevel@tonic-gate }
84450Sstevel@tonic-gate 
84460Sstevel@tonic-gate static int
openat(int fd,const char * name,int oflag,mode_t cmode)84470Sstevel@tonic-gate openat(int fd, const char *name, int oflag, mode_t cmode)
84480Sstevel@tonic-gate {
84490Sstevel@tonic-gate 	return (open(name, oflag, cmode));
84500Sstevel@tonic-gate }
84510Sstevel@tonic-gate 
84520Sstevel@tonic-gate static int
fchownat(int fd,const char * name,uid_t owner,gid_t group,int flag)84530Sstevel@tonic-gate fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
84540Sstevel@tonic-gate {
84550Sstevel@tonic-gate 	if (flag == AT_SYMLINK_NOFOLLOW)
84560Sstevel@tonic-gate 		return (lchown(name, owner, group));
84570Sstevel@tonic-gate 	else
84580Sstevel@tonic-gate 		return (chown(name, owner, group));
84590Sstevel@tonic-gate }
84600Sstevel@tonic-gate 
84610Sstevel@tonic-gate static int
renameat(int fromfd,char * old,int tofd,char * new)84620Sstevel@tonic-gate renameat(int fromfd, char *old, int tofd, char *new)
84630Sstevel@tonic-gate {
84640Sstevel@tonic-gate 	return (rename(old, new));
84650Sstevel@tonic-gate }
84660Sstevel@tonic-gate 
84670Sstevel@tonic-gate static int
futimesat(int fd,char * path,struct timeval times[2])84680Sstevel@tonic-gate futimesat(int fd, char *path, struct timeval times[2])
84690Sstevel@tonic-gate {
84700Sstevel@tonic-gate 	return (utimes(path, times));
84710Sstevel@tonic-gate }
84720Sstevel@tonic-gate 
84730Sstevel@tonic-gate static int
unlinkat(int dirfd,char * path,int flag)84740Sstevel@tonic-gate unlinkat(int dirfd, char *path, int flag)
84750Sstevel@tonic-gate {
84760Sstevel@tonic-gate 	if (flag == AT_REMOVEDIR)
84770Sstevel@tonic-gate 		return (rmdir(path));
84780Sstevel@tonic-gate 	else
84790Sstevel@tonic-gate 		return (unlink(path));
84800Sstevel@tonic-gate }
84810Sstevel@tonic-gate 
84820Sstevel@tonic-gate static int
fstatat(int fd,char * path,struct stat * buf,int flag)84830Sstevel@tonic-gate fstatat(int fd, char *path, struct stat *buf, int flag)
84840Sstevel@tonic-gate {
84850Sstevel@tonic-gate 	if (flag == AT_SYMLINK_NOFOLLOW)
84860Sstevel@tonic-gate 		return (lstat(path, buf));
84870Sstevel@tonic-gate 	else
84880Sstevel@tonic-gate 		return (stat(path, buf));
84890Sstevel@tonic-gate }
84900Sstevel@tonic-gate 
84910Sstevel@tonic-gate static int
attropen(char * file,char * attr,int omode,mode_t cmode)84920Sstevel@tonic-gate attropen(char *file, char *attr, int omode, mode_t cmode)
84930Sstevel@tonic-gate {
84940Sstevel@tonic-gate 	errno = ENOTSUP;
84950Sstevel@tonic-gate 	return (-1);
84960Sstevel@tonic-gate }
84970Sstevel@tonic-gate #endif
84980Sstevel@tonic-gate 
84990Sstevel@tonic-gate static void
chop_endslashes(char * path)85000Sstevel@tonic-gate chop_endslashes(char *path)
85010Sstevel@tonic-gate {
85020Sstevel@tonic-gate 	char *end, *ptr;
85030Sstevel@tonic-gate 
85040Sstevel@tonic-gate 	/*
85050Sstevel@tonic-gate 	 * Chop of slashes, but not if all we have is slashes
85060Sstevel@tonic-gate 	 * for example: ////
85070Sstevel@tonic-gate 	 * should make no changes, otherwise it will screw up
85080Sstevel@tonic-gate 	 * checkdir
85090Sstevel@tonic-gate 	 */
85100Sstevel@tonic-gate 	end = &path[strlen(path) -1];
85110Sstevel@tonic-gate 	if (*end == '/' && end != path) {
85120Sstevel@tonic-gate 		ptr = skipslashes(end, path);
85130Sstevel@tonic-gate 		if (ptr != NULL && ptr != path) {
85140Sstevel@tonic-gate 			*ptr = '\0';
85150Sstevel@tonic-gate 		}
85160Sstevel@tonic-gate 	}
85170Sstevel@tonic-gate }
85181676Sjpk /* Trusted Extensions */
85191676Sjpk 
85201676Sjpk /*
85211676Sjpk  * append_ext_attr():
85221676Sjpk  *
85231676Sjpk  * Append extended attributes and other information into the buffer
85241676Sjpk  * that gets written to the ancillary file.
85251676Sjpk  *
85261676Sjpk  * With option 'T', we create a tarfile which
85271676Sjpk  * has an ancillary file each corresponding archived file.
85281676Sjpk  * Each ancillary file contains 1 or more of the
85291676Sjpk  * following attributes:
85301676Sjpk  *
85311676Sjpk  *	attribute type        attribute		process procedure
85321676Sjpk  *	----------------      ----------------  --------------------------
85331676Sjpk  *   	DIR_TYPE       = 'D'   directory flag	append if a directory
85341676Sjpk  *    	LBL_TYPE       = 'L'   SL[IL] or SL	append ascii label
85351676Sjpk  *
85361676Sjpk  *
85371676Sjpk  */
85381676Sjpk static void
append_ext_attr(char * shortname,char ** secinfo,int * len)85391676Sjpk append_ext_attr(char *shortname, char **secinfo, int *len)
85401676Sjpk {
85411676Sjpk 	bslabel_t	b_slabel;	/* binary sensitvity label */
85421676Sjpk 	char		*ascii = NULL;	/* ascii label */
85431676Sjpk 
85441676Sjpk 	/*
85451676Sjpk 	 * For each attribute type, append it if it is
85461676Sjpk 	 * relevant to the file type.
85471676Sjpk 	 */
85481676Sjpk 
85491676Sjpk 	/*
85501676Sjpk 	 * For attribute type DIR_TYPE,
85511676Sjpk 	 * append it to the following file type:
85521676Sjpk 	 *
85531676Sjpk 	 *	S_IFDIR: directories
85541676Sjpk 	 */
85551676Sjpk 
85561676Sjpk 	/*
85571676Sjpk 	 * For attribute type LBL_TYPE,
85581676Sjpk 	 * append it to the following file type:
85591676Sjpk 	 *
85601676Sjpk 	 *	S_IFDIR: directories (including mld, sld)
85611676Sjpk 	 *	S_IFLNK: symbolic link
85621676Sjpk 	 *	S_IFREG: regular file but not hard link
85631676Sjpk 	 *	S_IFIFO: FIFO file but not hard link
85641676Sjpk 	 *	S_IFCHR: char special file but not hard link
85651676Sjpk 	 *	S_IFBLK: block special file but not hard link
85661676Sjpk 	 */
85671676Sjpk 	switch (stbuf.st_mode & S_IFMT) {
85681676Sjpk 
85691676Sjpk 	case S_IFDIR:
85701676Sjpk 
85711676Sjpk 		/*
85721676Sjpk 		 * append DIR_TYPE
85731676Sjpk 		 */
85741676Sjpk 		(void) append_secattr(secinfo, len, 1,
85754774Sas145665 		    "\0", DIR_TYPE);
85761676Sjpk 
85771676Sjpk 		/*
85781676Sjpk 		 * Get and append attribute types LBL_TYPE.
85791676Sjpk 		 * For directories, LBL_TYPE contains SL.
85801676Sjpk 		 */
85811676Sjpk 		/* get binary sensitivity label */
85821676Sjpk 		if (getlabel(shortname, &b_slabel) != 0) {
85831676Sjpk 			(void) fprintf(stderr,
85841676Sjpk 			    gettext("tar: can't get sensitvity label for "
85851676Sjpk 			    " %s, getlabel() error: %s\n"),
85861676Sjpk 			    shortname, strerror(errno));
85871676Sjpk 		} else {
85881676Sjpk 			/* get ascii SL */
85891676Sjpk 			if (bsltos(&b_slabel, &ascii,
85901676Sjpk 			    0, 0) <= 0) {
85911676Sjpk 				(void) fprintf(stderr,
85921676Sjpk 				    gettext("tar: can't get ascii SL for"
85931676Sjpk 				    " %s\n"), shortname);
85941676Sjpk 			} else {
85951676Sjpk 				/* append LBL_TYPE */
85961676Sjpk 				(void) append_secattr(secinfo, len,
85971676Sjpk 				    strlen(ascii) + 1, ascii,
85981676Sjpk 				    LBL_TYPE);
85991676Sjpk 
86001676Sjpk 				/* free storage */
86011676Sjpk 				if (ascii != NULL) {
86021676Sjpk 					free(ascii);
86031676Sjpk 					ascii = (char *)0;
86041676Sjpk 				}
86051676Sjpk 			}
86061676Sjpk 
86071676Sjpk 		}
86081676Sjpk 		break;
86091676Sjpk 
86101676Sjpk 	case S_IFLNK:
86111676Sjpk 	case S_IFREG:
86121676Sjpk 	case S_IFIFO:
86131676Sjpk 	case S_IFCHR:
86141676Sjpk 	case S_IFBLK:
86151676Sjpk 
86161676Sjpk 		/* get binary sensitivity label */
86171676Sjpk 		if (getlabel(shortname, &b_slabel) != 0) {
86181676Sjpk 			(void) fprintf(stderr,
86191676Sjpk 			    gettext("tar: can't get sensitivty label for %s, "
86201676Sjpk 			    "getlabel() error: %s\n"),
86211676Sjpk 			    shortname, strerror(errno));
86221676Sjpk 		} else {
86231676Sjpk 			/* get ascii IL[SL] */
86241676Sjpk 			if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
86251676Sjpk 				(void) fprintf(stderr,
86261676Sjpk 				    gettext("tar: can't translate sensitivity "
86271676Sjpk 				    " label for %s\n"), shortname);
86281676Sjpk 			} else {
86291676Sjpk 				char *cmw_label;
86301676Sjpk 				size_t  cmw_length;
86311676Sjpk 
86321676Sjpk 				cmw_length = strlen("ADMIN_LOW [] ") +
86331676Sjpk 				    strlen(ascii);
86341676Sjpk 				if ((cmw_label = malloc(cmw_length)) == NULL) {
86351676Sjpk 					(void) fprintf(stderr, gettext(
86361676Sjpk 					    "Insufficient memory for label\n"));
86371676Sjpk 					exit(1);
86381676Sjpk 				}
86391676Sjpk 				/* append LBL_TYPE */
86401676Sjpk 				(void) snprintf(cmw_label, cmw_length,
86411676Sjpk 				    "ADMIN_LOW [%s]", ascii);
86421676Sjpk 				(void) append_secattr(secinfo, len,
86431676Sjpk 				    strlen(cmw_label) + 1, cmw_label,
86441676Sjpk 				    LBL_TYPE);
86451676Sjpk 
86461676Sjpk 				/* free storage */
86471676Sjpk 				if (ascii != NULL) {
86481676Sjpk 					free(cmw_label);
86491676Sjpk 					free(ascii);
86501676Sjpk 					ascii = (char *)0;
86511676Sjpk 				}
86521676Sjpk 			}
86531676Sjpk 		}
86541676Sjpk 		break;
86551676Sjpk 
86561676Sjpk 	default:
86571676Sjpk 		break;
86581676Sjpk 	} /* end switch for LBL_TYPE */
86591676Sjpk 
86601676Sjpk 
86611676Sjpk 	/* DONE !! */
86621676Sjpk 	return;
86631676Sjpk 
86641676Sjpk } /* end of append_ext_attr */
86651676Sjpk 
86661676Sjpk 
86671676Sjpk /*
86681676Sjpk  *	Name: extract_attr()
86691676Sjpk  *
86701676Sjpk  *	Description:
86711676Sjpk  *		Process attributes from the ancillary file due to
86721676Sjpk  *		the T option.
86731676Sjpk  *
86741676Sjpk  *	Call by doxtract() as part of the switch case structure.
86751676Sjpk  *	Making this a separate routine because the nesting are too
86761676Sjpk  *	deep in doxtract, thus, leaving very little space
86771676Sjpk  *	on each line for instructions.
86781676Sjpk  *
86791676Sjpk  * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
86801676Sjpk  *
86811676Sjpk  * For option 'T', following are possible attributes in
86821676Sjpk  * a TS 8 ancillary file: (NOTE: No IL support)
86831676Sjpk  *
86841676Sjpk  *	attribute type        attribute		process procedure
86851676Sjpk  *	----------------      ----------------  -------------------------
86861676Sjpk  *    #	LBL_TYPE       = 'L'   SL               construct binary label
86871676Sjpk  *    #	APRIV_TYPE     = 'P'   allowed priv    	construct privileges
86881676Sjpk  *    #	FPRIV_TYPE     = 'p'   forced priv	construct privileges
86891676Sjpk  *    #	COMP_TYPE      = 'C'   path component	construct real path
86901676Sjpk  *    #	DIR_TYPE       = 'D'   directory flag	note it is a directory
86911676Sjpk  *    $	UFSD_ACL       = '1'   ACL data		construct ACL entries
86921676Sjpk  *	ATTR_FLAG_TYPE = 'F'   file attr flags  construct binary flags
86931676Sjpk  *	LK_COMP_TYPE   = 'K'   linked path comp construct linked real path
86941676Sjpk  *
86951676Sjpk  * note: # = attribute names common between TS 8 & TS 2.5 ancillary
86961676Sjpk  *           files.
86971676Sjpk  *       $ = ACL attribute is processed for the option 'p', it doesn't
86981676Sjpk  *           need option 'T'.
86991676Sjpk  *
87001676Sjpk  * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
87011676Sjpk  *
87021676Sjpk  */
87031676Sjpk static void
extract_attr(char ** file_ptr,struct sec_attr * attr)87041676Sjpk extract_attr(char **file_ptr, struct sec_attr *attr)
87051676Sjpk {
87061676Sjpk 	int	reterr, err;
87071676Sjpk 	char	*dummy_buf;	/* for attribute extract */
87081676Sjpk 
87091676Sjpk 	dummy_buf = attr->attr_info;
87101676Sjpk 
87111676Sjpk 	switch (attr->attr_type) {
87121676Sjpk 
87131676Sjpk 	case DIR_TYPE:
87141676Sjpk 
87151676Sjpk 		dir_flag++;
87161676Sjpk 		break;
87171676Sjpk 
87181676Sjpk 	case LBL_TYPE:
87191676Sjpk 
87201676Sjpk 		/*
87211676Sjpk 		 * LBL_TYPE is used to indicate SL for directory, and
87221676Sjpk 		 * CMW label for other file types.
87231676Sjpk 		 */
87241676Sjpk 
87251676Sjpk 		if (!dir_flag) { /* not directory */
87261676Sjpk 			/* Skip over IL portion */
87271676Sjpk 			char *sl_ptr = strchr(dummy_buf, '[');
87281676Sjpk 
87291676Sjpk 			if (sl_ptr == NULL)
87301676Sjpk 				err = 0;
87311676Sjpk 			else
87321676Sjpk 				err = stobsl(sl_ptr, &bs_label,
87331676Sjpk 				    NEW_LABEL, &reterr);
87341676Sjpk 		} else { /* directory */
87351676Sjpk 			err = stobsl(dummy_buf, &bs_label,
87361676Sjpk 			    NEW_LABEL, &reterr);
87371676Sjpk 		}
87381676Sjpk 		if (err == 0) {
87391676Sjpk 			(void) fprintf(stderr, gettext("tar: "
87401676Sjpk 			    "can't convert %s to binary label\n"),
87411676Sjpk 			    dummy_buf);
87421676Sjpk 			bslundef(&bs_label);
87431676Sjpk 		} else if (!blequal(&bs_label, &admin_low) &&
87441676Sjpk 		    !blequal(&bs_label, &admin_high)) {
87451676Sjpk 			bslabel_t *from_label;
87461676Sjpk 			char *buf;
87471676Sjpk 			char tempbuf[MAXPATHLEN];
87481676Sjpk 
87491676Sjpk 			if (*orig_namep != '/') {
87501676Sjpk 				/* got relative linked to path */
87511676Sjpk 				(void) getcwd(tempbuf, (sizeof (tempbuf)));
87521676Sjpk 				(void) strncat(tempbuf, "/", MAXPATHLEN);
87531676Sjpk 			} else
87541676Sjpk 				*tempbuf = '\0';
87551676Sjpk 
87561676Sjpk 			buf = real_path;
87571676Sjpk 			(void) strncat(tempbuf, orig_namep, MAXPATHLEN);
87581676Sjpk 			from_label = getlabelbypath(tempbuf);
87591676Sjpk 			if (from_label != NULL) {
87601676Sjpk 				if (blequal(from_label, &admin_low)) {
87611676Sjpk 					if ((getpathbylabel(tempbuf, buf,
87621676Sjpk 					    MAXPATHLEN, &bs_label) == NULL)) {
87631676Sjpk 						(void) fprintf(stderr,
87641676Sjpk 						    gettext("tar: "
87651676Sjpk 						"can't get zone root path for "
87661676Sjpk 						"%s\n"), tempbuf);
87671676Sjpk 					} else
87681676Sjpk 						rpath_flag = 1;
87691676Sjpk 				}
87701676Sjpk 				free(from_label);
87711676Sjpk 			}
87721676Sjpk 		}
87731676Sjpk 		break;
87741676Sjpk 
87751676Sjpk 	case COMP_TYPE:
87761676Sjpk 
87771676Sjpk 		rebuild_comp_path(dummy_buf, file_ptr);
87781676Sjpk 		break;
87791676Sjpk 
87801676Sjpk 	case LK_COMP_TYPE:
87811676Sjpk 
87821676Sjpk 		if (rebuild_lk_comp_path(dummy_buf, file_ptr)
87831676Sjpk 		    == 0) {
87841676Sjpk 			lk_rpath_flag = 1;
87851676Sjpk 		} else {
87861676Sjpk 			(void) fprintf(stderr, gettext("tar: warning: link's "
87871676Sjpk 			    "target pathname might be invalid.\n"));
87881676Sjpk 			lk_rpath_flag = 0;
87891676Sjpk 		}
87901676Sjpk 		break;
87911676Sjpk 	case APRIV_TYPE:
87921676Sjpk 		ignored_aprivs++;
87931676Sjpk 		break;
87941676Sjpk 	case FPRIV_TYPE:
87951676Sjpk 		ignored_fprivs++;
87961676Sjpk 		break;
87971676Sjpk 	case ATTR_FLAG_TYPE:
87981676Sjpk 		ignored_fattrs++;
87991676Sjpk 		break;
88001676Sjpk 
88011676Sjpk 	default:
88021676Sjpk 
88031676Sjpk 		break;
88041676Sjpk 	}
88051676Sjpk 
88061676Sjpk 	/* done */
88071676Sjpk 	return;
88081676Sjpk 
88091676Sjpk }	/* end extract_attr */
88101676Sjpk 
88111676Sjpk 
88121676Sjpk 
88131676Sjpk /*
88141676Sjpk  *	Name:	rebuild_comp_path()
88151676Sjpk  *
88161676Sjpk  *	Description:
88171676Sjpk  *		Take the string of components passed down by the calling
88181676Sjpk  *		routine and parse the values and rebuild the path.
88191676Sjpk  *		This routine no longer needs to produce a new real_path
88201676Sjpk  *		string because it is produced when the 'L' LABEL_TYPE is
88211676Sjpk  *		interpreted. So the only thing done here is to distinguish
88221676Sjpk  *		between an SLD and an MLD entry. We only want one, so we
88231676Sjpk  *		ignore the MLD entry by setting the mld_flag.
88241676Sjpk  *
88251676Sjpk  *	return value:
88261676Sjpk  *		none
88271676Sjpk  */
88281676Sjpk static void
rebuild_comp_path(char * str,char ** namep)88291676Sjpk rebuild_comp_path(char *str, char **namep)
88301676Sjpk {
88311676Sjpk 	char		*cp;
88321676Sjpk 
88331676Sjpk 	while (*str != '\0') {
88341676Sjpk 
88351676Sjpk 		switch (*str) {
88361676Sjpk 
88371676Sjpk 		case MLD_TYPE:
88381676Sjpk 
88391676Sjpk 			str++;
88401676Sjpk 			if ((cp = strstr(str, ";;")) != NULL) {
88411676Sjpk 				*cp = '\0';
88421676Sjpk 				str = cp + 2;
88431676Sjpk 				*cp = ';';
88441676Sjpk 			}
88451676Sjpk 			mld_flag = 1;
88461676Sjpk 			break;
88471676Sjpk 
88481676Sjpk 		case SLD_TYPE:
88491676Sjpk 
88501676Sjpk 			str++;
88511676Sjpk 			if ((cp = strstr(str, ";;")) != NULL) {
88521676Sjpk 				*cp = '\0';
88531676Sjpk 				str = cp + 2;
88541676Sjpk 				*cp = ';';
88551676Sjpk 			}
88561676Sjpk 			mld_flag = 0;
88571676Sjpk 			break;
88581676Sjpk 
88591676Sjpk 		case PATH_TYPE:
88601676Sjpk 
88611676Sjpk 			str++;
88621676Sjpk 			if ((cp = strstr(str, ";;")) != NULL) {
88631676Sjpk 				*cp = '\0';
88641676Sjpk 				str = cp + 2;
88651676Sjpk 				*cp = ';';
88661676Sjpk 			}
88671676Sjpk 			break;
88681676Sjpk 		}
88691676Sjpk 	}
88701676Sjpk 	if (rpath_flag)
88711676Sjpk 		*namep = real_path;
88721676Sjpk 	return;
88731676Sjpk 
88741676Sjpk } /* end rebuild_comp_path() */
88751676Sjpk 
88761676Sjpk /*
88771676Sjpk  *	Name:	rebuild_lk_comp_path()
88781676Sjpk  *
88791676Sjpk  *	Description:
88801676Sjpk  *		Take the string of components passed down by the calling
88811676Sjpk  *		routine and parse the values and rebuild the path.
88821676Sjpk  *
88831676Sjpk  *	return value:
88841676Sjpk  *		0 = succeeded
88851676Sjpk  *		-1 = failed
88861676Sjpk  */
88871676Sjpk static int
rebuild_lk_comp_path(char * str,char ** namep)88881676Sjpk rebuild_lk_comp_path(char *str, char **namep)
88891676Sjpk {
88901676Sjpk 	char		*cp;
88911676Sjpk 	int		reterr;
88921676Sjpk 	bslabel_t	bslabel;
88931676Sjpk 	char		*buf;
88941676Sjpk 	char		pbuf[MAXPATHLEN];
88951676Sjpk 	char		*ptr1, *ptr2;
88961676Sjpk 	int		plen;
88971676Sjpk 	int		use_pbuf;
88981676Sjpk 	char		tempbuf[MAXPATHLEN];
88991676Sjpk 	int		mismatch;
89001676Sjpk 	bslabel_t	*from_label;
89011676Sjpk 	char		zonename[ZONENAME_MAX];
89021676Sjpk 	zoneid_t	zoneid;
89031676Sjpk 
89041676Sjpk 	/* init stuff */
89051676Sjpk 	use_pbuf = 0;
89061676Sjpk 	mismatch = 0;
89071676Sjpk 
89081676Sjpk 	/*
89091676Sjpk 	 * For linked to pathname (LK_COMP_TYPE):
89101676Sjpk 	 *  - If the linked to pathname is absolute (start with /), we
89111676Sjpk 	 *    will use it as is.
89121676Sjpk 	 *  - If it is a relative pathname then it is relative to 1 of 2
89131676Sjpk 	 *    directories.  For a hardlink, it is relative to the current
89141676Sjpk 	 *    directory.  For a symbolic link, it is relative to the
89151676Sjpk 	 *    directory the symbolic link is in.  For the symbolic link
89161676Sjpk 	 *    case, set a flag to indicate we need to use the prefix of
89171676Sjpk 	 *    the restored file's pathname with the linked to pathname.
89181676Sjpk 	 *
89191676Sjpk 	 *    NOTE: At this point, we have no way to determine if we have
89201676Sjpk 	 *    a hardlink or a symbolic link.  We will compare the 1st
89211676Sjpk 	 *    component in the prefix portion of the restore file's
89221676Sjpk 	 *    pathname to the 1st component in the attribute data
89231676Sjpk 	 *    (the linked pathname).  If they are the same, we will assume
89241676Sjpk 	 *    the link pathname to reconstruct is relative to the current
89251676Sjpk 	 *    directory.  Otherwise, we will set a flag indicate we need
89261676Sjpk 	 *    to use a prefix with the reconstructed name.  Need to compare
89271676Sjpk 	 *    both the adorned and unadorned version before deciding a
89281676Sjpk 	 *    mismatch.
89291676Sjpk 	 */
89301676Sjpk 
89311676Sjpk 	buf = lk_real_path;
89321676Sjpk 	if (*(str + 1) != '/') { /* got relative linked to path */
89331676Sjpk 		ptr1 = orig_namep;
89341676Sjpk 		ptr2 = strrchr(ptr1, '/');
89351676Sjpk 		plen = ptr2 - ptr1;
89361676Sjpk 		if (plen > 0) {
89371676Sjpk 			pbuf[0] = '\0';
89381676Sjpk 			plen++;		/* include '/' */
89391676Sjpk 			(void) strncpy(pbuf, ptr1, plen);
89401676Sjpk 			*(pbuf + plen) = '\0';
89411676Sjpk 			ptr2 = strchr(pbuf, '/');
89421676Sjpk 			if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
89431676Sjpk 				mismatch = 1;
89441676Sjpk 		}
89451676Sjpk 
89461676Sjpk 		if (mismatch == 1)
89471676Sjpk 			use_pbuf = 1;
89481676Sjpk 	}
89491676Sjpk 
89501676Sjpk 	buf[0] = '\0';
89511676Sjpk 
89521676Sjpk 	while (*str != '\0') {
89531676Sjpk 
89541676Sjpk 		switch (*str) {
89551676Sjpk 
89561676Sjpk 		case MLD_TYPE:
89571676Sjpk 
89581676Sjpk 			str++;
89591676Sjpk 			if ((cp = strstr(str, ";;")) != NULL) {
89601676Sjpk 				*cp = '\0';
89611676Sjpk 
89621676Sjpk 				/*
89631676Sjpk 				 * Ignore attempts to backup over .MLD.
89641676Sjpk 				 */
89651676Sjpk 				if (strcmp(str, "../") != 0)
89661676Sjpk 					(void) strncat(buf, str, MAXPATHLEN);
89671676Sjpk 				str = cp + 2;
89681676Sjpk 				*cp = ';';
89691676Sjpk 			}
89701676Sjpk 			break;
89711676Sjpk 
89721676Sjpk 		case SLD_TYPE:
89731676Sjpk 
89741676Sjpk 			str++;
89751676Sjpk 			if ((cp = strstr(str, ";;")) != NULL) {
89761676Sjpk 				*cp = '\0';
89771676Sjpk 
89781676Sjpk 				/*
89791676Sjpk 				 * Use the path name in the header if
89801676Sjpk 				 * error occurs when processing the
89811676Sjpk 				 * SLD type.
89821676Sjpk 				 */
89831676Sjpk 
89841676Sjpk 				if (!stobsl(str, &bslabel,
89851676Sjpk 				    NO_CORRECTION, &reterr)) {
89861676Sjpk 					(void) fprintf(stderr, gettext(
89871676Sjpk 					    "tar: can't translate to binary"
89881676Sjpk 					    "SL for SLD, stobsl() error:"
89891676Sjpk 					    " %s\n"), strerror(errno));
89901676Sjpk 					return (-1);
89911676Sjpk 				}
89921676Sjpk 
89931676Sjpk 				str = cp + 2;
89941676Sjpk 				*cp = ';';
89951676Sjpk 
89961676Sjpk 				if (use_pbuf == 1) {
89971676Sjpk 					if (*pbuf != '/') {
89981676Sjpk 						/* relative linked to path */
89991676Sjpk 
90001676Sjpk 						(void) getcwd(tempbuf,
90011676Sjpk 						    (sizeof (tempbuf)));
90021676Sjpk 						(void) strncat(tempbuf, "/",
90031676Sjpk 						    MAXPATHLEN);
90041676Sjpk 						(void) strncat(tempbuf, pbuf,
90051676Sjpk 						    MAXPATHLEN);
90061676Sjpk 					}
90071676Sjpk 					else
90081676Sjpk 						(void) strcpy(tempbuf, pbuf);
90091676Sjpk 
90101676Sjpk 				} else if (*buf != '/') {
90111676Sjpk 					/* got relative linked to path */
90121676Sjpk 
90131676Sjpk 					(void) getcwd(tempbuf,
90141676Sjpk 					    (sizeof (tempbuf)));
90151676Sjpk 					(void) strncat(tempbuf, "/",
90161676Sjpk 					    MAXPATHLEN);
90171676Sjpk 				} else
90181676Sjpk 					*tempbuf = '\0';
90191676Sjpk 
90201676Sjpk 				(void) strncat(tempbuf, buf, MAXPATHLEN);
90211676Sjpk 				*buf = '\0';
90221676Sjpk 
90231676Sjpk 				if (blequal(&bslabel, &admin_high)) {
90241676Sjpk 					bslabel = admin_low;
90251676Sjpk 				}
90261676Sjpk 
90271676Sjpk 
90281676Sjpk 				/*
90291676Sjpk 				 * Check for cross-zone symbolic links
90301676Sjpk 				 */
90311676Sjpk 				from_label = getlabelbypath(real_path);
90321676Sjpk 				if (rpath_flag && (from_label != NULL) &&
90331676Sjpk 				    !blequal(&bslabel, from_label)) {
90341676Sjpk 					if ((zoneid =
90351676Sjpk 					    getzoneidbylabel(&bslabel)) == -1) {
90361676Sjpk 						(void) fprintf(stderr,
90371676Sjpk 						    gettext("tar: can't get "
90384774Sas145665 						    "zone ID for %s\n"),
90391676Sjpk 						    tempbuf);
90401676Sjpk 						return (-1);
90411676Sjpk 					}
90421676Sjpk 					if (zone_getattr(zoneid, ZONE_ATTR_NAME,
90431676Sjpk 					    &zonename, ZONENAME_MAX) == -1) {
90441676Sjpk 						/* Badly configured zone info */
90451676Sjpk 						(void) fprintf(stderr,
90461676Sjpk 						    gettext("tar: can't get "
90474774Sas145665 						    "zonename for %s\n"),
90481676Sjpk 						    tempbuf);
90491676Sjpk 						return (-1);
90501676Sjpk 					}
90511676Sjpk 					(void) strncpy(buf, AUTO_ZONE,
90521676Sjpk 					    MAXPATHLEN);
90531676Sjpk 					(void) strncat(buf, "/",
90541676Sjpk 					    MAXPATHLEN);
90551676Sjpk 					(void) strncat(buf, zonename,
90561676Sjpk 					    MAXPATHLEN);
90571676Sjpk 				}
90581676Sjpk 				if (from_label != NULL)
90591676Sjpk 					free(from_label);
90601676Sjpk 				(void) strncat(buf, tempbuf, MAXPATHLEN);
90611676Sjpk 				break;
90621676Sjpk 			}
90631676Sjpk 			mld_flag = 0;
90641676Sjpk 			break;
90651676Sjpk 
90661676Sjpk 		case PATH_TYPE:
90671676Sjpk 
90681676Sjpk 			str++;
90691676Sjpk 			if ((cp = strstr(str, ";;")) != NULL) {
90701676Sjpk 				*cp = '\0';
90711676Sjpk 				(void) strncat(buf, str, MAXPATHLEN);
90721676Sjpk 				str = cp + 2;
90731676Sjpk 				*cp = ';';
90741676Sjpk 			}
90751676Sjpk 			break;
90761676Sjpk 
90771676Sjpk 		default:
90781676Sjpk 
90791676Sjpk 			(void) fprintf(stderr, gettext(
90804774Sas145665 			    "tar: error rebuilding path %s\n"),
90814774Sas145665 			    *namep);
90821676Sjpk 			*buf = '\0';
90831676Sjpk 			str++;
90841676Sjpk 			return (-1);
90851676Sjpk 		}
90861676Sjpk 	}
90871676Sjpk 
90881676Sjpk 	/*
90891676Sjpk 	 * Done for LK_COMP_TYPE
90901676Sjpk 	 */
90911676Sjpk 
90921676Sjpk 	return (0);    /* component path is rebuilt successfully */
90931676Sjpk 
90941676Sjpk } /* end rebuild_lk_comp_path() */
90951676Sjpk 
90961676Sjpk /*
90971676Sjpk  *	Name: check_ext_attr()
90981676Sjpk  *
90991676Sjpk  *	Description:
91001676Sjpk  *		Check the extended attributes for a file being extracted.
91011676Sjpk  *		The attributes being checked here are CMW labels.
91021676Sjpk  *		ACLs are not set here because they are set by the
91031676Sjpk  *		pflag in doxtract().
91041676Sjpk  *
91051676Sjpk  *		If the label doesn't match, return 0
91061676Sjpk  *		else return 1
91071676Sjpk  */
91081676Sjpk static int
check_ext_attr(char * filename)91091676Sjpk check_ext_attr(char *filename)
91101676Sjpk {
91111676Sjpk 	bslabel_t	currentlabel;	/* label from zone */
91121676Sjpk 
91131676Sjpk 	if (bltype(&bs_label, SUN_SL_UN)) {
91141676Sjpk 		/* No label check possible */
91151676Sjpk 		return (0);
91161676Sjpk 	}
91171676Sjpk 	if (getlabel(filename, &currentlabel) != 0) {
91181676Sjpk 		(void) fprintf(stderr,
91191676Sjpk 		    gettext("tar: can't get label for "
91204774Sas145665 		    " %s, getlabel() error: %s\n"),
91214774Sas145665 		    filename, strerror(errno));
91221676Sjpk 		return (0);
91231676Sjpk 	} else if ((blequal(&currentlabel, &bs_label)) == 0) {
91241676Sjpk 		char	*src_label = NULL;	/* ascii label */
91251676Sjpk 
91261676Sjpk 		/* get current src SL */
91271676Sjpk 		if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
91281676Sjpk 			(void) fprintf(stderr,
91291676Sjpk 			    gettext("tar: can't interpret requested label for"
91304774Sas145665 			    " %s\n"), filename);
91311676Sjpk 		} else {
91321676Sjpk 			(void) fprintf(stderr,
91331676Sjpk 			    gettext("tar: can't apply label %s to %s\n"),
91344774Sas145665 			    src_label, filename);
91351676Sjpk 			free(src_label);
91361676Sjpk 		}
91371676Sjpk 		(void) fprintf(stderr,
91381676Sjpk 		    gettext("tar: %s not restored\n"), filename);
91391676Sjpk 		return (0);
91401676Sjpk 	}
91411676Sjpk 	return (1);
91421676Sjpk 
91431676Sjpk }	/* end check_ext_attr */
914411990Srich.burridge@sun.com 
914511990Srich.burridge@sun.com /* Compressing a tar file using compression method provided in 'opt' */
914611990Srich.burridge@sun.com 
914711990Srich.burridge@sun.com static void
compress_back()914811990Srich.burridge@sun.com compress_back()
914911990Srich.burridge@sun.com {
915011990Srich.burridge@sun.com 	pid_t	pid;
915111990Srich.burridge@sun.com 	int status;
915211990Srich.burridge@sun.com 	int wret;
915311990Srich.burridge@sun.com 	struct	stat statb;
915411990Srich.burridge@sun.com 
915511990Srich.burridge@sun.com 	if (vflag) {
915611990Srich.burridge@sun.com 		(void) fprintf(vfile,
915711990Srich.burridge@sun.com 		    gettext("Compressing '%s' with '%s'...\n"),
915811990Srich.burridge@sun.com 		    usefile, compress_opt);
915911990Srich.burridge@sun.com 	}
916011990Srich.burridge@sun.com 	if ((pid = fork()) == 0) {
916111990Srich.burridge@sun.com 		(void) execlp(compress_opt, compress_opt,
916211990Srich.burridge@sun.com 		    usefile, NULL);
916311990Srich.burridge@sun.com 	} else if (pid == -1) {
916411990Srich.burridge@sun.com 		vperror(1, "%s", gettext("Could not fork"));
916511990Srich.burridge@sun.com 	}
916611990Srich.burridge@sun.com 	wait_pid(pid);
916711990Srich.burridge@sun.com 	if (suffix == 0) {
916811990Srich.burridge@sun.com 		(void) rename(tfname, usefile);
916911990Srich.burridge@sun.com 	}
917011990Srich.burridge@sun.com }
917111990Srich.burridge@sun.com 
917211990Srich.burridge@sun.com /* The magic numbers from /etc/magic */
917311990Srich.burridge@sun.com 
917411990Srich.burridge@sun.com #define	GZIP_MAGIC	"\037\213"
917511990Srich.burridge@sun.com #define	BZIP_MAGIC	"BZh"
917611990Srich.burridge@sun.com #define	COMP_MAGIC	"\037\235"
917711990Srich.burridge@sun.com 
917811990Srich.burridge@sun.com void
check_compression()917911990Srich.burridge@sun.com check_compression()
918011990Srich.burridge@sun.com {
918111990Srich.burridge@sun.com 	char 	magic[2];
918211990Srich.burridge@sun.com 	char	buf[16];
918311990Srich.burridge@sun.com 	FILE	*fp;
918411990Srich.burridge@sun.com 
918511990Srich.burridge@sun.com 	if ((fp = fopen(usefile, "r")) != NULL) {
918611990Srich.burridge@sun.com 		(void) fread(buf, sizeof (char), 6, fp);
918711990Srich.burridge@sun.com 		magic[0] = buf[0];
918811990Srich.burridge@sun.com 		magic[1] = buf[1];
918911990Srich.burridge@sun.com 		(void) fclose(fp);
919011990Srich.burridge@sun.com 	}
919111990Srich.burridge@sun.com 
919211990Srich.burridge@sun.com 	if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
919311990Srich.burridge@sun.com 		if (xflag || tflag) {
919411990Srich.burridge@sun.com 			compress_opt = compress_malloc(strlen(GZCAT) + 1);
919511990Srich.burridge@sun.com 			(void) strcpy(compress_opt, GZCAT);
919611990Srich.burridge@sun.com 		} else if (uflag || rflag) {
919711990Srich.burridge@sun.com 			compress_opt = compress_malloc(strlen(GZIP) + 1);
919811990Srich.burridge@sun.com 			(void) strcpy(compress_opt, GZIP);
919911990Srich.burridge@sun.com 		}
920011990Srich.burridge@sun.com 	} else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
920111990Srich.burridge@sun.com 		if (xflag || tflag) {
920211990Srich.burridge@sun.com 			compress_opt = compress_malloc(strlen(BZCAT) + 1);
920311990Srich.burridge@sun.com 			(void) strcpy(compress_opt, BZCAT);
920411990Srich.burridge@sun.com 		} else if (uflag || rflag) {
920511990Srich.burridge@sun.com 			compress_opt = compress_malloc(strlen(BZIP) + 1);
920611990Srich.burridge@sun.com 			(void) strcpy(compress_opt, BZIP);
920711990Srich.burridge@sun.com 		}
920811990Srich.burridge@sun.com 	} else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
920911990Srich.burridge@sun.com 		if (xflag || tflag) {
921011990Srich.burridge@sun.com 			compress_opt = compress_malloc(strlen(ZCAT) + 1);
921111990Srich.burridge@sun.com 			(void) strcpy(compress_opt, ZCAT);
921211990Srich.burridge@sun.com 		} else if (uflag || rflag) {
921311990Srich.burridge@sun.com 			compress_opt = compress_malloc(strlen(COMPRESS) + 1);
921411990Srich.burridge@sun.com 			(void) strcpy(compress_opt, COMPRESS);
921511990Srich.burridge@sun.com 		}
921611990Srich.burridge@sun.com 	}
921711990Srich.burridge@sun.com }
921811990Srich.burridge@sun.com 
921911990Srich.burridge@sun.com char *
add_suffix()922011990Srich.burridge@sun.com add_suffix()
922111990Srich.burridge@sun.com {
922211990Srich.burridge@sun.com 	(void) strcpy(tfname, usefile);
922311990Srich.burridge@sun.com 	if (strcmp(compress_opt, GZIP) == 0) {
922411990Srich.burridge@sun.com 		if ((suffix = gz_suffix()) == NULL) {
922511990Srich.burridge@sun.com 			strlcat(tfname, gsuffix[0], sizeof (tfname));
922611990Srich.burridge@sun.com 			return (gsuffix[0]);
922711990Srich.burridge@sun.com 		}
922811990Srich.burridge@sun.com 	} else if (strcmp(compress_opt, COMPRESS) == 0) {
922911990Srich.burridge@sun.com 		if ((suffix = gz_suffix()) == NULL) {
923011990Srich.burridge@sun.com 			strlcat(tfname, gsuffix[6], sizeof (tfname));
923111990Srich.burridge@sun.com 			return (gsuffix[6]);
923211990Srich.burridge@sun.com 		}
923311990Srich.burridge@sun.com 	} else if (strcmp(compress_opt, BZIP) == 0) {
923411990Srich.burridge@sun.com 		if ((suffix = bz_suffix()) == NULL) {
923511990Srich.burridge@sun.com 			strlcat(tfname, bsuffix[0], sizeof (tfname));
923611990Srich.burridge@sun.com 			return (bsuffix[0]);
923711990Srich.burridge@sun.com 		}
923811990Srich.burridge@sun.com 	}
923911990Srich.burridge@sun.com 	return (NULL);
924011990Srich.burridge@sun.com }
924111990Srich.burridge@sun.com 
924211990Srich.burridge@sun.com /* Decompressing a tar file using compression method from the file type */
924311990Srich.burridge@sun.com void
decompress_file(void)924411990Srich.burridge@sun.com decompress_file(void)
924511990Srich.burridge@sun.com {
924611990Srich.burridge@sun.com 	pid_t 	pid;
924711990Srich.burridge@sun.com 	int	status;
924811990Srich.burridge@sun.com 	char	cmdstr[PATH_MAX];
924911990Srich.burridge@sun.com 	char	fname[PATH_MAX];
925011990Srich.burridge@sun.com 	char	*added_suffix;
925111990Srich.burridge@sun.com 
925211990Srich.burridge@sun.com 
925311990Srich.burridge@sun.com 	added_suffix = add_suffix();
925411990Srich.burridge@sun.com 	if (added_suffix != NULL)  {
925511990Srich.burridge@sun.com 		(void) rename(usefile, tfname);
925611990Srich.burridge@sun.com 	}
925711990Srich.burridge@sun.com 	if ((pid = fork()) == 0) {
925811990Srich.burridge@sun.com 		if (vflag) {
925911990Srich.burridge@sun.com 			(void) fprintf(vfile,
926011990Srich.burridge@sun.com 			    gettext("Decompressing '%s' with "
926111990Srich.burridge@sun.com 			    "'%s'...\n"), usefile, compress_opt);
926211990Srich.burridge@sun.com 		}
926311990Srich.burridge@sun.com 		(void) execlp(compress_opt, compress_opt, "-df",
926411990Srich.burridge@sun.com 		    tfname, NULL);
926512350Srich.burridge@sun.com 		vperror(1, gettext("Could not exec %s"), compress_opt);
926611990Srich.burridge@sun.com 	} else if (pid == -1) {
926712305Srich.burridge@sun.com 		vperror(1, gettext("Could not fork"));
926811990Srich.burridge@sun.com 	}
926911990Srich.burridge@sun.com 	wait_pid(pid);
927011990Srich.burridge@sun.com 	if (suffix != NULL) {
927111990Srich.burridge@sun.com 		/* restore the file name - original file was without suffix */
927211990Srich.burridge@sun.com 		*(usefile + strlen(usefile) - strlen(suffix)) = '\0';
927311990Srich.burridge@sun.com 	}
927411990Srich.burridge@sun.com }
927511990Srich.burridge@sun.com 
927611990Srich.burridge@sun.com /* Set the archive for writing and then compress the archive */
927711990Srich.burridge@sun.com pid_t
compress_file(void)927811990Srich.burridge@sun.com compress_file(void)
927911990Srich.burridge@sun.com {
928011990Srich.burridge@sun.com 	int fd[2];
928111990Srich.burridge@sun.com 	pid_t pid;
928211990Srich.burridge@sun.com 
928311990Srich.burridge@sun.com 	if (vflag) {
928411990Srich.burridge@sun.com 		(void) fprintf(vfile, gettext("Compressing '%s' with "
928511990Srich.burridge@sun.com 		    "'%s'...\n"), usefile, compress_opt);
928611990Srich.burridge@sun.com 	}
928711990Srich.burridge@sun.com 
928811990Srich.burridge@sun.com 	if (pipe(fd) < 0) {
928911990Srich.burridge@sun.com 		vperror(1, gettext("Could not create pipe"));
929011990Srich.burridge@sun.com 	}
929111990Srich.burridge@sun.com 	if (pid = fork() > 0) {
929211990Srich.burridge@sun.com 		mt = fd[1];
929311990Srich.burridge@sun.com 		(void) close(fd[0]);
929411990Srich.burridge@sun.com 		return (pid);
929511990Srich.burridge@sun.com 	}
929611990Srich.burridge@sun.com 	/* child */
929711990Srich.burridge@sun.com 	(void) dup2(fd[0], STDIN_FILENO);
929811990Srich.burridge@sun.com 	(void) close(fd[1]);
929911990Srich.burridge@sun.com 	(void) dup2(mt, STDOUT_FILENO);
930011990Srich.burridge@sun.com 	(void) execlp(compress_opt, compress_opt, NULL);
930112350Srich.burridge@sun.com 	vperror(1, gettext("Could not exec %s"), compress_opt);
930211990Srich.burridge@sun.com 	return (0);	/*NOTREACHED*/
930311990Srich.burridge@sun.com }
930411990Srich.burridge@sun.com 
930511990Srich.burridge@sun.com pid_t
uncompress_file(void)930611990Srich.burridge@sun.com uncompress_file(void)
930711990Srich.burridge@sun.com {
930811990Srich.burridge@sun.com 	int fd[2];
930911990Srich.burridge@sun.com 	pid_t pid;
931011990Srich.burridge@sun.com 
931111990Srich.burridge@sun.com 	if (vflag) {
931211990Srich.burridge@sun.com 		(void) fprintf(vfile, gettext("Decompressing '%s' with "
931311990Srich.burridge@sun.com 		    "'%s'...\n"), usefile, compress_opt);
931411990Srich.burridge@sun.com 	}
931511990Srich.burridge@sun.com 
931611990Srich.burridge@sun.com 	if (pipe(fd) < 0) {
931711990Srich.burridge@sun.com 		vperror(1, gettext("Could not create pipe"));
931811990Srich.burridge@sun.com 	}
931911990Srich.burridge@sun.com 	if (pid = fork() > 0) {
932011990Srich.burridge@sun.com 		mt = fd[0];
932111990Srich.burridge@sun.com 		(void) close(fd[1]);
932211990Srich.burridge@sun.com 		return (pid);
932311990Srich.burridge@sun.com 	}
932411990Srich.burridge@sun.com 	/* child */
932511990Srich.burridge@sun.com 	(void) dup2(fd[1], STDOUT_FILENO);
932611990Srich.burridge@sun.com 	(void) close(fd[0]);
932711990Srich.burridge@sun.com 	(void) dup2(mt, STDIN_FILENO);
932811990Srich.burridge@sun.com 	(void) execlp(compress_opt, compress_opt, NULL);
932912350Srich.burridge@sun.com 	vperror(1, gettext("Could not exec %s"), compress_opt);
933011990Srich.burridge@sun.com 	return (0);	/*NOTREACHED*/
933111990Srich.burridge@sun.com }
933211990Srich.burridge@sun.com 
933311990Srich.burridge@sun.com /* Checking valid 'bzip2' suffix */
933411990Srich.burridge@sun.com char *
bz_suffix()933511990Srich.burridge@sun.com bz_suffix()
933611990Srich.burridge@sun.com {
933711990Srich.burridge@sun.com 	int 	i;
933811990Srich.burridge@sun.com 	int	slen;
933911990Srich.burridge@sun.com 	int	nlen = strlen(usefile);
934011990Srich.burridge@sun.com 
934111990Srich.burridge@sun.com 	for (i = 0; i < BS; i++) {
934211990Srich.burridge@sun.com 		slen = strlen(bsuffix[i]);
934311990Srich.burridge@sun.com 		if (nlen < slen)
934411990Srich.burridge@sun.com 			return (NULL);
934511990Srich.burridge@sun.com 		if (strcmp(usefile + nlen - slen, bsuffix[i]) == 0)
934611990Srich.burridge@sun.com 			return (bsuffix[i]);
934711990Srich.burridge@sun.com 	}
934811990Srich.burridge@sun.com 	return (NULL);
934911990Srich.burridge@sun.com }
935011990Srich.burridge@sun.com 
935111990Srich.burridge@sun.com /* Checking valid 'gzip' suffix */
935211990Srich.burridge@sun.com char *
gz_suffix()935311990Srich.burridge@sun.com gz_suffix()
935411990Srich.burridge@sun.com {
935511990Srich.burridge@sun.com 	int 	i;
935611990Srich.burridge@sun.com 	int	slen;
935711990Srich.burridge@sun.com 	int	nlen = strlen(usefile);
935811990Srich.burridge@sun.com 
935911990Srich.burridge@sun.com 	for (i = 0; i < GS; i++) {
936011990Srich.burridge@sun.com 		slen = strlen(gsuffix[i]);
936111990Srich.burridge@sun.com 		if (nlen < slen)
936211990Srich.burridge@sun.com 			return (NULL);
936311990Srich.burridge@sun.com 		if (strcmp(usefile + nlen - slen, gsuffix[i]) == 0)
936411990Srich.burridge@sun.com 			return (gsuffix[i]);
936511990Srich.burridge@sun.com 	}
936611990Srich.burridge@sun.com 	return (NULL);
936711990Srich.burridge@sun.com }
936811990Srich.burridge@sun.com 
936911990Srich.burridge@sun.com void *
compress_malloc(size_t size)937011990Srich.burridge@sun.com compress_malloc(size_t size)
937111990Srich.burridge@sun.com {
937211990Srich.burridge@sun.com 	void *opt;
937311990Srich.burridge@sun.com 
937411990Srich.burridge@sun.com 	if ((opt = malloc(size)) == NULL) {
937511990Srich.burridge@sun.com 		vperror(1, "%s",
937611990Srich.burridge@sun.com 		    gettext("Could not allocate compress buffer\n"));
937711990Srich.burridge@sun.com 	}
937811990Srich.burridge@sun.com 	return (opt);
937911990Srich.burridge@sun.com }
938011990Srich.burridge@sun.com 
938111990Srich.burridge@sun.com void
wait_pid(pid_t pid)938211990Srich.burridge@sun.com wait_pid(pid_t pid)
938311990Srich.burridge@sun.com {
938411990Srich.burridge@sun.com 	int status;
938511990Srich.burridge@sun.com 
938611990Srich.burridge@sun.com 	while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
938711990Srich.burridge@sun.com 		;
938811990Srich.burridge@sun.com }
9389