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