10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51676Sjpk * Common Development and Distribution License (the "License").
61676Sjpk * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
2212109SRalph.Turner@Sun.COM * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
260Sstevel@tonic-gate /* All Rights Reserved */
270Sstevel@tonic-gate
280Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */
290Sstevel@tonic-gate /* All Rights Reserved */
300Sstevel@tonic-gate
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
330Sstevel@tonic-gate * under license from the Regents of the University of California.
340Sstevel@tonic-gate */
350Sstevel@tonic-gate
360Sstevel@tonic-gate #include <unistd.h>
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <sys/param.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <sys/mkdev.h>
410Sstevel@tonic-gate #include <sys/wait.h>
420Sstevel@tonic-gate #include <dirent.h>
430Sstevel@tonic-gate #include <errno.h>
440Sstevel@tonic-gate #include <stdio.h>
450Sstevel@tonic-gate #include <signal.h>
460Sstevel@tonic-gate #include <ctype.h>
470Sstevel@tonic-gate #include <locale.h>
480Sstevel@tonic-gate #include <nl_types.h>
490Sstevel@tonic-gate #include <langinfo.h>
500Sstevel@tonic-gate #include <pwd.h>
510Sstevel@tonic-gate #include <grp.h>
520Sstevel@tonic-gate #include <fcntl.h>
530Sstevel@tonic-gate #include <string.h>
540Sstevel@tonic-gate #include <malloc.h>
550Sstevel@tonic-gate #include <time.h>
560Sstevel@tonic-gate #include <utime.h>
570Sstevel@tonic-gate #include <stdlib.h>
580Sstevel@tonic-gate #include <stdarg.h>
590Sstevel@tonic-gate #include <widec.h>
600Sstevel@tonic-gate #include <sys/mtio.h>
610Sstevel@tonic-gate #include <sys/acl.h>
620Sstevel@tonic-gate #include <strings.h>
630Sstevel@tonic-gate #include <deflt.h>
640Sstevel@tonic-gate #include <limits.h>
650Sstevel@tonic-gate #include <iconv.h>
660Sstevel@tonic-gate #include <assert.h>
675331Samw #include <libgen.h>
685331Samw #include <libintl.h>
69789Sahrens #include <aclutils.h>
705331Samw #include <libnvpair.h>
715331Samw #include <archives.h>
724774Sas145665
730Sstevel@tonic-gate #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
740Sstevel@tonic-gate extern int defcntl();
750Sstevel@tonic-gate #endif
765331Samw #if defined(_PC_SATTR_ENABLED)
775331Samw #include <attr.h>
785331Samw #include <libcmdutils.h>
795331Samw #endif
800Sstevel@tonic-gate
811676Sjpk /* Trusted Extensions */
821676Sjpk #include <zone.h>
831676Sjpk #include <tsol/label.h>
841676Sjpk #include <sys/tsol/label_macro.h>
851676Sjpk
865331Samw #include "getresponse.h"
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate * Source compatibility
890Sstevel@tonic-gate */
900Sstevel@tonic-gate
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate * These constants come from archives.h and sys/fcntl.h
930Sstevel@tonic-gate * and were introduced by the extended attributes project
940Sstevel@tonic-gate * in Solaris 9.
950Sstevel@tonic-gate */
960Sstevel@tonic-gate #if !defined(O_XATTR)
970Sstevel@tonic-gate #define AT_SYMLINK_NOFOLLOW 0x1000
980Sstevel@tonic-gate #define AT_REMOVEDIR 0x1
990Sstevel@tonic-gate #define AT_FDCWD 0xffd19553
1000Sstevel@tonic-gate #define _XATTR_HDRTYPE 'E'
1010Sstevel@tonic-gate static int attropen();
1020Sstevel@tonic-gate static int fstatat();
1030Sstevel@tonic-gate static int renameat();
1040Sstevel@tonic-gate static int unlinkat();
1050Sstevel@tonic-gate static int openat();
1060Sstevel@tonic-gate static int fchownat();
1070Sstevel@tonic-gate static int futimesat();
1080Sstevel@tonic-gate #endif
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate * Compiling with -D_XPG4_2 gets this but produces other problems, so
1120Sstevel@tonic-gate * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
1130Sstevel@tonic-gate * explicitly doing the declaration here.
1140Sstevel@tonic-gate */
1150Sstevel@tonic-gate int utimes(const char *path, const struct timeval timeval_ptr[]);
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate #ifndef MINSIZE
1180Sstevel@tonic-gate #define MINSIZE 250
1190Sstevel@tonic-gate #endif
1200Sstevel@tonic-gate #define DEF_FILE "/etc/default/tar"
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate #define min(a, b) ((a) < (b) ? (a) : (b))
1230Sstevel@tonic-gate #define max(a, b) ((a) > (b) ? (a) : (b))
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate /* -DDEBUG ONLY for debugging */
1260Sstevel@tonic-gate #ifdef DEBUG
1270Sstevel@tonic-gate #undef DEBUG
1280Sstevel@tonic-gate #define DEBUG(a, b, c)\
1290Sstevel@tonic-gate (void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c)
1300Sstevel@tonic-gate #endif
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate #define TBLOCK 512 /* tape block size--should be universal */
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate #ifdef BSIZE
1350Sstevel@tonic-gate #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
1360Sstevel@tonic-gate #else /* BSIZE */
1370Sstevel@tonic-gate #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
1380Sstevel@tonic-gate #endif /* BSIZE */
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate #define NBLOCK 20
1410Sstevel@tonic-gate #define NAMSIZ 100
1420Sstevel@tonic-gate #define PRESIZ 155
1430Sstevel@tonic-gate #define MAXNAM 256
1440Sstevel@tonic-gate #define MODEMASK 0777777 /* file creation mode mask */
1450Sstevel@tonic-gate #define POSIXMODES 07777 /* mask for POSIX mode bits */
1460Sstevel@tonic-gate #define MAXEXT 9 /* reasonable max # extents for a file */
1470Sstevel@tonic-gate #define EXTMIN 50 /* min blks left on floppy to split a file */
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /* max value dblock.dbuf.efsize can store */
1500Sstevel@tonic-gate #define TAR_EFSIZE_MAX 0777777777
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate * Symbols which specify the values at which the use of the 'E' function
1540Sstevel@tonic-gate * modifier is required to properly store a file.
1550Sstevel@tonic-gate *
1560Sstevel@tonic-gate * TAR_OFFSET_MAX - the largest file size we can archive
1570Sstevel@tonic-gate * OCTAL7CHAR - the limit for ustar gid, uid, dev
1580Sstevel@tonic-gate */
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate #ifdef XHDR_DEBUG
1610Sstevel@tonic-gate /* tiny values which force the creation of extended header entries */
1620Sstevel@tonic-gate #define TAR_OFFSET_MAX 9
1630Sstevel@tonic-gate #define OCTAL7CHAR 2
1640Sstevel@tonic-gate #else
1650Sstevel@tonic-gate /* normal values */
166373Sceastha #define TAR_OFFSET_MAX 077777777777ULL
1670Sstevel@tonic-gate #define OCTAL7CHAR 07777777
1680Sstevel@tonic-gate #endif
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
1710Sstevel@tonic-gate #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate #define MAXLEV (PATH_MAX / 2)
1740Sstevel@tonic-gate #define LEV0 1
1750Sstevel@tonic-gate #define SYMLINK_LEV0 0
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate #define TRUE 1
1780Sstevel@tonic-gate #define FALSE 0
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate #define XATTR_FILE 1
1810Sstevel@tonic-gate #define NORMAL_FILE 0
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate #define PUT_AS_LINK 1
1840Sstevel@tonic-gate #define PUT_NOTAS_LINK 0
1850Sstevel@tonic-gate
1865331Samw #ifndef VIEW_READONLY
1875331Samw #define VIEW_READONLY "SUNWattr_ro"
1885331Samw #endif
1895331Samw
1905331Samw #ifndef VIEW_READWRITE
1915331Samw #define VIEW_READWRITE "SUNWattr_rw"
1925331Samw #endif
1935331Samw
1940Sstevel@tonic-gate #if _FILE_OFFSET_BITS == 64
1950Sstevel@tonic-gate #define FMT_off_t "lld"
1960Sstevel@tonic-gate #define FMT_off_t_o "llo"
1970Sstevel@tonic-gate #define FMT_blkcnt_t "lld"
1980Sstevel@tonic-gate #else
1990Sstevel@tonic-gate #define FMT_off_t "ld"
2000Sstevel@tonic-gate #define FMT_off_t_o "lo"
2010Sstevel@tonic-gate #define FMT_blkcnt_t "ld"
2020Sstevel@tonic-gate #endif
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate /* ACL support */
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate static
2070Sstevel@tonic-gate struct sec_attr {
2080Sstevel@tonic-gate char attr_type;
2090Sstevel@tonic-gate char attr_len[7];
2100Sstevel@tonic-gate char attr_info[1];
2110Sstevel@tonic-gate } *attr;
2120Sstevel@tonic-gate
2135331Samw #if defined(O_XATTR)
2145331Samw typedef enum {
2155331Samw ATTR_OK,
2165331Samw ATTR_SKIP,
2175331Samw ATTR_CHDIR_ERR,
2185331Samw ATTR_OPEN_ERR,
2195331Samw ATTR_XATTR_ERR,
2205331Samw ATTR_SATTR_ERR
2215331Samw } attr_status_t;
2225331Samw #endif
2235331Samw
2245331Samw #if defined(O_XATTR)
2255331Samw typedef enum {
2265331Samw ARC_CREATE,
2275331Samw ARC_RESTORE
2285331Samw } arc_action_t;
2295331Samw #endif
2305331Samw
2315331Samw typedef struct attr_data {
2325331Samw char *attr_parent;
2335331Samw char *attr_path;
2345331Samw int attr_parentfd;
2355331Samw int attr_rw_sysattr;
2365331Samw } attr_data_t;
2375331Samw
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate *
2400Sstevel@tonic-gate * Tar has been changed to support extended attributes.
2410Sstevel@tonic-gate *
2420Sstevel@tonic-gate * As part of this change tar now uses the new *at() syscalls
2430Sstevel@tonic-gate * such as openat, fchownat(), unlinkat()...
2440Sstevel@tonic-gate *
2450Sstevel@tonic-gate * This was done so that attributes can be handled with as few code changes
2460Sstevel@tonic-gate * as possible.
2470Sstevel@tonic-gate *
2480Sstevel@tonic-gate * What this means is that tar now opens the directory that a file or directory
2490Sstevel@tonic-gate * resides in and then performs *at() functions to manipulate the entry.
2500Sstevel@tonic-gate *
2510Sstevel@tonic-gate * For example a new file is now created like this:
2520Sstevel@tonic-gate *
2530Sstevel@tonic-gate * dfd = open(<some dir path>)
2540Sstevel@tonic-gate * fd = openat(dfd, <name>,....);
2550Sstevel@tonic-gate *
2560Sstevel@tonic-gate * or in the case of an extended attribute
2570Sstevel@tonic-gate *
2580Sstevel@tonic-gate * dfd = attropen(<pathname>, ".", ....)
2590Sstevel@tonic-gate *
2600Sstevel@tonic-gate * Once we have a directory file descriptor all of the *at() functions can
2610Sstevel@tonic-gate * be applied to it.
2620Sstevel@tonic-gate *
2630Sstevel@tonic-gate * unlinkat(dfd, <component name>,...)
2640Sstevel@tonic-gate * fchownat(dfd, <component name>,..)
2650Sstevel@tonic-gate *
2660Sstevel@tonic-gate * This works for both normal namespace files and extended attribute file
2670Sstevel@tonic-gate *
2680Sstevel@tonic-gate */
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /*
2710Sstevel@tonic-gate *
2720Sstevel@tonic-gate * Extended attribute Format
2730Sstevel@tonic-gate *
2740Sstevel@tonic-gate * Extended attributes are stored in two pieces.
2750Sstevel@tonic-gate * 1. An attribute header which has information about
2760Sstevel@tonic-gate * what file the attribute is for and what the attribute
2770Sstevel@tonic-gate * is named.
2780Sstevel@tonic-gate * 2. The attribute record itself. Stored as a normal file type
2790Sstevel@tonic-gate * of entry.
2800Sstevel@tonic-gate * Both the header and attribute record have special modes/typeflags
2810Sstevel@tonic-gate * associated with them.
2820Sstevel@tonic-gate *
2830Sstevel@tonic-gate * The names of the header in the archive look like:
2840Sstevel@tonic-gate * /dev/null/attr.hdr
2850Sstevel@tonic-gate *
2860Sstevel@tonic-gate * The name of the attribute looks like:
2870Sstevel@tonic-gate * /dev/null/attr
2880Sstevel@tonic-gate *
2890Sstevel@tonic-gate * This is done so that an archiver that doesn't understand these formats
2900Sstevel@tonic-gate * can just dispose of the attribute records.
2910Sstevel@tonic-gate *
2920Sstevel@tonic-gate * The format is composed of a fixed size header followed
2930Sstevel@tonic-gate * by a variable sized xattr_buf. If the attribute is a hard link
2940Sstevel@tonic-gate * to another attribute then another xattr_buf section is included
2950Sstevel@tonic-gate * for the link.
2960Sstevel@tonic-gate *
2970Sstevel@tonic-gate * The xattr_buf is used to define the necessary "pathing" steps
2980Sstevel@tonic-gate * to get to the extended attribute. This is necessary to support
2990Sstevel@tonic-gate * a fully recursive attribute model where an attribute may itself
3000Sstevel@tonic-gate * have an attribute.
3010Sstevel@tonic-gate *
3020Sstevel@tonic-gate * The basic layout looks like this.
3030Sstevel@tonic-gate *
3040Sstevel@tonic-gate * --------------------------------
3050Sstevel@tonic-gate * | |
3060Sstevel@tonic-gate * | xattr_hdr |
3070Sstevel@tonic-gate * | |
3080Sstevel@tonic-gate * --------------------------------
3090Sstevel@tonic-gate * --------------------------------
3100Sstevel@tonic-gate * | |
3110Sstevel@tonic-gate * | xattr_buf |
3120Sstevel@tonic-gate * | |
3130Sstevel@tonic-gate * --------------------------------
3140Sstevel@tonic-gate * --------------------------------
3150Sstevel@tonic-gate * | |
3160Sstevel@tonic-gate * | (optional link info) |
3170Sstevel@tonic-gate * | |
3180Sstevel@tonic-gate * --------------------------------
3190Sstevel@tonic-gate * --------------------------------
3200Sstevel@tonic-gate * | |
3210Sstevel@tonic-gate * | attribute itself |
3220Sstevel@tonic-gate * | stored as normal tar |
3230Sstevel@tonic-gate * | or cpio data with |
3240Sstevel@tonic-gate * | special mode or |
3250Sstevel@tonic-gate * | typeflag |
3260Sstevel@tonic-gate * | |
3270Sstevel@tonic-gate * --------------------------------
3280Sstevel@tonic-gate *
3290Sstevel@tonic-gate */
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate /*
3320Sstevel@tonic-gate * xattrhead is a pointer to the xattr_hdr
3330Sstevel@tonic-gate *
3340Sstevel@tonic-gate * xattrp is a pointer to the xattr_buf structure
3350Sstevel@tonic-gate * which contains the "pathing" steps to get to attributes
3360Sstevel@tonic-gate *
3370Sstevel@tonic-gate * xattr_linkp is a pointer to another xattr_buf structure that is
3380Sstevel@tonic-gate * only used when an attribute is actually linked to another attribute
3390Sstevel@tonic-gate *
3400Sstevel@tonic-gate */
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate static struct xattr_hdr *xattrhead;
3430Sstevel@tonic-gate static struct xattr_buf *xattrp;
3440Sstevel@tonic-gate static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
3455331Samw static char *xattrapath; /* attribute name */
3460Sstevel@tonic-gate static char *xattr_linkaname; /* attribute attribute is linked to */
3470Sstevel@tonic-gate static char Hiddendir; /* are we processing hidden xattr dir */
3480Sstevel@tonic-gate static char xattrbadhead;
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate /* Was statically allocated tbuf[NBLOCK] */
3510Sstevel@tonic-gate static
3520Sstevel@tonic-gate union hblock {
3530Sstevel@tonic-gate char dummy[TBLOCK];
3540Sstevel@tonic-gate struct header {
3550Sstevel@tonic-gate char name[NAMSIZ]; /* If non-null prefix, path is */
3560Sstevel@tonic-gate /* <prefix>/<name>; otherwise */
3570Sstevel@tonic-gate /* <name> */
3580Sstevel@tonic-gate char mode[8];
3590Sstevel@tonic-gate char uid[8];
3600Sstevel@tonic-gate char gid[8];
3610Sstevel@tonic-gate char size[12]; /* size of this extent if file split */
3620Sstevel@tonic-gate char mtime[12];
3630Sstevel@tonic-gate char chksum[8];
3640Sstevel@tonic-gate char typeflag;
3650Sstevel@tonic-gate char linkname[NAMSIZ];
3660Sstevel@tonic-gate char magic[6];
3670Sstevel@tonic-gate char version[2];
3680Sstevel@tonic-gate char uname[32];
3690Sstevel@tonic-gate char gname[32];
3700Sstevel@tonic-gate char devmajor[8];
3710Sstevel@tonic-gate char devminor[8];
3720Sstevel@tonic-gate char prefix[PRESIZ]; /* Together with "name", the path of */
3730Sstevel@tonic-gate /* the file: <prefix>/<name> */
3740Sstevel@tonic-gate char extno; /* extent #, null if not split */
3750Sstevel@tonic-gate char extotal; /* total extents */
3760Sstevel@tonic-gate char efsize[10]; /* size of entire file */
3770Sstevel@tonic-gate } dbuf;
3780Sstevel@tonic-gate } dblock, *tbuf, xhdr_buf;
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate static
3810Sstevel@tonic-gate struct xtar_hdr {
3820Sstevel@tonic-gate uid_t x_uid, /* Uid of file */
3830Sstevel@tonic-gate x_gid; /* Gid of file */
3840Sstevel@tonic-gate major_t x_devmajor; /* Device major node */
3850Sstevel@tonic-gate minor_t x_devminor; /* Device minor node */
3860Sstevel@tonic-gate off_t x_filesz; /* Length of file */
3870Sstevel@tonic-gate char *x_uname, /* Pointer to name of user */
3880Sstevel@tonic-gate *x_gname, /* Pointer to gid of user */
3890Sstevel@tonic-gate *x_linkpath, /* Path for a hard/symbolic link */
3900Sstevel@tonic-gate *x_path; /* Path of file */
3910Sstevel@tonic-gate timestruc_t x_mtime; /* Seconds and nanoseconds */
3920Sstevel@tonic-gate } Xtarhdr;
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate static
3950Sstevel@tonic-gate struct gen_hdr {
3960Sstevel@tonic-gate ulong_t g_mode; /* Mode of file */
3970Sstevel@tonic-gate uid_t g_uid, /* Uid of file */
3980Sstevel@tonic-gate g_gid; /* Gid of file */
3990Sstevel@tonic-gate off_t g_filesz; /* Length of file */
4000Sstevel@tonic-gate time_t g_mtime; /* Modification time */
4010Sstevel@tonic-gate uint_t g_cksum; /* Checksum of file */
4020Sstevel@tonic-gate ulong_t g_devmajor, /* File system of file */
4030Sstevel@tonic-gate g_devminor; /* Major/minor of special files */
4040Sstevel@tonic-gate } Gen;
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate static
4070Sstevel@tonic-gate struct linkbuf {
4080Sstevel@tonic-gate ino_t inum;
4090Sstevel@tonic-gate dev_t devnum;
4100Sstevel@tonic-gate int count;
4110Sstevel@tonic-gate char pathname[MAXNAM+1]; /* added 1 for last NULL */
4120Sstevel@tonic-gate char attrname[MAXNAM+1];
4130Sstevel@tonic-gate struct linkbuf *nextp;
4140Sstevel@tonic-gate } *ihead;
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /* see comments before build_table() */
4170Sstevel@tonic-gate #define TABLE_SIZE 512
4186525Sceastha typedef struct file_list {
4190Sstevel@tonic-gate char *name; /* Name of file to {in,ex}clude */
4200Sstevel@tonic-gate struct file_list *next; /* Linked list */
4216525Sceastha } file_list_t;
4226525Sceastha static file_list_t *exclude_tbl[TABLE_SIZE],
4236525Sceastha *include_tbl[TABLE_SIZE];
4240Sstevel@tonic-gate
4251676Sjpk static int append_secattr(char **, int *, int, char *, char);
4260Sstevel@tonic-gate static void write_ancillary(union hblock *, char *, int, char);
4270Sstevel@tonic-gate
4286525Sceastha static void add_file_to_table(file_list_t *table[], char *str);
4290Sstevel@tonic-gate static void assert_string(char *s, char *msg);
4300Sstevel@tonic-gate static int istape(int fd, int type);
4310Sstevel@tonic-gate static void backtape(void);
4326525Sceastha static void build_table(file_list_t *table[], char *file);
4335331Samw static int check_prefix(char **namep, char **dirp, char **compp);
4340Sstevel@tonic-gate static void closevol(void);
4350Sstevel@tonic-gate static void copy(void *dst, void *src);
4360Sstevel@tonic-gate static int convtoreg(off_t);
4373805Slovely static void delete_target(int fd, char *comp, char *namep);
4380Sstevel@tonic-gate static void doDirTimes(char *name, timestruc_t modTime);
4390Sstevel@tonic-gate static void done(int n);
4400Sstevel@tonic-gate static void dorep(char *argv[]);
4410Sstevel@tonic-gate static void dotable(char *argv[]);
4420Sstevel@tonic-gate static void doxtract(char *argv[]);
44312554Srich.burridge@oracle.com static int tar_chdir(const char *path);
44412423Srich.burridge@oracle.com static int is_directory(char *name);
44512201Srich.burridge@sun.com static int has_dot_dot(char *name);
44612201Srich.burridge@sun.com static int is_absolute(char *name);
44712201Srich.burridge@sun.com static char *make_relative_name(char *name, char **stripped_prefix);
4480Sstevel@tonic-gate static void fatal(char *format, ...);
4490Sstevel@tonic-gate static void vperror(int exit_status, char *fmt, ...);
4500Sstevel@tonic-gate static void flushtape(void);
4510Sstevel@tonic-gate static void getdir(void);
4520Sstevel@tonic-gate static void *getmem(size_t);
4530Sstevel@tonic-gate static void longt(struct stat *st, char aclchar);
4545482Sas158974 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
4550Sstevel@tonic-gate static int makeDir(char *name);
4560Sstevel@tonic-gate static void mterr(char *operation, int i, int exitcode);
4570Sstevel@tonic-gate static void newvol(void);
4580Sstevel@tonic-gate static void passtape(void);
4590Sstevel@tonic-gate static void putempty(blkcnt_t n);
4600Sstevel@tonic-gate static int putfile(char *longname, char *shortname, char *parent,
4615331Samw attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
4620Sstevel@tonic-gate static void readtape(char *buffer);
4630Sstevel@tonic-gate static void seekdisk(blkcnt_t blocks);
4640Sstevel@tonic-gate static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
4655482Sas158974 static void setbytes_to_skip(struct stat *st, int err);
4660Sstevel@tonic-gate static void splitfile(char *longname, int ifd, char *name,
4670Sstevel@tonic-gate char *prefix, int filetype);
4680Sstevel@tonic-gate static void tomodes(struct stat *sp);
4690Sstevel@tonic-gate static void usage(void);
4705331Samw static int xblocks(int issysattr, off_t bytes, int ofile);
4715331Samw static int xsfile(int issysattr, int ofd);
4720Sstevel@tonic-gate static void resugname(int dirfd, char *name, int symflag);
4730Sstevel@tonic-gate static int bcheck(char *bstr);
4740Sstevel@tonic-gate static int checkdir(char *name);
4750Sstevel@tonic-gate static int checksum(union hblock *dblockp);
4760Sstevel@tonic-gate #ifdef EUC
4770Sstevel@tonic-gate static int checksum_signed(union hblock *dblockp);
4780Sstevel@tonic-gate #endif /* EUC */
4790Sstevel@tonic-gate static int checkupdate(char *arg);
4800Sstevel@tonic-gate static int checkw(char c, char *name);
4810Sstevel@tonic-gate static int cmp(char *b, char *s, int n);
4820Sstevel@tonic-gate static int defset(char *arch);
4830Sstevel@tonic-gate static int endtape(void);
4846525Sceastha static int is_in_table(file_list_t *table[], char *str);
4850Sstevel@tonic-gate static int notsame(void);
4860Sstevel@tonic-gate static int is_prefix(char *s1, char *s2);
4870Sstevel@tonic-gate static int response(void);
4880Sstevel@tonic-gate static int build_dblock(const char *, const char *, const char,
4890Sstevel@tonic-gate const int filetype, const struct stat *, const dev_t, const char *);
4900Sstevel@tonic-gate static unsigned int hash(char *str);
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate static blkcnt_t kcheck(char *kstr);
4930Sstevel@tonic-gate static off_t bsrch(char *s, int n, off_t l, off_t h);
4940Sstevel@tonic-gate static void onintr(int sig);
4950Sstevel@tonic-gate static void onquit(int sig);
4960Sstevel@tonic-gate static void onhup(int sig);
4970Sstevel@tonic-gate static uid_t getuidbyname(char *);
4980Sstevel@tonic-gate static gid_t getgidbyname(char *);
4990Sstevel@tonic-gate static char *getname(gid_t);
5000Sstevel@tonic-gate static char *getgroup(gid_t);
5010Sstevel@tonic-gate static int checkf(char *name, int mode, int howmuch);
5020Sstevel@tonic-gate static int writetbuf(char *buffer, int n);
5035331Samw static int wantit(char *argv[], char **namep, char **dirp, char **comp,
5045331Samw attr_data_t **attrinfo);
5051676Sjpk static void append_ext_attr(char *shortname, char **secinfo, int *len);
5060Sstevel@tonic-gate static int get_xdata(void);
5070Sstevel@tonic-gate static void gen_num(const char *keyword, const u_longlong_t number);
5080Sstevel@tonic-gate static void gen_date(const char *keyword, const timestruc_t time_value);
5090Sstevel@tonic-gate static void gen_string(const char *keyword, const char *value);
5100Sstevel@tonic-gate static void get_xtime(char *value, timestruc_t *xtime);
5110Sstevel@tonic-gate static int chk_path_build(char *name, char *longname, char *linkname,
5120Sstevel@tonic-gate char *prefix, char type, int filetype);
5130Sstevel@tonic-gate static int gen_utf8_names(const char *filename);
5140Sstevel@tonic-gate static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
5150Sstevel@tonic-gate const char *src, int max_val);
5160Sstevel@tonic-gate static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
5170Sstevel@tonic-gate iconv_t iconv_cd, int xhdrflg, int max_val);
5180Sstevel@tonic-gate static int c_utf8(char *target, const char *source);
5195331Samw static int getstat(int dirfd, char *longname, char *shortname,
5205331Samw char *attrparent);
5215331Samw static void xattrs_put(char *, char *, char *, char *);
5220Sstevel@tonic-gate static void prepare_xattr(char **, char *, char *,
5230Sstevel@tonic-gate char, struct linkbuf *, int *);
5245331Samw static int put_link(char *name, char *longname, char *component,
5255331Samw char *longattrname, char *prefix, int filetype, char typeflag);
5260Sstevel@tonic-gate static int put_extra_attributes(char *longname, char *shortname,
5275331Samw char *longattrname, char *prefix, int filetype, char typeflag);
5285331Samw static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
5295331Samw char *prefix, int typeflag, int filetype, struct linkbuf *lp);
5305331Samw static int read_xattr_hdr(attr_data_t **attrinfo);
5311676Sjpk
5321676Sjpk /* Trusted Extensions */
5331676Sjpk #define AUTO_ZONE "/zone"
5341676Sjpk
5351676Sjpk static void extract_attr(char **file_ptr, struct sec_attr *);
5361676Sjpk static int check_ext_attr(char *filename);
5371676Sjpk static void rebuild_comp_path(char *str, char **namep);
5381676Sjpk static int rebuild_lk_comp_path(char *str, char **namep);
5391676Sjpk
5400Sstevel@tonic-gate static void get_parent(char *path, char *dir);
5410Sstevel@tonic-gate static char *get_component(char *path);
5425331Samw static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
5435331Samw char *name, int oflag, mode_t mode);
5440Sstevel@tonic-gate static char *skipslashes(char *string, char *start);
5450Sstevel@tonic-gate static void chop_endslashes(char *path);
54611990Srich.burridge@sun.com static pid_t compress_file(void);
54711990Srich.burridge@sun.com static void compress_back(void);
54811990Srich.burridge@sun.com static void decompress_file(void);
54911990Srich.burridge@sun.com static pid_t uncompress_file(void);
55011990Srich.burridge@sun.com static void *compress_malloc(size_t);
55111990Srich.burridge@sun.com static void check_compression();
55211990Srich.burridge@sun.com static char *bz_suffix();
55311990Srich.burridge@sun.com static char *gz_suffix();
55411990Srich.burridge@sun.com static char *add_suffix();
55511990Srich.burridge@sun.com static void wait_pid(pid_t);
556789Sahrens
5570Sstevel@tonic-gate static struct stat stbuf;
5580Sstevel@tonic-gate
5595331Samw static char *myname;
5600Sstevel@tonic-gate static int checkflag = 0;
5610Sstevel@tonic-gate static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
56211990Srich.burridge@sun.com static int rflag, xflag, vflag, tflag, mt, svmt, cflag, mflag, pflag;
5630Sstevel@tonic-gate static int uflag;
564*12836Srich.burridge@oracle.com static int errflag;
5650Sstevel@tonic-gate static int oflag;
566*12836Srich.burridge@oracle.com static int bflag, Aflag;
5670Sstevel@tonic-gate static int Pflag; /* POSIX conformant archive */
5680Sstevel@tonic-gate static int Eflag; /* Allow files greater than 8GB */
5690Sstevel@tonic-gate static int atflag; /* traverse extended attributes */
5705331Samw static int saflag; /* traverse extended sys attributes */
5710Sstevel@tonic-gate static int Dflag; /* Data change flag */
57211990Srich.burridge@sun.com static int jflag; /* flag to use 'bzip2' */
57311990Srich.burridge@sun.com static int zflag; /* flag to use 'gzip' */
57411990Srich.burridge@sun.com static int Zflag; /* flag to use 'compress' */
57511990Srich.burridge@sun.com
5761676Sjpk /* Trusted Extensions */
5771676Sjpk static int Tflag; /* Trusted Extensions attr flags */
5781676Sjpk static int dir_flag; /* for attribute extract */
5791676Sjpk static int mld_flag; /* for attribute extract */
5801676Sjpk static char *orig_namep; /* original namep - unadorned */
5811676Sjpk static int rpath_flag; /* MLD real path is rebuilt */
5821676Sjpk static char real_path[MAXPATHLEN]; /* MLD real path */
5831676Sjpk static int lk_rpath_flag; /* linked to real path is rebuilt */
5841676Sjpk static char lk_real_path[MAXPATHLEN]; /* linked real path */
5851676Sjpk static bslabel_t bs_label; /* for attribute extract */
5861676Sjpk static bslabel_t admin_low;
5871676Sjpk static bslabel_t admin_high;
5881676Sjpk static int ignored_aprivs = 0;
5891676Sjpk static int ignored_fprivs = 0;
5901676Sjpk static int ignored_fattrs = 0;
5911676Sjpk
5920Sstevel@tonic-gate static int term, chksum, wflag,
5930Sstevel@tonic-gate first = TRUE, defaults_used = FALSE, linkerrok;
5940Sstevel@tonic-gate static blkcnt_t recno;
5950Sstevel@tonic-gate static int freemem = 1;
5960Sstevel@tonic-gate static int nblock = NBLOCK;
5970Sstevel@tonic-gate static int Errflg = 0;
5980Sstevel@tonic-gate static int exitflag = 0;
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate static dev_t mt_dev; /* device containing output file */
6010Sstevel@tonic-gate static ino_t mt_ino; /* inode number of output file */
6020Sstevel@tonic-gate static int mt_devtype; /* dev type of archive, from stat structure */
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate static int update = 1; /* for `open' call */
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate static off_t low;
6070Sstevel@tonic-gate static off_t high;
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate static FILE *tfile;
6100Sstevel@tonic-gate static FILE *vfile = stdout;
61112422Srich.burridge@oracle.com static char *tmpdir;
61212422Srich.burridge@oracle.com static char *tmp_suffix = "/tarXXXXXX";
61312422Srich.burridge@oracle.com static char *tname;
6140Sstevel@tonic-gate static char archive[] = "archive0=";
6150Sstevel@tonic-gate static char *Xfile;
6160Sstevel@tonic-gate static char *usefile;
61711990Srich.burridge@sun.com static char tfname[1024];
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate static int mulvol; /* multi-volume option selected */
6200Sstevel@tonic-gate static blkcnt_t blocklim; /* number of blocks to accept per volume */
6210Sstevel@tonic-gate static blkcnt_t tapepos; /* current block number to be written */
6220Sstevel@tonic-gate static int NotTape; /* true if tape is a disk */
6230Sstevel@tonic-gate static int dumping; /* true if writing a tape or other archive */
6240Sstevel@tonic-gate static int extno; /* number of extent: starts at 1 */
6250Sstevel@tonic-gate static int extotal; /* total extents in this file */
6260Sstevel@tonic-gate static off_t extsize; /* size of current extent during extraction */
6270Sstevel@tonic-gate static ushort_t Oumask = 0; /* old umask value */
6280Sstevel@tonic-gate static int is_posix; /* true if archive we're reading is POSIX-conformant */
6290Sstevel@tonic-gate static const char *magic_type = "ustar";
6300Sstevel@tonic-gate static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
6310Sstevel@tonic-gate static char *xrec_ptr;
6320Sstevel@tonic-gate static off_t xrec_offset = 0;
6330Sstevel@tonic-gate static int Xhdrflag;
6340Sstevel@tonic-gate static int charset_type = 0;
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate static u_longlong_t xhdr_flgs; /* Bits set determine which items */
6370Sstevel@tonic-gate /* need to be in extended header. */
6380Sstevel@tonic-gate #define _X_DEVMAJOR 0x1
6390Sstevel@tonic-gate #define _X_DEVMINOR 0x2
6400Sstevel@tonic-gate #define _X_GID 0x4
6410Sstevel@tonic-gate #define _X_GNAME 0x8
6420Sstevel@tonic-gate #define _X_LINKPATH 0x10
6430Sstevel@tonic-gate #define _X_PATH 0x20
6440Sstevel@tonic-gate #define _X_SIZE 0x40
6450Sstevel@tonic-gate #define _X_UID 0x80
6460Sstevel@tonic-gate #define _X_UNAME 0x100
6470Sstevel@tonic-gate #define _X_ATIME 0x200
6480Sstevel@tonic-gate #define _X_CTIME 0x400
6490Sstevel@tonic-gate #define _X_MTIME 0x800
6505482Sas158974 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
6515482Sas158974 /* typeflag was followed by 'A' or non 'A' */
6525482Sas158974 /* typeflag. */
6530Sstevel@tonic-gate #define _X_LAST 0x40000000
6540Sstevel@tonic-gate
6550Sstevel@tonic-gate #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
6560Sstevel@tonic-gate #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
6570Sstevel@tonic-gate #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
6580Sstevel@tonic-gate #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
6590Sstevel@tonic-gate /*
6600Sstevel@tonic-gate * UTF_8 encoding requires more space than the current codeset equivalent.
6610Sstevel@tonic-gate * Currently a factor of 2-3 would suffice, but it is possible for a factor
6620Sstevel@tonic-gate * of 6 to be needed in the future, so for saftey, we use that here.
6630Sstevel@tonic-gate */
6640Sstevel@tonic-gate #define UTF_8_FACTOR 6
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate static u_longlong_t xhdr_count = 0;
6670Sstevel@tonic-gate static char xhdr_dirname[PRESIZ + 1];
6680Sstevel@tonic-gate static char pidchars[PID_MAX_DIGITS + 1];
6690Sstevel@tonic-gate static char *tchar = ""; /* null linkpath */
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
6720Sstevel@tonic-gate static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
6730Sstevel@tonic-gate static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
6740Sstevel@tonic-gate static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate * The following mechanism is provided to allow us to debug tar in complicated
6780Sstevel@tonic-gate * situations, like when it is part of a pipe. The idea is that you compile
67911990Srich.burridge@sun.com * with -DWAITAROUND defined, and then add the 'D' function modifier to the
68011990Srich.burridge@sun.com * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
6810Sstevel@tonic-gate * it will tell you to which pid to attach the debugger; otherwise, use ps to
6820Sstevel@tonic-gate * find it. Attach to the process from the debugger, and, *PRESTO*, you are
6830Sstevel@tonic-gate * there!
6840Sstevel@tonic-gate *
6850Sstevel@tonic-gate * Simply assign "waitaround = 0" once you attach to the process, and then
6860Sstevel@tonic-gate * proceed from there as usual.
6870Sstevel@tonic-gate */
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate #ifdef WAITAROUND
6900Sstevel@tonic-gate int waitaround = 0; /* wait for rendezvous with the debugger */
6910Sstevel@tonic-gate #endif
6920Sstevel@tonic-gate
69311990Srich.burridge@sun.com #define BZIP "/usr/bin/bzip2"
69411990Srich.burridge@sun.com #define GZIP "/usr/bin/gzip"
69511990Srich.burridge@sun.com #define COMPRESS "/usr/bin/compress"
69611990Srich.burridge@sun.com #define BZCAT "/usr/bin/bzcat"
69711990Srich.burridge@sun.com #define GZCAT "/usr/bin/gzcat"
69811990Srich.burridge@sun.com #define ZCAT "/usr/bin/zcat"
69911990Srich.burridge@sun.com #define GS 8 /* number of valid 'gzip' sufixes */
70011990Srich.burridge@sun.com #define BS 4 /* number of valid 'bzip2' sufixes */
70111990Srich.burridge@sun.com
70211990Srich.burridge@sun.com static char *compress_opt; /* compression type */
70311990Srich.burridge@sun.com
70411990Srich.burridge@sun.com static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
70511990Srich.burridge@sun.com ".tgz", ".taz"};
70611990Srich.burridge@sun.com static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
70711990Srich.burridge@sun.com static char *suffix;
70811990Srich.burridge@sun.com
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate int
main(int argc,char * argv[])7110Sstevel@tonic-gate main(int argc, char *argv[])
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate char *cp;
7140Sstevel@tonic-gate char *tmpdirp;
7150Sstevel@tonic-gate pid_t thispid;
71611990Srich.burridge@sun.com pid_t pid;
71711990Srich.burridge@sun.com int wstat;
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
7200Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
7210Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
7220Sstevel@tonic-gate #endif
7230Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
7240Sstevel@tonic-gate if (argc < 2)
7250Sstevel@tonic-gate usage();
7260Sstevel@tonic-gate
7270Sstevel@tonic-gate tfile = NULL;
7285331Samw if ((myname = strdup(argv[0])) == NULL) {
7295331Samw (void) fprintf(stderr, gettext(
7305331Samw "tar: cannot allocate program name\n"));
7315331Samw exit(1);
7325331Samw }
7330Sstevel@tonic-gate
7344774Sas145665 if (init_yes() < 0) {
7354774Sas145665 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
7364774Sas145665 strerror(errno));
7374774Sas145665 exit(2);
7384774Sas145665 }
7394774Sas145665
7400Sstevel@tonic-gate /*
7410Sstevel@tonic-gate * For XPG4 compatibility, we must be able to accept the "--"
7420Sstevel@tonic-gate * argument normally recognized by getopt; it is used to delimit
7430Sstevel@tonic-gate * the end opt the options section, and so can only appear in
7440Sstevel@tonic-gate * the position of the first argument. We simply skip it.
7450Sstevel@tonic-gate */
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate if (strcmp(argv[1], "--") == 0) {
7480Sstevel@tonic-gate argv++;
7490Sstevel@tonic-gate argc--;
7500Sstevel@tonic-gate if (argc < 3)
7510Sstevel@tonic-gate usage();
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate argv[argc] = NULL;
7550Sstevel@tonic-gate argv++;
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate /*
7580Sstevel@tonic-gate * Set up default values.
7590Sstevel@tonic-gate * Search the operand string looking for the first digit or an 'f'.
7600Sstevel@tonic-gate * If you find a digit, use the 'archive#' entry in DEF_FILE.
7610Sstevel@tonic-gate * If 'f' is given, bypass looking in DEF_FILE altogether.
7620Sstevel@tonic-gate * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
7630Sstevel@tonic-gate */
7640Sstevel@tonic-gate if ((usefile = getenv("TAPE")) == (char *)NULL) {
7650Sstevel@tonic-gate for (cp = *argv; *cp; ++cp)
7660Sstevel@tonic-gate if (isdigit(*cp) || *cp == 'f')
7670Sstevel@tonic-gate break;
7680Sstevel@tonic-gate if (*cp != 'f') {
7690Sstevel@tonic-gate archive[7] = (*cp)? *cp: '0';
7700Sstevel@tonic-gate if (!(defaults_used = defset(archive))) {
7710Sstevel@tonic-gate usefile = NULL;
7720Sstevel@tonic-gate nblock = 1;
7730Sstevel@tonic-gate blocklim = 0;
7740Sstevel@tonic-gate NotTape = 0;
7750Sstevel@tonic-gate }
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate for (cp = *argv++; *cp; cp++)
7800Sstevel@tonic-gate switch (*cp) {
7810Sstevel@tonic-gate #ifdef WAITAROUND
78211990Srich.burridge@sun.com case 'D':
7830Sstevel@tonic-gate /* rendezvous with the debugger */
7840Sstevel@tonic-gate waitaround = 1;
7850Sstevel@tonic-gate break;
7860Sstevel@tonic-gate #endif
7870Sstevel@tonic-gate case 'f':
7880Sstevel@tonic-gate assert_string(*argv, gettext(
7890Sstevel@tonic-gate "tar: tarfile must be specified with 'f' "
7900Sstevel@tonic-gate "function modifier\n"));
7910Sstevel@tonic-gate usefile = *argv++;
7920Sstevel@tonic-gate break;
7930Sstevel@tonic-gate case 'F':
794*12836Srich.burridge@oracle.com Fflag++;
7950Sstevel@tonic-gate break;
7960Sstevel@tonic-gate case 'c':
7970Sstevel@tonic-gate cflag++;
7980Sstevel@tonic-gate rflag++;
7990Sstevel@tonic-gate update = 1;
8000Sstevel@tonic-gate break;
8010Sstevel@tonic-gate #if defined(O_XATTR)
8020Sstevel@tonic-gate case '@':
8030Sstevel@tonic-gate atflag++;
8040Sstevel@tonic-gate break;
8055331Samw #endif /* O_XATTR */
8065331Samw #if defined(_PC_SATTR_ENABLED)
8075331Samw case '/':
8085331Samw saflag++;
8095331Samw break;
8105331Samw #endif /* _PC_SATTR_ENABLED */
8110Sstevel@tonic-gate case 'u':
8120Sstevel@tonic-gate uflag++; /* moved code after signals caught */
8130Sstevel@tonic-gate rflag++;
8140Sstevel@tonic-gate update = 2;
8150Sstevel@tonic-gate break;
8160Sstevel@tonic-gate case 'r':
8170Sstevel@tonic-gate rflag++;
8180Sstevel@tonic-gate update = 2;
8190Sstevel@tonic-gate break;
8200Sstevel@tonic-gate case 'v':
8210Sstevel@tonic-gate vflag++;
8220Sstevel@tonic-gate break;
8230Sstevel@tonic-gate case 'w':
8240Sstevel@tonic-gate wflag++;
8250Sstevel@tonic-gate break;
8260Sstevel@tonic-gate case 'x':
8270Sstevel@tonic-gate xflag++;
8280Sstevel@tonic-gate break;
8290Sstevel@tonic-gate case 'X':
8300Sstevel@tonic-gate assert_string(*argv, gettext(
8310Sstevel@tonic-gate "tar: exclude file must be specified with 'X' "
8320Sstevel@tonic-gate "function modifier\n"));
8330Sstevel@tonic-gate Xflag = 1;
8340Sstevel@tonic-gate Xfile = *argv++;
8350Sstevel@tonic-gate build_table(exclude_tbl, Xfile);
8360Sstevel@tonic-gate break;
8370Sstevel@tonic-gate case 't':
8380Sstevel@tonic-gate tflag++;
8390Sstevel@tonic-gate break;
8400Sstevel@tonic-gate case 'm':
8410Sstevel@tonic-gate mflag++;
8420Sstevel@tonic-gate break;
8430Sstevel@tonic-gate case 'p':
8440Sstevel@tonic-gate pflag++;
8450Sstevel@tonic-gate break;
8460Sstevel@tonic-gate case 'D':
8470Sstevel@tonic-gate Dflag++;
8480Sstevel@tonic-gate break;
8490Sstevel@tonic-gate case '-':
8500Sstevel@tonic-gate /* ignore this silently */
8510Sstevel@tonic-gate break;
8520Sstevel@tonic-gate case '0': /* numeric entries used only for defaults */
8530Sstevel@tonic-gate case '1':
8540Sstevel@tonic-gate case '2':
8550Sstevel@tonic-gate case '3':
8560Sstevel@tonic-gate case '4':
8570Sstevel@tonic-gate case '5':
8580Sstevel@tonic-gate case '6':
8590Sstevel@tonic-gate case '7':
8600Sstevel@tonic-gate break;
8610Sstevel@tonic-gate case 'b':
8620Sstevel@tonic-gate assert_string(*argv, gettext(
8630Sstevel@tonic-gate "tar: blocking factor must be specified "
8640Sstevel@tonic-gate "with 'b' function modifier\n"));
8650Sstevel@tonic-gate bflag++;
8660Sstevel@tonic-gate nblock = bcheck(*argv++);
8670Sstevel@tonic-gate break;
8680Sstevel@tonic-gate case 'n': /* not a magtape (instead of 'k') */
8690Sstevel@tonic-gate NotTape++; /* assume non-magtape */
8700Sstevel@tonic-gate break;
8710Sstevel@tonic-gate case 'l':
8720Sstevel@tonic-gate linkerrok++;
8730Sstevel@tonic-gate break;
8740Sstevel@tonic-gate case 'e':
875*12836Srich.burridge@oracle.com errflag++;
8760Sstevel@tonic-gate case 'o':
8770Sstevel@tonic-gate oflag++;
8780Sstevel@tonic-gate break;
8790Sstevel@tonic-gate case 'h':
8800Sstevel@tonic-gate hflag++;
8810Sstevel@tonic-gate break;
8820Sstevel@tonic-gate case 'i':
8830Sstevel@tonic-gate iflag++;
8840Sstevel@tonic-gate break;
8850Sstevel@tonic-gate case 'B':
8860Sstevel@tonic-gate Bflag++;
8870Sstevel@tonic-gate break;
8880Sstevel@tonic-gate case 'P':
8890Sstevel@tonic-gate Pflag++;
8900Sstevel@tonic-gate break;
8910Sstevel@tonic-gate case 'E':
8920Sstevel@tonic-gate Eflag++;
8930Sstevel@tonic-gate Pflag++; /* Only POSIX archive made */
8940Sstevel@tonic-gate break;
8951676Sjpk case 'T':
8961676Sjpk Tflag++; /* Handle Trusted Extensions attrs */
8971676Sjpk pflag++; /* also set flag for ACL */
8981676Sjpk break;
89911990Srich.burridge@sun.com case 'j': /* compession "bzip2" */
90011990Srich.burridge@sun.com jflag++;
90111990Srich.burridge@sun.com break;
90211990Srich.burridge@sun.com case 'z': /* compression "gzip" */
90311990Srich.burridge@sun.com zflag++;
90411990Srich.burridge@sun.com break;
90511990Srich.burridge@sun.com case 'Z': /* compression "compress" */
90611990Srich.burridge@sun.com Zflag++;
90711990Srich.burridge@sun.com break;
9080Sstevel@tonic-gate default:
9090Sstevel@tonic-gate (void) fprintf(stderr, gettext(
9100Sstevel@tonic-gate "tar: %c: unknown function modifier\n"), *cp);
9110Sstevel@tonic-gate usage();
9120Sstevel@tonic-gate }
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate if (!rflag && !xflag && !tflag)
9150Sstevel@tonic-gate usage();
9160Sstevel@tonic-gate if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
9170Sstevel@tonic-gate (void) fprintf(stderr, gettext(
9180Sstevel@tonic-gate "tar: specify only one of [ctxru].\n"));
9190Sstevel@tonic-gate usage();
9200Sstevel@tonic-gate }
92111990Srich.burridge@sun.com if (cflag) {
92211990Srich.burridge@sun.com if ((zflag && jflag) || (zflag && Zflag) ||
92311990Srich.burridge@sun.com (jflag && Zflag)) {
92411990Srich.burridge@sun.com (void) fprintf(stderr, gettext(
92511990Srich.burridge@sun.com "tar: specify only one of [jzZ] to "
92611990Srich.burridge@sun.com "create a compressed file.\n"));
92711990Srich.burridge@sun.com usage();
92811990Srich.burridge@sun.com }
92911990Srich.burridge@sun.com }
9301676Sjpk /* Trusted Extensions attribute handling */
9311676Sjpk if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
9321676Sjpk !is_system_labeled())) {
9331676Sjpk (void) fprintf(stderr, gettext(
9341676Sjpk "tar: the 'T' option is only available with "
9351676Sjpk "Trusted Extensions\nand must be run from "
9361676Sjpk "the global zone.\n"));
9371676Sjpk usage();
9381676Sjpk }
939*12836Srich.burridge@oracle.com if (cflag && *argv == NULL)
9400Sstevel@tonic-gate fatal(gettext("Missing filenames"));
9410Sstevel@tonic-gate if (usefile == NULL)
9420Sstevel@tonic-gate fatal(gettext("device argument required"));
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate /* alloc a buffer of the right size */
9450Sstevel@tonic-gate if ((tbuf = (union hblock *)
9461266Sceastha calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
9471266Sceastha (union hblock *)NULL) {
9480Sstevel@tonic-gate (void) fprintf(stderr, gettext(
9490Sstevel@tonic-gate "tar: cannot allocate physio buffer\n"));
9500Sstevel@tonic-gate exit(1);
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate if ((xrec_ptr = malloc(xrec_size)) == NULL) {
9540Sstevel@tonic-gate (void) fprintf(stderr, gettext(
9550Sstevel@tonic-gate "tar: cannot allocate extended header buffer\n"));
9560Sstevel@tonic-gate exit(1);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate #ifdef WAITAROUND
9600Sstevel@tonic-gate if (waitaround) {
9610Sstevel@tonic-gate (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
9620Sstevel@tonic-gate " %d\n"), getpid());
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate while (waitaround) {
9650Sstevel@tonic-gate (void) sleep(10);
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate #endif
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate thispid = getpid();
9710Sstevel@tonic-gate (void) sprintf(pidchars, "%ld", thispid);
9720Sstevel@tonic-gate thispid = strlen(pidchars);
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
9750Sstevel@tonic-gate (void) strcpy(xhdr_dirname, "/tmp");
9760Sstevel@tonic-gate else {
9770Sstevel@tonic-gate /*
9780Sstevel@tonic-gate * Make sure that dir is no longer than what can
9790Sstevel@tonic-gate * fit in the prefix part of the header.
9800Sstevel@tonic-gate */
9810Sstevel@tonic-gate if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
9820Sstevel@tonic-gate (void) strcpy(xhdr_dirname, "/tmp");
9830Sstevel@tonic-gate if ((vflag > 0) && (Eflag > 0))
9840Sstevel@tonic-gate (void) fprintf(stderr, gettext(
9850Sstevel@tonic-gate "Ignoring TMPDIR\n"));
9860Sstevel@tonic-gate } else
9870Sstevel@tonic-gate (void) strcpy(xhdr_dirname, tmpdirp);
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate (void) strcat(xhdr_dirname, "/PaxHeaders.");
9900Sstevel@tonic-gate (void) strcat(xhdr_dirname, pidchars);
9910Sstevel@tonic-gate
9920Sstevel@tonic-gate if (rflag) {
99311990Srich.burridge@sun.com if (cflag && usefile != NULL) {
99411990Srich.burridge@sun.com /* Set the compression type */
99511990Srich.burridge@sun.com if (jflag) {
99611990Srich.burridge@sun.com compress_opt = compress_malloc(strlen(BZIP)
99711990Srich.burridge@sun.com + 1);
99811990Srich.burridge@sun.com (void) strcpy(compress_opt, BZIP);
99911990Srich.burridge@sun.com } else if (zflag) {
100011990Srich.burridge@sun.com compress_opt = compress_malloc(strlen(GZIP)
100111990Srich.burridge@sun.com + 1);
100211990Srich.burridge@sun.com (void) strcpy(compress_opt, GZIP);
100311990Srich.burridge@sun.com } else if (Zflag) {
100411990Srich.burridge@sun.com compress_opt =
100511990Srich.burridge@sun.com compress_malloc(strlen(COMPRESS) + 1);
100611990Srich.burridge@sun.com (void) strcpy(compress_opt, COMPRESS);
100711990Srich.burridge@sun.com }
100811990Srich.burridge@sun.com } else {
100911990Srich.burridge@sun.com /*
101011990Srich.burridge@sun.com * Decompress if the file is compressed for
101111990Srich.burridge@sun.com * an update or replace.
101211990Srich.burridge@sun.com */
101311990Srich.burridge@sun.com if (strcmp(usefile, "-") != 0) {
101411990Srich.burridge@sun.com check_compression();
101511990Srich.burridge@sun.com if (compress_opt != NULL) {
101611990Srich.burridge@sun.com decompress_file();
101711990Srich.burridge@sun.com }
101811990Srich.burridge@sun.com }
101911990Srich.burridge@sun.com }
102011990Srich.burridge@sun.com
10210Sstevel@tonic-gate if (cflag && tfile != NULL)
10220Sstevel@tonic-gate usage();
10230Sstevel@tonic-gate if (signal(SIGINT, SIG_IGN) != SIG_IGN)
10240Sstevel@tonic-gate (void) signal(SIGINT, onintr);
10250Sstevel@tonic-gate if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
10260Sstevel@tonic-gate (void) signal(SIGHUP, onhup);
10270Sstevel@tonic-gate if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
10280Sstevel@tonic-gate (void) signal(SIGQUIT, onquit);
10290Sstevel@tonic-gate if (uflag) {
10300Sstevel@tonic-gate int tnum;
103112422Srich.burridge@oracle.com struct stat sbuf;
103212422Srich.burridge@oracle.com
103312422Srich.burridge@oracle.com tmpdir = getenv("TMPDIR");
103412422Srich.burridge@oracle.com /*
103512422Srich.burridge@oracle.com * If the name is invalid or this isn't a directory,
103612422Srich.burridge@oracle.com * or the directory is not writable, then reset to
103712422Srich.burridge@oracle.com * a default temporary directory.
103812422Srich.burridge@oracle.com */
103912422Srich.burridge@oracle.com if (tmpdir == NULL || *tmpdir == '\0' ||
104012422Srich.burridge@oracle.com (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
104112422Srich.burridge@oracle.com tmpdir = "/tmp";
104212422Srich.burridge@oracle.com } else if (stat(tmpdir, &sbuf) < 0 ||
104312422Srich.burridge@oracle.com (sbuf.st_mode & S_IFMT) != S_IFDIR ||
104412422Srich.burridge@oracle.com (sbuf.st_mode & S_IWRITE) == 0) {
104512422Srich.burridge@oracle.com tmpdir = "/tmp";
104612422Srich.burridge@oracle.com }
104712422Srich.burridge@oracle.com
104812422Srich.burridge@oracle.com if ((tname = calloc(1, strlen(tmpdir) +
104912422Srich.burridge@oracle.com strlen(tmp_suffix) + 1)) == NULL) {
105012422Srich.burridge@oracle.com vperror(1, gettext("tar: out of memory, "
105112422Srich.burridge@oracle.com "cannot create temporary file\n"));
105212422Srich.burridge@oracle.com }
105312422Srich.burridge@oracle.com (void) strcpy(tname, tmpdir);
105412422Srich.burridge@oracle.com (void) strcat(tname, tmp_suffix);
105512422Srich.burridge@oracle.com
10560Sstevel@tonic-gate if ((tnum = mkstemp(tname)) == -1)
10570Sstevel@tonic-gate vperror(1, "%s", tname);
10580Sstevel@tonic-gate if ((tfile = fdopen(tnum, "w")) == NULL)
10590Sstevel@tonic-gate vperror(1, "%s", tname);
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) {
10620Sstevel@tonic-gate if (cflag == 0)
10630Sstevel@tonic-gate fatal(gettext(
10640Sstevel@tonic-gate "can only create standard output archives."));
10650Sstevel@tonic-gate vfile = stderr;
10660Sstevel@tonic-gate mt = dup(1);
10670Sstevel@tonic-gate ++bflag;
10680Sstevel@tonic-gate } else {
10690Sstevel@tonic-gate if (cflag)
10700Sstevel@tonic-gate mt = open(usefile,
10710Sstevel@tonic-gate O_RDWR|O_CREAT|O_TRUNC, 0666);
10720Sstevel@tonic-gate else
10730Sstevel@tonic-gate mt = open(usefile, O_RDWR);
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate if (mt < 0) {
10760Sstevel@tonic-gate if (cflag == 0 || (mt = creat(usefile, 0666))
10771266Sceastha < 0)
10780Sstevel@tonic-gate vperror(1, "%s", usefile);
10790Sstevel@tonic-gate }
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate /* Get inode and device number of output file */
10820Sstevel@tonic-gate (void) fstat(mt, &stbuf);
10830Sstevel@tonic-gate mt_ino = stbuf.st_ino;
10840Sstevel@tonic-gate mt_dev = stbuf.st_dev;
10850Sstevel@tonic-gate mt_devtype = stbuf.st_mode & S_IFMT;
10860Sstevel@tonic-gate NotTape = !istape(mt, mt_devtype);
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate if (rflag && !cflag && (mt_devtype == S_IFIFO))
10890Sstevel@tonic-gate fatal(gettext("cannot append to pipe or FIFO."));
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate if (Aflag && vflag)
10920Sstevel@tonic-gate (void) printf(
10930Sstevel@tonic-gate gettext("Suppressing absolute pathnames\n"));
109411990Srich.burridge@sun.com if (cflag && compress_opt != NULL) {
109511990Srich.burridge@sun.com pid = compress_file();
109611990Srich.burridge@sun.com wait_pid(pid);
109711990Srich.burridge@sun.com }
10980Sstevel@tonic-gate dorep(argv);
109911990Srich.burridge@sun.com if (rflag && !cflag && (compress_opt != NULL))
110011990Srich.burridge@sun.com compress_back();
11010Sstevel@tonic-gate } else if (xflag || tflag) {
11020Sstevel@tonic-gate /*
11030Sstevel@tonic-gate * for each argument, check to see if there is a "-I file" pair.
11040Sstevel@tonic-gate * if so, move the 3rd argument into "-I"'s place, build_table()
11050Sstevel@tonic-gate * using "file"'s name and increment argc one (the second
11060Sstevel@tonic-gate * increment appears in the for loop) which removes the two
11070Sstevel@tonic-gate * args "-I" and "file" from the argument vector.
11080Sstevel@tonic-gate */
11090Sstevel@tonic-gate for (argc = 0; argv[argc]; argc++) {
11100Sstevel@tonic-gate if (strcmp(argv[argc], "-I") == 0) {
11110Sstevel@tonic-gate if (!argv[argc+1]) {
11120Sstevel@tonic-gate (void) fprintf(stderr, gettext(
11130Sstevel@tonic-gate "tar: missing argument for -I flag\n"));
11140Sstevel@tonic-gate done(2);
11150Sstevel@tonic-gate } else {
11160Sstevel@tonic-gate Iflag = 1;
11170Sstevel@tonic-gate argv[argc] = argv[argc+2];
11180Sstevel@tonic-gate build_table(include_tbl, argv[++argc]);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) {
11230Sstevel@tonic-gate mt = dup(0);
11240Sstevel@tonic-gate ++bflag;
11250Sstevel@tonic-gate /* try to recover from short reads when reading stdin */
11260Sstevel@tonic-gate ++Bflag;
11270Sstevel@tonic-gate } else if ((mt = open(usefile, 0)) < 0)
11280Sstevel@tonic-gate vperror(1, "%s", usefile);
11290Sstevel@tonic-gate
113011990Srich.burridge@sun.com /* Decompress if the file is compressed */
113111990Srich.burridge@sun.com
113211990Srich.burridge@sun.com if (strcmp(usefile, "-") != 0) {
113311990Srich.burridge@sun.com check_compression();
113411990Srich.burridge@sun.com if (compress_opt != NULL) {
113511990Srich.burridge@sun.com pid = uncompress_file();
113611990Srich.burridge@sun.com wait_pid(pid);
113711990Srich.burridge@sun.com }
113811990Srich.burridge@sun.com }
11390Sstevel@tonic-gate if (xflag) {
11400Sstevel@tonic-gate if (Aflag && vflag)
11411266Sceastha (void) printf(gettext(
11421266Sceastha "Suppressing absolute pathnames.\n"));
11430Sstevel@tonic-gate
11440Sstevel@tonic-gate doxtract(argv);
11450Sstevel@tonic-gate } else if (tflag)
11460Sstevel@tonic-gate dotable(argv);
11470Sstevel@tonic-gate }
11480Sstevel@tonic-gate else
11490Sstevel@tonic-gate usage();
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate done(Errflg);
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate /* Not reached: keep compiler quiet */
11540Sstevel@tonic-gate return (1);
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate static void
usage(void)11580Sstevel@tonic-gate usage(void)
11590Sstevel@tonic-gate {
1160*12836Srich.burridge@oracle.com (void) fprintf(stderr, gettext(
11610Sstevel@tonic-gate #if defined(O_XATTR)
11625331Samw #if defined(_PC_SATTR_ENABLED)
1163*12836Srich.burridge@oracle.com "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
11645331Samw #else
1165*12836Srich.burridge@oracle.com "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
11665331Samw #endif /* _PC_SATTR_ENABLED */
11670Sstevel@tonic-gate #else
1168*12836Srich.burridge@oracle.com "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
11695331Samw #endif /* O_XATTR */
1170*12836Srich.burridge@oracle.com "[j|z|Z] "
1171*12836Srich.burridge@oracle.com "[blocksize] [tarfile] [size] [exclude-file...] "
1172*12836Srich.burridge@oracle.com "{file | -I include-file | -C directory file}...\n"));
11730Sstevel@tonic-gate done(1);
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate
11760Sstevel@tonic-gate /*
11770Sstevel@tonic-gate * dorep - do "replacements"
11780Sstevel@tonic-gate *
11790Sstevel@tonic-gate * Dorep is responsible for creating ('c'), appending ('r')
11800Sstevel@tonic-gate * and updating ('u');
11810Sstevel@tonic-gate */
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate static void
dorep(char * argv[])11840Sstevel@tonic-gate dorep(char *argv[])
11850Sstevel@tonic-gate {
11860Sstevel@tonic-gate char *cp, *cp2, *p;
11870Sstevel@tonic-gate char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
11880Sstevel@tonic-gate char file[PATH_MAX*2], origdir[PATH_MAX+1];
11890Sstevel@tonic-gate FILE *fp = (FILE *)NULL;
11900Sstevel@tonic-gate int archtype;
11915482Sas158974 int ret;
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate if (!cflag) {
11950Sstevel@tonic-gate xhdr_flgs = 0;
11960Sstevel@tonic-gate getdir(); /* read header for next file */
11970Sstevel@tonic-gate if (Xhdrflag > 0) {
11980Sstevel@tonic-gate if (!Eflag)
11990Sstevel@tonic-gate fatal(gettext("Archive contains extended"
12000Sstevel@tonic-gate " header. -E flag required.\n"));
12015482Sas158974 ret = get_xdata(); /* Get extended header items */
12020Sstevel@tonic-gate /* and regular header */
12030Sstevel@tonic-gate } else {
12040Sstevel@tonic-gate if (Eflag)
12050Sstevel@tonic-gate fatal(gettext("Archive contains no extended"
12060Sstevel@tonic-gate " header. -E flag not allowed.\n"));
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate while (!endtape()) { /* changed from a do while */
12095482Sas158974 setbytes_to_skip(&stbuf, ret);
12100Sstevel@tonic-gate passtape(); /* skip the file data */
12110Sstevel@tonic-gate if (term)
12120Sstevel@tonic-gate done(Errflg); /* received signal to stop */
12130Sstevel@tonic-gate xhdr_flgs = 0;
12140Sstevel@tonic-gate getdir();
12150Sstevel@tonic-gate if (Xhdrflag > 0)
12165482Sas158974 ret = get_xdata();
12175482Sas158974 }
12185482Sas158974 if (ret == 0) {
12195482Sas158974 if ((dblock.dbuf.typeflag != 'A') &&
12205482Sas158974 (xhdr_flgs != 0)) {
12215482Sas158974 load_info_from_xtarhdr(xhdr_flgs,
12225482Sas158974 &Xtarhdr);
12235482Sas158974 xhdr_flgs |= _X_XHDR;
12245482Sas158974 }
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate backtape(); /* was called by endtape */
12270Sstevel@tonic-gate if (tfile != NULL) {
122812422Srich.burridge@oracle.com /*
122912422Srich.burridge@oracle.com * Buffer size is calculated to be the size of the
123012422Srich.burridge@oracle.com * tmpdir string, plus 6 times the size of the tname
123112422Srich.burridge@oracle.com * string, plus a value that is known to be greater
123212422Srich.burridge@oracle.com * than the command pipeline string.
123312422Srich.burridge@oracle.com */
123412422Srich.burridge@oracle.com int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
123512422Srich.burridge@oracle.com char *buf;
123612422Srich.burridge@oracle.com
123712422Srich.burridge@oracle.com if ((buf = (char *)calloc(1, buflen)) == NULL) {
123812422Srich.burridge@oracle.com vperror(1, gettext("tar: out of memory, "
123912422Srich.burridge@oracle.com "cannot create sort command file\n"));
124012422Srich.burridge@oracle.com }
124112422Srich.burridge@oracle.com
124212422Srich.burridge@oracle.com (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
124312422Srich.burridge@oracle.com "sort +0 -1 +1nr %s -o %s; awk '$1 "
12440Sstevel@tonic-gate "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
124512422Srich.burridge@oracle.com tmpdir, tname, tname, tname, tname, tname, tname);
12460Sstevel@tonic-gate (void) fflush(tfile);
12470Sstevel@tonic-gate (void) system(buf);
124812422Srich.burridge@oracle.com free(buf);
12490Sstevel@tonic-gate (void) freopen(tname, "r", tfile);
12500Sstevel@tonic-gate (void) fstat(fileno(tfile), &stbuf);
12510Sstevel@tonic-gate high = stbuf.st_size;
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate }
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate dumping = 1;
12560Sstevel@tonic-gate if (mulvol) { /* SP-1 */
12570Sstevel@tonic-gate if (nblock && (blocklim%nblock) != 0)
12580Sstevel@tonic-gate fatal(gettext(
12590Sstevel@tonic-gate "Volume size not a multiple of block size."));
12600Sstevel@tonic-gate blocklim -= 2; /* for trailer records */
12610Sstevel@tonic-gate if (vflag)
12620Sstevel@tonic-gate (void) fprintf(vfile, gettext("Volume ends at %"
12630Sstevel@tonic-gate FMT_blkcnt_t "K, blocking factor = %dK\n"),
12640Sstevel@tonic-gate K((blocklim - 1)), K(nblock));
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate /*
12680Sstevel@tonic-gate * Save the original directory before it gets
12690Sstevel@tonic-gate * changed.
12700Sstevel@tonic-gate */
12710Sstevel@tonic-gate if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
12720Sstevel@tonic-gate vperror(0, gettext("A parent directory cannot be read"));
12730Sstevel@tonic-gate exit(1);
12740Sstevel@tonic-gate }
12750Sstevel@tonic-gate
12760Sstevel@tonic-gate (void) strcpy(wdir, origdir);
12770Sstevel@tonic-gate
1278*12836Srich.burridge@oracle.com while ((*argv || fp) && !term) {
12790Sstevel@tonic-gate if (fp || (strcmp(*argv, "-I") == 0)) {
12800Sstevel@tonic-gate if (fp == NULL) {
12810Sstevel@tonic-gate if (*++argv == NULL)
12820Sstevel@tonic-gate fatal(gettext(
12830Sstevel@tonic-gate "missing file name for -I flag."));
12840Sstevel@tonic-gate else if ((fp = fopen(*argv++, "r")) == NULL)
12850Sstevel@tonic-gate vperror(0, "%s", argv[-1]);
12860Sstevel@tonic-gate continue;
12870Sstevel@tonic-gate } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
12880Sstevel@tonic-gate (void) fclose(fp);
12890Sstevel@tonic-gate fp = NULL;
12900Sstevel@tonic-gate continue;
12910Sstevel@tonic-gate } else {
12920Sstevel@tonic-gate cp = cp2 = file;
12930Sstevel@tonic-gate if ((p = strchr(cp2, '\n')))
12940Sstevel@tonic-gate *p = 0;
12950Sstevel@tonic-gate }
12960Sstevel@tonic-gate } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
129712554Srich.burridge@oracle.com if (tar_chdir(*++argv) < 0)
12980Sstevel@tonic-gate vperror(0, gettext(
12995331Samw "can't change directories to %s"), *argv);
13000Sstevel@tonic-gate else
13010Sstevel@tonic-gate (void) getcwd(wdir, (sizeof (wdir)));
13020Sstevel@tonic-gate argv++;
13030Sstevel@tonic-gate continue;
13040Sstevel@tonic-gate } else
13050Sstevel@tonic-gate cp = cp2 = strcpy(file, *argv++);
13060Sstevel@tonic-gate
13070Sstevel@tonic-gate /*
13080Sstevel@tonic-gate * point cp2 to the last '/' in file, but not
13090Sstevel@tonic-gate * to a trailing '/'
13100Sstevel@tonic-gate */
13110Sstevel@tonic-gate for (; *cp; cp++) {
13120Sstevel@tonic-gate if (*cp == '/') {
13130Sstevel@tonic-gate while (*(cp+1) == '/') {
13140Sstevel@tonic-gate ++cp;
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate if (*(cp+1) != '\0') {
13170Sstevel@tonic-gate /* not trailing slash */
13180Sstevel@tonic-gate cp2 = cp;
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate if (cp2 != file) {
13230Sstevel@tonic-gate *cp2 = '\0';
132412554Srich.burridge@oracle.com if (tar_chdir(file) < 0) {
13250Sstevel@tonic-gate vperror(0, gettext(
13265331Samw "can't change directories to %s"), file);
13270Sstevel@tonic-gate continue;
13280Sstevel@tonic-gate }
13290Sstevel@tonic-gate *cp2 = '/';
13300Sstevel@tonic-gate cp2++;
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate parent = getcwd(tempdir, (sizeof (tempdir)));
13345331Samw
13355331Samw archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
13360Sstevel@tonic-gate LEV0, SYMLINK_LEV0);
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate #if defined(O_XATTR)
13390Sstevel@tonic-gate if (!exitflag) {
13405331Samw if ((atflag || saflag) &&
13415331Samw (archtype == PUT_NOTAS_LINK)) {
13425331Samw xattrs_put(file, cp2, parent, NULL);
13430Sstevel@tonic-gate }
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate #endif
13460Sstevel@tonic-gate
134712554Srich.burridge@oracle.com if (tar_chdir(origdir) < 0)
13480Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"), origdir);
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate if (exitflag) {
13510Sstevel@tonic-gate /*
13520Sstevel@tonic-gate * If e function modifier has been specified
13530Sstevel@tonic-gate * write the files (that are listed before the
13540Sstevel@tonic-gate * file causing the error) to tape. exitflag is
13550Sstevel@tonic-gate * used because only some of the error conditions
13560Sstevel@tonic-gate * in putfile() recognize the e function modifier.
13570Sstevel@tonic-gate */
13580Sstevel@tonic-gate break;
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate putempty((blkcnt_t)2);
13630Sstevel@tonic-gate flushtape();
13640Sstevel@tonic-gate closevol(); /* SP-1 */
13650Sstevel@tonic-gate if (linkerrok == 1)
13660Sstevel@tonic-gate for (; ihead != NULL; ihead = ihead->nextp) {
13670Sstevel@tonic-gate if (ihead->count == 0)
13680Sstevel@tonic-gate continue;
13690Sstevel@tonic-gate (void) fprintf(stderr, gettext(
13700Sstevel@tonic-gate "tar: missing links to %s\n"), ihead->pathname);
13710Sstevel@tonic-gate if (errflag)
13720Sstevel@tonic-gate done(1);
13730Sstevel@tonic-gate else
13740Sstevel@tonic-gate Errflg = 1;
13750Sstevel@tonic-gate }
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate
13780Sstevel@tonic-gate
13790Sstevel@tonic-gate /*
13800Sstevel@tonic-gate * endtape - check for tape at end
13810Sstevel@tonic-gate *
13820Sstevel@tonic-gate * endtape checks the entry in dblock.dbuf to see if its the
13830Sstevel@tonic-gate * special EOT entry. Endtape is usually called after getdir().
13840Sstevel@tonic-gate *
13850Sstevel@tonic-gate * endtape used to call backtape; it no longer does, he who
13860Sstevel@tonic-gate * wants it backed up must call backtape himself
13870Sstevel@tonic-gate * RETURNS: 0 if not EOT, tape position unaffected
13880Sstevel@tonic-gate * 1 if EOT, tape position unaffected
13890Sstevel@tonic-gate */
13900Sstevel@tonic-gate
13910Sstevel@tonic-gate static int
endtape(void)13920Sstevel@tonic-gate endtape(void)
13930Sstevel@tonic-gate {
13940Sstevel@tonic-gate if (dblock.dbuf.name[0] == '\0') { /* null header = EOT */
13950Sstevel@tonic-gate return (1);
13960Sstevel@tonic-gate } else
13970Sstevel@tonic-gate return (0);
13980Sstevel@tonic-gate }
13990Sstevel@tonic-gate
14000Sstevel@tonic-gate /*
14010Sstevel@tonic-gate * getdir - get directory entry from tar tape
14020Sstevel@tonic-gate *
14030Sstevel@tonic-gate * getdir reads the next tarblock off the tape and cracks
14040Sstevel@tonic-gate * it as a directory. The checksum must match properly.
14050Sstevel@tonic-gate *
14060Sstevel@tonic-gate * If tfile is non-null getdir writes the file name and mod date
14070Sstevel@tonic-gate * to tfile.
14080Sstevel@tonic-gate */
14090Sstevel@tonic-gate
14100Sstevel@tonic-gate static void
getdir(void)14110Sstevel@tonic-gate getdir(void)
14120Sstevel@tonic-gate {
14130Sstevel@tonic-gate struct stat *sp;
14140Sstevel@tonic-gate #ifdef EUC
14150Sstevel@tonic-gate static int warn_chksum_sign = 0;
14160Sstevel@tonic-gate #endif /* EUC */
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate top:
14190Sstevel@tonic-gate readtape((char *)&dblock);
14200Sstevel@tonic-gate if (dblock.dbuf.name[0] == '\0')
14210Sstevel@tonic-gate return;
14220Sstevel@tonic-gate sp = &stbuf;
14230Sstevel@tonic-gate (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
14240Sstevel@tonic-gate (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
14250Sstevel@tonic-gate (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
14260Sstevel@tonic-gate (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
14270Sstevel@tonic-gate (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
14280Sstevel@tonic-gate (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
14290Sstevel@tonic-gate (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
14300Sstevel@tonic-gate (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
14310Sstevel@tonic-gate
14320Sstevel@tonic-gate is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate sp->st_mode = Gen.g_mode;
14350Sstevel@tonic-gate if (is_posix && (sp->st_mode & S_IFMT) == 0)
14360Sstevel@tonic-gate switch (dblock.dbuf.typeflag) {
14370Sstevel@tonic-gate case '0': case 0: case _XATTR_HDRTYPE:
14380Sstevel@tonic-gate sp->st_mode |= S_IFREG;
14390Sstevel@tonic-gate break;
14400Sstevel@tonic-gate case '1': /* hard link */
14410Sstevel@tonic-gate break;
14420Sstevel@tonic-gate case '2':
14430Sstevel@tonic-gate sp->st_mode |= S_IFLNK;
14440Sstevel@tonic-gate break;
14450Sstevel@tonic-gate case '3':
14460Sstevel@tonic-gate sp->st_mode |= S_IFCHR;
14470Sstevel@tonic-gate break;
14480Sstevel@tonic-gate case '4':
14490Sstevel@tonic-gate sp->st_mode |= S_IFBLK;
14500Sstevel@tonic-gate break;
14510Sstevel@tonic-gate case '5':
14520Sstevel@tonic-gate sp->st_mode |= S_IFDIR;
14530Sstevel@tonic-gate break;
14540Sstevel@tonic-gate case '6':
14550Sstevel@tonic-gate sp->st_mode |= S_IFIFO;
14560Sstevel@tonic-gate break;
14570Sstevel@tonic-gate default:
14580Sstevel@tonic-gate if (convtoreg(Gen.g_filesz))
14590Sstevel@tonic-gate sp->st_mode |= S_IFREG;
14600Sstevel@tonic-gate break;
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate
146311995Srich.burridge@sun.com if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
14640Sstevel@tonic-gate Xhdrflag = 1; /* Currently processing extended header */
146511995Srich.burridge@sun.com } else {
14660Sstevel@tonic-gate Xhdrflag = 0;
146711995Srich.burridge@sun.com }
14680Sstevel@tonic-gate
14690Sstevel@tonic-gate sp->st_uid = Gen.g_uid;
14700Sstevel@tonic-gate sp->st_gid = Gen.g_gid;
14710Sstevel@tonic-gate sp->st_size = Gen.g_filesz;
14720Sstevel@tonic-gate sp->st_mtime = Gen.g_mtime;
14730Sstevel@tonic-gate chksum = Gen.g_cksum;
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate if (dblock.dbuf.extno != '\0') { /* split file? */
14760Sstevel@tonic-gate extno = dblock.dbuf.extno;
14770Sstevel@tonic-gate extsize = Gen.g_filesz;
14780Sstevel@tonic-gate extotal = dblock.dbuf.extotal;
14790Sstevel@tonic-gate } else {
14800Sstevel@tonic-gate extno = 0; /* tell others file not split */
14810Sstevel@tonic-gate extsize = 0;
14820Sstevel@tonic-gate extotal = 0;
14830Sstevel@tonic-gate }
14840Sstevel@tonic-gate
14850Sstevel@tonic-gate #ifdef EUC
14860Sstevel@tonic-gate if (chksum != checksum(&dblock)) {
14870Sstevel@tonic-gate if (chksum != checksum_signed(&dblock)) {
14880Sstevel@tonic-gate (void) fprintf(stderr, gettext(
14890Sstevel@tonic-gate "tar: directory checksum error\n"));
149012535Srich.burridge@oracle.com if (iflag) {
149112535Srich.burridge@oracle.com Errflg = 2;
14920Sstevel@tonic-gate goto top;
149312535Srich.burridge@oracle.com }
14940Sstevel@tonic-gate done(2);
14950Sstevel@tonic-gate } else {
14960Sstevel@tonic-gate if (! warn_chksum_sign) {
14970Sstevel@tonic-gate warn_chksum_sign = 1;
14980Sstevel@tonic-gate (void) fprintf(stderr, gettext(
14990Sstevel@tonic-gate "tar: warning: tar file made with signed checksum\n"));
15000Sstevel@tonic-gate }
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate #else
15040Sstevel@tonic-gate if (chksum != checksum(&dblock)) {
15050Sstevel@tonic-gate (void) fprintf(stderr, gettext(
15060Sstevel@tonic-gate "tar: directory checksum error\n"));
150712535Srich.burridge@oracle.com if (iflag) {
150812535Srich.burridge@oracle.com Errflg = 2;
15090Sstevel@tonic-gate goto top;
151012535Srich.burridge@oracle.com }
15110Sstevel@tonic-gate done(2);
15120Sstevel@tonic-gate }
15130Sstevel@tonic-gate #endif /* EUC */
15140Sstevel@tonic-gate if (tfile != NULL && Xhdrflag == 0) {
15150Sstevel@tonic-gate /*
15160Sstevel@tonic-gate * If an extended header is present, then time is available
15170Sstevel@tonic-gate * in nanoseconds in the extended header data, so set it.
15180Sstevel@tonic-gate * Otherwise, give an invalid value so that checkupdate will
15190Sstevel@tonic-gate * not test beyond seconds.
15200Sstevel@tonic-gate */
15210Sstevel@tonic-gate if ((xhdr_flgs & _X_MTIME))
15220Sstevel@tonic-gate sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
15230Sstevel@tonic-gate else
15240Sstevel@tonic-gate sp->st_mtim.tv_nsec = -1;
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate if (xhdr_flgs & _X_PATH)
15270Sstevel@tonic-gate (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
15280Sstevel@tonic-gate Xtarhdr.x_path, sp->st_mtim.tv_sec,
15290Sstevel@tonic-gate sp->st_mtim.tv_nsec);
15300Sstevel@tonic-gate else
15310Sstevel@tonic-gate (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
15320Sstevel@tonic-gate NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
15330Sstevel@tonic-gate sp->st_mtim.tv_nsec);
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate
15360Sstevel@tonic-gate #if defined(O_XATTR)
15370Sstevel@tonic-gate Hiddendir = 0;
15380Sstevel@tonic-gate if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
15390Sstevel@tonic-gate if (xattrbadhead) {
15400Sstevel@tonic-gate free(xattrhead);
15410Sstevel@tonic-gate xattrp = NULL;
15420Sstevel@tonic-gate xattr_linkp = NULL;
15430Sstevel@tonic-gate xattrhead = NULL;
15440Sstevel@tonic-gate } else {
15455331Samw char *aname = basename(xattrapath);
15465331Samw size_t xindex = aname - xattrapath;
15475331Samw
15485331Samw if (xattrapath[xindex] == '.' &&
15495331Samw xattrapath[xindex + 1] == '\0' &&
15500Sstevel@tonic-gate xattrp->h_typeflag == '5') {
15510Sstevel@tonic-gate Hiddendir = 1;
15520Sstevel@tonic-gate sp->st_mode =
15531231Smarks (S_IFDIR | (sp->st_mode & POSIXMODES));
15540Sstevel@tonic-gate }
15550Sstevel@tonic-gate dblock.dbuf.typeflag = xattrp->h_typeflag;
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate }
15580Sstevel@tonic-gate #endif
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate /*
15630Sstevel@tonic-gate * passtape - skip over a file on the tape
15640Sstevel@tonic-gate *
15650Sstevel@tonic-gate * passtape skips over the next data file on the tape.
15660Sstevel@tonic-gate * The tape directory entry must be in dblock.dbuf. This
15670Sstevel@tonic-gate * routine just eats the number of blocks computed from the
15680Sstevel@tonic-gate * directory size entry; the tape must be (logically) positioned
15690Sstevel@tonic-gate * right after thee directory info.
15700Sstevel@tonic-gate */
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate static void
passtape(void)15730Sstevel@tonic-gate passtape(void)
15740Sstevel@tonic-gate {
15750Sstevel@tonic-gate blkcnt_t blocks;
15760Sstevel@tonic-gate char buf[TBLOCK];
15770Sstevel@tonic-gate
15780Sstevel@tonic-gate /*
15790Sstevel@tonic-gate * Types link(1), sym-link(2), char special(3), blk special(4),
15800Sstevel@tonic-gate * directory(5), and FIFO(6) do not have data blocks associated
15810Sstevel@tonic-gate * with them so just skip reading the data block.
15820Sstevel@tonic-gate */
15830Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
15841266Sceastha dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
15851266Sceastha dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
15860Sstevel@tonic-gate return;
15870Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size);
15880Sstevel@tonic-gate
15890Sstevel@tonic-gate /* if operating on disk, seek instead of reading */
15900Sstevel@tonic-gate if (NotTape)
15910Sstevel@tonic-gate seekdisk(blocks);
15920Sstevel@tonic-gate else
15930Sstevel@tonic-gate while (blocks-- > 0)
15940Sstevel@tonic-gate readtape(buf);
15950Sstevel@tonic-gate }
15960Sstevel@tonic-gate
15975331Samw #if defined(O_XATTR)
15985331Samw static int
is_sysattr(char * name)15995331Samw is_sysattr(char *name)
16005331Samw {
16015331Samw return ((strcmp(name, VIEW_READONLY) == 0) ||
16025331Samw (strcmp(name, VIEW_READWRITE) == 0));
16035331Samw }
16045331Samw #endif
16055331Samw
16065331Samw #if defined(O_XATTR)
16075331Samw /*
16085331Samw * Verify the attribute, attrname, is an attribute we want to restore.
16095331Samw * Never restore read-only system attribute files. Only restore read-write
16105331Samw * system attributes files when -/ was specified, and only traverse into
16115331Samw * the 2nd level attribute directory containing only system attributes if
16125331Samw * -@ was specified. This keeps us from archiving
16135331Samw * <attribute name>/<read-write system attribute file>
16145331Samw * when -/ was specified without -@.
16155331Samw *
16165331Samw * attrname - attribute file name
16175331Samw * attrparent - attribute's parent name within the base file's attribute
16185331Samw * directory hierarchy
16195331Samw */
16205331Samw static attr_status_t
verify_attr(char * attrname,char * attrparent,int arc_rwsysattr,int * rw_sysattr)16215331Samw verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
16225331Samw int *rw_sysattr)
16235331Samw {
16245331Samw #if defined(_PC_SATTR_ENABLED)
16255331Samw int attr_supported;
16265331Samw
16275331Samw /* Never restore read-only system attribute files */
16285331Samw if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
16295331Samw *rw_sysattr = 0;
16305331Samw return (ATTR_SKIP);
16315331Samw } else {
16325331Samw *rw_sysattr = (attr_supported == _RW_SATTR);
16335331Samw }
16345331Samw #else
16355331Samw /*
16365331Samw * Only need to check if this attribute is an extended system
16375331Samw * attribute.
16385331Samw */
16395331Samw if (*rw_sysattr = is_sysattr(attrname)) {
16405331Samw return (ATTR_SKIP);
16415331Samw } else {
16425331Samw return (ATTR_OK);
16435331Samw }
16445331Samw #endif /* _PC_SATTR_ENABLED */
16455331Samw
16465331Samw /*
16475331Samw * If the extended system attribute file is specified with the
16485331Samw * arc_rwsysattr flag, as being transient (default extended
16495331Samw * attributes), then don't archive it.
16505331Samw */
16515331Samw if (*rw_sysattr && !arc_rwsysattr) {
16525331Samw return (ATTR_SKIP);
16535331Samw }
16545331Samw
16555331Samw /*
16565331Samw * Only restore read-write system attribute files
16575331Samw * when -/ was specified. Only restore extended
16585331Samw * attributes when -@ was specified.
16595331Samw */
16605331Samw if (atflag) {
16615331Samw if (!saflag) {
16625331Samw /*
16635331Samw * Only archive/restore the hidden directory "." if
16645331Samw * we're processing the top level hidden attribute
16655331Samw * directory. We don't want to process the
16665331Samw * hidden attribute directory of the attribute
16675331Samw * directory that contains only extended system
16685331Samw * attributes.
16695331Samw */
16705331Samw if (*rw_sysattr || (Hiddendir &&
16715331Samw (attrparent != NULL))) {
16725331Samw return (ATTR_SKIP);
16735331Samw }
16745331Samw }
16755331Samw } else if (saflag) {
16765331Samw /*
16775331Samw * Only archive/restore read-write extended system attribute
16785331Samw * files of the base file.
16795331Samw */
16805331Samw if (!*rw_sysattr || (attrparent != NULL)) {
16815331Samw return (ATTR_SKIP);
16825331Samw }
16835331Samw } else {
16845331Samw return (ATTR_SKIP);
16855331Samw }
16865331Samw
16875331Samw return (ATTR_OK);
16885331Samw }
16895331Samw #endif
16900Sstevel@tonic-gate
16916525Sceastha static void
free_children(file_list_t * children)16926525Sceastha free_children(file_list_t *children)
16936525Sceastha {
16946525Sceastha file_list_t *child = children;
16956525Sceastha file_list_t *cptr;
16966525Sceastha
16976525Sceastha while (child != NULL) {
16986525Sceastha cptr = child->next;
16996525Sceastha if (child->name != NULL) {
17006525Sceastha free(child->name);
17016525Sceastha }
17026525Sceastha child = cptr;
17036525Sceastha }
17046525Sceastha }
17056525Sceastha
17060Sstevel@tonic-gate static int
putfile(char * longname,char * shortname,char * parent,attr_data_t * attrinfo,int filetype,int lev,int symlink_lev)17075331Samw putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
17080Sstevel@tonic-gate int filetype, int lev, int symlink_lev)
17090Sstevel@tonic-gate {
17100Sstevel@tonic-gate int infile = -1; /* deliberately invalid */
17110Sstevel@tonic-gate blkcnt_t blocks;
17120Sstevel@tonic-gate char buf[PATH_MAX + 2]; /* Add trailing slash and null */
17130Sstevel@tonic-gate char *bigbuf;
17140Sstevel@tonic-gate int maxread;
17150Sstevel@tonic-gate int hint; /* amount to write to get "in sync" */
17160Sstevel@tonic-gate char filetmp[PATH_MAX + 1];
17170Sstevel@tonic-gate char *cp;
17180Sstevel@tonic-gate char *name;
17195331Samw char *attrparent = NULL;
17205331Samw char *longattrname = NULL;
17216525Sceastha file_list_t *child = NULL;
17226525Sceastha file_list_t *child_end = NULL;
17236525Sceastha file_list_t *cptr;
17240Sstevel@tonic-gate struct dirent *dp;
17250Sstevel@tonic-gate DIR *dirp;
17260Sstevel@tonic-gate int i;
17270Sstevel@tonic-gate int split;
17280Sstevel@tonic-gate int dirfd = -1;
17290Sstevel@tonic-gate int rc = PUT_NOTAS_LINK;
17300Sstevel@tonic-gate int archtype = 0;
17315331Samw int rw_sysattr = 0;
17320Sstevel@tonic-gate char newparent[PATH_MAX + MAXNAMLEN + 1];
17330Sstevel@tonic-gate char *prefix = "";
17340Sstevel@tonic-gate char *tmpbuf;
17350Sstevel@tonic-gate char goodbuf[PRESIZ + 2];
17360Sstevel@tonic-gate char junkbuf[MAXNAM+1];
17370Sstevel@tonic-gate char *lastslash;
17380Sstevel@tonic-gate int j;
17390Sstevel@tonic-gate struct stat sbuf;
17400Sstevel@tonic-gate int readlink_max;
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate (void) memset(goodbuf, '\0', sizeof (goodbuf));
17430Sstevel@tonic-gate (void) memset(junkbuf, '\0', sizeof (junkbuf));
17440Sstevel@tonic-gate
17450Sstevel@tonic-gate xhdr_flgs = 0;
17460Sstevel@tonic-gate
17470Sstevel@tonic-gate if (filetype == XATTR_FILE) {
17485331Samw attrparent = attrinfo->attr_parent;
17495331Samw longattrname = attrinfo->attr_path;
17505331Samw dirfd = attrinfo->attr_parentfd;
17515750Sceastha rw_sysattr = attrinfo->attr_rw_sysattr;
17520Sstevel@tonic-gate } else {
17530Sstevel@tonic-gate dirfd = open(".", O_RDONLY);
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate if (dirfd == -1) {
17570Sstevel@tonic-gate (void) fprintf(stderr, gettext(
17585331Samw "tar: unable to open%sdirectory %s%s%s%s\n"),
17590Sstevel@tonic-gate (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
17605331Samw (attrparent == NULL) ? "" : gettext("of attribute "),
17615331Samw (attrparent == NULL) ? "" : attrparent,
17625331Samw (attrparent == NULL) ? "" : gettext(" of "),
17630Sstevel@tonic-gate (filetype == XATTR_FILE) ? longname : parent);
17640Sstevel@tonic-gate goto out;
17650Sstevel@tonic-gate }
17660Sstevel@tonic-gate
17670Sstevel@tonic-gate if (lev > MAXLEV) {
17680Sstevel@tonic-gate (void) fprintf(stderr,
17690Sstevel@tonic-gate gettext("tar: directory nesting too deep, %s not dumped\n"),
17700Sstevel@tonic-gate longname);
17710Sstevel@tonic-gate goto out;
17720Sstevel@tonic-gate }
17730Sstevel@tonic-gate
17745331Samw if (getstat(dirfd, longname, shortname, attrparent))
17750Sstevel@tonic-gate goto out;
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate if (hflag) {
17780Sstevel@tonic-gate /*
17790Sstevel@tonic-gate * Catch nesting where a file is a symlink to its directory.
17800Sstevel@tonic-gate */
17810Sstevel@tonic-gate j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
17820Sstevel@tonic-gate if (S_ISLNK(sbuf.st_mode)) {
17830Sstevel@tonic-gate if (symlink_lev++ >= MAXSYMLINKS) {
17840Sstevel@tonic-gate (void) fprintf(stderr, gettext(
17850Sstevel@tonic-gate "tar: %s: Number of symbolic links "
17860Sstevel@tonic-gate "encountered during path name traversal "
17870Sstevel@tonic-gate "exceeds MAXSYMLINKS\n"), longname);
17880Sstevel@tonic-gate Errflg = 1;
17890Sstevel@tonic-gate goto out;
17900Sstevel@tonic-gate }
17910Sstevel@tonic-gate }
17920Sstevel@tonic-gate }
17930Sstevel@tonic-gate
17940Sstevel@tonic-gate /*
17950Sstevel@tonic-gate * Check if the input file is the same as the tar file we
17960Sstevel@tonic-gate * are creating
17970Sstevel@tonic-gate */
17980Sstevel@tonic-gate if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
17990Sstevel@tonic-gate (void) fprintf(stderr, gettext(
18005331Samw "tar: %s%s%s%s%s same as archive file\n"),
18015331Samw rw_sysattr ? gettext("system ") : "",
18025331Samw (longattrname == NULL) ? "" : gettext("attribute "),
18035331Samw (longattrname == NULL) ? "" : longattrname,
18045331Samw (longattrname == NULL) ? "" : gettext(" of "),
18055331Samw longname);
18060Sstevel@tonic-gate Errflg = 1;
18070Sstevel@tonic-gate goto out;
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate /*
18100Sstevel@tonic-gate * Check size limit - we can't archive files that
18110Sstevel@tonic-gate * exceed TAR_OFFSET_MAX bytes because of header
18120Sstevel@tonic-gate * limitations. Exclude file types that set
18130Sstevel@tonic-gate * st_size to zero below because they take no
18140Sstevel@tonic-gate * archive space to represent contents.
18150Sstevel@tonic-gate */
18160Sstevel@tonic-gate if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
18170Sstevel@tonic-gate !S_ISDIR(stbuf.st_mode) &&
18180Sstevel@tonic-gate !S_ISCHR(stbuf.st_mode) &&
18190Sstevel@tonic-gate !S_ISBLK(stbuf.st_mode) &&
18200Sstevel@tonic-gate (Eflag == 0)) {
18210Sstevel@tonic-gate (void) fprintf(stderr, gettext(
18225331Samw "tar: %s%s%s%s%s too large to archive. "
18235331Samw "Use E function modifier.\n"),
18245331Samw rw_sysattr ? gettext("system ") : "",
18255331Samw (longattrname == NULL) ? "" : gettext("attribute "),
18265331Samw (longattrname == NULL) ? "" : longattrname,
18275331Samw (longattrname == NULL) ? "" : gettext(" of "),
18285331Samw longname);
18290Sstevel@tonic-gate if (errflag)
18300Sstevel@tonic-gate exitflag = 1;
18310Sstevel@tonic-gate Errflg = 1;
18320Sstevel@tonic-gate goto out;
18330Sstevel@tonic-gate }
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate if (tfile != NULL && checkupdate(longname) == 0) {
18360Sstevel@tonic-gate goto out;
18370Sstevel@tonic-gate }
18380Sstevel@tonic-gate if (checkw('r', longname) == 0) {
18390Sstevel@tonic-gate goto out;
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate
184212423Srich.burridge@oracle.com if (Fflag &&
184312423Srich.burridge@oracle.com checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
18440Sstevel@tonic-gate goto out;
18450Sstevel@tonic-gate
18460Sstevel@tonic-gate if (Xflag) {
18470Sstevel@tonic-gate if (is_in_table(exclude_tbl, longname)) {
18480Sstevel@tonic-gate if (vflag) {
18490Sstevel@tonic-gate (void) fprintf(vfile, gettext(
18500Sstevel@tonic-gate "a %s excluded\n"), longname);
18510Sstevel@tonic-gate }
18520Sstevel@tonic-gate goto out;
18530Sstevel@tonic-gate }
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate
18560Sstevel@tonic-gate /*
18570Sstevel@tonic-gate * If the length of the fullname is greater than MAXNAM,
18580Sstevel@tonic-gate * print out a message and return (unless extended headers are used,
18590Sstevel@tonic-gate * in which case fullname is limited to PATH_MAX).
18600Sstevel@tonic-gate */
18610Sstevel@tonic-gate
18620Sstevel@tonic-gate if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
18630Sstevel@tonic-gate (split > PATH_MAX)) {
18640Sstevel@tonic-gate (void) fprintf(stderr, gettext(
18650Sstevel@tonic-gate "tar: %s: file name too long\n"), longname);
18660Sstevel@tonic-gate if (errflag)
18670Sstevel@tonic-gate exitflag = 1;
18680Sstevel@tonic-gate Errflg = 1;
18690Sstevel@tonic-gate goto out;
18700Sstevel@tonic-gate }
18710Sstevel@tonic-gate
18720Sstevel@tonic-gate /*
18730Sstevel@tonic-gate * We split the fullname into prefix and name components if any one
18740Sstevel@tonic-gate * of three conditions holds:
18750Sstevel@tonic-gate * -- the length of the fullname exceeds NAMSIZ,
18760Sstevel@tonic-gate * -- the length of the fullname equals NAMSIZ, and the shortname
18770Sstevel@tonic-gate * is less than NAMSIZ, (splitting in this case preserves
18780Sstevel@tonic-gate * compatibility with 5.6 and 5.5.1 tar), or
18790Sstevel@tonic-gate * -- the length of the fullname equals NAMSIZ, the file is a
18800Sstevel@tonic-gate * directory and we are not in POSIX-conformant mode (where
18810Sstevel@tonic-gate * trailing slashes are removed from directories).
18820Sstevel@tonic-gate */
18830Sstevel@tonic-gate if ((split > NAMSIZ) ||
18840Sstevel@tonic-gate (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1885871Scasper (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
18860Sstevel@tonic-gate /*
18870Sstevel@tonic-gate * Since path is limited to PRESIZ characters, look for the
18880Sstevel@tonic-gate * last slash within PRESIZ + 1 characters only.
18890Sstevel@tonic-gate */
18900Sstevel@tonic-gate (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
18910Sstevel@tonic-gate tmpbuf = goodbuf;
18920Sstevel@tonic-gate lastslash = strrchr(tmpbuf, '/');
18930Sstevel@tonic-gate if (lastslash == NULL) {
18940Sstevel@tonic-gate i = split; /* Length of name */
18950Sstevel@tonic-gate j = 0; /* Length of prefix */
18960Sstevel@tonic-gate goodbuf[0] = '\0';
18970Sstevel@tonic-gate } else {
18980Sstevel@tonic-gate *lastslash = '\0'; /* Terminate the prefix */
18990Sstevel@tonic-gate j = strlen(tmpbuf);
19000Sstevel@tonic-gate i = split - j - 1;
19010Sstevel@tonic-gate }
19020Sstevel@tonic-gate /*
19030Sstevel@tonic-gate * If the filename is greater than NAMSIZ we can't
19040Sstevel@tonic-gate * archive the file unless we are using extended headers.
19050Sstevel@tonic-gate */
1906871Scasper if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
19070Sstevel@tonic-gate !Pflag)) {
19080Sstevel@tonic-gate /* Determine which (filename or path) is too long. */
19090Sstevel@tonic-gate lastslash = strrchr(longname, '/');
19100Sstevel@tonic-gate if (lastslash != NULL)
19110Sstevel@tonic-gate i = strlen(lastslash + 1);
19120Sstevel@tonic-gate if (Eflag > 0) {
19130Sstevel@tonic-gate xhdr_flgs |= _X_PATH;
19140Sstevel@tonic-gate Xtarhdr.x_path = longname;
19150Sstevel@tonic-gate if (i <= NAMSIZ)
19160Sstevel@tonic-gate (void) strcpy(junkbuf, lastslash + 1);
19170Sstevel@tonic-gate else
19180Sstevel@tonic-gate (void) sprintf(junkbuf, "%llu",
19190Sstevel@tonic-gate xhdr_count + 1);
19200Sstevel@tonic-gate if (split - i - 1 > PRESIZ)
19210Sstevel@tonic-gate (void) strcpy(goodbuf, xhdr_dirname);
19220Sstevel@tonic-gate } else {
19230Sstevel@tonic-gate if ((i > NAMSIZ) || (i == NAMSIZ &&
1924871Scasper S_ISDIR(stbuf.st_mode) && !Pflag))
19250Sstevel@tonic-gate (void) fprintf(stderr, gettext(
19260Sstevel@tonic-gate "tar: %s: filename is greater than "
19270Sstevel@tonic-gate "%d\n"), lastslash == NULL ?
19280Sstevel@tonic-gate longname : lastslash + 1, NAMSIZ);
19290Sstevel@tonic-gate else
19300Sstevel@tonic-gate (void) fprintf(stderr, gettext(
19310Sstevel@tonic-gate "tar: %s: prefix is greater than %d"
19320Sstevel@tonic-gate "\n"), longname, PRESIZ);
19330Sstevel@tonic-gate if (errflag)
19340Sstevel@tonic-gate exitflag = 1;
19350Sstevel@tonic-gate Errflg = 1;
19360Sstevel@tonic-gate goto out;
19370Sstevel@tonic-gate }
19380Sstevel@tonic-gate } else
19390Sstevel@tonic-gate (void) strncpy(&junkbuf[0], longname + j + 1,
19400Sstevel@tonic-gate strlen(longname + j + 1));
19410Sstevel@tonic-gate name = junkbuf;
19420Sstevel@tonic-gate prefix = goodbuf;
19430Sstevel@tonic-gate } else {
19440Sstevel@tonic-gate name = longname;
19450Sstevel@tonic-gate }
19460Sstevel@tonic-gate if (Aflag) {
19470Sstevel@tonic-gate if ((prefix != NULL) && (*prefix != '\0'))
19480Sstevel@tonic-gate while (*prefix == '/')
19490Sstevel@tonic-gate ++prefix;
19500Sstevel@tonic-gate else
19510Sstevel@tonic-gate while (*name == '/')
19520Sstevel@tonic-gate ++name;
19530Sstevel@tonic-gate }
19540Sstevel@tonic-gate
19550Sstevel@tonic-gate switch (stbuf.st_mode & S_IFMT) {
19560Sstevel@tonic-gate case S_IFDIR:
19570Sstevel@tonic-gate stbuf.st_size = (off_t)0;
19580Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size);
19590Sstevel@tonic-gate
19600Sstevel@tonic-gate if (filetype != XATTR_FILE && Hiddendir == 0) {
19610Sstevel@tonic-gate i = 0;
19620Sstevel@tonic-gate cp = buf;
19630Sstevel@tonic-gate while ((*cp++ = longname[i++]))
19640Sstevel@tonic-gate ;
19650Sstevel@tonic-gate *--cp = '/';
19660Sstevel@tonic-gate *++cp = 0;
19670Sstevel@tonic-gate }
19680Sstevel@tonic-gate if (!oflag) {
19690Sstevel@tonic-gate tomodes(&stbuf);
19700Sstevel@tonic-gate if (build_dblock(name, tchar, '5', filetype,
19710Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) {
19720Sstevel@tonic-gate goto out;
19730Sstevel@tonic-gate }
19740Sstevel@tonic-gate if (!Pflag) {
19750Sstevel@tonic-gate /*
19760Sstevel@tonic-gate * Old archives require a slash at the end
19770Sstevel@tonic-gate * of a directory name.
19780Sstevel@tonic-gate *
19790Sstevel@tonic-gate * XXX
19800Sstevel@tonic-gate * If directory name is too long, will
19810Sstevel@tonic-gate * slash overfill field?
19820Sstevel@tonic-gate */
19830Sstevel@tonic-gate if (strlen(name) > (unsigned)NAMSIZ-1) {
19840Sstevel@tonic-gate (void) fprintf(stderr, gettext(
19850Sstevel@tonic-gate "tar: %s: filename is greater "
19860Sstevel@tonic-gate "than %d\n"), name, NAMSIZ);
19870Sstevel@tonic-gate if (errflag)
19880Sstevel@tonic-gate exitflag = 1;
19890Sstevel@tonic-gate Errflg = 1;
19900Sstevel@tonic-gate goto out;
19910Sstevel@tonic-gate } else {
19920Sstevel@tonic-gate if (strlen(name) == (NAMSIZ - 1)) {
19930Sstevel@tonic-gate (void) memcpy(dblock.dbuf.name,
19940Sstevel@tonic-gate name, NAMSIZ);
19950Sstevel@tonic-gate dblock.dbuf.name[NAMSIZ-1]
19960Sstevel@tonic-gate = '/';
19970Sstevel@tonic-gate } else
19980Sstevel@tonic-gate (void) sprintf(dblock.dbuf.name,
19990Sstevel@tonic-gate "%s/", name);
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate /*
20020Sstevel@tonic-gate * need to recalculate checksum
20030Sstevel@tonic-gate * because the name changed.
20040Sstevel@tonic-gate */
20050Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum,
20060Sstevel@tonic-gate "%07o", checksum(&dblock));
20070Sstevel@tonic-gate }
20080Sstevel@tonic-gate }
20090Sstevel@tonic-gate
20105331Samw if (put_extra_attributes(longname, shortname,
20115331Samw longattrname, prefix, filetype, '5') != 0)
20120Sstevel@tonic-gate goto out;
20130Sstevel@tonic-gate
20140Sstevel@tonic-gate #if defined(O_XATTR)
20150Sstevel@tonic-gate /*
20160Sstevel@tonic-gate * Reset header typeflag when archiving directory, since
20170Sstevel@tonic-gate * build_dblock changed it on us.
20180Sstevel@tonic-gate */
20190Sstevel@tonic-gate if (filetype == XATTR_FILE) {
20200Sstevel@tonic-gate dblock.dbuf.typeflag = _XATTR_HDRTYPE;
20210Sstevel@tonic-gate } else {
20220Sstevel@tonic-gate dblock.dbuf.typeflag = '5';
20230Sstevel@tonic-gate }
20240Sstevel@tonic-gate #else
20250Sstevel@tonic-gate dblock.dbuf.typeflag = '5';
20260Sstevel@tonic-gate #endif
20270Sstevel@tonic-gate
20280Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o",
20290Sstevel@tonic-gate checksum(&dblock));
20300Sstevel@tonic-gate
20310Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1);
20320Sstevel@tonic-gate }
20330Sstevel@tonic-gate if (vflag) {
20340Sstevel@tonic-gate #ifdef DEBUG
20350Sstevel@tonic-gate if (NotTape)
20360Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
20370Sstevel@tonic-gate 0);
20380Sstevel@tonic-gate #endif
20390Sstevel@tonic-gate if (filetype == XATTR_FILE && Hiddendir) {
204012305Srich.burridge@sun.com (void) fprintf(vfile,
204112305Srich.burridge@sun.com gettext("a %s attribute %s "),
20425331Samw longname, longattrname);
20430Sstevel@tonic-gate
20440Sstevel@tonic-gate } else {
20450Sstevel@tonic-gate (void) fprintf(vfile, "a %s/ ", longname);
20460Sstevel@tonic-gate }
20470Sstevel@tonic-gate if (NotTape)
20480Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
20490Sstevel@tonic-gate K(blocks));
20500Sstevel@tonic-gate else
20510Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
20520Sstevel@tonic-gate " tape blocks\n"), blocks);
20530Sstevel@tonic-gate }
20540Sstevel@tonic-gate
20550Sstevel@tonic-gate /*
20560Sstevel@tonic-gate * If hidden dir then break now since xattrs_put() will do
20570Sstevel@tonic-gate * the iterating of the directory.
20580Sstevel@tonic-gate *
20595331Samw * At the moment, there can only be system attributes on
20605331Samw * attributes. There can be no attributes on attributes or
20615331Samw * directories within the attributes hidden directory hierarchy.
20620Sstevel@tonic-gate */
20630Sstevel@tonic-gate if (filetype == XATTR_FILE)
20640Sstevel@tonic-gate break;
20650Sstevel@tonic-gate
20660Sstevel@tonic-gate if (*shortname != '/')
20670Sstevel@tonic-gate (void) sprintf(newparent, "%s/%s", parent, shortname);
20680Sstevel@tonic-gate else
20690Sstevel@tonic-gate (void) sprintf(newparent, "%s", shortname);
20700Sstevel@tonic-gate
207112554Srich.burridge@oracle.com if (tar_chdir(shortname) < 0) {
20720Sstevel@tonic-gate vperror(0, "%s", newparent);
20730Sstevel@tonic-gate goto out;
20740Sstevel@tonic-gate }
20750Sstevel@tonic-gate
20760Sstevel@tonic-gate if ((dirp = opendir(".")) == NULL) {
20770Sstevel@tonic-gate vperror(0, gettext(
20785331Samw "can't open directory %s"), longname);
207912554Srich.burridge@oracle.com if (tar_chdir(parent) < 0)
20800Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"),
20810Sstevel@tonic-gate parent);
20820Sstevel@tonic-gate goto out;
20830Sstevel@tonic-gate }
20840Sstevel@tonic-gate
20856525Sceastha /*
20866525Sceastha * Create a list of files (children) in this directory to avoid
20876525Sceastha * having to perform telldir()/seekdir().
20886525Sceastha */
20890Sstevel@tonic-gate while ((dp = readdir(dirp)) != NULL && !term) {
20900Sstevel@tonic-gate if ((strcmp(".", dp->d_name) == 0) ||
20910Sstevel@tonic-gate (strcmp("..", dp->d_name) == 0))
20920Sstevel@tonic-gate continue;
20936525Sceastha if (((cptr = (file_list_t *)calloc(sizeof (char),
20946525Sceastha sizeof (file_list_t))) == NULL) ||
20956525Sceastha ((cptr->name = strdup(dp->d_name)) == NULL)) {
20966525Sceastha vperror(1, gettext(
20976525Sceastha "Insufficient memory for directory "
20986525Sceastha "list entry %s/%s\n"),
20996525Sceastha newparent, dp->d_name);
21006525Sceastha }
21016525Sceastha
21026525Sceastha /* Add the file to the list */
21036525Sceastha if (child == NULL) {
21046525Sceastha child = cptr;
21056525Sceastha } else {
21066525Sceastha child_end->next = cptr;
21076525Sceastha }
21086525Sceastha child_end = cptr;
21096525Sceastha }
21106525Sceastha (void) closedir(dirp);
21116525Sceastha
21126525Sceastha /*
21136525Sceastha * Archive each of the files in the current directory.
21146525Sceastha * If a file is a directory, putfile() is called
21156525Sceastha * recursively to archive the file hierarchy of the
21166525Sceastha * directory before archiving the next file in the
21176525Sceastha * current directory.
21186525Sceastha */
21196525Sceastha while ((child != NULL) && !term) {
21206525Sceastha (void) strcpy(cp, child->name);
21215331Samw archtype = putfile(buf, cp, newparent, NULL,
21220Sstevel@tonic-gate NORMAL_FILE, lev + 1, symlink_lev);
21230Sstevel@tonic-gate
21240Sstevel@tonic-gate if (!exitflag) {
21255331Samw if ((atflag || saflag) &&
21265331Samw (archtype == PUT_NOTAS_LINK)) {
21275331Samw xattrs_put(buf, cp, newparent, NULL);
21280Sstevel@tonic-gate }
21290Sstevel@tonic-gate }
21300Sstevel@tonic-gate if (exitflag)
21310Sstevel@tonic-gate break;
21320Sstevel@tonic-gate
21336525Sceastha /* Free each child as we are done processing it. */
21346525Sceastha cptr = child;
21356525Sceastha child = child->next;
21366525Sceastha free(cptr->name);
21376525Sceastha free(cptr);
21386525Sceastha }
21396525Sceastha if ((child != NULL) && !term) {
21406525Sceastha free_children(child);
21416525Sceastha }
21420Sstevel@tonic-gate
214312554Srich.burridge@oracle.com if (tar_chdir(parent) < 0) {
21440Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"), parent);
21450Sstevel@tonic-gate }
21460Sstevel@tonic-gate
21470Sstevel@tonic-gate break;
21480Sstevel@tonic-gate
21490Sstevel@tonic-gate case S_IFLNK:
21500Sstevel@tonic-gate readlink_max = NAMSIZ;
21510Sstevel@tonic-gate if (stbuf.st_size > NAMSIZ) {
21520Sstevel@tonic-gate if (Eflag > 0) {
21530Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH;
21540Sstevel@tonic-gate readlink_max = PATH_MAX;
21550Sstevel@tonic-gate } else {
21560Sstevel@tonic-gate (void) fprintf(stderr, gettext(
21570Sstevel@tonic-gate "tar: %s: symbolic link too long\n"),
21580Sstevel@tonic-gate longname);
21590Sstevel@tonic-gate if (errflag)
21600Sstevel@tonic-gate exitflag = 1;
21610Sstevel@tonic-gate Errflg = 1;
21620Sstevel@tonic-gate goto out;
21630Sstevel@tonic-gate }
21640Sstevel@tonic-gate }
21650Sstevel@tonic-gate /*
21660Sstevel@tonic-gate * Sym-links need header size of zero since you
21670Sstevel@tonic-gate * don't store any data for this type.
21680Sstevel@tonic-gate */
21690Sstevel@tonic-gate stbuf.st_size = (off_t)0;
21700Sstevel@tonic-gate tomodes(&stbuf);
21710Sstevel@tonic-gate i = readlink(shortname, filetmp, readlink_max);
21720Sstevel@tonic-gate if (i < 0) {
21730Sstevel@tonic-gate vperror(0, gettext(
21740Sstevel@tonic-gate "can't read symbolic link %s"), longname);
21750Sstevel@tonic-gate goto out;
21760Sstevel@tonic-gate } else {
21770Sstevel@tonic-gate filetmp[i] = 0;
21780Sstevel@tonic-gate }
21790Sstevel@tonic-gate if (vflag)
21800Sstevel@tonic-gate (void) fprintf(vfile, gettext(
21810Sstevel@tonic-gate "a %s symbolic link to %s\n"),
21820Sstevel@tonic-gate longname, filetmp);
21830Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) {
21840Sstevel@tonic-gate Xtarhdr.x_linkpath = filetmp;
21850Sstevel@tonic-gate if (build_dblock(name, tchar, '2', filetype, &stbuf,
21860Sstevel@tonic-gate stbuf.st_dev, prefix) != 0)
21870Sstevel@tonic-gate goto out;
21880Sstevel@tonic-gate } else
21890Sstevel@tonic-gate if (build_dblock(name, filetmp, '2', filetype, &stbuf,
21900Sstevel@tonic-gate stbuf.st_dev, prefix) != 0)
21910Sstevel@tonic-gate goto out;
21920Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1);
21930Sstevel@tonic-gate /*
21940Sstevel@tonic-gate * No acls for symlinks: mode is always 777
21950Sstevel@tonic-gate * dont call write ancillary
21960Sstevel@tonic-gate */
21970Sstevel@tonic-gate rc = PUT_AS_LINK;
21980Sstevel@tonic-gate break;
21990Sstevel@tonic-gate case S_IFREG:
22000Sstevel@tonic-gate if ((infile = openat(dirfd, shortname, 0)) < 0) {
220112305Srich.burridge@sun.com vperror(0, gettext("unable to open %s%s%s%s"), longname,
22025331Samw rw_sysattr ? gettext(" system") : "",
22030Sstevel@tonic-gate (filetype == XATTR_FILE) ?
22040Sstevel@tonic-gate gettext(" attribute ") : "",
22055331Samw (filetype == XATTR_FILE) ? (longattrname == NULL) ?
22065331Samw shortname : longattrname : "");
22070Sstevel@tonic-gate goto out;
22080Sstevel@tonic-gate }
22090Sstevel@tonic-gate
22100Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size);
22110Sstevel@tonic-gate
22125331Samw if (put_link(name, longname, shortname, longattrname,
22130Sstevel@tonic-gate prefix, filetype, '1') == 0) {
22140Sstevel@tonic-gate (void) close(infile);
22150Sstevel@tonic-gate rc = PUT_AS_LINK;
22160Sstevel@tonic-gate goto out;
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate
22190Sstevel@tonic-gate tomodes(&stbuf);
22200Sstevel@tonic-gate
22210Sstevel@tonic-gate /* correctly handle end of volume */
22220Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) {
22230Sstevel@tonic-gate /* split if floppy has some room and file is large */
22240Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) &&
22250Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) {
22260Sstevel@tonic-gate splitfile(longname, infile,
22270Sstevel@tonic-gate name, prefix, filetype);
22280Sstevel@tonic-gate (void) close(dirfd);
22290Sstevel@tonic-gate (void) close(infile);
22300Sstevel@tonic-gate goto out;
22310Sstevel@tonic-gate }
22320Sstevel@tonic-gate newvol(); /* not worth it--just get new volume */
22330Sstevel@tonic-gate }
22340Sstevel@tonic-gate #ifdef DEBUG
22350Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
22360Sstevel@tonic-gate blocks);
22370Sstevel@tonic-gate #endif
22380Sstevel@tonic-gate if (build_dblock(name, tchar, '0', filetype,
22390Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) {
22400Sstevel@tonic-gate goto out;
22410Sstevel@tonic-gate }
22420Sstevel@tonic-gate if (vflag) {
22430Sstevel@tonic-gate #ifdef DEBUG
22440Sstevel@tonic-gate if (NotTape)
22450Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
22460Sstevel@tonic-gate 0);
22470Sstevel@tonic-gate #endif
22485331Samw (void) fprintf(vfile, "a %s%s%s%s ", longname,
22495331Samw rw_sysattr ? gettext(" system") : "",
22505331Samw (filetype == XATTR_FILE) ? gettext(
22515331Samw " attribute ") : "",
22520Sstevel@tonic-gate (filetype == XATTR_FILE) ?
22535331Samw longattrname : "");
22540Sstevel@tonic-gate if (NotTape)
22550Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
22560Sstevel@tonic-gate K(blocks));
22570Sstevel@tonic-gate else
22580Sstevel@tonic-gate (void) fprintf(vfile,
22590Sstevel@tonic-gate gettext("%" FMT_blkcnt_t " tape blocks\n"),
22600Sstevel@tonic-gate blocks);
22610Sstevel@tonic-gate }
22620Sstevel@tonic-gate
22635331Samw if (put_extra_attributes(longname, shortname, longattrname,
22645331Samw prefix, filetype, '0') != 0)
22650Sstevel@tonic-gate goto out;
22660Sstevel@tonic-gate
22670Sstevel@tonic-gate /*
22680Sstevel@tonic-gate * No need to reset typeflag for extended attribute here, since
22690Sstevel@tonic-gate * put_extra_attributes already set it and we haven't called
22700Sstevel@tonic-gate * build_dblock().
22710Sstevel@tonic-gate */
22720Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
22730Sstevel@tonic-gate hint = writetbuf((char *)&dblock, 1);
22741266Sceastha maxread = max(min(stbuf.st_blksize, stbuf.st_size),
22751266Sceastha (nblock * TBLOCK));
22760Sstevel@tonic-gate if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
22770Sstevel@tonic-gate maxread = TBLOCK;
22780Sstevel@tonic-gate bigbuf = buf;
22790Sstevel@tonic-gate }
22800Sstevel@tonic-gate
22810Sstevel@tonic-gate while (((i = (int)
22820Sstevel@tonic-gate read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
22830Sstevel@tonic-gate blocks) {
22840Sstevel@tonic-gate blkcnt_t nblks;
22850Sstevel@tonic-gate
22860Sstevel@tonic-gate nblks = ((i-1)/TBLOCK)+1;
22870Sstevel@tonic-gate if (nblks > blocks)
22880Sstevel@tonic-gate nblks = blocks;
22890Sstevel@tonic-gate hint = writetbuf(bigbuf, nblks);
22900Sstevel@tonic-gate blocks -= nblks;
22910Sstevel@tonic-gate }
22920Sstevel@tonic-gate (void) close(infile);
22930Sstevel@tonic-gate if (bigbuf != buf)
22940Sstevel@tonic-gate free(bigbuf);
22950Sstevel@tonic-gate if (i < 0)
22960Sstevel@tonic-gate vperror(0, gettext("Read error on %s"), longname);
22970Sstevel@tonic-gate else if (blocks != 0 || i != 0) {
22980Sstevel@tonic-gate (void) fprintf(stderr, gettext(
22990Sstevel@tonic-gate "tar: %s: file changed size\n"), longname);
23000Sstevel@tonic-gate if (errflag) {
23010Sstevel@tonic-gate exitflag = 1;
23020Sstevel@tonic-gate Errflg = 1;
23030Sstevel@tonic-gate } else if (!Dflag) {
23040Sstevel@tonic-gate Errflg = 1;
23050Sstevel@tonic-gate }
23060Sstevel@tonic-gate }
23070Sstevel@tonic-gate putempty(blocks);
23080Sstevel@tonic-gate break;
23090Sstevel@tonic-gate case S_IFIFO:
23100Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size);
23110Sstevel@tonic-gate stbuf.st_size = (off_t)0;
23120Sstevel@tonic-gate
23135331Samw if (put_link(name, longname, shortname, longattrname,
23140Sstevel@tonic-gate prefix, filetype, '6') == 0) {
23150Sstevel@tonic-gate rc = PUT_AS_LINK;
23160Sstevel@tonic-gate goto out;
23170Sstevel@tonic-gate }
23180Sstevel@tonic-gate tomodes(&stbuf);
23190Sstevel@tonic-gate
23200Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) {
23210Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) &&
23220Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) {
23230Sstevel@tonic-gate splitfile(longname, infile, name,
23240Sstevel@tonic-gate prefix, filetype);
23250Sstevel@tonic-gate (void) close(dirfd);
23260Sstevel@tonic-gate (void) close(infile);
23270Sstevel@tonic-gate goto out;
23280Sstevel@tonic-gate }
23290Sstevel@tonic-gate newvol();
23300Sstevel@tonic-gate }
23310Sstevel@tonic-gate #ifdef DEBUG
23320Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
23330Sstevel@tonic-gate blocks);
23340Sstevel@tonic-gate #endif
23350Sstevel@tonic-gate if (vflag) {
23360Sstevel@tonic-gate #ifdef DEBUG
23370Sstevel@tonic-gate if (NotTape)
23380Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
23390Sstevel@tonic-gate 0);
23400Sstevel@tonic-gate #endif
23410Sstevel@tonic-gate if (NotTape)
23420Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %"
23430Sstevel@tonic-gate FMT_blkcnt_t "K\n "), longname, K(blocks));
23440Sstevel@tonic-gate else
23450Sstevel@tonic-gate (void) fprintf(vfile, gettext(
23460Sstevel@tonic-gate "a %s %" FMT_blkcnt_t " tape blocks\n"),
23470Sstevel@tonic-gate longname, blocks);
23480Sstevel@tonic-gate }
23490Sstevel@tonic-gate if (build_dblock(name, tchar, '6', filetype,
23500Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0)
23510Sstevel@tonic-gate goto out;
23520Sstevel@tonic-gate
23535331Samw if (put_extra_attributes(longname, shortname, longattrname,
23545331Samw prefix, filetype, '6') != 0)
23550Sstevel@tonic-gate goto out;
23560Sstevel@tonic-gate
23570Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
23580Sstevel@tonic-gate dblock.dbuf.typeflag = '6';
23590Sstevel@tonic-gate
23600Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1);
23610Sstevel@tonic-gate break;
23620Sstevel@tonic-gate case S_IFCHR:
23630Sstevel@tonic-gate stbuf.st_size = (off_t)0;
23640Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size);
23655331Samw if (put_link(name, longname, shortname, longattrname,
23665331Samw prefix, filetype, '3') == 0) {
23670Sstevel@tonic-gate rc = PUT_AS_LINK;
23680Sstevel@tonic-gate goto out;
23690Sstevel@tonic-gate }
23700Sstevel@tonic-gate tomodes(&stbuf);
23710Sstevel@tonic-gate
23720Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) {
23730Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) &&
23740Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) {
23750Sstevel@tonic-gate splitfile(longname, infile, name,
23760Sstevel@tonic-gate prefix, filetype);
23770Sstevel@tonic-gate (void) close(dirfd);
23780Sstevel@tonic-gate goto out;
23790Sstevel@tonic-gate }
23800Sstevel@tonic-gate newvol();
23810Sstevel@tonic-gate }
23820Sstevel@tonic-gate #ifdef DEBUG
23830Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
23840Sstevel@tonic-gate blocks);
23850Sstevel@tonic-gate #endif
23860Sstevel@tonic-gate if (vflag) {
23870Sstevel@tonic-gate #ifdef DEBUG
23880Sstevel@tonic-gate if (NotTape)
23890Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
23900Sstevel@tonic-gate 0);
23910Sstevel@tonic-gate #endif
23920Sstevel@tonic-gate if (NotTape)
23930Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %"
23940Sstevel@tonic-gate FMT_blkcnt_t "K\n"), longname, K(blocks));
23950Sstevel@tonic-gate else
23960Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %"
23970Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), longname,
23980Sstevel@tonic-gate blocks);
23990Sstevel@tonic-gate }
24000Sstevel@tonic-gate if (build_dblock(name, tchar, '3',
24010Sstevel@tonic-gate filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
24020Sstevel@tonic-gate goto out;
24030Sstevel@tonic-gate
24045331Samw if (put_extra_attributes(longname, shortname, longattrname,
24050Sstevel@tonic-gate prefix, filetype, '3') != 0)
24060Sstevel@tonic-gate goto out;
24070Sstevel@tonic-gate
24080Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
24090Sstevel@tonic-gate dblock.dbuf.typeflag = '3';
24100Sstevel@tonic-gate
24110Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1);
24120Sstevel@tonic-gate break;
24130Sstevel@tonic-gate case S_IFBLK:
24140Sstevel@tonic-gate stbuf.st_size = (off_t)0;
24150Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size);
24165331Samw if (put_link(name, longname, shortname, longattrname,
24175331Samw prefix, filetype, '4') == 0) {
24180Sstevel@tonic-gate rc = PUT_AS_LINK;
24190Sstevel@tonic-gate goto out;
24200Sstevel@tonic-gate }
24210Sstevel@tonic-gate tomodes(&stbuf);
24220Sstevel@tonic-gate
24230Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) {
24240Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) &&
24250Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) {
24260Sstevel@tonic-gate splitfile(longname, infile,
24270Sstevel@tonic-gate name, prefix, filetype);
24280Sstevel@tonic-gate (void) close(dirfd);
24290Sstevel@tonic-gate goto out;
24300Sstevel@tonic-gate }
24310Sstevel@tonic-gate newvol();
24320Sstevel@tonic-gate }
24330Sstevel@tonic-gate #ifdef DEBUG
24340Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
24350Sstevel@tonic-gate blocks);
24360Sstevel@tonic-gate #endif
24370Sstevel@tonic-gate if (vflag) {
24380Sstevel@tonic-gate #ifdef DEBUG
24390Sstevel@tonic-gate if (NotTape)
24400Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
24410Sstevel@tonic-gate 0);
24420Sstevel@tonic-gate #endif
24430Sstevel@tonic-gate (void) fprintf(vfile, "a %s ", longname);
24440Sstevel@tonic-gate if (NotTape)
24450Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
24460Sstevel@tonic-gate K(blocks));
24470Sstevel@tonic-gate else
24480Sstevel@tonic-gate (void) fprintf(vfile, gettext("%"
24490Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), blocks);
24500Sstevel@tonic-gate }
24510Sstevel@tonic-gate if (build_dblock(name, tchar, '4',
24520Sstevel@tonic-gate filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
24530Sstevel@tonic-gate goto out;
24540Sstevel@tonic-gate
24555331Samw if (put_extra_attributes(longname, shortname, longattrname,
24560Sstevel@tonic-gate prefix, filetype, '4') != 0)
24570Sstevel@tonic-gate goto out;
24580Sstevel@tonic-gate
24590Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
24600Sstevel@tonic-gate dblock.dbuf.typeflag = '4';
24610Sstevel@tonic-gate
24620Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1);
24630Sstevel@tonic-gate break;
24640Sstevel@tonic-gate default:
24650Sstevel@tonic-gate (void) fprintf(stderr, gettext(
24660Sstevel@tonic-gate "tar: %s is not a file. Not dumped\n"), longname);
24670Sstevel@tonic-gate if (errflag)
24680Sstevel@tonic-gate exitflag = 1;
24690Sstevel@tonic-gate Errflg = 1;
24700Sstevel@tonic-gate goto out;
24710Sstevel@tonic-gate }
24720Sstevel@tonic-gate
24730Sstevel@tonic-gate out:
24745331Samw if ((dirfd != -1) && (filetype != XATTR_FILE)) {
24750Sstevel@tonic-gate (void) close(dirfd);
24760Sstevel@tonic-gate }
24770Sstevel@tonic-gate return (rc);
24780Sstevel@tonic-gate }
24790Sstevel@tonic-gate
24800Sstevel@tonic-gate
24810Sstevel@tonic-gate /*
24820Sstevel@tonic-gate * splitfile dump a large file across volumes
24830Sstevel@tonic-gate *
24840Sstevel@tonic-gate * splitfile(longname, fd);
24850Sstevel@tonic-gate * char *longname; full name of file
24860Sstevel@tonic-gate * int ifd; input file descriptor
24870Sstevel@tonic-gate *
24880Sstevel@tonic-gate * NOTE: only called by putfile() to dump a large file.
24890Sstevel@tonic-gate */
24900Sstevel@tonic-gate
24910Sstevel@tonic-gate static void
splitfile(char * longname,int ifd,char * name,char * prefix,int filetype)24920Sstevel@tonic-gate splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
24930Sstevel@tonic-gate {
24940Sstevel@tonic-gate blkcnt_t blocks;
24950Sstevel@tonic-gate off_t bytes, s;
24960Sstevel@tonic-gate char buf[TBLOCK];
24970Sstevel@tonic-gate int i, extents;
24980Sstevel@tonic-gate
24990Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
25000Sstevel@tonic-gate
25010Sstevel@tonic-gate /*
25020Sstevel@tonic-gate * # extents =
25030Sstevel@tonic-gate * size of file after using up rest of this floppy
25040Sstevel@tonic-gate * blocks - (blocklim - tapepos) + 1 (for header)
25050Sstevel@tonic-gate * plus roundup value before divide by blocklim-1
25060Sstevel@tonic-gate * + (blocklim - 1) - 1
25070Sstevel@tonic-gate * all divided by blocklim-1 (one block for each header).
25080Sstevel@tonic-gate * this gives
25090Sstevel@tonic-gate * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
25100Sstevel@tonic-gate * which reduces to the expression used.
25110Sstevel@tonic-gate * one is added to account for this first extent.
25120Sstevel@tonic-gate *
25130Sstevel@tonic-gate * When one is dealing with extremely large archives, one may want
25140Sstevel@tonic-gate * to allow for a large number of extents. This code should be
25150Sstevel@tonic-gate * revisited to determine if extents should be changed to something
25160Sstevel@tonic-gate * larger than an int.
25170Sstevel@tonic-gate */
25180Sstevel@tonic-gate extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
25190Sstevel@tonic-gate
25200Sstevel@tonic-gate if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
25210Sstevel@tonic-gate (void) fprintf(stderr, gettext(
25220Sstevel@tonic-gate "tar: %s needs unusual number of volumes to split\n"
25230Sstevel@tonic-gate "tar: %s not dumped\n"), longname, longname);
25240Sstevel@tonic-gate return;
25250Sstevel@tonic-gate }
25260Sstevel@tonic-gate if (build_dblock(name, tchar, '0', filetype,
25270Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0)
25280Sstevel@tonic-gate return;
25290Sstevel@tonic-gate
25300Sstevel@tonic-gate dblock.dbuf.extotal = extents;
25310Sstevel@tonic-gate bytes = stbuf.st_size;
25320Sstevel@tonic-gate
25330Sstevel@tonic-gate /*
25340Sstevel@tonic-gate * The value contained in dblock.dbuf.efsize was formerly used when the
25350Sstevel@tonic-gate * v flag was specified in conjunction with the t flag. Although it is
25360Sstevel@tonic-gate * no longer used, older versions of tar will expect the former
25370Sstevel@tonic-gate * behaviour, so we must continue to write it to the archive.
25380Sstevel@tonic-gate *
25390Sstevel@tonic-gate * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
25400Sstevel@tonic-gate * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
25410Sstevel@tonic-gate * store 0.
25420Sstevel@tonic-gate */
25430Sstevel@tonic-gate if (bytes <= TAR_EFSIZE_MAX)
25440Sstevel@tonic-gate (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
25450Sstevel@tonic-gate else
25460Sstevel@tonic-gate (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
25470Sstevel@tonic-gate
25480Sstevel@tonic-gate (void) fprintf(stderr, gettext(
25490Sstevel@tonic-gate "tar: large file %s needs %d extents.\n"
25500Sstevel@tonic-gate "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
25510Sstevel@tonic-gate longname, extents, K(tapepos));
25520Sstevel@tonic-gate
25530Sstevel@tonic-gate s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
25540Sstevel@tonic-gate for (i = 1; i <= extents; i++) {
25550Sstevel@tonic-gate if (i > 1) {
25560Sstevel@tonic-gate newvol();
25570Sstevel@tonic-gate if (i == extents)
25580Sstevel@tonic-gate s = bytes; /* last ext. gets true bytes */
25590Sstevel@tonic-gate else
25600Sstevel@tonic-gate s = (off_t)(blocklim - 1)*TBLOCK; /* all */
25610Sstevel@tonic-gate }
25620Sstevel@tonic-gate bytes -= s;
25630Sstevel@tonic-gate blocks = TBLOCKS(s);
25640Sstevel@tonic-gate
25650Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
25660Sstevel@tonic-gate dblock.dbuf.extno = i;
25670Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
25680Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1);
25690Sstevel@tonic-gate
25700Sstevel@tonic-gate if (vflag)
25710Sstevel@tonic-gate (void) fprintf(vfile,
257212305Srich.burridge@sun.com gettext("+++ a %s %" FMT_blkcnt_t
257312305Srich.burridge@sun.com "K [extent #%d of %d]\n"),
25740Sstevel@tonic-gate longname, K(blocks), i, extents);
25750Sstevel@tonic-gate while (blocks && read(ifd, buf, TBLOCK) > 0) {
25760Sstevel@tonic-gate blocks--;
25770Sstevel@tonic-gate (void) writetbuf(buf, 1);
25780Sstevel@tonic-gate }
25790Sstevel@tonic-gate if (blocks != 0) {
25800Sstevel@tonic-gate (void) fprintf(stderr, gettext(
25810Sstevel@tonic-gate "tar: %s: file changed size\n"), longname);
25820Sstevel@tonic-gate (void) fprintf(stderr, gettext(
25830Sstevel@tonic-gate "tar: aborting split file %s\n"), longname);
25840Sstevel@tonic-gate (void) close(ifd);
25850Sstevel@tonic-gate return;
25860Sstevel@tonic-gate }
25870Sstevel@tonic-gate }
25880Sstevel@tonic-gate (void) close(ifd);
25890Sstevel@tonic-gate if (vflag)
25900Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
25910Sstevel@tonic-gate "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
25920Sstevel@tonic-gate extents);
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate
25950Sstevel@tonic-gate /*
25960Sstevel@tonic-gate * convtoreg - determines whether the file should be converted to a
25970Sstevel@tonic-gate * regular file when extracted
25980Sstevel@tonic-gate *
25990Sstevel@tonic-gate * Returns 1 when file size > 0 and typeflag is not recognized
26000Sstevel@tonic-gate * Otherwise returns 0
26010Sstevel@tonic-gate */
26020Sstevel@tonic-gate static int
convtoreg(off_t size)26030Sstevel@tonic-gate convtoreg(off_t size)
26040Sstevel@tonic-gate {
26050Sstevel@tonic-gate if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
26060Sstevel@tonic-gate (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') &&
26070Sstevel@tonic-gate (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
26080Sstevel@tonic-gate (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
26090Sstevel@tonic-gate (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
261011995Srich.burridge@sun.com (dblock.dbuf.typeflag != 'L') &&
26110Sstevel@tonic-gate (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
26120Sstevel@tonic-gate (dblock.dbuf.typeflag != 'X')) {
26130Sstevel@tonic-gate return (1);
26140Sstevel@tonic-gate }
26150Sstevel@tonic-gate return (0);
26160Sstevel@tonic-gate }
26170Sstevel@tonic-gate
26185331Samw #if defined(O_XATTR)
26195331Samw static int
save_cwd(void)26205331Samw save_cwd(void)
26215331Samw {
26225331Samw return (open(".", O_RDONLY));
26235331Samw }
26245331Samw #endif
26255331Samw
26265331Samw #if defined(O_XATTR)
26275331Samw static void
rest_cwd(int * cwd)26285331Samw rest_cwd(int *cwd)
26295331Samw {
26305331Samw if (*cwd != -1) {
26315331Samw if (fchdir(*cwd) < 0) {
26325331Samw vperror(0, gettext(
26335331Samw "Cannot fchdir to attribute directory"));
26345331Samw exit(1);
26355331Samw }
26365331Samw (void) close(*cwd);
26375331Samw *cwd = -1;
26385331Samw }
26395331Samw }
26405331Samw #endif
26415331Samw
26425331Samw /*
26435331Samw * Verify the underlying file system supports the attribute type.
26445331Samw * Only archive extended attribute files when '-@' was specified.
26455331Samw * Only archive system extended attribute files if '-/' was specified.
26465331Samw */
26475331Samw #if defined(O_XATTR)
26485331Samw static attr_status_t
verify_attr_support(char * filename,int attrflg,arc_action_t actflag,int * ext_attrflg)26495750Sceastha verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
26505750Sceastha int *ext_attrflg)
26515331Samw {
26525331Samw /*
26535750Sceastha * Verify extended attributes are supported/exist. We only
26545750Sceastha * need to check if we are processing a base file, not an
26555750Sceastha * extended attribute.
26565331Samw */
26575750Sceastha if (attrflg) {
26585750Sceastha *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
26595750Sceastha _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
26605750Sceastha }
26615750Sceastha
26625331Samw if (atflag) {
26635750Sceastha if (!*ext_attrflg) {
26645331Samw #if defined(_PC_SATTR_ENABLED)
26655331Samw if (saflag) {
26665331Samw /* Verify system attributes are supported */
26675331Samw if (sysattr_support(filename,
26685331Samw (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
26695331Samw _PC_SATTR_ENABLED) != 1) {
26705331Samw return (ATTR_SATTR_ERR);
26715331Samw }
26725331Samw } else
26735331Samw return (ATTR_XATTR_ERR);
26745331Samw #else
26755331Samw return (ATTR_XATTR_ERR);
26765331Samw #endif /* _PC_SATTR_ENABLED */
26775331Samw }
26785331Samw
26795331Samw #if defined(_PC_SATTR_ENABLED)
26805331Samw } else if (saflag) {
26815331Samw /* Verify system attributes are supported */
26825331Samw if (sysattr_support(filename, (actflag == ARC_CREATE) ?
26835331Samw _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
26845331Samw return (ATTR_SATTR_ERR);
26855331Samw }
26865331Samw #endif /* _PC_SATTR_ENABLED */
26875331Samw } else {
26885331Samw return (ATTR_SKIP);
26895331Samw }
26905331Samw
26915331Samw return (ATTR_OK);
26925331Samw }
26935331Samw #endif
26945331Samw
26955331Samw #if defined(O_XATTR)
26965331Samw /*
26975331Samw * Recursively open attribute directories until the attribute directory
26985331Samw * containing the specified attribute, attrname, is opened.
26995331Samw *
27005331Samw * Currently, only 2 directory levels of attributes are supported, (i.e.,
27015331Samw * extended system attributes on extended attributes). The following are
27025331Samw * the possible input combinations:
27035331Samw * 1. Open the attribute directory of the base file (don't change
27045331Samw * into it).
27055331Samw * attrinfo->parent = NULL
27065331Samw * attrname = '.'
27075331Samw * 2. Open the attribute directory of the base file and change into it.
27085331Samw * attrinfo->parent = NULL
27095331Samw * attrname = <attr> | <sys_attr>
27105331Samw * 3. Open the attribute directory of the base file, change into it,
27115331Samw * then recursively call open_attr_dir() to open the attribute's
27125331Samw * parent directory (don't change into it).
27135331Samw * attrinfo->parent = <attr>
27145331Samw * attrname = '.'
27155331Samw * 4. Open the attribute directory of the base file, change into it,
27165331Samw * then recursively call open_attr_dir() to open the attribute's
27175331Samw * parent directory and change into it.
27185331Samw * attrinfo->parent = <attr>
27195331Samw * attrname = <attr> | <sys_attr>
27205331Samw *
27215331Samw * An attribute directory will be opened only if the underlying file system
27225331Samw * supports the attribute type, and if the command line specifications (atflag
27235331Samw * and saflag) enable the processing of the attribute type.
27245331Samw *
27255331Samw * On succesful return, attrinfo->parentfd will be the file descriptor of the
27265331Samw * opened attribute directory. In addition, if the attribute is a read-write
27275331Samw * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
27285331Samw * it will be set to 0.
27295331Samw *
27305331Samw * Possible return values:
27315331Samw * ATTR_OK Successfully opened and, if needed, changed into the
27325331Samw * attribute directory containing attrname.
27335331Samw * ATTR_SKIP The command line specifications don't enable the
27345331Samw * processing of the attribute type.
27355331Samw * ATTR_CHDIR_ERR An error occurred while trying to change into an
27365331Samw * attribute directory.
27375331Samw * ATTR_OPEN_ERR An error occurred while trying to open an
27385331Samw * attribute directory.
27395331Samw * ATTR_XATTR_ERR The underlying file system doesn't support extended
27405331Samw * attributes.
27415331Samw * ATTR_SATTR_ERR The underlying file system doesn't support extended
27425331Samw * system attributes.
27435331Samw */
27445331Samw static int
open_attr_dir(char * attrname,char * dirp,int cwd,attr_data_t * attrinfo)27455331Samw open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
27465331Samw {
27475331Samw attr_status_t rc;
27485331Samw int firsttime = (attrinfo->attr_parentfd == -1);
27495331Samw int saveerrno;
27505750Sceastha int ext_attr;
27515331Samw
27525331Samw /*
27535331Samw * open_attr_dir() was recursively called (input combination number 4),
27545331Samw * close the previously opened file descriptor as we've already changed
27555331Samw * into it.
27565331Samw */
27575331Samw if (!firsttime) {
27585331Samw (void) close(attrinfo->attr_parentfd);
27595331Samw attrinfo->attr_parentfd = -1;
27605331Samw }
27615331Samw
27625331Samw /*
27635331Samw * Verify that the underlying file system supports the restoration
27645331Samw * of the attribute.
27655331Samw */
27665750Sceastha if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
27675750Sceastha &ext_attr)) != ATTR_OK) {
27685331Samw return (rc);
27695331Samw }
27705331Samw
27715331Samw /* Open the base file's attribute directory */
27725331Samw if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
27735331Samw /*
27745331Samw * Save the errno from the attropen so it can be reported
27755331Samw * if the retry of the attropen fails.
27765331Samw */
27775331Samw saveerrno = errno;
27785331Samw if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
27795331Samw NULL, ".", O_RDONLY, 0)) == -1) {
27805331Samw /*
27815331Samw * Reset typeflag back to real value so passtape
27825331Samw * will skip ahead correctly.
27835331Samw */
27845331Samw dblock.dbuf.typeflag = _XATTR_HDRTYPE;
27855331Samw (void) close(attrinfo->attr_parentfd);
27865331Samw attrinfo->attr_parentfd = -1;
27875331Samw errno = saveerrno;
27885331Samw return (ATTR_OPEN_ERR);
27895331Samw }
27905331Samw }
27915331Samw
27925331Samw /*
27935331Samw * Change into the parent attribute's directory unless we are
27945331Samw * processing the hidden attribute directory of the base file itself.
27955331Samw */
27965331Samw if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
27975331Samw if (fchdir(attrinfo->attr_parentfd) != 0) {
27985331Samw saveerrno = errno;
27995331Samw (void) close(attrinfo->attr_parentfd);
28005331Samw attrinfo->attr_parentfd = -1;
28015331Samw errno = saveerrno;
28025331Samw return (ATTR_CHDIR_ERR);
28035331Samw }
28045331Samw }
28055331Samw
28065331Samw /* Determine if the attribute should be processed */
28075331Samw if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
28085331Samw &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
28095331Samw saveerrno = errno;
28105331Samw (void) close(attrinfo->attr_parentfd);
28115331Samw attrinfo->attr_parentfd = -1;
28125331Samw errno = saveerrno;
28135331Samw return (rc);
28145331Samw }
28155331Samw
28165331Samw /*
28175331Samw * If the attribute is an extended attribute, or extended system
28185331Samw * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
28195331Samw * recursively call open_attr_dir() to open the attribute directory
28205331Samw * of the parent attribute.
28215331Samw */
28225331Samw if (firsttime && (attrinfo->attr_parent != NULL)) {
28235331Samw return (open_attr_dir(attrname, attrinfo->attr_parent,
28245331Samw attrinfo->attr_parentfd, attrinfo));
28255331Samw }
28265331Samw
28275331Samw return (ATTR_OK);
28285331Samw }
28295331Samw #endif
28305331Samw
28310Sstevel@tonic-gate static void
doxtract(char * argv[])28320Sstevel@tonic-gate doxtract(char *argv[])
28330Sstevel@tonic-gate {
28340Sstevel@tonic-gate struct stat xtractbuf; /* stat on file after extracting */
28350Sstevel@tonic-gate blkcnt_t blocks;
28360Sstevel@tonic-gate off_t bytes;
28370Sstevel@tonic-gate int ofile;
28380Sstevel@tonic-gate int newfile; /* Does the file already exist */
28390Sstevel@tonic-gate int xcnt = 0; /* count # files extracted */
28400Sstevel@tonic-gate int fcnt = 0; /* count # files in argv list */
28410Sstevel@tonic-gate int dir;
28420Sstevel@tonic-gate int dirfd = -1;
28435331Samw int cwd = -1;
28445750Sceastha int rw_sysattr;
28455331Samw int saveerrno;
28460Sstevel@tonic-gate uid_t Uid;
28470Sstevel@tonic-gate char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
28480Sstevel@tonic-gate char dirname[PATH_MAX+1];
28490Sstevel@tonic-gate char templink[PATH_MAX+1]; /* temp link with terminating NULL */
28500Sstevel@tonic-gate int once = 1;
28510Sstevel@tonic-gate int error;
28520Sstevel@tonic-gate int symflag;
28530Sstevel@tonic-gate int want;
28545331Samw attr_data_t *attrinfo = NULL; /* attribute info */
2855789Sahrens acl_t *aclp = NULL; /* acl info */
28561676Sjpk char dot[] = "."; /* dirp for using realpath */
28570Sstevel@tonic-gate timestruc_t time_zero; /* used for call to doDirTimes */
28580Sstevel@tonic-gate int dircreate;
28590Sstevel@tonic-gate int convflag;
28600Sstevel@tonic-gate time_zero.tv_sec = 0;
28610Sstevel@tonic-gate time_zero.tv_nsec = 0;
28620Sstevel@tonic-gate
28631676Sjpk /* reset Trusted Extensions variables */
28641676Sjpk rpath_flag = 0;
28651676Sjpk lk_rpath_flag = 0;
28661676Sjpk dir_flag = 0;
28671676Sjpk mld_flag = 0;
28681676Sjpk bslundef(&bs_label);
28691676Sjpk bsllow(&admin_low);
28701676Sjpk bslhigh(&admin_high);
28711676Sjpk orig_namep = 0;
28721676Sjpk
28730Sstevel@tonic-gate dumping = 0; /* for newvol(), et al: we are not writing */
28740Sstevel@tonic-gate
28750Sstevel@tonic-gate Uid = getuid();
28760Sstevel@tonic-gate
28770Sstevel@tonic-gate for (;;) {
28780Sstevel@tonic-gate convflag = 0;
28790Sstevel@tonic-gate symflag = 0;
28800Sstevel@tonic-gate dir = 0;
28815750Sceastha Hiddendir = 0;
28825750Sceastha rw_sysattr = 0;
28830Sstevel@tonic-gate ofile = -1;
28840Sstevel@tonic-gate
28855331Samw if (dirfd != -1) {
28865331Samw (void) close(dirfd);
28875331Samw dirfd = -1;
28885331Samw }
28895331Samw if (ofile != -1) {
28905331Samw if (close(ofile) != 0)
28915331Samw vperror(2, gettext("close error"));
28925331Samw }
28935331Samw
28945331Samw #if defined(O_XATTR)
28955331Samw if (cwd != -1) {
28965331Samw rest_cwd(&cwd);
28975331Samw }
28985331Samw #endif
28995331Samw
29000Sstevel@tonic-gate /* namep is set by wantit to point to the full name */
29015331Samw if ((want = wantit(argv, &namep, &dirp, &comp,
29025331Samw &attrinfo)) == 0) {
29030Sstevel@tonic-gate #if defined(O_XATTR)
29045331Samw if (xattrp != NULL) {
29050Sstevel@tonic-gate free(xattrhead);
29060Sstevel@tonic-gate xattrp = NULL;
29070Sstevel@tonic-gate xattr_linkp = NULL;
29080Sstevel@tonic-gate xattrhead = NULL;
29090Sstevel@tonic-gate }
29100Sstevel@tonic-gate #endif
29110Sstevel@tonic-gate continue;
29120Sstevel@tonic-gate }
29130Sstevel@tonic-gate if (want == -1)
29140Sstevel@tonic-gate break;
29150Sstevel@tonic-gate
29161676Sjpk /* Trusted Extensions */
29171676Sjpk /*
29181676Sjpk * During tar extract (x):
29191676Sjpk * If the pathname of the restored file has been
29201676Sjpk * reconstructed from the ancillary file,
29211676Sjpk * use it to process the normal file.
29221676Sjpk */
29231676Sjpk if (mld_flag) { /* Skip over .MLD. directory */
29241676Sjpk mld_flag = 0;
29251676Sjpk passtape();
29261676Sjpk continue;
29271676Sjpk }
29281676Sjpk orig_namep = namep; /* save original */
29291676Sjpk if (rpath_flag) {
29301676Sjpk namep = real_path; /* use zone path */
29311676Sjpk comp = real_path; /* use zone path */
29321676Sjpk dirp = dot; /* work from the top */
29331676Sjpk rpath_flag = 0; /* reset */
29341676Sjpk }
29351676Sjpk
29360Sstevel@tonic-gate if (dirfd != -1)
29370Sstevel@tonic-gate (void) close(dirfd);
29380Sstevel@tonic-gate
29390Sstevel@tonic-gate (void) strcpy(&dirname[0], namep);
29400Sstevel@tonic-gate dircreate = checkdir(&dirname[0]);
29410Sstevel@tonic-gate
29420Sstevel@tonic-gate #if defined(O_XATTR)
29435331Samw if (xattrp != NULL) {
29445331Samw int rc;
29455331Samw
29465331Samw if (((cwd = save_cwd()) == -1) ||
29475331Samw ((rc = open_attr_dir(comp, dirp, cwd,
29485331Samw attrinfo)) != ATTR_OK)) {
29495331Samw if (cwd == -1) {
29505331Samw vperror(0, gettext(
29515331Samw "unable to save current working "
29525331Samw "directory while processing "
29535331Samw "attribute %s of %s"),
29545331Samw dirp, attrinfo->attr_path);
29555331Samw } else if (rc != ATTR_SKIP) {
29565331Samw (void) fprintf(vfile,
29575331Samw gettext("tar: cannot open "
29585331Samw "%sattribute %s of file %s: %s\n"),
29595331Samw attrinfo->attr_rw_sysattr ? gettext(
29605331Samw "system ") : "",
29615331Samw comp, dirp, strerror(errno));
29625331Samw }
29635331Samw free(xattrhead);
29645331Samw xattrp = NULL;
29655331Samw xattr_linkp = NULL;
29665331Samw xattrhead = NULL;
29675331Samw
29685331Samw passtape();
29695331Samw continue;
29705331Samw } else {
29715331Samw dirfd = attrinfo->attr_parentfd;
29725331Samw rw_sysattr = attrinfo->attr_rw_sysattr;
29735331Samw }
29740Sstevel@tonic-gate } else {
29750Sstevel@tonic-gate dirfd = open(dirp, O_RDONLY);
29760Sstevel@tonic-gate }
29770Sstevel@tonic-gate #else
29780Sstevel@tonic-gate dirfd = open(dirp, O_RDONLY);
29790Sstevel@tonic-gate #endif
29800Sstevel@tonic-gate if (dirfd == -1) {
29815331Samw (void) fprintf(vfile, gettext(
29825331Samw "tar: cannot open %s: %s\n"),
29835331Samw dirp, strerror(errno));
29845331Samw passtape();
29855331Samw continue;
29860Sstevel@tonic-gate }
29870Sstevel@tonic-gate
29880Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH)
29890Sstevel@tonic-gate (void) strcpy(templink, Xtarhdr.x_linkpath);
29900Sstevel@tonic-gate else {
29910Sstevel@tonic-gate #if defined(O_XATTR)
29920Sstevel@tonic-gate if (xattrp && dblock.dbuf.typeflag == '1') {
29930Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ,
29940Sstevel@tonic-gate xattrp->h_names);
29950Sstevel@tonic-gate } else {
29960Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ,
29970Sstevel@tonic-gate dblock.dbuf.linkname);
29980Sstevel@tonic-gate }
29990Sstevel@tonic-gate #else
30000Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ,
30010Sstevel@tonic-gate dblock.dbuf.linkname);
30020Sstevel@tonic-gate #endif
30030Sstevel@tonic-gate }
30040Sstevel@tonic-gate
30050Sstevel@tonic-gate if (Fflag) {
300612423Srich.burridge@oracle.com if (checkf(namep, is_directory(namep), Fflag) == 0) {
30070Sstevel@tonic-gate passtape();
30080Sstevel@tonic-gate continue;
30090Sstevel@tonic-gate }
30100Sstevel@tonic-gate }
30110Sstevel@tonic-gate
30120Sstevel@tonic-gate if (checkw('x', namep) == 0) {
30130Sstevel@tonic-gate passtape();
30140Sstevel@tonic-gate continue;
30150Sstevel@tonic-gate }
30160Sstevel@tonic-gate if (once) {
30170Sstevel@tonic-gate if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
30180Sstevel@tonic-gate if (geteuid() == (uid_t)0) {
30190Sstevel@tonic-gate checkflag = 1;
30200Sstevel@tonic-gate pflag = 1;
30210Sstevel@tonic-gate } else {
30220Sstevel@tonic-gate /* get file creation mask */
30230Sstevel@tonic-gate Oumask = umask(0);
30240Sstevel@tonic-gate (void) umask(Oumask);
30250Sstevel@tonic-gate }
30260Sstevel@tonic-gate once = 0;
30270Sstevel@tonic-gate } else {
30280Sstevel@tonic-gate if (geteuid() == (uid_t)0) {
30290Sstevel@tonic-gate pflag = 1;
30300Sstevel@tonic-gate checkflag = 2;
30310Sstevel@tonic-gate }
30320Sstevel@tonic-gate if (!pflag) {
30330Sstevel@tonic-gate /* get file creation mask */
30340Sstevel@tonic-gate Oumask = umask(0);
30350Sstevel@tonic-gate (void) umask(Oumask);
30360Sstevel@tonic-gate }
30370Sstevel@tonic-gate once = 0;
30380Sstevel@tonic-gate }
30390Sstevel@tonic-gate }
30400Sstevel@tonic-gate
30410Sstevel@tonic-gate #if defined(O_XATTR)
30420Sstevel@tonic-gate /*
30430Sstevel@tonic-gate * Handle extraction of hidden attr dir.
30440Sstevel@tonic-gate * Dir is automatically created, we only
30450Sstevel@tonic-gate * need to update mode and perm's.
30460Sstevel@tonic-gate */
30475331Samw if ((xattrp != NULL) && Hiddendir == 1) {
30485331Samw bytes = stbuf.st_size;
30495331Samw blocks = TBLOCKS(bytes);
30505331Samw if (vflag) {
30515331Samw (void) fprintf(vfile,
305212305Srich.burridge@sun.com "x %s%s%s, %" FMT_off_t " %s, ", namep,
30535331Samw gettext(" attribute "),
305412305Srich.burridge@sun.com xattrapath, bytes,
305512305Srich.burridge@sun.com gettext("bytes"));
30565331Samw if (NotTape)
30575331Samw (void) fprintf(vfile,
30585331Samw "%" FMT_blkcnt_t "K\n", K(blocks));
30595331Samw else
30605331Samw (void) fprintf(vfile, gettext("%"
30615331Samw FMT_blkcnt_t " tape blocks\n"),
30625331Samw blocks);
30630Sstevel@tonic-gate }
30640Sstevel@tonic-gate
30655331Samw /*
30665331Samw * Set the permissions and mode of the attribute
30675331Samw * unless the attribute is a system attribute (can't
30685331Samw * successfully do this) or the hidden attribute
30695331Samw * directory (".") of an attribute (when the attribute
30705331Samw * is restored, the hidden attribute directory of an
30715331Samw * attribute is transient). Note: when the permissions
30725331Samw * and mode are set for the hidden attribute directory
30735331Samw * of a file on a system supporting extended system
30745331Samw * attributes, even though it returns successfully, it
30755331Samw * will not have any affect since the attribute
30765331Samw * directory is transient.
30775331Samw */
30785331Samw if (attrinfo->attr_parent == NULL) {
30795331Samw if (fchownat(dirfd, ".", stbuf.st_uid,
30805331Samw stbuf.st_gid, 0) != 0) {
30815331Samw vperror(0, gettext(
30825331Samw "%s%s%s: failed to set ownership "
30835331Samw "of attribute directory"), namep,
30845331Samw gettext(" attribute "), xattrapath);
30855331Samw }
30865331Samw
30875331Samw if (fchmod(dirfd, stbuf.st_mode) != 0) {
30885331Samw vperror(0, gettext(
30895331Samw "%s%s%s: failed to set permissions "
30905331Samw "of attribute directory"), namep,
30915331Samw gettext(" attribute "), xattrapath);
30925331Samw }
30930Sstevel@tonic-gate }
30940Sstevel@tonic-gate goto filedone;
30950Sstevel@tonic-gate }
30960Sstevel@tonic-gate #endif
30970Sstevel@tonic-gate
30980Sstevel@tonic-gate if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
30990Sstevel@tonic-gate dir = 1;
31000Sstevel@tonic-gate if (vflag) {
310112305Srich.burridge@sun.com (void) fprintf(vfile, "x %s, 0 %s, ",
310212305Srich.burridge@sun.com &dirname[0], gettext("bytes"));
31030Sstevel@tonic-gate if (NotTape)
31040Sstevel@tonic-gate (void) fprintf(vfile, "0K\n");
31050Sstevel@tonic-gate else
31060Sstevel@tonic-gate (void) fprintf(vfile, gettext("%"
31070Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"),
31080Sstevel@tonic-gate (blkcnt_t)0);
31090Sstevel@tonic-gate }
31100Sstevel@tonic-gate goto filedone;
31110Sstevel@tonic-gate }
31120Sstevel@tonic-gate
31130Sstevel@tonic-gate if (dblock.dbuf.typeflag == '6') { /* FIFO */
31140Sstevel@tonic-gate if (rmdir(namep) < 0) {
31150Sstevel@tonic-gate if (errno == ENOTDIR)
31160Sstevel@tonic-gate (void) unlink(namep);
31170Sstevel@tonic-gate }
31180Sstevel@tonic-gate linkp = templink;
31190Sstevel@tonic-gate if (*linkp != NULL) {
31200Sstevel@tonic-gate if (Aflag && *linkp == '/')
31210Sstevel@tonic-gate linkp++;
31220Sstevel@tonic-gate if (link(linkp, namep) < 0) {
31230Sstevel@tonic-gate (void) fprintf(stderr, gettext(
31240Sstevel@tonic-gate "tar: %s: cannot link\n"), namep);
31250Sstevel@tonic-gate continue;
31260Sstevel@tonic-gate }
31270Sstevel@tonic-gate if (vflag)
31280Sstevel@tonic-gate (void) fprintf(vfile, gettext(
31295331Samw "x %s linked to %s\n"), namep,
31305331Samw linkp);
31310Sstevel@tonic-gate xcnt++; /* increment # files extracted */
31320Sstevel@tonic-gate continue;
31330Sstevel@tonic-gate }
31340Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
31350Sstevel@tonic-gate (int)Gen.g_devmajor) < 0) {
31360Sstevel@tonic-gate vperror(0, gettext("%s: mknod failed"), namep);
31370Sstevel@tonic-gate continue;
31380Sstevel@tonic-gate }
31390Sstevel@tonic-gate bytes = stbuf.st_size;
31400Sstevel@tonic-gate blocks = TBLOCKS(bytes);
31410Sstevel@tonic-gate if (vflag) {
31420Sstevel@tonic-gate (void) fprintf(vfile, "x %s, %" FMT_off_t
314312305Srich.burridge@sun.com " %s, ", namep, bytes, gettext("bytes"));
31440Sstevel@tonic-gate if (NotTape)
31450Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t
31460Sstevel@tonic-gate "K\n", K(blocks));
31470Sstevel@tonic-gate else
31480Sstevel@tonic-gate (void) fprintf(vfile, gettext("%"
31490Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"),
31500Sstevel@tonic-gate blocks);
31510Sstevel@tonic-gate }
31520Sstevel@tonic-gate goto filedone;
31530Sstevel@tonic-gate }
31540Sstevel@tonic-gate if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
31550Sstevel@tonic-gate if (rmdir(namep) < 0) {
31560Sstevel@tonic-gate if (errno == ENOTDIR)
31570Sstevel@tonic-gate (void) unlink(namep);
31580Sstevel@tonic-gate }
31590Sstevel@tonic-gate linkp = templink;
31600Sstevel@tonic-gate if (*linkp != NULL) {
31610Sstevel@tonic-gate if (Aflag && *linkp == '/')
31620Sstevel@tonic-gate linkp++;
31630Sstevel@tonic-gate if (link(linkp, namep) < 0) {
31640Sstevel@tonic-gate (void) fprintf(stderr, gettext(
31650Sstevel@tonic-gate "tar: %s: cannot link\n"), namep);
31660Sstevel@tonic-gate continue;
31670Sstevel@tonic-gate }
31680Sstevel@tonic-gate if (vflag)
31690Sstevel@tonic-gate (void) fprintf(vfile, gettext(
31705331Samw "x %s linked to %s\n"), namep,
31715331Samw linkp);
31720Sstevel@tonic-gate xcnt++; /* increment # files extracted */
31730Sstevel@tonic-gate continue;
31740Sstevel@tonic-gate }
31750Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
31760Sstevel@tonic-gate (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
31770Sstevel@tonic-gate vperror(0, gettext(
31785331Samw "%s: mknod failed"), namep);
31790Sstevel@tonic-gate continue;
31800Sstevel@tonic-gate }
31810Sstevel@tonic-gate bytes = stbuf.st_size;
31820Sstevel@tonic-gate blocks = TBLOCKS(bytes);
31830Sstevel@tonic-gate if (vflag) {
31840Sstevel@tonic-gate (void) fprintf(vfile, "x %s, %" FMT_off_t
318512305Srich.burridge@sun.com " %s, ", namep, bytes, gettext("bytes"));
31860Sstevel@tonic-gate if (NotTape)
31870Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t
31880Sstevel@tonic-gate "K\n", K(blocks));
31890Sstevel@tonic-gate else
31900Sstevel@tonic-gate (void) fprintf(vfile, gettext("%"
31910Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"),
31920Sstevel@tonic-gate blocks);
31930Sstevel@tonic-gate }
31940Sstevel@tonic-gate goto filedone;
31950Sstevel@tonic-gate } else if (dblock.dbuf.typeflag == '3' && Uid) {
31960Sstevel@tonic-gate (void) fprintf(stderr, gettext(
31970Sstevel@tonic-gate "Can't create special %s\n"), namep);
31980Sstevel@tonic-gate continue;
31990Sstevel@tonic-gate }
32000Sstevel@tonic-gate
32010Sstevel@tonic-gate /* BLOCK SPECIAL */
32020Sstevel@tonic-gate
32030Sstevel@tonic-gate if (dblock.dbuf.typeflag == '4' && !Uid) {
32040Sstevel@tonic-gate if (rmdir(namep) < 0) {
32050Sstevel@tonic-gate if (errno == ENOTDIR)
32060Sstevel@tonic-gate (void) unlink(namep);
32070Sstevel@tonic-gate }
32080Sstevel@tonic-gate linkp = templink;
32090Sstevel@tonic-gate if (*linkp != NULL) {
32100Sstevel@tonic-gate if (Aflag && *linkp == '/')
32110Sstevel@tonic-gate linkp++;
32120Sstevel@tonic-gate if (link(linkp, namep) < 0) {
32130Sstevel@tonic-gate (void) fprintf(stderr, gettext(
32140Sstevel@tonic-gate "tar: %s: cannot link\n"), namep);
32150Sstevel@tonic-gate continue;
32160Sstevel@tonic-gate }
32170Sstevel@tonic-gate if (vflag)
32180Sstevel@tonic-gate (void) fprintf(vfile, gettext(
32195331Samw "x %s linked to %s\n"), namep,
32205331Samw linkp);
32210Sstevel@tonic-gate xcnt++; /* increment # files extracted */
32220Sstevel@tonic-gate continue;
32230Sstevel@tonic-gate }
32240Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
32250Sstevel@tonic-gate (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
32260Sstevel@tonic-gate vperror(0, gettext("%s: mknod failed"), namep);
32270Sstevel@tonic-gate continue;
32280Sstevel@tonic-gate }
32290Sstevel@tonic-gate bytes = stbuf.st_size;
32300Sstevel@tonic-gate blocks = TBLOCKS(bytes);
32310Sstevel@tonic-gate if (vflag) {
32320Sstevel@tonic-gate (void) fprintf(vfile, gettext("x %s, %"
32330Sstevel@tonic-gate FMT_off_t " bytes, "), namep, bytes);
32340Sstevel@tonic-gate if (NotTape)
32350Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t
32360Sstevel@tonic-gate "K\n", K(blocks));
32370Sstevel@tonic-gate else
32380Sstevel@tonic-gate (void) fprintf(vfile, gettext("%"
32390Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"),
32400Sstevel@tonic-gate blocks);
32410Sstevel@tonic-gate }
32420Sstevel@tonic-gate goto filedone;
32430Sstevel@tonic-gate } else if (dblock.dbuf.typeflag == '4' && Uid) {
32440Sstevel@tonic-gate (void) fprintf(stderr,
32450Sstevel@tonic-gate gettext("Can't create special %s\n"), namep);
32460Sstevel@tonic-gate continue;
32470Sstevel@tonic-gate }
32480Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2') { /* symlink */
32491676Sjpk if ((Tflag) && (lk_rpath_flag == 1))
32501676Sjpk linkp = lk_real_path;
32511676Sjpk else
32521676Sjpk linkp = templink;
32530Sstevel@tonic-gate if (Aflag && *linkp == '/')
32540Sstevel@tonic-gate linkp++;
32550Sstevel@tonic-gate if (rmdir(namep) < 0) {
32560Sstevel@tonic-gate if (errno == ENOTDIR)
32570Sstevel@tonic-gate (void) unlink(namep);
32580Sstevel@tonic-gate }
32590Sstevel@tonic-gate if (symlink(linkp, namep) < 0) {
32600Sstevel@tonic-gate vperror(0, gettext("%s: symbolic link failed"),
32610Sstevel@tonic-gate namep);
32620Sstevel@tonic-gate continue;
32630Sstevel@tonic-gate }
32640Sstevel@tonic-gate if (vflag)
32650Sstevel@tonic-gate (void) fprintf(vfile, gettext(
32660Sstevel@tonic-gate "x %s symbolic link to %s\n"),
32670Sstevel@tonic-gate namep, linkp);
32680Sstevel@tonic-gate
32690Sstevel@tonic-gate symflag = AT_SYMLINK_NOFOLLOW;
32700Sstevel@tonic-gate goto filedone;
32710Sstevel@tonic-gate }
32720Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1') {
32730Sstevel@tonic-gate linkp = templink;
32740Sstevel@tonic-gate if (Aflag && *linkp == '/')
32750Sstevel@tonic-gate linkp++;
32760Sstevel@tonic-gate if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
32770Sstevel@tonic-gate if (errno == ENOTDIR)
32780Sstevel@tonic-gate (void) unlinkat(dirfd, comp, 0);
32790Sstevel@tonic-gate }
32800Sstevel@tonic-gate #if defined(O_XATTR)
32810Sstevel@tonic-gate if (xattrp && xattr_linkp) {
32820Sstevel@tonic-gate if (fchdir(dirfd) < 0) {
32830Sstevel@tonic-gate vperror(0, gettext(
32840Sstevel@tonic-gate "Cannot fchdir to attribute "
32855331Samw "directory %s"),
32865331Samw (attrinfo->attr_parent == NULL) ?
32875331Samw dirp : attrinfo->attr_parent);
32880Sstevel@tonic-gate exit(1);
32890Sstevel@tonic-gate }
32900Sstevel@tonic-gate
32915331Samw error = link(xattr_linkaname, xattrapath);
32920Sstevel@tonic-gate } else {
32930Sstevel@tonic-gate error = link(linkp, namep);
32940Sstevel@tonic-gate }
32950Sstevel@tonic-gate #else
32960Sstevel@tonic-gate error = link(linkp, namep);
32970Sstevel@tonic-gate #endif
32980Sstevel@tonic-gate
32990Sstevel@tonic-gate if (error < 0) {
33000Sstevel@tonic-gate (void) fprintf(stderr, gettext(
33010Sstevel@tonic-gate "tar: %s%s%s: cannot link\n"),
33020Sstevel@tonic-gate namep, (xattr_linkp != NULL) ?
33030Sstevel@tonic-gate gettext(" attribute ") : "",
33040Sstevel@tonic-gate (xattr_linkp != NULL) ?
33055331Samw xattrapath : "");
33060Sstevel@tonic-gate continue;
33070Sstevel@tonic-gate }
33080Sstevel@tonic-gate if (vflag)
33090Sstevel@tonic-gate (void) fprintf(vfile, gettext(
33105331Samw "x %s%s%s linked to %s%s%s\n"), namep,
33110Sstevel@tonic-gate (xattr_linkp != NULL) ?
33120Sstevel@tonic-gate gettext(" attribute ") : "",
33130Sstevel@tonic-gate (xattr_linkp != NULL) ?
33140Sstevel@tonic-gate xattr_linkaname : "",
33155331Samw linkp,
33165331Samw (xattr_linkp != NULL) ?
33170Sstevel@tonic-gate gettext(" attribute ") : "",
33185331Samw (xattr_linkp != NULL) ? xattrapath : "");
33190Sstevel@tonic-gate xcnt++; /* increment # files extracted */
33200Sstevel@tonic-gate #if defined(O_XATTR)
33215331Samw if (xattrp != NULL) {
33220Sstevel@tonic-gate free(xattrhead);
33230Sstevel@tonic-gate xattrp = NULL;
33240Sstevel@tonic-gate xattr_linkp = NULL;
33250Sstevel@tonic-gate xattrhead = NULL;
33260Sstevel@tonic-gate }
33270Sstevel@tonic-gate #endif
33280Sstevel@tonic-gate continue;
33290Sstevel@tonic-gate }
33300Sstevel@tonic-gate
33310Sstevel@tonic-gate /* REGULAR FILES */
33320Sstevel@tonic-gate
33330Sstevel@tonic-gate if (convtoreg(stbuf.st_size)) {
33340Sstevel@tonic-gate convflag = 1;
33350Sstevel@tonic-gate if (errflag) {
33360Sstevel@tonic-gate (void) fprintf(stderr, gettext(
33370Sstevel@tonic-gate "tar: %s: typeflag '%c' not recognized\n"),
33380Sstevel@tonic-gate namep, dblock.dbuf.typeflag);
33390Sstevel@tonic-gate done(1);
33400Sstevel@tonic-gate } else {
33410Sstevel@tonic-gate (void) fprintf(stderr, gettext(
33420Sstevel@tonic-gate "tar: %s: typeflag '%c' not recognized, "
33430Sstevel@tonic-gate "converting to regular file\n"), namep,
33440Sstevel@tonic-gate dblock.dbuf.typeflag);
33450Sstevel@tonic-gate Errflg = 1;
33460Sstevel@tonic-gate }
33470Sstevel@tonic-gate }
33480Sstevel@tonic-gate if (dblock.dbuf.typeflag == '0' ||
33490Sstevel@tonic-gate dblock.dbuf.typeflag == NULL || convflag) {
33503805Slovely delete_target(dirfd, comp, namep);
33510Sstevel@tonic-gate linkp = templink;
33520Sstevel@tonic-gate if (*linkp != NULL) {
33530Sstevel@tonic-gate if (Aflag && *linkp == '/')
33540Sstevel@tonic-gate linkp++;
33550Sstevel@tonic-gate if (link(linkp, comp) < 0) {
33560Sstevel@tonic-gate (void) fprintf(stderr, gettext(
33570Sstevel@tonic-gate "tar: %s: cannot link\n"), namep);
33580Sstevel@tonic-gate continue;
33590Sstevel@tonic-gate }
33600Sstevel@tonic-gate if (vflag)
33610Sstevel@tonic-gate (void) fprintf(vfile, gettext(
33625331Samw "x %s linked to %s\n"), comp,
33635331Samw linkp);
33640Sstevel@tonic-gate xcnt++; /* increment # files extracted */
33655331Samw #if defined(O_XATTR)
33665331Samw if (xattrp != NULL) {
33675331Samw free(xattrhead);
33685331Samw xattrp = NULL;
33695331Samw xattr_linkp = NULL;
33705331Samw xattrhead = NULL;
33715331Samw }
33725331Samw #endif
33730Sstevel@tonic-gate continue;
33740Sstevel@tonic-gate }
33750Sstevel@tonic-gate newfile = ((fstatat(dirfd, comp,
33760Sstevel@tonic-gate &xtractbuf, 0) == -1) ? TRUE : FALSE);
33775331Samw ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
33785331Samw stbuf.st_mode & MODEMASK);
33795331Samw saveerrno = errno;
33805331Samw
33815331Samw #if defined(O_XATTR)
33825331Samw if (xattrp != NULL) {
33835331Samw if (ofile < 0) {
33845331Samw ofile = retry_open_attr(dirfd, cwd,
33855331Samw dirp, attrinfo->attr_parent, comp,
33865331Samw O_RDWR|O_CREAT|O_TRUNC,
33875331Samw stbuf.st_mode & MODEMASK);
33885331Samw }
33895331Samw }
33905331Samw #endif
33915331Samw if (ofile < 0) {
33925331Samw errno = saveerrno;
33930Sstevel@tonic-gate (void) fprintf(stderr, gettext(
33945331Samw "tar: %s%s%s%s - cannot create\n"),
33955331Samw (xattrp == NULL) ? "" : (rw_sysattr ?
339612305Srich.burridge@sun.com gettext("system attribute ") :
33975331Samw gettext("attribute ")),
33985331Samw (xattrp == NULL) ? "" : xattrapath,
33995331Samw (xattrp == NULL) ? "" : gettext(" of "),
34005331Samw (xattrp == NULL) ? comp : namep);
34010Sstevel@tonic-gate if (errflag)
34020Sstevel@tonic-gate done(1);
34030Sstevel@tonic-gate else
34040Sstevel@tonic-gate Errflg = 1;
34055331Samw #if defined(O_XATTR)
34065331Samw if (xattrp != NULL) {
34075331Samw dblock.dbuf.typeflag = _XATTR_HDRTYPE;
34085331Samw free(xattrhead);
34095331Samw xattrp = NULL;
34105331Samw xattr_linkp = NULL;
34115331Samw xattrhead = NULL;
34125331Samw }
34135331Samw #endif
34140Sstevel@tonic-gate passtape();
34150Sstevel@tonic-gate continue;
34160Sstevel@tonic-gate }
34170Sstevel@tonic-gate
34181676Sjpk if (Tflag && (check_ext_attr(namep) == 0)) {
34191676Sjpk if (errflag)
34201676Sjpk done(1);
34211676Sjpk else
34221676Sjpk Errflg = 1;
34231676Sjpk passtape();
34241676Sjpk continue;
34251676Sjpk }
34261676Sjpk
34270Sstevel@tonic-gate if (extno != 0) { /* file is in pieces */
34280Sstevel@tonic-gate if (extotal < 1 || extotal > MAXEXT)
34290Sstevel@tonic-gate (void) fprintf(stderr, gettext(
34305331Samw "tar: ignoring bad extent info for "
34315331Samw "%s%s%s%s\n"),
34325331Samw (xattrp == NULL) ? "" : (rw_sysattr ?
34335331Samw gettext("system attribute ") :
34345331Samw gettext("attribute ")),
34355331Samw (xattrp == NULL) ? "" : xattrapath,
34365331Samw (xattrp == NULL) ? "" : gettext(" of "),
34375331Samw (xattrp == NULL) ? comp : namep);
34380Sstevel@tonic-gate else {
34395331Samw /* extract it */
34405331Samw (void) xsfile(rw_sysattr, ofile);
34410Sstevel@tonic-gate }
34420Sstevel@tonic-gate }
34430Sstevel@tonic-gate extno = 0; /* let everyone know file is not split */
34440Sstevel@tonic-gate bytes = stbuf.st_size;
34450Sstevel@tonic-gate blocks = TBLOCKS(bytes);
34460Sstevel@tonic-gate if (vflag) {
34470Sstevel@tonic-gate (void) fprintf(vfile,
344812305Srich.burridge@sun.com "x %s%s%s, %" FMT_off_t " %s, ",
34490Sstevel@tonic-gate (xattrp == NULL) ? "" : dirp,
34505331Samw (xattrp == NULL) ? "" : (rw_sysattr ?
34515331Samw gettext(" system attribute ") :
34525331Samw gettext(" attribute ")),
345312305Srich.burridge@sun.com (xattrp == NULL) ? namep : xattrapath, bytes,
345412305Srich.burridge@sun.com gettext("bytes"));
34550Sstevel@tonic-gate if (NotTape)
34560Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
34570Sstevel@tonic-gate K(blocks));
34580Sstevel@tonic-gate else
34590Sstevel@tonic-gate (void) fprintf(vfile, gettext("%"
34600Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), blocks);
34610Sstevel@tonic-gate }
34620Sstevel@tonic-gate
34635331Samw if (xblocks(rw_sysattr, bytes, ofile) != 0) {
34645331Samw #if defined(O_XATTR)
34655331Samw if (xattrp != NULL) {
34665331Samw free(xattrhead);
34675331Samw xattrp = NULL;
34685331Samw xattr_linkp = NULL;
34695331Samw xattrhead = NULL;
34705331Samw }
34715331Samw #endif
34725331Samw continue;
34735331Samw }
34740Sstevel@tonic-gate filedone:
34750Sstevel@tonic-gate if (mflag == 0 && !symflag) {
34760Sstevel@tonic-gate if (dir)
34770Sstevel@tonic-gate doDirTimes(namep, stbuf.st_mtim);
34785331Samw
34790Sstevel@tonic-gate else
34805331Samw #if defined(O_XATTR)
34815331Samw if (xattrp != NULL) {
34825331Samw /*
34835331Samw * Set the time on the attribute unless
34845331Samw * the attribute is a system attribute
34855331Samw * (can't successfully do this) or the
34865331Samw * hidden attribute directory, "." (the
34875331Samw * time on the hidden attribute
34885331Samw * directory will be updated when
34895331Samw * attributes are restored, otherwise
34905331Samw * it's transient).
34915331Samw */
34925331Samw if (!rw_sysattr && (Hiddendir == 0)) {
34935331Samw setPathTimes(dirfd, comp,
34945331Samw stbuf.st_mtim);
34955331Samw }
34965331Samw } else
34975331Samw setPathTimes(dirfd, comp,
34985331Samw stbuf.st_mtim);
34995331Samw #else
35000Sstevel@tonic-gate setPathTimes(dirfd, comp, stbuf.st_mtim);
35015331Samw #endif
35020Sstevel@tonic-gate }
35030Sstevel@tonic-gate
35040Sstevel@tonic-gate /* moved this code from above */
35050Sstevel@tonic-gate if (pflag && !symflag && Hiddendir == 0) {
35065331Samw if (xattrp != NULL)
35070Sstevel@tonic-gate (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
35080Sstevel@tonic-gate else
35090Sstevel@tonic-gate (void) chmod(namep, stbuf.st_mode & MODEMASK);
35100Sstevel@tonic-gate }
35110Sstevel@tonic-gate
35120Sstevel@tonic-gate
35130Sstevel@tonic-gate /*
35140Sstevel@tonic-gate * Because ancillary file preceeds the normal file,
35150Sstevel@tonic-gate * acl info may have been retrieved (in aclp).
35160Sstevel@tonic-gate * All file types are directed here (go filedone).
35170Sstevel@tonic-gate * Always restore ACLs if there are ACLs.
35180Sstevel@tonic-gate */
35190Sstevel@tonic-gate if (aclp != NULL) {
35200Sstevel@tonic-gate int ret;
35210Sstevel@tonic-gate
35220Sstevel@tonic-gate #if defined(O_XATTR)
35235331Samw if (xattrp != NULL) {
35240Sstevel@tonic-gate if (Hiddendir)
3525789Sahrens ret = facl_set(dirfd, aclp);
35260Sstevel@tonic-gate else
3527789Sahrens ret = facl_set(ofile, aclp);
35280Sstevel@tonic-gate } else {
3529789Sahrens ret = acl_set(namep, aclp);
35300Sstevel@tonic-gate }
35310Sstevel@tonic-gate #else
35321676Sjpk ret = acl_set(namep, aclp);
35330Sstevel@tonic-gate #endif
35340Sstevel@tonic-gate if (ret < 0) {
35350Sstevel@tonic-gate if (pflag) {
35360Sstevel@tonic-gate (void) fprintf(stderr, gettext(
35375331Samw "%s%s%s%s: failed to set acl "
35385331Samw "entries\n"), namep,
35395331Samw (xattrp == NULL) ? "" :
35405331Samw (rw_sysattr ? gettext(
35415331Samw " system attribute ") :
35425331Samw gettext(" attribute ")),
35435331Samw (xattrp == NULL) ? "" :
35445331Samw xattrapath);
35450Sstevel@tonic-gate }
35460Sstevel@tonic-gate /* else: silent and continue */
35470Sstevel@tonic-gate }
3548789Sahrens acl_free(aclp);
35490Sstevel@tonic-gate aclp = NULL;
35500Sstevel@tonic-gate }
35510Sstevel@tonic-gate
35520Sstevel@tonic-gate if (!oflag)
3553*12836Srich.burridge@oracle.com /* set file ownership */
3554*12836Srich.burridge@oracle.com resugname(dirfd, comp, symflag);
35550Sstevel@tonic-gate
35560Sstevel@tonic-gate if (pflag && newfile == TRUE && !dir &&
35570Sstevel@tonic-gate (dblock.dbuf.typeflag == '0' ||
35580Sstevel@tonic-gate dblock.dbuf.typeflag == NULL ||
35590Sstevel@tonic-gate convflag || dblock.dbuf.typeflag == '1')) {
35600Sstevel@tonic-gate if (fstat(ofile, &xtractbuf) == -1)
35610Sstevel@tonic-gate (void) fprintf(stderr, gettext(
35625331Samw "tar: cannot stat extracted file "
35635331Samw "%s%s%s%s\n"),
35645331Samw (xattrp == NULL) ? "" : (rw_sysattr ?
35655331Samw gettext("system attribute ") :
35665331Samw gettext("attribute ")),
35675331Samw (xattrp == NULL) ? "" : xattrapath,
35685331Samw (xattrp == NULL) ? "" :
35695331Samw gettext(" of "), namep);
35705331Samw
35710Sstevel@tonic-gate else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
35720Sstevel@tonic-gate != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
35730Sstevel@tonic-gate (void) fprintf(stderr, gettext(
35740Sstevel@tonic-gate "tar: warning - file permissions have "
35755331Samw "changed for %s%s%s%s (are 0%o, should be "
35760Sstevel@tonic-gate "0%o)\n"),
35775331Samw (xattrp == NULL) ? "" : (rw_sysattr ?
35785331Samw gettext("system attribute ") :
35795331Samw gettext("attribute ")),
35805331Samw (xattrp == NULL) ? "" : xattrapath,
35815331Samw (xattrp == NULL) ? "" :
35825331Samw gettext(" of "), namep,
35835331Samw xtractbuf.st_mode, stbuf.st_mode);
35845331Samw
35850Sstevel@tonic-gate }
35860Sstevel@tonic-gate }
35875750Sceastha #if defined(O_XATTR)
35885750Sceastha if (xattrp != NULL) {
35895750Sceastha free(xattrhead);
35905750Sceastha xattrp = NULL;
35915750Sceastha xattr_linkp = NULL;
35925750Sceastha xattrhead = NULL;
35935750Sceastha }
35945750Sceastha #endif
35955750Sceastha
35960Sstevel@tonic-gate if (ofile != -1) {
35970Sstevel@tonic-gate (void) close(dirfd);
35980Sstevel@tonic-gate dirfd = -1;
35990Sstevel@tonic-gate if (close(ofile) != 0)
36000Sstevel@tonic-gate vperror(2, gettext("close error"));
36015331Samw ofile = -1;
36020Sstevel@tonic-gate }
36030Sstevel@tonic-gate xcnt++; /* increment # files extracted */
36040Sstevel@tonic-gate }
36051676Sjpk
36061676Sjpk /*
36071676Sjpk * Process ancillary file.
36081676Sjpk *
36091676Sjpk */
36101676Sjpk
36111676Sjpk if (dblock.dbuf.typeflag == 'A') { /* acl info */
36120Sstevel@tonic-gate char buf[TBLOCK];
36130Sstevel@tonic-gate char *secp;
36140Sstevel@tonic-gate char *tp;
36150Sstevel@tonic-gate int attrsize;
36160Sstevel@tonic-gate int cnt;
36170Sstevel@tonic-gate
36181676Sjpk /* reset Trusted Extensions flags */
36191676Sjpk dir_flag = 0;
36201676Sjpk mld_flag = 0;
36211676Sjpk lk_rpath_flag = 0;
36221676Sjpk rpath_flag = 0;
36230Sstevel@tonic-gate
36240Sstevel@tonic-gate if (pflag) {
36250Sstevel@tonic-gate bytes = stbuf.st_size;
36260Sstevel@tonic-gate if ((secp = malloc((int)bytes)) == NULL) {
36270Sstevel@tonic-gate (void) fprintf(stderr, gettext(
36280Sstevel@tonic-gate "Insufficient memory for acl\n"));
36290Sstevel@tonic-gate passtape();
36300Sstevel@tonic-gate continue;
36310Sstevel@tonic-gate }
36320Sstevel@tonic-gate tp = secp;
36330Sstevel@tonic-gate blocks = TBLOCKS(bytes);
36341676Sjpk
36351676Sjpk /*
36361676Sjpk * Display a line for each ancillary file.
36371676Sjpk */
36381676Sjpk if (vflag && Tflag)
36391676Sjpk (void) fprintf(vfile, "x %s(A), %"
364012305Srich.burridge@sun.com FMT_blkcnt_t " %s, %"
364112305Srich.burridge@sun.com FMT_blkcnt_t " %s\n",
364212305Srich.burridge@sun.com namep, bytes, gettext("bytes"),
364312305Srich.burridge@sun.com blocks, gettext("tape blocks"));
36441676Sjpk
36450Sstevel@tonic-gate while (blocks-- > 0) {
36460Sstevel@tonic-gate readtape(buf);
36470Sstevel@tonic-gate if (bytes <= TBLOCK) {
36480Sstevel@tonic-gate (void) memcpy(tp, buf,
36490Sstevel@tonic-gate (size_t)bytes);
36500Sstevel@tonic-gate break;
36510Sstevel@tonic-gate } else {
36520Sstevel@tonic-gate (void) memcpy(tp, buf,
36530Sstevel@tonic-gate TBLOCK);
36540Sstevel@tonic-gate tp += TBLOCK;
36550Sstevel@tonic-gate }
36560Sstevel@tonic-gate bytes -= TBLOCK;
36570Sstevel@tonic-gate }
3658789Sahrens bytes = stbuf.st_size;
36590Sstevel@tonic-gate /* got all attributes in secp */
36600Sstevel@tonic-gate tp = secp;
36610Sstevel@tonic-gate do {
36620Sstevel@tonic-gate attr = (struct sec_attr *)tp;
36630Sstevel@tonic-gate switch (attr->attr_type) {
36640Sstevel@tonic-gate case UFSD_ACL:
3665789Sahrens case ACE_ACL:
36660Sstevel@tonic-gate (void) sscanf(attr->attr_len,
3667789Sahrens "%7o",
3668789Sahrens (uint_t *)
3669789Sahrens &cnt);
36700Sstevel@tonic-gate /* header is 8 */
36710Sstevel@tonic-gate attrsize = 8 + (int)strlen(
36720Sstevel@tonic-gate &attr->attr_info[0]) + 1;
3673789Sahrens error =
3674789Sahrens acl_fromtext(
3675789Sahrens &attr->attr_info[0], &aclp);
3676789Sahrens
3677789Sahrens if (error != 0) {
36780Sstevel@tonic-gate (void) fprintf(stderr,
36790Sstevel@tonic-gate gettext(
36800Sstevel@tonic-gate "aclfromtext "
3681789Sahrens "failed: %s\n"),
3682789Sahrens acl_strerror(
3683789Sahrens error));
3684789Sahrens bytes -= attrsize;
36850Sstevel@tonic-gate break;
36860Sstevel@tonic-gate }
3687789Sahrens if (acl_cnt(aclp) != cnt) {
36880Sstevel@tonic-gate (void) fprintf(stderr,
36890Sstevel@tonic-gate gettext(
36900Sstevel@tonic-gate "aclcnt error\n"));
3691789Sahrens bytes -= attrsize;
36920Sstevel@tonic-gate break;
36930Sstevel@tonic-gate }
36940Sstevel@tonic-gate bytes -= attrsize;
36950Sstevel@tonic-gate break;
36960Sstevel@tonic-gate
36971676Sjpk /* Trusted Extensions */
36981676Sjpk
36991676Sjpk case DIR_TYPE:
37001676Sjpk case LBL_TYPE:
37011676Sjpk case APRIV_TYPE:
37021676Sjpk case FPRIV_TYPE:
37031676Sjpk case COMP_TYPE:
37041676Sjpk case LK_COMP_TYPE:
37051676Sjpk case ATTR_FLAG_TYPE:
37061676Sjpk attrsize =
37071676Sjpk sizeof (struct sec_attr) +
37081676Sjpk strlen(&attr->attr_info[0]);
37091676Sjpk bytes -= attrsize;
37101676Sjpk if (Tflag)
37111676Sjpk extract_attr(&namep,
37121676Sjpk attr);
37131676Sjpk break;
37140Sstevel@tonic-gate
37150Sstevel@tonic-gate default:
37160Sstevel@tonic-gate (void) fprintf(stderr, gettext(
37170Sstevel@tonic-gate "unrecognized attr"
37180Sstevel@tonic-gate " type\n"));
37190Sstevel@tonic-gate bytes = (off_t)0;
37200Sstevel@tonic-gate break;
37210Sstevel@tonic-gate }
37220Sstevel@tonic-gate
37230Sstevel@tonic-gate /* next attributes */
37240Sstevel@tonic-gate tp += attrsize;
37250Sstevel@tonic-gate } while (bytes != 0);
37260Sstevel@tonic-gate free(secp);
37275331Samw } else {
37280Sstevel@tonic-gate passtape();
37295331Samw }
37300Sstevel@tonic-gate } /* acl */
37310Sstevel@tonic-gate
37320Sstevel@tonic-gate } /* for */
37330Sstevel@tonic-gate
37340Sstevel@tonic-gate /*
37350Sstevel@tonic-gate * Ensure that all the directories still on the directory stack
37360Sstevel@tonic-gate * get their modification times set correctly by flushing the
37370Sstevel@tonic-gate * stack.
37380Sstevel@tonic-gate */
37390Sstevel@tonic-gate
37400Sstevel@tonic-gate doDirTimes(NULL, time_zero);
37410Sstevel@tonic-gate
37425331Samw #if defined(O_XATTR)
37435331Samw if (xattrp != NULL) {
37445331Samw free(xattrhead);
37455331Samw xattrp = NULL;
37465331Samw xattr_linkp = NULL;
37475331Samw xattrhead = NULL;
37485331Samw }
37495331Samw #endif
37505331Samw
37510Sstevel@tonic-gate /*
37520Sstevel@tonic-gate * Check if the number of files extracted is different from the
37530Sstevel@tonic-gate * number of files listed on the command line
37540Sstevel@tonic-gate */
37550Sstevel@tonic-gate if (fcnt > xcnt) {
37560Sstevel@tonic-gate (void) fprintf(stderr,
37570Sstevel@tonic-gate gettext("tar: %d file(s) not extracted\n"),
3758*12836Srich.burridge@oracle.com fcnt-xcnt);
37590Sstevel@tonic-gate Errflg = 1;
37600Sstevel@tonic-gate }
37610Sstevel@tonic-gate }
37620Sstevel@tonic-gate
37630Sstevel@tonic-gate /*
37640Sstevel@tonic-gate * xblocks extract file/extent from tape to output file
37650Sstevel@tonic-gate *
37665750Sceastha * xblocks(issysattr, bytes, ofile);
37675750Sceastha *
37685750Sceastha * issysattr flag set if the files being extracted
37695750Sceastha * is an extended system attribute file.
37705750Sceastha * unsigned long long bytes size of extent or file to be extracted
37715750Sceastha * ofile output file
37720Sstevel@tonic-gate *
37730Sstevel@tonic-gate * called by doxtract() and xsfile()
37740Sstevel@tonic-gate */
37750Sstevel@tonic-gate
37765331Samw static int
xblocks(int issysattr,off_t bytes,int ofile)37775331Samw xblocks(int issysattr, off_t bytes, int ofile)
37780Sstevel@tonic-gate {
37795750Sceastha char *buf;
37800Sstevel@tonic-gate char tempname[NAMSIZ+1];
37815750Sceastha size_t maxwrite;
37825750Sceastha size_t bytesread;
37835750Sceastha size_t piosize; /* preferred I/O size */
37845750Sceastha struct stat tsbuf;
37855750Sceastha
37865750Sceastha /* Don't need to do anything if this is a zero size file */
37875750Sceastha if (bytes <= 0) {
37885750Sceastha return (0);
37895750Sceastha }
37905750Sceastha
37915750Sceastha /*
37925750Sceastha * To figure out the size of the buffer used to accumulate data
37935750Sceastha * from readtape() and to write to the file, we need to determine
37945750Sceastha * the largest chunk of data to be written to the file at one time.
37955750Sceastha * This is determined based on the smallest of the following two
37965750Sceastha * things:
37975750Sceastha * 1) The size of the archived file.
37985750Sceastha * 2) The preferred I/O size of the file.
37995750Sceastha */
38005750Sceastha if (issysattr || (bytes <= TBLOCK)) {
38015750Sceastha /*
38025750Sceastha * Writes to system attribute files must be
38035750Sceastha * performed in one operation.
38045750Sceastha */
38055750Sceastha maxwrite = bytes;
38065750Sceastha } else {
38075750Sceastha /*
38085750Sceastha * fstat() the file to get the preferred I/O size.
38095750Sceastha * If it fails, then resort back to just writing
38105750Sceastha * one block at a time.
38115750Sceastha */
38125750Sceastha if (fstat(ofile, &tsbuf) == 0) {
38135750Sceastha piosize = tsbuf.st_blksize;
38145750Sceastha } else {
38155750Sceastha piosize = TBLOCK;
38165750Sceastha }
38175750Sceastha maxwrite = min(bytes, piosize);
38185750Sceastha }
38195750Sceastha
38205750Sceastha /*
38215750Sceastha * The buffer used to accumulate the data for the write operation
38225750Sceastha * needs to be the maximum number of bytes to be written rounded up
38235750Sceastha * to the nearest TBLOCK since readtape reads one block at a time.
38245750Sceastha */
38255750Sceastha if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
38265750Sceastha fatal(gettext("cannot allocate buffer"));
38275750Sceastha }
38285750Sceastha
38295750Sceastha while (bytes > 0) {
38305750Sceastha
38315750Sceastha /*
38325750Sceastha * readtape() obtains one block (TBLOCK) of data at a time.
38335750Sceastha * Accumulate as many blocks of data in buf as we can write
38345750Sceastha * in one operation.
38355750Sceastha */
38365750Sceastha for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
38375750Sceastha readtape(buf + bytesread);
38385750Sceastha }
38395750Sceastha
38405750Sceastha if (write(ofile, buf, maxwrite) < 0) {
38415331Samw int saveerrno = errno;
38425331Samw
38430Sstevel@tonic-gate if (xhdr_flgs & _X_PATH)
38445750Sceastha (void) strlcpy(tempname, Xtarhdr.x_path,
38455750Sceastha sizeof (tempname));
38460Sstevel@tonic-gate else
38470Sstevel@tonic-gate (void) sprintf(tempname, "%.*s", NAMSIZ,
38480Sstevel@tonic-gate dblock.dbuf.name);
38495331Samw /*
38505331Samw * If the extended system attribute being extracted
38515331Samw * contains attributes that the user needs privileges
38525331Samw * for, then just display a warning message, skip
38535331Samw * the extraction of this file, and return.
38545331Samw */
38555331Samw if ((saveerrno == EPERM) && issysattr) {
38565331Samw (void) fprintf(stderr, gettext(
38575331Samw "tar: unable to extract system attribute "
38585331Samw "%s: insufficient privileges\n"), tempname);
38595331Samw Errflg = 1;
38605750Sceastha (void) free(buf);
38615331Samw return (1);
38625331Samw } else {
38635331Samw (void) fprintf(stderr, gettext(
38645331Samw "tar: %s: HELP - extract write error\n"),
38655331Samw tempname);
38665331Samw done(2);
38675331Samw }
38680Sstevel@tonic-gate }
38695750Sceastha bytes -= maxwrite;
38705750Sceastha
38715750Sceastha /*
38725750Sceastha * If we've reached this point and there is still data
38735750Sceastha * to be written, maxwrite had to have been determined
38745750Sceastha * by the preferred I/O size. If the number of bytes
38755750Sceastha * left to write is smaller than the preferred I/O size,
38765750Sceastha * then we're about to do our final write to the file, so
38775750Sceastha * just set maxwrite to the number of bytes left to write.
38785750Sceastha */
38795750Sceastha if ((bytes > 0) && (bytes < maxwrite)) {
38805750Sceastha maxwrite = bytes;
38815750Sceastha }
38825750Sceastha }
38835750Sceastha free(buf);
38845331Samw
38855331Samw return (0);
38860Sstevel@tonic-gate }
38870Sstevel@tonic-gate
38880Sstevel@tonic-gate /*
38890Sstevel@tonic-gate * xsfile extract split file
38900Sstevel@tonic-gate *
38910Sstevel@tonic-gate * xsfile(ofd); ofd = output file descriptor
38920Sstevel@tonic-gate *
38930Sstevel@tonic-gate * file extracted and put in ofd via xblocks()
38940Sstevel@tonic-gate *
38950Sstevel@tonic-gate * NOTE: only called by doxtract() to extract one large file
38960Sstevel@tonic-gate */
38970Sstevel@tonic-gate
38980Sstevel@tonic-gate static union hblock savedblock; /* to ensure same file across volumes */
38990Sstevel@tonic-gate
39005331Samw static int
xsfile(int issysattr,int ofd)39015331Samw xsfile(int issysattr, int ofd)
39020Sstevel@tonic-gate {
39030Sstevel@tonic-gate int i, c;
39045331Samw int sysattrerr = 0;
39050Sstevel@tonic-gate char name[PATH_MAX+1]; /* holds name for diagnostics */
39060Sstevel@tonic-gate int extents, totalext;
39070Sstevel@tonic-gate off_t bytes, totalbytes;
39080Sstevel@tonic-gate
39090Sstevel@tonic-gate if (xhdr_flgs & _X_PATH)
39100Sstevel@tonic-gate (void) strcpy(name, Xtarhdr.x_path);
39110Sstevel@tonic-gate else
39120Sstevel@tonic-gate (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
39130Sstevel@tonic-gate
39140Sstevel@tonic-gate totalbytes = (off_t)0; /* in case we read in half the file */
39150Sstevel@tonic-gate totalext = 0; /* these keep count */
39160Sstevel@tonic-gate
39170Sstevel@tonic-gate (void) fprintf(stderr, gettext(
39180Sstevel@tonic-gate "tar: %s split across %d volumes\n"), name, extotal);
39190Sstevel@tonic-gate
39200Sstevel@tonic-gate /* make sure we do extractions in order */
39210Sstevel@tonic-gate if (extno != 1) { /* starting in middle of file? */
39220Sstevel@tonic-gate (void) printf(gettext(
39231266Sceastha "tar: first extent read is not #1\n"
39244774Sas145665 "OK to read file beginning with extent #%d (%s/%s) ? "),
39254774Sas145665 extno, yesstr, nostr);
39264774Sas145665 if (yes() == 0) {
39270Sstevel@tonic-gate canit:
39280Sstevel@tonic-gate passtape();
39290Sstevel@tonic-gate if (close(ofd) != 0)
39300Sstevel@tonic-gate vperror(2, gettext("close error"));
39315331Samw if (sysattrerr) {
39325331Samw return (1);
39335331Samw } else {
39345331Samw return (0);
39355331Samw }
39360Sstevel@tonic-gate }
39370Sstevel@tonic-gate }
39380Sstevel@tonic-gate extents = extotal;
39390Sstevel@tonic-gate i = extno;
39400Sstevel@tonic-gate /*CONSTCOND*/
39410Sstevel@tonic-gate while (1) {
39420Sstevel@tonic-gate if (xhdr_flgs & _X_SIZE) {
39430Sstevel@tonic-gate bytes = extsize;
39440Sstevel@tonic-gate } else {
39450Sstevel@tonic-gate bytes = stbuf.st_size;
39460Sstevel@tonic-gate }
39470Sstevel@tonic-gate
39480Sstevel@tonic-gate if (vflag)
394912305Srich.burridge@sun.com (void) fprintf(vfile, "+++ x %s [%s #%d], %"
395012305Srich.burridge@sun.com FMT_off_t " %s, %ldK\n",
395112305Srich.burridge@sun.com name, gettext("extent"), extno,
395212305Srich.burridge@sun.com bytes, gettext("bytes"),
39530Sstevel@tonic-gate (long)K(TBLOCKS(bytes)));
39545331Samw if (xblocks(issysattr, bytes, ofd) != 0) {
39555331Samw sysattrerr = 1;
39565331Samw goto canit;
39575331Samw }
39580Sstevel@tonic-gate
39590Sstevel@tonic-gate totalbytes += bytes;
39600Sstevel@tonic-gate totalext++;
39610Sstevel@tonic-gate if (++i > extents)
39620Sstevel@tonic-gate break;
39630Sstevel@tonic-gate
39640Sstevel@tonic-gate /* get next volume and verify it's the right one */
39650Sstevel@tonic-gate copy(&savedblock, &dblock);
39660Sstevel@tonic-gate tryagain:
39670Sstevel@tonic-gate newvol();
39680Sstevel@tonic-gate xhdr_flgs = 0;
39690Sstevel@tonic-gate getdir();
39700Sstevel@tonic-gate if (Xhdrflag > 0)
39710Sstevel@tonic-gate (void) get_xdata(); /* Get x-header & regular hdr */
39725482Sas158974 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
39735482Sas158974 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
39745482Sas158974 xhdr_flgs |= _X_XHDR;
39755482Sas158974 }
39760Sstevel@tonic-gate if (endtape()) { /* seemingly empty volume */
39770Sstevel@tonic-gate (void) fprintf(stderr, gettext(
39780Sstevel@tonic-gate "tar: first record is null\n"));
39790Sstevel@tonic-gate asknicely:
39800Sstevel@tonic-gate (void) fprintf(stderr, gettext(
39810Sstevel@tonic-gate "tar: need volume with extent #%d of %s\n"),
39820Sstevel@tonic-gate i, name);
39830Sstevel@tonic-gate goto tryagain;
39840Sstevel@tonic-gate }
39850Sstevel@tonic-gate if (notsame()) {
39860Sstevel@tonic-gate (void) fprintf(stderr, gettext(
39870Sstevel@tonic-gate "tar: first file on that volume is not "
39880Sstevel@tonic-gate "the same file\n"));
39890Sstevel@tonic-gate goto asknicely;
39900Sstevel@tonic-gate }
39910Sstevel@tonic-gate if (i != extno) {
39920Sstevel@tonic-gate (void) fprintf(stderr, gettext(
39931266Sceastha "tar: extent #%d received out of order\ntar: "
39941266Sceastha "should be #%d\n"), extno, i);
39950Sstevel@tonic-gate (void) fprintf(stderr, gettext(
39960Sstevel@tonic-gate "Ignore error, Abort this file, or "
39970Sstevel@tonic-gate "load New volume (i/a/n) ? "));
39980Sstevel@tonic-gate c = response();
39990Sstevel@tonic-gate if (c == 'a')
40000Sstevel@tonic-gate goto canit;
40010Sstevel@tonic-gate if (c != 'i') /* default to new volume */
40020Sstevel@tonic-gate goto asknicely;
40030Sstevel@tonic-gate i = extno; /* okay, start from there */
40040Sstevel@tonic-gate }
40050Sstevel@tonic-gate }
40060Sstevel@tonic-gate if (vflag)
40070Sstevel@tonic-gate (void) fprintf(vfile, gettext(
40080Sstevel@tonic-gate "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
40090Sstevel@tonic-gate name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
40105331Samw
40115331Samw return (0);
40120Sstevel@tonic-gate }
40130Sstevel@tonic-gate
40140Sstevel@tonic-gate
40150Sstevel@tonic-gate /*
40160Sstevel@tonic-gate * notsame() check if extract file extent is invalid
40170Sstevel@tonic-gate *
40180Sstevel@tonic-gate * returns true if anything differs between savedblock and dblock
40190Sstevel@tonic-gate * except extno (extent number), checksum, or size (extent size).
40200Sstevel@tonic-gate * Determines if this header belongs to the same file as the one we're
40210Sstevel@tonic-gate * extracting.
40220Sstevel@tonic-gate *
40230Sstevel@tonic-gate * NOTE: though rather bulky, it is only called once per file
40240Sstevel@tonic-gate * extension, and it can withstand changes in the definition
40250Sstevel@tonic-gate * of the header structure.
40260Sstevel@tonic-gate *
40270Sstevel@tonic-gate * WARNING: this routine is local to xsfile() above
40280Sstevel@tonic-gate */
40290Sstevel@tonic-gate
40300Sstevel@tonic-gate static int
notsame(void)40310Sstevel@tonic-gate notsame(void)
40320Sstevel@tonic-gate {
40330Sstevel@tonic-gate return (
40340Sstevel@tonic-gate (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
40350Sstevel@tonic-gate (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
40360Sstevel@tonic-gate (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
40370Sstevel@tonic-gate (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
40380Sstevel@tonic-gate (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
40390Sstevel@tonic-gate (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
40400Sstevel@tonic-gate (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
40410Sstevel@tonic-gate (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
40420Sstevel@tonic-gate (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
40430Sstevel@tonic-gate }
40440Sstevel@tonic-gate
40450Sstevel@tonic-gate static void
dotable(char * argv[])40460Sstevel@tonic-gate dotable(char *argv[])
4047*12836Srich.burridge@oracle.com {
4048*12836Srich.burridge@oracle.com int tcnt = 0; /* count # files tabled */
4049*12836Srich.burridge@oracle.com int fcnt = 0; /* count # files in argv list */
40500Sstevel@tonic-gate char *namep, *dirp, *comp;
40510Sstevel@tonic-gate int want;
40520Sstevel@tonic-gate char aclchar = ' '; /* either blank or '+' */
40530Sstevel@tonic-gate char templink[PATH_MAX+1];
40545331Samw attr_data_t *attrinfo = NULL;
40550Sstevel@tonic-gate
40560Sstevel@tonic-gate dumping = 0;
40570Sstevel@tonic-gate
40580Sstevel@tonic-gate /* if not on magtape, maximize seek speed */
40590Sstevel@tonic-gate if (NotTape && !bflag) {
40600Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
40610Sstevel@tonic-gate nblock = SYS_BLOCK / TBLOCK;
40620Sstevel@tonic-gate #else
40630Sstevel@tonic-gate nblock = 1;
40640Sstevel@tonic-gate #endif
40650Sstevel@tonic-gate }
40660Sstevel@tonic-gate
40670Sstevel@tonic-gate for (;;) {
40680Sstevel@tonic-gate
40690Sstevel@tonic-gate /* namep is set by wantit to point to the full name */
40705331Samw if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
40710Sstevel@tonic-gate continue;
40720Sstevel@tonic-gate if (want == -1)
40730Sstevel@tonic-gate break;
40740Sstevel@tonic-gate if (dblock.dbuf.typeflag != 'A')
40750Sstevel@tonic-gate ++tcnt;
40760Sstevel@tonic-gate
407712423Srich.burridge@oracle.com if (Fflag) {
407812423Srich.burridge@oracle.com if (checkf(namep, is_directory(namep), Fflag) == 0) {
407912423Srich.burridge@oracle.com passtape();
408012423Srich.burridge@oracle.com continue;
408112423Srich.burridge@oracle.com }
408212423Srich.burridge@oracle.com }
40830Sstevel@tonic-gate /*
40840Sstevel@tonic-gate * ACL support:
40850Sstevel@tonic-gate * aclchar is introduced to indicate if there are
40860Sstevel@tonic-gate * acl entries. longt() now takes one extra argument.
40870Sstevel@tonic-gate */
40880Sstevel@tonic-gate if (vflag) {
40890Sstevel@tonic-gate if (dblock.dbuf.typeflag == 'A') {
40900Sstevel@tonic-gate aclchar = '+';
40910Sstevel@tonic-gate passtape();
40920Sstevel@tonic-gate continue;
40930Sstevel@tonic-gate }
40940Sstevel@tonic-gate longt(&stbuf, aclchar);
40950Sstevel@tonic-gate aclchar = ' ';
40960Sstevel@tonic-gate }
40970Sstevel@tonic-gate
40980Sstevel@tonic-gate
40990Sstevel@tonic-gate #if defined(O_XATTR)
41005331Samw if (xattrp != NULL) {
41015331Samw int issysattr;
41025331Samw char *bn = basename(attrinfo->attr_path);
41035331Samw
41045331Samw /*
41055331Samw * We could use sysattr_type() to test whether or not
41065331Samw * the attribute we are processing is really an
41075331Samw * extended system attribute, which as of this writing
41085331Samw * just does a strcmp(), however, sysattr_type() may
41095331Samw * be changed to issue a pathconf() call instead, which
41105331Samw * would require being changed into the parent attribute
41115331Samw * directory. So instead, just do simple string
41125331Samw * comparisons to see if we are processing an extended
41135331Samw * system attribute.
41145331Samw */
41155331Samw issysattr = is_sysattr(bn);
41165331Samw
41175331Samw (void) printf(gettext("%s %sattribute %s"),
41185331Samw xattrp->h_names,
41195331Samw issysattr ? gettext("system ") : "",
41205331Samw attrinfo->attr_path);
41210Sstevel@tonic-gate } else {
41220Sstevel@tonic-gate (void) printf("%s", namep);
41230Sstevel@tonic-gate }
41240Sstevel@tonic-gate #else
41250Sstevel@tonic-gate (void) printf("%s", namep);
41260Sstevel@tonic-gate #endif
41270Sstevel@tonic-gate
41280Sstevel@tonic-gate if (extno != 0) {
41290Sstevel@tonic-gate if (vflag) {
41300Sstevel@tonic-gate /* keep the '\n' for backwards compatibility */
41310Sstevel@tonic-gate (void) fprintf(vfile, gettext(
41320Sstevel@tonic-gate "\n [extent #%d of %d]"), extno, extotal);
41330Sstevel@tonic-gate } else {
41340Sstevel@tonic-gate (void) fprintf(vfile, gettext(
41350Sstevel@tonic-gate " [extent #%d of %d]"), extno, extotal);
41360Sstevel@tonic-gate }
41370Sstevel@tonic-gate }
41380Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) {
41390Sstevel@tonic-gate (void) strcpy(templink, Xtarhdr.x_linkpath);
41400Sstevel@tonic-gate } else {
41410Sstevel@tonic-gate #if defined(O_XATTR)
41425331Samw if (xattrp != NULL) {
41430Sstevel@tonic-gate (void) sprintf(templink,
41440Sstevel@tonic-gate "file %.*s", NAMSIZ, xattrp->h_names);
41450Sstevel@tonic-gate } else {
41460Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ,
41470Sstevel@tonic-gate dblock.dbuf.linkname);
41480Sstevel@tonic-gate }
41490Sstevel@tonic-gate #else
41500Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ,
41510Sstevel@tonic-gate dblock.dbuf.linkname);
41520Sstevel@tonic-gate #endif
41530Sstevel@tonic-gate templink[NAMSIZ] = '\0';
41540Sstevel@tonic-gate }
41550Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1') {
41560Sstevel@tonic-gate /*
41570Sstevel@tonic-gate * TRANSLATION_NOTE
41580Sstevel@tonic-gate * Subject is omitted here.
41590Sstevel@tonic-gate * Translate this as if
41600Sstevel@tonic-gate * <subject> linked to %s
41610Sstevel@tonic-gate */
41620Sstevel@tonic-gate #if defined(O_XATTR)
41635331Samw if (xattrp != NULL) {
41640Sstevel@tonic-gate (void) printf(
41650Sstevel@tonic-gate gettext(" linked to attribute %s"),
41660Sstevel@tonic-gate xattr_linkp->h_names +
41670Sstevel@tonic-gate strlen(xattr_linkp->h_names) + 1);
41680Sstevel@tonic-gate } else {
41690Sstevel@tonic-gate (void) printf(
41700Sstevel@tonic-gate gettext(" linked to %s"), templink);
41710Sstevel@tonic-gate }
41720Sstevel@tonic-gate #else
41730Sstevel@tonic-gate (void) printf(
41740Sstevel@tonic-gate gettext(" linked to %s"), templink);
41750Sstevel@tonic-gate
41760Sstevel@tonic-gate #endif
41770Sstevel@tonic-gate }
41780Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2')
41790Sstevel@tonic-gate (void) printf(gettext(
41800Sstevel@tonic-gate /*
41810Sstevel@tonic-gate * TRANSLATION_NOTE
41820Sstevel@tonic-gate * Subject is omitted here.
41830Sstevel@tonic-gate * Translate this as if
41840Sstevel@tonic-gate * <subject> symbolic link to %s
41850Sstevel@tonic-gate */
41860Sstevel@tonic-gate " symbolic link to %s"), templink);
41870Sstevel@tonic-gate (void) printf("\n");
41880Sstevel@tonic-gate #if defined(O_XATTR)
41895331Samw if (xattrp != NULL) {
41900Sstevel@tonic-gate free(xattrhead);
41910Sstevel@tonic-gate xattrp = NULL;
41920Sstevel@tonic-gate xattrhead = NULL;
41930Sstevel@tonic-gate }
41940Sstevel@tonic-gate #endif
41950Sstevel@tonic-gate passtape();
41960Sstevel@tonic-gate }
41970Sstevel@tonic-gate /*
41980Sstevel@tonic-gate * Check if the number of files tabled is different from the
41990Sstevel@tonic-gate * number of files listed on the command line
42000Sstevel@tonic-gate */
42010Sstevel@tonic-gate if (fcnt > tcnt) {
42020Sstevel@tonic-gate (void) fprintf(stderr, gettext(
42030Sstevel@tonic-gate "tar: %d file(s) not found\n"), fcnt-tcnt);
42040Sstevel@tonic-gate Errflg = 1;
42050Sstevel@tonic-gate }
42060Sstevel@tonic-gate }
42070Sstevel@tonic-gate
42080Sstevel@tonic-gate static void
putempty(blkcnt_t n)42090Sstevel@tonic-gate putempty(blkcnt_t n)
42100Sstevel@tonic-gate {
42110Sstevel@tonic-gate char buf[TBLOCK];
42120Sstevel@tonic-gate char *cp;
42130Sstevel@tonic-gate
42140Sstevel@tonic-gate for (cp = buf; cp < &buf[TBLOCK]; )
42150Sstevel@tonic-gate *cp++ = '\0';
42160Sstevel@tonic-gate while (n-- > 0)
42170Sstevel@tonic-gate (void) writetbuf(buf, 1);
42180Sstevel@tonic-gate }
42190Sstevel@tonic-gate
42200Sstevel@tonic-gate static ushort_t Ftype = S_IFMT;
42210Sstevel@tonic-gate
42220Sstevel@tonic-gate static void
verbose(struct stat * st,char aclchar)42230Sstevel@tonic-gate verbose(struct stat *st, char aclchar)
42240Sstevel@tonic-gate {
42250Sstevel@tonic-gate int i, j, temp;
42260Sstevel@tonic-gate mode_t mode;
42270Sstevel@tonic-gate char modestr[12];
42280Sstevel@tonic-gate
42290Sstevel@tonic-gate for (i = 0; i < 11; i++)
42300Sstevel@tonic-gate modestr[i] = '-';
42310Sstevel@tonic-gate modestr[i] = '\0';
42320Sstevel@tonic-gate
42330Sstevel@tonic-gate /* a '+' sign is printed if there is ACL */
42340Sstevel@tonic-gate modestr[i-1] = aclchar;
42350Sstevel@tonic-gate
42360Sstevel@tonic-gate mode = st->st_mode;
42370Sstevel@tonic-gate for (i = 0; i < 3; i++) {
42380Sstevel@tonic-gate temp = (mode >> (6 - (i * 3)));
42390Sstevel@tonic-gate j = (i * 3) + 1;
42400Sstevel@tonic-gate if (S_IROTH & temp)
42410Sstevel@tonic-gate modestr[j] = 'r';
42420Sstevel@tonic-gate if (S_IWOTH & temp)
42430Sstevel@tonic-gate modestr[j + 1] = 'w';
42440Sstevel@tonic-gate if (S_IXOTH & temp)
42450Sstevel@tonic-gate modestr[j + 2] = 'x';
42460Sstevel@tonic-gate }
42470Sstevel@tonic-gate temp = st->st_mode & Ftype;
42480Sstevel@tonic-gate switch (temp) {
42490Sstevel@tonic-gate case (S_IFIFO):
42500Sstevel@tonic-gate modestr[0] = 'p';
42510Sstevel@tonic-gate break;
42520Sstevel@tonic-gate case (S_IFCHR):
42530Sstevel@tonic-gate modestr[0] = 'c';
42540Sstevel@tonic-gate break;
42550Sstevel@tonic-gate case (S_IFDIR):
42560Sstevel@tonic-gate modestr[0] = 'd';
42570Sstevel@tonic-gate break;
42580Sstevel@tonic-gate case (S_IFBLK):
42590Sstevel@tonic-gate modestr[0] = 'b';
42600Sstevel@tonic-gate break;
42610Sstevel@tonic-gate case (S_IFREG): /* was initialized to '-' */
42620Sstevel@tonic-gate break;
42630Sstevel@tonic-gate case (S_IFLNK):
42640Sstevel@tonic-gate modestr[0] = 'l';
42650Sstevel@tonic-gate break;
42660Sstevel@tonic-gate default:
42670Sstevel@tonic-gate /* This field may be zero in old archives. */
42680Sstevel@tonic-gate if (is_posix && dblock.dbuf.typeflag != '1') {
42690Sstevel@tonic-gate /*
42700Sstevel@tonic-gate * For POSIX compliant archives, the mode field
42710Sstevel@tonic-gate * consists of 12 bits, ie: the file type bits
42720Sstevel@tonic-gate * are not stored in dblock.dbuf.mode.
42730Sstevel@tonic-gate * For files other than hard links, getdir() sets
42740Sstevel@tonic-gate * the file type bits in the st_mode field of the
42750Sstevel@tonic-gate * stat structure based upon dblock.dbuf.typeflag.
42760Sstevel@tonic-gate */
42770Sstevel@tonic-gate (void) fprintf(stderr, gettext(
42780Sstevel@tonic-gate "tar: impossible file type"));
42790Sstevel@tonic-gate }
42800Sstevel@tonic-gate }
42810Sstevel@tonic-gate
42820Sstevel@tonic-gate if ((S_ISUID & Gen.g_mode) == S_ISUID)
42830Sstevel@tonic-gate modestr[3] = 's';
42840Sstevel@tonic-gate if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
42850Sstevel@tonic-gate modestr[9] = 't';
42860Sstevel@tonic-gate if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
42870Sstevel@tonic-gate modestr[6] = 's';
42880Sstevel@tonic-gate else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
42890Sstevel@tonic-gate modestr[6] = 'l';
42900Sstevel@tonic-gate (void) fprintf(vfile, "%s", modestr);
42910Sstevel@tonic-gate }
42920Sstevel@tonic-gate
42930Sstevel@tonic-gate static void
longt(struct stat * st,char aclchar)42940Sstevel@tonic-gate longt(struct stat *st, char aclchar)
42950Sstevel@tonic-gate {
42960Sstevel@tonic-gate char fileDate[30];
42970Sstevel@tonic-gate struct tm *tm;
42980Sstevel@tonic-gate
42990Sstevel@tonic-gate verbose(st, aclchar);
43000Sstevel@tonic-gate (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
43010Sstevel@tonic-gate
43020Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2') {
43030Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH)
43040Sstevel@tonic-gate st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
43050Sstevel@tonic-gate else
43060Sstevel@tonic-gate st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
43070Sstevel@tonic-gate '\0', NAMSIZ) ?
43080Sstevel@tonic-gate (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
43090Sstevel@tonic-gate }
43100Sstevel@tonic-gate (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
43110Sstevel@tonic-gate
43120Sstevel@tonic-gate tm = localtime(&(st->st_mtime));
43130Sstevel@tonic-gate (void) strftime(fileDate, sizeof (fileDate),
43140Sstevel@tonic-gate dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
43150Sstevel@tonic-gate (void) fprintf(vfile, " %s ", fileDate);
43160Sstevel@tonic-gate }
43170Sstevel@tonic-gate
43180Sstevel@tonic-gate
43190Sstevel@tonic-gate /*
43200Sstevel@tonic-gate * checkdir - Attempt to ensure that the path represented in name
43210Sstevel@tonic-gate * exists, and return 1 if this is true and name itself is a
43220Sstevel@tonic-gate * directory.
43230Sstevel@tonic-gate * Return 0 if this path cannot be created or if name is not
43240Sstevel@tonic-gate * a directory.
43250Sstevel@tonic-gate */
43260Sstevel@tonic-gate
43270Sstevel@tonic-gate static int
checkdir(char * name)43280Sstevel@tonic-gate checkdir(char *name)
43290Sstevel@tonic-gate {
43300Sstevel@tonic-gate char lastChar; /* the last character in name */
43310Sstevel@tonic-gate char *cp; /* scratch pointer into name */
43320Sstevel@tonic-gate char *firstSlash = NULL; /* first slash in name */
43330Sstevel@tonic-gate char *lastSlash = NULL; /* last slash in name */
43340Sstevel@tonic-gate int nameLen; /* length of name */
43350Sstevel@tonic-gate int trailingSlash; /* true if name ends in slash */
43360Sstevel@tonic-gate int leadingSlash; /* true if name begins with slash */
43370Sstevel@tonic-gate int markedDir; /* true if name denotes a directory */
43380Sstevel@tonic-gate int success; /* status of makeDir call */
43390Sstevel@tonic-gate
43400Sstevel@tonic-gate
43410Sstevel@tonic-gate /*
43420Sstevel@tonic-gate * Scan through the name, and locate first and last slashes.
43430Sstevel@tonic-gate */
43440Sstevel@tonic-gate
43450Sstevel@tonic-gate for (cp = name; *cp; cp++) {
43460Sstevel@tonic-gate if (*cp == '/') {
43470Sstevel@tonic-gate if (! firstSlash) {
43480Sstevel@tonic-gate firstSlash = cp;
43490Sstevel@tonic-gate }
43500Sstevel@tonic-gate lastSlash = cp;
43510Sstevel@tonic-gate }
43520Sstevel@tonic-gate }
43530Sstevel@tonic-gate
43540Sstevel@tonic-gate /*
43550Sstevel@tonic-gate * Determine what you can from the proceeds of the scan.
43560Sstevel@tonic-gate */
43570Sstevel@tonic-gate
43580Sstevel@tonic-gate lastChar = *(cp - 1);
43590Sstevel@tonic-gate nameLen = (int)(cp - name);
43600Sstevel@tonic-gate trailingSlash = (lastChar == '/');
43610Sstevel@tonic-gate leadingSlash = (*name == '/');
43620Sstevel@tonic-gate markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
43630Sstevel@tonic-gate
43640Sstevel@tonic-gate if (! lastSlash && ! markedDir) {
43650Sstevel@tonic-gate /*
43660Sstevel@tonic-gate * The named file does not have any subdrectory
43670Sstevel@tonic-gate * structure; just bail out.
43680Sstevel@tonic-gate */
43690Sstevel@tonic-gate
43700Sstevel@tonic-gate return (0);
43710Sstevel@tonic-gate }
43720Sstevel@tonic-gate
43730Sstevel@tonic-gate /*
43740Sstevel@tonic-gate * Make sure that name doesn`t end with slash for the loop.
43750Sstevel@tonic-gate * This ensures that the makeDir attempt after the loop is
43760Sstevel@tonic-gate * meaningful.
43770Sstevel@tonic-gate */
43780Sstevel@tonic-gate
43790Sstevel@tonic-gate if (trailingSlash) {
43800Sstevel@tonic-gate name[nameLen-1] = '\0';
43810Sstevel@tonic-gate }
43820Sstevel@tonic-gate
43830Sstevel@tonic-gate /*
43840Sstevel@tonic-gate * Make the path one component at a time.
43850Sstevel@tonic-gate */
43860Sstevel@tonic-gate
43870Sstevel@tonic-gate for (cp = strchr(leadingSlash ? name+1 : name, '/');
43880Sstevel@tonic-gate cp;
43890Sstevel@tonic-gate cp = strchr(cp+1, '/')) {
43900Sstevel@tonic-gate *cp = '\0';
43910Sstevel@tonic-gate success = makeDir(name);
43920Sstevel@tonic-gate *cp = '/';
43930Sstevel@tonic-gate
43940Sstevel@tonic-gate if (!success) {
43950Sstevel@tonic-gate name[nameLen-1] = lastChar;
43960Sstevel@tonic-gate return (0);
43970Sstevel@tonic-gate }
43980Sstevel@tonic-gate }
43990Sstevel@tonic-gate
44000Sstevel@tonic-gate /*
44010Sstevel@tonic-gate * This makes the last component of the name, if it is a
44020Sstevel@tonic-gate * directory.
44030Sstevel@tonic-gate */
44040Sstevel@tonic-gate
44050Sstevel@tonic-gate if (markedDir) {
44060Sstevel@tonic-gate if (! makeDir(name)) {
44070Sstevel@tonic-gate name[nameLen-1] = lastChar;
44080Sstevel@tonic-gate return (0);
44090Sstevel@tonic-gate }
44100Sstevel@tonic-gate }
44110Sstevel@tonic-gate
44120Sstevel@tonic-gate name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
44130Sstevel@tonic-gate return (markedDir);
44140Sstevel@tonic-gate }
44150Sstevel@tonic-gate
44160Sstevel@tonic-gate /*
44170Sstevel@tonic-gate * resugname - Restore the user name and group name. Search the NIS
44180Sstevel@tonic-gate * before using the uid and gid.
44190Sstevel@tonic-gate * (It is presumed that an archive entry cannot be
44200Sstevel@tonic-gate * simultaneously a symlink and some other type.)
44210Sstevel@tonic-gate */
44220Sstevel@tonic-gate
44230Sstevel@tonic-gate static void
resugname(int dirfd,char * name,int symflag)44240Sstevel@tonic-gate resugname(int dirfd, /* dir fd file resides in */
44250Sstevel@tonic-gate char *name, /* name of the file to be modified */
44260Sstevel@tonic-gate int symflag) /* true if file is a symbolic link */
44270Sstevel@tonic-gate {
44280Sstevel@tonic-gate uid_t duid;
44290Sstevel@tonic-gate gid_t dgid;
44300Sstevel@tonic-gate struct stat *sp = &stbuf;
44310Sstevel@tonic-gate char *u_g_name;
44320Sstevel@tonic-gate
44330Sstevel@tonic-gate if (checkflag == 1) { /* Extended tar format and euid == 0 */
44340Sstevel@tonic-gate
44350Sstevel@tonic-gate /*
44360Sstevel@tonic-gate * Try and extract the intended uid and gid from the name
44370Sstevel@tonic-gate * service before believing the uid and gid in the header.
44380Sstevel@tonic-gate *
44390Sstevel@tonic-gate * In the case where we archived a setuid or setgid file
44400Sstevel@tonic-gate * owned by someone with a large uid, then it will
44410Sstevel@tonic-gate * have made it into the archive with a uid of nobody. If
44420Sstevel@tonic-gate * the corresponding username doesn't appear to exist, then we
44430Sstevel@tonic-gate * want to make sure it *doesn't* end up as setuid nobody!
44440Sstevel@tonic-gate *
44450Sstevel@tonic-gate * Our caller will print an error message about the fact
44460Sstevel@tonic-gate * that the restore didn't work out quite right ..
44470Sstevel@tonic-gate */
44480Sstevel@tonic-gate if (xhdr_flgs & _X_UNAME)
44490Sstevel@tonic-gate u_g_name = Xtarhdr.x_uname;
44500Sstevel@tonic-gate else
44510Sstevel@tonic-gate u_g_name = dblock.dbuf.uname;
44520Sstevel@tonic-gate if ((duid = getuidbyname(u_g_name)) == -1) {
44530Sstevel@tonic-gate if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
44540Sstevel@tonic-gate (sp->st_mode & S_ISUID) == S_ISUID)
44550Sstevel@tonic-gate (void) chmod(name,
44561266Sceastha MODEMASK & sp->st_mode & ~S_ISUID);
44570Sstevel@tonic-gate duid = sp->st_uid;
44580Sstevel@tonic-gate }
44590Sstevel@tonic-gate
44600Sstevel@tonic-gate /* (Ditto for gids) */
44610Sstevel@tonic-gate
44620Sstevel@tonic-gate if (xhdr_flgs & _X_GNAME)
44630Sstevel@tonic-gate u_g_name = Xtarhdr.x_gname;
44640Sstevel@tonic-gate else
44650Sstevel@tonic-gate u_g_name = dblock.dbuf.gname;
44660Sstevel@tonic-gate if ((dgid = getgidbyname(u_g_name)) == -1) {
44670Sstevel@tonic-gate if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
44680Sstevel@tonic-gate (sp->st_mode & S_ISGID) == S_ISGID)
44690Sstevel@tonic-gate (void) chmod(name,
44701266Sceastha MODEMASK & sp->st_mode & ~S_ISGID);
44710Sstevel@tonic-gate dgid = sp->st_gid;
44720Sstevel@tonic-gate }
44730Sstevel@tonic-gate } else if (checkflag == 2) { /* tar format and euid == 0 */
44740Sstevel@tonic-gate duid = sp->st_uid;
44750Sstevel@tonic-gate dgid = sp->st_gid;
44760Sstevel@tonic-gate }
44770Sstevel@tonic-gate if ((checkflag == 1) || (checkflag == 2))
44780Sstevel@tonic-gate (void) fchownat(dirfd, name, duid, dgid, symflag);
44790Sstevel@tonic-gate }
44800Sstevel@tonic-gate
44810Sstevel@tonic-gate /*ARGSUSED*/
44820Sstevel@tonic-gate static void
onintr(int sig)44830Sstevel@tonic-gate onintr(int sig)
44840Sstevel@tonic-gate {
44850Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN);
44860Sstevel@tonic-gate term++;
44870Sstevel@tonic-gate }
44880Sstevel@tonic-gate
44890Sstevel@tonic-gate /*ARGSUSED*/
44900Sstevel@tonic-gate static void
onquit(int sig)44910Sstevel@tonic-gate onquit(int sig)
44920Sstevel@tonic-gate {
44930Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN);
44940Sstevel@tonic-gate term++;
44950Sstevel@tonic-gate }
44960Sstevel@tonic-gate
44970Sstevel@tonic-gate /*ARGSUSED*/
44980Sstevel@tonic-gate static void
onhup(int sig)44990Sstevel@tonic-gate onhup(int sig)
45000Sstevel@tonic-gate {
45010Sstevel@tonic-gate (void) signal(SIGHUP, SIG_IGN);
45020Sstevel@tonic-gate term++;
45030Sstevel@tonic-gate }
45040Sstevel@tonic-gate
45050Sstevel@tonic-gate static void
tomodes(struct stat * sp)45060Sstevel@tonic-gate tomodes(struct stat *sp)
45070Sstevel@tonic-gate {
45080Sstevel@tonic-gate uid_t uid;
45090Sstevel@tonic-gate gid_t gid;
45100Sstevel@tonic-gate
45110Sstevel@tonic-gate bzero(dblock.dummy, TBLOCK);
45120Sstevel@tonic-gate
45130Sstevel@tonic-gate /*
45140Sstevel@tonic-gate * If the uid or gid is too large, we can't put it into
45150Sstevel@tonic-gate * the archive. We could fail to put anything in the
45160Sstevel@tonic-gate * archive at all .. but most of the time the name service
45170Sstevel@tonic-gate * will save the day when we do a lookup at restore time.
45180Sstevel@tonic-gate *
45190Sstevel@tonic-gate * Instead we choose a "safe" uid and gid, and fix up whether
45200Sstevel@tonic-gate * or not the setuid and setgid bits are left set to extraction
45210Sstevel@tonic-gate * time.
45220Sstevel@tonic-gate */
45230Sstevel@tonic-gate if (Eflag) {
45240Sstevel@tonic-gate if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
45250Sstevel@tonic-gate xhdr_flgs |= _X_UID;
45260Sstevel@tonic-gate Xtarhdr.x_uid = uid;
45270Sstevel@tonic-gate }
45280Sstevel@tonic-gate if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
45290Sstevel@tonic-gate xhdr_flgs |= _X_GID;
45300Sstevel@tonic-gate Xtarhdr.x_gid = gid;
45310Sstevel@tonic-gate }
45320Sstevel@tonic-gate if (sp->st_size > TAR_OFFSET_MAX) {
45330Sstevel@tonic-gate xhdr_flgs |= _X_SIZE;
45340Sstevel@tonic-gate Xtarhdr.x_filesz = sp->st_size;
45350Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
45360Sstevel@tonic-gate (off_t)0);
45370Sstevel@tonic-gate } else
45380Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
45390Sstevel@tonic-gate sp->st_size);
45400Sstevel@tonic-gate } else {
45410Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
45420Sstevel@tonic-gate sp->st_size);
45430Sstevel@tonic-gate }
45440Sstevel@tonic-gate if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
45450Sstevel@tonic-gate uid = UID_NOBODY;
45460Sstevel@tonic-gate if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
45470Sstevel@tonic-gate gid = GID_NOBODY;
45480Sstevel@tonic-gate (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
45490Sstevel@tonic-gate (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
45500Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
45510Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
45520Sstevel@tonic-gate }
45530Sstevel@tonic-gate
45540Sstevel@tonic-gate static int
45550Sstevel@tonic-gate #ifdef EUC
45560Sstevel@tonic-gate /*
45570Sstevel@tonic-gate * Warning: the result of this function depends whether 'char' is a
45580Sstevel@tonic-gate * signed or unsigned data type. This a source of potential
45590Sstevel@tonic-gate * non-portability among heterogeneous systems. It is retained here
45600Sstevel@tonic-gate * for backward compatibility.
45610Sstevel@tonic-gate */
checksum_signed(union hblock * dblockp)45620Sstevel@tonic-gate checksum_signed(union hblock *dblockp)
45630Sstevel@tonic-gate #else
45640Sstevel@tonic-gate checksum(union hblock *dblockp)
45650Sstevel@tonic-gate #endif /* EUC */
45660Sstevel@tonic-gate {
45670Sstevel@tonic-gate int i;
45680Sstevel@tonic-gate char *cp;
45690Sstevel@tonic-gate
45700Sstevel@tonic-gate for (cp = dblockp->dbuf.chksum;
45710Sstevel@tonic-gate cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
45720Sstevel@tonic-gate *cp = ' ';
45730Sstevel@tonic-gate i = 0;
45740Sstevel@tonic-gate for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
45750Sstevel@tonic-gate i += *cp;
45760Sstevel@tonic-gate return (i);
45770Sstevel@tonic-gate }
45780Sstevel@tonic-gate
45790Sstevel@tonic-gate #ifdef EUC
45800Sstevel@tonic-gate /*
45810Sstevel@tonic-gate * Generate unsigned checksum, regardless of what C compiler is
45820Sstevel@tonic-gate * used. Survives in the face of arbitrary 8-bit clean filenames,
45830Sstevel@tonic-gate * e.g., internationalized filenames.
45840Sstevel@tonic-gate */
45850Sstevel@tonic-gate static int
checksum(union hblock * dblockp)45860Sstevel@tonic-gate checksum(union hblock *dblockp)
45870Sstevel@tonic-gate {
45880Sstevel@tonic-gate unsigned i;
45890Sstevel@tonic-gate unsigned char *cp;
45900Sstevel@tonic-gate
45910Sstevel@tonic-gate for (cp = (unsigned char *) dblockp->dbuf.chksum;
45920Sstevel@tonic-gate cp < (unsigned char *)
45930Sstevel@tonic-gate &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
45940Sstevel@tonic-gate *cp = ' ';
45950Sstevel@tonic-gate i = 0;
45960Sstevel@tonic-gate for (cp = (unsigned char *) dblockp->dummy;
45970Sstevel@tonic-gate cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
45980Sstevel@tonic-gate i += *cp;
45990Sstevel@tonic-gate
46000Sstevel@tonic-gate return (i);
46010Sstevel@tonic-gate }
46020Sstevel@tonic-gate #endif /* EUC */
46030Sstevel@tonic-gate
46040Sstevel@tonic-gate /*
46050Sstevel@tonic-gate * If the w flag is set, output the action to be taken and the name of the
46060Sstevel@tonic-gate * file. Perform the action if the user response is affirmative.
46070Sstevel@tonic-gate */
46080Sstevel@tonic-gate
46090Sstevel@tonic-gate static int
checkw(char c,char * name)46100Sstevel@tonic-gate checkw(char c, char *name)
46110Sstevel@tonic-gate {
46120Sstevel@tonic-gate if (wflag) {
46130Sstevel@tonic-gate (void) fprintf(vfile, "%c ", c);
46140Sstevel@tonic-gate if (vflag)
46150Sstevel@tonic-gate longt(&stbuf, ' '); /* do we have acl info here */
46160Sstevel@tonic-gate (void) fprintf(vfile, "%s: ", name);
46174774Sas145665 if (yes() == 1) {
46180Sstevel@tonic-gate return (1);
46190Sstevel@tonic-gate }
46200Sstevel@tonic-gate return (0);
46210Sstevel@tonic-gate }
46220Sstevel@tonic-gate return (1);
46230Sstevel@tonic-gate }
46240Sstevel@tonic-gate
46250Sstevel@tonic-gate /*
462612423Srich.burridge@oracle.com * When the F flag is set, exclude RCS and SCCS directories (and any files
462712423Srich.burridge@oracle.com * or directories under them). If F is set twice, also exclude .o files,
462812423Srich.burridge@oracle.com * and files names errs, core, and a.out.
462912423Srich.burridge@oracle.com *
463012423Srich.burridge@oracle.com * Return 0 if file should be excluded, 1 otherwise.
46310Sstevel@tonic-gate */
46320Sstevel@tonic-gate
46330Sstevel@tonic-gate static int
checkf(char * longname,int is_dir,int howmuch)463412423Srich.burridge@oracle.com checkf(char *longname, int is_dir, int howmuch)
463512423Srich.burridge@oracle.com {
463612423Srich.burridge@oracle.com static char fullname[PATH_MAX + 1];
463712423Srich.burridge@oracle.com char *dir, *name;
463812423Srich.burridge@oracle.com
463912423Srich.burridge@oracle.com #if defined(O_XATTR)
464012423Srich.burridge@oracle.com /*
464112423Srich.burridge@oracle.com * If there is an xattr_buf structure associated with this file,
464212423Srich.burridge@oracle.com * always return 1.
464312423Srich.burridge@oracle.com */
464412423Srich.burridge@oracle.com if (xattrp) {
464512423Srich.burridge@oracle.com return (1);
464612423Srich.burridge@oracle.com }
464712423Srich.burridge@oracle.com #endif
464812423Srich.burridge@oracle.com
464912423Srich.burridge@oracle.com /*
465012423Srich.burridge@oracle.com * First check to see if the base name is an RCS or SCCS directory.
465112423Srich.burridge@oracle.com */
465212423Srich.burridge@oracle.com if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
465312423Srich.burridge@oracle.com return (1);
465412423Srich.burridge@oracle.com
465512423Srich.burridge@oracle.com name = basename(fullname);
465612423Srich.burridge@oracle.com if (is_dir) {
46570Sstevel@tonic-gate if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
46580Sstevel@tonic-gate return (0);
465912423Srich.burridge@oracle.com }
466012423Srich.burridge@oracle.com
466112423Srich.burridge@oracle.com /*
466212423Srich.burridge@oracle.com * If two -F command line options were given then exclude .o files,
466312423Srich.burridge@oracle.com * and files named errs, core, and a.out.
466412423Srich.burridge@oracle.com */
466512423Srich.burridge@oracle.com if (howmuch > 1 && !is_dir) {
466612423Srich.burridge@oracle.com size_t l = strlen(name);
466712423Srich.burridge@oracle.com
466812423Srich.burridge@oracle.com if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
466912423Srich.burridge@oracle.com return (0);
46700Sstevel@tonic-gate if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
46710Sstevel@tonic-gate strcmp(name, "a.out") == 0)
46720Sstevel@tonic-gate return (0);
46730Sstevel@tonic-gate }
46740Sstevel@tonic-gate
467512423Srich.burridge@oracle.com /*
467612423Srich.burridge@oracle.com * At this point, check to see if this file has a parent directory
467712423Srich.burridge@oracle.com * named RCS or SCCS. If so, then this file should be excluded too.
467812423Srich.burridge@oracle.com * The strcpy() operation is done again, because basename(3C) may
467912423Srich.burridge@oracle.com * modify the path string passed to it.
468012423Srich.burridge@oracle.com */
468112423Srich.burridge@oracle.com if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
468212423Srich.burridge@oracle.com return (1);
468312423Srich.burridge@oracle.com
468412423Srich.burridge@oracle.com dir = dirname(fullname);
468512423Srich.burridge@oracle.com while (strcmp(dir, ".") != 0) {
468612423Srich.burridge@oracle.com name = basename(dir);
468712423Srich.burridge@oracle.com if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
468812423Srich.burridge@oracle.com return (0);
468912423Srich.burridge@oracle.com dir = dirname(dir);
469012423Srich.burridge@oracle.com }
469112423Srich.burridge@oracle.com
46920Sstevel@tonic-gate return (1);
46930Sstevel@tonic-gate }
46940Sstevel@tonic-gate
46950Sstevel@tonic-gate static int
response(void)46960Sstevel@tonic-gate response(void)
46970Sstevel@tonic-gate {
46980Sstevel@tonic-gate int c;
46990Sstevel@tonic-gate
47000Sstevel@tonic-gate c = getchar();
47010Sstevel@tonic-gate if (c != '\n')
47021266Sceastha while (getchar() != '\n')
47031266Sceastha ;
47040Sstevel@tonic-gate else c = 'n';
47050Sstevel@tonic-gate return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
47060Sstevel@tonic-gate }
47070Sstevel@tonic-gate
47080Sstevel@tonic-gate /* Has file been modified since being put into archive? If so, return > 0. */
47090Sstevel@tonic-gate
47109694SScott.Rotondo@Sun.COM static off_t lookup(char *);
47119694SScott.Rotondo@Sun.COM
47120Sstevel@tonic-gate static int
checkupdate(char * arg)47130Sstevel@tonic-gate checkupdate(char *arg)
47140Sstevel@tonic-gate {
47150Sstevel@tonic-gate char name[PATH_MAX+1];
47160Sstevel@tonic-gate time_t mtime;
47170Sstevel@tonic-gate long nsecs;
47180Sstevel@tonic-gate off_t seekp;
47190Sstevel@tonic-gate
47200Sstevel@tonic-gate rewind(tfile);
47210Sstevel@tonic-gate if ((seekp = lookup(arg)) < 0)
47220Sstevel@tonic-gate return (1);
47230Sstevel@tonic-gate (void) fseek(tfile, seekp, 0);
47240Sstevel@tonic-gate (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
47250Sstevel@tonic-gate
47260Sstevel@tonic-gate /*
47270Sstevel@tonic-gate * Unless nanoseconds were stored in the file, only use seconds for
47280Sstevel@tonic-gate * comparison of time. Nanoseconds are stored when -E is specified.
47290Sstevel@tonic-gate */
47300Sstevel@tonic-gate if (Eflag == 0)
47310Sstevel@tonic-gate return (stbuf.st_mtime > mtime);
47320Sstevel@tonic-gate
47330Sstevel@tonic-gate if ((stbuf.st_mtime < mtime) ||
47340Sstevel@tonic-gate ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
47350Sstevel@tonic-gate return (0);
47360Sstevel@tonic-gate return (1);
47370Sstevel@tonic-gate }
47380Sstevel@tonic-gate
47390Sstevel@tonic-gate
47400Sstevel@tonic-gate /*
47410Sstevel@tonic-gate * newvol get new floppy (or tape) volume
47420Sstevel@tonic-gate *
47430Sstevel@tonic-gate * newvol(); resets tapepos and first to TRUE, prompts for
47440Sstevel@tonic-gate * for new volume, and waits.
47450Sstevel@tonic-gate * if dumping, end-of-file is written onto the tape.
47460Sstevel@tonic-gate */
47470Sstevel@tonic-gate
47480Sstevel@tonic-gate static void
newvol(void)47490Sstevel@tonic-gate newvol(void)
47500Sstevel@tonic-gate {
47510Sstevel@tonic-gate int c;
47520Sstevel@tonic-gate
47530Sstevel@tonic-gate if (dumping) {
47540Sstevel@tonic-gate #ifdef DEBUG
47550Sstevel@tonic-gate DEBUG("newvol called with 'dumping' set\n", 0, 0);
47560Sstevel@tonic-gate #endif
47570Sstevel@tonic-gate putempty((blkcnt_t)2); /* 2 EOT marks */
47580Sstevel@tonic-gate closevol();
47590Sstevel@tonic-gate flushtape();
47600Sstevel@tonic-gate sync();
47610Sstevel@tonic-gate tapepos = 0;
47620Sstevel@tonic-gate } else
47630Sstevel@tonic-gate first = TRUE;
47640Sstevel@tonic-gate if (close(mt) != 0)
47650Sstevel@tonic-gate vperror(2, gettext("close error"));
47660Sstevel@tonic-gate mt = 0;
47670Sstevel@tonic-gate (void) fprintf(stderr, gettext(
47680Sstevel@tonic-gate "tar: \007please insert new volume, then press RETURN."));
47690Sstevel@tonic-gate (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
47700Sstevel@tonic-gate while ((c = getchar()) != '\n' && ! term)
47710Sstevel@tonic-gate if (c == EOF)
47720Sstevel@tonic-gate done(Errflg);
47730Sstevel@tonic-gate if (term)
47740Sstevel@tonic-gate done(Errflg);
47750Sstevel@tonic-gate
47760Sstevel@tonic-gate errno = 0;
47770Sstevel@tonic-gate
47780Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) {
47790Sstevel@tonic-gate mt = dup(1);
47800Sstevel@tonic-gate } else {
47810Sstevel@tonic-gate mt = open(usefile, dumping ? update : 0);
47820Sstevel@tonic-gate }
47830Sstevel@tonic-gate
47840Sstevel@tonic-gate if (mt < 0) {
47850Sstevel@tonic-gate (void) fprintf(stderr, gettext(
47860Sstevel@tonic-gate "tar: cannot reopen %s (%s)\n"),
47870Sstevel@tonic-gate dumping ? gettext("output") : gettext("input"), usefile);
47880Sstevel@tonic-gate
478912305Srich.burridge@sun.com #ifdef DEBUG
479012305Srich.burridge@sun.com DEBUG("update=%d, usefile=%s ", update, usefile);
479112305Srich.burridge@sun.com DEBUG("mt=%d, [%s]\n", mt, strerror(errno));
479212305Srich.burridge@sun.com #endif
47930Sstevel@tonic-gate
47940Sstevel@tonic-gate done(2);
47950Sstevel@tonic-gate }
47960Sstevel@tonic-gate }
47970Sstevel@tonic-gate
47980Sstevel@tonic-gate /*
47990Sstevel@tonic-gate * Write a trailer portion to close out the current output volume.
48000Sstevel@tonic-gate */
48010Sstevel@tonic-gate
48020Sstevel@tonic-gate static void
closevol(void)48030Sstevel@tonic-gate closevol(void)
48040Sstevel@tonic-gate {
48050Sstevel@tonic-gate if (mulvol) {
48060Sstevel@tonic-gate /*
48070Sstevel@tonic-gate * blocklim does not count the 2 EOT marks;
48080Sstevel@tonic-gate * tapepos does count the 2 EOT marks;
48090Sstevel@tonic-gate * therefore we need the +2 below.
48100Sstevel@tonic-gate */
48110Sstevel@tonic-gate putempty(blocklim + (blkcnt_t)2 - tapepos);
48120Sstevel@tonic-gate }
48130Sstevel@tonic-gate }
48140Sstevel@tonic-gate
48150Sstevel@tonic-gate static void
done(int n)48160Sstevel@tonic-gate done(int n)
48170Sstevel@tonic-gate {
481812476Srich.burridge@oracle.com /*
481912476Srich.burridge@oracle.com * If we were terminated in some way, and we would otherwise have
482012476Srich.burridge@oracle.com * exited with a value of 0, adjust to 1, so that external callers
482112476Srich.burridge@oracle.com * can determine this by looking at the exit status.
482212476Srich.burridge@oracle.com */
482312476Srich.burridge@oracle.com if (term && n == 0)
482412476Srich.burridge@oracle.com n = 1;
482512476Srich.burridge@oracle.com
482612275Srich.burridge@sun.com if (tfile != NULL)
482712275Srich.burridge@sun.com (void) unlink(tname);
482811990Srich.burridge@sun.com if (compress_opt != NULL)
482911990Srich.burridge@sun.com (void) free(compress_opt);
48300Sstevel@tonic-gate if (mt > 0) {
48310Sstevel@tonic-gate if ((close(mt) != 0) || (fclose(stdout) != 0)) {
48320Sstevel@tonic-gate perror(gettext("tar: close error"));
48330Sstevel@tonic-gate exit(2);
48340Sstevel@tonic-gate }
48350Sstevel@tonic-gate }
48360Sstevel@tonic-gate exit(n);
48370Sstevel@tonic-gate }
48380Sstevel@tonic-gate
48390Sstevel@tonic-gate /*
48400Sstevel@tonic-gate * Determine if s1 is a prefix portion of s2 (or the same as s2).
48410Sstevel@tonic-gate */
48420Sstevel@tonic-gate
48430Sstevel@tonic-gate static int
is_prefix(char * s1,char * s2)48440Sstevel@tonic-gate is_prefix(char *s1, char *s2)
48450Sstevel@tonic-gate {
48460Sstevel@tonic-gate while (*s1)
48470Sstevel@tonic-gate if (*s1++ != *s2++)
48480Sstevel@tonic-gate return (0);
48490Sstevel@tonic-gate if (*s2)
48500Sstevel@tonic-gate return (*s2 == '/');
48510Sstevel@tonic-gate return (1);
48520Sstevel@tonic-gate }
48530Sstevel@tonic-gate
48540Sstevel@tonic-gate /*
48550Sstevel@tonic-gate * lookup and bsrch look through tfile entries to find a match for a name.
48560Sstevel@tonic-gate * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
48570Sstevel@tonic-gate * a pair of newline chars, so the buffer it uses must be long enough for
48580Sstevel@tonic-gate * two lines: name and modification time as well as period, newline and space.
48590Sstevel@tonic-gate *
48600Sstevel@tonic-gate * A kludge was added to bsrch to take care of matching on the first entry
48610Sstevel@tonic-gate * in the file--there is no leading newline. So, if we are reading from the
48620Sstevel@tonic-gate * start of the file, read into byte two and set the first byte to a newline.
48630Sstevel@tonic-gate * Otherwise, the first entry cannot be matched.
48640Sstevel@tonic-gate *
48650Sstevel@tonic-gate */
48660Sstevel@tonic-gate
48670Sstevel@tonic-gate #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
48680Sstevel@tonic-gate static off_t
lookup(char * s)48690Sstevel@tonic-gate lookup(char *s)
48700Sstevel@tonic-gate {
48710Sstevel@tonic-gate int i;
48720Sstevel@tonic-gate off_t a;
48730Sstevel@tonic-gate
48740Sstevel@tonic-gate for (i = 0; s[i]; i++)
48750Sstevel@tonic-gate if (s[i] == ' ')
48760Sstevel@tonic-gate break;
48770Sstevel@tonic-gate a = bsrch(s, i, low, high);
48780Sstevel@tonic-gate return (a);
48790Sstevel@tonic-gate }
48800Sstevel@tonic-gate
48810Sstevel@tonic-gate static off_t
bsrch(char * s,int n,off_t l,off_t h)48820Sstevel@tonic-gate bsrch(char *s, int n, off_t l, off_t h)
48830Sstevel@tonic-gate {
48840Sstevel@tonic-gate int i, j;
48850Sstevel@tonic-gate char b[N];
48860Sstevel@tonic-gate off_t m, m1;
48870Sstevel@tonic-gate
48880Sstevel@tonic-gate
48890Sstevel@tonic-gate loop:
48900Sstevel@tonic-gate if (l >= h)
48910Sstevel@tonic-gate return ((off_t)-1);
48920Sstevel@tonic-gate m = l + (h-l)/2 - N/2;
48930Sstevel@tonic-gate if (m < l)
48940Sstevel@tonic-gate m = l;
48950Sstevel@tonic-gate (void) fseek(tfile, m, 0);
48960Sstevel@tonic-gate if (m == 0) {
48970Sstevel@tonic-gate (void) fread(b+1, 1, N-1, tfile);
48980Sstevel@tonic-gate b[0] = '\n';
48990Sstevel@tonic-gate m--;
49000Sstevel@tonic-gate } else
49010Sstevel@tonic-gate (void) fread(b, 1, N, tfile);
49020Sstevel@tonic-gate for (i = 0; i < N; i++) {
49030Sstevel@tonic-gate if (b[i] == '\n')
49040Sstevel@tonic-gate break;
49050Sstevel@tonic-gate m++;
49060Sstevel@tonic-gate }
49070Sstevel@tonic-gate if (m >= h)
49080Sstevel@tonic-gate return ((off_t)-1);
49090Sstevel@tonic-gate m1 = m;
49100Sstevel@tonic-gate j = i;
49110Sstevel@tonic-gate for (i++; i < N; i++) {
49120Sstevel@tonic-gate m1++;
49130Sstevel@tonic-gate if (b[i] == '\n')
49140Sstevel@tonic-gate break;
49150Sstevel@tonic-gate }
49160Sstevel@tonic-gate i = cmp(b+j, s, n);
49170Sstevel@tonic-gate if (i < 0) {
49180Sstevel@tonic-gate h = m;
49190Sstevel@tonic-gate goto loop;
49200Sstevel@tonic-gate }
49210Sstevel@tonic-gate if (i > 0) {
49220Sstevel@tonic-gate l = m1;
49230Sstevel@tonic-gate goto loop;
49240Sstevel@tonic-gate }
49250Sstevel@tonic-gate if (m < 0)
49260Sstevel@tonic-gate m = 0;
49270Sstevel@tonic-gate return (m);
49280Sstevel@tonic-gate }
49290Sstevel@tonic-gate
49300Sstevel@tonic-gate static int
cmp(char * b,char * s,int n)49310Sstevel@tonic-gate cmp(char *b, char *s, int n)
49320Sstevel@tonic-gate {
49330Sstevel@tonic-gate int i;
49340Sstevel@tonic-gate
49350Sstevel@tonic-gate assert(b[0] == '\n');
49360Sstevel@tonic-gate
49370Sstevel@tonic-gate for (i = 0; i < n; i++) {
49380Sstevel@tonic-gate if (b[i+1] > s[i])
49390Sstevel@tonic-gate return (-1);
49400Sstevel@tonic-gate if (b[i+1] < s[i])
49410Sstevel@tonic-gate return (1);
49420Sstevel@tonic-gate }
49430Sstevel@tonic-gate return (b[i+1] == ' '? 0 : -1);
49440Sstevel@tonic-gate }
49450Sstevel@tonic-gate
49460Sstevel@tonic-gate
49470Sstevel@tonic-gate /*
49480Sstevel@tonic-gate * seekdisk seek to next file on archive
49490Sstevel@tonic-gate *
49500Sstevel@tonic-gate * called by passtape() only
49510Sstevel@tonic-gate *
49520Sstevel@tonic-gate * WARNING: expects "nblock" to be set, that is, readtape() to have
49530Sstevel@tonic-gate * already been called. Since passtape() is only called
49540Sstevel@tonic-gate * after a file header block has been read (why else would
49550Sstevel@tonic-gate * we skip to next file?), this is currently safe.
49560Sstevel@tonic-gate *
49570Sstevel@tonic-gate * changed to guarantee SYS_BLOCK boundary
49580Sstevel@tonic-gate */
49590Sstevel@tonic-gate
49600Sstevel@tonic-gate static void
seekdisk(blkcnt_t blocks)49610Sstevel@tonic-gate seekdisk(blkcnt_t blocks)
49620Sstevel@tonic-gate {
49630Sstevel@tonic-gate off_t seekval;
49640Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
49650Sstevel@tonic-gate /* handle non-multiple of SYS_BLOCK */
49660Sstevel@tonic-gate blkcnt_t nxb; /* # extra blocks */
49670Sstevel@tonic-gate #endif
49680Sstevel@tonic-gate
49690Sstevel@tonic-gate tapepos += blocks;
49700Sstevel@tonic-gate #ifdef DEBUG
49710Sstevel@tonic-gate DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0);
49720Sstevel@tonic-gate #endif
49730Sstevel@tonic-gate if (recno + blocks <= nblock) {
49740Sstevel@tonic-gate recno += blocks;
49750Sstevel@tonic-gate return;
49760Sstevel@tonic-gate }
49770Sstevel@tonic-gate if (recno > nblock)
49780Sstevel@tonic-gate recno = nblock;
49790Sstevel@tonic-gate seekval = (off_t)blocks - (nblock - recno);
49800Sstevel@tonic-gate recno = nblock; /* so readtape() reads next time through */
49810Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
49820Sstevel@tonic-gate nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
49830Sstevel@tonic-gate #ifdef DEBUG
49840Sstevel@tonic-gate DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
49850Sstevel@tonic-gate nxb, seekval);
49860Sstevel@tonic-gate #endif
49870Sstevel@tonic-gate if (nxb && nxb > seekval) /* don't seek--we'll read */
49880Sstevel@tonic-gate goto noseek;
49890Sstevel@tonic-gate seekval -= nxb; /* don't seek quite so far */
49900Sstevel@tonic-gate #endif
49910Sstevel@tonic-gate if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
49920Sstevel@tonic-gate (void) fprintf(stderr, gettext(
49930Sstevel@tonic-gate "tar: device seek error\n"));
49940Sstevel@tonic-gate done(3);
49950Sstevel@tonic-gate }
49960Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
49970Sstevel@tonic-gate /* read those extra blocks */
49980Sstevel@tonic-gate noseek:
49990Sstevel@tonic-gate if (nxb) {
50000Sstevel@tonic-gate #ifdef DEBUG
50010Sstevel@tonic-gate DEBUG("reading extra blocks\n", 0, 0);
50020Sstevel@tonic-gate #endif
50030Sstevel@tonic-gate if (read(mt, tbuf, TBLOCK*nblock) < 0) {
50040Sstevel@tonic-gate (void) fprintf(stderr, gettext(
50050Sstevel@tonic-gate "tar: read error while skipping file\n"));
50060Sstevel@tonic-gate done(8);
50070Sstevel@tonic-gate }
50080Sstevel@tonic-gate recno = nxb; /* so we don't read in next readtape() */
50090Sstevel@tonic-gate }
50100Sstevel@tonic-gate #endif
50110Sstevel@tonic-gate }
50120Sstevel@tonic-gate
50130Sstevel@tonic-gate static void
readtape(char * buffer)50140Sstevel@tonic-gate readtape(char *buffer)
50150Sstevel@tonic-gate {
50160Sstevel@tonic-gate int i, j;
50170Sstevel@tonic-gate
50180Sstevel@tonic-gate ++tapepos;
50190Sstevel@tonic-gate if (recno >= nblock || first) {
50200Sstevel@tonic-gate if (first) {
50210Sstevel@tonic-gate /*
50220Sstevel@tonic-gate * set the number of blocks to read initially, based on
50230Sstevel@tonic-gate * the defined defaults for the device, or on the
50240Sstevel@tonic-gate * explicit block factor given.
50250Sstevel@tonic-gate */
502612350Srich.burridge@sun.com if (bflag || defaults_used || NotTape)
50270Sstevel@tonic-gate j = nblock;
50280Sstevel@tonic-gate else
50290Sstevel@tonic-gate j = NBLOCK;
50300Sstevel@tonic-gate } else
50310Sstevel@tonic-gate j = nblock;
50320Sstevel@tonic-gate
50330Sstevel@tonic-gate if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
50340Sstevel@tonic-gate (void) fprintf(stderr, gettext(
50350Sstevel@tonic-gate "tar: tape read error\n"));
50360Sstevel@tonic-gate done(3);
50370Sstevel@tonic-gate /*
50382512Sss161016 * i == 0 and !rflag means that EOF is reached and we are
50392512Sss161016 * trying to update or replace an empty tar file, so exit
50402512Sss161016 * with an error.
50412512Sss161016 *
50422512Sss161016 * If i == 0 and !first and NotTape, it means the pointer
50432512Sss161016 * has gone past the EOF. It could happen if two processes
50442512Sss161016 * try to update the same tar file simultaneously. So exit
50452512Sss161016 * with an error.
50460Sstevel@tonic-gate */
50472512Sss161016
50482512Sss161016 } else if (i == 0) {
50492512Sss161016 if (first && !rflag) {
50502512Sss161016 (void) fprintf(stderr, gettext(
50512512Sss161016 "tar: blocksize = %d\n"), i);
50522512Sss161016 done(Errflg);
50532512Sss161016 } else if (!first && (!rflag || NotTape)) {
50542512Sss161016 mterr("read", 0, 2);
50552512Sss161016 }
50560Sstevel@tonic-gate } else if ((!first || Bflag) && i != TBLOCK*j) {
50570Sstevel@tonic-gate /*
50580Sstevel@tonic-gate * Short read - try to get the remaining bytes.
50590Sstevel@tonic-gate */
50600Sstevel@tonic-gate
50610Sstevel@tonic-gate int remaining = (TBLOCK * j) - i;
50620Sstevel@tonic-gate char *b = (char *)tbuf + i;
50630Sstevel@tonic-gate int r;
50640Sstevel@tonic-gate
50650Sstevel@tonic-gate do {
50660Sstevel@tonic-gate if ((r = read(mt, b, remaining)) < 0) {
50670Sstevel@tonic-gate (void) fprintf(stderr,
50680Sstevel@tonic-gate gettext("tar: tape read error\n"));
50690Sstevel@tonic-gate done(3);
50700Sstevel@tonic-gate }
50710Sstevel@tonic-gate b += r;
50720Sstevel@tonic-gate remaining -= r;
50730Sstevel@tonic-gate i += r;
50740Sstevel@tonic-gate } while (remaining > 0 && r != 0);
50750Sstevel@tonic-gate }
50760Sstevel@tonic-gate if (first) {
50770Sstevel@tonic-gate if ((i % TBLOCK) != 0) {
50780Sstevel@tonic-gate (void) fprintf(stderr, gettext(
50790Sstevel@tonic-gate "tar: tape blocksize error\n"));
50800Sstevel@tonic-gate done(3);
50810Sstevel@tonic-gate }
50820Sstevel@tonic-gate i /= TBLOCK;
50830Sstevel@tonic-gate if (vflag && i != nblock && i != 1) {
50840Sstevel@tonic-gate if (!NotTape)
50850Sstevel@tonic-gate (void) fprintf(stderr, gettext(
50860Sstevel@tonic-gate "tar: blocksize = %d\n"), i);
50870Sstevel@tonic-gate }
50880Sstevel@tonic-gate
50890Sstevel@tonic-gate /*
50900Sstevel@tonic-gate * If we are reading a tape, then a short read is
50910Sstevel@tonic-gate * understood to signify that the amount read is
50920Sstevel@tonic-gate * the tape's actual blocking factor. We adapt
50930Sstevel@tonic-gate * nblock accordingly. There is no reason to do
50940Sstevel@tonic-gate * this when the device is not blocked.
50950Sstevel@tonic-gate */
50960Sstevel@tonic-gate
50970Sstevel@tonic-gate if (!NotTape)
50980Sstevel@tonic-gate nblock = i;
50990Sstevel@tonic-gate }
51000Sstevel@tonic-gate recno = 0;
51010Sstevel@tonic-gate }
51020Sstevel@tonic-gate
51030Sstevel@tonic-gate first = FALSE;
51040Sstevel@tonic-gate copy(buffer, &tbuf[recno++]);
51050Sstevel@tonic-gate }
51060Sstevel@tonic-gate
51070Sstevel@tonic-gate
51080Sstevel@tonic-gate /*
51090Sstevel@tonic-gate * replacement for writetape.
51100Sstevel@tonic-gate */
51110Sstevel@tonic-gate
51120Sstevel@tonic-gate static int
writetbuf(char * buffer,int n)51130Sstevel@tonic-gate writetbuf(char *buffer, int n)
51140Sstevel@tonic-gate {
51150Sstevel@tonic-gate int i;
51160Sstevel@tonic-gate
51170Sstevel@tonic-gate tapepos += n; /* output block count */
51180Sstevel@tonic-gate
51190Sstevel@tonic-gate if (recno >= nblock) {
51200Sstevel@tonic-gate i = write(mt, (char *)tbuf, TBLOCK*nblock);
51210Sstevel@tonic-gate if (i != TBLOCK*nblock)
51220Sstevel@tonic-gate mterr("write", i, 2);
51230Sstevel@tonic-gate recno = 0;
51240Sstevel@tonic-gate }
51250Sstevel@tonic-gate
51260Sstevel@tonic-gate /*
51270Sstevel@tonic-gate * Special case: We have an empty tape buffer, and the
51280Sstevel@tonic-gate * users data size is >= the tape block size: Avoid
51290Sstevel@tonic-gate * the bcopy and dma direct to tape. BIG WIN. Add the
51300Sstevel@tonic-gate * residual to the tape buffer.
51310Sstevel@tonic-gate */
51320Sstevel@tonic-gate while (recno == 0 && n >= nblock) {
51330Sstevel@tonic-gate i = (int)write(mt, buffer, TBLOCK*nblock);
51340Sstevel@tonic-gate if (i != TBLOCK*nblock)
51350Sstevel@tonic-gate mterr("write", i, 2);
51360Sstevel@tonic-gate n -= nblock;
51370Sstevel@tonic-gate buffer += (nblock * TBLOCK);
51380Sstevel@tonic-gate }
51390Sstevel@tonic-gate
51400Sstevel@tonic-gate while (n-- > 0) {
51410Sstevel@tonic-gate (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
51420Sstevel@tonic-gate buffer += TBLOCK;
51430Sstevel@tonic-gate if (recno >= nblock) {
51440Sstevel@tonic-gate i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
51450Sstevel@tonic-gate if (i != TBLOCK*nblock)
51460Sstevel@tonic-gate mterr("write", i, 2);
51470Sstevel@tonic-gate recno = 0;
51480Sstevel@tonic-gate }
51490Sstevel@tonic-gate }
51500Sstevel@tonic-gate
51510Sstevel@tonic-gate /* Tell the user how much to write to get in sync */
51520Sstevel@tonic-gate return (nblock - recno);
51530Sstevel@tonic-gate }
51540Sstevel@tonic-gate
51550Sstevel@tonic-gate /*
51560Sstevel@tonic-gate * backtape - reposition tape after reading soft "EOF" record
51570Sstevel@tonic-gate *
51580Sstevel@tonic-gate * Backtape tries to reposition the tape back over the EOF
51590Sstevel@tonic-gate * record. This is for the 'u' and 'r' function letters so that the
51600Sstevel@tonic-gate * tape can be extended. This code is not well designed, but
51610Sstevel@tonic-gate * I'm confident that the only callers who care about the
51620Sstevel@tonic-gate * backspace-over-EOF feature are those involved in 'u' and 'r'.
51630Sstevel@tonic-gate *
51640Sstevel@tonic-gate * The proper way to backup the tape is through the use of mtio.
51650Sstevel@tonic-gate * Earlier spins used lseek combined with reads in a confusing
51660Sstevel@tonic-gate * maneuver that only worked on 4.x, but shouldn't have, even
51670Sstevel@tonic-gate * there. Lseeks are explicitly not supported for tape devices.
51680Sstevel@tonic-gate */
51690Sstevel@tonic-gate
51700Sstevel@tonic-gate static void
backtape(void)51710Sstevel@tonic-gate backtape(void)
51720Sstevel@tonic-gate {
51730Sstevel@tonic-gate struct mtop mtcmd;
51740Sstevel@tonic-gate #ifdef DEBUG
51750Sstevel@tonic-gate DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
51760Sstevel@tonic-gate nblock);
51770Sstevel@tonic-gate #endif
51780Sstevel@tonic-gate /*
51790Sstevel@tonic-gate * Backup to the position in the archive where the record
51800Sstevel@tonic-gate * currently sitting in the tbuf buffer is situated.
51810Sstevel@tonic-gate */
51820Sstevel@tonic-gate
51830Sstevel@tonic-gate if (NotTape) {
51840Sstevel@tonic-gate /*
51850Sstevel@tonic-gate * For non-tape devices, this means lseeking to the
51860Sstevel@tonic-gate * correct position. The absolute location tapepos-recno
51870Sstevel@tonic-gate * should be the beginning of the current record.
51880Sstevel@tonic-gate */
51890Sstevel@tonic-gate
51900Sstevel@tonic-gate if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
51910Sstevel@tonic-gate (off_t)-1) {
51920Sstevel@tonic-gate (void) fprintf(stderr,
51930Sstevel@tonic-gate gettext("tar: lseek to end of archive failed\n"));
51940Sstevel@tonic-gate done(4);
51950Sstevel@tonic-gate }
51960Sstevel@tonic-gate } else {
51970Sstevel@tonic-gate /*
51980Sstevel@tonic-gate * For tape devices, we backup over the most recently
51990Sstevel@tonic-gate * read record.
52000Sstevel@tonic-gate */
52010Sstevel@tonic-gate
52020Sstevel@tonic-gate mtcmd.mt_op = MTBSR;
52030Sstevel@tonic-gate mtcmd.mt_count = 1;
52040Sstevel@tonic-gate
52050Sstevel@tonic-gate if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
52060Sstevel@tonic-gate (void) fprintf(stderr,
52071266Sceastha gettext("tar: backspace over record failed\n"));
52080Sstevel@tonic-gate done(4);
52090Sstevel@tonic-gate }
52100Sstevel@tonic-gate }
52110Sstevel@tonic-gate
52120Sstevel@tonic-gate /*
52130Sstevel@tonic-gate * Decrement the tape and tbuf buffer indices to prepare for the
52140Sstevel@tonic-gate * coming write to overwrite the soft EOF record.
52150Sstevel@tonic-gate */
52160Sstevel@tonic-gate
52170Sstevel@tonic-gate recno--;
52180Sstevel@tonic-gate tapepos--;
52190Sstevel@tonic-gate }
52200Sstevel@tonic-gate
52210Sstevel@tonic-gate
52220Sstevel@tonic-gate /*
52230Sstevel@tonic-gate * flushtape write buffered block(s) onto tape
52240Sstevel@tonic-gate *
52250Sstevel@tonic-gate * recno points to next free block in tbuf. If nonzero, a write is done.
52260Sstevel@tonic-gate * Care is taken to write in multiples of SYS_BLOCK when device is
52270Sstevel@tonic-gate * non-magtape in case raw i/o is used.
52280Sstevel@tonic-gate *
52290Sstevel@tonic-gate * NOTE: this is called by writetape() to do the actual writing
52300Sstevel@tonic-gate */
52310Sstevel@tonic-gate
52320Sstevel@tonic-gate static void
flushtape(void)52330Sstevel@tonic-gate flushtape(void)
52340Sstevel@tonic-gate {
52350Sstevel@tonic-gate #ifdef DEBUG
52360Sstevel@tonic-gate DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0);
52370Sstevel@tonic-gate #endif
52380Sstevel@tonic-gate if (recno > 0) { /* anything buffered? */
52390Sstevel@tonic-gate if (NotTape) {
52400Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK
52410Sstevel@tonic-gate int i;
52420Sstevel@tonic-gate
52430Sstevel@tonic-gate /*
52440Sstevel@tonic-gate * an odd-block write can only happen when
52450Sstevel@tonic-gate * we are at the end of a volume that is not a tape.
52460Sstevel@tonic-gate * Here we round recno up to an even SYS_BLOCK
52470Sstevel@tonic-gate * boundary.
52480Sstevel@tonic-gate */
52490Sstevel@tonic-gate if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
52500Sstevel@tonic-gate #ifdef DEBUG
52510Sstevel@tonic-gate DEBUG("flushtape() %d rounding blocks\n", i, 0);
52520Sstevel@tonic-gate #endif
52530Sstevel@tonic-gate recno += i; /* round up to even SYS_BLOCK */
52540Sstevel@tonic-gate }
52550Sstevel@tonic-gate #endif
52560Sstevel@tonic-gate if (recno > nblock)
52570Sstevel@tonic-gate recno = nblock;
52580Sstevel@tonic-gate }
52590Sstevel@tonic-gate #ifdef DEBUG
52600Sstevel@tonic-gate DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
52610Sstevel@tonic-gate " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
52620Sstevel@tonic-gate (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
52630Sstevel@tonic-gate #endif
52640Sstevel@tonic-gate if (write(mt, tbuf,
52650Sstevel@tonic-gate (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
52660Sstevel@tonic-gate (void) fprintf(stderr, gettext(
52670Sstevel@tonic-gate "tar: tape write error\n"));
52680Sstevel@tonic-gate done(2);
52690Sstevel@tonic-gate }
52700Sstevel@tonic-gate recno = 0;
52710Sstevel@tonic-gate }
52720Sstevel@tonic-gate }
52730Sstevel@tonic-gate
52740Sstevel@tonic-gate static void
copy(void * dst,void * src)52750Sstevel@tonic-gate copy(void *dst, void *src)
52760Sstevel@tonic-gate {
52770Sstevel@tonic-gate (void) memcpy(dst, src, TBLOCK);
52780Sstevel@tonic-gate }
52790Sstevel@tonic-gate
52800Sstevel@tonic-gate /*
52810Sstevel@tonic-gate * kcheck()
52820Sstevel@tonic-gate * - checks the validity of size values for non-tape devices
52830Sstevel@tonic-gate * - if size is zero, mulvol tar is disabled and size is
52840Sstevel@tonic-gate * assumed to be infinite.
52850Sstevel@tonic-gate * - returns volume size in TBLOCKS
52860Sstevel@tonic-gate */
52870Sstevel@tonic-gate
52880Sstevel@tonic-gate static blkcnt_t
kcheck(char * kstr)52890Sstevel@tonic-gate kcheck(char *kstr)
52900Sstevel@tonic-gate {
52910Sstevel@tonic-gate blkcnt_t kval;
52920Sstevel@tonic-gate
52930Sstevel@tonic-gate kval = strtoll(kstr, NULL, 0);
52940Sstevel@tonic-gate if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
52950Sstevel@tonic-gate mulvol = 0; /* definitely not mulvol, but we must */
52960Sstevel@tonic-gate return (0); /* took out setting of NotTape */
52970Sstevel@tonic-gate }
52980Sstevel@tonic-gate if (kval < (blkcnt_t)MINSIZE) {
52990Sstevel@tonic-gate (void) fprintf(stderr, gettext(
53000Sstevel@tonic-gate "tar: sizes below %luK not supported (%" FMT_blkcnt_t
53010Sstevel@tonic-gate ").\n"), (ulong_t)MINSIZE, kval);
5302*12836Srich.burridge@oracle.com (void) fprintf(stderr, gettext(
5303*12836Srich.burridge@oracle.com "bad size entry for %s in %s.\n"),
5304*12836Srich.burridge@oracle.com archive, DEF_FILE);
53050Sstevel@tonic-gate done(1);
53060Sstevel@tonic-gate }
53070Sstevel@tonic-gate mulvol++;
53080Sstevel@tonic-gate NotTape++; /* implies non-tape */
53090Sstevel@tonic-gate return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
53100Sstevel@tonic-gate }
53110Sstevel@tonic-gate
53120Sstevel@tonic-gate
53130Sstevel@tonic-gate /*
53140Sstevel@tonic-gate * bcheck()
53150Sstevel@tonic-gate * - checks the validity of blocking factors
53160Sstevel@tonic-gate * - returns blocking factor
53170Sstevel@tonic-gate */
53180Sstevel@tonic-gate
53190Sstevel@tonic-gate static int
bcheck(char * bstr)53200Sstevel@tonic-gate bcheck(char *bstr)
53210Sstevel@tonic-gate {
53220Sstevel@tonic-gate blkcnt_t bval;
53230Sstevel@tonic-gate
53240Sstevel@tonic-gate bval = strtoll(bstr, NULL, 0);
53250Sstevel@tonic-gate if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
53260Sstevel@tonic-gate (void) fprintf(stderr, gettext(
53270Sstevel@tonic-gate "tar: invalid blocksize \"%s\".\n"), bstr);
53280Sstevel@tonic-gate if (!bflag)
53290Sstevel@tonic-gate (void) fprintf(stderr, gettext(
53300Sstevel@tonic-gate "bad blocksize entry for '%s' in %s.\n"),
53310Sstevel@tonic-gate archive, DEF_FILE);
53320Sstevel@tonic-gate done(1);
53330Sstevel@tonic-gate }
53340Sstevel@tonic-gate
53350Sstevel@tonic-gate return ((int)bval);
53360Sstevel@tonic-gate }
53370Sstevel@tonic-gate
53380Sstevel@tonic-gate
53390Sstevel@tonic-gate /*
53400Sstevel@tonic-gate * defset()
53410Sstevel@tonic-gate * - reads DEF_FILE for the set of default values specified.
53420Sstevel@tonic-gate * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
53430Sstevel@tonic-gate * - 'usefile' points to static data, so will be overwritten
53440Sstevel@tonic-gate * if this routine is called a second time.
53450Sstevel@tonic-gate * - the pattern specified by 'arch' must be followed by four
53460Sstevel@tonic-gate * blank-separated fields (1) device (2) blocking,
53470Sstevel@tonic-gate * (3) size(K), and (4) tape
53480Sstevel@tonic-gate * for example: archive0=/dev/fd 1 400 n
53490Sstevel@tonic-gate */
53500Sstevel@tonic-gate
53510Sstevel@tonic-gate static int
defset(char * arch)53520Sstevel@tonic-gate defset(char *arch)
53530Sstevel@tonic-gate {
53540Sstevel@tonic-gate char *bp;
53550Sstevel@tonic-gate
53560Sstevel@tonic-gate if (defopen(DEF_FILE) != 0)
53570Sstevel@tonic-gate return (FALSE);
53580Sstevel@tonic-gate if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
53590Sstevel@tonic-gate (void) fprintf(stderr, gettext(
53600Sstevel@tonic-gate "tar: error setting parameters for %s.\n"), DEF_FILE);
53610Sstevel@tonic-gate return (FALSE); /* & following ones too */
53620Sstevel@tonic-gate }
53630Sstevel@tonic-gate if ((bp = defread(arch)) == NULL) {
53640Sstevel@tonic-gate (void) fprintf(stderr, gettext(
53650Sstevel@tonic-gate "tar: missing or invalid '%s' entry in %s.\n"),
53661266Sceastha arch, DEF_FILE);
53670Sstevel@tonic-gate return (FALSE);
53680Sstevel@tonic-gate }
53690Sstevel@tonic-gate if ((usefile = strtok(bp, " \t")) == NULL) {
53700Sstevel@tonic-gate (void) fprintf(stderr, gettext(
53710Sstevel@tonic-gate "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
53720Sstevel@tonic-gate return (FALSE);
53730Sstevel@tonic-gate }
53740Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) == NULL) {
53750Sstevel@tonic-gate (void) fprintf(stderr, gettext(
53760Sstevel@tonic-gate "tar: block component missing in '%s' entry in %s.\n"),
53770Sstevel@tonic-gate arch, DEF_FILE);
53780Sstevel@tonic-gate return (FALSE);
53790Sstevel@tonic-gate }
53800Sstevel@tonic-gate nblock = bcheck(bp);
53810Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) == NULL) {
53820Sstevel@tonic-gate (void) fprintf(stderr, gettext(
53830Sstevel@tonic-gate "tar: size component missing in '%s' entry in %s.\n"),
53840Sstevel@tonic-gate arch, DEF_FILE);
53850Sstevel@tonic-gate return (FALSE);
53860Sstevel@tonic-gate }
53870Sstevel@tonic-gate blocklim = kcheck(bp);
53880Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) != NULL)
53890Sstevel@tonic-gate NotTape = (*bp == 'n' || *bp == 'N');
53900Sstevel@tonic-gate else
53910Sstevel@tonic-gate NotTape = (blocklim != 0);
53920Sstevel@tonic-gate (void) defopen(NULL);
53930Sstevel@tonic-gate #ifdef DEBUG
53940Sstevel@tonic-gate DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile);
53950Sstevel@tonic-gate DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
53960Sstevel@tonic-gate nblock, blocklim);
53970Sstevel@tonic-gate DEBUG("defset: not tape = %d\n", NotTape, 0);
53980Sstevel@tonic-gate #endif
53990Sstevel@tonic-gate return (TRUE);
54000Sstevel@tonic-gate }
54010Sstevel@tonic-gate
54020Sstevel@tonic-gate
54030Sstevel@tonic-gate /*
54040Sstevel@tonic-gate * Following code handles excluded and included files.
54050Sstevel@tonic-gate * A hash table of file names to be {in,ex}cluded is built.
54060Sstevel@tonic-gate * For excluded files, before writing or extracting a file
54070Sstevel@tonic-gate * check to see if it is in the exclude_tbl.
54080Sstevel@tonic-gate * For included files, the wantit() procedure will check to
54090Sstevel@tonic-gate * see if the named file is in the include_tbl.
54100Sstevel@tonic-gate */
54110Sstevel@tonic-gate
54120Sstevel@tonic-gate static void
build_table(file_list_t * table[],char * file)54136525Sceastha build_table(file_list_t *table[], char *file)
54140Sstevel@tonic-gate {
54150Sstevel@tonic-gate FILE *fp;
54160Sstevel@tonic-gate char buf[PATH_MAX + 1];
54170Sstevel@tonic-gate
54180Sstevel@tonic-gate if ((fp = fopen(file, "r")) == (FILE *)NULL)
54190Sstevel@tonic-gate vperror(1, gettext("could not open %s"), file);
54200Sstevel@tonic-gate while (fgets(buf, sizeof (buf), fp) != NULL) {
54210Sstevel@tonic-gate if (buf[strlen(buf) - 1] == '\n')
54220Sstevel@tonic-gate buf[strlen(buf) - 1] = '\0';
54230Sstevel@tonic-gate /* Only add to table if line has something in it */
54240Sstevel@tonic-gate if (strspn(buf, " \t") != strlen(buf))
54250Sstevel@tonic-gate add_file_to_table(table, buf);
54260Sstevel@tonic-gate }
54270Sstevel@tonic-gate (void) fclose(fp);
54280Sstevel@tonic-gate }
54290Sstevel@tonic-gate
54300Sstevel@tonic-gate
54310Sstevel@tonic-gate /*
54320Sstevel@tonic-gate * Add a file name to the the specified table, if the file name has any
54330Sstevel@tonic-gate * trailing '/'s then delete them before inserting into the table
54340Sstevel@tonic-gate */
54350Sstevel@tonic-gate
54360Sstevel@tonic-gate static void
add_file_to_table(file_list_t * table[],char * str)54376525Sceastha add_file_to_table(file_list_t *table[], char *str)
54380Sstevel@tonic-gate {
54390Sstevel@tonic-gate char name[PATH_MAX + 1];
54400Sstevel@tonic-gate unsigned int h;
54416525Sceastha file_list_t *exp;
54420Sstevel@tonic-gate
54430Sstevel@tonic-gate (void) strcpy(name, str);
54440Sstevel@tonic-gate while (name[strlen(name) - 1] == '/') {
54450Sstevel@tonic-gate name[strlen(name) - 1] = NULL;
54460Sstevel@tonic-gate }
54470Sstevel@tonic-gate
54480Sstevel@tonic-gate h = hash(name);
54496525Sceastha if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
54500Sstevel@tonic-gate sizeof (char))) == NULL) {
54510Sstevel@tonic-gate (void) fprintf(stderr, gettext(
54520Sstevel@tonic-gate "tar: out of memory, exclude/include table(entry)\n"));
54530Sstevel@tonic-gate exit(1);
54540Sstevel@tonic-gate }
54550Sstevel@tonic-gate
54560Sstevel@tonic-gate if ((exp->name = strdup(name)) == NULL) {
54570Sstevel@tonic-gate (void) fprintf(stderr, gettext(
54580Sstevel@tonic-gate "tar: out of memory, exclude/include table(file name)\n"));
54590Sstevel@tonic-gate exit(1);
54600Sstevel@tonic-gate }
54610Sstevel@tonic-gate
54620Sstevel@tonic-gate exp->next = table[h];
54630Sstevel@tonic-gate table[h] = exp;
54640Sstevel@tonic-gate }
54650Sstevel@tonic-gate
54660Sstevel@tonic-gate
54670Sstevel@tonic-gate /*
54680Sstevel@tonic-gate * See if a file name or any of the file's parent directories is in the
54690Sstevel@tonic-gate * specified table, if the file name has any trailing '/'s then delete
54700Sstevel@tonic-gate * them before searching the table
54710Sstevel@tonic-gate */
54720Sstevel@tonic-gate
54730Sstevel@tonic-gate static int
is_in_table(file_list_t * table[],char * str)54746525Sceastha is_in_table(file_list_t *table[], char *str)
54750Sstevel@tonic-gate {
54760Sstevel@tonic-gate char name[PATH_MAX + 1];
54770Sstevel@tonic-gate unsigned int h;
54786525Sceastha file_list_t *exp;
54790Sstevel@tonic-gate char *ptr;
54800Sstevel@tonic-gate
54810Sstevel@tonic-gate (void) strcpy(name, str);
54820Sstevel@tonic-gate while (name[strlen(name) - 1] == '/') {
54830Sstevel@tonic-gate name[strlen(name) - 1] = NULL;
54840Sstevel@tonic-gate }
54850Sstevel@tonic-gate
54860Sstevel@tonic-gate /*
54870Sstevel@tonic-gate * check for the file name in the passed list
54880Sstevel@tonic-gate */
54890Sstevel@tonic-gate h = hash(name);
54900Sstevel@tonic-gate exp = table[h];
54910Sstevel@tonic-gate while (exp != NULL) {
54920Sstevel@tonic-gate if (strcmp(name, exp->name) == 0) {
54930Sstevel@tonic-gate return (1);
54940Sstevel@tonic-gate }
54950Sstevel@tonic-gate exp = exp->next;
54960Sstevel@tonic-gate }
54970Sstevel@tonic-gate
54980Sstevel@tonic-gate /*
54990Sstevel@tonic-gate * check for any parent directories in the file list
55000Sstevel@tonic-gate */
55010Sstevel@tonic-gate while ((ptr = strrchr(name, '/'))) {
55020Sstevel@tonic-gate *ptr = NULL;
55030Sstevel@tonic-gate h = hash(name);
55040Sstevel@tonic-gate exp = table[h];
55050Sstevel@tonic-gate while (exp != NULL) {
55060Sstevel@tonic-gate if (strcmp(name, exp->name) == 0) {
55070Sstevel@tonic-gate return (1);
55080Sstevel@tonic-gate }
55090Sstevel@tonic-gate exp = exp->next;
55100Sstevel@tonic-gate }
55110Sstevel@tonic-gate }
55120Sstevel@tonic-gate
55130Sstevel@tonic-gate return (0);
55140Sstevel@tonic-gate }
55150Sstevel@tonic-gate
55160Sstevel@tonic-gate
55170Sstevel@tonic-gate /*
55180Sstevel@tonic-gate * Compute a hash from a string.
55190Sstevel@tonic-gate */
55200Sstevel@tonic-gate
55210Sstevel@tonic-gate static unsigned int
hash(char * str)55220Sstevel@tonic-gate hash(char *str)
55230Sstevel@tonic-gate {
55240Sstevel@tonic-gate char *cp;
55250Sstevel@tonic-gate unsigned int h;
55260Sstevel@tonic-gate
55270Sstevel@tonic-gate h = 0;
55280Sstevel@tonic-gate for (cp = str; *cp; cp++) {
55290Sstevel@tonic-gate h += *cp;
55300Sstevel@tonic-gate }
55310Sstevel@tonic-gate return (h % TABLE_SIZE);
55320Sstevel@tonic-gate }
55330Sstevel@tonic-gate
55340Sstevel@tonic-gate static void *
getmem(size_t size)55350Sstevel@tonic-gate getmem(size_t size)
55360Sstevel@tonic-gate {
55370Sstevel@tonic-gate void *p = calloc((unsigned)size, sizeof (char));
55380Sstevel@tonic-gate
55390Sstevel@tonic-gate if (p == NULL && freemem) {
55400Sstevel@tonic-gate (void) fprintf(stderr, gettext(
55410Sstevel@tonic-gate "tar: out of memory, link and directory modtime "
55420Sstevel@tonic-gate "info lost\n"));
55430Sstevel@tonic-gate freemem = 0;
55440Sstevel@tonic-gate if (errflag)
55450Sstevel@tonic-gate done(1);
55460Sstevel@tonic-gate else
55470Sstevel@tonic-gate Errflg = 1;
55480Sstevel@tonic-gate }
55490Sstevel@tonic-gate return (p);
55500Sstevel@tonic-gate }
55510Sstevel@tonic-gate
55520Sstevel@tonic-gate /*
55530Sstevel@tonic-gate * vperror() --variable argument perror.
55540Sstevel@tonic-gate * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
55550Sstevel@tonic-gate * the errflag (exit on error) is checked -- if it is non-zero, tar exits
55560Sstevel@tonic-gate * with the value of whatever "errno" is set to. If exit_status is not
55570Sstevel@tonic-gate * zero, then tar exits with that error status. If errflag and exit_status
55580Sstevel@tonic-gate * are both zero, the routine returns to where it was called and sets Errflg
55590Sstevel@tonic-gate * to errno.
55600Sstevel@tonic-gate */
55610Sstevel@tonic-gate
55620Sstevel@tonic-gate static void
vperror(int exit_status,char * fmt,...)55630Sstevel@tonic-gate vperror(int exit_status, char *fmt, ...)
55640Sstevel@tonic-gate {
55650Sstevel@tonic-gate va_list ap;
55660Sstevel@tonic-gate
55670Sstevel@tonic-gate va_start(ap, fmt);
55680Sstevel@tonic-gate (void) fputs("tar: ", stderr);
55690Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap);
55700Sstevel@tonic-gate (void) fprintf(stderr, ": %s\n", strerror(errno));
55710Sstevel@tonic-gate va_end(ap);
55720Sstevel@tonic-gate if (exit_status)
55730Sstevel@tonic-gate done(exit_status);
55740Sstevel@tonic-gate else
55750Sstevel@tonic-gate if (errflag)
55760Sstevel@tonic-gate done(errno);
55770Sstevel@tonic-gate else
55780Sstevel@tonic-gate Errflg = errno;
55790Sstevel@tonic-gate }
55800Sstevel@tonic-gate
55810Sstevel@tonic-gate
55820Sstevel@tonic-gate static void
fatal(char * format,...)55830Sstevel@tonic-gate fatal(char *format, ...)
55840Sstevel@tonic-gate {
55850Sstevel@tonic-gate va_list ap;
55860Sstevel@tonic-gate
55870Sstevel@tonic-gate va_start(ap, format);
55880Sstevel@tonic-gate (void) fprintf(stderr, "tar: ");
55890Sstevel@tonic-gate (void) vfprintf(stderr, format, ap);
55900Sstevel@tonic-gate (void) fprintf(stderr, "\n");
55910Sstevel@tonic-gate va_end(ap);
55920Sstevel@tonic-gate done(1);
55930Sstevel@tonic-gate }
55940Sstevel@tonic-gate
55950Sstevel@tonic-gate
55960Sstevel@tonic-gate /*
55970Sstevel@tonic-gate * Check to make sure that argument is a char * ptr.
55980Sstevel@tonic-gate * Actually, we just check to see that it is non-null.
55990Sstevel@tonic-gate * If it is null, print out the message and call usage(), bailing out.
56000Sstevel@tonic-gate */
56010Sstevel@tonic-gate
56020Sstevel@tonic-gate static void
assert_string(char * s,char * msg)56030Sstevel@tonic-gate assert_string(char *s, char *msg)
56040Sstevel@tonic-gate {
56050Sstevel@tonic-gate if (s == NULL) {
56060Sstevel@tonic-gate (void) fprintf(stderr, msg);
56070Sstevel@tonic-gate usage();
56080Sstevel@tonic-gate }
56090Sstevel@tonic-gate }
56100Sstevel@tonic-gate
56110Sstevel@tonic-gate
56120Sstevel@tonic-gate static void
mterr(char * operation,int i,int exitcode)56130Sstevel@tonic-gate mterr(char *operation, int i, int exitcode)
56140Sstevel@tonic-gate {
56150Sstevel@tonic-gate (void) fprintf(stderr, gettext(
56160Sstevel@tonic-gate "tar: %s error: "), operation);
56170Sstevel@tonic-gate if (i < 0)
56180Sstevel@tonic-gate perror("");
56190Sstevel@tonic-gate else
56200Sstevel@tonic-gate (void) fprintf(stderr, gettext("unexpected EOF\n"));
56210Sstevel@tonic-gate done(exitcode);
56220Sstevel@tonic-gate }
56230Sstevel@tonic-gate
56240Sstevel@tonic-gate static int
wantit(char * argv[],char ** namep,char ** dirp,char ** component,attr_data_t ** attrinfo)56255331Samw wantit(char *argv[], char **namep, char **dirp, char **component,
56265331Samw attr_data_t **attrinfo)
56270Sstevel@tonic-gate {
56280Sstevel@tonic-gate char **cp;
56290Sstevel@tonic-gate int gotit; /* true if we've found a match */
56305482Sas158974 int ret;
56310Sstevel@tonic-gate
56320Sstevel@tonic-gate top:
56335482Sas158974 if (xhdr_flgs & _X_XHDR) {
56345482Sas158974 xhdr_flgs = 0;
56355482Sas158974 }
56360Sstevel@tonic-gate getdir();
56370Sstevel@tonic-gate if (Xhdrflag > 0) {
56385482Sas158974 ret = get_xdata();
56395482Sas158974 if (ret != 0) { /* Xhdr items and regular header */
56405482Sas158974 setbytes_to_skip(&stbuf, ret);
56410Sstevel@tonic-gate passtape();
56420Sstevel@tonic-gate return (0); /* Error--don't want to extract */
56430Sstevel@tonic-gate }
56440Sstevel@tonic-gate }
56450Sstevel@tonic-gate
56465482Sas158974 /*
56475482Sas158974 * If typeflag is not 'A' and xhdr_flgs is set, then processing
56485482Sas158974 * of ancillary file is either over or ancillary file
56495482Sas158974 * processing is not required, load info from Xtarhdr and set
56505482Sas158974 * _X_XHDR bit in xhdr_flgs.
56515482Sas158974 */
56525482Sas158974 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
56535482Sas158974 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
56545482Sas158974 xhdr_flgs |= _X_XHDR;
56555482Sas158974 }
56565482Sas158974
56570Sstevel@tonic-gate #if defined(O_XATTR)
56580Sstevel@tonic-gate if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
56595331Samw /*
56605331Samw * Always needs to read the extended header. If atflag, saflag,
56615331Samw * or tflag isn't set, then we'll have the correct info for
56625331Samw * passtape() later.
56635331Samw */
56645331Samw (void) read_xattr_hdr(attrinfo);
56650Sstevel@tonic-gate goto top;
56660Sstevel@tonic-gate }
56675331Samw /*
56685750Sceastha * Now that we've read the extended header, call passtape()
56695750Sceastha * if we don't want to restore attributes or system attributes.
56705750Sceastha * Don't restore the attribute if we are extracting
56715750Sceastha * a file from an archive (as opposed to doing a table of
56725750Sceastha * contents) and any of the following are true:
56735750Sceastha * 1. neither -@ or -/ was specified.
56745750Sceastha * 2. -@ was specified, -/ wasn't specified, and we're
56755750Sceastha * processing a hidden attribute directory of an attribute
56765750Sceastha * or we're processing a read-write system attribute file.
56775750Sceastha * 3. -@ wasn't specified, -/ was specified, and the file
56785750Sceastha * we're processing is not a read-write system attribute file,
56795750Sceastha * or we're processing the hidden attribute directory of an
56805750Sceastha * attribute.
56815750Sceastha *
56825750Sceastha * We always process the attributes if we're just generating
56835750Sceastha * generating a table of contents, or if both -@ and -/ were
56845750Sceastha * specified.
56855331Samw */
56865750Sceastha if (xattrp != NULL) {
56875750Sceastha attr_data_t *ainfo = *attrinfo;
56885750Sceastha
56895750Sceastha if (!tflag &&
56905750Sceastha ((!atflag && !saflag) ||
56915750Sceastha (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
56925750Sceastha ainfo->attr_rw_sysattr)) ||
56935750Sceastha (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
56945750Sceastha !ainfo->attr_rw_sysattr)))) {
56955750Sceastha passtape();
56965750Sceastha return (0);
56975750Sceastha }
56985331Samw }
56990Sstevel@tonic-gate #endif
57000Sstevel@tonic-gate
57010Sstevel@tonic-gate /* sets *namep to point at the proper name */
57025331Samw if (check_prefix(namep, dirp, component) != 0) {
57035331Samw passtape();
57045331Samw return (0);
57055331Samw }
57060Sstevel@tonic-gate
57070Sstevel@tonic-gate if (endtape()) {
57080Sstevel@tonic-gate if (Bflag) {
57090Sstevel@tonic-gate /*
57100Sstevel@tonic-gate * Logically at EOT - consume any extra blocks
57110Sstevel@tonic-gate * so that write to our stdin won't fail and
57120Sstevel@tonic-gate * emit an error message; otherwise something
57130Sstevel@tonic-gate * like "dd if=foo.tar | (cd bar; tar xvf -)"
57140Sstevel@tonic-gate * will produce a bogus error message from "dd".
57150Sstevel@tonic-gate */
57160Sstevel@tonic-gate
57170Sstevel@tonic-gate while (read(mt, tbuf, TBLOCK*nblock) > 0) {
57180Sstevel@tonic-gate /* empty body */
57190Sstevel@tonic-gate }
57200Sstevel@tonic-gate }
57210Sstevel@tonic-gate return (-1);
57220Sstevel@tonic-gate }
57230Sstevel@tonic-gate
57240Sstevel@tonic-gate gotit = 0;
57250Sstevel@tonic-gate
57260Sstevel@tonic-gate if ((Iflag && is_in_table(include_tbl, *namep)) ||
57270Sstevel@tonic-gate (! Iflag && *argv == NULL)) {
57280Sstevel@tonic-gate gotit = 1;
57290Sstevel@tonic-gate } else {
57300Sstevel@tonic-gate for (cp = argv; *cp; cp++) {
57310Sstevel@tonic-gate if (is_prefix(*cp, *namep)) {
57320Sstevel@tonic-gate gotit = 1;
57330Sstevel@tonic-gate break;
57340Sstevel@tonic-gate }
57350Sstevel@tonic-gate }
57360Sstevel@tonic-gate }
57370Sstevel@tonic-gate
57380Sstevel@tonic-gate if (! gotit) {
57390Sstevel@tonic-gate passtape();
57400Sstevel@tonic-gate return (0);
57410Sstevel@tonic-gate }
57420Sstevel@tonic-gate
57430Sstevel@tonic-gate if (Xflag && is_in_table(exclude_tbl, *namep)) {
57440Sstevel@tonic-gate if (vflag) {
57450Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s excluded\n"),
57460Sstevel@tonic-gate *namep);
57470Sstevel@tonic-gate }
57480Sstevel@tonic-gate passtape();
57490Sstevel@tonic-gate return (0);
57500Sstevel@tonic-gate }
57510Sstevel@tonic-gate
57520Sstevel@tonic-gate return (1);
57530Sstevel@tonic-gate }
57540Sstevel@tonic-gate
57555482Sas158974
57565482Sas158974 static void
setbytes_to_skip(struct stat * st,int err)57575482Sas158974 setbytes_to_skip(struct stat *st, int err)
57585482Sas158974 {
57595482Sas158974 /*
57605482Sas158974 * In a scenario where a typeflag 'X' was followed by
57615482Sas158974 * a typeflag 'A' and typeflag 'O', then the number of
57625482Sas158974 * bytes to skip should be the size of ancillary file,
57635482Sas158974 * plus the dblock for regular file, and the size
57645482Sas158974 * from Xtarhdr. However, if the typeflag was just 'X'
57655482Sas158974 * followed by typeflag 'O', then the number of bytes
57665482Sas158974 * to skip should be the size from Xtarhdr.
57675482Sas158974 */
57685482Sas158974 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
576912109SRalph.Turner@Sun.COM (xhdr_flgs & _X_SIZE)) {
57705750Sceastha st->st_size += TBLOCK + Xtarhdr.x_filesz;
57715482Sas158974 xhdr_flgs |= _X_XHDR;
57725482Sas158974 } else if ((dblock.dbuf.typeflag != 'A') &&
577312109SRalph.Turner@Sun.COM (xhdr_flgs & _X_SIZE)) {
577412109SRalph.Turner@Sun.COM st->st_size += Xtarhdr.x_filesz;
57755482Sas158974 xhdr_flgs |= _X_XHDR;
57765482Sas158974 }
57775482Sas158974 }
57785482Sas158974
57795331Samw static int
fill_in_attr_info(char * attr,char * longname,char * attrparent,int atparentfd,int rw_sysattr,attr_data_t ** attrinfo)57805331Samw fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
57815331Samw int rw_sysattr, attr_data_t **attrinfo)
57825331Samw {
57835331Samw size_t pathlen;
57845331Samw char *tpath;
57855331Samw char *tparent;
57865331Samw
57875331Samw /* parent info */
57885331Samw if (attrparent != NULL) {
57895331Samw if ((tparent = strdup(attrparent)) == NULL) {
57905331Samw vperror(0, gettext(
57915331Samw "unable to allocate memory for attribute parent "
57925331Samw "name for %sattribute %s/%s of %s"),
57935331Samw rw_sysattr ? gettext("system ") : "",
57945331Samw attrparent, attr, longname);
57955331Samw return (1);
57965331Samw }
57975331Samw } else {
57985331Samw tparent = NULL;
57995331Samw }
58005331Samw
58015331Samw /* path info */
58025331Samw pathlen = strlen(attr) + 1;
58035331Samw if (attrparent != NULL) {
58045331Samw pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
58055331Samw }
58065331Samw if ((tpath = calloc(1, pathlen)) == NULL) {
58075331Samw vperror(0, gettext(
58085331Samw "unable to allocate memory for full "
58095331Samw "attribute path name for %sattribute %s%s%s of %s"),
58105331Samw rw_sysattr ? gettext("system ") : "",
58115331Samw (attrparent == NULL) ? "" : attrparent,
58125331Samw (attrparent == NULL) ? "" : "/",
58135331Samw attr, longname);
58145331Samw if (tparent != NULL) {
58155331Samw free(tparent);
58165331Samw }
58175331Samw return (1);
58185331Samw }
58195331Samw (void) snprintf(tpath, pathlen, "%s%s%s",
58205331Samw (attrparent == NULL) ? "" : attrparent,
58215331Samw (attrparent == NULL) ? "" : "/",
58225331Samw attr);
58235331Samw
58245331Samw /* fill in the attribute info */
58255331Samw if (*attrinfo == NULL) {
58265331Samw if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
58275331Samw vperror(0, gettext(
58285331Samw "unable to allocate memory for attribute "
58295331Samw "information for %sattribute %s%s%s of %s"),
58305331Samw rw_sysattr ? gettext("system ") : "",
58315331Samw (attrparent == NULL) ? "" : attrparent,
58325331Samw (attrparent == NULL) ? "" : gettext("/"),
58335331Samw attr, longname);
58345331Samw if (tparent != NULL) {
58355331Samw free(tparent);
58365331Samw }
58375331Samw free(tpath);
58385331Samw return (1);
58395331Samw }
58405331Samw } else {
58415331Samw if ((*attrinfo)->attr_parent != NULL) {
58425331Samw free((*attrinfo)->attr_parent);
58435331Samw }
58445331Samw if ((*attrinfo)->attr_path != NULL) {
58455331Samw free((*attrinfo)->attr_path);
58465331Samw }
58475331Samw /*
58485331Samw * The parent file descriptor is passed in, so don't
58495331Samw * close it here as it should be closed by the function
58505331Samw * that opened it.
58515331Samw */
58525331Samw }
58535331Samw (*attrinfo)->attr_parent = tparent;
58545331Samw (*attrinfo)->attr_path = tpath;
58555331Samw (*attrinfo)->attr_rw_sysattr = rw_sysattr;
58565331Samw (*attrinfo)->attr_parentfd = atparentfd;
58575331Samw
58585331Samw return (0);
58595331Samw }
58600Sstevel@tonic-gate
58610Sstevel@tonic-gate /*
586212423Srich.burridge@oracle.com * Test to see if name is a directory.
586312423Srich.burridge@oracle.com *
586412423Srich.burridge@oracle.com * Return 1 if true, 0 otherwise.
586512423Srich.burridge@oracle.com */
586612423Srich.burridge@oracle.com
586712423Srich.burridge@oracle.com static int
is_directory(char * name)586812423Srich.burridge@oracle.com is_directory(char *name)
586912423Srich.burridge@oracle.com {
587012423Srich.burridge@oracle.com #if defined(O_XATTR)
587112423Srich.burridge@oracle.com /*
587212423Srich.burridge@oracle.com * If there is an xattr_buf structure associated with this file,
587312423Srich.burridge@oracle.com * then the directory test is based on whether the name has a
587412423Srich.burridge@oracle.com * trailing slash.
587512423Srich.burridge@oracle.com */
587612423Srich.burridge@oracle.com if (xattrp)
587712423Srich.burridge@oracle.com return (name[strlen(name) - 1] == '/');
587812423Srich.burridge@oracle.com #endif
587912423Srich.burridge@oracle.com if (is_posix)
588012423Srich.burridge@oracle.com return (dblock.dbuf.typeflag == '5');
588112423Srich.burridge@oracle.com else
588212423Srich.burridge@oracle.com return (name[strlen(name) - 1] == '/');
588312423Srich.burridge@oracle.com }
588412423Srich.burridge@oracle.com
588512423Srich.burridge@oracle.com /*
588612554Srich.burridge@oracle.com * Version of chdir that handles directory pathnames of greater than PATH_MAX
588712554Srich.burridge@oracle.com * length, by changing the working directory to manageable portions of the
588812554Srich.burridge@oracle.com * complete directory pathname. If any of these attempts fail, then it exits
588912554Srich.burridge@oracle.com * non-zero.
589012554Srich.burridge@oracle.com *
589112554Srich.burridge@oracle.com * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
589212554Srich.burridge@oracle.com * pathname is greater than PATH_MAX, then this still won't work, and this
589312554Srich.burridge@oracle.com * routine will return -1 with errno set to ENAMETOOLONG.
589412554Srich.burridge@oracle.com *
589512554Srich.burridge@oracle.com * NOTE: this routine is semantically different to the system chdir in
589612554Srich.burridge@oracle.com * that it is remotely possible for the currently working directory to be
589712554Srich.burridge@oracle.com * changed to a different directory, if a chdir call fails when processing
589812554Srich.burridge@oracle.com * one of the segments of a path that is greater than PATH_MAX. This isn't
589912554Srich.burridge@oracle.com * a problem as this is tar's own specific version of chdir.
590012554Srich.burridge@oracle.com */
590112554Srich.burridge@oracle.com
590212554Srich.burridge@oracle.com static int
tar_chdir(const char * path)590312554Srich.burridge@oracle.com tar_chdir(const char *path) {
590412554Srich.burridge@oracle.com const char *sep = "/";
590512554Srich.burridge@oracle.com char *path_copy = NULL;
590612554Srich.burridge@oracle.com char *ptr = NULL;
590712554Srich.burridge@oracle.com
590812554Srich.burridge@oracle.com /* The trivial case. */
590912554Srich.burridge@oracle.com if (chdir(path) == 0) {
591012554Srich.burridge@oracle.com return (0);
591112554Srich.burridge@oracle.com }
591212554Srich.burridge@oracle.com if (errno == ENAMETOOLONG) {
591312554Srich.burridge@oracle.com if (path[0] == '/' && chdir(sep) != 0)
591412554Srich.burridge@oracle.com return (-1);
591512554Srich.burridge@oracle.com
591612554Srich.burridge@oracle.com /* strtok(3C) modifies the string, so make a copy. */
591712554Srich.burridge@oracle.com if ((path_copy = strdup(path)) == NULL) {
591812554Srich.burridge@oracle.com return (-1);
591912554Srich.burridge@oracle.com }
592012554Srich.burridge@oracle.com
592112554Srich.burridge@oracle.com /* chdir(2) for every path element. */
592212554Srich.burridge@oracle.com for (ptr = strtok(path_copy, sep);
592312554Srich.burridge@oracle.com ptr != NULL;
592412554Srich.burridge@oracle.com ptr = strtok(NULL, sep)) {
592512554Srich.burridge@oracle.com if (chdir(ptr) != 0) {
592612554Srich.burridge@oracle.com free(path_copy);
592712554Srich.burridge@oracle.com return (-1);
592812554Srich.burridge@oracle.com }
592912554Srich.burridge@oracle.com }
593012554Srich.burridge@oracle.com free(path_copy);
593112554Srich.burridge@oracle.com return (0);
593212554Srich.burridge@oracle.com }
593312554Srich.burridge@oracle.com
593412554Srich.burridge@oracle.com /* If chdir fails for any reason except ENAMETOOLONG. */
593512554Srich.burridge@oracle.com return (-1);
593612554Srich.burridge@oracle.com }
593712554Srich.burridge@oracle.com
593812554Srich.burridge@oracle.com /*
593912201Srich.burridge@sun.com * Test if name has a '..' sequence in it.
594012201Srich.burridge@sun.com *
594112201Srich.burridge@sun.com * Return 1 if found, 0 otherwise.
594212201Srich.burridge@sun.com */
594312201Srich.burridge@sun.com
594412201Srich.burridge@sun.com static int
has_dot_dot(char * name)594512201Srich.burridge@sun.com has_dot_dot(char *name)
594612201Srich.burridge@sun.com {
594712201Srich.burridge@sun.com char *s;
594812201Srich.burridge@sun.com size_t name_len = strlen(name);
594912201Srich.burridge@sun.com
595012201Srich.burridge@sun.com for (s = name; s < (name + name_len - 2); s++) {
595112201Srich.burridge@sun.com if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
595212201Srich.burridge@sun.com return (1);
595312201Srich.burridge@sun.com
595412201Srich.burridge@sun.com while (! (*s == '/')) {
595512201Srich.burridge@sun.com if (! *s++)
595612201Srich.burridge@sun.com return (0);
595712201Srich.burridge@sun.com }
595812201Srich.burridge@sun.com }
595912201Srich.burridge@sun.com
596012201Srich.burridge@sun.com return (0);
596112201Srich.burridge@sun.com }
596212201Srich.burridge@sun.com
596312201Srich.burridge@sun.com /*
596412201Srich.burridge@sun.com * Test if name is an absolute path name.
596512201Srich.burridge@sun.com *
596612201Srich.burridge@sun.com * Return 1 if true, 0 otherwise.
596712201Srich.burridge@sun.com */
596812201Srich.burridge@sun.com
596912201Srich.burridge@sun.com static int
is_absolute(char * name)597012201Srich.burridge@sun.com is_absolute(char *name)
597112201Srich.burridge@sun.com {
597212436Srich.burridge@oracle.com #if defined(O_XATTR)
597312436Srich.burridge@oracle.com /*
597412436Srich.burridge@oracle.com * If this is an extended attribute (whose name will begin with
597512436Srich.burridge@oracle.com * "/dev/null/", always return 0 as they should be extracted with
597612436Srich.burridge@oracle.com * the name intact, to allow other tar archiving programs that
597712436Srich.burridge@oracle.com * don't understand extended attributes, to correctly throw them away.
597812436Srich.burridge@oracle.com */
597912436Srich.burridge@oracle.com if (xattrp)
598012436Srich.burridge@oracle.com return (0);
598112436Srich.burridge@oracle.com #endif
598212436Srich.burridge@oracle.com
598312201Srich.burridge@sun.com return (name[0] == '/');
598412201Srich.burridge@sun.com }
598512201Srich.burridge@sun.com
598612201Srich.burridge@sun.com /*
598712201Srich.burridge@sun.com * Adjust the pathname to make it a relative one. Strip off any leading
598812201Srich.burridge@sun.com * '/' characters and if the pathname contains any '..' sequences, strip
598912201Srich.burridge@sun.com * upto and including the last occurance of '../' (or '..' if found at
599012201Srich.burridge@sun.com * the very end of the pathname).
599112201Srich.burridge@sun.com *
599212201Srich.burridge@sun.com * Return the relative pathname. stripped_prefix will also return the
599312201Srich.burridge@sun.com * portion of name that was stripped off and should be freed by the
599412201Srich.burridge@sun.com * calling routine when no longer needed.
599512201Srich.burridge@sun.com */
599612201Srich.burridge@sun.com
599712201Srich.burridge@sun.com static char *
make_relative_name(char * name,char ** stripped_prefix)599812201Srich.burridge@sun.com make_relative_name(char *name, char **stripped_prefix)
599912201Srich.burridge@sun.com {
600012201Srich.burridge@sun.com char *s;
600112201Srich.burridge@sun.com size_t prefix_len = 0;
600212201Srich.burridge@sun.com size_t name_len = strlen(name);
600312201Srich.burridge@sun.com
600412201Srich.burridge@sun.com for (s = name + prefix_len; s < (name + name_len - 2); ) {
600512201Srich.burridge@sun.com if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
600612201Srich.burridge@sun.com prefix_len = s + 2 - name;
600712201Srich.burridge@sun.com
600812201Srich.burridge@sun.com do {
600912201Srich.burridge@sun.com char c = *s++;
601012201Srich.burridge@sun.com
601112201Srich.burridge@sun.com if (c == '/')
601212201Srich.burridge@sun.com break;
601312201Srich.burridge@sun.com } while (*s);
601412201Srich.burridge@sun.com }
601512201Srich.burridge@sun.com
601612201Srich.burridge@sun.com for (s = name + prefix_len; *s == '/'; s++)
601712201Srich.burridge@sun.com continue;
601812201Srich.burridge@sun.com prefix_len = s - name;
601912201Srich.burridge@sun.com
602012201Srich.burridge@sun.com /* Create the portion of the name that was stripped off. */
602112201Srich.burridge@sun.com s = malloc(prefix_len + 1);
602212201Srich.burridge@sun.com memcpy(s, name, prefix_len);
602312201Srich.burridge@sun.com s[prefix_len] = 0;
602412201Srich.burridge@sun.com *stripped_prefix = s;
602512201Srich.burridge@sun.com s = &name[prefix_len];
602612201Srich.burridge@sun.com
602712201Srich.burridge@sun.com return (s);
602812201Srich.burridge@sun.com }
602912201Srich.burridge@sun.com
603012201Srich.burridge@sun.com /*
60310Sstevel@tonic-gate * Return through *namep a pointer to the proper fullname (i.e "<name> |
60320Sstevel@tonic-gate * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
60335331Samw *
60345331Samw * Returns 0 if successful, otherwise returns 1.
60350Sstevel@tonic-gate */
60360Sstevel@tonic-gate
60375331Samw static int
check_prefix(char ** namep,char ** dirp,char ** compp)60380Sstevel@tonic-gate check_prefix(char **namep, char **dirp, char **compp)
60390Sstevel@tonic-gate {
60400Sstevel@tonic-gate static char fullname[PATH_MAX + 1];
60410Sstevel@tonic-gate static char dir[PATH_MAX + 1];
60420Sstevel@tonic-gate static char component[PATH_MAX + 1];
60430Sstevel@tonic-gate static char savename[PATH_MAX + 1];
60440Sstevel@tonic-gate char *s;
60450Sstevel@tonic-gate
60460Sstevel@tonic-gate (void) memset(dir, 0, sizeof (dir));
60470Sstevel@tonic-gate (void) memset(component, 0, sizeof (component));
60480Sstevel@tonic-gate
60490Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) {
60500Sstevel@tonic-gate (void) strcpy(fullname, Xtarhdr.x_path);
60510Sstevel@tonic-gate } else {
60520Sstevel@tonic-gate if (dblock.dbuf.prefix[0] != '\0')
60530Sstevel@tonic-gate (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
60540Sstevel@tonic-gate dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
60550Sstevel@tonic-gate else
60560Sstevel@tonic-gate (void) sprintf(fullname, "%.*s", NAMSIZ,
60570Sstevel@tonic-gate dblock.dbuf.name);
60580Sstevel@tonic-gate }
60590Sstevel@tonic-gate
60600Sstevel@tonic-gate /*
606112201Srich.burridge@sun.com * If we are printing a table of contents or extracting an archive,
606212201Srich.burridge@sun.com * make absolute pathnames relative and prohibit the unpacking of
606312201Srich.burridge@sun.com * files contain ".." in their name (unless the user has supplied
606412201Srich.burridge@sun.com * the -P option).
606512201Srich.burridge@sun.com */
606612201Srich.burridge@sun.com if ((tflag || xflag) && !Pflag) {
606712201Srich.burridge@sun.com if (is_absolute(fullname) || has_dot_dot(fullname)) {
606812201Srich.burridge@sun.com char *stripped_prefix;
606912201Srich.burridge@sun.com size_t prefix_len = 0;
607012201Srich.burridge@sun.com
607112201Srich.burridge@sun.com (void) strcpy(savename, fullname);
607212201Srich.burridge@sun.com strcpy(fullname,
607312201Srich.burridge@sun.com make_relative_name(savename, &stripped_prefix));
607412201Srich.burridge@sun.com (void) fprintf(stderr,
607512201Srich.burridge@sun.com gettext("tar: Removing leading '%s' from '%s'\n"),
607612201Srich.burridge@sun.com stripped_prefix, savename);
607712201Srich.burridge@sun.com free(stripped_prefix);
607812201Srich.burridge@sun.com }
607912201Srich.burridge@sun.com }
608012201Srich.burridge@sun.com
608112201Srich.burridge@sun.com /*
60820Sstevel@tonic-gate * Set dir and component names
60830Sstevel@tonic-gate */
60840Sstevel@tonic-gate
60850Sstevel@tonic-gate get_parent(fullname, dir);
60860Sstevel@tonic-gate
60870Sstevel@tonic-gate #if defined(O_XATTR)
60885331Samw if (xattrp == NULL) {
60890Sstevel@tonic-gate #endif
60900Sstevel@tonic-gate /*
60910Sstevel@tonic-gate * Save of real name since were going to chop off the
60920Sstevel@tonic-gate * trailing slashes.
60930Sstevel@tonic-gate */
60940Sstevel@tonic-gate (void) strcpy(savename, fullname);
60950Sstevel@tonic-gate /*
60960Sstevel@tonic-gate * first strip of trailing slashes.
60970Sstevel@tonic-gate */
60980Sstevel@tonic-gate chop_endslashes(savename);
60990Sstevel@tonic-gate s = get_component(savename);
61000Sstevel@tonic-gate (void) strcpy(component, s);
61010Sstevel@tonic-gate
61020Sstevel@tonic-gate #if defined(O_XATTR)
61030Sstevel@tonic-gate } else {
61040Sstevel@tonic-gate (void) strcpy(fullname, xattrp->h_names);
61050Sstevel@tonic-gate (void) strcpy(dir, fullname);
61065331Samw (void) strcpy(component, basename(xattrp->h_names +
61075331Samw strlen(xattrp->h_names) + 1));
61080Sstevel@tonic-gate }
61090Sstevel@tonic-gate #endif
61100Sstevel@tonic-gate *namep = fullname;
61110Sstevel@tonic-gate *dirp = dir;
61120Sstevel@tonic-gate *compp = component;
61135331Samw
61145331Samw return (0);
61150Sstevel@tonic-gate }
61160Sstevel@tonic-gate
61170Sstevel@tonic-gate /*
61180Sstevel@tonic-gate * Return true if the object indicated by the file descriptor and type
61190Sstevel@tonic-gate * is a tape device, false otherwise
61200Sstevel@tonic-gate */
61210Sstevel@tonic-gate
61220Sstevel@tonic-gate static int
istape(int fd,int type)61230Sstevel@tonic-gate istape(int fd, int type)
61240Sstevel@tonic-gate {
61250Sstevel@tonic-gate int result = 0;
61260Sstevel@tonic-gate
6127871Scasper if (S_ISCHR(type)) {
61280Sstevel@tonic-gate struct mtget mtg;
61290Sstevel@tonic-gate
61300Sstevel@tonic-gate if (ioctl(fd, MTIOCGET, &mtg) != -1) {
61310Sstevel@tonic-gate result = 1;
61320Sstevel@tonic-gate }
61330Sstevel@tonic-gate }
61340Sstevel@tonic-gate
61350Sstevel@tonic-gate return (result);
61360Sstevel@tonic-gate }
61370Sstevel@tonic-gate
61380Sstevel@tonic-gate #include <utmpx.h>
61390Sstevel@tonic-gate
61400Sstevel@tonic-gate struct utmpx utmpx;
61410Sstevel@tonic-gate
61420Sstevel@tonic-gate #define NMAX (sizeof (utmpx.ut_name))
61430Sstevel@tonic-gate
61440Sstevel@tonic-gate typedef struct cachenode { /* this struct must be zeroed before using */
61450Sstevel@tonic-gate struct cachenode *next; /* next in hash chain */
61460Sstevel@tonic-gate int val; /* the uid or gid of this entry */
61470Sstevel@tonic-gate int namehash; /* name's hash signature */
61480Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */
61490Sstevel@tonic-gate } cachenode_t;
61500Sstevel@tonic-gate
61510Sstevel@tonic-gate #define HASHSIZE 256
61520Sstevel@tonic-gate
61530Sstevel@tonic-gate static cachenode_t *names[HASHSIZE];
61540Sstevel@tonic-gate static cachenode_t *groups[HASHSIZE];
61550Sstevel@tonic-gate static cachenode_t *uids[HASHSIZE];
61560Sstevel@tonic-gate static cachenode_t *gids[HASHSIZE];
61570Sstevel@tonic-gate
61580Sstevel@tonic-gate static int
hash_byname(char * name)61590Sstevel@tonic-gate hash_byname(char *name)
61600Sstevel@tonic-gate {
61610Sstevel@tonic-gate int i, c, h = 0;
61620Sstevel@tonic-gate
61630Sstevel@tonic-gate for (i = 0; i < NMAX; i++) {
61640Sstevel@tonic-gate c = name[i];
61650Sstevel@tonic-gate if (c == '\0')
61660Sstevel@tonic-gate break;
61670Sstevel@tonic-gate h = (h << 4) + h + c;
61680Sstevel@tonic-gate }
61690Sstevel@tonic-gate return (h);
61700Sstevel@tonic-gate }
61710Sstevel@tonic-gate
61720Sstevel@tonic-gate static cachenode_t *
hash_lookup_byval(cachenode_t * table[],int val)61730Sstevel@tonic-gate hash_lookup_byval(cachenode_t *table[], int val)
61740Sstevel@tonic-gate {
61750Sstevel@tonic-gate int h = val;
61760Sstevel@tonic-gate cachenode_t *c;
61770Sstevel@tonic-gate
61780Sstevel@tonic-gate for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
61790Sstevel@tonic-gate if (c->val == val)
61800Sstevel@tonic-gate return (c);
61810Sstevel@tonic-gate }
61820Sstevel@tonic-gate return (NULL);
61830Sstevel@tonic-gate }
61840Sstevel@tonic-gate
61850Sstevel@tonic-gate static cachenode_t *
hash_lookup_byname(cachenode_t * table[],char * name)61860Sstevel@tonic-gate hash_lookup_byname(cachenode_t *table[], char *name)
61870Sstevel@tonic-gate {
61880Sstevel@tonic-gate int h = hash_byname(name);
61890Sstevel@tonic-gate cachenode_t *c;
61900Sstevel@tonic-gate
61910Sstevel@tonic-gate for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
61920Sstevel@tonic-gate if (c->namehash == h && strcmp(c->name, name) == 0)
61930Sstevel@tonic-gate return (c);
61940Sstevel@tonic-gate }
61950Sstevel@tonic-gate return (NULL);
61960Sstevel@tonic-gate }
61970Sstevel@tonic-gate
61980Sstevel@tonic-gate static cachenode_t *
hash_insert(cachenode_t * table[],char * name,int value)61990Sstevel@tonic-gate hash_insert(cachenode_t *table[], char *name, int value)
62000Sstevel@tonic-gate {
62010Sstevel@tonic-gate cachenode_t *c;
62020Sstevel@tonic-gate int signature;
62030Sstevel@tonic-gate
62040Sstevel@tonic-gate c = calloc(1, sizeof (cachenode_t));
62050Sstevel@tonic-gate if (c == NULL) {
62060Sstevel@tonic-gate perror("malloc");
62070Sstevel@tonic-gate exit(1);
62080Sstevel@tonic-gate }
62090Sstevel@tonic-gate if (name != NULL) {
62100Sstevel@tonic-gate (void) strncpy(c->name, name, NMAX);
62110Sstevel@tonic-gate c->namehash = hash_byname(name);
62120Sstevel@tonic-gate }
62130Sstevel@tonic-gate c->val = value;
62140Sstevel@tonic-gate if (table == uids || table == gids)
62150Sstevel@tonic-gate signature = c->val;
62160Sstevel@tonic-gate else
62170Sstevel@tonic-gate signature = c->namehash;
62180Sstevel@tonic-gate c->next = table[signature & (HASHSIZE - 1)];
62190Sstevel@tonic-gate table[signature & (HASHSIZE - 1)] = c;
62200Sstevel@tonic-gate return (c);
62210Sstevel@tonic-gate }
62220Sstevel@tonic-gate
62230Sstevel@tonic-gate static char *
getname(uid_t uid)62240Sstevel@tonic-gate getname(uid_t uid)
62250Sstevel@tonic-gate {
62260Sstevel@tonic-gate cachenode_t *c;
62270Sstevel@tonic-gate
62280Sstevel@tonic-gate if ((c = hash_lookup_byval(uids, uid)) == NULL) {
62290Sstevel@tonic-gate struct passwd *pwent = getpwuid(uid);
62300Sstevel@tonic-gate c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
62310Sstevel@tonic-gate }
62320Sstevel@tonic-gate return (c->name);
62330Sstevel@tonic-gate }
62340Sstevel@tonic-gate
62350Sstevel@tonic-gate static char *
getgroup(gid_t gid)62360Sstevel@tonic-gate getgroup(gid_t gid)
62370Sstevel@tonic-gate {
62380Sstevel@tonic-gate cachenode_t *c;
62390Sstevel@tonic-gate
62400Sstevel@tonic-gate if ((c = hash_lookup_byval(gids, gid)) == NULL) {
62410Sstevel@tonic-gate struct group *grent = getgrgid(gid);
62420Sstevel@tonic-gate c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
62430Sstevel@tonic-gate }
62440Sstevel@tonic-gate return (c->name);
62450Sstevel@tonic-gate }
62460Sstevel@tonic-gate
62470Sstevel@tonic-gate static uid_t
getuidbyname(char * name)62480Sstevel@tonic-gate getuidbyname(char *name)
62490Sstevel@tonic-gate {
62500Sstevel@tonic-gate cachenode_t *c;
62510Sstevel@tonic-gate
62520Sstevel@tonic-gate if ((c = hash_lookup_byname(names, name)) == NULL) {
62530Sstevel@tonic-gate struct passwd *pwent = getpwnam(name);
62540Sstevel@tonic-gate c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
62550Sstevel@tonic-gate }
62560Sstevel@tonic-gate return ((uid_t)c->val);
62570Sstevel@tonic-gate }
62580Sstevel@tonic-gate
62590Sstevel@tonic-gate static gid_t
getgidbyname(char * group)62600Sstevel@tonic-gate getgidbyname(char *group)
62610Sstevel@tonic-gate {
62620Sstevel@tonic-gate cachenode_t *c;
62630Sstevel@tonic-gate
62640Sstevel@tonic-gate if ((c = hash_lookup_byname(groups, group)) == NULL) {
62650Sstevel@tonic-gate struct group *grent = getgrnam(group);
62660Sstevel@tonic-gate c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
62670Sstevel@tonic-gate }
62680Sstevel@tonic-gate return ((gid_t)c->val);
62690Sstevel@tonic-gate }
62700Sstevel@tonic-gate
62710Sstevel@tonic-gate /*
62720Sstevel@tonic-gate * Build the header.
62730Sstevel@tonic-gate * Determine whether or not an extended header is also needed. If needed,
62740Sstevel@tonic-gate * create and write the extended header and its data.
62750Sstevel@tonic-gate * Writing of the extended header assumes that "tomodes" has been called and
62760Sstevel@tonic-gate * the relevant information has been placed in the header block.
62770Sstevel@tonic-gate */
62780Sstevel@tonic-gate
62790Sstevel@tonic-gate static int
build_dblock(const char * name,const char * linkname,const char typeflag,const int filetype,const struct stat * sp,const dev_t device,const char * prefix)62800Sstevel@tonic-gate build_dblock(
62810Sstevel@tonic-gate const char *name,
62820Sstevel@tonic-gate const char *linkname,
62830Sstevel@tonic-gate const char typeflag,
62840Sstevel@tonic-gate const int filetype,
62850Sstevel@tonic-gate const struct stat *sp,
62860Sstevel@tonic-gate const dev_t device,
62870Sstevel@tonic-gate const char *prefix)
62880Sstevel@tonic-gate {
62890Sstevel@tonic-gate int nblks;
62900Sstevel@tonic-gate major_t dev;
62910Sstevel@tonic-gate const char *filename;
62920Sstevel@tonic-gate const char *lastslash;
62930Sstevel@tonic-gate
62940Sstevel@tonic-gate if (filetype == XATTR_FILE)
62950Sstevel@tonic-gate dblock.dbuf.typeflag = _XATTR_HDRTYPE;
62960Sstevel@tonic-gate else
62970Sstevel@tonic-gate dblock.dbuf.typeflag = typeflag;
62980Sstevel@tonic-gate (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
62990Sstevel@tonic-gate (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
63000Sstevel@tonic-gate (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
63010Sstevel@tonic-gate
63020Sstevel@tonic-gate if (xhdr_flgs & _X_PATH)
63030Sstevel@tonic-gate filename = Xtarhdr.x_path;
63040Sstevel@tonic-gate else
63050Sstevel@tonic-gate filename = name;
63060Sstevel@tonic-gate
63070Sstevel@tonic-gate if ((dev = major(device)) > OCTAL7CHAR) {
63080Sstevel@tonic-gate if (Eflag) {
63090Sstevel@tonic-gate xhdr_flgs |= _X_DEVMAJOR;
63100Sstevel@tonic-gate Xtarhdr.x_devmajor = dev;
63110Sstevel@tonic-gate } else {
63120Sstevel@tonic-gate (void) fprintf(stderr, gettext(
63130Sstevel@tonic-gate "Device major too large for %s. Use -E flag."),
63140Sstevel@tonic-gate filename);
63150Sstevel@tonic-gate if (errflag)
63160Sstevel@tonic-gate done(1);
63170Sstevel@tonic-gate else
63180Sstevel@tonic-gate Errflg = 1;
63190Sstevel@tonic-gate }
63200Sstevel@tonic-gate dev = 0;
63210Sstevel@tonic-gate }
63220Sstevel@tonic-gate (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
63230Sstevel@tonic-gate if ((dev = minor(device)) > OCTAL7CHAR) {
63240Sstevel@tonic-gate if (Eflag) {
63250Sstevel@tonic-gate xhdr_flgs |= _X_DEVMINOR;
63260Sstevel@tonic-gate Xtarhdr.x_devminor = dev;
63270Sstevel@tonic-gate } else {
63280Sstevel@tonic-gate (void) fprintf(stderr, gettext(
63290Sstevel@tonic-gate "Device minor too large for %s. Use -E flag."),
63300Sstevel@tonic-gate filename);
63310Sstevel@tonic-gate if (errflag)
63320Sstevel@tonic-gate done(1);
63330Sstevel@tonic-gate else
63340Sstevel@tonic-gate Errflg = 1;
63350Sstevel@tonic-gate }
63360Sstevel@tonic-gate dev = 0;
63370Sstevel@tonic-gate }
63380Sstevel@tonic-gate (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
63390Sstevel@tonic-gate
63400Sstevel@tonic-gate (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
63410Sstevel@tonic-gate (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
63420Sstevel@tonic-gate (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
63430Sstevel@tonic-gate (void) sprintf(dblock.dbuf.version, "00");
63440Sstevel@tonic-gate (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
63450Sstevel@tonic-gate (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
63460Sstevel@tonic-gate (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
63470Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
63480Sstevel@tonic-gate
63490Sstevel@tonic-gate if (Eflag) {
63500Sstevel@tonic-gate (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
63510Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
63520Sstevel@tonic-gate lastslash = strrchr(name, '/');
63530Sstevel@tonic-gate if (lastslash == NULL)
63540Sstevel@tonic-gate lastslash = name;
63550Sstevel@tonic-gate else
63560Sstevel@tonic-gate lastslash++;
63570Sstevel@tonic-gate (void) strcpy(xhdr_buf.dbuf.name, lastslash);
63580Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
63590Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
63600Sstevel@tonic-gate (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
63610Sstevel@tonic-gate xhdr_count++;
63620Sstevel@tonic-gate xrec_offset = 0;
63630Sstevel@tonic-gate gen_date("mtime", sp->st_mtim);
63640Sstevel@tonic-gate xhdr_buf.dbuf.typeflag = 'X';
63650Sstevel@tonic-gate if (gen_utf8_names(filename) != 0)
63660Sstevel@tonic-gate return (1);
63670Sstevel@tonic-gate
63680Sstevel@tonic-gate #ifdef XHDR_DEBUG
63690Sstevel@tonic-gate Xtarhdr.x_uname = dblock.dbuf.uname;
63700Sstevel@tonic-gate Xtarhdr.x_gname = dblock.dbuf.gname;
63710Sstevel@tonic-gate xhdr_flgs |= (_X_UNAME | _X_GNAME);
63720Sstevel@tonic-gate #endif
63730Sstevel@tonic-gate if (xhdr_flgs) {
63740Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMAJOR)
63750Sstevel@tonic-gate gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
63760Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMINOR)
63770Sstevel@tonic-gate gen_num("SUN.devminor", Xtarhdr.x_devminor);
63780Sstevel@tonic-gate if (xhdr_flgs & _X_GID)
63790Sstevel@tonic-gate gen_num("gid", Xtarhdr.x_gid);
63800Sstevel@tonic-gate if (xhdr_flgs & _X_UID)
63810Sstevel@tonic-gate gen_num("uid", Xtarhdr.x_uid);
63820Sstevel@tonic-gate if (xhdr_flgs & _X_SIZE)
63830Sstevel@tonic-gate gen_num("size", Xtarhdr.x_filesz);
63840Sstevel@tonic-gate if (xhdr_flgs & _X_PATH)
63850Sstevel@tonic-gate gen_string("path", Xtarhdr.x_path);
63860Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH)
63870Sstevel@tonic-gate gen_string("linkpath", Xtarhdr.x_linkpath);
63880Sstevel@tonic-gate if (xhdr_flgs & _X_GNAME)
63890Sstevel@tonic-gate gen_string("gname", Xtarhdr.x_gname);
63900Sstevel@tonic-gate if (xhdr_flgs & _X_UNAME)
63910Sstevel@tonic-gate gen_string("uname", Xtarhdr.x_uname);
63920Sstevel@tonic-gate }
63930Sstevel@tonic-gate (void) sprintf(xhdr_buf.dbuf.size,
63940Sstevel@tonic-gate "%011" FMT_off_t_o, xrec_offset);
63950Sstevel@tonic-gate (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
63960Sstevel@tonic-gate checksum(&xhdr_buf));
63970Sstevel@tonic-gate (void) writetbuf((char *)&xhdr_buf, 1);
63980Sstevel@tonic-gate nblks = TBLOCKS(xrec_offset);
63990Sstevel@tonic-gate (void) writetbuf(xrec_ptr, nblks);
64000Sstevel@tonic-gate }
64010Sstevel@tonic-gate return (0);
64020Sstevel@tonic-gate }
64030Sstevel@tonic-gate
64040Sstevel@tonic-gate
64050Sstevel@tonic-gate /*
64060Sstevel@tonic-gate * makeDir - ensure that a directory with the pathname denoted by name
64070Sstevel@tonic-gate * exists, and return 1 on success, and 0 on failure (e.g.,
64080Sstevel@tonic-gate * read-only file system, exists but not-a-directory).
64090Sstevel@tonic-gate */
64100Sstevel@tonic-gate
64110Sstevel@tonic-gate static int
makeDir(char * name)64120Sstevel@tonic-gate makeDir(char *name)
64130Sstevel@tonic-gate {
64140Sstevel@tonic-gate struct stat buf;
64150Sstevel@tonic-gate
64160Sstevel@tonic-gate if (access(name, 0) < 0) { /* name doesn't exist */
64170Sstevel@tonic-gate if (mkdir(name, 0777) < 0) {
64180Sstevel@tonic-gate vperror(0, "%s", name);
64190Sstevel@tonic-gate return (0);
64200Sstevel@tonic-gate }
64210Sstevel@tonic-gate } else { /* name exists */
64220Sstevel@tonic-gate if (stat(name, &buf) < 0) {
64230Sstevel@tonic-gate vperror(0, "%s", name);
64240Sstevel@tonic-gate return (0);
64250Sstevel@tonic-gate }
64260Sstevel@tonic-gate
64270Sstevel@tonic-gate return ((buf.st_mode & S_IFMT) == S_IFDIR);
64280Sstevel@tonic-gate }
64290Sstevel@tonic-gate
64300Sstevel@tonic-gate return (1);
64310Sstevel@tonic-gate }
64320Sstevel@tonic-gate
64330Sstevel@tonic-gate
64340Sstevel@tonic-gate /*
64350Sstevel@tonic-gate * Save this directory and its mtime on the stack, popping and setting
64360Sstevel@tonic-gate * the mtimes of any stacked dirs which aren't parents of this one.
64370Sstevel@tonic-gate * A null name causes the entire stack to be unwound and set.
64380Sstevel@tonic-gate *
64390Sstevel@tonic-gate * Since all the elements of the directory "stack" share a common
64400Sstevel@tonic-gate * prefix, we can make do with one string. We keep only the current
64410Sstevel@tonic-gate * directory path, with an associated array of mtime's. A negative
64420Sstevel@tonic-gate * mtime means no mtime.
64430Sstevel@tonic-gate *
64440Sstevel@tonic-gate * This stack algorithm is not guaranteed to work for tapes created
64450Sstevel@tonic-gate * with the 'r' function letter, but the vast majority of tapes with
64460Sstevel@tonic-gate * directories are not. This avoids saving every directory record on
64470Sstevel@tonic-gate * the tape and setting all the times at the end.
64480Sstevel@tonic-gate *
64490Sstevel@tonic-gate * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
64500Sstevel@tonic-gate * environment)
64510Sstevel@tonic-gate */
64520Sstevel@tonic-gate
64530Sstevel@tonic-gate static void
doDirTimes(char * name,timestruc_t modTime)64540Sstevel@tonic-gate doDirTimes(char *name, timestruc_t modTime)
64550Sstevel@tonic-gate {
64560Sstevel@tonic-gate static char dirstack[PATH_MAX+2];
64570Sstevel@tonic-gate /* Add spaces for the last slash and last NULL */
64580Sstevel@tonic-gate static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
64590Sstevel@tonic-gate char *p = dirstack;
64600Sstevel@tonic-gate char *q = name;
64610Sstevel@tonic-gate char *savp;
64620Sstevel@tonic-gate
64630Sstevel@tonic-gate if (q) {
64640Sstevel@tonic-gate /*
64650Sstevel@tonic-gate * Find common prefix
64660Sstevel@tonic-gate */
64670Sstevel@tonic-gate
64680Sstevel@tonic-gate while (*p == *q && *p) {
64690Sstevel@tonic-gate p++; q++;
64700Sstevel@tonic-gate }
64710Sstevel@tonic-gate }
64720Sstevel@tonic-gate
64730Sstevel@tonic-gate savp = p;
64740Sstevel@tonic-gate while (*p) {
64750Sstevel@tonic-gate /*
64760Sstevel@tonic-gate * Not a child: unwind the stack, setting the times.
64770Sstevel@tonic-gate * The order we do this doesn't matter, so we go "forward."
64780Sstevel@tonic-gate */
64790Sstevel@tonic-gate
64800Sstevel@tonic-gate if (*p == '/')
64810Sstevel@tonic-gate if (modtimes[p - dirstack].tv_sec >= 0) {
64820Sstevel@tonic-gate *p = '\0'; /* zap the slash */
64830Sstevel@tonic-gate setPathTimes(AT_FDCWD, dirstack,
64841266Sceastha modtimes[p - dirstack]);
64850Sstevel@tonic-gate *p = '/';
64860Sstevel@tonic-gate }
64870Sstevel@tonic-gate ++p;
64880Sstevel@tonic-gate }
64890Sstevel@tonic-gate
64900Sstevel@tonic-gate p = savp;
64910Sstevel@tonic-gate
64920Sstevel@tonic-gate /*
64930Sstevel@tonic-gate * Push this one on the "stack"
64940Sstevel@tonic-gate */
64950Sstevel@tonic-gate
64960Sstevel@tonic-gate if (q) {
64970Sstevel@tonic-gate
64980Sstevel@tonic-gate /*
64990Sstevel@tonic-gate * Since the name parameter points the dir pathname
65000Sstevel@tonic-gate * which is limited only to contain PATH_MAX chars
65010Sstevel@tonic-gate * at maximum, we can ignore the overflow case of p.
65020Sstevel@tonic-gate */
65030Sstevel@tonic-gate
65040Sstevel@tonic-gate while ((*p = *q++)) { /* append the rest of the new dir */
65050Sstevel@tonic-gate modtimes[p - dirstack].tv_sec = -1;
65060Sstevel@tonic-gate p++;
65070Sstevel@tonic-gate }
65080Sstevel@tonic-gate
65090Sstevel@tonic-gate /*
65100Sstevel@tonic-gate * If the tar file had used 'P' or 'E' function modifier,
65110Sstevel@tonic-gate * append the last slash.
65120Sstevel@tonic-gate */
65130Sstevel@tonic-gate if (*(p - 1) != '/') {
65140Sstevel@tonic-gate *p++ = '/';
65150Sstevel@tonic-gate *p = '\0';
65160Sstevel@tonic-gate }
65170Sstevel@tonic-gate /* overwrite the last one */
65180Sstevel@tonic-gate modtimes[p - dirstack - 1] = modTime;
65190Sstevel@tonic-gate }
65200Sstevel@tonic-gate }
65210Sstevel@tonic-gate
65220Sstevel@tonic-gate
65230Sstevel@tonic-gate /*
65240Sstevel@tonic-gate * setPathTimes - set the modification time for given path. Return 1 if
65250Sstevel@tonic-gate * successful and 0 if not successful.
65260Sstevel@tonic-gate */
65270Sstevel@tonic-gate
65280Sstevel@tonic-gate static void
setPathTimes(int dirfd,char * path,timestruc_t modTime)65290Sstevel@tonic-gate setPathTimes(int dirfd, char *path, timestruc_t modTime)
65300Sstevel@tonic-gate
65310Sstevel@tonic-gate {
65320Sstevel@tonic-gate struct timeval timebuf[2];
65330Sstevel@tonic-gate
65340Sstevel@tonic-gate /*
65350Sstevel@tonic-gate * futimesat takes an array of two timeval structs.
65360Sstevel@tonic-gate * The first entry contains access time.
65370Sstevel@tonic-gate * The second entry contains modification time.
65380Sstevel@tonic-gate * Unlike a timestruc_t, which uses nanoseconds, timeval uses
65390Sstevel@tonic-gate * microseconds.
65400Sstevel@tonic-gate */
65410Sstevel@tonic-gate timebuf[0].tv_sec = time((time_t *)0);
65420Sstevel@tonic-gate timebuf[0].tv_usec = 0;
65430Sstevel@tonic-gate timebuf[1].tv_sec = modTime.tv_sec;
65440Sstevel@tonic-gate
65450Sstevel@tonic-gate /* Extended header: use microseconds */
65460Sstevel@tonic-gate timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
65470Sstevel@tonic-gate
65480Sstevel@tonic-gate if (futimesat(dirfd, path, timebuf) < 0)
654912305Srich.burridge@sun.com vperror(0, gettext("can't set time on %s"), path);
65500Sstevel@tonic-gate }
65510Sstevel@tonic-gate
65520Sstevel@tonic-gate
65530Sstevel@tonic-gate /*
65540Sstevel@tonic-gate * If hflag is set then delete the symbolic link's target.
65550Sstevel@tonic-gate * If !hflag then delete the target.
65560Sstevel@tonic-gate */
65570Sstevel@tonic-gate
65580Sstevel@tonic-gate static void
delete_target(int fd,char * comp,char * namep)65593805Slovely delete_target(int fd, char *comp, char *namep)
65600Sstevel@tonic-gate {
65610Sstevel@tonic-gate struct stat xtractbuf;
65620Sstevel@tonic-gate char buf[PATH_MAX + 1];
65630Sstevel@tonic-gate int n;
65640Sstevel@tonic-gate
65650Sstevel@tonic-gate
65663805Slovely if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
65670Sstevel@tonic-gate if (errno == ENOTDIR && !hflag) {
65683805Slovely (void) unlinkat(fd, comp, 0);
65690Sstevel@tonic-gate } else if (errno == ENOTDIR && hflag) {
65700Sstevel@tonic-gate if (!lstat(namep, &xtractbuf)) {
65710Sstevel@tonic-gate if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
65723805Slovely (void) unlinkat(fd, comp, 0);
65730Sstevel@tonic-gate } else if ((n = readlink(namep, buf,
65741266Sceastha PATH_MAX)) != -1) {
65750Sstevel@tonic-gate buf[n] = (char)NULL;
65760Sstevel@tonic-gate (void) unlinkat(fd, buf,
65771266Sceastha AT_REMOVEDIR);
65780Sstevel@tonic-gate if (errno == ENOTDIR)
65790Sstevel@tonic-gate (void) unlinkat(fd, buf, 0);
65800Sstevel@tonic-gate } else {
65813805Slovely (void) unlinkat(fd, comp, 0);
65820Sstevel@tonic-gate }
65830Sstevel@tonic-gate } else {
65843805Slovely (void) unlinkat(fd, comp, 0);
65850Sstevel@tonic-gate }
65860Sstevel@tonic-gate }
65870Sstevel@tonic-gate }
65880Sstevel@tonic-gate }
65890Sstevel@tonic-gate
65900Sstevel@tonic-gate
65910Sstevel@tonic-gate /*
65920Sstevel@tonic-gate * ACL changes:
65930Sstevel@tonic-gate * putfile():
65940Sstevel@tonic-gate * Get acl info after stat. Write out ancillary file
65950Sstevel@tonic-gate * before the normal file, i.e. directory, regular, FIFO,
65960Sstevel@tonic-gate * link, special. If acl count is less than 4, no need to
65970Sstevel@tonic-gate * create ancillary file. (i.e. standard permission is in
65980Sstevel@tonic-gate * use.
65990Sstevel@tonic-gate * doxtract():
66000Sstevel@tonic-gate * Process ancillary file. Read it in and set acl info.
66010Sstevel@tonic-gate * watch out for 'o' function modifier.
66020Sstevel@tonic-gate * 't' function letter to display table
66030Sstevel@tonic-gate */
66040Sstevel@tonic-gate
66050Sstevel@tonic-gate /*
66060Sstevel@tonic-gate * New functions for ACLs and other security attributes
66070Sstevel@tonic-gate */
66080Sstevel@tonic-gate
66090Sstevel@tonic-gate /*
66100Sstevel@tonic-gate * The function appends the new security attribute info to the end of
66110Sstevel@tonic-gate * existing secinfo.
66120Sstevel@tonic-gate */
66130Sstevel@tonic-gate int
append_secattr(char ** secinfo,int * secinfo_len,int size,char * attrtext,char attr_type)66140Sstevel@tonic-gate append_secattr(
66150Sstevel@tonic-gate char **secinfo, /* existing security info */
66160Sstevel@tonic-gate int *secinfo_len, /* length of existing security info */
66171676Sjpk int size, /* new attribute size: unit depends on type */
66181676Sjpk char *attrtext, /* new attribute text */
66191676Sjpk char attr_type) /* new attribute type */
66200Sstevel@tonic-gate {
66210Sstevel@tonic-gate char *new_secinfo;
66220Sstevel@tonic-gate int newattrsize;
66230Sstevel@tonic-gate int oldsize;
66241676Sjpk struct sec_attr *attr;
66250Sstevel@tonic-gate
66260Sstevel@tonic-gate /* no need to add */
66271676Sjpk if (attr_type != DIR_TYPE) {
66281676Sjpk if (attrtext == NULL)
66291676Sjpk return (0);
66301676Sjpk }
66311676Sjpk
66321676Sjpk switch (attr_type) {
66331676Sjpk case UFSD_ACL:
66341676Sjpk case ACE_ACL:
66350Sstevel@tonic-gate if (attrtext == NULL) {
663612305Srich.burridge@sun.com (void) fprintf(stderr, gettext("acltotext failed\n"));
66370Sstevel@tonic-gate return (-1);
66380Sstevel@tonic-gate }
66390Sstevel@tonic-gate /* header: type + size = 8 */
66400Sstevel@tonic-gate newattrsize = 8 + (int)strlen(attrtext) + 1;
66410Sstevel@tonic-gate attr = (struct sec_attr *)malloc(newattrsize);
66420Sstevel@tonic-gate if (attr == NULL) {
664312305Srich.burridge@sun.com (void) fprintf(stderr,
664412305Srich.burridge@sun.com gettext("can't allocate memory\n"));
66450Sstevel@tonic-gate return (-1);
66460Sstevel@tonic-gate }
66471676Sjpk attr->attr_type = attr_type;
66480Sstevel@tonic-gate (void) sprintf(attr->attr_len,
66491676Sjpk "%06o", size); /* acl entry count */
66500Sstevel@tonic-gate (void) strcpy((char *)&attr->attr_info[0], attrtext);
66510Sstevel@tonic-gate free(attrtext);
66520Sstevel@tonic-gate break;
66530Sstevel@tonic-gate
66541676Sjpk /* Trusted Extensions */
66551676Sjpk case DIR_TYPE:
66561676Sjpk case LBL_TYPE:
66571676Sjpk newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
66581676Sjpk attr = (struct sec_attr *)malloc(newattrsize);
66591676Sjpk if (attr == NULL) {
66601676Sjpk (void) fprintf(stderr,
66611676Sjpk gettext("can't allocate memory\n"));
66621676Sjpk return (-1);
66631676Sjpk }
66641676Sjpk attr->attr_type = attr_type;
66651676Sjpk (void) sprintf(attr->attr_len,
66661676Sjpk "%06d", size); /* len of attr data */
66671676Sjpk (void) strcpy((char *)&attr->attr_info[0], attrtext);
66681676Sjpk break;
66690Sstevel@tonic-gate
66700Sstevel@tonic-gate default:
667112305Srich.burridge@sun.com (void) fprintf(stderr,
667212305Srich.burridge@sun.com gettext("unrecognized attribute type\n"));
66730Sstevel@tonic-gate return (-1);
66740Sstevel@tonic-gate }
66750Sstevel@tonic-gate
66760Sstevel@tonic-gate /* old security info + new attr header(8) + new attr */
66770Sstevel@tonic-gate oldsize = *secinfo_len;
66780Sstevel@tonic-gate *secinfo_len += newattrsize;
66790Sstevel@tonic-gate new_secinfo = (char *)malloc(*secinfo_len);
66800Sstevel@tonic-gate if (new_secinfo == NULL) {
668112305Srich.burridge@sun.com (void) fprintf(stderr, gettext("can't allocate memory\n"));
66820Sstevel@tonic-gate *secinfo_len -= newattrsize;
66831676Sjpk free(attr);
66840Sstevel@tonic-gate return (-1);
66850Sstevel@tonic-gate }
66860Sstevel@tonic-gate
66870Sstevel@tonic-gate (void) memcpy(new_secinfo, *secinfo, oldsize);
66880Sstevel@tonic-gate (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
66890Sstevel@tonic-gate
66900Sstevel@tonic-gate free(*secinfo);
66911676Sjpk free(attr);
66920Sstevel@tonic-gate *secinfo = new_secinfo;
66930Sstevel@tonic-gate return (0);
66940Sstevel@tonic-gate }
66950Sstevel@tonic-gate
66960Sstevel@tonic-gate /*
66970Sstevel@tonic-gate * write_ancillary(): write out an ancillary file.
66980Sstevel@tonic-gate * The file has the same header as normal file except the type and size
66990Sstevel@tonic-gate * fields. The type is 'A' and size is the sum of all attributes
67000Sstevel@tonic-gate * in bytes.
67010Sstevel@tonic-gate * The body contains a list of attribute type, size and info. Currently,
67020Sstevel@tonic-gate * there is only ACL info. This file is put before the normal file.
67030Sstevel@tonic-gate */
67040Sstevel@tonic-gate void
write_ancillary(union hblock * dblockp,char * secinfo,int len,char hdrtype)67050Sstevel@tonic-gate write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
67060Sstevel@tonic-gate {
67070Sstevel@tonic-gate long blocks;
67080Sstevel@tonic-gate int savflag;
67090Sstevel@tonic-gate int savsize;
67100Sstevel@tonic-gate
67110Sstevel@tonic-gate /* Just tranditional permissions or no security attribute info */
67120Sstevel@tonic-gate if (len == 0 || secinfo == NULL)
67130Sstevel@tonic-gate return;
67140Sstevel@tonic-gate
67150Sstevel@tonic-gate /* save flag and size */
67160Sstevel@tonic-gate savflag = (dblockp->dbuf).typeflag;
67170Sstevel@tonic-gate (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
67180Sstevel@tonic-gate
67190Sstevel@tonic-gate /* special flag for ancillary file */
67200Sstevel@tonic-gate if (hdrtype == _XATTR_HDRTYPE)
67210Sstevel@tonic-gate dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
67220Sstevel@tonic-gate else
67230Sstevel@tonic-gate dblockp->dbuf.typeflag = 'A';
67240Sstevel@tonic-gate
67250Sstevel@tonic-gate /* for pre-2.5 versions of tar, need to make sure */
67260Sstevel@tonic-gate /* the ACL file is readable */
67270Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo",
67281266Sceastha (stbuf.st_mode & POSIXMODES) | 0000200);
67290Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.size, "%011o", len);
67300Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
67310Sstevel@tonic-gate
67320Sstevel@tonic-gate /* write out the header */
67330Sstevel@tonic-gate (void) writetbuf((char *)dblockp, 1);
67340Sstevel@tonic-gate
67350Sstevel@tonic-gate /* write out security info */
67360Sstevel@tonic-gate blocks = TBLOCKS(len);
67370Sstevel@tonic-gate (void) writetbuf((char *)secinfo, (int)blocks);
67380Sstevel@tonic-gate
67390Sstevel@tonic-gate /* restore mode, flag and size */
67400Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
67410Sstevel@tonic-gate dblockp->dbuf.typeflag = savflag;
67420Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
67430Sstevel@tonic-gate }
67440Sstevel@tonic-gate
67450Sstevel@tonic-gate /*
67460Sstevel@tonic-gate * Read the data record for extended headers and then the regular header.
67470Sstevel@tonic-gate * The data are read into the buffer and then null-terminated. Entries
674811995Srich.burridge@sun.com * for typeflag 'X' extended headers are of the format:
67490Sstevel@tonic-gate * "%d %s=%s\n"
67500Sstevel@tonic-gate *
67510Sstevel@tonic-gate * When an extended header record is found, the extended header must
67520Sstevel@tonic-gate * be processed and its values used to override the values in the
67530Sstevel@tonic-gate * normal header. The way this is done is to process the extended
67540Sstevel@tonic-gate * header data record and set the data values, then call getdir
67550Sstevel@tonic-gate * to process the regular header, then then to reconcile the two
67560Sstevel@tonic-gate * sets of data.
67570Sstevel@tonic-gate */
67580Sstevel@tonic-gate
67590Sstevel@tonic-gate static int
get_xdata(void)67600Sstevel@tonic-gate get_xdata(void)
67610Sstevel@tonic-gate {
67620Sstevel@tonic-gate struct keylist_pair {
67630Sstevel@tonic-gate int keynum;
67640Sstevel@tonic-gate char *keylist;
67650Sstevel@tonic-gate } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
67660Sstevel@tonic-gate _X_DEVMINOR, "SUN.devminor",
67670Sstevel@tonic-gate _X_GID, "gid",
67680Sstevel@tonic-gate _X_GNAME, "gname",
67690Sstevel@tonic-gate _X_LINKPATH, "linkpath",
67700Sstevel@tonic-gate _X_PATH, "path",
67710Sstevel@tonic-gate _X_SIZE, "size",
67720Sstevel@tonic-gate _X_UID, "uid",
67730Sstevel@tonic-gate _X_UNAME, "uname",
67740Sstevel@tonic-gate _X_MTIME, "mtime",
67750Sstevel@tonic-gate _X_LAST, "NULL" };
67760Sstevel@tonic-gate char *lineloc;
67770Sstevel@tonic-gate int length, i;
67780Sstevel@tonic-gate char *keyword, *value;
67790Sstevel@tonic-gate blkcnt_t nblocks;
67800Sstevel@tonic-gate int bufneeded;
67810Sstevel@tonic-gate int errors;
67820Sstevel@tonic-gate
67835482Sas158974 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
67840Sstevel@tonic-gate xhdr_count++;
67850Sstevel@tonic-gate errors = 0;
67860Sstevel@tonic-gate
67870Sstevel@tonic-gate nblocks = TBLOCKS(stbuf.st_size);
67880Sstevel@tonic-gate bufneeded = nblocks * TBLOCK;
67890Sstevel@tonic-gate if (bufneeded >= xrec_size) {
67900Sstevel@tonic-gate free(xrec_ptr);
67910Sstevel@tonic-gate xrec_size = bufneeded + 1;
67920Sstevel@tonic-gate if ((xrec_ptr = malloc(xrec_size)) == NULL)
67930Sstevel@tonic-gate fatal(gettext("cannot allocate buffer"));
67940Sstevel@tonic-gate }
67950Sstevel@tonic-gate
67960Sstevel@tonic-gate lineloc = xrec_ptr;
67970Sstevel@tonic-gate
67980Sstevel@tonic-gate while (nblocks-- > 0) {
67990Sstevel@tonic-gate readtape(lineloc);
68000Sstevel@tonic-gate lineloc += TBLOCK;
68010Sstevel@tonic-gate }
68020Sstevel@tonic-gate lineloc = xrec_ptr;
68030Sstevel@tonic-gate xrec_ptr[stbuf.st_size] = '\0';
68040Sstevel@tonic-gate while (lineloc < xrec_ptr + stbuf.st_size) {
680511995Srich.burridge@sun.com if (dblock.dbuf.typeflag == 'L') {
680611995Srich.burridge@sun.com length = xrec_size;
680711995Srich.burridge@sun.com keyword = "path";
680811995Srich.burridge@sun.com value = lineloc;
680911995Srich.burridge@sun.com } else {
681011995Srich.burridge@sun.com length = atoi(lineloc);
681111995Srich.burridge@sun.com *(lineloc + length - 1) = '\0';
681211995Srich.burridge@sun.com keyword = strchr(lineloc, ' ') + 1;
681311995Srich.burridge@sun.com value = strchr(keyword, '=') + 1;
681411995Srich.burridge@sun.com *(value - 1) = '\0';
681511995Srich.burridge@sun.com }
68160Sstevel@tonic-gate i = 0;
68170Sstevel@tonic-gate lineloc += length;
68180Sstevel@tonic-gate while (keylist_pair[i].keynum != (int)_X_LAST) {
68190Sstevel@tonic-gate if (strcmp(keyword, keylist_pair[i].keylist) == 0)
68200Sstevel@tonic-gate break;
68210Sstevel@tonic-gate i++;
68220Sstevel@tonic-gate }
68230Sstevel@tonic-gate errno = 0;
68240Sstevel@tonic-gate switch (keylist_pair[i].keynum) {
68250Sstevel@tonic-gate case _X_DEVMAJOR:
68260Sstevel@tonic-gate Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
68270Sstevel@tonic-gate if (errno) {
68280Sstevel@tonic-gate (void) fprintf(stderr, gettext(
68290Sstevel@tonic-gate "tar: Extended header major value error "
68300Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count);
68310Sstevel@tonic-gate errors++;
68320Sstevel@tonic-gate } else
68330Sstevel@tonic-gate xhdr_flgs |= _X_DEVMAJOR;
68340Sstevel@tonic-gate break;
68350Sstevel@tonic-gate case _X_DEVMINOR:
68360Sstevel@tonic-gate Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
68370Sstevel@tonic-gate if (errno) {
68380Sstevel@tonic-gate (void) fprintf(stderr, gettext(
68390Sstevel@tonic-gate "tar: Extended header minor value error "
68400Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count);
68410Sstevel@tonic-gate errors++;
68420Sstevel@tonic-gate } else
68430Sstevel@tonic-gate xhdr_flgs |= _X_DEVMINOR;
68440Sstevel@tonic-gate break;
68450Sstevel@tonic-gate case _X_GID:
68460Sstevel@tonic-gate xhdr_flgs |= _X_GID;
68470Sstevel@tonic-gate Xtarhdr.x_gid = strtol(value, NULL, 0);
68480Sstevel@tonic-gate if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
68490Sstevel@tonic-gate (void) fprintf(stderr, gettext(
68500Sstevel@tonic-gate "tar: Extended header gid value error "
68510Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count);
68520Sstevel@tonic-gate Xtarhdr.x_gid = GID_NOBODY;
68530Sstevel@tonic-gate }
68540Sstevel@tonic-gate break;
68550Sstevel@tonic-gate case _X_GNAME:
68560Sstevel@tonic-gate if (utf8_local("gname", &Xtarhdr.x_gname,
68570Sstevel@tonic-gate local_gname, value, _POSIX_NAME_MAX) == 0)
68580Sstevel@tonic-gate xhdr_flgs |= _X_GNAME;
68590Sstevel@tonic-gate break;
68600Sstevel@tonic-gate case _X_LINKPATH:
68610Sstevel@tonic-gate if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
68620Sstevel@tonic-gate local_linkpath, value, PATH_MAX) == 0)
68630Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH;
68640Sstevel@tonic-gate else
68650Sstevel@tonic-gate errors++;
68660Sstevel@tonic-gate break;
68670Sstevel@tonic-gate case _X_PATH:
68680Sstevel@tonic-gate if (utf8_local("path", &Xtarhdr.x_path,
68690Sstevel@tonic-gate local_path, value, PATH_MAX) == 0)
68700Sstevel@tonic-gate xhdr_flgs |= _X_PATH;
68710Sstevel@tonic-gate else
68720Sstevel@tonic-gate errors++;
68730Sstevel@tonic-gate break;
68740Sstevel@tonic-gate case _X_SIZE:
68750Sstevel@tonic-gate Xtarhdr.x_filesz = strtoull(value, NULL, 0);
68760Sstevel@tonic-gate if (errno) {
68770Sstevel@tonic-gate (void) fprintf(stderr, gettext(
68780Sstevel@tonic-gate "tar: Extended header invalid filesize "
68790Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count);
68800Sstevel@tonic-gate errors++;
68810Sstevel@tonic-gate } else
68820Sstevel@tonic-gate xhdr_flgs |= _X_SIZE;
68830Sstevel@tonic-gate break;
68840Sstevel@tonic-gate case _X_UID:
68850Sstevel@tonic-gate xhdr_flgs |= _X_UID;
68860Sstevel@tonic-gate Xtarhdr.x_uid = strtol(value, NULL, 0);
68870Sstevel@tonic-gate if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
68880Sstevel@tonic-gate (void) fprintf(stderr, gettext(
68890Sstevel@tonic-gate "tar: Extended header uid value error "
68900Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count);
68910Sstevel@tonic-gate Xtarhdr.x_uid = UID_NOBODY;
68920Sstevel@tonic-gate }
68930Sstevel@tonic-gate break;
68940Sstevel@tonic-gate case _X_UNAME:
68950Sstevel@tonic-gate if (utf8_local("uname", &Xtarhdr.x_uname,
68960Sstevel@tonic-gate local_uname, value, _POSIX_NAME_MAX) == 0)
68970Sstevel@tonic-gate xhdr_flgs |= _X_UNAME;
68980Sstevel@tonic-gate break;
68990Sstevel@tonic-gate case _X_MTIME:
69000Sstevel@tonic-gate get_xtime(value, &(Xtarhdr.x_mtime));
69010Sstevel@tonic-gate if (errno)
69020Sstevel@tonic-gate (void) fprintf(stderr, gettext(
69030Sstevel@tonic-gate "tar: Extended header modification time "
69040Sstevel@tonic-gate "value error for file # %llu.\n"),
69050Sstevel@tonic-gate xhdr_count);
69060Sstevel@tonic-gate else
69070Sstevel@tonic-gate xhdr_flgs |= _X_MTIME;
69080Sstevel@tonic-gate break;
69090Sstevel@tonic-gate default:
69100Sstevel@tonic-gate (void) fprintf(stderr,
69110Sstevel@tonic-gate gettext("tar: unrecognized extended"
69120Sstevel@tonic-gate " header keyword '%s'. Ignored.\n"), keyword);
69130Sstevel@tonic-gate break;
69140Sstevel@tonic-gate }
69150Sstevel@tonic-gate }
69160Sstevel@tonic-gate
69170Sstevel@tonic-gate getdir(); /* get regular header */
69180Sstevel@tonic-gate if (errors && errflag)
69190Sstevel@tonic-gate done(1);
69200Sstevel@tonic-gate else
69210Sstevel@tonic-gate if (errors)
69220Sstevel@tonic-gate Errflg = 1;
69230Sstevel@tonic-gate return (errors);
69240Sstevel@tonic-gate }
69250Sstevel@tonic-gate
69260Sstevel@tonic-gate /*
69275482Sas158974 * load_info_from_xtarhdr - sets Gen and stbuf variables from
69285482Sas158974 * extended header
69295482Sas158974 * load_info_from_xtarhdr(flag, xhdrp);
69305482Sas158974 * u_longlong_t flag; xhdr_flgs
69315482Sas158974 * struct xtar_hdr *xhdrp; pointer to extended header
69325482Sas158974 * NOTE: called when typeflag is not 'A' and xhdr_flgs
69335482Sas158974 * is set.
69345482Sas158974 */
69355482Sas158974 static void
load_info_from_xtarhdr(u_longlong_t flag,struct xtar_hdr * xhdrp)69365482Sas158974 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
69375482Sas158974 {
69385482Sas158974 if (flag & _X_DEVMAJOR) {
69395482Sas158974 Gen.g_devmajor = xhdrp->x_devmajor;
69405482Sas158974 }
69415482Sas158974 if (flag & _X_DEVMINOR) {
69425482Sas158974 Gen.g_devminor = xhdrp->x_devminor;
69435482Sas158974 }
69445482Sas158974 if (flag & _X_GID) {
69455482Sas158974 Gen.g_gid = xhdrp->x_gid;
69465482Sas158974 stbuf.st_gid = xhdrp->x_gid;
69475482Sas158974 }
69485482Sas158974 if (flag & _X_UID) {
69495482Sas158974 Gen.g_uid = xhdrp->x_uid;
69505482Sas158974 stbuf.st_uid = xhdrp->x_uid;
69515482Sas158974 }
69525482Sas158974 if (flag & _X_SIZE) {
69535482Sas158974 Gen.g_filesz = xhdrp->x_filesz;
69545482Sas158974 stbuf.st_size = xhdrp->x_filesz;
69555482Sas158974 }
69565482Sas158974 if (flag & _X_MTIME) {
69575482Sas158974 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
69585482Sas158974 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
69595482Sas158974 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
69605482Sas158974 }
69615482Sas158974 }
69625482Sas158974
69635482Sas158974 /*
69640Sstevel@tonic-gate * gen_num creates a string from a keyword and an usigned long long in the
69650Sstevel@tonic-gate * format: %d %s=%s\n
69660Sstevel@tonic-gate * This is part of the extended header data record.
69670Sstevel@tonic-gate */
69680Sstevel@tonic-gate
69690Sstevel@tonic-gate void
gen_num(const char * keyword,const u_longlong_t number)69700Sstevel@tonic-gate gen_num(const char *keyword, const u_longlong_t number)
69710Sstevel@tonic-gate {
69720Sstevel@tonic-gate char save_val[ULONGLONG_MAX_DIGITS + 1];
69730Sstevel@tonic-gate int len;
69740Sstevel@tonic-gate char *curr_ptr;
69750Sstevel@tonic-gate
69760Sstevel@tonic-gate (void) sprintf(save_val, "%llu", number);
69770Sstevel@tonic-gate /*
69780Sstevel@tonic-gate * len = length of entire line, including itself. len will be
69790Sstevel@tonic-gate * two digits. So, add the string lengths plus the length of len,
69800Sstevel@tonic-gate * plus a blank, an equal sign, and a newline.
69810Sstevel@tonic-gate */
69820Sstevel@tonic-gate len = strlen(save_val) + strlen(keyword) + 5;
69830Sstevel@tonic-gate if (xrec_offset + len > xrec_size) {
69840Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
69850Sstevel@tonic-gate fatal(gettext(
69860Sstevel@tonic-gate "cannot allocate extended header buffer"));
69870Sstevel@tonic-gate xrec_ptr = curr_ptr;
69880Sstevel@tonic-gate xrec_size *= 2;
69890Sstevel@tonic-gate }
69900Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset],
69910Sstevel@tonic-gate "%d %s=%s\n", len, keyword, save_val);
69920Sstevel@tonic-gate xrec_offset += len;
69930Sstevel@tonic-gate }
69940Sstevel@tonic-gate
69950Sstevel@tonic-gate /*
69960Sstevel@tonic-gate * gen_date creates a string from a keyword and a timestruc_t in the
69970Sstevel@tonic-gate * format: %d %s=%s\n
69980Sstevel@tonic-gate * This is part of the extended header data record.
69990Sstevel@tonic-gate * Currently, granularity is only microseconds, so the low-order three digits
70000Sstevel@tonic-gate * will be truncated.
70010Sstevel@tonic-gate */
70020Sstevel@tonic-gate
70030Sstevel@tonic-gate void
gen_date(const char * keyword,const timestruc_t time_value)70040Sstevel@tonic-gate gen_date(const char *keyword, const timestruc_t time_value)
70050Sstevel@tonic-gate {
70060Sstevel@tonic-gate /* Allow for <seconds>.<nanoseconds>\n */
70070Sstevel@tonic-gate char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
70080Sstevel@tonic-gate int len;
70090Sstevel@tonic-gate char *curr_ptr;
70100Sstevel@tonic-gate
70110Sstevel@tonic-gate (void) sprintf(save_val, "%ld", time_value.tv_sec);
70120Sstevel@tonic-gate len = strlen(save_val);
70130Sstevel@tonic-gate save_val[len] = '.';
70140Sstevel@tonic-gate (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
70150Sstevel@tonic-gate
70160Sstevel@tonic-gate /*
70170Sstevel@tonic-gate * len = length of entire line, including itself. len will be
70180Sstevel@tonic-gate * two digits. So, add the string lengths plus the length of len,
70190Sstevel@tonic-gate * plus a blank, an equal sign, and a newline.
70200Sstevel@tonic-gate */
70210Sstevel@tonic-gate len = strlen(save_val) + strlen(keyword) + 5;
70220Sstevel@tonic-gate if (xrec_offset + len > xrec_size) {
70230Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
70240Sstevel@tonic-gate fatal(gettext(
70250Sstevel@tonic-gate "cannot allocate extended header buffer"));
70260Sstevel@tonic-gate xrec_ptr = curr_ptr;
70270Sstevel@tonic-gate xrec_size *= 2;
70280Sstevel@tonic-gate }
70290Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset],
70300Sstevel@tonic-gate "%d %s=%s\n", len, keyword, save_val);
70310Sstevel@tonic-gate xrec_offset += len;
70320Sstevel@tonic-gate }
70330Sstevel@tonic-gate
70340Sstevel@tonic-gate /*
70350Sstevel@tonic-gate * gen_string creates a string from a keyword and a char * in the
70360Sstevel@tonic-gate * format: %d %s=%s\n
70370Sstevel@tonic-gate * This is part of the extended header data record.
70380Sstevel@tonic-gate */
70390Sstevel@tonic-gate
70400Sstevel@tonic-gate void
gen_string(const char * keyword,const char * value)70410Sstevel@tonic-gate gen_string(const char *keyword, const char *value)
70420Sstevel@tonic-gate {
70430Sstevel@tonic-gate int len;
70440Sstevel@tonic-gate char *curr_ptr;
70450Sstevel@tonic-gate
70460Sstevel@tonic-gate /*
70470Sstevel@tonic-gate * len = length of entire line, including itself. The character length
70480Sstevel@tonic-gate * of len must be 1-4 characters, because the maximum size of the path
70490Sstevel@tonic-gate * or the name is PATH_MAX, which is 1024. So, assume 1 character
70500Sstevel@tonic-gate * for len, one for the space, one for the "=", and one for the newline.
70510Sstevel@tonic-gate * Then adjust as needed.
70520Sstevel@tonic-gate */
70530Sstevel@tonic-gate /* LINTED constant expression */
70540Sstevel@tonic-gate assert(PATH_MAX <= 9996);
70550Sstevel@tonic-gate len = strlen(value) + strlen(keyword) + 4;
70560Sstevel@tonic-gate if (len > 997)
70570Sstevel@tonic-gate len += 3;
70580Sstevel@tonic-gate else if (len > 98)
70590Sstevel@tonic-gate len += 2;
70600Sstevel@tonic-gate else if (len > 9)
70610Sstevel@tonic-gate len += 1;
70620Sstevel@tonic-gate if (xrec_offset + len > xrec_size) {
70630Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
70640Sstevel@tonic-gate fatal(gettext(
70650Sstevel@tonic-gate "cannot allocate extended header buffer"));
70660Sstevel@tonic-gate xrec_ptr = curr_ptr;
70670Sstevel@tonic-gate xrec_size *= 2;
70680Sstevel@tonic-gate }
70690Sstevel@tonic-gate #ifdef XHDR_DEBUG
70700Sstevel@tonic-gate if (strcmp(keyword+1, "name") != 0)
70710Sstevel@tonic-gate #endif
70720Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset],
70730Sstevel@tonic-gate "%d %s=%s\n", len, keyword, value);
70740Sstevel@tonic-gate #ifdef XHDR_DEBUG
70750Sstevel@tonic-gate else {
70760Sstevel@tonic-gate len += 11;
70770Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset],
70780Sstevel@tonic-gate "%d %s=%snametoolong\n", len, keyword, value);
70790Sstevel@tonic-gate }
70800Sstevel@tonic-gate #endif
70810Sstevel@tonic-gate xrec_offset += len;
70820Sstevel@tonic-gate }
70830Sstevel@tonic-gate
70840Sstevel@tonic-gate /*
70850Sstevel@tonic-gate * Convert time found in the extended header data to seconds and nanoseconds.
70860Sstevel@tonic-gate */
70870Sstevel@tonic-gate
70880Sstevel@tonic-gate void
get_xtime(char * value,timestruc_t * xtime)70890Sstevel@tonic-gate get_xtime(char *value, timestruc_t *xtime)
70900Sstevel@tonic-gate {
70910Sstevel@tonic-gate char nanosec[10];
70920Sstevel@tonic-gate char *period;
70930Sstevel@tonic-gate int i;
70940Sstevel@tonic-gate
70950Sstevel@tonic-gate (void) memset(nanosec, '0', 9);
70960Sstevel@tonic-gate nanosec[9] = '\0';
70970Sstevel@tonic-gate
70980Sstevel@tonic-gate period = strchr(value, '.');
70990Sstevel@tonic-gate if (period != NULL)
71000Sstevel@tonic-gate period[0] = '\0';
71010Sstevel@tonic-gate xtime->tv_sec = strtol(value, NULL, 10);
71020Sstevel@tonic-gate if (period == NULL)
71030Sstevel@tonic-gate xtime->tv_nsec = 0;
71040Sstevel@tonic-gate else {
71050Sstevel@tonic-gate i = strlen(period +1);
71060Sstevel@tonic-gate (void) strncpy(nanosec, period + 1, min(i, 9));
71070Sstevel@tonic-gate xtime->tv_nsec = strtol(nanosec, NULL, 10);
71080Sstevel@tonic-gate }
71090Sstevel@tonic-gate }
71100Sstevel@tonic-gate
71110Sstevel@tonic-gate /*
71120Sstevel@tonic-gate * Check linkpath for length.
71130Sstevel@tonic-gate * Emit an error message and return 1 if too long.
71140Sstevel@tonic-gate */
71150Sstevel@tonic-gate
71160Sstevel@tonic-gate int
chk_path_build(char * name,char * longname,char * linkname,char * prefix,char type,int filetype)71170Sstevel@tonic-gate chk_path_build(
71180Sstevel@tonic-gate char *name,
71190Sstevel@tonic-gate char *longname,
71200Sstevel@tonic-gate char *linkname,
71210Sstevel@tonic-gate char *prefix,
71220Sstevel@tonic-gate char type,
71230Sstevel@tonic-gate int filetype)
71240Sstevel@tonic-gate {
71250Sstevel@tonic-gate
71260Sstevel@tonic-gate if (strlen(linkname) > (size_t)NAMSIZ) {
71270Sstevel@tonic-gate if (Eflag > 0) {
71280Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH;
71290Sstevel@tonic-gate Xtarhdr.x_linkpath = linkname;
71300Sstevel@tonic-gate } else {
71310Sstevel@tonic-gate (void) fprintf(stderr, gettext(
71320Sstevel@tonic-gate "tar: %s: linked to %s\n"), longname, linkname);
71330Sstevel@tonic-gate (void) fprintf(stderr, gettext(
71340Sstevel@tonic-gate "tar: %s: linked name too long\n"), linkname);
71350Sstevel@tonic-gate if (errflag)
71360Sstevel@tonic-gate done(1);
71370Sstevel@tonic-gate else
71380Sstevel@tonic-gate Errflg = 1;
71390Sstevel@tonic-gate return (1);
71400Sstevel@tonic-gate }
71410Sstevel@tonic-gate }
71420Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH)
71430Sstevel@tonic-gate return (build_dblock(name, tchar, type,
71441266Sceastha filetype, &stbuf, stbuf.st_dev,
71450Sstevel@tonic-gate prefix));
71460Sstevel@tonic-gate else
71470Sstevel@tonic-gate return (build_dblock(name, linkname, type,
71481266Sceastha filetype, &stbuf, stbuf.st_dev, prefix));
71490Sstevel@tonic-gate }
71500Sstevel@tonic-gate
71510Sstevel@tonic-gate /*
71520Sstevel@tonic-gate * Convert from UTF-8 to local character set.
71530Sstevel@tonic-gate */
71540Sstevel@tonic-gate
71550Sstevel@tonic-gate static int
utf8_local(char * option,char ** Xhdr_ptrptr,char * target,const char * source,int max_val)71560Sstevel@tonic-gate utf8_local(
71570Sstevel@tonic-gate char *option,
71580Sstevel@tonic-gate char **Xhdr_ptrptr,
71590Sstevel@tonic-gate char *target,
71600Sstevel@tonic-gate const char *source,
71610Sstevel@tonic-gate int max_val)
71620Sstevel@tonic-gate {
71630Sstevel@tonic-gate static iconv_t iconv_cd;
71640Sstevel@tonic-gate char *nl_target;
71650Sstevel@tonic-gate const char *iconv_src;
71660Sstevel@tonic-gate char *iconv_trg;
71671266Sceastha size_t inlen;
71681266Sceastha size_t outlen;
71690Sstevel@tonic-gate
71700Sstevel@tonic-gate if (charset_type == -1) { /* iconv_open failed in earlier try */
71710Sstevel@tonic-gate (void) fprintf(stderr, gettext(
71720Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
71730Sstevel@tonic-gate xhdr_count, source);
71740Sstevel@tonic-gate return (1);
71750Sstevel@tonic-gate } else if (charset_type == 0) { /* iconv_open has not yet been done */
71760Sstevel@tonic-gate nl_target = nl_langinfo(CODESET);
71770Sstevel@tonic-gate if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
71780Sstevel@tonic-gate nl_target = "646";
71790Sstevel@tonic-gate if (strcmp(nl_target, "646") == 0)
71800Sstevel@tonic-gate charset_type = 1;
71810Sstevel@tonic-gate else if (strcmp(nl_target, "UTF-8") == 0)
71820Sstevel@tonic-gate charset_type = 3;
71830Sstevel@tonic-gate else {
71840Sstevel@tonic-gate if (strncmp(nl_target, "ISO", 3) == 0)
71850Sstevel@tonic-gate nl_target += 3;
71860Sstevel@tonic-gate charset_type = 2;
71870Sstevel@tonic-gate errno = 0;
71880Sstevel@tonic-gate if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
71890Sstevel@tonic-gate (iconv_t)-1) {
71900Sstevel@tonic-gate if (errno == EINVAL)
71910Sstevel@tonic-gate (void) fprintf(stderr, gettext(
71920Sstevel@tonic-gate "tar: conversion routines not "
71930Sstevel@tonic-gate "available for current locale. "));
71940Sstevel@tonic-gate (void) fprintf(stderr, gettext(
71950Sstevel@tonic-gate "file # %llu: (%s) UTF-8 conversion"
71960Sstevel@tonic-gate " failed.\n"), xhdr_count, source);
71970Sstevel@tonic-gate charset_type = -1;
71980Sstevel@tonic-gate return (1);
71990Sstevel@tonic-gate }
72000Sstevel@tonic-gate }
72010Sstevel@tonic-gate }
72020Sstevel@tonic-gate
72030Sstevel@tonic-gate /* locale using 7-bit codeset or UTF-8 locale */
72040Sstevel@tonic-gate if (charset_type == 1 || charset_type == 3) {
72050Sstevel@tonic-gate if (strlen(source) > max_val) {
72060Sstevel@tonic-gate (void) fprintf(stderr, gettext(
72070Sstevel@tonic-gate "tar: file # %llu: Extended header %s too long.\n"),
72080Sstevel@tonic-gate xhdr_count, option);
72090Sstevel@tonic-gate return (1);
72100Sstevel@tonic-gate }
72110Sstevel@tonic-gate if (charset_type == 3)
72120Sstevel@tonic-gate (void) strcpy(target, source);
72130Sstevel@tonic-gate else if (c_utf8(target, source) != 0) {
72140Sstevel@tonic-gate (void) fprintf(stderr, gettext(
72150Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion"
72160Sstevel@tonic-gate " failed.\n"), xhdr_count, source);
72170Sstevel@tonic-gate return (1);
72180Sstevel@tonic-gate }
72190Sstevel@tonic-gate *Xhdr_ptrptr = target;
72200Sstevel@tonic-gate return (0);
72210Sstevel@tonic-gate }
72220Sstevel@tonic-gate
72230Sstevel@tonic-gate iconv_src = source;
72240Sstevel@tonic-gate iconv_trg = target;
72250Sstevel@tonic-gate inlen = strlen(source);
72260Sstevel@tonic-gate outlen = max_val * UTF_8_FACTOR;
72270Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
72280Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */
72290Sstevel@tonic-gate (void) fprintf(stderr, gettext(
72300Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
72310Sstevel@tonic-gate xhdr_count, source);
72320Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */
72330Sstevel@tonic-gate iconv_src = (const char *)NULL;
72340Sstevel@tonic-gate inlen = 0;
72350Sstevel@tonic-gate (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
72360Sstevel@tonic-gate return (1);
72370Sstevel@tonic-gate }
72380Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */
72390Sstevel@tonic-gate iconv_src = (const char *)NULL;
72400Sstevel@tonic-gate inlen = 0;
72410Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
72420Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */
72430Sstevel@tonic-gate (void) fprintf(stderr, gettext(
72440Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
72450Sstevel@tonic-gate xhdr_count, source);
72460Sstevel@tonic-gate return (1);
72470Sstevel@tonic-gate }
72480Sstevel@tonic-gate
72490Sstevel@tonic-gate *iconv_trg = '\0'; /* Null-terminate iconv output string */
72500Sstevel@tonic-gate if (strlen(target) > max_val) {
72510Sstevel@tonic-gate (void) fprintf(stderr, gettext(
72520Sstevel@tonic-gate "tar: file # %llu: Extended header %s too long.\n"),
72530Sstevel@tonic-gate xhdr_count, option);
72540Sstevel@tonic-gate return (1);
72550Sstevel@tonic-gate }
72560Sstevel@tonic-gate *Xhdr_ptrptr = target;
72570Sstevel@tonic-gate return (0);
72580Sstevel@tonic-gate }
72590Sstevel@tonic-gate
72600Sstevel@tonic-gate /*
72610Sstevel@tonic-gate * Check gname, uname, path, and linkpath to see if they need to go in an
72620Sstevel@tonic-gate * extended header. If they are already slated to be in an extended header,
72630Sstevel@tonic-gate * or if they are not ascii, then they need to be in the extended header.
72640Sstevel@tonic-gate * Then, convert all extended names to UTF-8.
72650Sstevel@tonic-gate */
72660Sstevel@tonic-gate
72670Sstevel@tonic-gate int
gen_utf8_names(const char * filename)72680Sstevel@tonic-gate gen_utf8_names(const char *filename)
72690Sstevel@tonic-gate {
72700Sstevel@tonic-gate static iconv_t iconv_cd;
72710Sstevel@tonic-gate char *nl_target;
72720Sstevel@tonic-gate char tempbuf[MAXNAM + 1];
72731266Sceastha int nbytes;
72741266Sceastha int errors;
72750Sstevel@tonic-gate
72760Sstevel@tonic-gate if (charset_type == -1) { /* Previous failure to open. */
72770Sstevel@tonic-gate (void) fprintf(stderr, gettext(
72780Sstevel@tonic-gate "tar: file # %llu: UTF-8 conversion failed.\n"),
72790Sstevel@tonic-gate xhdr_count);
72800Sstevel@tonic-gate return (1);
72810Sstevel@tonic-gate }
72820Sstevel@tonic-gate
72830Sstevel@tonic-gate if (charset_type == 0) { /* Need to get conversion descriptor */
72840Sstevel@tonic-gate nl_target = nl_langinfo(CODESET);
72850Sstevel@tonic-gate if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
72860Sstevel@tonic-gate nl_target = "646";
72870Sstevel@tonic-gate if (strcmp(nl_target, "646") == 0)
72880Sstevel@tonic-gate charset_type = 1;
72890Sstevel@tonic-gate else if (strcmp(nl_target, "UTF-8") == 0)
72900Sstevel@tonic-gate charset_type = 3;
72910Sstevel@tonic-gate else {
72920Sstevel@tonic-gate if (strncmp(nl_target, "ISO", 3) == 0)
72930Sstevel@tonic-gate nl_target += 3;
72940Sstevel@tonic-gate charset_type = 2;
72950Sstevel@tonic-gate errno = 0;
72960Sstevel@tonic-gate #ifdef ICONV_DEBUG
72970Sstevel@tonic-gate (void) fprintf(stderr,
729812305Srich.burridge@sun.com gettext("Opening iconv_cd with target %s\n"),
72990Sstevel@tonic-gate nl_target);
73000Sstevel@tonic-gate #endif
73010Sstevel@tonic-gate if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
73020Sstevel@tonic-gate (iconv_t)-1) {
73030Sstevel@tonic-gate if (errno == EINVAL)
73040Sstevel@tonic-gate (void) fprintf(stderr, gettext(
73050Sstevel@tonic-gate "tar: conversion routines not "
73060Sstevel@tonic-gate "available for current locale. "));
73070Sstevel@tonic-gate (void) fprintf(stderr, gettext(
73080Sstevel@tonic-gate "file (%s): UTF-8 conversion failed.\n"),
73090Sstevel@tonic-gate filename);
73100Sstevel@tonic-gate charset_type = -1;
73110Sstevel@tonic-gate return (1);
73120Sstevel@tonic-gate }
73130Sstevel@tonic-gate }
73140Sstevel@tonic-gate }
73150Sstevel@tonic-gate
73160Sstevel@tonic-gate errors = 0;
73170Sstevel@tonic-gate
73180Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_gname, local_gname,
73190Sstevel@tonic-gate dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
73200Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_uname, local_uname,
73210Sstevel@tonic-gate dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
73220Sstevel@tonic-gate if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
73230Sstevel@tonic-gate (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
73240Sstevel@tonic-gate tempbuf[NAMSIZ] = '\0';
73250Sstevel@tonic-gate }
73260Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
73270Sstevel@tonic-gate tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
73280Sstevel@tonic-gate if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
73290Sstevel@tonic-gate (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
73301221Ssr161167 tempbuf[PRESIZ] = '\0';
73310Sstevel@tonic-gate nbytes = strlen(tempbuf);
73320Sstevel@tonic-gate if (nbytes > 0) {
73330Sstevel@tonic-gate tempbuf[nbytes++] = '/';
73340Sstevel@tonic-gate tempbuf[nbytes] = '\0';
73350Sstevel@tonic-gate }
73361221Ssr161167 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
73371221Ssr161167 (MAXNAM - nbytes));
73381221Ssr161167 tempbuf[MAXNAM] = '\0';
73390Sstevel@tonic-gate }
73400Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_path, local_path,
73410Sstevel@tonic-gate tempbuf, iconv_cd, _X_PATH, PATH_MAX);
73420Sstevel@tonic-gate
73430Sstevel@tonic-gate if (errors > 0)
73440Sstevel@tonic-gate (void) fprintf(stderr, gettext(
73450Sstevel@tonic-gate "tar: file (%s): UTF-8 conversion failed.\n"), filename);
73460Sstevel@tonic-gate
73470Sstevel@tonic-gate if (errors && errflag)
73480Sstevel@tonic-gate done(1);
73490Sstevel@tonic-gate else
73500Sstevel@tonic-gate if (errors)
73510Sstevel@tonic-gate Errflg = 1;
73520Sstevel@tonic-gate return (errors);
73530Sstevel@tonic-gate }
73540Sstevel@tonic-gate
73550Sstevel@tonic-gate static int
local_utf8(char ** Xhdr_ptrptr,char * target,const char * source,iconv_t iconv_cd,int xhdrflg,int max_val)73560Sstevel@tonic-gate local_utf8(
73570Sstevel@tonic-gate char **Xhdr_ptrptr,
73580Sstevel@tonic-gate char *target,
73590Sstevel@tonic-gate const char *source,
73600Sstevel@tonic-gate iconv_t iconv_cd,
73610Sstevel@tonic-gate int xhdrflg,
73620Sstevel@tonic-gate int max_val)
73630Sstevel@tonic-gate {
73640Sstevel@tonic-gate const char *iconv_src;
73650Sstevel@tonic-gate const char *starting_src;
73660Sstevel@tonic-gate char *iconv_trg;
73671266Sceastha size_t inlen;
73681266Sceastha size_t outlen;
73690Sstevel@tonic-gate #ifdef ICONV_DEBUG
73700Sstevel@tonic-gate unsigned char c_to_hex;
73710Sstevel@tonic-gate #endif
73720Sstevel@tonic-gate
73730Sstevel@tonic-gate /*
73740Sstevel@tonic-gate * If the item is already slated for extended format, get the string
73750Sstevel@tonic-gate * to convert from the extended header record. Otherwise, get it from
73760Sstevel@tonic-gate * the regular (dblock) area.
73770Sstevel@tonic-gate */
73780Sstevel@tonic-gate if (xhdr_flgs & xhdrflg) {
73790Sstevel@tonic-gate if (charset_type == 3) { /* Already UTF-8, just copy */
73800Sstevel@tonic-gate (void) strcpy(target, *Xhdr_ptrptr);
73810Sstevel@tonic-gate *Xhdr_ptrptr = target;
73820Sstevel@tonic-gate return (0);
73830Sstevel@tonic-gate } else
73840Sstevel@tonic-gate iconv_src = (const char *) *Xhdr_ptrptr;
73850Sstevel@tonic-gate } else {
73860Sstevel@tonic-gate if (charset_type == 3) /* Already in UTF-8 format */
73870Sstevel@tonic-gate return (0); /* Don't create xhdr record */
73880Sstevel@tonic-gate iconv_src = source;
73890Sstevel@tonic-gate }
73900Sstevel@tonic-gate starting_src = iconv_src;
73910Sstevel@tonic-gate iconv_trg = target;
73920Sstevel@tonic-gate if ((inlen = strlen(iconv_src)) == 0)
73930Sstevel@tonic-gate return (0);
73940Sstevel@tonic-gate
73950Sstevel@tonic-gate if (charset_type == 1) { /* locale using 7-bit codeset */
73960Sstevel@tonic-gate if (c_utf8(target, starting_src) != 0) {
73970Sstevel@tonic-gate (void) fprintf(stderr,
73980Sstevel@tonic-gate gettext("tar: invalid character in"
73990Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src);
74000Sstevel@tonic-gate return (1);
74010Sstevel@tonic-gate }
74020Sstevel@tonic-gate return (0);
74030Sstevel@tonic-gate }
74040Sstevel@tonic-gate
74050Sstevel@tonic-gate outlen = max_val * UTF_8_FACTOR;
74060Sstevel@tonic-gate errno = 0;
74070Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
74080Sstevel@tonic-gate (size_t)-1) {
74090Sstevel@tonic-gate /* An error occurred, or not all characters were converted */
74100Sstevel@tonic-gate if (errno == EILSEQ)
74110Sstevel@tonic-gate (void) fprintf(stderr,
74120Sstevel@tonic-gate gettext("tar: invalid character in"
74130Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src);
74140Sstevel@tonic-gate else
74150Sstevel@tonic-gate (void) fprintf(stderr, gettext(
74160Sstevel@tonic-gate "tar: conversion to UTF-8 aborted for '%s'.\n"),
74170Sstevel@tonic-gate starting_src);
74180Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */
74190Sstevel@tonic-gate iconv_src = (const char *)NULL;
74200Sstevel@tonic-gate inlen = 0;
74210Sstevel@tonic-gate (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
74220Sstevel@tonic-gate return (1);
74230Sstevel@tonic-gate }
74240Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */
74250Sstevel@tonic-gate iconv_src = (const char *)NULL;
74260Sstevel@tonic-gate inlen = 0;
74270Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
74280Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */
74290Sstevel@tonic-gate if (errno == EILSEQ)
74300Sstevel@tonic-gate (void) fprintf(stderr,
74310Sstevel@tonic-gate gettext("tar: invalid character in"
74320Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src);
74330Sstevel@tonic-gate else
74340Sstevel@tonic-gate (void) fprintf(stderr, gettext(
74350Sstevel@tonic-gate "tar: conversion to UTF-8 aborted for '%s'.\n"),
74360Sstevel@tonic-gate starting_src);
74370Sstevel@tonic-gate return (1);
74380Sstevel@tonic-gate }
74390Sstevel@tonic-gate
74400Sstevel@tonic-gate *iconv_trg = '\0'; /* Null-terminate iconv output string */
74410Sstevel@tonic-gate if (strcmp(starting_src, target) != 0) {
74420Sstevel@tonic-gate *Xhdr_ptrptr = target;
74430Sstevel@tonic-gate xhdr_flgs |= xhdrflg;
74440Sstevel@tonic-gate #ifdef ICONV_DEBUG
74450Sstevel@tonic-gate (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
74460Sstevel@tonic-gate strlen(starting_src), inlen, max_val, outlen);
74470Sstevel@tonic-gate (void) fprintf(stderr, "Input string:\n ");
74480Sstevel@tonic-gate for (inlen = 0; inlen < strlen(starting_src); inlen++) {
74490Sstevel@tonic-gate c_to_hex = (unsigned char)starting_src[inlen];
74500Sstevel@tonic-gate (void) fprintf(stderr, " %2.2x", c_to_hex);
74510Sstevel@tonic-gate if (inlen % 20 == 19)
74520Sstevel@tonic-gate (void) fprintf(stderr, "\n ");
74530Sstevel@tonic-gate }
74540Sstevel@tonic-gate (void) fprintf(stderr, "\nOutput string:\n ");
74550Sstevel@tonic-gate for (inlen = 0; inlen < strlen(target); inlen++) {
74560Sstevel@tonic-gate c_to_hex = (unsigned char)target[inlen];
74570Sstevel@tonic-gate (void) fprintf(stderr, " %2.2x", c_to_hex);
74580Sstevel@tonic-gate if (inlen % 20 == 19)
74590Sstevel@tonic-gate (void) fprintf(stderr, "\n ");
74600Sstevel@tonic-gate }
74610Sstevel@tonic-gate (void) fprintf(stderr, "\n");
74620Sstevel@tonic-gate #endif
74630Sstevel@tonic-gate }
74640Sstevel@tonic-gate
74650Sstevel@tonic-gate return (0);
74660Sstevel@tonic-gate }
74670Sstevel@tonic-gate
74680Sstevel@tonic-gate /*
74690Sstevel@tonic-gate * Function to test each byte of the source string to make sure it is
74700Sstevel@tonic-gate * in within bounds (value between 0 and 127).
74710Sstevel@tonic-gate * If valid, copy source to target.
74720Sstevel@tonic-gate */
74730Sstevel@tonic-gate
74740Sstevel@tonic-gate int
c_utf8(char * target,const char * source)74750Sstevel@tonic-gate c_utf8(char *target, const char *source)
74760Sstevel@tonic-gate {
74770Sstevel@tonic-gate size_t len;
74780Sstevel@tonic-gate const char *thischar;
74790Sstevel@tonic-gate
74800Sstevel@tonic-gate len = strlen(source);
74810Sstevel@tonic-gate thischar = source;
74820Sstevel@tonic-gate while (len-- > 0) {
74830Sstevel@tonic-gate if (!isascii((int)(*thischar++)))
74840Sstevel@tonic-gate return (1);
74850Sstevel@tonic-gate }
74860Sstevel@tonic-gate
74870Sstevel@tonic-gate (void) strcpy(target, source);
74880Sstevel@tonic-gate return (0);
74890Sstevel@tonic-gate }
74900Sstevel@tonic-gate
74910Sstevel@tonic-gate
74920Sstevel@tonic-gate #if defined(O_XATTR)
74930Sstevel@tonic-gate #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
74940Sstevel@tonic-gate
74950Sstevel@tonic-gate static void
prepare_xattr(char ** attrbuf,char * filename,char * attrpath,char typeflag,struct linkbuf * linkinfo,int * rlen)74960Sstevel@tonic-gate prepare_xattr(
74970Sstevel@tonic-gate char **attrbuf,
74980Sstevel@tonic-gate char *filename,
74995331Samw char *attrpath,
75000Sstevel@tonic-gate char typeflag,
75010Sstevel@tonic-gate struct linkbuf *linkinfo,
75020Sstevel@tonic-gate int *rlen)
75030Sstevel@tonic-gate {
75040Sstevel@tonic-gate char *bufhead; /* ptr to full buffer */
75055331Samw char *aptr;
75060Sstevel@tonic-gate struct xattr_hdr *hptr; /* ptr to header in bufhead */
75070Sstevel@tonic-gate struct xattr_buf *tptr; /* ptr to pathing pieces */
75080Sstevel@tonic-gate int totalen; /* total buffer length */
75090Sstevel@tonic-gate int len; /* length returned to user */
75100Sstevel@tonic-gate int stringlen; /* length of filename + attr */
75110Sstevel@tonic-gate /*
75120Sstevel@tonic-gate * length of filename + attr
75130Sstevel@tonic-gate * in link section
75140Sstevel@tonic-gate */
75150Sstevel@tonic-gate int linkstringlen;
75160Sstevel@tonic-gate int complen; /* length of pathing section */
75170Sstevel@tonic-gate int linklen; /* length of link section */
75185331Samw int attrnames_index; /* attrnames starting index */
75190Sstevel@tonic-gate
75200Sstevel@tonic-gate /*
75210Sstevel@tonic-gate * Release previous buffer
75220Sstevel@tonic-gate */
75230Sstevel@tonic-gate
75240Sstevel@tonic-gate if (*attrbuf != (char *)NULL) {
75250Sstevel@tonic-gate free(*attrbuf);
75260Sstevel@tonic-gate *attrbuf = NULL;
75270Sstevel@tonic-gate }
75280Sstevel@tonic-gate
75290Sstevel@tonic-gate /*
75300Sstevel@tonic-gate * First add in fixed size stuff
75310Sstevel@tonic-gate */
75320Sstevel@tonic-gate len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
75330Sstevel@tonic-gate
75340Sstevel@tonic-gate /*
75350Sstevel@tonic-gate * Add space for two nulls
75360Sstevel@tonic-gate */
75375331Samw stringlen = strlen(attrpath) + strlen(filename) + 2;
75380Sstevel@tonic-gate complen = stringlen + sizeof (struct xattr_buf);
75390Sstevel@tonic-gate
75400Sstevel@tonic-gate len += stringlen;
75410Sstevel@tonic-gate
75420Sstevel@tonic-gate /*
75430Sstevel@tonic-gate * Now add on space for link info if any
75440Sstevel@tonic-gate */
75450Sstevel@tonic-gate
75460Sstevel@tonic-gate if (linkinfo != NULL) {
75470Sstevel@tonic-gate /*
75480Sstevel@tonic-gate * Again add space for two nulls
75490Sstevel@tonic-gate */
75500Sstevel@tonic-gate linkstringlen = strlen(linkinfo->pathname) +
75510Sstevel@tonic-gate strlen(linkinfo->attrname) + 2;
75525331Samw linklen = linkstringlen + sizeof (struct xattr_buf);
75535331Samw len += linklen;
75545331Samw } else {
75555331Samw linklen = 0;
75560Sstevel@tonic-gate }
75570Sstevel@tonic-gate
75580Sstevel@tonic-gate /*
75590Sstevel@tonic-gate * Now add padding to end to fill out TBLOCK
75600Sstevel@tonic-gate *
75610Sstevel@tonic-gate * Function returns size of real data and not size + padding.
75620Sstevel@tonic-gate */
75630Sstevel@tonic-gate
75640Sstevel@tonic-gate totalen = ROUNDTOTBLOCK(len);
75650Sstevel@tonic-gate
75660Sstevel@tonic-gate if ((bufhead = calloc(1, totalen)) == NULL) {
75670Sstevel@tonic-gate fatal(gettext("Out of memory."));
75680Sstevel@tonic-gate }
75690Sstevel@tonic-gate
75700Sstevel@tonic-gate
75710Sstevel@tonic-gate /*
75720Sstevel@tonic-gate * Now we can fill in the necessary pieces
75730Sstevel@tonic-gate */
75740Sstevel@tonic-gate
75750Sstevel@tonic-gate /*
75760Sstevel@tonic-gate * first fill in the fixed header
75770Sstevel@tonic-gate */
75780Sstevel@tonic-gate hptr = (struct xattr_hdr *)bufhead;
75790Sstevel@tonic-gate (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
75800Sstevel@tonic-gate (void) sprintf(hptr->h_component_len, "%0*d",
75810Sstevel@tonic-gate sizeof (hptr->h_component_len) - 1, complen);
75820Sstevel@tonic-gate (void) sprintf(hptr->h_link_component_len, "%0*d",
75830Sstevel@tonic-gate sizeof (hptr->h_link_component_len) - 1, linklen);
75840Sstevel@tonic-gate (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
75850Sstevel@tonic-gate
75860Sstevel@tonic-gate /*
75870Sstevel@tonic-gate * Now fill in the filename + attrnames section
75885331Samw * The filename and attrnames section can be composed of two or more
75895331Samw * path segments separated by a null character. The first segment
75905331Samw * is the path to the parent file that roots the entire sequence in
75915331Samw * the normal name space. The remaining segments describes a path
75925331Samw * rooted at the hidden extended attribute directory of the leaf file of
75935331Samw * the previous segment, making it possible to name attributes on
75945331Samw * attributes. Thus, if we are just archiving an extended attribute,
75955331Samw * the second segment will contain the attribute name. If we are
75965331Samw * archiving a system attribute of an extended attribute, then the
75975331Samw * second segment will contain the attribute name, and a third segment
75985331Samw * will contain the system attribute name. The attribute pathing
75995331Samw * information is obtained from 'attrpath'.
76000Sstevel@tonic-gate */
76010Sstevel@tonic-gate
76020Sstevel@tonic-gate tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
76030Sstevel@tonic-gate (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
76040Sstevel@tonic-gate stringlen);
76050Sstevel@tonic-gate (void) strcpy(tptr->h_names, filename);
76065331Samw attrnames_index = strlen(filename) + 1;
76075331Samw (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
76080Sstevel@tonic-gate tptr->h_typeflag = typeflag;
76090Sstevel@tonic-gate
76100Sstevel@tonic-gate /*
76115331Samw * Split the attrnames section into two segments if 'attrpath'
76125331Samw * contains pathing information for a system attribute of an
76135331Samw * extended attribute. We split them by replacing the '/' with
76145331Samw * a '\0'.
76155331Samw */
76165331Samw if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
76175331Samw *aptr = '\0';
76185331Samw }
76195331Samw
76205331Samw /*
76210Sstevel@tonic-gate * Now fill in the optional link section if we have one
76220Sstevel@tonic-gate */
76230Sstevel@tonic-gate
76240Sstevel@tonic-gate if (linkinfo != (struct linkbuf *)NULL) {
76250Sstevel@tonic-gate tptr = (struct xattr_buf *)(bufhead +
76260Sstevel@tonic-gate sizeof (struct xattr_hdr) + complen);
76270Sstevel@tonic-gate
76280Sstevel@tonic-gate (void) sprintf(tptr->h_namesz, "%0*d",
76290Sstevel@tonic-gate sizeof (tptr->h_namesz) - 1, linkstringlen);
76300Sstevel@tonic-gate (void) strcpy(tptr->h_names, linkinfo->pathname);
76310Sstevel@tonic-gate (void) strcpy(
76320Sstevel@tonic-gate &tptr->h_names[strlen(linkinfo->pathname) + 1],
76330Sstevel@tonic-gate linkinfo->attrname);
76340Sstevel@tonic-gate tptr->h_typeflag = typeflag;
76350Sstevel@tonic-gate }
76360Sstevel@tonic-gate *attrbuf = (char *)bufhead;
76370Sstevel@tonic-gate *rlen = len;
76380Sstevel@tonic-gate }
76390Sstevel@tonic-gate
76400Sstevel@tonic-gate #else
76410Sstevel@tonic-gate static void
prepare_xattr(char ** attrbuf,char * filename,char * attrname,char typeflag,struct linkbuf * linkinfo,int * rlen)76420Sstevel@tonic-gate prepare_xattr(
76430Sstevel@tonic-gate char **attrbuf,
76440Sstevel@tonic-gate char *filename,
76450Sstevel@tonic-gate char *attrname,
76460Sstevel@tonic-gate char typeflag,
76470Sstevel@tonic-gate struct linkbuf *linkinfo,
76480Sstevel@tonic-gate int *rlen)
76490Sstevel@tonic-gate {
76500Sstevel@tonic-gate *attrbuf = NULL;
76510Sstevel@tonic-gate *rlen = 0;
76520Sstevel@tonic-gate }
76530Sstevel@tonic-gate #endif
76540Sstevel@tonic-gate
76550Sstevel@tonic-gate int
getstat(int dirfd,char * longname,char * shortname,char * attrparent)76565331Samw getstat(int dirfd, char *longname, char *shortname, char *attrparent)
76570Sstevel@tonic-gate {
76580Sstevel@tonic-gate
76590Sstevel@tonic-gate int i, j;
76600Sstevel@tonic-gate int printerr;
76610Sstevel@tonic-gate int slnkerr;
76620Sstevel@tonic-gate struct stat symlnbuf;
76630Sstevel@tonic-gate
76640Sstevel@tonic-gate if (!hflag)
76650Sstevel@tonic-gate i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
76660Sstevel@tonic-gate else
76670Sstevel@tonic-gate i = fstatat(dirfd, shortname, &stbuf, 0);
76680Sstevel@tonic-gate
76690Sstevel@tonic-gate if (i < 0) {
76700Sstevel@tonic-gate /* Initialize flag to print error mesg. */
76710Sstevel@tonic-gate printerr = 1;
76720Sstevel@tonic-gate /*
76730Sstevel@tonic-gate * If stat is done, then need to do lstat
76740Sstevel@tonic-gate * to determine whether it's a sym link
76750Sstevel@tonic-gate */
76760Sstevel@tonic-gate if (hflag) {
76770Sstevel@tonic-gate /* Save returned error */
76780Sstevel@tonic-gate slnkerr = errno;
76790Sstevel@tonic-gate
76800Sstevel@tonic-gate j = fstatat(dirfd, shortname,
76810Sstevel@tonic-gate &symlnbuf, AT_SYMLINK_NOFOLLOW);
76820Sstevel@tonic-gate /*
76830Sstevel@tonic-gate * Suppress error message when file is a symbolic link
76840Sstevel@tonic-gate * and function modifier 'l' is off. Exception: when
76850Sstevel@tonic-gate * a symlink points to a symlink points to a
76860Sstevel@tonic-gate * symlink ... and we get past MAXSYMLINKS. That
76870Sstevel@tonic-gate * error will cause a file not to be archived, and
76880Sstevel@tonic-gate * needs to be printed.
76890Sstevel@tonic-gate */
76900Sstevel@tonic-gate if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
76910Sstevel@tonic-gate (S_ISLNK(symlnbuf.st_mode)))
76920Sstevel@tonic-gate printerr = 0;
76930Sstevel@tonic-gate
76940Sstevel@tonic-gate /*
76950Sstevel@tonic-gate * Restore errno in case the lstat
76960Sstevel@tonic-gate * on symbolic link change
76970Sstevel@tonic-gate */
76980Sstevel@tonic-gate errno = slnkerr;
76990Sstevel@tonic-gate }
77000Sstevel@tonic-gate
77010Sstevel@tonic-gate if (printerr) {
77020Sstevel@tonic-gate (void) fprintf(stderr, gettext(
77035331Samw "tar: %s%s%s%s: %s\n"),
77045331Samw (attrparent == NULL) ? "" : gettext("attribute "),
77055331Samw (attrparent == NULL) ? "" : attrparent,
77065331Samw (attrparent == NULL) ? "" : gettext(" of "),
77075331Samw longname, strerror(errno));
77080Sstevel@tonic-gate Errflg = 1;
77090Sstevel@tonic-gate }
77100Sstevel@tonic-gate return (1);
77110Sstevel@tonic-gate }
77120Sstevel@tonic-gate return (0);
77130Sstevel@tonic-gate }
77140Sstevel@tonic-gate
77155331Samw /*
77165331Samw * Recursively archive the extended attributes and/or extended system attributes
77175331Samw * of the base file, longname. Note: extended system attribute files will be
77185331Samw * archived only if the extended system attributes are not transient (i.e. the
77195331Samw * extended system attributes are other than the default values).
77205331Samw *
77215331Samw * If -@ was specified and the underlying file system supports it, archive the
77225331Samw * extended attributes, and if there is a system attribute associated with the
77235331Samw * extended attribute, then recursively call xattrs_put() to archive the
77245331Samw * hidden attribute directory and the extended system attribute. If -/ was
77255331Samw * specified and the underlying file system supports it, archive the extended
77265331Samw * system attributes. Read-only extended system attributes are never archived.
77275331Samw *
77285331Samw * Currently, there cannot be attributes on attributes; only system
77295331Samw * attributes on attributes. In addition, there cannot be attributes on
77305331Samw * system attributes. A file and it's attribute directory hierarchy looks as
77315331Samw * follows:
77325331Samw * longname ----> . ("." is the hidden attribute directory)
77335331Samw * |
77345331Samw * ----------------------------
77355331Samw * | |
77365331Samw * <sys_attr_name> <attr_name> ----> .
77375331Samw * |
77385331Samw * <sys_attr_name>
77395331Samw *
77405331Samw */
77410Sstevel@tonic-gate #if defined(O_XATTR)
77420Sstevel@tonic-gate static void
xattrs_put(char * longname,char * shortname,char * parent,char * attrparent)77435331Samw xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
77445331Samw {
77455331Samw char *filename = (attrparent == NULL) ? shortname : attrparent;
77465331Samw int arc_rwsysattr = 0;
77470Sstevel@tonic-gate int dirfd;
77485331Samw int fd = -1;
77495331Samw int rw_sysattr = 0;
77505750Sceastha int ext_attr = 0;
77515331Samw int rc;
77520Sstevel@tonic-gate DIR *dirp;
77530Sstevel@tonic-gate struct dirent *dp;
77545331Samw attr_data_t *attrinfo = NULL;
77555331Samw
77565331Samw /*
77575331Samw * If the underlying file system supports it, then archive the extended
77585331Samw * attributes if -@ was specified, and the extended system attributes
77595331Samw * if -/ was specified.
77605331Samw */
77615750Sceastha if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
77625750Sceastha &ext_attr) != ATTR_OK) {
77630Sstevel@tonic-gate return;
77640Sstevel@tonic-gate }
77650Sstevel@tonic-gate
77665331Samw /*
77675331Samw * Only want to archive a read-write extended system attribute file
77685331Samw * if it contains extended system attribute settings that are not the
77695331Samw * default values.
77705331Samw */
77715331Samw #if defined(_PC_SATTR_ENABLED)
77725331Samw if (saflag) {
77735331Samw int filefd;
77745331Samw nvlist_t *slist = NULL;
77755331Samw
77765331Samw /* Determine if there are non-transient system attributes */
77775331Samw errno = 0;
77785331Samw if ((filefd = open(filename, O_RDONLY)) == -1) {
77795331Samw if (attrparent == NULL) {
77805331Samw vperror(0, gettext(
77815331Samw "unable to open file %s"), longname);
77825331Samw }
77835331Samw return;
77845331Samw }
77855331Samw if (((slist = sysattr_list(basename(myname), filefd,
77865331Samw filename)) != NULL) || (errno != 0)) {
77875331Samw arc_rwsysattr = 1;
77885331Samw }
77895331Samw if (slist != NULL) {
77905331Samw (void) nvlist_free(slist);
77915331Samw slist = NULL;
77925331Samw }
77935331Samw (void) close(filefd);
77945331Samw }
77955750Sceastha
77965750Sceastha /*
77975750Sceastha * If we aren't archiving extended system attributes, and we are
77985750Sceastha * processing an attribute, or if we are archiving extended system
77995750Sceastha * attributes, and there are are no extended attributes, then there's
78005750Sceastha * no need to open up the attribute directory of the file unless the
78015750Sceastha * extended system attributes are not transient (i.e, the system
78025750Sceastha * attributes are not the default values).
78035750Sceastha */
78045750Sceastha if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
78055750Sceastha (saflag && !ext_attr))) {
78065750Sceastha return;
78075750Sceastha }
78085331Samw #endif /* _PC_SATTR_ENABLED */
78095331Samw
78105331Samw /* open the parent attribute directory */
78115331Samw fd = attropen(filename, ".", O_RDONLY);
78125331Samw if (fd < 0) {
78135331Samw vperror(0, gettext(
78145331Samw "unable to open attribute directory for %s%s%sfile %s"),
78155331Samw (attrparent == NULL) ? "" : gettext("attribute "),
78165331Samw (attrparent == NULL) ? "" : attrparent,
78175331Samw (attrparent == NULL) ? "" : gettext(" of "),
78180Sstevel@tonic-gate longname);
78190Sstevel@tonic-gate return;
78200Sstevel@tonic-gate }
78210Sstevel@tonic-gate
78225331Samw /*
78235331Samw * We need to change into the parent's attribute directory to determine
78245331Samw * if each of the attributes should be archived.
78255331Samw */
78265331Samw if (fchdir(fd) < 0) {
78275331Samw vperror(0, gettext(
78285331Samw "cannot change to attribute directory of %s%s%sfile %s"),
78295331Samw (attrparent == NULL) ? "" : gettext("attribute "),
78305331Samw (attrparent == NULL) ? "" : attrparent,
78315331Samw (attrparent == NULL) ? "" : gettext(" of "),
78325331Samw longname);
78335331Samw (void) close(fd);
78345331Samw return;
78355331Samw }
78365331Samw
78375331Samw if (((dirfd = dup(fd)) == -1) ||
78385331Samw ((dirp = fdopendir(dirfd)) == NULL)) {
78390Sstevel@tonic-gate (void) fprintf(stderr, gettext(
78405331Samw "tar: unable to open dir pointer for %s%s%sfile %s\n"),
78415331Samw (attrparent == NULL) ? "" : gettext("attribute "),
78425331Samw (attrparent == NULL) ? "" : attrparent,
78435331Samw (attrparent == NULL) ? "" : gettext(" of "),
78445331Samw longname);
78455331Samw if (fd > 0) {
78465331Samw (void) close(fd);
78475331Samw }
78480Sstevel@tonic-gate return;
78490Sstevel@tonic-gate }
78500Sstevel@tonic-gate
78510Sstevel@tonic-gate while (dp = readdir(dirp)) {
78525331Samw if (strcmp(dp->d_name, "..") == 0) {
78530Sstevel@tonic-gate continue;
78545331Samw } else if (strcmp(dp->d_name, ".") == 0) {
78550Sstevel@tonic-gate Hiddendir = 1;
78565331Samw } else {
78570Sstevel@tonic-gate Hiddendir = 0;
78585331Samw }
78595331Samw
78605331Samw /* Determine if this attribute should be archived */
78615331Samw if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
78625331Samw &rw_sysattr) != ATTR_OK) {
78635331Samw continue;
78645331Samw }
78655331Samw
78665331Samw /* gather the attribute's information to pass to putfile() */
78675331Samw if ((fill_in_attr_info(dp->d_name, longname, attrparent,
78685331Samw fd, rw_sysattr, &attrinfo)) == 1) {
78695331Samw continue;
78705331Samw }
78715331Samw
78725331Samw /* add the attribute to the archive */
78735331Samw rc = putfile(longname, dp->d_name, parent, attrinfo,
78740Sstevel@tonic-gate XATTR_FILE, LEV0, SYMLINK_LEV0);
78750Sstevel@tonic-gate
78765331Samw if (exitflag) {
78770Sstevel@tonic-gate break;
78785331Samw }
78795331Samw
78805331Samw #if defined(_PC_SATTR_ENABLED)
78815331Samw /*
78825331Samw * If both -/ and -@ were specified, then archive the
78835331Samw * attribute's extended system attributes and hidden directory
78845331Samw * by making a recursive call to xattrs_put().
78855331Samw */
78865331Samw if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
78875331Samw (Hiddendir == 0)) {
78885331Samw
78895331Samw xattrs_put(longname, shortname, parent, dp->d_name);
78905331Samw
78915331Samw /*
78925331Samw * Change back to the parent's attribute directory
78935331Samw * to process any further attributes.
78945331Samw */
78955331Samw if (fchdir(fd) < 0) {
78965331Samw vperror(0, gettext(
78975331Samw "cannot change back to attribute directory "
78985331Samw "of file %s"), longname);
78995331Samw break;
79005331Samw }
79015331Samw }
79025331Samw #endif /* _PC_SATTR_ENABLED */
79035331Samw }
79045331Samw
79055331Samw if (attrinfo != NULL) {
79065331Samw if (attrinfo->attr_parent != NULL) {
79075331Samw free(attrinfo->attr_parent);
79085331Samw }
79095331Samw free(attrinfo->attr_path);
79105331Samw free(attrinfo);
79115331Samw }
79120Sstevel@tonic-gate (void) closedir(dirp);
79135331Samw if (fd != -1) {
79145331Samw (void) close(fd);
79155331Samw }
79165331Samw
79175331Samw /* Change back to the parent directory of the base file */
79185331Samw if (attrparent == NULL) {
791912554Srich.burridge@oracle.com (void) tar_chdir(parent);
79205331Samw }
79215750Sceastha Hiddendir = 0;
79220Sstevel@tonic-gate }
79230Sstevel@tonic-gate #else
79240Sstevel@tonic-gate static void
xattrs_put(char * longname,char * shortname,char * parent,char * attrppath)79255331Samw xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
79260Sstevel@tonic-gate {
79270Sstevel@tonic-gate }
79280Sstevel@tonic-gate #endif /* O_XATTR */
79290Sstevel@tonic-gate
79300Sstevel@tonic-gate static int
put_link(char * name,char * longname,char * component,char * longattrname,char * prefix,int filetype,char type)79315331Samw put_link(char *name, char *longname, char *component, char *longattrname,
79325331Samw char *prefix, int filetype, char type)
79330Sstevel@tonic-gate {
79340Sstevel@tonic-gate
79350Sstevel@tonic-gate if (stbuf.st_nlink > 1) {
79360Sstevel@tonic-gate struct linkbuf *lp;
79370Sstevel@tonic-gate int found = 0;
79380Sstevel@tonic-gate
79390Sstevel@tonic-gate for (lp = ihead; lp != NULL; lp = lp->nextp)
79400Sstevel@tonic-gate if (lp->inum == stbuf.st_ino &&
79410Sstevel@tonic-gate lp->devnum == stbuf.st_dev) {
79420Sstevel@tonic-gate found++;
79430Sstevel@tonic-gate break;
79440Sstevel@tonic-gate }
79450Sstevel@tonic-gate if (found) {
79460Sstevel@tonic-gate #if defined(O_XATTR)
79470Sstevel@tonic-gate if (filetype == XATTR_FILE)
79485331Samw if (put_xattr_hdr(longname, component,
79495331Samw longattrname, prefix, type, filetype, lp)) {
79500Sstevel@tonic-gate goto out;
79510Sstevel@tonic-gate }
79520Sstevel@tonic-gate #endif
79530Sstevel@tonic-gate stbuf.st_size = (off_t)0;
79540Sstevel@tonic-gate if (filetype != XATTR_FILE) {
79550Sstevel@tonic-gate tomodes(&stbuf);
79560Sstevel@tonic-gate if (chk_path_build(name, longname, lp->pathname,
79570Sstevel@tonic-gate prefix, type, filetype) > 0) {
79580Sstevel@tonic-gate goto out;
79590Sstevel@tonic-gate }
79600Sstevel@tonic-gate }
79610Sstevel@tonic-gate
79620Sstevel@tonic-gate if (mulvol && tapepos + 1 >= blocklim)
79630Sstevel@tonic-gate newvol();
79640Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1);
79650Sstevel@tonic-gate /*
79660Sstevel@tonic-gate * write_ancillary() is not needed here.
79670Sstevel@tonic-gate * The first link is handled in the following
79680Sstevel@tonic-gate * else statement. No need to process ACLs
79690Sstevel@tonic-gate * for other hard links since they are the
79700Sstevel@tonic-gate * same file.
79710Sstevel@tonic-gate */
79720Sstevel@tonic-gate
79730Sstevel@tonic-gate if (vflag) {
79740Sstevel@tonic-gate #ifdef DEBUG
79750Sstevel@tonic-gate if (NotTape)
79760Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t
79770Sstevel@tonic-gate "K\t", K(tapepos), 0);
79780Sstevel@tonic-gate #endif
79790Sstevel@tonic-gate if (filetype == XATTR_FILE) {
79800Sstevel@tonic-gate (void) fprintf(vfile, gettext(
79810Sstevel@tonic-gate "a %s attribute %s link to "
79825331Samw "%s attribute %s\n"),
79835331Samw name, component, name,
79845331Samw lp->attrname);
79850Sstevel@tonic-gate } else {
79860Sstevel@tonic-gate (void) fprintf(vfile, gettext(
79870Sstevel@tonic-gate "a %s link to %s\n"),
79880Sstevel@tonic-gate longname, lp->pathname);
79890Sstevel@tonic-gate }
79900Sstevel@tonic-gate }
79910Sstevel@tonic-gate lp->count--;
79920Sstevel@tonic-gate return (0);
79930Sstevel@tonic-gate } else {
79940Sstevel@tonic-gate lp = (struct linkbuf *)getmem(sizeof (*lp));
79950Sstevel@tonic-gate if (lp != (struct linkbuf *)NULL) {
79960Sstevel@tonic-gate lp->nextp = ihead;
79970Sstevel@tonic-gate ihead = lp;
79980Sstevel@tonic-gate lp->inum = stbuf.st_ino;
79990Sstevel@tonic-gate lp->devnum = stbuf.st_dev;
80000Sstevel@tonic-gate lp->count = stbuf.st_nlink - 1;
80010Sstevel@tonic-gate if (filetype == XATTR_FILE) {
80020Sstevel@tonic-gate (void) strcpy(lp->pathname, longname);
80035331Samw (void) strcpy(lp->attrname,
80045331Samw component);
80050Sstevel@tonic-gate } else {
80060Sstevel@tonic-gate (void) strcpy(lp->pathname, longname);
80070Sstevel@tonic-gate (void) strcpy(lp->attrname, "");
80080Sstevel@tonic-gate }
80090Sstevel@tonic-gate }
80100Sstevel@tonic-gate }
80110Sstevel@tonic-gate }
80120Sstevel@tonic-gate
80130Sstevel@tonic-gate out:
80140Sstevel@tonic-gate return (1);
80150Sstevel@tonic-gate }
80160Sstevel@tonic-gate
80170Sstevel@tonic-gate static int
put_extra_attributes(char * longname,char * shortname,char * longattrname,char * prefix,int filetype,char typeflag)80185331Samw put_extra_attributes(char *longname, char *shortname, char *longattrname,
80195331Samw char *prefix, int filetype, char typeflag)
80200Sstevel@tonic-gate {
8021789Sahrens static acl_t *aclp = NULL;
8022789Sahrens int error;
8023789Sahrens
8024789Sahrens if (aclp != NULL) {
8025789Sahrens acl_free(aclp);
80260Sstevel@tonic-gate aclp = NULL;
80270Sstevel@tonic-gate }
80280Sstevel@tonic-gate #if defined(O_XATTR)
80295331Samw if ((atflag || saflag) && (filetype == XATTR_FILE)) {
80305331Samw if (put_xattr_hdr(longname, shortname, longattrname, prefix,
80310Sstevel@tonic-gate typeflag, filetype, NULL)) {
80320Sstevel@tonic-gate return (1);
80330Sstevel@tonic-gate }
80340Sstevel@tonic-gate }
80350Sstevel@tonic-gate #endif
80360Sstevel@tonic-gate
80370Sstevel@tonic-gate /* ACL support */
80380Sstevel@tonic-gate if (pflag) {
80390Sstevel@tonic-gate char *secinfo = NULL;
80400Sstevel@tonic-gate int len = 0;
80410Sstevel@tonic-gate
80420Sstevel@tonic-gate /* ACL support */
80430Sstevel@tonic-gate if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
80440Sstevel@tonic-gate /*
80450Sstevel@tonic-gate * Get ACL info: dont bother allocating space if
8046789Sahrens * there is only a trivial ACL.
80470Sstevel@tonic-gate */
8048789Sahrens if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8049789Sahrens &aclp)) != 0) {
80500Sstevel@tonic-gate (void) fprintf(stderr, gettext(
8051789Sahrens "%s: failed to retrieve acl : %s\n"),
8052789Sahrens longname, acl_strerror(error));
80530Sstevel@tonic-gate return (1);
80540Sstevel@tonic-gate }
80550Sstevel@tonic-gate }
80560Sstevel@tonic-gate
80570Sstevel@tonic-gate /* append security attributes if any */
8058789Sahrens if (aclp != NULL) {
80591676Sjpk (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
80607057Smarks acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
80617057Smarks ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
80627057Smarks UFSD_ACL : ACE_ACL);
80631676Sjpk }
80641676Sjpk
80651676Sjpk if (Tflag) {
80661676Sjpk /* append Trusted Extensions extended attributes */
80671676Sjpk append_ext_attr(shortname, &secinfo, &len);
80681676Sjpk (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
80691676Sjpk
80701676Sjpk } else if (aclp != NULL) {
80710Sstevel@tonic-gate (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
80720Sstevel@tonic-gate }
80730Sstevel@tonic-gate }
80740Sstevel@tonic-gate return (0);
80750Sstevel@tonic-gate }
80760Sstevel@tonic-gate
80770Sstevel@tonic-gate #if defined(O_XATTR)
80780Sstevel@tonic-gate static int
put_xattr_hdr(char * longname,char * shortname,char * longattrname,char * prefix,int typeflag,int filetype,struct linkbuf * lp)80795331Samw put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
80800Sstevel@tonic-gate int typeflag, int filetype, struct linkbuf *lp)
80810Sstevel@tonic-gate {
80820Sstevel@tonic-gate char *lname = NULL;
80830Sstevel@tonic-gate char *sname = NULL;
80840Sstevel@tonic-gate int error = 0;
80850Sstevel@tonic-gate static char *attrbuf = NULL;
80860Sstevel@tonic-gate int attrlen;
80870Sstevel@tonic-gate
80880Sstevel@tonic-gate lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
80890Sstevel@tonic-gate strlen(shortname) + strlen(".hdr") + 1);
80900Sstevel@tonic-gate
80910Sstevel@tonic-gate if (lname == NULL) {
80920Sstevel@tonic-gate fatal(gettext("Out of Memory."));
80930Sstevel@tonic-gate }
80940Sstevel@tonic-gate sname = malloc(sizeof (char) * strlen(shortname) +
80955331Samw strlen(".hdr") + 1);
80960Sstevel@tonic-gate if (sname == NULL) {
80970Sstevel@tonic-gate fatal(gettext("Out of Memory."));
80980Sstevel@tonic-gate }
80990Sstevel@tonic-gate
81000Sstevel@tonic-gate (void) sprintf(sname, "%s.hdr", shortname);
81010Sstevel@tonic-gate (void) sprintf(lname, "/dev/null/%s", sname);
81020Sstevel@tonic-gate
81030Sstevel@tonic-gate if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
81040Sstevel@tonic-gate sizeof (dblock.dbuf.name)) {
81050Sstevel@tonic-gate fatal(gettext(
81060Sstevel@tonic-gate "Buffer overflow writing extended attribute file name"));
81070Sstevel@tonic-gate }
81080Sstevel@tonic-gate
81090Sstevel@tonic-gate /*
81100Sstevel@tonic-gate * dump extended attr lookup info
81110Sstevel@tonic-gate */
81125331Samw prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
81130Sstevel@tonic-gate write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
81140Sstevel@tonic-gate
81150Sstevel@tonic-gate (void) sprintf(lname, "/dev/null/%s", shortname);
81160Sstevel@tonic-gate (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
81170Sstevel@tonic-gate
81180Sstevel@tonic-gate /*
81190Sstevel@tonic-gate * Set up filename for attribute
81200Sstevel@tonic-gate */
81210Sstevel@tonic-gate
81220Sstevel@tonic-gate error = build_dblock(lname, tchar, '0', filetype,
81230Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix);
81240Sstevel@tonic-gate free(lname);
81250Sstevel@tonic-gate free(sname);
81260Sstevel@tonic-gate
81270Sstevel@tonic-gate return (error);
81280Sstevel@tonic-gate }
81290Sstevel@tonic-gate #endif
81300Sstevel@tonic-gate
81310Sstevel@tonic-gate #if defined(O_XATTR)
81320Sstevel@tonic-gate static int
read_xattr_hdr(attr_data_t ** attrinfo)81335331Samw read_xattr_hdr(attr_data_t **attrinfo)
81340Sstevel@tonic-gate {
81350Sstevel@tonic-gate char buf[TBLOCK];
81365331Samw char *attrparent = NULL;
81370Sstevel@tonic-gate blkcnt_t blocks;
81380Sstevel@tonic-gate char *tp;
81390Sstevel@tonic-gate off_t bytes;
81400Sstevel@tonic-gate int comp_len, link_len;
81410Sstevel@tonic-gate int namelen;
81425331Samw int attrparentlen;
81435331Samw int parentfilelen;
81440Sstevel@tonic-gate
81450Sstevel@tonic-gate if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
81460Sstevel@tonic-gate return (1);
81470Sstevel@tonic-gate
81480Sstevel@tonic-gate bytes = stbuf.st_size;
81490Sstevel@tonic-gate if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
81500Sstevel@tonic-gate (void) fprintf(stderr, gettext(
81510Sstevel@tonic-gate "Insufficient memory for extended attribute\n"));
81520Sstevel@tonic-gate return (1);
81530Sstevel@tonic-gate }
81540Sstevel@tonic-gate
81550Sstevel@tonic-gate tp = (char *)xattrhead;
81560Sstevel@tonic-gate blocks = TBLOCKS(bytes);
81570Sstevel@tonic-gate while (blocks-- > 0) {
81580Sstevel@tonic-gate readtape(buf);
81590Sstevel@tonic-gate if (bytes <= TBLOCK) {
81600Sstevel@tonic-gate (void) memcpy(tp, buf, (size_t)bytes);
81610Sstevel@tonic-gate break;
81620Sstevel@tonic-gate } else {
81630Sstevel@tonic-gate (void) memcpy(tp, buf, TBLOCK);
81640Sstevel@tonic-gate tp += TBLOCK;
81650Sstevel@tonic-gate }
81660Sstevel@tonic-gate bytes -= TBLOCK;
81670Sstevel@tonic-gate }
81680Sstevel@tonic-gate
81690Sstevel@tonic-gate /*
81700Sstevel@tonic-gate * Validate that we can handle header format
81710Sstevel@tonic-gate */
81720Sstevel@tonic-gate if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
81730Sstevel@tonic-gate (void) fprintf(stderr,
81740Sstevel@tonic-gate gettext("Unknown extended attribute format encountered\n"));
81750Sstevel@tonic-gate (void) fprintf(stderr,
81760Sstevel@tonic-gate gettext("Disabling extended attribute parsing\n"));
81770Sstevel@tonic-gate xattrbadhead = 1;
81780Sstevel@tonic-gate return (0);
81790Sstevel@tonic-gate }
81800Sstevel@tonic-gate (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
81810Sstevel@tonic-gate (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
81820Sstevel@tonic-gate xattrp = (struct xattr_buf *)(((char *)xattrhead) +
81830Sstevel@tonic-gate sizeof (struct xattr_hdr));
81840Sstevel@tonic-gate (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
81850Sstevel@tonic-gate if (link_len > 0)
81860Sstevel@tonic-gate xattr_linkp = (struct xattr_buf *)
81870Sstevel@tonic-gate ((int)xattrp + (int)comp_len);
81880Sstevel@tonic-gate else
81890Sstevel@tonic-gate xattr_linkp = NULL;
81900Sstevel@tonic-gate
81915331Samw /*
81925331Samw * Gather the attribute path from the filename and attrnames section.
81935331Samw * The filename and attrnames section can be composed of two or more
81945331Samw * path segments separated by a null character. The first segment
81955331Samw * is the path to the parent file that roots the entire sequence in
81965331Samw * the normal name space. The remaining segments describes a path
81975331Samw * rooted at the hidden extended attribute directory of the leaf file of
81985331Samw * the previous segment, making it possible to name attributes on
81995331Samw * attributes.
82005331Samw */
82015331Samw parentfilelen = strlen(xattrp->h_names);
82025331Samw xattrapath = xattrp->h_names + parentfilelen + 1;
82035331Samw if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
82045331Samw /*
82055331Samw * The attrnames section contains a system attribute on an
82065331Samw * attribute. Save the name of the attribute for use later,
82075331Samw * and replace the null separating the attribute name from
82085331Samw * the system attribute name with a '/' so that xattrapath can
82095331Samw * be used to display messages with the full attribute path name
82105331Samw * rooted at the hidden attribute directory of the base file
82115331Samw * in normal name space.
82125331Samw */
82135331Samw attrparent = strdup(xattrapath);
82145331Samw attrparentlen = strlen(attrparent);
82155331Samw xattrapath[attrparentlen] = '/';
82165331Samw }
82175331Samw if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
82185331Samw xattrapath + attrparentlen + 1, xattrapath, attrparent,
82195331Samw -1, 0, attrinfo)) == 1) {
82205331Samw free(attrparent);
82215331Samw return (1);
82225331Samw }
82235331Samw
82245331Samw /* Gather link info */
82250Sstevel@tonic-gate if (xattr_linkp) {
82260Sstevel@tonic-gate xattr_linkaname = xattr_linkp->h_names +
82270Sstevel@tonic-gate strlen(xattr_linkp->h_names) + 1;
82280Sstevel@tonic-gate } else {
82290Sstevel@tonic-gate xattr_linkaname = NULL;
82300Sstevel@tonic-gate }
82311231Smarks
82320Sstevel@tonic-gate return (0);
82330Sstevel@tonic-gate }
82340Sstevel@tonic-gate #else
82350Sstevel@tonic-gate static int
read_xattr_hdr(attr_data_t ** attrinfo)82365331Samw read_xattr_hdr(attr_data_t **attrinfo)
82370Sstevel@tonic-gate {
82380Sstevel@tonic-gate return (0);
82390Sstevel@tonic-gate }
82400Sstevel@tonic-gate #endif
82410Sstevel@tonic-gate
82420Sstevel@tonic-gate /*
82430Sstevel@tonic-gate * skip over extra slashes in string.
82440Sstevel@tonic-gate *
82450Sstevel@tonic-gate * For example:
82460Sstevel@tonic-gate * /usr/tmp/////
82470Sstevel@tonic-gate *
82480Sstevel@tonic-gate * would return pointer at
82490Sstevel@tonic-gate * /usr/tmp/////
82500Sstevel@tonic-gate * ^
82510Sstevel@tonic-gate */
82520Sstevel@tonic-gate static char *
skipslashes(char * string,char * start)82530Sstevel@tonic-gate skipslashes(char *string, char *start)
82540Sstevel@tonic-gate {
82550Sstevel@tonic-gate while ((string > start) && *(string - 1) == '/') {
82560Sstevel@tonic-gate string--;
82570Sstevel@tonic-gate }
82580Sstevel@tonic-gate
82590Sstevel@tonic-gate return (string);
82600Sstevel@tonic-gate }
82610Sstevel@tonic-gate
82620Sstevel@tonic-gate /*
82630Sstevel@tonic-gate * Return the parent directory of a given path.
82640Sstevel@tonic-gate *
82650Sstevel@tonic-gate * Examples:
82660Sstevel@tonic-gate * /usr/tmp return /usr
82670Sstevel@tonic-gate * /usr/tmp/file return /usr/tmp
82680Sstevel@tonic-gate * / returns .
82690Sstevel@tonic-gate * /usr returns /
82700Sstevel@tonic-gate * file returns .
82710Sstevel@tonic-gate *
82720Sstevel@tonic-gate * dir is assumed to be at least as big as path.
82730Sstevel@tonic-gate */
82740Sstevel@tonic-gate static void
get_parent(char * path,char * dir)82750Sstevel@tonic-gate get_parent(char *path, char *dir)
82760Sstevel@tonic-gate {
82770Sstevel@tonic-gate char *s;
82780Sstevel@tonic-gate char tmpdir[PATH_MAX + 1];
82790Sstevel@tonic-gate
82800Sstevel@tonic-gate if (strlen(path) > PATH_MAX) {
82810Sstevel@tonic-gate fatal(gettext("pathname is too long"));
82820Sstevel@tonic-gate }
82830Sstevel@tonic-gate (void) strcpy(tmpdir, path);
82840Sstevel@tonic-gate chop_endslashes(tmpdir);
82850Sstevel@tonic-gate
82860Sstevel@tonic-gate if ((s = strrchr(tmpdir, '/')) == NULL) {
82870Sstevel@tonic-gate (void) strcpy(dir, ".");
82880Sstevel@tonic-gate } else {
82890Sstevel@tonic-gate s = skipslashes(s, tmpdir);
82900Sstevel@tonic-gate *s = '\0';
82910Sstevel@tonic-gate if (s == tmpdir)
82920Sstevel@tonic-gate (void) strcpy(dir, "/");
82930Sstevel@tonic-gate else
82940Sstevel@tonic-gate (void) strcpy(dir, tmpdir);
82950Sstevel@tonic-gate }
82960Sstevel@tonic-gate }
82970Sstevel@tonic-gate
82980Sstevel@tonic-gate #if defined(O_XATTR)
82990Sstevel@tonic-gate static char *
get_component(char * path)83000Sstevel@tonic-gate get_component(char *path)
83010Sstevel@tonic-gate {
83020Sstevel@tonic-gate char *ptr;
83030Sstevel@tonic-gate
83040Sstevel@tonic-gate ptr = strrchr(path, '/');
83050Sstevel@tonic-gate if (ptr == NULL) {
83060Sstevel@tonic-gate return (path);
83070Sstevel@tonic-gate } else {
83080Sstevel@tonic-gate /*
83090Sstevel@tonic-gate * Handle trailing slash
83100Sstevel@tonic-gate */
83110Sstevel@tonic-gate if (*(ptr + 1) == '\0')
83120Sstevel@tonic-gate return (ptr);
83130Sstevel@tonic-gate else
83140Sstevel@tonic-gate return (ptr + 1);
83150Sstevel@tonic-gate }
83160Sstevel@tonic-gate }
83170Sstevel@tonic-gate #else
83180Sstevel@tonic-gate static char *
get_component(char * path)83190Sstevel@tonic-gate get_component(char *path)
83200Sstevel@tonic-gate {
83210Sstevel@tonic-gate return (path);
83220Sstevel@tonic-gate }
83230Sstevel@tonic-gate #endif
83240Sstevel@tonic-gate
83255331Samw #if defined(O_XATTR)
83260Sstevel@tonic-gate static int
retry_open_attr(int pdirfd,int cwd,char * dirp,char * pattr,char * name,int oflag,mode_t mode)83275331Samw retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
83285331Samw int oflag, mode_t mode)
83295331Samw {
83305331Samw int dirfd;
83315331Samw int ofilefd = -1;
83320Sstevel@tonic-gate struct timeval times[2];
83330Sstevel@tonic-gate mode_t newmode;
83340Sstevel@tonic-gate struct stat parentstat;
83351231Smarks acl_t *aclp = NULL;
83361231Smarks int error;
83370Sstevel@tonic-gate
83380Sstevel@tonic-gate /*
83390Sstevel@tonic-gate * We couldn't get to attrdir. See if its
83400Sstevel@tonic-gate * just a mode problem on the parent file.
83410Sstevel@tonic-gate * for example: a mode such as r-xr--r--
83425331Samw * on a ufs file system without extended
83435331Samw * system attribute support won't let us
83445331Samw * create an attribute dir if it doesn't
83455331Samw * already exist, and on a ufs file system
83465331Samw * with extended system attribute support
83475331Samw * won't let us open the attribute for
83485331Samw * write.
83491231Smarks *
83501231Smarks * If file has a non-trivial ACL, then save it
83511231Smarks * off so that we can place it back on after doing
83521231Smarks * chmod's.
83530Sstevel@tonic-gate */
83545331Samw if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
83555331Samw O_RDONLY)) == -1) {
83565331Samw return (-1);
83575331Samw }
83585331Samw if (fstat(dirfd, &parentstat) == -1) {
83595331Samw (void) fprintf(stderr, gettext(
83605331Samw "tar: cannot stat %sfile %s: %s\n"),
83615331Samw (pdirfd == -1) ? "" : gettext("parent of "),
83625331Samw (pdirfd == -1) ? dirp : name, strerror(errno));
83631231Smarks return (-1);
83641231Smarks }
83655331Samw if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
83665331Samw (void) fprintf(stderr, gettext(
83675331Samw "tar: failed to retrieve ACL on %sfile %s: %s\n"),
83685331Samw (pdirfd == -1) ? "" : gettext("parent of "),
83695331Samw (pdirfd == -1) ? dirp : name, strerror(errno));
83701231Smarks return (-1);
83711231Smarks }
83721231Smarks
83730Sstevel@tonic-gate newmode = S_IWUSR | parentstat.st_mode;
83745331Samw if (fchmod(dirfd, newmode) == -1) {
83750Sstevel@tonic-gate (void) fprintf(stderr,
83765331Samw gettext(
83775331Samw "tar: cannot fchmod %sfile %s to %o: %s\n"),
83785331Samw (pdirfd == -1) ? "" : gettext("parent of "),
83795331Samw (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
83801231Smarks if (aclp)
83811231Smarks acl_free(aclp);
83821231Smarks return (-1);
83830Sstevel@tonic-gate }
83840Sstevel@tonic-gate
83855331Samw
83865331Samw if (pdirfd == -1) {
83875331Samw /*
83885331Samw * We weren't able to create the attribute directory before.
83895331Samw * Now try again.
83905331Samw */
83915331Samw ofilefd = attropen(dirp, ".", oflag);
83925331Samw } else {
83935331Samw /*
83945331Samw * We weren't able to create open the attribute before.
83955331Samw * Now try again.
83965331Samw */
83975331Samw ofilefd = openat(pdirfd, name, oflag, mode);
83985331Samw }
83991231Smarks
84001231Smarks /*
84011231Smarks * Put mode back to original
84021231Smarks */
84035331Samw if (fchmod(dirfd, parentstat.st_mode) == -1) {
84040Sstevel@tonic-gate (void) fprintf(stderr,
84055331Samw gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
84065331Samw (pdirfd == -1) ? "" : gettext("parent of "),
84075331Samw (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
84081231Smarks }
84091231Smarks
84101231Smarks if (aclp) {
84115331Samw error = facl_set(dirfd, aclp);
84121231Smarks if (error) {
84131231Smarks (void) fprintf(stderr,
84145331Samw gettext("tar: failed to set acl entries on "
84155331Samw "%sfile %s\n"),
84165331Samw (pdirfd == -1) ? "" : gettext("parent of "),
84175331Samw (pdirfd == -1) ? dirp : name);
84181231Smarks }
84191231Smarks acl_free(aclp);
84201231Smarks }
84211231Smarks
84221231Smarks /*
84231231Smarks * Put back time stamps
84241231Smarks */
84251231Smarks
84261231Smarks times[0].tv_sec = parentstat.st_atime;
84271231Smarks times[0].tv_usec = 0;
84281231Smarks times[1].tv_sec = parentstat.st_mtime;
84291231Smarks times[1].tv_usec = 0;
84305331Samw
84315331Samw (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
84325331Samw
84335331Samw (void) close(dirfd);
84345331Samw
84355331Samw return (ofilefd);
84365331Samw }
84375331Samw #endif
84380Sstevel@tonic-gate
84390Sstevel@tonic-gate #if !defined(O_XATTR)
84400Sstevel@tonic-gate static int
openat64(int fd,const char * name,int oflag,mode_t cmode)84410Sstevel@tonic-gate openat64(int fd, const char *name, int oflag, mode_t cmode)
84420Sstevel@tonic-gate {
84430Sstevel@tonic-gate return (open64(name, oflag, cmode));
84440Sstevel@tonic-gate }
84450Sstevel@tonic-gate
84460Sstevel@tonic-gate static int
openat(int fd,const char * name,int oflag,mode_t cmode)84470Sstevel@tonic-gate openat(int fd, const char *name, int oflag, mode_t cmode)
84480Sstevel@tonic-gate {
84490Sstevel@tonic-gate return (open(name, oflag, cmode));
84500Sstevel@tonic-gate }
84510Sstevel@tonic-gate
84520Sstevel@tonic-gate static int
fchownat(int fd,const char * name,uid_t owner,gid_t group,int flag)84530Sstevel@tonic-gate fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
84540Sstevel@tonic-gate {
84550Sstevel@tonic-gate if (flag == AT_SYMLINK_NOFOLLOW)
84560Sstevel@tonic-gate return (lchown(name, owner, group));
84570Sstevel@tonic-gate else
84580Sstevel@tonic-gate return (chown(name, owner, group));
84590Sstevel@tonic-gate }
84600Sstevel@tonic-gate
84610Sstevel@tonic-gate static int
renameat(int fromfd,char * old,int tofd,char * new)84620Sstevel@tonic-gate renameat(int fromfd, char *old, int tofd, char *new)
84630Sstevel@tonic-gate {
84640Sstevel@tonic-gate return (rename(old, new));
84650Sstevel@tonic-gate }
84660Sstevel@tonic-gate
84670Sstevel@tonic-gate static int
futimesat(int fd,char * path,struct timeval times[2])84680Sstevel@tonic-gate futimesat(int fd, char *path, struct timeval times[2])
84690Sstevel@tonic-gate {
84700Sstevel@tonic-gate return (utimes(path, times));
84710Sstevel@tonic-gate }
84720Sstevel@tonic-gate
84730Sstevel@tonic-gate static int
unlinkat(int dirfd,char * path,int flag)84740Sstevel@tonic-gate unlinkat(int dirfd, char *path, int flag)
84750Sstevel@tonic-gate {
84760Sstevel@tonic-gate if (flag == AT_REMOVEDIR)
84770Sstevel@tonic-gate return (rmdir(path));
84780Sstevel@tonic-gate else
84790Sstevel@tonic-gate return (unlink(path));
84800Sstevel@tonic-gate }
84810Sstevel@tonic-gate
84820Sstevel@tonic-gate static int
fstatat(int fd,char * path,struct stat * buf,int flag)84830Sstevel@tonic-gate fstatat(int fd, char *path, struct stat *buf, int flag)
84840Sstevel@tonic-gate {
84850Sstevel@tonic-gate if (flag == AT_SYMLINK_NOFOLLOW)
84860Sstevel@tonic-gate return (lstat(path, buf));
84870Sstevel@tonic-gate else
84880Sstevel@tonic-gate return (stat(path, buf));
84890Sstevel@tonic-gate }
84900Sstevel@tonic-gate
84910Sstevel@tonic-gate static int
attropen(char * file,char * attr,int omode,mode_t cmode)84920Sstevel@tonic-gate attropen(char *file, char *attr, int omode, mode_t cmode)
84930Sstevel@tonic-gate {
84940Sstevel@tonic-gate errno = ENOTSUP;
84950Sstevel@tonic-gate return (-1);
84960Sstevel@tonic-gate }
84970Sstevel@tonic-gate #endif
84980Sstevel@tonic-gate
84990Sstevel@tonic-gate static void
chop_endslashes(char * path)85000Sstevel@tonic-gate chop_endslashes(char *path)
85010Sstevel@tonic-gate {
85020Sstevel@tonic-gate char *end, *ptr;
85030Sstevel@tonic-gate
85040Sstevel@tonic-gate /*
85050Sstevel@tonic-gate * Chop of slashes, but not if all we have is slashes
85060Sstevel@tonic-gate * for example: ////
85070Sstevel@tonic-gate * should make no changes, otherwise it will screw up
85080Sstevel@tonic-gate * checkdir
85090Sstevel@tonic-gate */
85100Sstevel@tonic-gate end = &path[strlen(path) -1];
85110Sstevel@tonic-gate if (*end == '/' && end != path) {
85120Sstevel@tonic-gate ptr = skipslashes(end, path);
85130Sstevel@tonic-gate if (ptr != NULL && ptr != path) {
85140Sstevel@tonic-gate *ptr = '\0';
85150Sstevel@tonic-gate }
85160Sstevel@tonic-gate }
85170Sstevel@tonic-gate }
85181676Sjpk /* Trusted Extensions */
85191676Sjpk
85201676Sjpk /*
85211676Sjpk * append_ext_attr():
85221676Sjpk *
85231676Sjpk * Append extended attributes and other information into the buffer
85241676Sjpk * that gets written to the ancillary file.
85251676Sjpk *
85261676Sjpk * With option 'T', we create a tarfile which
85271676Sjpk * has an ancillary file each corresponding archived file.
85281676Sjpk * Each ancillary file contains 1 or more of the
85291676Sjpk * following attributes:
85301676Sjpk *
85311676Sjpk * attribute type attribute process procedure
85321676Sjpk * ---------------- ---------------- --------------------------
85331676Sjpk * DIR_TYPE = 'D' directory flag append if a directory
85341676Sjpk * LBL_TYPE = 'L' SL[IL] or SL append ascii label
85351676Sjpk *
85361676Sjpk *
85371676Sjpk */
85381676Sjpk static void
append_ext_attr(char * shortname,char ** secinfo,int * len)85391676Sjpk append_ext_attr(char *shortname, char **secinfo, int *len)
85401676Sjpk {
85411676Sjpk bslabel_t b_slabel; /* binary sensitvity label */
85421676Sjpk char *ascii = NULL; /* ascii label */
85431676Sjpk
85441676Sjpk /*
85451676Sjpk * For each attribute type, append it if it is
85461676Sjpk * relevant to the file type.
85471676Sjpk */
85481676Sjpk
85491676Sjpk /*
85501676Sjpk * For attribute type DIR_TYPE,
85511676Sjpk * append it to the following file type:
85521676Sjpk *
85531676Sjpk * S_IFDIR: directories
85541676Sjpk */
85551676Sjpk
85561676Sjpk /*
85571676Sjpk * For attribute type LBL_TYPE,
85581676Sjpk * append it to the following file type:
85591676Sjpk *
85601676Sjpk * S_IFDIR: directories (including mld, sld)
85611676Sjpk * S_IFLNK: symbolic link
85621676Sjpk * S_IFREG: regular file but not hard link
85631676Sjpk * S_IFIFO: FIFO file but not hard link
85641676Sjpk * S_IFCHR: char special file but not hard link
85651676Sjpk * S_IFBLK: block special file but not hard link
85661676Sjpk */
85671676Sjpk switch (stbuf.st_mode & S_IFMT) {
85681676Sjpk
85691676Sjpk case S_IFDIR:
85701676Sjpk
85711676Sjpk /*
85721676Sjpk * append DIR_TYPE
85731676Sjpk */
85741676Sjpk (void) append_secattr(secinfo, len, 1,
85754774Sas145665 "\0", DIR_TYPE);
85761676Sjpk
85771676Sjpk /*
85781676Sjpk * Get and append attribute types LBL_TYPE.
85791676Sjpk * For directories, LBL_TYPE contains SL.
85801676Sjpk */
85811676Sjpk /* get binary sensitivity label */
85821676Sjpk if (getlabel(shortname, &b_slabel) != 0) {
85831676Sjpk (void) fprintf(stderr,
85841676Sjpk gettext("tar: can't get sensitvity label for "
85851676Sjpk " %s, getlabel() error: %s\n"),
85861676Sjpk shortname, strerror(errno));
85871676Sjpk } else {
85881676Sjpk /* get ascii SL */
85891676Sjpk if (bsltos(&b_slabel, &ascii,
85901676Sjpk 0, 0) <= 0) {
85911676Sjpk (void) fprintf(stderr,
85921676Sjpk gettext("tar: can't get ascii SL for"
85931676Sjpk " %s\n"), shortname);
85941676Sjpk } else {
85951676Sjpk /* append LBL_TYPE */
85961676Sjpk (void) append_secattr(secinfo, len,
85971676Sjpk strlen(ascii) + 1, ascii,
85981676Sjpk LBL_TYPE);
85991676Sjpk
86001676Sjpk /* free storage */
86011676Sjpk if (ascii != NULL) {
86021676Sjpk free(ascii);
86031676Sjpk ascii = (char *)0;
86041676Sjpk }
86051676Sjpk }
86061676Sjpk
86071676Sjpk }
86081676Sjpk break;
86091676Sjpk
86101676Sjpk case S_IFLNK:
86111676Sjpk case S_IFREG:
86121676Sjpk case S_IFIFO:
86131676Sjpk case S_IFCHR:
86141676Sjpk case S_IFBLK:
86151676Sjpk
86161676Sjpk /* get binary sensitivity label */
86171676Sjpk if (getlabel(shortname, &b_slabel) != 0) {
86181676Sjpk (void) fprintf(stderr,
86191676Sjpk gettext("tar: can't get sensitivty label for %s, "
86201676Sjpk "getlabel() error: %s\n"),
86211676Sjpk shortname, strerror(errno));
86221676Sjpk } else {
86231676Sjpk /* get ascii IL[SL] */
86241676Sjpk if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
86251676Sjpk (void) fprintf(stderr,
86261676Sjpk gettext("tar: can't translate sensitivity "
86271676Sjpk " label for %s\n"), shortname);
86281676Sjpk } else {
86291676Sjpk char *cmw_label;
86301676Sjpk size_t cmw_length;
86311676Sjpk
86321676Sjpk cmw_length = strlen("ADMIN_LOW [] ") +
86331676Sjpk strlen(ascii);
86341676Sjpk if ((cmw_label = malloc(cmw_length)) == NULL) {
86351676Sjpk (void) fprintf(stderr, gettext(
86361676Sjpk "Insufficient memory for label\n"));
86371676Sjpk exit(1);
86381676Sjpk }
86391676Sjpk /* append LBL_TYPE */
86401676Sjpk (void) snprintf(cmw_label, cmw_length,
86411676Sjpk "ADMIN_LOW [%s]", ascii);
86421676Sjpk (void) append_secattr(secinfo, len,
86431676Sjpk strlen(cmw_label) + 1, cmw_label,
86441676Sjpk LBL_TYPE);
86451676Sjpk
86461676Sjpk /* free storage */
86471676Sjpk if (ascii != NULL) {
86481676Sjpk free(cmw_label);
86491676Sjpk free(ascii);
86501676Sjpk ascii = (char *)0;
86511676Sjpk }
86521676Sjpk }
86531676Sjpk }
86541676Sjpk break;
86551676Sjpk
86561676Sjpk default:
86571676Sjpk break;
86581676Sjpk } /* end switch for LBL_TYPE */
86591676Sjpk
86601676Sjpk
86611676Sjpk /* DONE !! */
86621676Sjpk return;
86631676Sjpk
86641676Sjpk } /* end of append_ext_attr */
86651676Sjpk
86661676Sjpk
86671676Sjpk /*
86681676Sjpk * Name: extract_attr()
86691676Sjpk *
86701676Sjpk * Description:
86711676Sjpk * Process attributes from the ancillary file due to
86721676Sjpk * the T option.
86731676Sjpk *
86741676Sjpk * Call by doxtract() as part of the switch case structure.
86751676Sjpk * Making this a separate routine because the nesting are too
86761676Sjpk * deep in doxtract, thus, leaving very little space
86771676Sjpk * on each line for instructions.
86781676Sjpk *
86791676Sjpk * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
86801676Sjpk *
86811676Sjpk * For option 'T', following are possible attributes in
86821676Sjpk * a TS 8 ancillary file: (NOTE: No IL support)
86831676Sjpk *
86841676Sjpk * attribute type attribute process procedure
86851676Sjpk * ---------------- ---------------- -------------------------
86861676Sjpk * # LBL_TYPE = 'L' SL construct binary label
86871676Sjpk * # APRIV_TYPE = 'P' allowed priv construct privileges
86881676Sjpk * # FPRIV_TYPE = 'p' forced priv construct privileges
86891676Sjpk * # COMP_TYPE = 'C' path component construct real path
86901676Sjpk * # DIR_TYPE = 'D' directory flag note it is a directory
86911676Sjpk * $ UFSD_ACL = '1' ACL data construct ACL entries
86921676Sjpk * ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
86931676Sjpk * LK_COMP_TYPE = 'K' linked path comp construct linked real path
86941676Sjpk *
86951676Sjpk * note: # = attribute names common between TS 8 & TS 2.5 ancillary
86961676Sjpk * files.
86971676Sjpk * $ = ACL attribute is processed for the option 'p', it doesn't
86981676Sjpk * need option 'T'.
86991676Sjpk *
87001676Sjpk * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
87011676Sjpk *
87021676Sjpk */
87031676Sjpk static void
extract_attr(char ** file_ptr,struct sec_attr * attr)87041676Sjpk extract_attr(char **file_ptr, struct sec_attr *attr)
87051676Sjpk {
87061676Sjpk int reterr, err;
87071676Sjpk char *dummy_buf; /* for attribute extract */
87081676Sjpk
87091676Sjpk dummy_buf = attr->attr_info;
87101676Sjpk
87111676Sjpk switch (attr->attr_type) {
87121676Sjpk
87131676Sjpk case DIR_TYPE:
87141676Sjpk
87151676Sjpk dir_flag++;
87161676Sjpk break;
87171676Sjpk
87181676Sjpk case LBL_TYPE:
87191676Sjpk
87201676Sjpk /*
87211676Sjpk * LBL_TYPE is used to indicate SL for directory, and
87221676Sjpk * CMW label for other file types.
87231676Sjpk */
87241676Sjpk
87251676Sjpk if (!dir_flag) { /* not directory */
87261676Sjpk /* Skip over IL portion */
87271676Sjpk char *sl_ptr = strchr(dummy_buf, '[');
87281676Sjpk
87291676Sjpk if (sl_ptr == NULL)
87301676Sjpk err = 0;
87311676Sjpk else
87321676Sjpk err = stobsl(sl_ptr, &bs_label,
87331676Sjpk NEW_LABEL, &reterr);
87341676Sjpk } else { /* directory */
87351676Sjpk err = stobsl(dummy_buf, &bs_label,
87361676Sjpk NEW_LABEL, &reterr);
87371676Sjpk }
87381676Sjpk if (err == 0) {
87391676Sjpk (void) fprintf(stderr, gettext("tar: "
87401676Sjpk "can't convert %s to binary label\n"),
87411676Sjpk dummy_buf);
87421676Sjpk bslundef(&bs_label);
87431676Sjpk } else if (!blequal(&bs_label, &admin_low) &&
87441676Sjpk !blequal(&bs_label, &admin_high)) {
87451676Sjpk bslabel_t *from_label;
87461676Sjpk char *buf;
87471676Sjpk char tempbuf[MAXPATHLEN];
87481676Sjpk
87491676Sjpk if (*orig_namep != '/') {
87501676Sjpk /* got relative linked to path */
87511676Sjpk (void) getcwd(tempbuf, (sizeof (tempbuf)));
87521676Sjpk (void) strncat(tempbuf, "/", MAXPATHLEN);
87531676Sjpk } else
87541676Sjpk *tempbuf = '\0';
87551676Sjpk
87561676Sjpk buf = real_path;
87571676Sjpk (void) strncat(tempbuf, orig_namep, MAXPATHLEN);
87581676Sjpk from_label = getlabelbypath(tempbuf);
87591676Sjpk if (from_label != NULL) {
87601676Sjpk if (blequal(from_label, &admin_low)) {
87611676Sjpk if ((getpathbylabel(tempbuf, buf,
87621676Sjpk MAXPATHLEN, &bs_label) == NULL)) {
87631676Sjpk (void) fprintf(stderr,
87641676Sjpk gettext("tar: "
87651676Sjpk "can't get zone root path for "
87661676Sjpk "%s\n"), tempbuf);
87671676Sjpk } else
87681676Sjpk rpath_flag = 1;
87691676Sjpk }
87701676Sjpk free(from_label);
87711676Sjpk }
87721676Sjpk }
87731676Sjpk break;
87741676Sjpk
87751676Sjpk case COMP_TYPE:
87761676Sjpk
87771676Sjpk rebuild_comp_path(dummy_buf, file_ptr);
87781676Sjpk break;
87791676Sjpk
87801676Sjpk case LK_COMP_TYPE:
87811676Sjpk
87821676Sjpk if (rebuild_lk_comp_path(dummy_buf, file_ptr)
87831676Sjpk == 0) {
87841676Sjpk lk_rpath_flag = 1;
87851676Sjpk } else {
87861676Sjpk (void) fprintf(stderr, gettext("tar: warning: link's "
87871676Sjpk "target pathname might be invalid.\n"));
87881676Sjpk lk_rpath_flag = 0;
87891676Sjpk }
87901676Sjpk break;
87911676Sjpk case APRIV_TYPE:
87921676Sjpk ignored_aprivs++;
87931676Sjpk break;
87941676Sjpk case FPRIV_TYPE:
87951676Sjpk ignored_fprivs++;
87961676Sjpk break;
87971676Sjpk case ATTR_FLAG_TYPE:
87981676Sjpk ignored_fattrs++;
87991676Sjpk break;
88001676Sjpk
88011676Sjpk default:
88021676Sjpk
88031676Sjpk break;
88041676Sjpk }
88051676Sjpk
88061676Sjpk /* done */
88071676Sjpk return;
88081676Sjpk
88091676Sjpk } /* end extract_attr */
88101676Sjpk
88111676Sjpk
88121676Sjpk
88131676Sjpk /*
88141676Sjpk * Name: rebuild_comp_path()
88151676Sjpk *
88161676Sjpk * Description:
88171676Sjpk * Take the string of components passed down by the calling
88181676Sjpk * routine and parse the values and rebuild the path.
88191676Sjpk * This routine no longer needs to produce a new real_path
88201676Sjpk * string because it is produced when the 'L' LABEL_TYPE is
88211676Sjpk * interpreted. So the only thing done here is to distinguish
88221676Sjpk * between an SLD and an MLD entry. We only want one, so we
88231676Sjpk * ignore the MLD entry by setting the mld_flag.
88241676Sjpk *
88251676Sjpk * return value:
88261676Sjpk * none
88271676Sjpk */
88281676Sjpk static void
rebuild_comp_path(char * str,char ** namep)88291676Sjpk rebuild_comp_path(char *str, char **namep)
88301676Sjpk {
88311676Sjpk char *cp;
88321676Sjpk
88331676Sjpk while (*str != '\0') {
88341676Sjpk
88351676Sjpk switch (*str) {
88361676Sjpk
88371676Sjpk case MLD_TYPE:
88381676Sjpk
88391676Sjpk str++;
88401676Sjpk if ((cp = strstr(str, ";;")) != NULL) {
88411676Sjpk *cp = '\0';
88421676Sjpk str = cp + 2;
88431676Sjpk *cp = ';';
88441676Sjpk }
88451676Sjpk mld_flag = 1;
88461676Sjpk break;
88471676Sjpk
88481676Sjpk case SLD_TYPE:
88491676Sjpk
88501676Sjpk str++;
88511676Sjpk if ((cp = strstr(str, ";;")) != NULL) {
88521676Sjpk *cp = '\0';
88531676Sjpk str = cp + 2;
88541676Sjpk *cp = ';';
88551676Sjpk }
88561676Sjpk mld_flag = 0;
88571676Sjpk break;
88581676Sjpk
88591676Sjpk case PATH_TYPE:
88601676Sjpk
88611676Sjpk str++;
88621676Sjpk if ((cp = strstr(str, ";;")) != NULL) {
88631676Sjpk *cp = '\0';
88641676Sjpk str = cp + 2;
88651676Sjpk *cp = ';';
88661676Sjpk }
88671676Sjpk break;
88681676Sjpk }
88691676Sjpk }
88701676Sjpk if (rpath_flag)
88711676Sjpk *namep = real_path;
88721676Sjpk return;
88731676Sjpk
88741676Sjpk } /* end rebuild_comp_path() */
88751676Sjpk
88761676Sjpk /*
88771676Sjpk * Name: rebuild_lk_comp_path()
88781676Sjpk *
88791676Sjpk * Description:
88801676Sjpk * Take the string of components passed down by the calling
88811676Sjpk * routine and parse the values and rebuild the path.
88821676Sjpk *
88831676Sjpk * return value:
88841676Sjpk * 0 = succeeded
88851676Sjpk * -1 = failed
88861676Sjpk */
88871676Sjpk static int
rebuild_lk_comp_path(char * str,char ** namep)88881676Sjpk rebuild_lk_comp_path(char *str, char **namep)
88891676Sjpk {
88901676Sjpk char *cp;
88911676Sjpk int reterr;
88921676Sjpk bslabel_t bslabel;
88931676Sjpk char *buf;
88941676Sjpk char pbuf[MAXPATHLEN];
88951676Sjpk char *ptr1, *ptr2;
88961676Sjpk int plen;
88971676Sjpk int use_pbuf;
88981676Sjpk char tempbuf[MAXPATHLEN];
88991676Sjpk int mismatch;
89001676Sjpk bslabel_t *from_label;
89011676Sjpk char zonename[ZONENAME_MAX];
89021676Sjpk zoneid_t zoneid;
89031676Sjpk
89041676Sjpk /* init stuff */
89051676Sjpk use_pbuf = 0;
89061676Sjpk mismatch = 0;
89071676Sjpk
89081676Sjpk /*
89091676Sjpk * For linked to pathname (LK_COMP_TYPE):
89101676Sjpk * - If the linked to pathname is absolute (start with /), we
89111676Sjpk * will use it as is.
89121676Sjpk * - If it is a relative pathname then it is relative to 1 of 2
89131676Sjpk * directories. For a hardlink, it is relative to the current
89141676Sjpk * directory. For a symbolic link, it is relative to the
89151676Sjpk * directory the symbolic link is in. For the symbolic link
89161676Sjpk * case, set a flag to indicate we need to use the prefix of
89171676Sjpk * the restored file's pathname with the linked to pathname.
89181676Sjpk *
89191676Sjpk * NOTE: At this point, we have no way to determine if we have
89201676Sjpk * a hardlink or a symbolic link. We will compare the 1st
89211676Sjpk * component in the prefix portion of the restore file's
89221676Sjpk * pathname to the 1st component in the attribute data
89231676Sjpk * (the linked pathname). If they are the same, we will assume
89241676Sjpk * the link pathname to reconstruct is relative to the current
89251676Sjpk * directory. Otherwise, we will set a flag indicate we need
89261676Sjpk * to use a prefix with the reconstructed name. Need to compare
89271676Sjpk * both the adorned and unadorned version before deciding a
89281676Sjpk * mismatch.
89291676Sjpk */
89301676Sjpk
89311676Sjpk buf = lk_real_path;
89321676Sjpk if (*(str + 1) != '/') { /* got relative linked to path */
89331676Sjpk ptr1 = orig_namep;
89341676Sjpk ptr2 = strrchr(ptr1, '/');
89351676Sjpk plen = ptr2 - ptr1;
89361676Sjpk if (plen > 0) {
89371676Sjpk pbuf[0] = '\0';
89381676Sjpk plen++; /* include '/' */
89391676Sjpk (void) strncpy(pbuf, ptr1, plen);
89401676Sjpk *(pbuf + plen) = '\0';
89411676Sjpk ptr2 = strchr(pbuf, '/');
89421676Sjpk if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
89431676Sjpk mismatch = 1;
89441676Sjpk }
89451676Sjpk
89461676Sjpk if (mismatch == 1)
89471676Sjpk use_pbuf = 1;
89481676Sjpk }
89491676Sjpk
89501676Sjpk buf[0] = '\0';
89511676Sjpk
89521676Sjpk while (*str != '\0') {
89531676Sjpk
89541676Sjpk switch (*str) {
89551676Sjpk
89561676Sjpk case MLD_TYPE:
89571676Sjpk
89581676Sjpk str++;
89591676Sjpk if ((cp = strstr(str, ";;")) != NULL) {
89601676Sjpk *cp = '\0';
89611676Sjpk
89621676Sjpk /*
89631676Sjpk * Ignore attempts to backup over .MLD.
89641676Sjpk */
89651676Sjpk if (strcmp(str, "../") != 0)
89661676Sjpk (void) strncat(buf, str, MAXPATHLEN);
89671676Sjpk str = cp + 2;
89681676Sjpk *cp = ';';
89691676Sjpk }
89701676Sjpk break;
89711676Sjpk
89721676Sjpk case SLD_TYPE:
89731676Sjpk
89741676Sjpk str++;
89751676Sjpk if ((cp = strstr(str, ";;")) != NULL) {
89761676Sjpk *cp = '\0';
89771676Sjpk
89781676Sjpk /*
89791676Sjpk * Use the path name in the header if
89801676Sjpk * error occurs when processing the
89811676Sjpk * SLD type.
89821676Sjpk */
89831676Sjpk
89841676Sjpk if (!stobsl(str, &bslabel,
89851676Sjpk NO_CORRECTION, &reterr)) {
89861676Sjpk (void) fprintf(stderr, gettext(
89871676Sjpk "tar: can't translate to binary"
89881676Sjpk "SL for SLD, stobsl() error:"
89891676Sjpk " %s\n"), strerror(errno));
89901676Sjpk return (-1);
89911676Sjpk }
89921676Sjpk
89931676Sjpk str = cp + 2;
89941676Sjpk *cp = ';';
89951676Sjpk
89961676Sjpk if (use_pbuf == 1) {
89971676Sjpk if (*pbuf != '/') {
89981676Sjpk /* relative linked to path */
89991676Sjpk
90001676Sjpk (void) getcwd(tempbuf,
90011676Sjpk (sizeof (tempbuf)));
90021676Sjpk (void) strncat(tempbuf, "/",
90031676Sjpk MAXPATHLEN);
90041676Sjpk (void) strncat(tempbuf, pbuf,
90051676Sjpk MAXPATHLEN);
90061676Sjpk }
90071676Sjpk else
90081676Sjpk (void) strcpy(tempbuf, pbuf);
90091676Sjpk
90101676Sjpk } else if (*buf != '/') {
90111676Sjpk /* got relative linked to path */
90121676Sjpk
90131676Sjpk (void) getcwd(tempbuf,
90141676Sjpk (sizeof (tempbuf)));
90151676Sjpk (void) strncat(tempbuf, "/",
90161676Sjpk MAXPATHLEN);
90171676Sjpk } else
90181676Sjpk *tempbuf = '\0';
90191676Sjpk
90201676Sjpk (void) strncat(tempbuf, buf, MAXPATHLEN);
90211676Sjpk *buf = '\0';
90221676Sjpk
90231676Sjpk if (blequal(&bslabel, &admin_high)) {
90241676Sjpk bslabel = admin_low;
90251676Sjpk }
90261676Sjpk
90271676Sjpk
90281676Sjpk /*
90291676Sjpk * Check for cross-zone symbolic links
90301676Sjpk */
90311676Sjpk from_label = getlabelbypath(real_path);
90321676Sjpk if (rpath_flag && (from_label != NULL) &&
90331676Sjpk !blequal(&bslabel, from_label)) {
90341676Sjpk if ((zoneid =
90351676Sjpk getzoneidbylabel(&bslabel)) == -1) {
90361676Sjpk (void) fprintf(stderr,
90371676Sjpk gettext("tar: can't get "
90384774Sas145665 "zone ID for %s\n"),
90391676Sjpk tempbuf);
90401676Sjpk return (-1);
90411676Sjpk }
90421676Sjpk if (zone_getattr(zoneid, ZONE_ATTR_NAME,
90431676Sjpk &zonename, ZONENAME_MAX) == -1) {
90441676Sjpk /* Badly configured zone info */
90451676Sjpk (void) fprintf(stderr,
90461676Sjpk gettext("tar: can't get "
90474774Sas145665 "zonename for %s\n"),
90481676Sjpk tempbuf);
90491676Sjpk return (-1);
90501676Sjpk }
90511676Sjpk (void) strncpy(buf, AUTO_ZONE,
90521676Sjpk MAXPATHLEN);
90531676Sjpk (void) strncat(buf, "/",
90541676Sjpk MAXPATHLEN);
90551676Sjpk (void) strncat(buf, zonename,
90561676Sjpk MAXPATHLEN);
90571676Sjpk }
90581676Sjpk if (from_label != NULL)
90591676Sjpk free(from_label);
90601676Sjpk (void) strncat(buf, tempbuf, MAXPATHLEN);
90611676Sjpk break;
90621676Sjpk }
90631676Sjpk mld_flag = 0;
90641676Sjpk break;
90651676Sjpk
90661676Sjpk case PATH_TYPE:
90671676Sjpk
90681676Sjpk str++;
90691676Sjpk if ((cp = strstr(str, ";;")) != NULL) {
90701676Sjpk *cp = '\0';
90711676Sjpk (void) strncat(buf, str, MAXPATHLEN);
90721676Sjpk str = cp + 2;
90731676Sjpk *cp = ';';
90741676Sjpk }
90751676Sjpk break;
90761676Sjpk
90771676Sjpk default:
90781676Sjpk
90791676Sjpk (void) fprintf(stderr, gettext(
90804774Sas145665 "tar: error rebuilding path %s\n"),
90814774Sas145665 *namep);
90821676Sjpk *buf = '\0';
90831676Sjpk str++;
90841676Sjpk return (-1);
90851676Sjpk }
90861676Sjpk }
90871676Sjpk
90881676Sjpk /*
90891676Sjpk * Done for LK_COMP_TYPE
90901676Sjpk */
90911676Sjpk
90921676Sjpk return (0); /* component path is rebuilt successfully */
90931676Sjpk
90941676Sjpk } /* end rebuild_lk_comp_path() */
90951676Sjpk
90961676Sjpk /*
90971676Sjpk * Name: check_ext_attr()
90981676Sjpk *
90991676Sjpk * Description:
91001676Sjpk * Check the extended attributes for a file being extracted.
91011676Sjpk * The attributes being checked here are CMW labels.
91021676Sjpk * ACLs are not set here because they are set by the
91031676Sjpk * pflag in doxtract().
91041676Sjpk *
91051676Sjpk * If the label doesn't match, return 0
91061676Sjpk * else return 1
91071676Sjpk */
91081676Sjpk static int
check_ext_attr(char * filename)91091676Sjpk check_ext_attr(char *filename)
91101676Sjpk {
91111676Sjpk bslabel_t currentlabel; /* label from zone */
91121676Sjpk
91131676Sjpk if (bltype(&bs_label, SUN_SL_UN)) {
91141676Sjpk /* No label check possible */
91151676Sjpk return (0);
91161676Sjpk }
91171676Sjpk if (getlabel(filename, ¤tlabel) != 0) {
91181676Sjpk (void) fprintf(stderr,
91191676Sjpk gettext("tar: can't get label for "
91204774Sas145665 " %s, getlabel() error: %s\n"),
91214774Sas145665 filename, strerror(errno));
91221676Sjpk return (0);
91231676Sjpk } else if ((blequal(¤tlabel, &bs_label)) == 0) {
91241676Sjpk char *src_label = NULL; /* ascii label */
91251676Sjpk
91261676Sjpk /* get current src SL */
91271676Sjpk if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
91281676Sjpk (void) fprintf(stderr,
91291676Sjpk gettext("tar: can't interpret requested label for"
91304774Sas145665 " %s\n"), filename);
91311676Sjpk } else {
91321676Sjpk (void) fprintf(stderr,
91331676Sjpk gettext("tar: can't apply label %s to %s\n"),
91344774Sas145665 src_label, filename);
91351676Sjpk free(src_label);
91361676Sjpk }
91371676Sjpk (void) fprintf(stderr,
91381676Sjpk gettext("tar: %s not restored\n"), filename);
91391676Sjpk return (0);
91401676Sjpk }
91411676Sjpk return (1);
91421676Sjpk
91431676Sjpk } /* end check_ext_attr */
914411990Srich.burridge@sun.com
914511990Srich.burridge@sun.com /* Compressing a tar file using compression method provided in 'opt' */
914611990Srich.burridge@sun.com
914711990Srich.burridge@sun.com static void
compress_back()914811990Srich.burridge@sun.com compress_back()
914911990Srich.burridge@sun.com {
915011990Srich.burridge@sun.com pid_t pid;
915111990Srich.burridge@sun.com int status;
915211990Srich.burridge@sun.com int wret;
915311990Srich.burridge@sun.com struct stat statb;
915411990Srich.burridge@sun.com
915511990Srich.burridge@sun.com if (vflag) {
915611990Srich.burridge@sun.com (void) fprintf(vfile,
915711990Srich.burridge@sun.com gettext("Compressing '%s' with '%s'...\n"),
915811990Srich.burridge@sun.com usefile, compress_opt);
915911990Srich.burridge@sun.com }
916011990Srich.burridge@sun.com if ((pid = fork()) == 0) {
916111990Srich.burridge@sun.com (void) execlp(compress_opt, compress_opt,
916211990Srich.burridge@sun.com usefile, NULL);
916311990Srich.burridge@sun.com } else if (pid == -1) {
916411990Srich.burridge@sun.com vperror(1, "%s", gettext("Could not fork"));
916511990Srich.burridge@sun.com }
916611990Srich.burridge@sun.com wait_pid(pid);
916711990Srich.burridge@sun.com if (suffix == 0) {
916811990Srich.burridge@sun.com (void) rename(tfname, usefile);
916911990Srich.burridge@sun.com }
917011990Srich.burridge@sun.com }
917111990Srich.burridge@sun.com
917211990Srich.burridge@sun.com /* The magic numbers from /etc/magic */
917311990Srich.burridge@sun.com
917411990Srich.burridge@sun.com #define GZIP_MAGIC "\037\213"
917511990Srich.burridge@sun.com #define BZIP_MAGIC "BZh"
917611990Srich.burridge@sun.com #define COMP_MAGIC "\037\235"
917711990Srich.burridge@sun.com
917811990Srich.burridge@sun.com void
check_compression()917911990Srich.burridge@sun.com check_compression()
918011990Srich.burridge@sun.com {
918111990Srich.burridge@sun.com char magic[2];
918211990Srich.burridge@sun.com char buf[16];
918311990Srich.burridge@sun.com FILE *fp;
918411990Srich.burridge@sun.com
918511990Srich.burridge@sun.com if ((fp = fopen(usefile, "r")) != NULL) {
918611990Srich.burridge@sun.com (void) fread(buf, sizeof (char), 6, fp);
918711990Srich.burridge@sun.com magic[0] = buf[0];
918811990Srich.burridge@sun.com magic[1] = buf[1];
918911990Srich.burridge@sun.com (void) fclose(fp);
919011990Srich.burridge@sun.com }
919111990Srich.burridge@sun.com
919211990Srich.burridge@sun.com if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
919311990Srich.burridge@sun.com if (xflag || tflag) {
919411990Srich.burridge@sun.com compress_opt = compress_malloc(strlen(GZCAT) + 1);
919511990Srich.burridge@sun.com (void) strcpy(compress_opt, GZCAT);
919611990Srich.burridge@sun.com } else if (uflag || rflag) {
919711990Srich.burridge@sun.com compress_opt = compress_malloc(strlen(GZIP) + 1);
919811990Srich.burridge@sun.com (void) strcpy(compress_opt, GZIP);
919911990Srich.burridge@sun.com }
920011990Srich.burridge@sun.com } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
920111990Srich.burridge@sun.com if (xflag || tflag) {
920211990Srich.burridge@sun.com compress_opt = compress_malloc(strlen(BZCAT) + 1);
920311990Srich.burridge@sun.com (void) strcpy(compress_opt, BZCAT);
920411990Srich.burridge@sun.com } else if (uflag || rflag) {
920511990Srich.burridge@sun.com compress_opt = compress_malloc(strlen(BZIP) + 1);
920611990Srich.burridge@sun.com (void) strcpy(compress_opt, BZIP);
920711990Srich.burridge@sun.com }
920811990Srich.burridge@sun.com } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
920911990Srich.burridge@sun.com if (xflag || tflag) {
921011990Srich.burridge@sun.com compress_opt = compress_malloc(strlen(ZCAT) + 1);
921111990Srich.burridge@sun.com (void) strcpy(compress_opt, ZCAT);
921211990Srich.burridge@sun.com } else if (uflag || rflag) {
921311990Srich.burridge@sun.com compress_opt = compress_malloc(strlen(COMPRESS) + 1);
921411990Srich.burridge@sun.com (void) strcpy(compress_opt, COMPRESS);
921511990Srich.burridge@sun.com }
921611990Srich.burridge@sun.com }
921711990Srich.burridge@sun.com }
921811990Srich.burridge@sun.com
921911990Srich.burridge@sun.com char *
add_suffix()922011990Srich.burridge@sun.com add_suffix()
922111990Srich.burridge@sun.com {
922211990Srich.burridge@sun.com (void) strcpy(tfname, usefile);
922311990Srich.burridge@sun.com if (strcmp(compress_opt, GZIP) == 0) {
922411990Srich.burridge@sun.com if ((suffix = gz_suffix()) == NULL) {
922511990Srich.burridge@sun.com strlcat(tfname, gsuffix[0], sizeof (tfname));
922611990Srich.burridge@sun.com return (gsuffix[0]);
922711990Srich.burridge@sun.com }
922811990Srich.burridge@sun.com } else if (strcmp(compress_opt, COMPRESS) == 0) {
922911990Srich.burridge@sun.com if ((suffix = gz_suffix()) == NULL) {
923011990Srich.burridge@sun.com strlcat(tfname, gsuffix[6], sizeof (tfname));
923111990Srich.burridge@sun.com return (gsuffix[6]);
923211990Srich.burridge@sun.com }
923311990Srich.burridge@sun.com } else if (strcmp(compress_opt, BZIP) == 0) {
923411990Srich.burridge@sun.com if ((suffix = bz_suffix()) == NULL) {
923511990Srich.burridge@sun.com strlcat(tfname, bsuffix[0], sizeof (tfname));
923611990Srich.burridge@sun.com return (bsuffix[0]);
923711990Srich.burridge@sun.com }
923811990Srich.burridge@sun.com }
923911990Srich.burridge@sun.com return (NULL);
924011990Srich.burridge@sun.com }
924111990Srich.burridge@sun.com
924211990Srich.burridge@sun.com /* Decompressing a tar file using compression method from the file type */
924311990Srich.burridge@sun.com void
decompress_file(void)924411990Srich.burridge@sun.com decompress_file(void)
924511990Srich.burridge@sun.com {
924611990Srich.burridge@sun.com pid_t pid;
924711990Srich.burridge@sun.com int status;
924811990Srich.burridge@sun.com char cmdstr[PATH_MAX];
924911990Srich.burridge@sun.com char fname[PATH_MAX];
925011990Srich.burridge@sun.com char *added_suffix;
925111990Srich.burridge@sun.com
925211990Srich.burridge@sun.com
925311990Srich.burridge@sun.com added_suffix = add_suffix();
925411990Srich.burridge@sun.com if (added_suffix != NULL) {
925511990Srich.burridge@sun.com (void) rename(usefile, tfname);
925611990Srich.burridge@sun.com }
925711990Srich.burridge@sun.com if ((pid = fork()) == 0) {
925811990Srich.burridge@sun.com if (vflag) {
925911990Srich.burridge@sun.com (void) fprintf(vfile,
926011990Srich.burridge@sun.com gettext("Decompressing '%s' with "
926111990Srich.burridge@sun.com "'%s'...\n"), usefile, compress_opt);
926211990Srich.burridge@sun.com }
926311990Srich.burridge@sun.com (void) execlp(compress_opt, compress_opt, "-df",
926411990Srich.burridge@sun.com tfname, NULL);
926512350Srich.burridge@sun.com vperror(1, gettext("Could not exec %s"), compress_opt);
926611990Srich.burridge@sun.com } else if (pid == -1) {
926712305Srich.burridge@sun.com vperror(1, gettext("Could not fork"));
926811990Srich.burridge@sun.com }
926911990Srich.burridge@sun.com wait_pid(pid);
927011990Srich.burridge@sun.com if (suffix != NULL) {
927111990Srich.burridge@sun.com /* restore the file name - original file was without suffix */
927211990Srich.burridge@sun.com *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
927311990Srich.burridge@sun.com }
927411990Srich.burridge@sun.com }
927511990Srich.burridge@sun.com
927611990Srich.burridge@sun.com /* Set the archive for writing and then compress the archive */
927711990Srich.burridge@sun.com pid_t
compress_file(void)927811990Srich.burridge@sun.com compress_file(void)
927911990Srich.burridge@sun.com {
928011990Srich.burridge@sun.com int fd[2];
928111990Srich.burridge@sun.com pid_t pid;
928211990Srich.burridge@sun.com
928311990Srich.burridge@sun.com if (vflag) {
928411990Srich.burridge@sun.com (void) fprintf(vfile, gettext("Compressing '%s' with "
928511990Srich.burridge@sun.com "'%s'...\n"), usefile, compress_opt);
928611990Srich.burridge@sun.com }
928711990Srich.burridge@sun.com
928811990Srich.burridge@sun.com if (pipe(fd) < 0) {
928911990Srich.burridge@sun.com vperror(1, gettext("Could not create pipe"));
929011990Srich.burridge@sun.com }
929111990Srich.burridge@sun.com if (pid = fork() > 0) {
929211990Srich.burridge@sun.com mt = fd[1];
929311990Srich.burridge@sun.com (void) close(fd[0]);
929411990Srich.burridge@sun.com return (pid);
929511990Srich.burridge@sun.com }
929611990Srich.burridge@sun.com /* child */
929711990Srich.burridge@sun.com (void) dup2(fd[0], STDIN_FILENO);
929811990Srich.burridge@sun.com (void) close(fd[1]);
929911990Srich.burridge@sun.com (void) dup2(mt, STDOUT_FILENO);
930011990Srich.burridge@sun.com (void) execlp(compress_opt, compress_opt, NULL);
930112350Srich.burridge@sun.com vperror(1, gettext("Could not exec %s"), compress_opt);
930211990Srich.burridge@sun.com return (0); /*NOTREACHED*/
930311990Srich.burridge@sun.com }
930411990Srich.burridge@sun.com
930511990Srich.burridge@sun.com pid_t
uncompress_file(void)930611990Srich.burridge@sun.com uncompress_file(void)
930711990Srich.burridge@sun.com {
930811990Srich.burridge@sun.com int fd[2];
930911990Srich.burridge@sun.com pid_t pid;
931011990Srich.burridge@sun.com
931111990Srich.burridge@sun.com if (vflag) {
931211990Srich.burridge@sun.com (void) fprintf(vfile, gettext("Decompressing '%s' with "
931311990Srich.burridge@sun.com "'%s'...\n"), usefile, compress_opt);
931411990Srich.burridge@sun.com }
931511990Srich.burridge@sun.com
931611990Srich.burridge@sun.com if (pipe(fd) < 0) {
931711990Srich.burridge@sun.com vperror(1, gettext("Could not create pipe"));
931811990Srich.burridge@sun.com }
931911990Srich.burridge@sun.com if (pid = fork() > 0) {
932011990Srich.burridge@sun.com mt = fd[0];
932111990Srich.burridge@sun.com (void) close(fd[1]);
932211990Srich.burridge@sun.com return (pid);
932311990Srich.burridge@sun.com }
932411990Srich.burridge@sun.com /* child */
932511990Srich.burridge@sun.com (void) dup2(fd[1], STDOUT_FILENO);
932611990Srich.burridge@sun.com (void) close(fd[0]);
932711990Srich.burridge@sun.com (void) dup2(mt, STDIN_FILENO);
932811990Srich.burridge@sun.com (void) execlp(compress_opt, compress_opt, NULL);
932912350Srich.burridge@sun.com vperror(1, gettext("Could not exec %s"), compress_opt);
933011990Srich.burridge@sun.com return (0); /*NOTREACHED*/
933111990Srich.burridge@sun.com }
933211990Srich.burridge@sun.com
933311990Srich.burridge@sun.com /* Checking valid 'bzip2' suffix */
933411990Srich.burridge@sun.com char *
bz_suffix()933511990Srich.burridge@sun.com bz_suffix()
933611990Srich.burridge@sun.com {
933711990Srich.burridge@sun.com int i;
933811990Srich.burridge@sun.com int slen;
933911990Srich.burridge@sun.com int nlen = strlen(usefile);
934011990Srich.burridge@sun.com
934111990Srich.burridge@sun.com for (i = 0; i < BS; i++) {
934211990Srich.burridge@sun.com slen = strlen(bsuffix[i]);
934311990Srich.burridge@sun.com if (nlen < slen)
934411990Srich.burridge@sun.com return (NULL);
934511990Srich.burridge@sun.com if (strcmp(usefile + nlen - slen, bsuffix[i]) == 0)
934611990Srich.burridge@sun.com return (bsuffix[i]);
934711990Srich.burridge@sun.com }
934811990Srich.burridge@sun.com return (NULL);
934911990Srich.burridge@sun.com }
935011990Srich.burridge@sun.com
935111990Srich.burridge@sun.com /* Checking valid 'gzip' suffix */
935211990Srich.burridge@sun.com char *
gz_suffix()935311990Srich.burridge@sun.com gz_suffix()
935411990Srich.burridge@sun.com {
935511990Srich.burridge@sun.com int i;
935611990Srich.burridge@sun.com int slen;
935711990Srich.burridge@sun.com int nlen = strlen(usefile);
935811990Srich.burridge@sun.com
935911990Srich.burridge@sun.com for (i = 0; i < GS; i++) {
936011990Srich.burridge@sun.com slen = strlen(gsuffix[i]);
936111990Srich.burridge@sun.com if (nlen < slen)
936211990Srich.burridge@sun.com return (NULL);
936311990Srich.burridge@sun.com if (strcmp(usefile + nlen - slen, gsuffix[i]) == 0)
936411990Srich.burridge@sun.com return (gsuffix[i]);
936511990Srich.burridge@sun.com }
936611990Srich.burridge@sun.com return (NULL);
936711990Srich.burridge@sun.com }
936811990Srich.burridge@sun.com
936911990Srich.burridge@sun.com void *
compress_malloc(size_t size)937011990Srich.burridge@sun.com compress_malloc(size_t size)
937111990Srich.burridge@sun.com {
937211990Srich.burridge@sun.com void *opt;
937311990Srich.burridge@sun.com
937411990Srich.burridge@sun.com if ((opt = malloc(size)) == NULL) {
937511990Srich.burridge@sun.com vperror(1, "%s",
937611990Srich.burridge@sun.com gettext("Could not allocate compress buffer\n"));
937711990Srich.burridge@sun.com }
937811990Srich.burridge@sun.com return (opt);
937911990Srich.burridge@sun.com }
938011990Srich.burridge@sun.com
938111990Srich.burridge@sun.com void
wait_pid(pid_t pid)938211990Srich.burridge@sun.com wait_pid(pid_t pid)
938311990Srich.burridge@sun.com {
938411990Srich.burridge@sun.com int status;
938511990Srich.burridge@sun.com
938611990Srich.burridge@sun.com while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
938711990Srich.burridge@sun.com ;
938811990Srich.burridge@sun.com }
9389