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