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