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