1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 31*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /* 34*7c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 35*7c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 36*7c478bd9Sstevel@tonic-gate */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #include <unistd.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 46*7c478bd9Sstevel@tonic-gate #include <dirent.h> 47*7c478bd9Sstevel@tonic-gate #include <errno.h> 48*7c478bd9Sstevel@tonic-gate #include <stdio.h> 49*7c478bd9Sstevel@tonic-gate #include <signal.h> 50*7c478bd9Sstevel@tonic-gate #include <ctype.h> 51*7c478bd9Sstevel@tonic-gate #include <locale.h> 52*7c478bd9Sstevel@tonic-gate #include <nl_types.h> 53*7c478bd9Sstevel@tonic-gate #include <langinfo.h> 54*7c478bd9Sstevel@tonic-gate #include <pwd.h> 55*7c478bd9Sstevel@tonic-gate #include <grp.h> 56*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 57*7c478bd9Sstevel@tonic-gate #include <string.h> 58*7c478bd9Sstevel@tonic-gate #include <malloc.h> 59*7c478bd9Sstevel@tonic-gate #include <time.h> 60*7c478bd9Sstevel@tonic-gate #include <utime.h> 61*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 62*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 63*7c478bd9Sstevel@tonic-gate #include <widec.h> 64*7c478bd9Sstevel@tonic-gate #include <sys/mtio.h> 65*7c478bd9Sstevel@tonic-gate #include <libintl.h> 66*7c478bd9Sstevel@tonic-gate #include <sys/acl.h> 67*7c478bd9Sstevel@tonic-gate #include <strings.h> 68*7c478bd9Sstevel@tonic-gate #include <deflt.h> 69*7c478bd9Sstevel@tonic-gate #include <limits.h> 70*7c478bd9Sstevel@tonic-gate #include <iconv.h> 71*7c478bd9Sstevel@tonic-gate #include <assert.h> 72*7c478bd9Sstevel@tonic-gate #if defined(__SunOS_5_6) || defined(__SunOS_5_7) 73*7c478bd9Sstevel@tonic-gate extern int defcntl(); 74*7c478bd9Sstevel@tonic-gate #endif 75*7c478bd9Sstevel@tonic-gate #include <archives.h> 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * Source compatibility 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate * These constants come from archives.h and sys/fcntl.h 83*7c478bd9Sstevel@tonic-gate * and were introduced by the extended attributes project 84*7c478bd9Sstevel@tonic-gate * in Solaris 9. 85*7c478bd9Sstevel@tonic-gate */ 86*7c478bd9Sstevel@tonic-gate #if !defined(O_XATTR) 87*7c478bd9Sstevel@tonic-gate #define AT_SYMLINK_NOFOLLOW 0x1000 88*7c478bd9Sstevel@tonic-gate #define AT_REMOVEDIR 0x1 89*7c478bd9Sstevel@tonic-gate #define AT_FDCWD 0xffd19553 90*7c478bd9Sstevel@tonic-gate #define _XATTR_HDRTYPE 'E' 91*7c478bd9Sstevel@tonic-gate static int attropen(); 92*7c478bd9Sstevel@tonic-gate static int fstatat(); 93*7c478bd9Sstevel@tonic-gate static int renameat(); 94*7c478bd9Sstevel@tonic-gate static int unlinkat(); 95*7c478bd9Sstevel@tonic-gate static int openat(); 96*7c478bd9Sstevel@tonic-gate static int fchownat(); 97*7c478bd9Sstevel@tonic-gate static int futimesat(); 98*7c478bd9Sstevel@tonic-gate #endif 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* 101*7c478bd9Sstevel@tonic-gate * Compiling with -D_XPG4_2 gets this but produces other problems, so 102*7c478bd9Sstevel@tonic-gate * instead of including sys/time.h and compiling with -D_XPG4_2, I'm 103*7c478bd9Sstevel@tonic-gate * explicitly doing the declaration here. 104*7c478bd9Sstevel@tonic-gate */ 105*7c478bd9Sstevel@tonic-gate int utimes(const char *path, const struct timeval timeval_ptr[]); 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate #ifndef MINSIZE 108*7c478bd9Sstevel@tonic-gate #define MINSIZE 250 109*7c478bd9Sstevel@tonic-gate #endif 110*7c478bd9Sstevel@tonic-gate #define DEF_FILE "/etc/default/tar" 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate #define min(a, b) ((a) < (b) ? (a) : (b)) 113*7c478bd9Sstevel@tonic-gate #define max(a, b) ((a) > (b) ? (a) : (b)) 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate /* -DDEBUG ONLY for debugging */ 116*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 117*7c478bd9Sstevel@tonic-gate #undef DEBUG 118*7c478bd9Sstevel@tonic-gate #define DEBUG(a, b, c)\ 119*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c) 120*7c478bd9Sstevel@tonic-gate #endif 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate #define TBLOCK 512 /* tape block size--should be universal */ 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate #ifdef BSIZE 125*7c478bd9Sstevel@tonic-gate #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */ 126*7c478bd9Sstevel@tonic-gate #else /* BSIZE */ 127*7c478bd9Sstevel@tonic-gate #define SYS_BLOCK 512 /* default if no BSIZE in param.h */ 128*7c478bd9Sstevel@tonic-gate #endif /* BSIZE */ 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate #define NBLOCK 20 131*7c478bd9Sstevel@tonic-gate #define NAMSIZ 100 132*7c478bd9Sstevel@tonic-gate #define PRESIZ 155 133*7c478bd9Sstevel@tonic-gate #define MAXNAM 256 134*7c478bd9Sstevel@tonic-gate #define MODEMASK 0777777 /* file creation mode mask */ 135*7c478bd9Sstevel@tonic-gate #define POSIXMODES 07777 /* mask for POSIX mode bits */ 136*7c478bd9Sstevel@tonic-gate #define MAXEXT 9 /* reasonable max # extents for a file */ 137*7c478bd9Sstevel@tonic-gate #define EXTMIN 50 /* min blks left on floppy to split a file */ 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* max value dblock.dbuf.efsize can store */ 140*7c478bd9Sstevel@tonic-gate #define TAR_EFSIZE_MAX 0777777777 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate * Symbols which specify the values at which the use of the 'E' function 144*7c478bd9Sstevel@tonic-gate * modifier is required to properly store a file. 145*7c478bd9Sstevel@tonic-gate * 146*7c478bd9Sstevel@tonic-gate * TAR_OFFSET_MAX - the largest file size we can archive 147*7c478bd9Sstevel@tonic-gate * OCTAL7CHAR - the limit for ustar gid, uid, dev 148*7c478bd9Sstevel@tonic-gate */ 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate #ifdef XHDR_DEBUG 151*7c478bd9Sstevel@tonic-gate /* tiny values which force the creation of extended header entries */ 152*7c478bd9Sstevel@tonic-gate #define TAR_OFFSET_MAX 9 153*7c478bd9Sstevel@tonic-gate #define OCTAL7CHAR 2 154*7c478bd9Sstevel@tonic-gate #else 155*7c478bd9Sstevel@tonic-gate /* normal values */ 156*7c478bd9Sstevel@tonic-gate #define TAR_OFFSET_MAX 077777777777 157*7c478bd9Sstevel@tonic-gate #define OCTAL7CHAR 07777777 158*7c478bd9Sstevel@tonic-gate #endif 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK) 161*7c478bd9Sstevel@tonic-gate #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */ 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate #define MAXLEV (PATH_MAX / 2) 164*7c478bd9Sstevel@tonic-gate #define LEV0 1 165*7c478bd9Sstevel@tonic-gate #define SYMLINK_LEV0 0 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate #define TRUE 1 168*7c478bd9Sstevel@tonic-gate #define FALSE 0 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate #define XATTR_FILE 1 171*7c478bd9Sstevel@tonic-gate #define NORMAL_FILE 0 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate #define PUT_AS_LINK 1 174*7c478bd9Sstevel@tonic-gate #define PUT_NOTAS_LINK 0 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate #if _FILE_OFFSET_BITS == 64 177*7c478bd9Sstevel@tonic-gate #define FMT_off_t "lld" 178*7c478bd9Sstevel@tonic-gate #define FMT_off_t_o "llo" 179*7c478bd9Sstevel@tonic-gate #define FMT_blkcnt_t "lld" 180*7c478bd9Sstevel@tonic-gate #else 181*7c478bd9Sstevel@tonic-gate #define FMT_off_t "ld" 182*7c478bd9Sstevel@tonic-gate #define FMT_off_t_o "lo" 183*7c478bd9Sstevel@tonic-gate #define FMT_blkcnt_t "ld" 184*7c478bd9Sstevel@tonic-gate #endif 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* ACL support */ 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate static 189*7c478bd9Sstevel@tonic-gate struct sec_attr { 190*7c478bd9Sstevel@tonic-gate char attr_type; 191*7c478bd9Sstevel@tonic-gate char attr_len[7]; 192*7c478bd9Sstevel@tonic-gate char attr_info[1]; 193*7c478bd9Sstevel@tonic-gate } *attr; 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate #define ACL_HDR 'A' 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /* 198*7c478bd9Sstevel@tonic-gate * 199*7c478bd9Sstevel@tonic-gate * Tar has been changed to support extended attributes. 200*7c478bd9Sstevel@tonic-gate * 201*7c478bd9Sstevel@tonic-gate * As part of this change tar now uses the new *at() syscalls 202*7c478bd9Sstevel@tonic-gate * such as openat, fchownat(), unlinkat()... 203*7c478bd9Sstevel@tonic-gate * 204*7c478bd9Sstevel@tonic-gate * This was done so that attributes can be handled with as few code changes 205*7c478bd9Sstevel@tonic-gate * as possible. 206*7c478bd9Sstevel@tonic-gate * 207*7c478bd9Sstevel@tonic-gate * What this means is that tar now opens the directory that a file or directory 208*7c478bd9Sstevel@tonic-gate * resides in and then performs *at() functions to manipulate the entry. 209*7c478bd9Sstevel@tonic-gate * 210*7c478bd9Sstevel@tonic-gate * For example a new file is now created like this: 211*7c478bd9Sstevel@tonic-gate * 212*7c478bd9Sstevel@tonic-gate * dfd = open(<some dir path>) 213*7c478bd9Sstevel@tonic-gate * fd = openat(dfd, <name>,....); 214*7c478bd9Sstevel@tonic-gate * 215*7c478bd9Sstevel@tonic-gate * or in the case of an extended attribute 216*7c478bd9Sstevel@tonic-gate * 217*7c478bd9Sstevel@tonic-gate * dfd = attropen(<pathname>, ".", ....) 218*7c478bd9Sstevel@tonic-gate * 219*7c478bd9Sstevel@tonic-gate * Once we have a directory file descriptor all of the *at() functions can 220*7c478bd9Sstevel@tonic-gate * be applied to it. 221*7c478bd9Sstevel@tonic-gate * 222*7c478bd9Sstevel@tonic-gate * unlinkat(dfd, <component name>,...) 223*7c478bd9Sstevel@tonic-gate * fchownat(dfd, <component name>,..) 224*7c478bd9Sstevel@tonic-gate * 225*7c478bd9Sstevel@tonic-gate * This works for both normal namespace files and extended attribute file 226*7c478bd9Sstevel@tonic-gate * 227*7c478bd9Sstevel@tonic-gate */ 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate /* 230*7c478bd9Sstevel@tonic-gate * 231*7c478bd9Sstevel@tonic-gate * Extended attribute Format 232*7c478bd9Sstevel@tonic-gate * 233*7c478bd9Sstevel@tonic-gate * Extended attributes are stored in two pieces. 234*7c478bd9Sstevel@tonic-gate * 1. An attribute header which has information about 235*7c478bd9Sstevel@tonic-gate * what file the attribute is for and what the attribute 236*7c478bd9Sstevel@tonic-gate * is named. 237*7c478bd9Sstevel@tonic-gate * 2. The attribute record itself. Stored as a normal file type 238*7c478bd9Sstevel@tonic-gate * of entry. 239*7c478bd9Sstevel@tonic-gate * Both the header and attribute record have special modes/typeflags 240*7c478bd9Sstevel@tonic-gate * associated with them. 241*7c478bd9Sstevel@tonic-gate * 242*7c478bd9Sstevel@tonic-gate * The names of the header in the archive look like: 243*7c478bd9Sstevel@tonic-gate * /dev/null/attr.hdr 244*7c478bd9Sstevel@tonic-gate * 245*7c478bd9Sstevel@tonic-gate * The name of the attribute looks like: 246*7c478bd9Sstevel@tonic-gate * /dev/null/attr 247*7c478bd9Sstevel@tonic-gate * 248*7c478bd9Sstevel@tonic-gate * This is done so that an archiver that doesn't understand these formats 249*7c478bd9Sstevel@tonic-gate * can just dispose of the attribute records. 250*7c478bd9Sstevel@tonic-gate * 251*7c478bd9Sstevel@tonic-gate * The format is composed of a fixed size header followed 252*7c478bd9Sstevel@tonic-gate * by a variable sized xattr_buf. If the attribute is a hard link 253*7c478bd9Sstevel@tonic-gate * to another attribute then another xattr_buf section is included 254*7c478bd9Sstevel@tonic-gate * for the link. 255*7c478bd9Sstevel@tonic-gate * 256*7c478bd9Sstevel@tonic-gate * The xattr_buf is used to define the necessary "pathing" steps 257*7c478bd9Sstevel@tonic-gate * to get to the extended attribute. This is necessary to support 258*7c478bd9Sstevel@tonic-gate * a fully recursive attribute model where an attribute may itself 259*7c478bd9Sstevel@tonic-gate * have an attribute. 260*7c478bd9Sstevel@tonic-gate * 261*7c478bd9Sstevel@tonic-gate * The basic layout looks like this. 262*7c478bd9Sstevel@tonic-gate * 263*7c478bd9Sstevel@tonic-gate * -------------------------------- 264*7c478bd9Sstevel@tonic-gate * | | 265*7c478bd9Sstevel@tonic-gate * | xattr_hdr | 266*7c478bd9Sstevel@tonic-gate * | | 267*7c478bd9Sstevel@tonic-gate * -------------------------------- 268*7c478bd9Sstevel@tonic-gate * -------------------------------- 269*7c478bd9Sstevel@tonic-gate * | | 270*7c478bd9Sstevel@tonic-gate * | xattr_buf | 271*7c478bd9Sstevel@tonic-gate * | | 272*7c478bd9Sstevel@tonic-gate * -------------------------------- 273*7c478bd9Sstevel@tonic-gate * -------------------------------- 274*7c478bd9Sstevel@tonic-gate * | | 275*7c478bd9Sstevel@tonic-gate * | (optional link info) | 276*7c478bd9Sstevel@tonic-gate * | | 277*7c478bd9Sstevel@tonic-gate * -------------------------------- 278*7c478bd9Sstevel@tonic-gate * -------------------------------- 279*7c478bd9Sstevel@tonic-gate * | | 280*7c478bd9Sstevel@tonic-gate * | attribute itself | 281*7c478bd9Sstevel@tonic-gate * | stored as normal tar | 282*7c478bd9Sstevel@tonic-gate * | or cpio data with | 283*7c478bd9Sstevel@tonic-gate * | special mode or | 284*7c478bd9Sstevel@tonic-gate * | typeflag | 285*7c478bd9Sstevel@tonic-gate * | | 286*7c478bd9Sstevel@tonic-gate * -------------------------------- 287*7c478bd9Sstevel@tonic-gate * 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * xattrhead is a pointer to the xattr_hdr 292*7c478bd9Sstevel@tonic-gate * 293*7c478bd9Sstevel@tonic-gate * xattrp is a pointer to the xattr_buf structure 294*7c478bd9Sstevel@tonic-gate * which contains the "pathing" steps to get to attributes 295*7c478bd9Sstevel@tonic-gate * 296*7c478bd9Sstevel@tonic-gate * xattr_linkp is a pointer to another xattr_buf structure that is 297*7c478bd9Sstevel@tonic-gate * only used when an attribute is actually linked to another attribute 298*7c478bd9Sstevel@tonic-gate * 299*7c478bd9Sstevel@tonic-gate */ 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate static struct xattr_hdr *xattrhead; 302*7c478bd9Sstevel@tonic-gate static struct xattr_buf *xattrp; 303*7c478bd9Sstevel@tonic-gate static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */ 304*7c478bd9Sstevel@tonic-gate static char *xattraname; /* attribute name */ 305*7c478bd9Sstevel@tonic-gate static char *xattr_linkaname; /* attribute attribute is linked to */ 306*7c478bd9Sstevel@tonic-gate static char Hiddendir; /* are we processing hidden xattr dir */ 307*7c478bd9Sstevel@tonic-gate static char xattrbadhead; 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate /* Was statically allocated tbuf[NBLOCK] */ 310*7c478bd9Sstevel@tonic-gate static 311*7c478bd9Sstevel@tonic-gate union hblock { 312*7c478bd9Sstevel@tonic-gate char dummy[TBLOCK]; 313*7c478bd9Sstevel@tonic-gate struct header { 314*7c478bd9Sstevel@tonic-gate char name[NAMSIZ]; /* If non-null prefix, path is */ 315*7c478bd9Sstevel@tonic-gate /* <prefix>/<name>; otherwise */ 316*7c478bd9Sstevel@tonic-gate /* <name> */ 317*7c478bd9Sstevel@tonic-gate char mode[8]; 318*7c478bd9Sstevel@tonic-gate char uid[8]; 319*7c478bd9Sstevel@tonic-gate char gid[8]; 320*7c478bd9Sstevel@tonic-gate char size[12]; /* size of this extent if file split */ 321*7c478bd9Sstevel@tonic-gate char mtime[12]; 322*7c478bd9Sstevel@tonic-gate char chksum[8]; 323*7c478bd9Sstevel@tonic-gate char typeflag; 324*7c478bd9Sstevel@tonic-gate char linkname[NAMSIZ]; 325*7c478bd9Sstevel@tonic-gate char magic[6]; 326*7c478bd9Sstevel@tonic-gate char version[2]; 327*7c478bd9Sstevel@tonic-gate char uname[32]; 328*7c478bd9Sstevel@tonic-gate char gname[32]; 329*7c478bd9Sstevel@tonic-gate char devmajor[8]; 330*7c478bd9Sstevel@tonic-gate char devminor[8]; 331*7c478bd9Sstevel@tonic-gate char prefix[PRESIZ]; /* Together with "name", the path of */ 332*7c478bd9Sstevel@tonic-gate /* the file: <prefix>/<name> */ 333*7c478bd9Sstevel@tonic-gate char extno; /* extent #, null if not split */ 334*7c478bd9Sstevel@tonic-gate char extotal; /* total extents */ 335*7c478bd9Sstevel@tonic-gate char efsize[10]; /* size of entire file */ 336*7c478bd9Sstevel@tonic-gate } dbuf; 337*7c478bd9Sstevel@tonic-gate } dblock, *tbuf, xhdr_buf; 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate static 340*7c478bd9Sstevel@tonic-gate struct xtar_hdr { 341*7c478bd9Sstevel@tonic-gate uid_t x_uid, /* Uid of file */ 342*7c478bd9Sstevel@tonic-gate x_gid; /* Gid of file */ 343*7c478bd9Sstevel@tonic-gate major_t x_devmajor; /* Device major node */ 344*7c478bd9Sstevel@tonic-gate minor_t x_devminor; /* Device minor node */ 345*7c478bd9Sstevel@tonic-gate off_t x_filesz; /* Length of file */ 346*7c478bd9Sstevel@tonic-gate char *x_uname, /* Pointer to name of user */ 347*7c478bd9Sstevel@tonic-gate *x_gname, /* Pointer to gid of user */ 348*7c478bd9Sstevel@tonic-gate *x_linkpath, /* Path for a hard/symbolic link */ 349*7c478bd9Sstevel@tonic-gate *x_path; /* Path of file */ 350*7c478bd9Sstevel@tonic-gate timestruc_t x_mtime; /* Seconds and nanoseconds */ 351*7c478bd9Sstevel@tonic-gate } Xtarhdr; 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate static 354*7c478bd9Sstevel@tonic-gate struct gen_hdr { 355*7c478bd9Sstevel@tonic-gate ulong_t g_mode; /* Mode of file */ 356*7c478bd9Sstevel@tonic-gate uid_t g_uid, /* Uid of file */ 357*7c478bd9Sstevel@tonic-gate g_gid; /* Gid of file */ 358*7c478bd9Sstevel@tonic-gate off_t g_filesz; /* Length of file */ 359*7c478bd9Sstevel@tonic-gate time_t g_mtime; /* Modification time */ 360*7c478bd9Sstevel@tonic-gate uint_t g_cksum; /* Checksum of file */ 361*7c478bd9Sstevel@tonic-gate ulong_t g_devmajor, /* File system of file */ 362*7c478bd9Sstevel@tonic-gate g_devminor; /* Major/minor of special files */ 363*7c478bd9Sstevel@tonic-gate } Gen; 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate static 366*7c478bd9Sstevel@tonic-gate struct linkbuf { 367*7c478bd9Sstevel@tonic-gate ino_t inum; 368*7c478bd9Sstevel@tonic-gate dev_t devnum; 369*7c478bd9Sstevel@tonic-gate int count; 370*7c478bd9Sstevel@tonic-gate char pathname[MAXNAM+1]; /* added 1 for last NULL */ 371*7c478bd9Sstevel@tonic-gate char attrname[MAXNAM+1]; 372*7c478bd9Sstevel@tonic-gate struct linkbuf *nextp; 373*7c478bd9Sstevel@tonic-gate } *ihead; 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate /* see comments before build_table() */ 376*7c478bd9Sstevel@tonic-gate #define TABLE_SIZE 512 377*7c478bd9Sstevel@tonic-gate struct file_list { 378*7c478bd9Sstevel@tonic-gate char *name; /* Name of file to {in,ex}clude */ 379*7c478bd9Sstevel@tonic-gate struct file_list *next; /* Linked list */ 380*7c478bd9Sstevel@tonic-gate }; 381*7c478bd9Sstevel@tonic-gate static struct file_list *exclude_tbl[TABLE_SIZE], 382*7c478bd9Sstevel@tonic-gate *include_tbl[TABLE_SIZE]; 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate static int append_secattr(char **, int *, int, aclent_t *, char); 385*7c478bd9Sstevel@tonic-gate static void write_ancillary(union hblock *, char *, int, char); 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate static void add_file_to_table(struct file_list *table[], char *str); 388*7c478bd9Sstevel@tonic-gate static void assert_string(char *s, char *msg); 389*7c478bd9Sstevel@tonic-gate static int istape(int fd, int type); 390*7c478bd9Sstevel@tonic-gate static void backtape(void); 391*7c478bd9Sstevel@tonic-gate static void build_table(struct file_list *table[], char *file); 392*7c478bd9Sstevel@tonic-gate static void check_prefix(char **namep, char **dirp, char **compp); 393*7c478bd9Sstevel@tonic-gate static void closevol(void); 394*7c478bd9Sstevel@tonic-gate static void copy(void *dst, void *src); 395*7c478bd9Sstevel@tonic-gate static int convtoreg(off_t); 396*7c478bd9Sstevel@tonic-gate static void delete_target(int fd, char *namep); 397*7c478bd9Sstevel@tonic-gate static void doDirTimes(char *name, timestruc_t modTime); 398*7c478bd9Sstevel@tonic-gate static void done(int n); 399*7c478bd9Sstevel@tonic-gate static void dorep(char *argv[]); 400*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 401*7c478bd9Sstevel@tonic-gate static void dotable(char *argv[], int cnt); 402*7c478bd9Sstevel@tonic-gate static void doxtract(char *argv[], int cnt); 403*7c478bd9Sstevel@tonic-gate #else 404*7c478bd9Sstevel@tonic-gate static void dotable(char *argv[]); 405*7c478bd9Sstevel@tonic-gate static void doxtract(char *argv[]); 406*7c478bd9Sstevel@tonic-gate #endif 407*7c478bd9Sstevel@tonic-gate static void fatal(char *format, ...); 408*7c478bd9Sstevel@tonic-gate static void vperror(int exit_status, char *fmt, ...); 409*7c478bd9Sstevel@tonic-gate static void flushtape(void); 410*7c478bd9Sstevel@tonic-gate static void getdir(void); 411*7c478bd9Sstevel@tonic-gate static void *getmem(size_t); 412*7c478bd9Sstevel@tonic-gate static void longt(struct stat *st, char aclchar); 413*7c478bd9Sstevel@tonic-gate static int makeDir(char *name); 414*7c478bd9Sstevel@tonic-gate static void mterr(char *operation, int i, int exitcode); 415*7c478bd9Sstevel@tonic-gate static void newvol(void); 416*7c478bd9Sstevel@tonic-gate static void passtape(void); 417*7c478bd9Sstevel@tonic-gate static void putempty(blkcnt_t n); 418*7c478bd9Sstevel@tonic-gate static int putfile(char *longname, char *shortname, char *parent, 419*7c478bd9Sstevel@tonic-gate int filetype, int lev, int symlink_lev); 420*7c478bd9Sstevel@tonic-gate static void readtape(char *buffer); 421*7c478bd9Sstevel@tonic-gate static void seekdisk(blkcnt_t blocks); 422*7c478bd9Sstevel@tonic-gate static void setPathTimes(int dirfd, char *path, timestruc_t modTime); 423*7c478bd9Sstevel@tonic-gate static void splitfile(char *longname, int ifd, char *name, 424*7c478bd9Sstevel@tonic-gate char *prefix, int filetype); 425*7c478bd9Sstevel@tonic-gate static void tomodes(struct stat *sp); 426*7c478bd9Sstevel@tonic-gate static void usage(void); 427*7c478bd9Sstevel@tonic-gate static void xblocks(off_t bytes, int ofile); 428*7c478bd9Sstevel@tonic-gate static void xsfile(int ofd); 429*7c478bd9Sstevel@tonic-gate static void resugname(int dirfd, char *name, int symflag); 430*7c478bd9Sstevel@tonic-gate static int bcheck(char *bstr); 431*7c478bd9Sstevel@tonic-gate static int checkdir(char *name); 432*7c478bd9Sstevel@tonic-gate static int checksum(union hblock *dblockp); 433*7c478bd9Sstevel@tonic-gate #ifdef EUC 434*7c478bd9Sstevel@tonic-gate static int checksum_signed(union hblock *dblockp); 435*7c478bd9Sstevel@tonic-gate #endif /* EUC */ 436*7c478bd9Sstevel@tonic-gate static int checkupdate(char *arg); 437*7c478bd9Sstevel@tonic-gate static int checkw(char c, char *name); 438*7c478bd9Sstevel@tonic-gate static int cmp(char *b, char *s, int n); 439*7c478bd9Sstevel@tonic-gate static int defset(char *arch); 440*7c478bd9Sstevel@tonic-gate static int endtape(void); 441*7c478bd9Sstevel@tonic-gate static int is_in_table(struct file_list *table[], char *str); 442*7c478bd9Sstevel@tonic-gate static int notsame(void); 443*7c478bd9Sstevel@tonic-gate static int is_prefix(char *s1, char *s2); 444*7c478bd9Sstevel@tonic-gate static int response(void); 445*7c478bd9Sstevel@tonic-gate static int build_dblock(const char *, const char *, const char, 446*7c478bd9Sstevel@tonic-gate const int filetype, const struct stat *, const dev_t, const char *); 447*7c478bd9Sstevel@tonic-gate static wchar_t yesnoresponse(void); 448*7c478bd9Sstevel@tonic-gate static unsigned int hash(char *str); 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 451*7c478bd9Sstevel@tonic-gate static void initarg(char *argv[], char *file); 452*7c478bd9Sstevel@tonic-gate static char *nextarg(); 453*7c478bd9Sstevel@tonic-gate #endif 454*7c478bd9Sstevel@tonic-gate static blkcnt_t kcheck(char *kstr); 455*7c478bd9Sstevel@tonic-gate static off_t bsrch(char *s, int n, off_t l, off_t h); 456*7c478bd9Sstevel@tonic-gate static void onintr(int sig); 457*7c478bd9Sstevel@tonic-gate static void onquit(int sig); 458*7c478bd9Sstevel@tonic-gate static void onhup(int sig); 459*7c478bd9Sstevel@tonic-gate static uid_t getuidbyname(char *); 460*7c478bd9Sstevel@tonic-gate static gid_t getgidbyname(char *); 461*7c478bd9Sstevel@tonic-gate static char *getname(gid_t); 462*7c478bd9Sstevel@tonic-gate static char *getgroup(gid_t); 463*7c478bd9Sstevel@tonic-gate static int checkf(char *name, int mode, int howmuch); 464*7c478bd9Sstevel@tonic-gate static int writetbuf(char *buffer, int n); 465*7c478bd9Sstevel@tonic-gate static int wantit(char *argv[], char **namep, char **dirp, char **comp); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate static int get_xdata(void); 468*7c478bd9Sstevel@tonic-gate static void gen_num(const char *keyword, const u_longlong_t number); 469*7c478bd9Sstevel@tonic-gate static void gen_date(const char *keyword, const timestruc_t time_value); 470*7c478bd9Sstevel@tonic-gate static void gen_string(const char *keyword, const char *value); 471*7c478bd9Sstevel@tonic-gate static void get_xtime(char *value, timestruc_t *xtime); 472*7c478bd9Sstevel@tonic-gate static int chk_path_build(char *name, char *longname, char *linkname, 473*7c478bd9Sstevel@tonic-gate char *prefix, char type, int filetype); 474*7c478bd9Sstevel@tonic-gate static int gen_utf8_names(const char *filename); 475*7c478bd9Sstevel@tonic-gate static int utf8_local(char *option, char **Xhdr_ptrptr, char *target, 476*7c478bd9Sstevel@tonic-gate const char *src, int max_val); 477*7c478bd9Sstevel@tonic-gate static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src, 478*7c478bd9Sstevel@tonic-gate iconv_t iconv_cd, int xhdrflg, int max_val); 479*7c478bd9Sstevel@tonic-gate static int c_utf8(char *target, const char *source); 480*7c478bd9Sstevel@tonic-gate static int getstat(int dirfd, char *longname, char *shortname); 481*7c478bd9Sstevel@tonic-gate static void xattrs_put(char *, char *, char *); 482*7c478bd9Sstevel@tonic-gate static void prepare_xattr(char **, char *, char *, 483*7c478bd9Sstevel@tonic-gate char, struct linkbuf *, int *); 484*7c478bd9Sstevel@tonic-gate static int put_link(char *name, char *longname, char *component, char *prefix, 485*7c478bd9Sstevel@tonic-gate int filetype, char typeflag); 486*7c478bd9Sstevel@tonic-gate static int put_extra_attributes(char *longname, char *shortname, 487*7c478bd9Sstevel@tonic-gate char *prefix, int filetype, char typeflag); 488*7c478bd9Sstevel@tonic-gate static int put_xattr_hdr(char *longname, char *shortname, char *prefix, 489*7c478bd9Sstevel@tonic-gate int typeflag, int filetype, struct linkbuf *lp); 490*7c478bd9Sstevel@tonic-gate static int read_xattr_hdr(); 491*7c478bd9Sstevel@tonic-gate static void get_parent(char *path, char *dir); 492*7c478bd9Sstevel@tonic-gate static char *get_component(char *path); 493*7c478bd9Sstevel@tonic-gate static int retry_attrdir_open(char *name); 494*7c478bd9Sstevel@tonic-gate static char *skipslashes(char *string, char *start); 495*7c478bd9Sstevel@tonic-gate static void chop_endslashes(char *path); 496*7c478bd9Sstevel@tonic-gate static struct stat stbuf; 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate static int checkflag = 0; 499*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 500*7c478bd9Sstevel@tonic-gate static int Fileflag; 501*7c478bd9Sstevel@tonic-gate char *sysv3_env; 502*7c478bd9Sstevel@tonic-gate #endif 503*7c478bd9Sstevel@tonic-gate static int Xflag, Fflag, iflag, hflag, Bflag, Iflag; 504*7c478bd9Sstevel@tonic-gate static int rflag, xflag, vflag, tflag, mt, cflag, mflag, pflag; 505*7c478bd9Sstevel@tonic-gate static int uflag; 506*7c478bd9Sstevel@tonic-gate static int eflag, errflag, qflag; 507*7c478bd9Sstevel@tonic-gate static int oflag; 508*7c478bd9Sstevel@tonic-gate static int bflag, kflag, Aflag; 509*7c478bd9Sstevel@tonic-gate static int Pflag; /* POSIX conformant archive */ 510*7c478bd9Sstevel@tonic-gate static int Eflag; /* Allow files greater than 8GB */ 511*7c478bd9Sstevel@tonic-gate static int atflag; /* traverse extended attributes */ 512*7c478bd9Sstevel@tonic-gate static int Dflag; /* Data change flag */ 513*7c478bd9Sstevel@tonic-gate static int term, chksum, wflag, 514*7c478bd9Sstevel@tonic-gate first = TRUE, defaults_used = FALSE, linkerrok; 515*7c478bd9Sstevel@tonic-gate static blkcnt_t recno; 516*7c478bd9Sstevel@tonic-gate static int freemem = 1; 517*7c478bd9Sstevel@tonic-gate static int nblock = NBLOCK; 518*7c478bd9Sstevel@tonic-gate static int Errflg = 0; 519*7c478bd9Sstevel@tonic-gate static int exitflag = 0; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate static dev_t mt_dev; /* device containing output file */ 522*7c478bd9Sstevel@tonic-gate static ino_t mt_ino; /* inode number of output file */ 523*7c478bd9Sstevel@tonic-gate static int mt_devtype; /* dev type of archive, from stat structure */ 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate static int update = 1; /* for `open' call */ 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate static off_t low; 528*7c478bd9Sstevel@tonic-gate static off_t high; 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate static FILE *tfile; 531*7c478bd9Sstevel@tonic-gate static FILE *vfile = stdout; 532*7c478bd9Sstevel@tonic-gate static char tname[] = "/tmp/tarXXXXXX"; 533*7c478bd9Sstevel@tonic-gate static char archive[] = "archive0="; 534*7c478bd9Sstevel@tonic-gate static char *Xfile; 535*7c478bd9Sstevel@tonic-gate static char *usefile; 536*7c478bd9Sstevel@tonic-gate static char *Filefile; 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate static int mulvol; /* multi-volume option selected */ 539*7c478bd9Sstevel@tonic-gate static blkcnt_t blocklim; /* number of blocks to accept per volume */ 540*7c478bd9Sstevel@tonic-gate static blkcnt_t tapepos; /* current block number to be written */ 541*7c478bd9Sstevel@tonic-gate static int NotTape; /* true if tape is a disk */ 542*7c478bd9Sstevel@tonic-gate static int dumping; /* true if writing a tape or other archive */ 543*7c478bd9Sstevel@tonic-gate static int extno; /* number of extent: starts at 1 */ 544*7c478bd9Sstevel@tonic-gate static int extotal; /* total extents in this file */ 545*7c478bd9Sstevel@tonic-gate static off_t extsize; /* size of current extent during extraction */ 546*7c478bd9Sstevel@tonic-gate static ushort_t Oumask = 0; /* old umask value */ 547*7c478bd9Sstevel@tonic-gate static int is_posix; /* true if archive we're reading is POSIX-conformant */ 548*7c478bd9Sstevel@tonic-gate static const char *magic_type = "ustar"; 549*7c478bd9Sstevel@tonic-gate static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */ 550*7c478bd9Sstevel@tonic-gate static char *xrec_ptr; 551*7c478bd9Sstevel@tonic-gate static off_t xrec_offset = 0; 552*7c478bd9Sstevel@tonic-gate static int Xhdrflag; 553*7c478bd9Sstevel@tonic-gate static int charset_type = 0; 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate static u_longlong_t xhdr_flgs; /* Bits set determine which items */ 556*7c478bd9Sstevel@tonic-gate /* need to be in extended header. */ 557*7c478bd9Sstevel@tonic-gate #define _X_DEVMAJOR 0x1 558*7c478bd9Sstevel@tonic-gate #define _X_DEVMINOR 0x2 559*7c478bd9Sstevel@tonic-gate #define _X_GID 0x4 560*7c478bd9Sstevel@tonic-gate #define _X_GNAME 0x8 561*7c478bd9Sstevel@tonic-gate #define _X_LINKPATH 0x10 562*7c478bd9Sstevel@tonic-gate #define _X_PATH 0x20 563*7c478bd9Sstevel@tonic-gate #define _X_SIZE 0x40 564*7c478bd9Sstevel@tonic-gate #define _X_UID 0x80 565*7c478bd9Sstevel@tonic-gate #define _X_UNAME 0x100 566*7c478bd9Sstevel@tonic-gate #define _X_ATIME 0x200 567*7c478bd9Sstevel@tonic-gate #define _X_CTIME 0x400 568*7c478bd9Sstevel@tonic-gate #define _X_MTIME 0x800 569*7c478bd9Sstevel@tonic-gate #define _X_LAST 0x40000000 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4) 572*7c478bd9Sstevel@tonic-gate #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4) 573*7c478bd9Sstevel@tonic-gate #define LONG_MAX_DIGITS (10 * sizeof (long) / 4) 574*7c478bd9Sstevel@tonic-gate #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4) 575*7c478bd9Sstevel@tonic-gate /* 576*7c478bd9Sstevel@tonic-gate * UTF_8 encoding requires more space than the current codeset equivalent. 577*7c478bd9Sstevel@tonic-gate * Currently a factor of 2-3 would suffice, but it is possible for a factor 578*7c478bd9Sstevel@tonic-gate * of 6 to be needed in the future, so for saftey, we use that here. 579*7c478bd9Sstevel@tonic-gate */ 580*7c478bd9Sstevel@tonic-gate #define UTF_8_FACTOR 6 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate static u_longlong_t xhdr_count = 0; 583*7c478bd9Sstevel@tonic-gate static char xhdr_dirname[PRESIZ + 1]; 584*7c478bd9Sstevel@tonic-gate static char pidchars[PID_MAX_DIGITS + 1]; 585*7c478bd9Sstevel@tonic-gate static char *tchar = ""; /* null linkpath */ 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate static char local_path[UTF_8_FACTOR * PATH_MAX + 1]; 588*7c478bd9Sstevel@tonic-gate static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1]; 589*7c478bd9Sstevel@tonic-gate static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1]; 590*7c478bd9Sstevel@tonic-gate static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1]; 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate /* 593*7c478bd9Sstevel@tonic-gate * The following mechanism is provided to allow us to debug tar in complicated 594*7c478bd9Sstevel@tonic-gate * situations, like when it is part of a pipe. The idea is that you compile 595*7c478bd9Sstevel@tonic-gate * with -DWAITAROUND defined, and then add the 'z' function modifier to the 596*7c478bd9Sstevel@tonic-gate * target tar invocation, eg. "tar czf tarfile file". If stderr is available, 597*7c478bd9Sstevel@tonic-gate * it will tell you to which pid to attach the debugger; otherwise, use ps to 598*7c478bd9Sstevel@tonic-gate * find it. Attach to the process from the debugger, and, *PRESTO*, you are 599*7c478bd9Sstevel@tonic-gate * there! 600*7c478bd9Sstevel@tonic-gate * 601*7c478bd9Sstevel@tonic-gate * Simply assign "waitaround = 0" once you attach to the process, and then 602*7c478bd9Sstevel@tonic-gate * proceed from there as usual. 603*7c478bd9Sstevel@tonic-gate */ 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate #ifdef WAITAROUND 606*7c478bd9Sstevel@tonic-gate int waitaround = 0; /* wait for rendezvous with the debugger */ 607*7c478bd9Sstevel@tonic-gate #endif 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate int 611*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 612*7c478bd9Sstevel@tonic-gate { 613*7c478bd9Sstevel@tonic-gate char *cp; 614*7c478bd9Sstevel@tonic-gate char *tmpdirp; 615*7c478bd9Sstevel@tonic-gate pid_t thispid; 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 618*7c478bd9Sstevel@tonic-gate int tbl_cnt = 0; 619*7c478bd9Sstevel@tonic-gate sysv3_env = getenv("SYSV3"); 620*7c478bd9Sstevel@tonic-gate #endif 621*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 622*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 623*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 624*7c478bd9Sstevel@tonic-gate #endif 625*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 626*7c478bd9Sstevel@tonic-gate if (argc < 2) 627*7c478bd9Sstevel@tonic-gate usage(); 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate tfile = NULL; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate /* 632*7c478bd9Sstevel@tonic-gate * For XPG4 compatibility, we must be able to accept the "--" 633*7c478bd9Sstevel@tonic-gate * argument normally recognized by getopt; it is used to delimit 634*7c478bd9Sstevel@tonic-gate * the end opt the options section, and so can only appear in 635*7c478bd9Sstevel@tonic-gate * the position of the first argument. We simply skip it. 636*7c478bd9Sstevel@tonic-gate */ 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate if (strcmp(argv[1], "--") == 0) { 639*7c478bd9Sstevel@tonic-gate argv++; 640*7c478bd9Sstevel@tonic-gate argc--; 641*7c478bd9Sstevel@tonic-gate if (argc < 3) 642*7c478bd9Sstevel@tonic-gate usage(); 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate argv[argc] = NULL; 646*7c478bd9Sstevel@tonic-gate argv++; 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate /* 649*7c478bd9Sstevel@tonic-gate * Set up default values. 650*7c478bd9Sstevel@tonic-gate * Search the operand string looking for the first digit or an 'f'. 651*7c478bd9Sstevel@tonic-gate * If you find a digit, use the 'archive#' entry in DEF_FILE. 652*7c478bd9Sstevel@tonic-gate * If 'f' is given, bypass looking in DEF_FILE altogether. 653*7c478bd9Sstevel@tonic-gate * If no digit or 'f' is given, still look in DEF_FILE but use '0'. 654*7c478bd9Sstevel@tonic-gate */ 655*7c478bd9Sstevel@tonic-gate if ((usefile = getenv("TAPE")) == (char *)NULL) { 656*7c478bd9Sstevel@tonic-gate for (cp = *argv; *cp; ++cp) 657*7c478bd9Sstevel@tonic-gate if (isdigit(*cp) || *cp == 'f') 658*7c478bd9Sstevel@tonic-gate break; 659*7c478bd9Sstevel@tonic-gate if (*cp != 'f') { 660*7c478bd9Sstevel@tonic-gate archive[7] = (*cp)? *cp: '0'; 661*7c478bd9Sstevel@tonic-gate if (!(defaults_used = defset(archive))) { 662*7c478bd9Sstevel@tonic-gate usefile = NULL; 663*7c478bd9Sstevel@tonic-gate nblock = 1; 664*7c478bd9Sstevel@tonic-gate blocklim = 0; 665*7c478bd9Sstevel@tonic-gate NotTape = 0; 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate } 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate for (cp = *argv++; *cp; cp++) 671*7c478bd9Sstevel@tonic-gate switch (*cp) { 672*7c478bd9Sstevel@tonic-gate #ifdef WAITAROUND 673*7c478bd9Sstevel@tonic-gate case 'z': 674*7c478bd9Sstevel@tonic-gate /* rendezvous with the debugger */ 675*7c478bd9Sstevel@tonic-gate waitaround = 1; 676*7c478bd9Sstevel@tonic-gate break; 677*7c478bd9Sstevel@tonic-gate #endif 678*7c478bd9Sstevel@tonic-gate case 'f': 679*7c478bd9Sstevel@tonic-gate assert_string(*argv, gettext( 680*7c478bd9Sstevel@tonic-gate "tar: tarfile must be specified with 'f' " 681*7c478bd9Sstevel@tonic-gate "function modifier\n")); 682*7c478bd9Sstevel@tonic-gate usefile = *argv++; 683*7c478bd9Sstevel@tonic-gate break; 684*7c478bd9Sstevel@tonic-gate case 'F': 685*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 686*7c478bd9Sstevel@tonic-gate if (sysv3_env) { 687*7c478bd9Sstevel@tonic-gate assert_string(*argv, gettext( 688*7c478bd9Sstevel@tonic-gate "tar: 'F' requires a file name\n")); 689*7c478bd9Sstevel@tonic-gate Filefile = *argv++; 690*7c478bd9Sstevel@tonic-gate Fileflag++; 691*7c478bd9Sstevel@tonic-gate } else 692*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 693*7c478bd9Sstevel@tonic-gate Fflag++; 694*7c478bd9Sstevel@tonic-gate break; 695*7c478bd9Sstevel@tonic-gate case 'c': 696*7c478bd9Sstevel@tonic-gate cflag++; 697*7c478bd9Sstevel@tonic-gate rflag++; 698*7c478bd9Sstevel@tonic-gate update = 1; 699*7c478bd9Sstevel@tonic-gate break; 700*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 701*7c478bd9Sstevel@tonic-gate case '@': 702*7c478bd9Sstevel@tonic-gate atflag++; 703*7c478bd9Sstevel@tonic-gate break; 704*7c478bd9Sstevel@tonic-gate #endif 705*7c478bd9Sstevel@tonic-gate case 'u': 706*7c478bd9Sstevel@tonic-gate uflag++; /* moved code after signals caught */ 707*7c478bd9Sstevel@tonic-gate rflag++; 708*7c478bd9Sstevel@tonic-gate update = 2; 709*7c478bd9Sstevel@tonic-gate break; 710*7c478bd9Sstevel@tonic-gate case 'r': 711*7c478bd9Sstevel@tonic-gate rflag++; 712*7c478bd9Sstevel@tonic-gate update = 2; 713*7c478bd9Sstevel@tonic-gate break; 714*7c478bd9Sstevel@tonic-gate case 'v': 715*7c478bd9Sstevel@tonic-gate vflag++; 716*7c478bd9Sstevel@tonic-gate break; 717*7c478bd9Sstevel@tonic-gate case 'w': 718*7c478bd9Sstevel@tonic-gate wflag++; 719*7c478bd9Sstevel@tonic-gate break; 720*7c478bd9Sstevel@tonic-gate case 'x': 721*7c478bd9Sstevel@tonic-gate xflag++; 722*7c478bd9Sstevel@tonic-gate break; 723*7c478bd9Sstevel@tonic-gate case 'X': 724*7c478bd9Sstevel@tonic-gate assert_string(*argv, gettext( 725*7c478bd9Sstevel@tonic-gate "tar: exclude file must be specified with 'X' " 726*7c478bd9Sstevel@tonic-gate "function modifier\n")); 727*7c478bd9Sstevel@tonic-gate Xflag = 1; 728*7c478bd9Sstevel@tonic-gate Xfile = *argv++; 729*7c478bd9Sstevel@tonic-gate build_table(exclude_tbl, Xfile); 730*7c478bd9Sstevel@tonic-gate break; 731*7c478bd9Sstevel@tonic-gate case 't': 732*7c478bd9Sstevel@tonic-gate tflag++; 733*7c478bd9Sstevel@tonic-gate break; 734*7c478bd9Sstevel@tonic-gate case 'm': 735*7c478bd9Sstevel@tonic-gate mflag++; 736*7c478bd9Sstevel@tonic-gate break; 737*7c478bd9Sstevel@tonic-gate case 'p': 738*7c478bd9Sstevel@tonic-gate pflag++; 739*7c478bd9Sstevel@tonic-gate break; 740*7c478bd9Sstevel@tonic-gate case 'D': 741*7c478bd9Sstevel@tonic-gate Dflag++; 742*7c478bd9Sstevel@tonic-gate break; 743*7c478bd9Sstevel@tonic-gate case '-': 744*7c478bd9Sstevel@tonic-gate /* ignore this silently */ 745*7c478bd9Sstevel@tonic-gate break; 746*7c478bd9Sstevel@tonic-gate case '0': /* numeric entries used only for defaults */ 747*7c478bd9Sstevel@tonic-gate case '1': 748*7c478bd9Sstevel@tonic-gate case '2': 749*7c478bd9Sstevel@tonic-gate case '3': 750*7c478bd9Sstevel@tonic-gate case '4': 751*7c478bd9Sstevel@tonic-gate case '5': 752*7c478bd9Sstevel@tonic-gate case '6': 753*7c478bd9Sstevel@tonic-gate case '7': 754*7c478bd9Sstevel@tonic-gate break; 755*7c478bd9Sstevel@tonic-gate case 'b': 756*7c478bd9Sstevel@tonic-gate assert_string(*argv, gettext( 757*7c478bd9Sstevel@tonic-gate "tar: blocking factor must be specified " 758*7c478bd9Sstevel@tonic-gate "with 'b' function modifier\n")); 759*7c478bd9Sstevel@tonic-gate bflag++; 760*7c478bd9Sstevel@tonic-gate nblock = bcheck(*argv++); 761*7c478bd9Sstevel@tonic-gate break; 762*7c478bd9Sstevel@tonic-gate case 'q': 763*7c478bd9Sstevel@tonic-gate qflag++; 764*7c478bd9Sstevel@tonic-gate break; 765*7c478bd9Sstevel@tonic-gate case 'k': 766*7c478bd9Sstevel@tonic-gate assert_string(*argv, gettext( 767*7c478bd9Sstevel@tonic-gate "tar: size value must be specified with 'k' " 768*7c478bd9Sstevel@tonic-gate "function modifier\n")); 769*7c478bd9Sstevel@tonic-gate kflag++; 770*7c478bd9Sstevel@tonic-gate blocklim = kcheck(*argv++); 771*7c478bd9Sstevel@tonic-gate break; 772*7c478bd9Sstevel@tonic-gate case 'n': /* not a magtape (instead of 'k') */ 773*7c478bd9Sstevel@tonic-gate NotTape++; /* assume non-magtape */ 774*7c478bd9Sstevel@tonic-gate break; 775*7c478bd9Sstevel@tonic-gate case 'l': 776*7c478bd9Sstevel@tonic-gate linkerrok++; 777*7c478bd9Sstevel@tonic-gate break; 778*7c478bd9Sstevel@tonic-gate case 'e': 779*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 780*7c478bd9Sstevel@tonic-gate /* If sysv3 IS set, don't be as verbose */ 781*7c478bd9Sstevel@tonic-gate if (!sysv3_env) 782*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 783*7c478bd9Sstevel@tonic-gate errflag++; 784*7c478bd9Sstevel@tonic-gate eflag++; 785*7c478bd9Sstevel@tonic-gate break; 786*7c478bd9Sstevel@tonic-gate case 'o': 787*7c478bd9Sstevel@tonic-gate oflag++; 788*7c478bd9Sstevel@tonic-gate break; 789*7c478bd9Sstevel@tonic-gate case 'h': 790*7c478bd9Sstevel@tonic-gate hflag++; 791*7c478bd9Sstevel@tonic-gate break; 792*7c478bd9Sstevel@tonic-gate case 'i': 793*7c478bd9Sstevel@tonic-gate iflag++; 794*7c478bd9Sstevel@tonic-gate break; 795*7c478bd9Sstevel@tonic-gate case 'B': 796*7c478bd9Sstevel@tonic-gate Bflag++; 797*7c478bd9Sstevel@tonic-gate break; 798*7c478bd9Sstevel@tonic-gate case 'P': 799*7c478bd9Sstevel@tonic-gate Pflag++; 800*7c478bd9Sstevel@tonic-gate break; 801*7c478bd9Sstevel@tonic-gate case 'E': 802*7c478bd9Sstevel@tonic-gate Eflag++; 803*7c478bd9Sstevel@tonic-gate Pflag++; /* Only POSIX archive made */ 804*7c478bd9Sstevel@tonic-gate break; 805*7c478bd9Sstevel@tonic-gate default: 806*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 807*7c478bd9Sstevel@tonic-gate "tar: %c: unknown function modifier\n"), *cp); 808*7c478bd9Sstevel@tonic-gate usage(); 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 812*7c478bd9Sstevel@tonic-gate if (Xflag && Fileflag) { 813*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 814*7c478bd9Sstevel@tonic-gate "tar: specify only one of X or F.\n")); 815*7c478bd9Sstevel@tonic-gate usage(); 816*7c478bd9Sstevel@tonic-gate } 817*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate if (!rflag && !xflag && !tflag) 820*7c478bd9Sstevel@tonic-gate usage(); 821*7c478bd9Sstevel@tonic-gate if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) { 822*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 823*7c478bd9Sstevel@tonic-gate "tar: specify only one of [ctxru].\n")); 824*7c478bd9Sstevel@tonic-gate usage(); 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate if (cflag && *argv == NULL && Filefile == NULL) 827*7c478bd9Sstevel@tonic-gate fatal(gettext("Missing filenames")); 828*7c478bd9Sstevel@tonic-gate if (usefile == NULL) 829*7c478bd9Sstevel@tonic-gate fatal(gettext("device argument required")); 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate /* alloc a buffer of the right size */ 832*7c478bd9Sstevel@tonic-gate if ((tbuf = (union hblock *) 833*7c478bd9Sstevel@tonic-gate calloc(sizeof (union hblock) * nblock, sizeof (char))) == 834*7c478bd9Sstevel@tonic-gate (union hblock *)NULL) { 835*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 836*7c478bd9Sstevel@tonic-gate "tar: cannot allocate physio buffer\n")); 837*7c478bd9Sstevel@tonic-gate exit(1); 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate if ((xrec_ptr = malloc(xrec_size)) == NULL) { 841*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 842*7c478bd9Sstevel@tonic-gate "tar: cannot allocate extended header buffer\n")); 843*7c478bd9Sstevel@tonic-gate exit(1); 844*7c478bd9Sstevel@tonic-gate } 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate #ifdef WAITAROUND 847*7c478bd9Sstevel@tonic-gate if (waitaround) { 848*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Rendezvous with tar on pid" 849*7c478bd9Sstevel@tonic-gate " %d\n"), getpid()); 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate while (waitaround) { 852*7c478bd9Sstevel@tonic-gate (void) sleep(10); 853*7c478bd9Sstevel@tonic-gate } 854*7c478bd9Sstevel@tonic-gate } 855*7c478bd9Sstevel@tonic-gate #endif 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate thispid = getpid(); 858*7c478bd9Sstevel@tonic-gate (void) sprintf(pidchars, "%ld", thispid); 859*7c478bd9Sstevel@tonic-gate thispid = strlen(pidchars); 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL) 862*7c478bd9Sstevel@tonic-gate (void) strcpy(xhdr_dirname, "/tmp"); 863*7c478bd9Sstevel@tonic-gate else { 864*7c478bd9Sstevel@tonic-gate /* 865*7c478bd9Sstevel@tonic-gate * Make sure that dir is no longer than what can 866*7c478bd9Sstevel@tonic-gate * fit in the prefix part of the header. 867*7c478bd9Sstevel@tonic-gate */ 868*7c478bd9Sstevel@tonic-gate if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) { 869*7c478bd9Sstevel@tonic-gate (void) strcpy(xhdr_dirname, "/tmp"); 870*7c478bd9Sstevel@tonic-gate if ((vflag > 0) && (Eflag > 0)) 871*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 872*7c478bd9Sstevel@tonic-gate "Ignoring TMPDIR\n")); 873*7c478bd9Sstevel@tonic-gate } else 874*7c478bd9Sstevel@tonic-gate (void) strcpy(xhdr_dirname, tmpdirp); 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate (void) strcat(xhdr_dirname, "/PaxHeaders."); 877*7c478bd9Sstevel@tonic-gate (void) strcat(xhdr_dirname, pidchars); 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate if (rflag) { 880*7c478bd9Sstevel@tonic-gate if (cflag && tfile != NULL) 881*7c478bd9Sstevel@tonic-gate usage(); 882*7c478bd9Sstevel@tonic-gate if (signal(SIGINT, SIG_IGN) != SIG_IGN) 883*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, onintr); 884*7c478bd9Sstevel@tonic-gate if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 885*7c478bd9Sstevel@tonic-gate (void) signal(SIGHUP, onhup); 886*7c478bd9Sstevel@tonic-gate if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 887*7c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, onquit); 888*7c478bd9Sstevel@tonic-gate if (uflag) { 889*7c478bd9Sstevel@tonic-gate int tnum; 890*7c478bd9Sstevel@tonic-gate if ((tnum = mkstemp(tname)) == -1) 891*7c478bd9Sstevel@tonic-gate vperror(1, "%s", tname); 892*7c478bd9Sstevel@tonic-gate if ((tfile = fdopen(tnum, "w")) == NULL) 893*7c478bd9Sstevel@tonic-gate vperror(1, "%s", tname); 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) { 896*7c478bd9Sstevel@tonic-gate if (cflag == 0) 897*7c478bd9Sstevel@tonic-gate fatal(gettext( 898*7c478bd9Sstevel@tonic-gate "can only create standard output archives.")); 899*7c478bd9Sstevel@tonic-gate vfile = stderr; 900*7c478bd9Sstevel@tonic-gate mt = dup(1); 901*7c478bd9Sstevel@tonic-gate ++bflag; 902*7c478bd9Sstevel@tonic-gate } else { 903*7c478bd9Sstevel@tonic-gate if (cflag) 904*7c478bd9Sstevel@tonic-gate mt = open(usefile, 905*7c478bd9Sstevel@tonic-gate O_RDWR|O_CREAT|O_TRUNC, 0666); 906*7c478bd9Sstevel@tonic-gate else 907*7c478bd9Sstevel@tonic-gate mt = open(usefile, O_RDWR); 908*7c478bd9Sstevel@tonic-gate 909*7c478bd9Sstevel@tonic-gate if (mt < 0) { 910*7c478bd9Sstevel@tonic-gate if (cflag == 0 || (mt = creat(usefile, 0666)) 911*7c478bd9Sstevel@tonic-gate < 0) 912*7c478bd9Sstevel@tonic-gate vperror(1, "%s", usefile); 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate } 915*7c478bd9Sstevel@tonic-gate /* Get inode and device number of output file */ 916*7c478bd9Sstevel@tonic-gate (void) fstat(mt, &stbuf); 917*7c478bd9Sstevel@tonic-gate mt_ino = stbuf.st_ino; 918*7c478bd9Sstevel@tonic-gate mt_dev = stbuf.st_dev; 919*7c478bd9Sstevel@tonic-gate mt_devtype = stbuf.st_mode & S_IFMT; 920*7c478bd9Sstevel@tonic-gate NotTape = !istape(mt, mt_devtype); 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate if (rflag && !cflag && (mt_devtype == S_IFIFO)) 923*7c478bd9Sstevel@tonic-gate fatal(gettext("cannot append to pipe or FIFO.")); 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate if (Aflag && vflag) 926*7c478bd9Sstevel@tonic-gate (void) printf( 927*7c478bd9Sstevel@tonic-gate gettext("Suppressing absolute pathnames\n")); 928*7c478bd9Sstevel@tonic-gate dorep(argv); 929*7c478bd9Sstevel@tonic-gate } else if (xflag || tflag) { 930*7c478bd9Sstevel@tonic-gate /* 931*7c478bd9Sstevel@tonic-gate * for each argument, check to see if there is a "-I file" pair. 932*7c478bd9Sstevel@tonic-gate * if so, move the 3rd argument into "-I"'s place, build_table() 933*7c478bd9Sstevel@tonic-gate * using "file"'s name and increment argc one (the second 934*7c478bd9Sstevel@tonic-gate * increment appears in the for loop) which removes the two 935*7c478bd9Sstevel@tonic-gate * args "-I" and "file" from the argument vector. 936*7c478bd9Sstevel@tonic-gate */ 937*7c478bd9Sstevel@tonic-gate for (argc = 0; argv[argc]; argc++) { 938*7c478bd9Sstevel@tonic-gate if (strcmp(argv[argc], "-I") == 0) { 939*7c478bd9Sstevel@tonic-gate if (!argv[argc+1]) { 940*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 941*7c478bd9Sstevel@tonic-gate "tar: missing argument for -I flag\n")); 942*7c478bd9Sstevel@tonic-gate done(2); 943*7c478bd9Sstevel@tonic-gate } else { 944*7c478bd9Sstevel@tonic-gate Iflag = 1; 945*7c478bd9Sstevel@tonic-gate argv[argc] = argv[argc+2]; 946*7c478bd9Sstevel@tonic-gate build_table(include_tbl, argv[++argc]); 947*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 948*7c478bd9Sstevel@tonic-gate if (Fileflag) { 949*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 950*7c478bd9Sstevel@tonic-gate "tar: only one of I or F.\n")); 951*7c478bd9Sstevel@tonic-gate usage(); 952*7c478bd9Sstevel@tonic-gate } 953*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate } 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate } 958*7c478bd9Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) { 959*7c478bd9Sstevel@tonic-gate mt = dup(0); 960*7c478bd9Sstevel@tonic-gate ++bflag; 961*7c478bd9Sstevel@tonic-gate /* try to recover from short reads when reading stdin */ 962*7c478bd9Sstevel@tonic-gate ++Bflag; 963*7c478bd9Sstevel@tonic-gate } else if ((mt = open(usefile, 0)) < 0) 964*7c478bd9Sstevel@tonic-gate vperror(1, "%s", usefile); 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate if (xflag) { 967*7c478bd9Sstevel@tonic-gate if (Aflag && vflag) 968*7c478bd9Sstevel@tonic-gate (void) printf(gettext 969*7c478bd9Sstevel@tonic-gate ("Suppressing absolute pathnames.\n")); 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 972*7c478bd9Sstevel@tonic-gate doxtract(argv, tbl_cnt); 973*7c478bd9Sstevel@tonic-gate #else 974*7c478bd9Sstevel@tonic-gate doxtract(argv); 975*7c478bd9Sstevel@tonic-gate #endif 976*7c478bd9Sstevel@tonic-gate } else if (tflag) 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 979*7c478bd9Sstevel@tonic-gate dotable(argv, tbl_cnt); 980*7c478bd9Sstevel@tonic-gate #else 981*7c478bd9Sstevel@tonic-gate dotable(argv); 982*7c478bd9Sstevel@tonic-gate #endif 983*7c478bd9Sstevel@tonic-gate } 984*7c478bd9Sstevel@tonic-gate else 985*7c478bd9Sstevel@tonic-gate usage(); 986*7c478bd9Sstevel@tonic-gate 987*7c478bd9Sstevel@tonic-gate done(Errflg); 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate /* Not reached: keep compiler quiet */ 990*7c478bd9Sstevel@tonic-gate return (1); 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate 993*7c478bd9Sstevel@tonic-gate static void 994*7c478bd9Sstevel@tonic-gate usage(void) 995*7c478bd9Sstevel@tonic-gate { 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 998*7c478bd9Sstevel@tonic-gate if (sysv3_env) { 999*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1000*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 1001*7c478bd9Sstevel@tonic-gate "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqvw@[0-7]][bfFk][X...] " 1002*7c478bd9Sstevel@tonic-gate #else 1003*7c478bd9Sstevel@tonic-gate "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqvw[0-7]][bfFk][X...] " 1004*7c478bd9Sstevel@tonic-gate #endif 1005*7c478bd9Sstevel@tonic-gate "[blocksize] [tarfile] [filename] [size] [exclude-file...] " 1006*7c478bd9Sstevel@tonic-gate "{file | -I include-file | -C directory file}...\n")); 1007*7c478bd9Sstevel@tonic-gate } else 1008*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 1009*7c478bd9Sstevel@tonic-gate { 1010*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1011*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 1012*7c478bd9Sstevel@tonic-gate "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqvw@[0-7]][bfk][X...] " 1013*7c478bd9Sstevel@tonic-gate #else 1014*7c478bd9Sstevel@tonic-gate "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqvw[0-7]][bfk][X...] " 1015*7c478bd9Sstevel@tonic-gate #endif 1016*7c478bd9Sstevel@tonic-gate "[blocksize] [tarfile] [size] [exclude-file...] " 1017*7c478bd9Sstevel@tonic-gate "{file | -I include-file | -C directory file}...\n")); 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate done(1); 1020*7c478bd9Sstevel@tonic-gate } 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate /* 1023*7c478bd9Sstevel@tonic-gate * dorep - do "replacements" 1024*7c478bd9Sstevel@tonic-gate * 1025*7c478bd9Sstevel@tonic-gate * Dorep is responsible for creating ('c'), appending ('r') 1026*7c478bd9Sstevel@tonic-gate * and updating ('u'); 1027*7c478bd9Sstevel@tonic-gate */ 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate static void 1030*7c478bd9Sstevel@tonic-gate dorep(char *argv[]) 1031*7c478bd9Sstevel@tonic-gate { 1032*7c478bd9Sstevel@tonic-gate char *cp, *cp2, *p; 1033*7c478bd9Sstevel@tonic-gate char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent; 1034*7c478bd9Sstevel@tonic-gate char file[PATH_MAX*2], origdir[PATH_MAX+1]; 1035*7c478bd9Sstevel@tonic-gate FILE *fp = (FILE *)NULL; 1036*7c478bd9Sstevel@tonic-gate FILE *ff = (FILE *)NULL; 1037*7c478bd9Sstevel@tonic-gate int archtype; 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate if (!cflag) { 1041*7c478bd9Sstevel@tonic-gate xhdr_flgs = 0; 1042*7c478bd9Sstevel@tonic-gate getdir(); /* read header for next file */ 1043*7c478bd9Sstevel@tonic-gate if (Xhdrflag > 0) { 1044*7c478bd9Sstevel@tonic-gate if (!Eflag) 1045*7c478bd9Sstevel@tonic-gate fatal(gettext("Archive contains extended" 1046*7c478bd9Sstevel@tonic-gate " header. -E flag required.\n")); 1047*7c478bd9Sstevel@tonic-gate (void) get_xdata(); /* Get extended header items */ 1048*7c478bd9Sstevel@tonic-gate /* and regular header */ 1049*7c478bd9Sstevel@tonic-gate } else { 1050*7c478bd9Sstevel@tonic-gate if (Eflag) 1051*7c478bd9Sstevel@tonic-gate fatal(gettext("Archive contains no extended" 1052*7c478bd9Sstevel@tonic-gate " header. -E flag not allowed.\n")); 1053*7c478bd9Sstevel@tonic-gate } 1054*7c478bd9Sstevel@tonic-gate while (!endtape()) { /* changed from a do while */ 1055*7c478bd9Sstevel@tonic-gate passtape(); /* skip the file data */ 1056*7c478bd9Sstevel@tonic-gate if (term) 1057*7c478bd9Sstevel@tonic-gate done(Errflg); /* received signal to stop */ 1058*7c478bd9Sstevel@tonic-gate xhdr_flgs = 0; 1059*7c478bd9Sstevel@tonic-gate getdir(); 1060*7c478bd9Sstevel@tonic-gate if (Xhdrflag > 0) 1061*7c478bd9Sstevel@tonic-gate (void) get_xdata(); 1062*7c478bd9Sstevel@tonic-gate } 1063*7c478bd9Sstevel@tonic-gate backtape(); /* was called by endtape */ 1064*7c478bd9Sstevel@tonic-gate if (tfile != NULL) { 1065*7c478bd9Sstevel@tonic-gate char buf[200]; 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "sort +0 -1 +1nr %s -o %s; awk '$1 " 1068*7c478bd9Sstevel@tonic-gate "!= prev {print; prev=$1}' %s >%sX;mv %sX %s", 1069*7c478bd9Sstevel@tonic-gate tname, tname, tname, tname, tname, tname); 1070*7c478bd9Sstevel@tonic-gate (void) fflush(tfile); 1071*7c478bd9Sstevel@tonic-gate (void) system(buf); 1072*7c478bd9Sstevel@tonic-gate (void) freopen(tname, "r", tfile); 1073*7c478bd9Sstevel@tonic-gate (void) fstat(fileno(tfile), &stbuf); 1074*7c478bd9Sstevel@tonic-gate high = stbuf.st_size; 1075*7c478bd9Sstevel@tonic-gate } 1076*7c478bd9Sstevel@tonic-gate } 1077*7c478bd9Sstevel@tonic-gate 1078*7c478bd9Sstevel@tonic-gate dumping = 1; 1079*7c478bd9Sstevel@tonic-gate if (mulvol) { /* SP-1 */ 1080*7c478bd9Sstevel@tonic-gate if (nblock && (blocklim%nblock) != 0) 1081*7c478bd9Sstevel@tonic-gate fatal(gettext( 1082*7c478bd9Sstevel@tonic-gate "Volume size not a multiple of block size.")); 1083*7c478bd9Sstevel@tonic-gate blocklim -= 2; /* for trailer records */ 1084*7c478bd9Sstevel@tonic-gate if (vflag) 1085*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("Volume ends at %" 1086*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t "K, blocking factor = %dK\n"), 1087*7c478bd9Sstevel@tonic-gate K((blocklim - 1)), K(nblock)); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 1091*7c478bd9Sstevel@tonic-gate if (Fileflag) { 1092*7c478bd9Sstevel@tonic-gate if (Filefile != NULL) { 1093*7c478bd9Sstevel@tonic-gate if ((ff = fopen(Filefile, "r")) == NULL) 1094*7c478bd9Sstevel@tonic-gate vperror(0, "%s", Filefile); 1095*7c478bd9Sstevel@tonic-gate } else { 1096*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1097*7c478bd9Sstevel@tonic-gate "tar: F requires a file name.\n")); 1098*7c478bd9Sstevel@tonic-gate usage(); 1099*7c478bd9Sstevel@tonic-gate } 1100*7c478bd9Sstevel@tonic-gate } 1101*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate /* 1104*7c478bd9Sstevel@tonic-gate * Save the original directory before it gets 1105*7c478bd9Sstevel@tonic-gate * changed. 1106*7c478bd9Sstevel@tonic-gate */ 1107*7c478bd9Sstevel@tonic-gate if (getcwd(origdir, (PATH_MAX+1)) == NULL) { 1108*7c478bd9Sstevel@tonic-gate vperror(0, gettext("A parent directory cannot be read")); 1109*7c478bd9Sstevel@tonic-gate exit(1); 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate (void) strcpy(wdir, origdir); 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate while ((*argv || fp || ff) && !term) { 1115*7c478bd9Sstevel@tonic-gate if (fp || (strcmp(*argv, "-I") == 0)) { 1116*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 1117*7c478bd9Sstevel@tonic-gate if (Fileflag) { 1118*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1119*7c478bd9Sstevel@tonic-gate "tar: only one of I or F.\n")); 1120*7c478bd9Sstevel@tonic-gate usage(); 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 1123*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 1124*7c478bd9Sstevel@tonic-gate if (*++argv == NULL) 1125*7c478bd9Sstevel@tonic-gate fatal(gettext( 1126*7c478bd9Sstevel@tonic-gate "missing file name for -I flag.")); 1127*7c478bd9Sstevel@tonic-gate else if ((fp = fopen(*argv++, "r")) == NULL) 1128*7c478bd9Sstevel@tonic-gate vperror(0, "%s", argv[-1]); 1129*7c478bd9Sstevel@tonic-gate continue; 1130*7c478bd9Sstevel@tonic-gate } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) { 1131*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1132*7c478bd9Sstevel@tonic-gate fp = NULL; 1133*7c478bd9Sstevel@tonic-gate continue; 1134*7c478bd9Sstevel@tonic-gate } else { 1135*7c478bd9Sstevel@tonic-gate cp = cp2 = file; 1136*7c478bd9Sstevel@tonic-gate if ((p = strchr(cp2, '\n'))) 1137*7c478bd9Sstevel@tonic-gate *p = 0; 1138*7c478bd9Sstevel@tonic-gate } 1139*7c478bd9Sstevel@tonic-gate } else if ((strcmp(*argv, "-C") == 0) && argv[1]) { 1140*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 1141*7c478bd9Sstevel@tonic-gate if (Fileflag) { 1142*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1143*7c478bd9Sstevel@tonic-gate "tar: only one of F or C\n")); 1144*7c478bd9Sstevel@tonic-gate usage(); 1145*7c478bd9Sstevel@tonic-gate } 1146*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate if (chdir(*++argv) < 0) 1149*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 1150*7c478bd9Sstevel@tonic-gate "can't change directories to %s"), *argv); 1151*7c478bd9Sstevel@tonic-gate else 1152*7c478bd9Sstevel@tonic-gate (void) getcwd(wdir, (sizeof (wdir))); 1153*7c478bd9Sstevel@tonic-gate argv++; 1154*7c478bd9Sstevel@tonic-gate continue; 1155*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 1156*7c478bd9Sstevel@tonic-gate } else if (Fileflag && (ff != NULL)) { 1157*7c478bd9Sstevel@tonic-gate if ((fgets(file, PATH_MAX-1, ff)) == NULL) { 1158*7c478bd9Sstevel@tonic-gate (void) fclose(ff); 1159*7c478bd9Sstevel@tonic-gate ff = NULL; 1160*7c478bd9Sstevel@tonic-gate continue; 1161*7c478bd9Sstevel@tonic-gate } else { 1162*7c478bd9Sstevel@tonic-gate cp = cp2 = file; 1163*7c478bd9Sstevel@tonic-gate if (p = strchr(cp2, '\n')) 1164*7c478bd9Sstevel@tonic-gate *p = 0; 1165*7c478bd9Sstevel@tonic-gate } 1166*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 1167*7c478bd9Sstevel@tonic-gate } else 1168*7c478bd9Sstevel@tonic-gate cp = cp2 = strcpy(file, *argv++); 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate /* 1171*7c478bd9Sstevel@tonic-gate * point cp2 to the last '/' in file, but not 1172*7c478bd9Sstevel@tonic-gate * to a trailing '/' 1173*7c478bd9Sstevel@tonic-gate */ 1174*7c478bd9Sstevel@tonic-gate for (; *cp; cp++) { 1175*7c478bd9Sstevel@tonic-gate if (*cp == '/') { 1176*7c478bd9Sstevel@tonic-gate while (*(cp+1) == '/') { 1177*7c478bd9Sstevel@tonic-gate ++cp; 1178*7c478bd9Sstevel@tonic-gate } 1179*7c478bd9Sstevel@tonic-gate if (*(cp+1) != '\0') { 1180*7c478bd9Sstevel@tonic-gate /* not trailing slash */ 1181*7c478bd9Sstevel@tonic-gate cp2 = cp; 1182*7c478bd9Sstevel@tonic-gate } 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate } 1185*7c478bd9Sstevel@tonic-gate if (cp2 != file) { 1186*7c478bd9Sstevel@tonic-gate *cp2 = '\0'; 1187*7c478bd9Sstevel@tonic-gate if (chdir(file) < 0) { 1188*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 1189*7c478bd9Sstevel@tonic-gate "can't change directories to %s"), file); 1190*7c478bd9Sstevel@tonic-gate continue; 1191*7c478bd9Sstevel@tonic-gate } 1192*7c478bd9Sstevel@tonic-gate *cp2 = '/'; 1193*7c478bd9Sstevel@tonic-gate cp2++; 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate parent = getcwd(tempdir, (sizeof (tempdir))); 1197*7c478bd9Sstevel@tonic-gate archtype = putfile(file, cp2, parent, NORMAL_FILE, 1198*7c478bd9Sstevel@tonic-gate LEV0, SYMLINK_LEV0); 1199*7c478bd9Sstevel@tonic-gate 1200*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 1201*7c478bd9Sstevel@tonic-gate if (!exitflag) { 1202*7c478bd9Sstevel@tonic-gate if (atflag && archtype == PUT_NOTAS_LINK) { 1203*7c478bd9Sstevel@tonic-gate xattrs_put(file, cp2, parent); 1204*7c478bd9Sstevel@tonic-gate } 1205*7c478bd9Sstevel@tonic-gate } 1206*7c478bd9Sstevel@tonic-gate #endif 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate if (chdir(origdir) < 0) 1209*7c478bd9Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"), origdir); 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate if (exitflag) { 1212*7c478bd9Sstevel@tonic-gate /* 1213*7c478bd9Sstevel@tonic-gate * If e function modifier has been specified 1214*7c478bd9Sstevel@tonic-gate * write the files (that are listed before the 1215*7c478bd9Sstevel@tonic-gate * file causing the error) to tape. exitflag is 1216*7c478bd9Sstevel@tonic-gate * used because only some of the error conditions 1217*7c478bd9Sstevel@tonic-gate * in putfile() recognize the e function modifier. 1218*7c478bd9Sstevel@tonic-gate */ 1219*7c478bd9Sstevel@tonic-gate break; 1220*7c478bd9Sstevel@tonic-gate } 1221*7c478bd9Sstevel@tonic-gate } 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate putempty((blkcnt_t)2); 1224*7c478bd9Sstevel@tonic-gate flushtape(); 1225*7c478bd9Sstevel@tonic-gate closevol(); /* SP-1 */ 1226*7c478bd9Sstevel@tonic-gate if (linkerrok == 1) 1227*7c478bd9Sstevel@tonic-gate for (; ihead != NULL; ihead = ihead->nextp) { 1228*7c478bd9Sstevel@tonic-gate if (ihead->count == 0) 1229*7c478bd9Sstevel@tonic-gate continue; 1230*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1231*7c478bd9Sstevel@tonic-gate "tar: missing links to %s\n"), ihead->pathname); 1232*7c478bd9Sstevel@tonic-gate if (errflag) 1233*7c478bd9Sstevel@tonic-gate done(1); 1234*7c478bd9Sstevel@tonic-gate else 1235*7c478bd9Sstevel@tonic-gate Errflg = 1; 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate } 1238*7c478bd9Sstevel@tonic-gate 1239*7c478bd9Sstevel@tonic-gate 1240*7c478bd9Sstevel@tonic-gate /* 1241*7c478bd9Sstevel@tonic-gate * endtape - check for tape at end 1242*7c478bd9Sstevel@tonic-gate * 1243*7c478bd9Sstevel@tonic-gate * endtape checks the entry in dblock.dbuf to see if its the 1244*7c478bd9Sstevel@tonic-gate * special EOT entry. Endtape is usually called after getdir(). 1245*7c478bd9Sstevel@tonic-gate * 1246*7c478bd9Sstevel@tonic-gate * endtape used to call backtape; it no longer does, he who 1247*7c478bd9Sstevel@tonic-gate * wants it backed up must call backtape himself 1248*7c478bd9Sstevel@tonic-gate * RETURNS: 0 if not EOT, tape position unaffected 1249*7c478bd9Sstevel@tonic-gate * 1 if EOT, tape position unaffected 1250*7c478bd9Sstevel@tonic-gate */ 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate static int 1253*7c478bd9Sstevel@tonic-gate endtape(void) 1254*7c478bd9Sstevel@tonic-gate { 1255*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.name[0] == '\0') { /* null header = EOT */ 1256*7c478bd9Sstevel@tonic-gate return (1); 1257*7c478bd9Sstevel@tonic-gate } else 1258*7c478bd9Sstevel@tonic-gate return (0); 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate /* 1262*7c478bd9Sstevel@tonic-gate * getdir - get directory entry from tar tape 1263*7c478bd9Sstevel@tonic-gate * 1264*7c478bd9Sstevel@tonic-gate * getdir reads the next tarblock off the tape and cracks 1265*7c478bd9Sstevel@tonic-gate * it as a directory. The checksum must match properly. 1266*7c478bd9Sstevel@tonic-gate * 1267*7c478bd9Sstevel@tonic-gate * If tfile is non-null getdir writes the file name and mod date 1268*7c478bd9Sstevel@tonic-gate * to tfile. 1269*7c478bd9Sstevel@tonic-gate */ 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate static void 1272*7c478bd9Sstevel@tonic-gate getdir(void) 1273*7c478bd9Sstevel@tonic-gate { 1274*7c478bd9Sstevel@tonic-gate struct stat *sp; 1275*7c478bd9Sstevel@tonic-gate #ifdef EUC 1276*7c478bd9Sstevel@tonic-gate static int warn_chksum_sign = 0; 1277*7c478bd9Sstevel@tonic-gate #endif /* EUC */ 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate top: 1280*7c478bd9Sstevel@tonic-gate readtape((char *)&dblock); 1281*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.name[0] == '\0') 1282*7c478bd9Sstevel@tonic-gate return; 1283*7c478bd9Sstevel@tonic-gate sp = &stbuf; 1284*7c478bd9Sstevel@tonic-gate (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode); 1285*7c478bd9Sstevel@tonic-gate (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid); 1286*7c478bd9Sstevel@tonic-gate (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid); 1287*7c478bd9Sstevel@tonic-gate (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz); 1288*7c478bd9Sstevel@tonic-gate (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime); 1289*7c478bd9Sstevel@tonic-gate (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum); 1290*7c478bd9Sstevel@tonic-gate (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor); 1291*7c478bd9Sstevel@tonic-gate (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor); 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0); 1294*7c478bd9Sstevel@tonic-gate 1295*7c478bd9Sstevel@tonic-gate sp->st_mode = Gen.g_mode; 1296*7c478bd9Sstevel@tonic-gate if (is_posix && (sp->st_mode & S_IFMT) == 0) 1297*7c478bd9Sstevel@tonic-gate switch (dblock.dbuf.typeflag) { 1298*7c478bd9Sstevel@tonic-gate case '0': case 0: case _XATTR_HDRTYPE: 1299*7c478bd9Sstevel@tonic-gate sp->st_mode |= S_IFREG; 1300*7c478bd9Sstevel@tonic-gate break; 1301*7c478bd9Sstevel@tonic-gate case '1': /* hard link */ 1302*7c478bd9Sstevel@tonic-gate break; 1303*7c478bd9Sstevel@tonic-gate case '2': 1304*7c478bd9Sstevel@tonic-gate sp->st_mode |= S_IFLNK; 1305*7c478bd9Sstevel@tonic-gate break; 1306*7c478bd9Sstevel@tonic-gate case '3': 1307*7c478bd9Sstevel@tonic-gate sp->st_mode |= S_IFCHR; 1308*7c478bd9Sstevel@tonic-gate break; 1309*7c478bd9Sstevel@tonic-gate case '4': 1310*7c478bd9Sstevel@tonic-gate sp->st_mode |= S_IFBLK; 1311*7c478bd9Sstevel@tonic-gate break; 1312*7c478bd9Sstevel@tonic-gate case '5': 1313*7c478bd9Sstevel@tonic-gate sp->st_mode |= S_IFDIR; 1314*7c478bd9Sstevel@tonic-gate break; 1315*7c478bd9Sstevel@tonic-gate case '6': 1316*7c478bd9Sstevel@tonic-gate sp->st_mode |= S_IFIFO; 1317*7c478bd9Sstevel@tonic-gate break; 1318*7c478bd9Sstevel@tonic-gate default: 1319*7c478bd9Sstevel@tonic-gate if (convtoreg(Gen.g_filesz)) 1320*7c478bd9Sstevel@tonic-gate sp->st_mode |= S_IFREG; 1321*7c478bd9Sstevel@tonic-gate break; 1322*7c478bd9Sstevel@tonic-gate } 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == 'X') 1325*7c478bd9Sstevel@tonic-gate Xhdrflag = 1; /* Currently processing extended header */ 1326*7c478bd9Sstevel@tonic-gate else 1327*7c478bd9Sstevel@tonic-gate Xhdrflag = 0; 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate sp->st_uid = Gen.g_uid; 1330*7c478bd9Sstevel@tonic-gate sp->st_gid = Gen.g_gid; 1331*7c478bd9Sstevel@tonic-gate sp->st_size = Gen.g_filesz; 1332*7c478bd9Sstevel@tonic-gate sp->st_mtime = Gen.g_mtime; 1333*7c478bd9Sstevel@tonic-gate chksum = Gen.g_cksum; 1334*7c478bd9Sstevel@tonic-gate 1335*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.extno != '\0') { /* split file? */ 1336*7c478bd9Sstevel@tonic-gate extno = dblock.dbuf.extno; 1337*7c478bd9Sstevel@tonic-gate extsize = Gen.g_filesz; 1338*7c478bd9Sstevel@tonic-gate extotal = dblock.dbuf.extotal; 1339*7c478bd9Sstevel@tonic-gate } else { 1340*7c478bd9Sstevel@tonic-gate extno = 0; /* tell others file not split */ 1341*7c478bd9Sstevel@tonic-gate extsize = 0; 1342*7c478bd9Sstevel@tonic-gate extotal = 0; 1343*7c478bd9Sstevel@tonic-gate } 1344*7c478bd9Sstevel@tonic-gate 1345*7c478bd9Sstevel@tonic-gate #ifdef EUC 1346*7c478bd9Sstevel@tonic-gate if (chksum != checksum(&dblock)) { 1347*7c478bd9Sstevel@tonic-gate if (chksum != checksum_signed(&dblock)) { 1348*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1349*7c478bd9Sstevel@tonic-gate "tar: directory checksum error\n")); 1350*7c478bd9Sstevel@tonic-gate if (iflag) 1351*7c478bd9Sstevel@tonic-gate goto top; 1352*7c478bd9Sstevel@tonic-gate done(2); 1353*7c478bd9Sstevel@tonic-gate } else { 1354*7c478bd9Sstevel@tonic-gate if (! warn_chksum_sign) { 1355*7c478bd9Sstevel@tonic-gate warn_chksum_sign = 1; 1356*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1357*7c478bd9Sstevel@tonic-gate "tar: warning: tar file made with signed checksum\n")); 1358*7c478bd9Sstevel@tonic-gate } 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate } 1361*7c478bd9Sstevel@tonic-gate #else 1362*7c478bd9Sstevel@tonic-gate if (chksum != checksum(&dblock)) { 1363*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1364*7c478bd9Sstevel@tonic-gate "tar: directory checksum error\n")); 1365*7c478bd9Sstevel@tonic-gate if (iflag) 1366*7c478bd9Sstevel@tonic-gate goto top; 1367*7c478bd9Sstevel@tonic-gate done(2); 1368*7c478bd9Sstevel@tonic-gate } 1369*7c478bd9Sstevel@tonic-gate #endif /* EUC */ 1370*7c478bd9Sstevel@tonic-gate if (tfile != NULL && Xhdrflag == 0) { 1371*7c478bd9Sstevel@tonic-gate /* 1372*7c478bd9Sstevel@tonic-gate * If an extended header is present, then time is available 1373*7c478bd9Sstevel@tonic-gate * in nanoseconds in the extended header data, so set it. 1374*7c478bd9Sstevel@tonic-gate * Otherwise, give an invalid value so that checkupdate will 1375*7c478bd9Sstevel@tonic-gate * not test beyond seconds. 1376*7c478bd9Sstevel@tonic-gate */ 1377*7c478bd9Sstevel@tonic-gate if ((xhdr_flgs & _X_MTIME)) 1378*7c478bd9Sstevel@tonic-gate sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec; 1379*7c478bd9Sstevel@tonic-gate else 1380*7c478bd9Sstevel@tonic-gate sp->st_mtim.tv_nsec = -1; 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 1383*7c478bd9Sstevel@tonic-gate (void) fprintf(tfile, "%s %10ld.%9.9ld\n", 1384*7c478bd9Sstevel@tonic-gate Xtarhdr.x_path, sp->st_mtim.tv_sec, 1385*7c478bd9Sstevel@tonic-gate sp->st_mtim.tv_nsec); 1386*7c478bd9Sstevel@tonic-gate else 1387*7c478bd9Sstevel@tonic-gate (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n", 1388*7c478bd9Sstevel@tonic-gate NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec, 1389*7c478bd9Sstevel@tonic-gate sp->st_mtim.tv_nsec); 1390*7c478bd9Sstevel@tonic-gate } 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 1393*7c478bd9Sstevel@tonic-gate Hiddendir = 0; 1394*7c478bd9Sstevel@tonic-gate if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) { 1395*7c478bd9Sstevel@tonic-gate if (xattrbadhead) { 1396*7c478bd9Sstevel@tonic-gate free(xattrhead); 1397*7c478bd9Sstevel@tonic-gate xattrp = NULL; 1398*7c478bd9Sstevel@tonic-gate xattr_linkp = NULL; 1399*7c478bd9Sstevel@tonic-gate xattrhead = NULL; 1400*7c478bd9Sstevel@tonic-gate } else { 1401*7c478bd9Sstevel@tonic-gate if (xattraname[0] == '.' && xattraname[1] == '\0' && 1402*7c478bd9Sstevel@tonic-gate xattrp->h_typeflag == '5') { 1403*7c478bd9Sstevel@tonic-gate Hiddendir = 1; 1404*7c478bd9Sstevel@tonic-gate sp->st_mode = 1405*7c478bd9Sstevel@tonic-gate (S_IFDIR | (sp->st_mode & S_IAMB)); 1406*7c478bd9Sstevel@tonic-gate } 1407*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = xattrp->h_typeflag; 1408*7c478bd9Sstevel@tonic-gate } 1409*7c478bd9Sstevel@tonic-gate } 1410*7c478bd9Sstevel@tonic-gate #endif 1411*7c478bd9Sstevel@tonic-gate } 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate 1414*7c478bd9Sstevel@tonic-gate /* 1415*7c478bd9Sstevel@tonic-gate * passtape - skip over a file on the tape 1416*7c478bd9Sstevel@tonic-gate * 1417*7c478bd9Sstevel@tonic-gate * passtape skips over the next data file on the tape. 1418*7c478bd9Sstevel@tonic-gate * The tape directory entry must be in dblock.dbuf. This 1419*7c478bd9Sstevel@tonic-gate * routine just eats the number of blocks computed from the 1420*7c478bd9Sstevel@tonic-gate * directory size entry; the tape must be (logically) positioned 1421*7c478bd9Sstevel@tonic-gate * right after thee directory info. 1422*7c478bd9Sstevel@tonic-gate */ 1423*7c478bd9Sstevel@tonic-gate 1424*7c478bd9Sstevel@tonic-gate static void 1425*7c478bd9Sstevel@tonic-gate passtape(void) 1426*7c478bd9Sstevel@tonic-gate { 1427*7c478bd9Sstevel@tonic-gate blkcnt_t blocks; 1428*7c478bd9Sstevel@tonic-gate char buf[TBLOCK]; 1429*7c478bd9Sstevel@tonic-gate 1430*7c478bd9Sstevel@tonic-gate /* 1431*7c478bd9Sstevel@tonic-gate * Types link(1), sym-link(2), char special(3), blk special(4), 1432*7c478bd9Sstevel@tonic-gate * directory(5), and FIFO(6) do not have data blocks associated 1433*7c478bd9Sstevel@tonic-gate * with them so just skip reading the data block. 1434*7c478bd9Sstevel@tonic-gate */ 1435*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' || 1436*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' || 1437*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6') 1438*7c478bd9Sstevel@tonic-gate return; 1439*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate /* if operating on disk, seek instead of reading */ 1442*7c478bd9Sstevel@tonic-gate if (NotTape) 1443*7c478bd9Sstevel@tonic-gate seekdisk(blocks); 1444*7c478bd9Sstevel@tonic-gate else 1445*7c478bd9Sstevel@tonic-gate while (blocks-- > 0) 1446*7c478bd9Sstevel@tonic-gate readtape(buf); 1447*7c478bd9Sstevel@tonic-gate } 1448*7c478bd9Sstevel@tonic-gate 1449*7c478bd9Sstevel@tonic-gate 1450*7c478bd9Sstevel@tonic-gate static int 1451*7c478bd9Sstevel@tonic-gate putfile(char *longname, char *shortname, char *parent, 1452*7c478bd9Sstevel@tonic-gate int filetype, int lev, int symlink_lev) 1453*7c478bd9Sstevel@tonic-gate { 1454*7c478bd9Sstevel@tonic-gate int infile = -1; /* deliberately invalid */ 1455*7c478bd9Sstevel@tonic-gate blkcnt_t blocks; 1456*7c478bd9Sstevel@tonic-gate char buf[PATH_MAX + 2]; /* Add trailing slash and null */ 1457*7c478bd9Sstevel@tonic-gate char *bigbuf; 1458*7c478bd9Sstevel@tonic-gate int maxread; 1459*7c478bd9Sstevel@tonic-gate int hint; /* amount to write to get "in sync" */ 1460*7c478bd9Sstevel@tonic-gate char filetmp[PATH_MAX + 1]; 1461*7c478bd9Sstevel@tonic-gate char *cp; 1462*7c478bd9Sstevel@tonic-gate char *name; 1463*7c478bd9Sstevel@tonic-gate struct dirent *dp; 1464*7c478bd9Sstevel@tonic-gate DIR *dirp; 1465*7c478bd9Sstevel@tonic-gate int i; 1466*7c478bd9Sstevel@tonic-gate long l; 1467*7c478bd9Sstevel@tonic-gate int split; 1468*7c478bd9Sstevel@tonic-gate int dirfd = -1; 1469*7c478bd9Sstevel@tonic-gate int rc = PUT_NOTAS_LINK; 1470*7c478bd9Sstevel@tonic-gate int archtype = 0; 1471*7c478bd9Sstevel@tonic-gate char newparent[PATH_MAX + MAXNAMLEN + 1]; 1472*7c478bd9Sstevel@tonic-gate char *prefix = ""; 1473*7c478bd9Sstevel@tonic-gate char *tmpbuf; 1474*7c478bd9Sstevel@tonic-gate char goodbuf[PRESIZ + 2]; 1475*7c478bd9Sstevel@tonic-gate char junkbuf[MAXNAM+1]; 1476*7c478bd9Sstevel@tonic-gate char *lastslash; 1477*7c478bd9Sstevel@tonic-gate int j; 1478*7c478bd9Sstevel@tonic-gate struct stat sbuf; 1479*7c478bd9Sstevel@tonic-gate int readlink_max; 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate (void) memset(goodbuf, '\0', sizeof (goodbuf)); 1482*7c478bd9Sstevel@tonic-gate (void) memset(junkbuf, '\0', sizeof (junkbuf)); 1483*7c478bd9Sstevel@tonic-gate 1484*7c478bd9Sstevel@tonic-gate xhdr_flgs = 0; 1485*7c478bd9Sstevel@tonic-gate 1486*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) { 1487*7c478bd9Sstevel@tonic-gate dirfd = attropen(get_component(longname), ".", O_RDONLY); 1488*7c478bd9Sstevel@tonic-gate } else { 1489*7c478bd9Sstevel@tonic-gate dirfd = open(".", O_RDONLY); 1490*7c478bd9Sstevel@tonic-gate } 1491*7c478bd9Sstevel@tonic-gate 1492*7c478bd9Sstevel@tonic-gate if (dirfd == -1) { 1493*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1494*7c478bd9Sstevel@tonic-gate "tar: unable to open%sdirectory %s\n"), 1495*7c478bd9Sstevel@tonic-gate (filetype == XATTR_FILE) ? gettext(" attribute ") : " ", 1496*7c478bd9Sstevel@tonic-gate (filetype == XATTR_FILE) ? longname : parent); 1497*7c478bd9Sstevel@tonic-gate goto out; 1498*7c478bd9Sstevel@tonic-gate } 1499*7c478bd9Sstevel@tonic-gate 1500*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) { 1501*7c478bd9Sstevel@tonic-gate if (fchdir(dirfd) < 0) { 1502*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1503*7c478bd9Sstevel@tonic-gate "tar: unable to fchdir into attribute directory" 1504*7c478bd9Sstevel@tonic-gate " of file %s\n"), longname); 1505*7c478bd9Sstevel@tonic-gate goto out; 1506*7c478bd9Sstevel@tonic-gate } 1507*7c478bd9Sstevel@tonic-gate } 1508*7c478bd9Sstevel@tonic-gate 1509*7c478bd9Sstevel@tonic-gate if (lev > MAXLEV) { 1510*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1511*7c478bd9Sstevel@tonic-gate gettext("tar: directory nesting too deep, %s not dumped\n"), 1512*7c478bd9Sstevel@tonic-gate longname); 1513*7c478bd9Sstevel@tonic-gate goto out; 1514*7c478bd9Sstevel@tonic-gate } 1515*7c478bd9Sstevel@tonic-gate 1516*7c478bd9Sstevel@tonic-gate if (getstat(dirfd, longname, shortname)) 1517*7c478bd9Sstevel@tonic-gate goto out; 1518*7c478bd9Sstevel@tonic-gate 1519*7c478bd9Sstevel@tonic-gate if (hflag) { 1520*7c478bd9Sstevel@tonic-gate /* 1521*7c478bd9Sstevel@tonic-gate * Catch nesting where a file is a symlink to its directory. 1522*7c478bd9Sstevel@tonic-gate */ 1523*7c478bd9Sstevel@tonic-gate j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW); 1524*7c478bd9Sstevel@tonic-gate if (S_ISLNK(sbuf.st_mode)) { 1525*7c478bd9Sstevel@tonic-gate if (symlink_lev++ >= MAXSYMLINKS) { 1526*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1527*7c478bd9Sstevel@tonic-gate "tar: %s: Number of symbolic links " 1528*7c478bd9Sstevel@tonic-gate "encountered during path name traversal " 1529*7c478bd9Sstevel@tonic-gate "exceeds MAXSYMLINKS\n"), longname); 1530*7c478bd9Sstevel@tonic-gate Errflg = 1; 1531*7c478bd9Sstevel@tonic-gate goto out; 1532*7c478bd9Sstevel@tonic-gate } 1533*7c478bd9Sstevel@tonic-gate } 1534*7c478bd9Sstevel@tonic-gate } 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate /* 1537*7c478bd9Sstevel@tonic-gate * Check if the input file is the same as the tar file we 1538*7c478bd9Sstevel@tonic-gate * are creating 1539*7c478bd9Sstevel@tonic-gate */ 1540*7c478bd9Sstevel@tonic-gate if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) { 1541*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1542*7c478bd9Sstevel@tonic-gate "tar: %s same as archive file\n"), longname); 1543*7c478bd9Sstevel@tonic-gate Errflg = 1; 1544*7c478bd9Sstevel@tonic-gate goto out; 1545*7c478bd9Sstevel@tonic-gate } 1546*7c478bd9Sstevel@tonic-gate /* 1547*7c478bd9Sstevel@tonic-gate * Check size limit - we can't archive files that 1548*7c478bd9Sstevel@tonic-gate * exceed TAR_OFFSET_MAX bytes because of header 1549*7c478bd9Sstevel@tonic-gate * limitations. Exclude file types that set 1550*7c478bd9Sstevel@tonic-gate * st_size to zero below because they take no 1551*7c478bd9Sstevel@tonic-gate * archive space to represent contents. 1552*7c478bd9Sstevel@tonic-gate */ 1553*7c478bd9Sstevel@tonic-gate if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) && 1554*7c478bd9Sstevel@tonic-gate !S_ISDIR(stbuf.st_mode) && 1555*7c478bd9Sstevel@tonic-gate !S_ISCHR(stbuf.st_mode) && 1556*7c478bd9Sstevel@tonic-gate !S_ISBLK(stbuf.st_mode) && 1557*7c478bd9Sstevel@tonic-gate (Eflag == 0)) { 1558*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1559*7c478bd9Sstevel@tonic-gate "tar: %s too large to archive. " 1560*7c478bd9Sstevel@tonic-gate "Use E function modifier.\n"), longname); 1561*7c478bd9Sstevel@tonic-gate if (errflag) 1562*7c478bd9Sstevel@tonic-gate exitflag = 1; 1563*7c478bd9Sstevel@tonic-gate Errflg = 1; 1564*7c478bd9Sstevel@tonic-gate goto out; 1565*7c478bd9Sstevel@tonic-gate } 1566*7c478bd9Sstevel@tonic-gate 1567*7c478bd9Sstevel@tonic-gate if (tfile != NULL && checkupdate(longname) == 0) { 1568*7c478bd9Sstevel@tonic-gate goto out; 1569*7c478bd9Sstevel@tonic-gate } 1570*7c478bd9Sstevel@tonic-gate if (checkw('r', longname) == 0) { 1571*7c478bd9Sstevel@tonic-gate goto out; 1572*7c478bd9Sstevel@tonic-gate } 1573*7c478bd9Sstevel@tonic-gate 1574*7c478bd9Sstevel@tonic-gate if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 1575*7c478bd9Sstevel@tonic-gate goto out; 1576*7c478bd9Sstevel@tonic-gate 1577*7c478bd9Sstevel@tonic-gate if (Xflag) { 1578*7c478bd9Sstevel@tonic-gate if (is_in_table(exclude_tbl, longname)) { 1579*7c478bd9Sstevel@tonic-gate if (vflag) { 1580*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 1581*7c478bd9Sstevel@tonic-gate "a %s excluded\n"), longname); 1582*7c478bd9Sstevel@tonic-gate } 1583*7c478bd9Sstevel@tonic-gate goto out; 1584*7c478bd9Sstevel@tonic-gate } 1585*7c478bd9Sstevel@tonic-gate } 1586*7c478bd9Sstevel@tonic-gate 1587*7c478bd9Sstevel@tonic-gate /* 1588*7c478bd9Sstevel@tonic-gate * If the length of the fullname is greater than MAXNAM, 1589*7c478bd9Sstevel@tonic-gate * print out a message and return (unless extended headers are used, 1590*7c478bd9Sstevel@tonic-gate * in which case fullname is limited to PATH_MAX). 1591*7c478bd9Sstevel@tonic-gate */ 1592*7c478bd9Sstevel@tonic-gate 1593*7c478bd9Sstevel@tonic-gate if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) || 1594*7c478bd9Sstevel@tonic-gate (split > PATH_MAX)) { 1595*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1596*7c478bd9Sstevel@tonic-gate "tar: %s: file name too long\n"), longname); 1597*7c478bd9Sstevel@tonic-gate if (errflag) 1598*7c478bd9Sstevel@tonic-gate exitflag = 1; 1599*7c478bd9Sstevel@tonic-gate Errflg = 1; 1600*7c478bd9Sstevel@tonic-gate goto out; 1601*7c478bd9Sstevel@tonic-gate } 1602*7c478bd9Sstevel@tonic-gate 1603*7c478bd9Sstevel@tonic-gate /* 1604*7c478bd9Sstevel@tonic-gate * We split the fullname into prefix and name components if any one 1605*7c478bd9Sstevel@tonic-gate * of three conditions holds: 1606*7c478bd9Sstevel@tonic-gate * -- the length of the fullname exceeds NAMSIZ, 1607*7c478bd9Sstevel@tonic-gate * -- the length of the fullname equals NAMSIZ, and the shortname 1608*7c478bd9Sstevel@tonic-gate * is less than NAMSIZ, (splitting in this case preserves 1609*7c478bd9Sstevel@tonic-gate * compatibility with 5.6 and 5.5.1 tar), or 1610*7c478bd9Sstevel@tonic-gate * -- the length of the fullname equals NAMSIZ, the file is a 1611*7c478bd9Sstevel@tonic-gate * directory and we are not in POSIX-conformant mode (where 1612*7c478bd9Sstevel@tonic-gate * trailing slashes are removed from directories). 1613*7c478bd9Sstevel@tonic-gate */ 1614*7c478bd9Sstevel@tonic-gate if ((split > NAMSIZ) || 1615*7c478bd9Sstevel@tonic-gate (split == NAMSIZ && strlen(shortname) < NAMSIZ) || 1616*7c478bd9Sstevel@tonic-gate (split == NAMSIZ && (stbuf.st_mode & S_IFDIR) && !Pflag)) { 1617*7c478bd9Sstevel@tonic-gate /* 1618*7c478bd9Sstevel@tonic-gate * Since path is limited to PRESIZ characters, look for the 1619*7c478bd9Sstevel@tonic-gate * last slash within PRESIZ + 1 characters only. 1620*7c478bd9Sstevel@tonic-gate */ 1621*7c478bd9Sstevel@tonic-gate (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1)); 1622*7c478bd9Sstevel@tonic-gate tmpbuf = goodbuf; 1623*7c478bd9Sstevel@tonic-gate lastslash = strrchr(tmpbuf, '/'); 1624*7c478bd9Sstevel@tonic-gate if (lastslash == NULL) { 1625*7c478bd9Sstevel@tonic-gate i = split; /* Length of name */ 1626*7c478bd9Sstevel@tonic-gate j = 0; /* Length of prefix */ 1627*7c478bd9Sstevel@tonic-gate goodbuf[0] = '\0'; 1628*7c478bd9Sstevel@tonic-gate } else { 1629*7c478bd9Sstevel@tonic-gate *lastslash = '\0'; /* Terminate the prefix */ 1630*7c478bd9Sstevel@tonic-gate j = strlen(tmpbuf); 1631*7c478bd9Sstevel@tonic-gate i = split - j - 1; 1632*7c478bd9Sstevel@tonic-gate } 1633*7c478bd9Sstevel@tonic-gate /* 1634*7c478bd9Sstevel@tonic-gate * If the filename is greater than NAMSIZ we can't 1635*7c478bd9Sstevel@tonic-gate * archive the file unless we are using extended headers. 1636*7c478bd9Sstevel@tonic-gate */ 1637*7c478bd9Sstevel@tonic-gate if ((i > NAMSIZ) || (i == NAMSIZ && (stbuf.st_mode & S_IFDIR) && 1638*7c478bd9Sstevel@tonic-gate !Pflag)) { 1639*7c478bd9Sstevel@tonic-gate /* Determine which (filename or path) is too long. */ 1640*7c478bd9Sstevel@tonic-gate lastslash = strrchr(longname, '/'); 1641*7c478bd9Sstevel@tonic-gate if (lastslash != NULL) 1642*7c478bd9Sstevel@tonic-gate i = strlen(lastslash + 1); 1643*7c478bd9Sstevel@tonic-gate if (Eflag > 0) { 1644*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_PATH; 1645*7c478bd9Sstevel@tonic-gate Xtarhdr.x_path = longname; 1646*7c478bd9Sstevel@tonic-gate if (i <= NAMSIZ) 1647*7c478bd9Sstevel@tonic-gate (void) strcpy(junkbuf, lastslash + 1); 1648*7c478bd9Sstevel@tonic-gate else 1649*7c478bd9Sstevel@tonic-gate (void) sprintf(junkbuf, "%llu", 1650*7c478bd9Sstevel@tonic-gate xhdr_count + 1); 1651*7c478bd9Sstevel@tonic-gate if (split - i - 1 > PRESIZ) 1652*7c478bd9Sstevel@tonic-gate (void) strcpy(goodbuf, xhdr_dirname); 1653*7c478bd9Sstevel@tonic-gate } else { 1654*7c478bd9Sstevel@tonic-gate if ((i > NAMSIZ) || (i == NAMSIZ && 1655*7c478bd9Sstevel@tonic-gate (stbuf.st_mode & S_IFDIR) && !Pflag)) 1656*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1657*7c478bd9Sstevel@tonic-gate "tar: %s: filename is greater than " 1658*7c478bd9Sstevel@tonic-gate "%d\n"), lastslash == NULL ? 1659*7c478bd9Sstevel@tonic-gate longname : lastslash + 1, NAMSIZ); 1660*7c478bd9Sstevel@tonic-gate else 1661*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1662*7c478bd9Sstevel@tonic-gate "tar: %s: prefix is greater than %d" 1663*7c478bd9Sstevel@tonic-gate "\n"), longname, PRESIZ); 1664*7c478bd9Sstevel@tonic-gate if (errflag) 1665*7c478bd9Sstevel@tonic-gate exitflag = 1; 1666*7c478bd9Sstevel@tonic-gate Errflg = 1; 1667*7c478bd9Sstevel@tonic-gate goto out; 1668*7c478bd9Sstevel@tonic-gate } 1669*7c478bd9Sstevel@tonic-gate } else 1670*7c478bd9Sstevel@tonic-gate (void) strncpy(&junkbuf[0], longname + j + 1, 1671*7c478bd9Sstevel@tonic-gate strlen(longname + j + 1)); 1672*7c478bd9Sstevel@tonic-gate name = junkbuf; 1673*7c478bd9Sstevel@tonic-gate prefix = goodbuf; 1674*7c478bd9Sstevel@tonic-gate } else { 1675*7c478bd9Sstevel@tonic-gate name = longname; 1676*7c478bd9Sstevel@tonic-gate } 1677*7c478bd9Sstevel@tonic-gate if (Aflag) { 1678*7c478bd9Sstevel@tonic-gate if ((prefix != NULL) && (*prefix != '\0')) 1679*7c478bd9Sstevel@tonic-gate while (*prefix == '/') 1680*7c478bd9Sstevel@tonic-gate ++prefix; 1681*7c478bd9Sstevel@tonic-gate else 1682*7c478bd9Sstevel@tonic-gate while (*name == '/') 1683*7c478bd9Sstevel@tonic-gate ++name; 1684*7c478bd9Sstevel@tonic-gate } 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate switch (stbuf.st_mode & S_IFMT) { 1687*7c478bd9Sstevel@tonic-gate case S_IFDIR: 1688*7c478bd9Sstevel@tonic-gate stbuf.st_size = (off_t)0; 1689*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 1690*7c478bd9Sstevel@tonic-gate 1691*7c478bd9Sstevel@tonic-gate if (filetype != XATTR_FILE && Hiddendir == 0) { 1692*7c478bd9Sstevel@tonic-gate i = 0; 1693*7c478bd9Sstevel@tonic-gate cp = buf; 1694*7c478bd9Sstevel@tonic-gate while ((*cp++ = longname[i++])) 1695*7c478bd9Sstevel@tonic-gate ; 1696*7c478bd9Sstevel@tonic-gate *--cp = '/'; 1697*7c478bd9Sstevel@tonic-gate *++cp = 0; 1698*7c478bd9Sstevel@tonic-gate } 1699*7c478bd9Sstevel@tonic-gate if (!oflag) { 1700*7c478bd9Sstevel@tonic-gate tomodes(&stbuf); 1701*7c478bd9Sstevel@tonic-gate if (build_dblock(name, tchar, '5', filetype, 1702*7c478bd9Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) { 1703*7c478bd9Sstevel@tonic-gate goto out; 1704*7c478bd9Sstevel@tonic-gate } 1705*7c478bd9Sstevel@tonic-gate if (!Pflag) { 1706*7c478bd9Sstevel@tonic-gate /* 1707*7c478bd9Sstevel@tonic-gate * Old archives require a slash at the end 1708*7c478bd9Sstevel@tonic-gate * of a directory name. 1709*7c478bd9Sstevel@tonic-gate * 1710*7c478bd9Sstevel@tonic-gate * XXX 1711*7c478bd9Sstevel@tonic-gate * If directory name is too long, will 1712*7c478bd9Sstevel@tonic-gate * slash overfill field? 1713*7c478bd9Sstevel@tonic-gate */ 1714*7c478bd9Sstevel@tonic-gate if (strlen(name) > (unsigned)NAMSIZ-1) { 1715*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1716*7c478bd9Sstevel@tonic-gate "tar: %s: filename is greater " 1717*7c478bd9Sstevel@tonic-gate "than %d\n"), name, NAMSIZ); 1718*7c478bd9Sstevel@tonic-gate if (errflag) 1719*7c478bd9Sstevel@tonic-gate exitflag = 1; 1720*7c478bd9Sstevel@tonic-gate Errflg = 1; 1721*7c478bd9Sstevel@tonic-gate goto out; 1722*7c478bd9Sstevel@tonic-gate } else { 1723*7c478bd9Sstevel@tonic-gate if (strlen(name) == (NAMSIZ - 1)) { 1724*7c478bd9Sstevel@tonic-gate (void) memcpy(dblock.dbuf.name, 1725*7c478bd9Sstevel@tonic-gate name, NAMSIZ); 1726*7c478bd9Sstevel@tonic-gate dblock.dbuf.name[NAMSIZ-1] 1727*7c478bd9Sstevel@tonic-gate = '/'; 1728*7c478bd9Sstevel@tonic-gate } else 1729*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.name, 1730*7c478bd9Sstevel@tonic-gate "%s/", name); 1731*7c478bd9Sstevel@tonic-gate 1732*7c478bd9Sstevel@tonic-gate /* 1733*7c478bd9Sstevel@tonic-gate * need to recalculate checksum 1734*7c478bd9Sstevel@tonic-gate * because the name changed. 1735*7c478bd9Sstevel@tonic-gate */ 1736*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, 1737*7c478bd9Sstevel@tonic-gate "%07o", checksum(&dblock)); 1738*7c478bd9Sstevel@tonic-gate } 1739*7c478bd9Sstevel@tonic-gate } 1740*7c478bd9Sstevel@tonic-gate 1741*7c478bd9Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, prefix, 1742*7c478bd9Sstevel@tonic-gate filetype, '5') != 0) 1743*7c478bd9Sstevel@tonic-gate goto out; 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 1746*7c478bd9Sstevel@tonic-gate /* 1747*7c478bd9Sstevel@tonic-gate * Reset header typeflag when archiving directory, since 1748*7c478bd9Sstevel@tonic-gate * build_dblock changed it on us. 1749*7c478bd9Sstevel@tonic-gate */ 1750*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) { 1751*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = _XATTR_HDRTYPE; 1752*7c478bd9Sstevel@tonic-gate } else { 1753*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = '5'; 1754*7c478bd9Sstevel@tonic-gate } 1755*7c478bd9Sstevel@tonic-gate #else 1756*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = '5'; 1757*7c478bd9Sstevel@tonic-gate #endif 1758*7c478bd9Sstevel@tonic-gate 1759*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", 1760*7c478bd9Sstevel@tonic-gate checksum(&dblock)); 1761*7c478bd9Sstevel@tonic-gate 1762*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 1763*7c478bd9Sstevel@tonic-gate } 1764*7c478bd9Sstevel@tonic-gate if (vflag) { 1765*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1766*7c478bd9Sstevel@tonic-gate if (NotTape) 1767*7c478bd9Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 1768*7c478bd9Sstevel@tonic-gate 0); 1769*7c478bd9Sstevel@tonic-gate #endif 1770*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE && Hiddendir) { 1771*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "a %s attribute . ", 1772*7c478bd9Sstevel@tonic-gate longname); 1773*7c478bd9Sstevel@tonic-gate 1774*7c478bd9Sstevel@tonic-gate } else { 1775*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "a %s/ ", longname); 1776*7c478bd9Sstevel@tonic-gate } 1777*7c478bd9Sstevel@tonic-gate if (NotTape) 1778*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n", 1779*7c478bd9Sstevel@tonic-gate K(blocks)); 1780*7c478bd9Sstevel@tonic-gate else 1781*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" FMT_blkcnt_t 1782*7c478bd9Sstevel@tonic-gate " tape blocks\n"), blocks); 1783*7c478bd9Sstevel@tonic-gate } 1784*7c478bd9Sstevel@tonic-gate 1785*7c478bd9Sstevel@tonic-gate /* 1786*7c478bd9Sstevel@tonic-gate * If hidden dir then break now since xattrs_put() will do 1787*7c478bd9Sstevel@tonic-gate * the iterating of the directory. 1788*7c478bd9Sstevel@tonic-gate * 1789*7c478bd9Sstevel@tonic-gate * At the moment, there can't be attributes on attributes 1790*7c478bd9Sstevel@tonic-gate * or directories within the attributes hidden directory 1791*7c478bd9Sstevel@tonic-gate * hierarchy. 1792*7c478bd9Sstevel@tonic-gate */ 1793*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) 1794*7c478bd9Sstevel@tonic-gate break; 1795*7c478bd9Sstevel@tonic-gate 1796*7c478bd9Sstevel@tonic-gate if (*shortname != '/') 1797*7c478bd9Sstevel@tonic-gate (void) sprintf(newparent, "%s/%s", parent, shortname); 1798*7c478bd9Sstevel@tonic-gate else 1799*7c478bd9Sstevel@tonic-gate (void) sprintf(newparent, "%s", shortname); 1800*7c478bd9Sstevel@tonic-gate 1801*7c478bd9Sstevel@tonic-gate if (chdir(shortname) < 0) { 1802*7c478bd9Sstevel@tonic-gate vperror(0, "%s", newparent); 1803*7c478bd9Sstevel@tonic-gate goto out; 1804*7c478bd9Sstevel@tonic-gate } 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate if ((dirp = opendir(".")) == NULL) { 1807*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 1808*7c478bd9Sstevel@tonic-gate "can't open directory %s"), longname); 1809*7c478bd9Sstevel@tonic-gate if (chdir(parent) < 0) 1810*7c478bd9Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"), 1811*7c478bd9Sstevel@tonic-gate parent); 1812*7c478bd9Sstevel@tonic-gate goto out; 1813*7c478bd9Sstevel@tonic-gate } 1814*7c478bd9Sstevel@tonic-gate 1815*7c478bd9Sstevel@tonic-gate while ((dp = readdir(dirp)) != NULL && !term) { 1816*7c478bd9Sstevel@tonic-gate if ((strcmp(".", dp->d_name) == 0) || 1817*7c478bd9Sstevel@tonic-gate (strcmp("..", dp->d_name) == 0)) 1818*7c478bd9Sstevel@tonic-gate continue; 1819*7c478bd9Sstevel@tonic-gate (void) strcpy(cp, dp->d_name); 1820*7c478bd9Sstevel@tonic-gate if (stat(dp->d_name, &sbuf) < 0 || 1821*7c478bd9Sstevel@tonic-gate (sbuf.st_mode & S_IFMT) == S_IFDIR) { 1822*7c478bd9Sstevel@tonic-gate l = telldir(dirp); 1823*7c478bd9Sstevel@tonic-gate (void) closedir(dirp); 1824*7c478bd9Sstevel@tonic-gate } else 1825*7c478bd9Sstevel@tonic-gate l = -1; 1826*7c478bd9Sstevel@tonic-gate 1827*7c478bd9Sstevel@tonic-gate archtype = putfile(buf, cp, newparent, 1828*7c478bd9Sstevel@tonic-gate NORMAL_FILE, lev + 1, symlink_lev); 1829*7c478bd9Sstevel@tonic-gate 1830*7c478bd9Sstevel@tonic-gate if (!exitflag) { 1831*7c478bd9Sstevel@tonic-gate if (atflag && archtype == PUT_NOTAS_LINK) { 1832*7c478bd9Sstevel@tonic-gate xattrs_put(buf, cp, newparent); 1833*7c478bd9Sstevel@tonic-gate } 1834*7c478bd9Sstevel@tonic-gate } 1835*7c478bd9Sstevel@tonic-gate if (exitflag) 1836*7c478bd9Sstevel@tonic-gate break; 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate /* 1839*7c478bd9Sstevel@tonic-gate * If the directory was not closed, then it does 1840*7c478bd9Sstevel@tonic-gate * not need to be reopened. 1841*7c478bd9Sstevel@tonic-gate */ 1842*7c478bd9Sstevel@tonic-gate if (l < 0) 1843*7c478bd9Sstevel@tonic-gate continue; 1844*7c478bd9Sstevel@tonic-gate if ((dirp = opendir(".")) == NULL) { 1845*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 1846*7c478bd9Sstevel@tonic-gate "can't open directory %s"), longname); 1847*7c478bd9Sstevel@tonic-gate if (chdir(parent) < 0) 1848*7c478bd9Sstevel@tonic-gate vperror(0, 1849*7c478bd9Sstevel@tonic-gate gettext("cannot change back?: %s"), 1850*7c478bd9Sstevel@tonic-gate parent); 1851*7c478bd9Sstevel@tonic-gate goto out; 1852*7c478bd9Sstevel@tonic-gate } 1853*7c478bd9Sstevel@tonic-gate seekdir(dirp, l); 1854*7c478bd9Sstevel@tonic-gate 1855*7c478bd9Sstevel@tonic-gate } 1856*7c478bd9Sstevel@tonic-gate (void) closedir(dirp); 1857*7c478bd9Sstevel@tonic-gate 1858*7c478bd9Sstevel@tonic-gate if (chdir(parent) < 0) { 1859*7c478bd9Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"), parent); 1860*7c478bd9Sstevel@tonic-gate } 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate break; 1863*7c478bd9Sstevel@tonic-gate 1864*7c478bd9Sstevel@tonic-gate case S_IFLNK: 1865*7c478bd9Sstevel@tonic-gate readlink_max = NAMSIZ; 1866*7c478bd9Sstevel@tonic-gate if (stbuf.st_size > NAMSIZ) { 1867*7c478bd9Sstevel@tonic-gate if (Eflag > 0) { 1868*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH; 1869*7c478bd9Sstevel@tonic-gate readlink_max = PATH_MAX; 1870*7c478bd9Sstevel@tonic-gate } else { 1871*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1872*7c478bd9Sstevel@tonic-gate "tar: %s: symbolic link too long\n"), 1873*7c478bd9Sstevel@tonic-gate longname); 1874*7c478bd9Sstevel@tonic-gate if (errflag) 1875*7c478bd9Sstevel@tonic-gate exitflag = 1; 1876*7c478bd9Sstevel@tonic-gate Errflg = 1; 1877*7c478bd9Sstevel@tonic-gate goto out; 1878*7c478bd9Sstevel@tonic-gate } 1879*7c478bd9Sstevel@tonic-gate } 1880*7c478bd9Sstevel@tonic-gate /* 1881*7c478bd9Sstevel@tonic-gate * Sym-links need header size of zero since you 1882*7c478bd9Sstevel@tonic-gate * don't store any data for this type. 1883*7c478bd9Sstevel@tonic-gate */ 1884*7c478bd9Sstevel@tonic-gate stbuf.st_size = (off_t)0; 1885*7c478bd9Sstevel@tonic-gate tomodes(&stbuf); 1886*7c478bd9Sstevel@tonic-gate i = readlink(shortname, filetmp, readlink_max); 1887*7c478bd9Sstevel@tonic-gate if (i < 0) { 1888*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 1889*7c478bd9Sstevel@tonic-gate "can't read symbolic link %s"), longname); 1890*7c478bd9Sstevel@tonic-gate goto out; 1891*7c478bd9Sstevel@tonic-gate } else { 1892*7c478bd9Sstevel@tonic-gate filetmp[i] = 0; 1893*7c478bd9Sstevel@tonic-gate } 1894*7c478bd9Sstevel@tonic-gate if (vflag) 1895*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 1896*7c478bd9Sstevel@tonic-gate "a %s symbolic link to %s\n"), 1897*7c478bd9Sstevel@tonic-gate longname, filetmp); 1898*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) { 1899*7c478bd9Sstevel@tonic-gate Xtarhdr.x_linkpath = filetmp; 1900*7c478bd9Sstevel@tonic-gate if (build_dblock(name, tchar, '2', filetype, &stbuf, 1901*7c478bd9Sstevel@tonic-gate stbuf.st_dev, prefix) != 0) 1902*7c478bd9Sstevel@tonic-gate goto out; 1903*7c478bd9Sstevel@tonic-gate } else 1904*7c478bd9Sstevel@tonic-gate if (build_dblock(name, filetmp, '2', filetype, &stbuf, 1905*7c478bd9Sstevel@tonic-gate stbuf.st_dev, prefix) != 0) 1906*7c478bd9Sstevel@tonic-gate goto out; 1907*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 1908*7c478bd9Sstevel@tonic-gate /* 1909*7c478bd9Sstevel@tonic-gate * No acls for symlinks: mode is always 777 1910*7c478bd9Sstevel@tonic-gate * dont call write ancillary 1911*7c478bd9Sstevel@tonic-gate */ 1912*7c478bd9Sstevel@tonic-gate rc = PUT_AS_LINK; 1913*7c478bd9Sstevel@tonic-gate break; 1914*7c478bd9Sstevel@tonic-gate case S_IFREG: 1915*7c478bd9Sstevel@tonic-gate if ((infile = openat(dirfd, shortname, 0)) < 0) { 1916*7c478bd9Sstevel@tonic-gate vperror(0, "%s%s%s", longname, 1917*7c478bd9Sstevel@tonic-gate (filetype == XATTR_FILE) ? 1918*7c478bd9Sstevel@tonic-gate gettext(" attribute ") : "", 1919*7c478bd9Sstevel@tonic-gate (filetype == XATTR_FILE) ? 1920*7c478bd9Sstevel@tonic-gate shortname : ""); 1921*7c478bd9Sstevel@tonic-gate goto out; 1922*7c478bd9Sstevel@tonic-gate } 1923*7c478bd9Sstevel@tonic-gate 1924*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 1925*7c478bd9Sstevel@tonic-gate 1926*7c478bd9Sstevel@tonic-gate if (put_link(name, longname, shortname, 1927*7c478bd9Sstevel@tonic-gate prefix, filetype, '1') == 0) { 1928*7c478bd9Sstevel@tonic-gate (void) close(infile); 1929*7c478bd9Sstevel@tonic-gate rc = PUT_AS_LINK; 1930*7c478bd9Sstevel@tonic-gate goto out; 1931*7c478bd9Sstevel@tonic-gate } 1932*7c478bd9Sstevel@tonic-gate 1933*7c478bd9Sstevel@tonic-gate tomodes(&stbuf); 1934*7c478bd9Sstevel@tonic-gate 1935*7c478bd9Sstevel@tonic-gate /* correctly handle end of volume */ 1936*7c478bd9Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) { 1937*7c478bd9Sstevel@tonic-gate /* file won't fit */ 1938*7c478bd9Sstevel@tonic-gate if (eflag) { 1939*7c478bd9Sstevel@tonic-gate if (blocks <= blocklim) { 1940*7c478bd9Sstevel@tonic-gate newvol(); 1941*7c478bd9Sstevel@tonic-gate break; 1942*7c478bd9Sstevel@tonic-gate } 1943*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1944*7c478bd9Sstevel@tonic-gate "tar: Single file cannot fit on volume\n")); 1945*7c478bd9Sstevel@tonic-gate done(3); 1946*7c478bd9Sstevel@tonic-gate } 1947*7c478bd9Sstevel@tonic-gate /* split if floppy has some room and file is large */ 1948*7c478bd9Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) && 1949*7c478bd9Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) { 1950*7c478bd9Sstevel@tonic-gate splitfile(longname, infile, 1951*7c478bd9Sstevel@tonic-gate name, prefix, filetype); 1952*7c478bd9Sstevel@tonic-gate (void) close(dirfd); 1953*7c478bd9Sstevel@tonic-gate (void) close(infile); 1954*7c478bd9Sstevel@tonic-gate goto out; 1955*7c478bd9Sstevel@tonic-gate } 1956*7c478bd9Sstevel@tonic-gate newvol(); /* not worth it--just get new volume */ 1957*7c478bd9Sstevel@tonic-gate } 1958*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1959*7c478bd9Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname, 1960*7c478bd9Sstevel@tonic-gate blocks); 1961*7c478bd9Sstevel@tonic-gate #endif 1962*7c478bd9Sstevel@tonic-gate if (build_dblock(name, tchar, '0', filetype, 1963*7c478bd9Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) { 1964*7c478bd9Sstevel@tonic-gate goto out; 1965*7c478bd9Sstevel@tonic-gate } 1966*7c478bd9Sstevel@tonic-gate if (vflag) { 1967*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1968*7c478bd9Sstevel@tonic-gate if (NotTape) 1969*7c478bd9Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 1970*7c478bd9Sstevel@tonic-gate 0); 1971*7c478bd9Sstevel@tonic-gate #endif 1972*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "a %s%s%s ", longname, 1973*7c478bd9Sstevel@tonic-gate (filetype == XATTR_FILE) ? 1974*7c478bd9Sstevel@tonic-gate gettext(" attribute ") : "", 1975*7c478bd9Sstevel@tonic-gate (filetype == XATTR_FILE) ? 1976*7c478bd9Sstevel@tonic-gate shortname : ""); 1977*7c478bd9Sstevel@tonic-gate if (NotTape) 1978*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n", 1979*7c478bd9Sstevel@tonic-gate K(blocks)); 1980*7c478bd9Sstevel@tonic-gate else 1981*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, 1982*7c478bd9Sstevel@tonic-gate gettext("%" FMT_blkcnt_t " tape blocks\n"), 1983*7c478bd9Sstevel@tonic-gate blocks); 1984*7c478bd9Sstevel@tonic-gate } 1985*7c478bd9Sstevel@tonic-gate 1986*7c478bd9Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, prefix, 1987*7c478bd9Sstevel@tonic-gate filetype, '0') != 0) 1988*7c478bd9Sstevel@tonic-gate goto out; 1989*7c478bd9Sstevel@tonic-gate 1990*7c478bd9Sstevel@tonic-gate /* 1991*7c478bd9Sstevel@tonic-gate * No need to reset typeflag for extended attribute here, since 1992*7c478bd9Sstevel@tonic-gate * put_extra_attributes already set it and we haven't called 1993*7c478bd9Sstevel@tonic-gate * build_dblock(). 1994*7c478bd9Sstevel@tonic-gate */ 1995*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 1996*7c478bd9Sstevel@tonic-gate hint = writetbuf((char *)&dblock, 1); 1997*7c478bd9Sstevel@tonic-gate maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 1998*7c478bd9Sstevel@tonic-gate if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) { 1999*7c478bd9Sstevel@tonic-gate maxread = TBLOCK; 2000*7c478bd9Sstevel@tonic-gate bigbuf = buf; 2001*7c478bd9Sstevel@tonic-gate } 2002*7c478bd9Sstevel@tonic-gate 2003*7c478bd9Sstevel@tonic-gate while (((i = (int) 2004*7c478bd9Sstevel@tonic-gate read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) && 2005*7c478bd9Sstevel@tonic-gate blocks) { 2006*7c478bd9Sstevel@tonic-gate blkcnt_t nblks; 2007*7c478bd9Sstevel@tonic-gate 2008*7c478bd9Sstevel@tonic-gate nblks = ((i-1)/TBLOCK)+1; 2009*7c478bd9Sstevel@tonic-gate if (nblks > blocks) 2010*7c478bd9Sstevel@tonic-gate nblks = blocks; 2011*7c478bd9Sstevel@tonic-gate hint = writetbuf(bigbuf, nblks); 2012*7c478bd9Sstevel@tonic-gate blocks -= nblks; 2013*7c478bd9Sstevel@tonic-gate } 2014*7c478bd9Sstevel@tonic-gate (void) close(infile); 2015*7c478bd9Sstevel@tonic-gate if (bigbuf != buf) 2016*7c478bd9Sstevel@tonic-gate free(bigbuf); 2017*7c478bd9Sstevel@tonic-gate if (i < 0) 2018*7c478bd9Sstevel@tonic-gate vperror(0, gettext("Read error on %s"), longname); 2019*7c478bd9Sstevel@tonic-gate else if (blocks != 0 || i != 0) { 2020*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2021*7c478bd9Sstevel@tonic-gate "tar: %s: file changed size\n"), longname); 2022*7c478bd9Sstevel@tonic-gate if (errflag) { 2023*7c478bd9Sstevel@tonic-gate exitflag = 1; 2024*7c478bd9Sstevel@tonic-gate Errflg = 1; 2025*7c478bd9Sstevel@tonic-gate } else if (!Dflag) { 2026*7c478bd9Sstevel@tonic-gate Errflg = 1; 2027*7c478bd9Sstevel@tonic-gate } 2028*7c478bd9Sstevel@tonic-gate } 2029*7c478bd9Sstevel@tonic-gate putempty(blocks); 2030*7c478bd9Sstevel@tonic-gate break; 2031*7c478bd9Sstevel@tonic-gate case S_IFIFO: 2032*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 2033*7c478bd9Sstevel@tonic-gate stbuf.st_size = (off_t)0; 2034*7c478bd9Sstevel@tonic-gate 2035*7c478bd9Sstevel@tonic-gate if (put_link(name, longname, shortname, 2036*7c478bd9Sstevel@tonic-gate prefix, filetype, '6') == 0) { 2037*7c478bd9Sstevel@tonic-gate rc = PUT_AS_LINK; 2038*7c478bd9Sstevel@tonic-gate goto out; 2039*7c478bd9Sstevel@tonic-gate } 2040*7c478bd9Sstevel@tonic-gate tomodes(&stbuf); 2041*7c478bd9Sstevel@tonic-gate 2042*7c478bd9Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) { 2043*7c478bd9Sstevel@tonic-gate if (eflag) { 2044*7c478bd9Sstevel@tonic-gate if (blocks <= blocklim) { 2045*7c478bd9Sstevel@tonic-gate newvol(); 2046*7c478bd9Sstevel@tonic-gate break; 2047*7c478bd9Sstevel@tonic-gate } 2048*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2049*7c478bd9Sstevel@tonic-gate "tar: Single file cannot fit on volume\n")); 2050*7c478bd9Sstevel@tonic-gate done(3); 2051*7c478bd9Sstevel@tonic-gate } 2052*7c478bd9Sstevel@tonic-gate 2053*7c478bd9Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) && 2054*7c478bd9Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) { 2055*7c478bd9Sstevel@tonic-gate splitfile(longname, infile, name, 2056*7c478bd9Sstevel@tonic-gate prefix, filetype); 2057*7c478bd9Sstevel@tonic-gate (void) close(dirfd); 2058*7c478bd9Sstevel@tonic-gate (void) close(infile); 2059*7c478bd9Sstevel@tonic-gate goto out; 2060*7c478bd9Sstevel@tonic-gate } 2061*7c478bd9Sstevel@tonic-gate newvol(); 2062*7c478bd9Sstevel@tonic-gate } 2063*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2064*7c478bd9Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname, 2065*7c478bd9Sstevel@tonic-gate blocks); 2066*7c478bd9Sstevel@tonic-gate #endif 2067*7c478bd9Sstevel@tonic-gate if (vflag) { 2068*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2069*7c478bd9Sstevel@tonic-gate if (NotTape) 2070*7c478bd9Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 2071*7c478bd9Sstevel@tonic-gate 0); 2072*7c478bd9Sstevel@tonic-gate #endif 2073*7c478bd9Sstevel@tonic-gate if (NotTape) 2074*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" 2075*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t "K\n "), longname, K(blocks)); 2076*7c478bd9Sstevel@tonic-gate else 2077*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2078*7c478bd9Sstevel@tonic-gate "a %s %" FMT_blkcnt_t " tape blocks\n"), 2079*7c478bd9Sstevel@tonic-gate longname, blocks); 2080*7c478bd9Sstevel@tonic-gate } 2081*7c478bd9Sstevel@tonic-gate if (build_dblock(name, tchar, '6', filetype, 2082*7c478bd9Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) 2083*7c478bd9Sstevel@tonic-gate goto out; 2084*7c478bd9Sstevel@tonic-gate 2085*7c478bd9Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, prefix, 2086*7c478bd9Sstevel@tonic-gate filetype, '6') != 0) 2087*7c478bd9Sstevel@tonic-gate goto out; 2088*7c478bd9Sstevel@tonic-gate 2089*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 2090*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = '6'; 2091*7c478bd9Sstevel@tonic-gate 2092*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 2093*7c478bd9Sstevel@tonic-gate break; 2094*7c478bd9Sstevel@tonic-gate case S_IFCHR: 2095*7c478bd9Sstevel@tonic-gate stbuf.st_size = (off_t)0; 2096*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 2097*7c478bd9Sstevel@tonic-gate if (put_link(name, longname, 2098*7c478bd9Sstevel@tonic-gate shortname, prefix, filetype, '3') == 0) { 2099*7c478bd9Sstevel@tonic-gate rc = PUT_AS_LINK; 2100*7c478bd9Sstevel@tonic-gate goto out; 2101*7c478bd9Sstevel@tonic-gate } 2102*7c478bd9Sstevel@tonic-gate tomodes(&stbuf); 2103*7c478bd9Sstevel@tonic-gate 2104*7c478bd9Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) { 2105*7c478bd9Sstevel@tonic-gate if (eflag) { 2106*7c478bd9Sstevel@tonic-gate if (blocks <= blocklim) { 2107*7c478bd9Sstevel@tonic-gate newvol(); 2108*7c478bd9Sstevel@tonic-gate break; 2109*7c478bd9Sstevel@tonic-gate } 2110*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2111*7c478bd9Sstevel@tonic-gate "tar: Single file cannot fit on volume\n")); 2112*7c478bd9Sstevel@tonic-gate done(3); 2113*7c478bd9Sstevel@tonic-gate } 2114*7c478bd9Sstevel@tonic-gate 2115*7c478bd9Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) && 2116*7c478bd9Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) { 2117*7c478bd9Sstevel@tonic-gate splitfile(longname, infile, name, 2118*7c478bd9Sstevel@tonic-gate prefix, filetype); 2119*7c478bd9Sstevel@tonic-gate (void) close(dirfd); 2120*7c478bd9Sstevel@tonic-gate goto out; 2121*7c478bd9Sstevel@tonic-gate } 2122*7c478bd9Sstevel@tonic-gate newvol(); 2123*7c478bd9Sstevel@tonic-gate } 2124*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2125*7c478bd9Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname, 2126*7c478bd9Sstevel@tonic-gate blocks); 2127*7c478bd9Sstevel@tonic-gate #endif 2128*7c478bd9Sstevel@tonic-gate if (vflag) { 2129*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2130*7c478bd9Sstevel@tonic-gate if (NotTape) 2131*7c478bd9Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 2132*7c478bd9Sstevel@tonic-gate 0); 2133*7c478bd9Sstevel@tonic-gate #endif 2134*7c478bd9Sstevel@tonic-gate if (NotTape) 2135*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" 2136*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t "K\n"), longname, K(blocks)); 2137*7c478bd9Sstevel@tonic-gate else 2138*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" 2139*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), longname, 2140*7c478bd9Sstevel@tonic-gate blocks); 2141*7c478bd9Sstevel@tonic-gate } 2142*7c478bd9Sstevel@tonic-gate if (build_dblock(name, tchar, '3', 2143*7c478bd9Sstevel@tonic-gate filetype, &stbuf, stbuf.st_rdev, prefix) != 0) 2144*7c478bd9Sstevel@tonic-gate goto out; 2145*7c478bd9Sstevel@tonic-gate 2146*7c478bd9Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, 2147*7c478bd9Sstevel@tonic-gate prefix, filetype, '3') != 0) 2148*7c478bd9Sstevel@tonic-gate goto out; 2149*7c478bd9Sstevel@tonic-gate 2150*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 2151*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = '3'; 2152*7c478bd9Sstevel@tonic-gate 2153*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 2154*7c478bd9Sstevel@tonic-gate break; 2155*7c478bd9Sstevel@tonic-gate case S_IFBLK: 2156*7c478bd9Sstevel@tonic-gate stbuf.st_size = (off_t)0; 2157*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 2158*7c478bd9Sstevel@tonic-gate if (put_link(name, longname, 2159*7c478bd9Sstevel@tonic-gate shortname, prefix, filetype, '4') == 0) { 2160*7c478bd9Sstevel@tonic-gate rc = PUT_AS_LINK; 2161*7c478bd9Sstevel@tonic-gate goto out; 2162*7c478bd9Sstevel@tonic-gate } 2163*7c478bd9Sstevel@tonic-gate tomodes(&stbuf); 2164*7c478bd9Sstevel@tonic-gate 2165*7c478bd9Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) { 2166*7c478bd9Sstevel@tonic-gate if (eflag) { 2167*7c478bd9Sstevel@tonic-gate if (blocks <= blocklim) { 2168*7c478bd9Sstevel@tonic-gate newvol(); 2169*7c478bd9Sstevel@tonic-gate break; 2170*7c478bd9Sstevel@tonic-gate } 2171*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2172*7c478bd9Sstevel@tonic-gate "tar: Single file cannot fit on volume\n")); 2173*7c478bd9Sstevel@tonic-gate done(3); 2174*7c478bd9Sstevel@tonic-gate } 2175*7c478bd9Sstevel@tonic-gate 2176*7c478bd9Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) && 2177*7c478bd9Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) { 2178*7c478bd9Sstevel@tonic-gate splitfile(longname, infile, 2179*7c478bd9Sstevel@tonic-gate name, prefix, filetype); 2180*7c478bd9Sstevel@tonic-gate (void) close(dirfd); 2181*7c478bd9Sstevel@tonic-gate goto out; 2182*7c478bd9Sstevel@tonic-gate } 2183*7c478bd9Sstevel@tonic-gate newvol(); 2184*7c478bd9Sstevel@tonic-gate } 2185*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2186*7c478bd9Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname, 2187*7c478bd9Sstevel@tonic-gate blocks); 2188*7c478bd9Sstevel@tonic-gate #endif 2189*7c478bd9Sstevel@tonic-gate if (vflag) { 2190*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2191*7c478bd9Sstevel@tonic-gate if (NotTape) 2192*7c478bd9Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 2193*7c478bd9Sstevel@tonic-gate 0); 2194*7c478bd9Sstevel@tonic-gate #endif 2195*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "a %s ", longname); 2196*7c478bd9Sstevel@tonic-gate if (NotTape) 2197*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n", 2198*7c478bd9Sstevel@tonic-gate K(blocks)); 2199*7c478bd9Sstevel@tonic-gate else 2200*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2201*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), blocks); 2202*7c478bd9Sstevel@tonic-gate } 2203*7c478bd9Sstevel@tonic-gate if (build_dblock(name, tchar, '4', 2204*7c478bd9Sstevel@tonic-gate filetype, &stbuf, stbuf.st_rdev, prefix) != 0) 2205*7c478bd9Sstevel@tonic-gate goto out; 2206*7c478bd9Sstevel@tonic-gate 2207*7c478bd9Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, 2208*7c478bd9Sstevel@tonic-gate prefix, filetype, '4') != 0) 2209*7c478bd9Sstevel@tonic-gate goto out; 2210*7c478bd9Sstevel@tonic-gate 2211*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 2212*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = '4'; 2213*7c478bd9Sstevel@tonic-gate 2214*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 2215*7c478bd9Sstevel@tonic-gate break; 2216*7c478bd9Sstevel@tonic-gate default: 2217*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2218*7c478bd9Sstevel@tonic-gate "tar: %s is not a file. Not dumped\n"), longname); 2219*7c478bd9Sstevel@tonic-gate if (errflag) 2220*7c478bd9Sstevel@tonic-gate exitflag = 1; 2221*7c478bd9Sstevel@tonic-gate Errflg = 1; 2222*7c478bd9Sstevel@tonic-gate goto out; 2223*7c478bd9Sstevel@tonic-gate } 2224*7c478bd9Sstevel@tonic-gate 2225*7c478bd9Sstevel@tonic-gate out: 2226*7c478bd9Sstevel@tonic-gate if (dirfd != -1) { 2227*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) 2228*7c478bd9Sstevel@tonic-gate (void) chdir(parent); 2229*7c478bd9Sstevel@tonic-gate (void) close(dirfd); 2230*7c478bd9Sstevel@tonic-gate } 2231*7c478bd9Sstevel@tonic-gate return (rc); 2232*7c478bd9Sstevel@tonic-gate } 2233*7c478bd9Sstevel@tonic-gate 2234*7c478bd9Sstevel@tonic-gate 2235*7c478bd9Sstevel@tonic-gate /* 2236*7c478bd9Sstevel@tonic-gate * splitfile dump a large file across volumes 2237*7c478bd9Sstevel@tonic-gate * 2238*7c478bd9Sstevel@tonic-gate * splitfile(longname, fd); 2239*7c478bd9Sstevel@tonic-gate * char *longname; full name of file 2240*7c478bd9Sstevel@tonic-gate * int ifd; input file descriptor 2241*7c478bd9Sstevel@tonic-gate * 2242*7c478bd9Sstevel@tonic-gate * NOTE: only called by putfile() to dump a large file. 2243*7c478bd9Sstevel@tonic-gate */ 2244*7c478bd9Sstevel@tonic-gate 2245*7c478bd9Sstevel@tonic-gate static void 2246*7c478bd9Sstevel@tonic-gate splitfile(char *longname, int ifd, char *name, char *prefix, int filetype) 2247*7c478bd9Sstevel@tonic-gate { 2248*7c478bd9Sstevel@tonic-gate blkcnt_t blocks; 2249*7c478bd9Sstevel@tonic-gate off_t bytes, s; 2250*7c478bd9Sstevel@tonic-gate char buf[TBLOCK]; 2251*7c478bd9Sstevel@tonic-gate int i, extents; 2252*7c478bd9Sstevel@tonic-gate 2253*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */ 2254*7c478bd9Sstevel@tonic-gate 2255*7c478bd9Sstevel@tonic-gate /* 2256*7c478bd9Sstevel@tonic-gate * # extents = 2257*7c478bd9Sstevel@tonic-gate * size of file after using up rest of this floppy 2258*7c478bd9Sstevel@tonic-gate * blocks - (blocklim - tapepos) + 1 (for header) 2259*7c478bd9Sstevel@tonic-gate * plus roundup value before divide by blocklim-1 2260*7c478bd9Sstevel@tonic-gate * + (blocklim - 1) - 1 2261*7c478bd9Sstevel@tonic-gate * all divided by blocklim-1 (one block for each header). 2262*7c478bd9Sstevel@tonic-gate * this gives 2263*7c478bd9Sstevel@tonic-gate * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1) 2264*7c478bd9Sstevel@tonic-gate * which reduces to the expression used. 2265*7c478bd9Sstevel@tonic-gate * one is added to account for this first extent. 2266*7c478bd9Sstevel@tonic-gate * 2267*7c478bd9Sstevel@tonic-gate * When one is dealing with extremely large archives, one may want 2268*7c478bd9Sstevel@tonic-gate * to allow for a large number of extents. This code should be 2269*7c478bd9Sstevel@tonic-gate * revisited to determine if extents should be changed to something 2270*7c478bd9Sstevel@tonic-gate * larger than an int. 2271*7c478bd9Sstevel@tonic-gate */ 2272*7c478bd9Sstevel@tonic-gate extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1); 2273*7c478bd9Sstevel@tonic-gate 2274*7c478bd9Sstevel@tonic-gate if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */ 2275*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2276*7c478bd9Sstevel@tonic-gate "tar: %s needs unusual number of volumes to split\n" 2277*7c478bd9Sstevel@tonic-gate "tar: %s not dumped\n"), longname, longname); 2278*7c478bd9Sstevel@tonic-gate return; 2279*7c478bd9Sstevel@tonic-gate } 2280*7c478bd9Sstevel@tonic-gate if (build_dblock(name, tchar, '0', filetype, 2281*7c478bd9Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) 2282*7c478bd9Sstevel@tonic-gate return; 2283*7c478bd9Sstevel@tonic-gate 2284*7c478bd9Sstevel@tonic-gate dblock.dbuf.extotal = extents; 2285*7c478bd9Sstevel@tonic-gate bytes = stbuf.st_size; 2286*7c478bd9Sstevel@tonic-gate 2287*7c478bd9Sstevel@tonic-gate /* 2288*7c478bd9Sstevel@tonic-gate * The value contained in dblock.dbuf.efsize was formerly used when the 2289*7c478bd9Sstevel@tonic-gate * v flag was specified in conjunction with the t flag. Although it is 2290*7c478bd9Sstevel@tonic-gate * no longer used, older versions of tar will expect the former 2291*7c478bd9Sstevel@tonic-gate * behaviour, so we must continue to write it to the archive. 2292*7c478bd9Sstevel@tonic-gate * 2293*7c478bd9Sstevel@tonic-gate * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it 2294*7c478bd9Sstevel@tonic-gate * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply 2295*7c478bd9Sstevel@tonic-gate * store 0. 2296*7c478bd9Sstevel@tonic-gate */ 2297*7c478bd9Sstevel@tonic-gate if (bytes <= TAR_EFSIZE_MAX) 2298*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes); 2299*7c478bd9Sstevel@tonic-gate else 2300*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0); 2301*7c478bd9Sstevel@tonic-gate 2302*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2303*7c478bd9Sstevel@tonic-gate "tar: large file %s needs %d extents.\n" 2304*7c478bd9Sstevel@tonic-gate "tar: current device seek position = %" FMT_blkcnt_t "K\n"), 2305*7c478bd9Sstevel@tonic-gate longname, extents, K(tapepos)); 2306*7c478bd9Sstevel@tonic-gate 2307*7c478bd9Sstevel@tonic-gate s = (off_t)(blocklim - tapepos - 1) * TBLOCK; 2308*7c478bd9Sstevel@tonic-gate for (i = 1; i <= extents; i++) { 2309*7c478bd9Sstevel@tonic-gate if (i > 1) { 2310*7c478bd9Sstevel@tonic-gate newvol(); 2311*7c478bd9Sstevel@tonic-gate if (i == extents) 2312*7c478bd9Sstevel@tonic-gate s = bytes; /* last ext. gets true bytes */ 2313*7c478bd9Sstevel@tonic-gate else 2314*7c478bd9Sstevel@tonic-gate s = (off_t)(blocklim - 1)*TBLOCK; /* all */ 2315*7c478bd9Sstevel@tonic-gate } 2316*7c478bd9Sstevel@tonic-gate bytes -= s; 2317*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(s); 2318*7c478bd9Sstevel@tonic-gate 2319*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s); 2320*7c478bd9Sstevel@tonic-gate dblock.dbuf.extno = i; 2321*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 2322*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 2323*7c478bd9Sstevel@tonic-gate 2324*7c478bd9Sstevel@tonic-gate if (vflag) 2325*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, 2326*7c478bd9Sstevel@tonic-gate "+++ a %s %" FMT_blkcnt_t "K [extent #%d of %d]\n", 2327*7c478bd9Sstevel@tonic-gate longname, K(blocks), i, extents); 2328*7c478bd9Sstevel@tonic-gate while (blocks && read(ifd, buf, TBLOCK) > 0) { 2329*7c478bd9Sstevel@tonic-gate blocks--; 2330*7c478bd9Sstevel@tonic-gate (void) writetbuf(buf, 1); 2331*7c478bd9Sstevel@tonic-gate } 2332*7c478bd9Sstevel@tonic-gate if (blocks != 0) { 2333*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2334*7c478bd9Sstevel@tonic-gate "tar: %s: file changed size\n"), longname); 2335*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2336*7c478bd9Sstevel@tonic-gate "tar: aborting split file %s\n"), longname); 2337*7c478bd9Sstevel@tonic-gate (void) close(ifd); 2338*7c478bd9Sstevel@tonic-gate return; 2339*7c478bd9Sstevel@tonic-gate } 2340*7c478bd9Sstevel@tonic-gate } 2341*7c478bd9Sstevel@tonic-gate (void) close(ifd); 2342*7c478bd9Sstevel@tonic-gate if (vflag) 2343*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d " 2344*7c478bd9Sstevel@tonic-gate "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)), 2345*7c478bd9Sstevel@tonic-gate extents); 2346*7c478bd9Sstevel@tonic-gate } 2347*7c478bd9Sstevel@tonic-gate 2348*7c478bd9Sstevel@tonic-gate /* 2349*7c478bd9Sstevel@tonic-gate * convtoreg - determines whether the file should be converted to a 2350*7c478bd9Sstevel@tonic-gate * regular file when extracted 2351*7c478bd9Sstevel@tonic-gate * 2352*7c478bd9Sstevel@tonic-gate * Returns 1 when file size > 0 and typeflag is not recognized 2353*7c478bd9Sstevel@tonic-gate * Otherwise returns 0 2354*7c478bd9Sstevel@tonic-gate */ 2355*7c478bd9Sstevel@tonic-gate static int 2356*7c478bd9Sstevel@tonic-gate convtoreg(off_t size) 2357*7c478bd9Sstevel@tonic-gate { 2358*7c478bd9Sstevel@tonic-gate if ((size > 0) && (dblock.dbuf.typeflag != '0') && 2359*7c478bd9Sstevel@tonic-gate (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') && 2360*7c478bd9Sstevel@tonic-gate (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') && 2361*7c478bd9Sstevel@tonic-gate (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') && 2362*7c478bd9Sstevel@tonic-gate (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') && 2363*7c478bd9Sstevel@tonic-gate (dblock.dbuf.typeflag != _XATTR_HDRTYPE) && 2364*7c478bd9Sstevel@tonic-gate (dblock.dbuf.typeflag != 'X')) { 2365*7c478bd9Sstevel@tonic-gate return (1); 2366*7c478bd9Sstevel@tonic-gate } 2367*7c478bd9Sstevel@tonic-gate return (0); 2368*7c478bd9Sstevel@tonic-gate } 2369*7c478bd9Sstevel@tonic-gate 2370*7c478bd9Sstevel@tonic-gate static void 2371*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 2372*7c478bd9Sstevel@tonic-gate doxtract(char *argv[], int tbl_cnt) 2373*7c478bd9Sstevel@tonic-gate #else 2374*7c478bd9Sstevel@tonic-gate doxtract(char *argv[]) 2375*7c478bd9Sstevel@tonic-gate #endif 2376*7c478bd9Sstevel@tonic-gate { 2377*7c478bd9Sstevel@tonic-gate struct stat xtractbuf; /* stat on file after extracting */ 2378*7c478bd9Sstevel@tonic-gate blkcnt_t blocks; 2379*7c478bd9Sstevel@tonic-gate off_t bytes; 2380*7c478bd9Sstevel@tonic-gate int ofile; 2381*7c478bd9Sstevel@tonic-gate int newfile; /* Does the file already exist */ 2382*7c478bd9Sstevel@tonic-gate int xcnt = 0; /* count # files extracted */ 2383*7c478bd9Sstevel@tonic-gate int fcnt = 0; /* count # files in argv list */ 2384*7c478bd9Sstevel@tonic-gate int dir; 2385*7c478bd9Sstevel@tonic-gate int dirfd = -1; 2386*7c478bd9Sstevel@tonic-gate uid_t Uid; 2387*7c478bd9Sstevel@tonic-gate char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */ 2388*7c478bd9Sstevel@tonic-gate char dirname[PATH_MAX+1]; 2389*7c478bd9Sstevel@tonic-gate char templink[PATH_MAX+1]; /* temp link with terminating NULL */ 2390*7c478bd9Sstevel@tonic-gate char origdir[PATH_MAX+1]; 2391*7c478bd9Sstevel@tonic-gate int once = 1; 2392*7c478bd9Sstevel@tonic-gate int error; 2393*7c478bd9Sstevel@tonic-gate int symflag; 2394*7c478bd9Sstevel@tonic-gate int want; 2395*7c478bd9Sstevel@tonic-gate aclent_t *aclp = NULL; /* acl buffer pointer */ 2396*7c478bd9Sstevel@tonic-gate int aclcnt = 0; /* acl entries count */ 2397*7c478bd9Sstevel@tonic-gate timestruc_t time_zero; /* used for call to doDirTimes */ 2398*7c478bd9Sstevel@tonic-gate int dircreate; 2399*7c478bd9Sstevel@tonic-gate int convflag; 2400*7c478bd9Sstevel@tonic-gate 2401*7c478bd9Sstevel@tonic-gate time_zero.tv_sec = 0; 2402*7c478bd9Sstevel@tonic-gate time_zero.tv_nsec = 0; 2403*7c478bd9Sstevel@tonic-gate 2404*7c478bd9Sstevel@tonic-gate dumping = 0; /* for newvol(), et al: we are not writing */ 2405*7c478bd9Sstevel@tonic-gate 2406*7c478bd9Sstevel@tonic-gate /* 2407*7c478bd9Sstevel@tonic-gate * Count the number of files that are to be extracted 2408*7c478bd9Sstevel@tonic-gate */ 2409*7c478bd9Sstevel@tonic-gate Uid = getuid(); 2410*7c478bd9Sstevel@tonic-gate 2411*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 2412*7c478bd9Sstevel@tonic-gate initarg(argv, Filefile); 2413*7c478bd9Sstevel@tonic-gate while (nextarg() != NULL) 2414*7c478bd9Sstevel@tonic-gate ++fcnt; 2415*7c478bd9Sstevel@tonic-gate fcnt += tbl_cnt; 2416*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 2417*7c478bd9Sstevel@tonic-gate 2418*7c478bd9Sstevel@tonic-gate for (;;) { 2419*7c478bd9Sstevel@tonic-gate convflag = 0; 2420*7c478bd9Sstevel@tonic-gate symflag = 0; 2421*7c478bd9Sstevel@tonic-gate dir = 0; 2422*7c478bd9Sstevel@tonic-gate ofile = -1; 2423*7c478bd9Sstevel@tonic-gate 2424*7c478bd9Sstevel@tonic-gate /* namep is set by wantit to point to the full name */ 2425*7c478bd9Sstevel@tonic-gate if ((want = wantit(argv, &namep, &dirp, &comp)) == 0) { 2426*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2427*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2428*7c478bd9Sstevel@tonic-gate free(xattrhead); 2429*7c478bd9Sstevel@tonic-gate xattrp = NULL; 2430*7c478bd9Sstevel@tonic-gate xattr_linkp = NULL; 2431*7c478bd9Sstevel@tonic-gate xattrhead = NULL; 2432*7c478bd9Sstevel@tonic-gate } 2433*7c478bd9Sstevel@tonic-gate #endif 2434*7c478bd9Sstevel@tonic-gate continue; 2435*7c478bd9Sstevel@tonic-gate } 2436*7c478bd9Sstevel@tonic-gate if (want == -1) 2437*7c478bd9Sstevel@tonic-gate break; 2438*7c478bd9Sstevel@tonic-gate 2439*7c478bd9Sstevel@tonic-gate if (dirfd != -1) 2440*7c478bd9Sstevel@tonic-gate (void) close(dirfd); 2441*7c478bd9Sstevel@tonic-gate 2442*7c478bd9Sstevel@tonic-gate (void) strcpy(&dirname[0], namep); 2443*7c478bd9Sstevel@tonic-gate dircreate = checkdir(&dirname[0]); 2444*7c478bd9Sstevel@tonic-gate 2445*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2446*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2447*7c478bd9Sstevel@tonic-gate dirfd = attropen(dirp, ".", O_RDONLY); 2448*7c478bd9Sstevel@tonic-gate } else { 2449*7c478bd9Sstevel@tonic-gate dirfd = open(dirp, O_RDONLY); 2450*7c478bd9Sstevel@tonic-gate } 2451*7c478bd9Sstevel@tonic-gate #else 2452*7c478bd9Sstevel@tonic-gate dirfd = open(dirp, O_RDONLY); 2453*7c478bd9Sstevel@tonic-gate #endif 2454*7c478bd9Sstevel@tonic-gate 2455*7c478bd9Sstevel@tonic-gate if (dirfd == -1) { 2456*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2457*7c478bd9Sstevel@tonic-gate if (xattrp) { 2458*7c478bd9Sstevel@tonic-gate dirfd = retry_attrdir_open(dirp); 2459*7c478bd9Sstevel@tonic-gate } 2460*7c478bd9Sstevel@tonic-gate #endif 2461*7c478bd9Sstevel@tonic-gate if (dirfd == -1) { 2462*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2463*7c478bd9Sstevel@tonic-gate "tar: cannot open %s %s\n"), dirp, 2464*7c478bd9Sstevel@tonic-gate strerror(errno)); 2465*7c478bd9Sstevel@tonic-gate passtape(); 2466*7c478bd9Sstevel@tonic-gate continue; 2467*7c478bd9Sstevel@tonic-gate } 2468*7c478bd9Sstevel@tonic-gate } 2469*7c478bd9Sstevel@tonic-gate 2470*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) 2471*7c478bd9Sstevel@tonic-gate (void) strcpy(templink, Xtarhdr.x_linkpath); 2472*7c478bd9Sstevel@tonic-gate else { 2473*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2474*7c478bd9Sstevel@tonic-gate if (xattrp && dblock.dbuf.typeflag == '1') { 2475*7c478bd9Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 2476*7c478bd9Sstevel@tonic-gate xattrp->h_names); 2477*7c478bd9Sstevel@tonic-gate } else { 2478*7c478bd9Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 2479*7c478bd9Sstevel@tonic-gate dblock.dbuf.linkname); 2480*7c478bd9Sstevel@tonic-gate } 2481*7c478bd9Sstevel@tonic-gate #else 2482*7c478bd9Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 2483*7c478bd9Sstevel@tonic-gate dblock.dbuf.linkname); 2484*7c478bd9Sstevel@tonic-gate #endif 2485*7c478bd9Sstevel@tonic-gate } 2486*7c478bd9Sstevel@tonic-gate 2487*7c478bd9Sstevel@tonic-gate if (Fflag) { 2488*7c478bd9Sstevel@tonic-gate char *s; 2489*7c478bd9Sstevel@tonic-gate 2490*7c478bd9Sstevel@tonic-gate if ((s = strrchr(namep, '/')) == 0) 2491*7c478bd9Sstevel@tonic-gate s = namep; 2492*7c478bd9Sstevel@tonic-gate 2493*7c478bd9Sstevel@tonic-gate else 2494*7c478bd9Sstevel@tonic-gate s++; 2495*7c478bd9Sstevel@tonic-gate if (checkf(s, stbuf.st_mode, Fflag) == 0) { 2496*7c478bd9Sstevel@tonic-gate passtape(); 2497*7c478bd9Sstevel@tonic-gate continue; 2498*7c478bd9Sstevel@tonic-gate } 2499*7c478bd9Sstevel@tonic-gate } 2500*7c478bd9Sstevel@tonic-gate 2501*7c478bd9Sstevel@tonic-gate if (checkw('x', namep) == 0) { 2502*7c478bd9Sstevel@tonic-gate passtape(); 2503*7c478bd9Sstevel@tonic-gate continue; 2504*7c478bd9Sstevel@tonic-gate } 2505*7c478bd9Sstevel@tonic-gate if (once) { 2506*7c478bd9Sstevel@tonic-gate if (strcmp(dblock.dbuf.magic, magic_type) == 0) { 2507*7c478bd9Sstevel@tonic-gate if (geteuid() == (uid_t)0) { 2508*7c478bd9Sstevel@tonic-gate checkflag = 1; 2509*7c478bd9Sstevel@tonic-gate pflag = 1; 2510*7c478bd9Sstevel@tonic-gate } else { 2511*7c478bd9Sstevel@tonic-gate /* get file creation mask */ 2512*7c478bd9Sstevel@tonic-gate Oumask = umask(0); 2513*7c478bd9Sstevel@tonic-gate (void) umask(Oumask); 2514*7c478bd9Sstevel@tonic-gate } 2515*7c478bd9Sstevel@tonic-gate once = 0; 2516*7c478bd9Sstevel@tonic-gate } else { 2517*7c478bd9Sstevel@tonic-gate if (geteuid() == (uid_t)0) { 2518*7c478bd9Sstevel@tonic-gate pflag = 1; 2519*7c478bd9Sstevel@tonic-gate checkflag = 2; 2520*7c478bd9Sstevel@tonic-gate } 2521*7c478bd9Sstevel@tonic-gate if (!pflag) { 2522*7c478bd9Sstevel@tonic-gate /* get file creation mask */ 2523*7c478bd9Sstevel@tonic-gate Oumask = umask(0); 2524*7c478bd9Sstevel@tonic-gate (void) umask(Oumask); 2525*7c478bd9Sstevel@tonic-gate } 2526*7c478bd9Sstevel@tonic-gate once = 0; 2527*7c478bd9Sstevel@tonic-gate } 2528*7c478bd9Sstevel@tonic-gate } 2529*7c478bd9Sstevel@tonic-gate 2530*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2531*7c478bd9Sstevel@tonic-gate /* 2532*7c478bd9Sstevel@tonic-gate * Handle extraction of hidden attr dir. 2533*7c478bd9Sstevel@tonic-gate * Dir is automatically created, we only 2534*7c478bd9Sstevel@tonic-gate * need to update mode and perm's. 2535*7c478bd9Sstevel@tonic-gate */ 2536*7c478bd9Sstevel@tonic-gate if ((xattrp != (struct xattr_buf *)NULL) && Hiddendir == 1) { 2537*7c478bd9Sstevel@tonic-gate if (fchownat(dirfd, ".", stbuf.st_uid, 2538*7c478bd9Sstevel@tonic-gate stbuf.st_gid, 0) != 0) { 2539*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 2540*7c478bd9Sstevel@tonic-gate "%s: failed to set ownership of attribute" 2541*7c478bd9Sstevel@tonic-gate " directory"), namep); 2542*7c478bd9Sstevel@tonic-gate } 2543*7c478bd9Sstevel@tonic-gate 2544*7c478bd9Sstevel@tonic-gate if (fchmod(dirfd, stbuf.st_mode) != 0) { 2545*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 2546*7c478bd9Sstevel@tonic-gate "%s: failed to set permissions of" 2547*7c478bd9Sstevel@tonic-gate " attribute directory"), namep); 2548*7c478bd9Sstevel@tonic-gate } 2549*7c478bd9Sstevel@tonic-gate goto filedone; 2550*7c478bd9Sstevel@tonic-gate } 2551*7c478bd9Sstevel@tonic-gate #endif 2552*7c478bd9Sstevel@tonic-gate 2553*7c478bd9Sstevel@tonic-gate if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) { 2554*7c478bd9Sstevel@tonic-gate dir = 1; 2555*7c478bd9Sstevel@tonic-gate if (vflag) { 2556*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "x %s, 0 bytes, ", 2557*7c478bd9Sstevel@tonic-gate &dirname[0]); 2558*7c478bd9Sstevel@tonic-gate if (NotTape) 2559*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "0K\n"); 2560*7c478bd9Sstevel@tonic-gate else 2561*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2562*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), 2563*7c478bd9Sstevel@tonic-gate (blkcnt_t)0); 2564*7c478bd9Sstevel@tonic-gate } 2565*7c478bd9Sstevel@tonic-gate goto filedone; 2566*7c478bd9Sstevel@tonic-gate } 2567*7c478bd9Sstevel@tonic-gate 2568*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '6') { /* FIFO */ 2569*7c478bd9Sstevel@tonic-gate if (rmdir(namep) < 0) { 2570*7c478bd9Sstevel@tonic-gate if (errno == ENOTDIR) 2571*7c478bd9Sstevel@tonic-gate (void) unlink(namep); 2572*7c478bd9Sstevel@tonic-gate } 2573*7c478bd9Sstevel@tonic-gate linkp = templink; 2574*7c478bd9Sstevel@tonic-gate if (*linkp != NULL) { 2575*7c478bd9Sstevel@tonic-gate if (Aflag && *linkp == '/') 2576*7c478bd9Sstevel@tonic-gate linkp++; 2577*7c478bd9Sstevel@tonic-gate if (link(linkp, namep) < 0) { 2578*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2579*7c478bd9Sstevel@tonic-gate "tar: %s: cannot link\n"), namep); 2580*7c478bd9Sstevel@tonic-gate continue; 2581*7c478bd9Sstevel@tonic-gate } 2582*7c478bd9Sstevel@tonic-gate if (vflag) 2583*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2584*7c478bd9Sstevel@tonic-gate "%s linked to %s\n"), namep, linkp); 2585*7c478bd9Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2586*7c478bd9Sstevel@tonic-gate continue; 2587*7c478bd9Sstevel@tonic-gate } 2588*7c478bd9Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFIFO), 2589*7c478bd9Sstevel@tonic-gate (int)Gen.g_devmajor) < 0) { 2590*7c478bd9Sstevel@tonic-gate vperror(0, gettext("%s: mknod failed"), namep); 2591*7c478bd9Sstevel@tonic-gate continue; 2592*7c478bd9Sstevel@tonic-gate } 2593*7c478bd9Sstevel@tonic-gate bytes = stbuf.st_size; 2594*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2595*7c478bd9Sstevel@tonic-gate if (vflag) { 2596*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "x %s, %" FMT_off_t 2597*7c478bd9Sstevel@tonic-gate " bytes, ", namep, bytes); 2598*7c478bd9Sstevel@tonic-gate if (NotTape) 2599*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t 2600*7c478bd9Sstevel@tonic-gate "K\n", K(blocks)); 2601*7c478bd9Sstevel@tonic-gate else 2602*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2603*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), 2604*7c478bd9Sstevel@tonic-gate blocks); 2605*7c478bd9Sstevel@tonic-gate } 2606*7c478bd9Sstevel@tonic-gate goto filedone; 2607*7c478bd9Sstevel@tonic-gate } 2608*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */ 2609*7c478bd9Sstevel@tonic-gate if (rmdir(namep) < 0) { 2610*7c478bd9Sstevel@tonic-gate if (errno == ENOTDIR) 2611*7c478bd9Sstevel@tonic-gate (void) unlink(namep); 2612*7c478bd9Sstevel@tonic-gate } 2613*7c478bd9Sstevel@tonic-gate linkp = templink; 2614*7c478bd9Sstevel@tonic-gate if (*linkp != NULL) { 2615*7c478bd9Sstevel@tonic-gate if (Aflag && *linkp == '/') 2616*7c478bd9Sstevel@tonic-gate linkp++; 2617*7c478bd9Sstevel@tonic-gate if (link(linkp, namep) < 0) { 2618*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2619*7c478bd9Sstevel@tonic-gate "tar: %s: cannot link\n"), namep); 2620*7c478bd9Sstevel@tonic-gate continue; 2621*7c478bd9Sstevel@tonic-gate } 2622*7c478bd9Sstevel@tonic-gate if (vflag) 2623*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2624*7c478bd9Sstevel@tonic-gate "%s linked to %s\n"), namep, linkp); 2625*7c478bd9Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2626*7c478bd9Sstevel@tonic-gate continue; 2627*7c478bd9Sstevel@tonic-gate } 2628*7c478bd9Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFCHR), 2629*7c478bd9Sstevel@tonic-gate (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) { 2630*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 2631*7c478bd9Sstevel@tonic-gate "%s: mknod failed"), namep); 2632*7c478bd9Sstevel@tonic-gate continue; 2633*7c478bd9Sstevel@tonic-gate } 2634*7c478bd9Sstevel@tonic-gate bytes = stbuf.st_size; 2635*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2636*7c478bd9Sstevel@tonic-gate if (vflag) { 2637*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "x %s, %" FMT_off_t 2638*7c478bd9Sstevel@tonic-gate " bytes, ", namep, bytes); 2639*7c478bd9Sstevel@tonic-gate if (NotTape) 2640*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t 2641*7c478bd9Sstevel@tonic-gate "K\n", K(blocks)); 2642*7c478bd9Sstevel@tonic-gate else 2643*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2644*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), 2645*7c478bd9Sstevel@tonic-gate blocks); 2646*7c478bd9Sstevel@tonic-gate } 2647*7c478bd9Sstevel@tonic-gate goto filedone; 2648*7c478bd9Sstevel@tonic-gate } else if (dblock.dbuf.typeflag == '3' && Uid) { 2649*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2650*7c478bd9Sstevel@tonic-gate "Can't create special %s\n"), namep); 2651*7c478bd9Sstevel@tonic-gate continue; 2652*7c478bd9Sstevel@tonic-gate } 2653*7c478bd9Sstevel@tonic-gate 2654*7c478bd9Sstevel@tonic-gate /* BLOCK SPECIAL */ 2655*7c478bd9Sstevel@tonic-gate 2656*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '4' && !Uid) { 2657*7c478bd9Sstevel@tonic-gate if (rmdir(namep) < 0) { 2658*7c478bd9Sstevel@tonic-gate if (errno == ENOTDIR) 2659*7c478bd9Sstevel@tonic-gate (void) unlink(namep); 2660*7c478bd9Sstevel@tonic-gate } 2661*7c478bd9Sstevel@tonic-gate linkp = templink; 2662*7c478bd9Sstevel@tonic-gate if (*linkp != NULL) { 2663*7c478bd9Sstevel@tonic-gate if (Aflag && *linkp == '/') 2664*7c478bd9Sstevel@tonic-gate linkp++; 2665*7c478bd9Sstevel@tonic-gate if (link(linkp, namep) < 0) { 2666*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2667*7c478bd9Sstevel@tonic-gate "tar: %s: cannot link\n"), namep); 2668*7c478bd9Sstevel@tonic-gate continue; 2669*7c478bd9Sstevel@tonic-gate } 2670*7c478bd9Sstevel@tonic-gate if (vflag) 2671*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2672*7c478bd9Sstevel@tonic-gate "%s linked to %s\n"), namep, linkp); 2673*7c478bd9Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2674*7c478bd9Sstevel@tonic-gate continue; 2675*7c478bd9Sstevel@tonic-gate } 2676*7c478bd9Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFBLK), 2677*7c478bd9Sstevel@tonic-gate (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) { 2678*7c478bd9Sstevel@tonic-gate vperror(0, gettext("%s: mknod failed"), namep); 2679*7c478bd9Sstevel@tonic-gate continue; 2680*7c478bd9Sstevel@tonic-gate } 2681*7c478bd9Sstevel@tonic-gate bytes = stbuf.st_size; 2682*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2683*7c478bd9Sstevel@tonic-gate if (vflag) { 2684*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("x %s, %" 2685*7c478bd9Sstevel@tonic-gate FMT_off_t " bytes, "), namep, bytes); 2686*7c478bd9Sstevel@tonic-gate if (NotTape) 2687*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t 2688*7c478bd9Sstevel@tonic-gate "K\n", K(blocks)); 2689*7c478bd9Sstevel@tonic-gate else 2690*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2691*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), 2692*7c478bd9Sstevel@tonic-gate blocks); 2693*7c478bd9Sstevel@tonic-gate } 2694*7c478bd9Sstevel@tonic-gate goto filedone; 2695*7c478bd9Sstevel@tonic-gate } else if (dblock.dbuf.typeflag == '4' && Uid) { 2696*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2697*7c478bd9Sstevel@tonic-gate gettext("Can't create special %s\n"), namep); 2698*7c478bd9Sstevel@tonic-gate continue; 2699*7c478bd9Sstevel@tonic-gate } 2700*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2') { /* symlink */ 2701*7c478bd9Sstevel@tonic-gate linkp = templink; 2702*7c478bd9Sstevel@tonic-gate if (Aflag && *linkp == '/') 2703*7c478bd9Sstevel@tonic-gate linkp++; 2704*7c478bd9Sstevel@tonic-gate if (rmdir(namep) < 0) { 2705*7c478bd9Sstevel@tonic-gate if (errno == ENOTDIR) 2706*7c478bd9Sstevel@tonic-gate (void) unlink(namep); 2707*7c478bd9Sstevel@tonic-gate } 2708*7c478bd9Sstevel@tonic-gate if (symlink(linkp, namep) < 0) { 2709*7c478bd9Sstevel@tonic-gate vperror(0, gettext("%s: symbolic link failed"), 2710*7c478bd9Sstevel@tonic-gate namep); 2711*7c478bd9Sstevel@tonic-gate continue; 2712*7c478bd9Sstevel@tonic-gate } 2713*7c478bd9Sstevel@tonic-gate if (vflag) 2714*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2715*7c478bd9Sstevel@tonic-gate "x %s symbolic link to %s\n"), 2716*7c478bd9Sstevel@tonic-gate namep, linkp); 2717*7c478bd9Sstevel@tonic-gate 2718*7c478bd9Sstevel@tonic-gate symflag = AT_SYMLINK_NOFOLLOW; 2719*7c478bd9Sstevel@tonic-gate goto filedone; 2720*7c478bd9Sstevel@tonic-gate } 2721*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1') { 2722*7c478bd9Sstevel@tonic-gate linkp = templink; 2723*7c478bd9Sstevel@tonic-gate if (Aflag && *linkp == '/') 2724*7c478bd9Sstevel@tonic-gate linkp++; 2725*7c478bd9Sstevel@tonic-gate if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) { 2726*7c478bd9Sstevel@tonic-gate if (errno == ENOTDIR) 2727*7c478bd9Sstevel@tonic-gate (void) unlinkat(dirfd, comp, 0); 2728*7c478bd9Sstevel@tonic-gate } 2729*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2730*7c478bd9Sstevel@tonic-gate if (xattrp && xattr_linkp) { 2731*7c478bd9Sstevel@tonic-gate if (getcwd(origdir, (PATH_MAX+1)) == 2732*7c478bd9Sstevel@tonic-gate (char *)NULL) { 2733*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 2734*7c478bd9Sstevel@tonic-gate "A parent directory cannot" 2735*7c478bd9Sstevel@tonic-gate " be read")); 2736*7c478bd9Sstevel@tonic-gate exit(1); 2737*7c478bd9Sstevel@tonic-gate } 2738*7c478bd9Sstevel@tonic-gate 2739*7c478bd9Sstevel@tonic-gate if (fchdir(dirfd) < 0) { 2740*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 2741*7c478bd9Sstevel@tonic-gate "Cannot fchdir to attribute " 2742*7c478bd9Sstevel@tonic-gate "directory")); 2743*7c478bd9Sstevel@tonic-gate exit(1); 2744*7c478bd9Sstevel@tonic-gate } 2745*7c478bd9Sstevel@tonic-gate 2746*7c478bd9Sstevel@tonic-gate error = link(xattr_linkaname, xattraname); 2747*7c478bd9Sstevel@tonic-gate if (chdir(origdir) < 0) { 2748*7c478bd9Sstevel@tonic-gate vperror(0, gettext( 2749*7c478bd9Sstevel@tonic-gate "Cannot chdir out of attribute " 2750*7c478bd9Sstevel@tonic-gate "directory")); 2751*7c478bd9Sstevel@tonic-gate exit(1); 2752*7c478bd9Sstevel@tonic-gate } 2753*7c478bd9Sstevel@tonic-gate } else { 2754*7c478bd9Sstevel@tonic-gate error = link(linkp, namep); 2755*7c478bd9Sstevel@tonic-gate } 2756*7c478bd9Sstevel@tonic-gate #else 2757*7c478bd9Sstevel@tonic-gate error = link(linkp, namep); 2758*7c478bd9Sstevel@tonic-gate #endif 2759*7c478bd9Sstevel@tonic-gate 2760*7c478bd9Sstevel@tonic-gate if (error < 0) { 2761*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2762*7c478bd9Sstevel@tonic-gate "tar: %s%s%s: cannot link\n"), 2763*7c478bd9Sstevel@tonic-gate namep, (xattr_linkp != NULL) ? 2764*7c478bd9Sstevel@tonic-gate gettext(" attribute ") : "", 2765*7c478bd9Sstevel@tonic-gate (xattr_linkp != NULL) ? 2766*7c478bd9Sstevel@tonic-gate xattraname : ""); 2767*7c478bd9Sstevel@tonic-gate continue; 2768*7c478bd9Sstevel@tonic-gate } 2769*7c478bd9Sstevel@tonic-gate if (vflag) 2770*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2771*7c478bd9Sstevel@tonic-gate "%s%s%s linked to %s%s%s\n"), namep, 2772*7c478bd9Sstevel@tonic-gate (xattr_linkp != NULL) ? 2773*7c478bd9Sstevel@tonic-gate gettext(" attribute ") : "", 2774*7c478bd9Sstevel@tonic-gate (xattr_linkp != NULL) ? 2775*7c478bd9Sstevel@tonic-gate xattr_linkaname : "", 2776*7c478bd9Sstevel@tonic-gate linkp, (xattr_linkp != NULL) ? 2777*7c478bd9Sstevel@tonic-gate gettext(" attribute ") : "", 2778*7c478bd9Sstevel@tonic-gate (xattr_linkp != NULL) ? 2779*7c478bd9Sstevel@tonic-gate xattraname : ""); 2780*7c478bd9Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2781*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2782*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2783*7c478bd9Sstevel@tonic-gate free(xattrhead); 2784*7c478bd9Sstevel@tonic-gate xattrp = NULL; 2785*7c478bd9Sstevel@tonic-gate xattr_linkp = NULL; 2786*7c478bd9Sstevel@tonic-gate xattrhead = NULL; 2787*7c478bd9Sstevel@tonic-gate } 2788*7c478bd9Sstevel@tonic-gate #endif 2789*7c478bd9Sstevel@tonic-gate continue; 2790*7c478bd9Sstevel@tonic-gate } 2791*7c478bd9Sstevel@tonic-gate 2792*7c478bd9Sstevel@tonic-gate /* REGULAR FILES */ 2793*7c478bd9Sstevel@tonic-gate 2794*7c478bd9Sstevel@tonic-gate if (convtoreg(stbuf.st_size)) { 2795*7c478bd9Sstevel@tonic-gate convflag = 1; 2796*7c478bd9Sstevel@tonic-gate if (errflag) { 2797*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2798*7c478bd9Sstevel@tonic-gate "tar: %s: typeflag '%c' not recognized\n"), 2799*7c478bd9Sstevel@tonic-gate namep, dblock.dbuf.typeflag); 2800*7c478bd9Sstevel@tonic-gate done(1); 2801*7c478bd9Sstevel@tonic-gate } else { 2802*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2803*7c478bd9Sstevel@tonic-gate "tar: %s: typeflag '%c' not recognized, " 2804*7c478bd9Sstevel@tonic-gate "converting to regular file\n"), namep, 2805*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag); 2806*7c478bd9Sstevel@tonic-gate Errflg = 1; 2807*7c478bd9Sstevel@tonic-gate } 2808*7c478bd9Sstevel@tonic-gate } 2809*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '0' || 2810*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag == NULL || convflag) { 2811*7c478bd9Sstevel@tonic-gate delete_target(dirfd, comp); 2812*7c478bd9Sstevel@tonic-gate linkp = templink; 2813*7c478bd9Sstevel@tonic-gate if (*linkp != NULL) { 2814*7c478bd9Sstevel@tonic-gate if (Aflag && *linkp == '/') 2815*7c478bd9Sstevel@tonic-gate linkp++; 2816*7c478bd9Sstevel@tonic-gate if (link(linkp, comp) < 0) { 2817*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2818*7c478bd9Sstevel@tonic-gate "tar: %s: cannot link\n"), namep); 2819*7c478bd9Sstevel@tonic-gate continue; 2820*7c478bd9Sstevel@tonic-gate } 2821*7c478bd9Sstevel@tonic-gate if (vflag) 2822*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2823*7c478bd9Sstevel@tonic-gate "%s linked to %s\n"), comp, linkp); 2824*7c478bd9Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2825*7c478bd9Sstevel@tonic-gate continue; 2826*7c478bd9Sstevel@tonic-gate } 2827*7c478bd9Sstevel@tonic-gate newfile = ((fstatat(dirfd, comp, 2828*7c478bd9Sstevel@tonic-gate &xtractbuf, 0) == -1) ? TRUE : FALSE); 2829*7c478bd9Sstevel@tonic-gate if ((ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC, 2830*7c478bd9Sstevel@tonic-gate stbuf.st_mode & MODEMASK)) < 0) { 2831*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2832*7c478bd9Sstevel@tonic-gate "tar: %s - cannot create\n"), comp); 2833*7c478bd9Sstevel@tonic-gate if (errflag) 2834*7c478bd9Sstevel@tonic-gate done(1); 2835*7c478bd9Sstevel@tonic-gate else 2836*7c478bd9Sstevel@tonic-gate Errflg = 1; 2837*7c478bd9Sstevel@tonic-gate passtape(); 2838*7c478bd9Sstevel@tonic-gate continue; 2839*7c478bd9Sstevel@tonic-gate } 2840*7c478bd9Sstevel@tonic-gate 2841*7c478bd9Sstevel@tonic-gate if (extno != 0) { /* file is in pieces */ 2842*7c478bd9Sstevel@tonic-gate if (extotal < 1 || extotal > MAXEXT) 2843*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2844*7c478bd9Sstevel@tonic-gate "tar: ignoring bad extent info for %s\n"), 2845*7c478bd9Sstevel@tonic-gate comp); 2846*7c478bd9Sstevel@tonic-gate else { 2847*7c478bd9Sstevel@tonic-gate xsfile(ofile); /* extract it */ 2848*7c478bd9Sstevel@tonic-gate goto filedone; 2849*7c478bd9Sstevel@tonic-gate } 2850*7c478bd9Sstevel@tonic-gate } 2851*7c478bd9Sstevel@tonic-gate extno = 0; /* let everyone know file is not split */ 2852*7c478bd9Sstevel@tonic-gate bytes = stbuf.st_size; 2853*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2854*7c478bd9Sstevel@tonic-gate if (vflag) { 2855*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, 2856*7c478bd9Sstevel@tonic-gate "x %s%s%s, %" FMT_off_t " bytes, ", 2857*7c478bd9Sstevel@tonic-gate (xattrp == NULL) ? "" : dirp, 2858*7c478bd9Sstevel@tonic-gate (xattrp == NULL) ? "" : gettext(" attribute "), 2859*7c478bd9Sstevel@tonic-gate (xattrp == NULL) ? namep : comp, bytes); 2860*7c478bd9Sstevel@tonic-gate if (NotTape) 2861*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n", 2862*7c478bd9Sstevel@tonic-gate K(blocks)); 2863*7c478bd9Sstevel@tonic-gate else 2864*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2865*7c478bd9Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), blocks); 2866*7c478bd9Sstevel@tonic-gate } 2867*7c478bd9Sstevel@tonic-gate 2868*7c478bd9Sstevel@tonic-gate xblocks(bytes, ofile); 2869*7c478bd9Sstevel@tonic-gate filedone: 2870*7c478bd9Sstevel@tonic-gate if (mflag == 0 && !symflag) { 2871*7c478bd9Sstevel@tonic-gate if (dir) 2872*7c478bd9Sstevel@tonic-gate doDirTimes(namep, stbuf.st_mtim); 2873*7c478bd9Sstevel@tonic-gate else 2874*7c478bd9Sstevel@tonic-gate setPathTimes(dirfd, comp, stbuf.st_mtim); 2875*7c478bd9Sstevel@tonic-gate } 2876*7c478bd9Sstevel@tonic-gate 2877*7c478bd9Sstevel@tonic-gate /* moved this code from above */ 2878*7c478bd9Sstevel@tonic-gate if (pflag && !symflag && Hiddendir == 0) { 2879*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) 2880*7c478bd9Sstevel@tonic-gate (void) fchmod(ofile, stbuf.st_mode & MODEMASK); 2881*7c478bd9Sstevel@tonic-gate else 2882*7c478bd9Sstevel@tonic-gate (void) chmod(namep, stbuf.st_mode & MODEMASK); 2883*7c478bd9Sstevel@tonic-gate } 2884*7c478bd9Sstevel@tonic-gate 2885*7c478bd9Sstevel@tonic-gate 2886*7c478bd9Sstevel@tonic-gate /* 2887*7c478bd9Sstevel@tonic-gate * Because ancillary file preceeds the normal file, 2888*7c478bd9Sstevel@tonic-gate * acl info may have been retrieved (in aclp). 2889*7c478bd9Sstevel@tonic-gate * All file types are directed here (go filedone). 2890*7c478bd9Sstevel@tonic-gate * Always restore ACLs if there are ACLs. 2891*7c478bd9Sstevel@tonic-gate */ 2892*7c478bd9Sstevel@tonic-gate if (aclp != NULL) { 2893*7c478bd9Sstevel@tonic-gate int ret; 2894*7c478bd9Sstevel@tonic-gate 2895*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2896*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2897*7c478bd9Sstevel@tonic-gate if (Hiddendir) 2898*7c478bd9Sstevel@tonic-gate ret = facl(dirfd, SETACL, 2899*7c478bd9Sstevel@tonic-gate aclcnt, aclp); 2900*7c478bd9Sstevel@tonic-gate else 2901*7c478bd9Sstevel@tonic-gate ret = facl(ofile, SETACL, 2902*7c478bd9Sstevel@tonic-gate aclcnt, aclp); 2903*7c478bd9Sstevel@tonic-gate } else { 2904*7c478bd9Sstevel@tonic-gate ret = acl(namep, SETACL, aclcnt, aclp); 2905*7c478bd9Sstevel@tonic-gate } 2906*7c478bd9Sstevel@tonic-gate #else 2907*7c478bd9Sstevel@tonic-gate ret = acl(namep, SETACL, aclcnt, aclp); 2908*7c478bd9Sstevel@tonic-gate #endif 2909*7c478bd9Sstevel@tonic-gate if (ret < 0) { 2910*7c478bd9Sstevel@tonic-gate if (pflag) { 2911*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2912*7c478bd9Sstevel@tonic-gate "%s: failed to set acl entries\n"), 2913*7c478bd9Sstevel@tonic-gate namep); 2914*7c478bd9Sstevel@tonic-gate } 2915*7c478bd9Sstevel@tonic-gate /* else: silent and continue */ 2916*7c478bd9Sstevel@tonic-gate } 2917*7c478bd9Sstevel@tonic-gate free(aclp); 2918*7c478bd9Sstevel@tonic-gate aclp = NULL; 2919*7c478bd9Sstevel@tonic-gate } 2920*7c478bd9Sstevel@tonic-gate 2921*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 2922*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2923*7c478bd9Sstevel@tonic-gate free(xattrhead); 2924*7c478bd9Sstevel@tonic-gate xattrp = NULL; 2925*7c478bd9Sstevel@tonic-gate xattr_linkp = NULL; 2926*7c478bd9Sstevel@tonic-gate xattrhead = NULL; 2927*7c478bd9Sstevel@tonic-gate } 2928*7c478bd9Sstevel@tonic-gate #endif 2929*7c478bd9Sstevel@tonic-gate 2930*7c478bd9Sstevel@tonic-gate if (!oflag) 2931*7c478bd9Sstevel@tonic-gate resugname(dirfd, comp, symflag); /* set file ownership */ 2932*7c478bd9Sstevel@tonic-gate 2933*7c478bd9Sstevel@tonic-gate if (pflag && newfile == TRUE && !dir && 2934*7c478bd9Sstevel@tonic-gate (dblock.dbuf.typeflag == '0' || 2935*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag == NULL || 2936*7c478bd9Sstevel@tonic-gate convflag || dblock.dbuf.typeflag == '1')) { 2937*7c478bd9Sstevel@tonic-gate if (fstat(ofile, &xtractbuf) == -1) 2938*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2939*7c478bd9Sstevel@tonic-gate "tar: cannot stat extracted file %s\n"), 2940*7c478bd9Sstevel@tonic-gate namep); 2941*7c478bd9Sstevel@tonic-gate else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT)) 2942*7c478bd9Sstevel@tonic-gate != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) { 2943*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2944*7c478bd9Sstevel@tonic-gate "tar: warning - file permissions have " 2945*7c478bd9Sstevel@tonic-gate "changed for %s (are 0%o, should be " 2946*7c478bd9Sstevel@tonic-gate "0%o)\n"), 2947*7c478bd9Sstevel@tonic-gate namep, xtractbuf.st_mode, stbuf.st_mode); 2948*7c478bd9Sstevel@tonic-gate } 2949*7c478bd9Sstevel@tonic-gate } 2950*7c478bd9Sstevel@tonic-gate if (ofile != -1) { 2951*7c478bd9Sstevel@tonic-gate (void) close(dirfd); 2952*7c478bd9Sstevel@tonic-gate dirfd = -1; 2953*7c478bd9Sstevel@tonic-gate if (close(ofile) != 0) 2954*7c478bd9Sstevel@tonic-gate vperror(2, gettext("close error")); 2955*7c478bd9Sstevel@tonic-gate } 2956*7c478bd9Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2957*7c478bd9Sstevel@tonic-gate } 2958*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == 'A') { /* acl info */ 2959*7c478bd9Sstevel@tonic-gate char buf[TBLOCK]; 2960*7c478bd9Sstevel@tonic-gate char *secp; 2961*7c478bd9Sstevel@tonic-gate char *tp; 2962*7c478bd9Sstevel@tonic-gate int attrsize; 2963*7c478bd9Sstevel@tonic-gate int cnt; 2964*7c478bd9Sstevel@tonic-gate 2965*7c478bd9Sstevel@tonic-gate 2966*7c478bd9Sstevel@tonic-gate if (pflag) { 2967*7c478bd9Sstevel@tonic-gate bytes = stbuf.st_size; 2968*7c478bd9Sstevel@tonic-gate if ((secp = malloc((int)bytes)) == NULL) { 2969*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2970*7c478bd9Sstevel@tonic-gate "Insufficient memory for acl\n")); 2971*7c478bd9Sstevel@tonic-gate passtape(); 2972*7c478bd9Sstevel@tonic-gate continue; 2973*7c478bd9Sstevel@tonic-gate } 2974*7c478bd9Sstevel@tonic-gate tp = secp; 2975*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2976*7c478bd9Sstevel@tonic-gate while (blocks-- > 0) { 2977*7c478bd9Sstevel@tonic-gate readtape(buf); 2978*7c478bd9Sstevel@tonic-gate if (bytes <= TBLOCK) { 2979*7c478bd9Sstevel@tonic-gate (void) memcpy(tp, buf, 2980*7c478bd9Sstevel@tonic-gate (size_t)bytes); 2981*7c478bd9Sstevel@tonic-gate break; 2982*7c478bd9Sstevel@tonic-gate } else { 2983*7c478bd9Sstevel@tonic-gate (void) memcpy(tp, buf, 2984*7c478bd9Sstevel@tonic-gate TBLOCK); 2985*7c478bd9Sstevel@tonic-gate tp += TBLOCK; 2986*7c478bd9Sstevel@tonic-gate } 2987*7c478bd9Sstevel@tonic-gate bytes -= TBLOCK; 2988*7c478bd9Sstevel@tonic-gate } 2989*7c478bd9Sstevel@tonic-gate /* got all attributes in secp */ 2990*7c478bd9Sstevel@tonic-gate tp = secp; 2991*7c478bd9Sstevel@tonic-gate do { 2992*7c478bd9Sstevel@tonic-gate attr = (struct sec_attr *)tp; 2993*7c478bd9Sstevel@tonic-gate switch (attr->attr_type) { 2994*7c478bd9Sstevel@tonic-gate case UFSD_ACL: 2995*7c478bd9Sstevel@tonic-gate (void) sscanf(attr->attr_len, 2996*7c478bd9Sstevel@tonic-gate "%7o", (uint_t *)&aclcnt); 2997*7c478bd9Sstevel@tonic-gate /* header is 8 */ 2998*7c478bd9Sstevel@tonic-gate attrsize = 8 + (int)strlen( 2999*7c478bd9Sstevel@tonic-gate &attr->attr_info[0]) + 1; 3000*7c478bd9Sstevel@tonic-gate aclp = aclfromtext( 3001*7c478bd9Sstevel@tonic-gate &attr->attr_info[0], &cnt); 3002*7c478bd9Sstevel@tonic-gate if (aclp == NULL) { 3003*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3004*7c478bd9Sstevel@tonic-gate gettext( 3005*7c478bd9Sstevel@tonic-gate "aclfromtext " 3006*7c478bd9Sstevel@tonic-gate "failed\n")); 3007*7c478bd9Sstevel@tonic-gate break; 3008*7c478bd9Sstevel@tonic-gate } 3009*7c478bd9Sstevel@tonic-gate if (aclcnt != cnt) { 3010*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3011*7c478bd9Sstevel@tonic-gate gettext( 3012*7c478bd9Sstevel@tonic-gate "aclcnt error\n")); 3013*7c478bd9Sstevel@tonic-gate break; 3014*7c478bd9Sstevel@tonic-gate } 3015*7c478bd9Sstevel@tonic-gate bytes -= attrsize; 3016*7c478bd9Sstevel@tonic-gate break; 3017*7c478bd9Sstevel@tonic-gate 3018*7c478bd9Sstevel@tonic-gate /* SunFed case goes here */ 3019*7c478bd9Sstevel@tonic-gate 3020*7c478bd9Sstevel@tonic-gate default: 3021*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3022*7c478bd9Sstevel@tonic-gate "unrecognized attr" 3023*7c478bd9Sstevel@tonic-gate " type\n")); 3024*7c478bd9Sstevel@tonic-gate bytes = (off_t)0; 3025*7c478bd9Sstevel@tonic-gate break; 3026*7c478bd9Sstevel@tonic-gate } 3027*7c478bd9Sstevel@tonic-gate 3028*7c478bd9Sstevel@tonic-gate /* next attributes */ 3029*7c478bd9Sstevel@tonic-gate tp += attrsize; 3030*7c478bd9Sstevel@tonic-gate } while (bytes != 0); 3031*7c478bd9Sstevel@tonic-gate free(secp); 3032*7c478bd9Sstevel@tonic-gate } else 3033*7c478bd9Sstevel@tonic-gate passtape(); 3034*7c478bd9Sstevel@tonic-gate } /* acl */ 3035*7c478bd9Sstevel@tonic-gate 3036*7c478bd9Sstevel@tonic-gate } /* for */ 3037*7c478bd9Sstevel@tonic-gate 3038*7c478bd9Sstevel@tonic-gate /* 3039*7c478bd9Sstevel@tonic-gate * Ensure that all the directories still on the directory stack 3040*7c478bd9Sstevel@tonic-gate * get their modification times set correctly by flushing the 3041*7c478bd9Sstevel@tonic-gate * stack. 3042*7c478bd9Sstevel@tonic-gate */ 3043*7c478bd9Sstevel@tonic-gate 3044*7c478bd9Sstevel@tonic-gate doDirTimes(NULL, time_zero); 3045*7c478bd9Sstevel@tonic-gate 3046*7c478bd9Sstevel@tonic-gate /* 3047*7c478bd9Sstevel@tonic-gate * Check if the number of files extracted is different from the 3048*7c478bd9Sstevel@tonic-gate * number of files listed on the command line 3049*7c478bd9Sstevel@tonic-gate */ 3050*7c478bd9Sstevel@tonic-gate if (fcnt > xcnt) { 3051*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3052*7c478bd9Sstevel@tonic-gate gettext("tar: %d file(s) not extracted\n"), 3053*7c478bd9Sstevel@tonic-gate fcnt-xcnt); 3054*7c478bd9Sstevel@tonic-gate Errflg = 1; 3055*7c478bd9Sstevel@tonic-gate } 3056*7c478bd9Sstevel@tonic-gate } 3057*7c478bd9Sstevel@tonic-gate 3058*7c478bd9Sstevel@tonic-gate /* 3059*7c478bd9Sstevel@tonic-gate * xblocks extract file/extent from tape to output file 3060*7c478bd9Sstevel@tonic-gate * 3061*7c478bd9Sstevel@tonic-gate * xblocks(bytes, ofile); 3062*7c478bd9Sstevel@tonic-gate * unsigned long long bytes; size of extent or file to be extracted 3063*7c478bd9Sstevel@tonic-gate * 3064*7c478bd9Sstevel@tonic-gate * called by doxtract() and xsfile() 3065*7c478bd9Sstevel@tonic-gate */ 3066*7c478bd9Sstevel@tonic-gate 3067*7c478bd9Sstevel@tonic-gate static void 3068*7c478bd9Sstevel@tonic-gate xblocks(off_t bytes, int ofile) 3069*7c478bd9Sstevel@tonic-gate { 3070*7c478bd9Sstevel@tonic-gate blkcnt_t blocks; 3071*7c478bd9Sstevel@tonic-gate char buf[TBLOCK]; 3072*7c478bd9Sstevel@tonic-gate char tempname[NAMSIZ+1]; 3073*7c478bd9Sstevel@tonic-gate int write_count; 3074*7c478bd9Sstevel@tonic-gate 3075*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(bytes); 3076*7c478bd9Sstevel@tonic-gate while (blocks-- > 0) { 3077*7c478bd9Sstevel@tonic-gate readtape(buf); 3078*7c478bd9Sstevel@tonic-gate if (bytes > TBLOCK) 3079*7c478bd9Sstevel@tonic-gate write_count = TBLOCK; 3080*7c478bd9Sstevel@tonic-gate else 3081*7c478bd9Sstevel@tonic-gate write_count = bytes; 3082*7c478bd9Sstevel@tonic-gate if (write(ofile, buf, write_count) < 0) { 3083*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 3084*7c478bd9Sstevel@tonic-gate (void) strcpy(tempname, Xtarhdr.x_path); 3085*7c478bd9Sstevel@tonic-gate else 3086*7c478bd9Sstevel@tonic-gate (void) sprintf(tempname, "%.*s", NAMSIZ, 3087*7c478bd9Sstevel@tonic-gate dblock.dbuf.name); 3088*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3089*7c478bd9Sstevel@tonic-gate "tar: %s: HELP - extract write error\n"), tempname); 3090*7c478bd9Sstevel@tonic-gate done(2); 3091*7c478bd9Sstevel@tonic-gate } 3092*7c478bd9Sstevel@tonic-gate bytes -= TBLOCK; 3093*7c478bd9Sstevel@tonic-gate } 3094*7c478bd9Sstevel@tonic-gate } 3095*7c478bd9Sstevel@tonic-gate 3096*7c478bd9Sstevel@tonic-gate 3097*7c478bd9Sstevel@tonic-gate /* 3098*7c478bd9Sstevel@tonic-gate * xsfile extract split file 3099*7c478bd9Sstevel@tonic-gate * 3100*7c478bd9Sstevel@tonic-gate * xsfile(ofd); ofd = output file descriptor 3101*7c478bd9Sstevel@tonic-gate * 3102*7c478bd9Sstevel@tonic-gate * file extracted and put in ofd via xblocks() 3103*7c478bd9Sstevel@tonic-gate * 3104*7c478bd9Sstevel@tonic-gate * NOTE: only called by doxtract() to extract one large file 3105*7c478bd9Sstevel@tonic-gate */ 3106*7c478bd9Sstevel@tonic-gate 3107*7c478bd9Sstevel@tonic-gate static union hblock savedblock; /* to ensure same file across volumes */ 3108*7c478bd9Sstevel@tonic-gate 3109*7c478bd9Sstevel@tonic-gate static void 3110*7c478bd9Sstevel@tonic-gate xsfile(int ofd) 3111*7c478bd9Sstevel@tonic-gate { 3112*7c478bd9Sstevel@tonic-gate int i, c; 3113*7c478bd9Sstevel@tonic-gate char name[PATH_MAX+1]; /* holds name for diagnostics */ 3114*7c478bd9Sstevel@tonic-gate int extents, totalext; 3115*7c478bd9Sstevel@tonic-gate off_t bytes, totalbytes; 3116*7c478bd9Sstevel@tonic-gate 3117*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 3118*7c478bd9Sstevel@tonic-gate (void) strcpy(name, Xtarhdr.x_path); 3119*7c478bd9Sstevel@tonic-gate else 3120*7c478bd9Sstevel@tonic-gate (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name); 3121*7c478bd9Sstevel@tonic-gate 3122*7c478bd9Sstevel@tonic-gate totalbytes = (off_t)0; /* in case we read in half the file */ 3123*7c478bd9Sstevel@tonic-gate totalext = 0; /* these keep count */ 3124*7c478bd9Sstevel@tonic-gate 3125*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3126*7c478bd9Sstevel@tonic-gate "tar: %s split across %d volumes\n"), name, extotal); 3127*7c478bd9Sstevel@tonic-gate 3128*7c478bd9Sstevel@tonic-gate /* make sure we do extractions in order */ 3129*7c478bd9Sstevel@tonic-gate if (extno != 1) { /* starting in middle of file? */ 3130*7c478bd9Sstevel@tonic-gate wchar_t yeschar; 3131*7c478bd9Sstevel@tonic-gate wchar_t nochar; 3132*7c478bd9Sstevel@tonic-gate (void) mbtowc(&yeschar, nl_langinfo(YESSTR), MB_LEN_MAX); 3133*7c478bd9Sstevel@tonic-gate (void) mbtowc(&nochar, nl_langinfo(NOSTR), MB_LEN_MAX); 3134*7c478bd9Sstevel@tonic-gate (void) printf(gettext( 3135*7c478bd9Sstevel@tonic-gate "tar: first extent read is not #1\n" 3136*7c478bd9Sstevel@tonic-gate "OK to read file beginning with extent #%d (%wc/%wc) ? "), 3137*7c478bd9Sstevel@tonic-gate extno, yeschar, nochar); 3138*7c478bd9Sstevel@tonic-gate if (yesnoresponse() != yeschar) { 3139*7c478bd9Sstevel@tonic-gate canit: 3140*7c478bd9Sstevel@tonic-gate passtape(); 3141*7c478bd9Sstevel@tonic-gate if (close(ofd) != 0) 3142*7c478bd9Sstevel@tonic-gate vperror(2, gettext("close error")); 3143*7c478bd9Sstevel@tonic-gate return; 3144*7c478bd9Sstevel@tonic-gate } 3145*7c478bd9Sstevel@tonic-gate } 3146*7c478bd9Sstevel@tonic-gate extents = extotal; 3147*7c478bd9Sstevel@tonic-gate i = extno; 3148*7c478bd9Sstevel@tonic-gate /*CONSTCOND*/ 3149*7c478bd9Sstevel@tonic-gate while (1) { 3150*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_SIZE) { 3151*7c478bd9Sstevel@tonic-gate bytes = extsize; 3152*7c478bd9Sstevel@tonic-gate } else { 3153*7c478bd9Sstevel@tonic-gate bytes = stbuf.st_size; 3154*7c478bd9Sstevel@tonic-gate } 3155*7c478bd9Sstevel@tonic-gate 3156*7c478bd9Sstevel@tonic-gate if (vflag) 3157*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "+++ x %s [extent #%d], %" 3158*7c478bd9Sstevel@tonic-gate FMT_off_t " bytes, %ldK\n", name, extno, bytes, 3159*7c478bd9Sstevel@tonic-gate (long)K(TBLOCKS(bytes))); 3160*7c478bd9Sstevel@tonic-gate xblocks(bytes, ofd); 3161*7c478bd9Sstevel@tonic-gate 3162*7c478bd9Sstevel@tonic-gate totalbytes += bytes; 3163*7c478bd9Sstevel@tonic-gate totalext++; 3164*7c478bd9Sstevel@tonic-gate if (++i > extents) 3165*7c478bd9Sstevel@tonic-gate break; 3166*7c478bd9Sstevel@tonic-gate 3167*7c478bd9Sstevel@tonic-gate /* get next volume and verify it's the right one */ 3168*7c478bd9Sstevel@tonic-gate copy(&savedblock, &dblock); 3169*7c478bd9Sstevel@tonic-gate tryagain: 3170*7c478bd9Sstevel@tonic-gate newvol(); 3171*7c478bd9Sstevel@tonic-gate xhdr_flgs = 0; 3172*7c478bd9Sstevel@tonic-gate getdir(); 3173*7c478bd9Sstevel@tonic-gate if (Xhdrflag > 0) 3174*7c478bd9Sstevel@tonic-gate (void) get_xdata(); /* Get x-header & regular hdr */ 3175*7c478bd9Sstevel@tonic-gate if (endtape()) { /* seemingly empty volume */ 3176*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3177*7c478bd9Sstevel@tonic-gate "tar: first record is null\n")); 3178*7c478bd9Sstevel@tonic-gate asknicely: 3179*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3180*7c478bd9Sstevel@tonic-gate "tar: need volume with extent #%d of %s\n"), 3181*7c478bd9Sstevel@tonic-gate i, name); 3182*7c478bd9Sstevel@tonic-gate goto tryagain; 3183*7c478bd9Sstevel@tonic-gate } 3184*7c478bd9Sstevel@tonic-gate if (notsame()) { 3185*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3186*7c478bd9Sstevel@tonic-gate "tar: first file on that volume is not " 3187*7c478bd9Sstevel@tonic-gate "the same file\n")); 3188*7c478bd9Sstevel@tonic-gate goto asknicely; 3189*7c478bd9Sstevel@tonic-gate } 3190*7c478bd9Sstevel@tonic-gate if (i != extno) { 3191*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3192*7c478bd9Sstevel@tonic-gate "tar: extent #%d received out of order\ntar: should be #%d\n"), 3193*7c478bd9Sstevel@tonic-gate extno, i); 3194*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3195*7c478bd9Sstevel@tonic-gate "Ignore error, Abort this file, or " 3196*7c478bd9Sstevel@tonic-gate "load New volume (i/a/n) ? ")); 3197*7c478bd9Sstevel@tonic-gate c = response(); 3198*7c478bd9Sstevel@tonic-gate if (c == 'a') 3199*7c478bd9Sstevel@tonic-gate goto canit; 3200*7c478bd9Sstevel@tonic-gate if (c != 'i') /* default to new volume */ 3201*7c478bd9Sstevel@tonic-gate goto asknicely; 3202*7c478bd9Sstevel@tonic-gate i = extno; /* okay, start from there */ 3203*7c478bd9Sstevel@tonic-gate } 3204*7c478bd9Sstevel@tonic-gate } 3205*7c478bd9Sstevel@tonic-gate if (vflag) 3206*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 3207*7c478bd9Sstevel@tonic-gate "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"), 3208*7c478bd9Sstevel@tonic-gate name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes))); 3209*7c478bd9Sstevel@tonic-gate } 3210*7c478bd9Sstevel@tonic-gate 3211*7c478bd9Sstevel@tonic-gate 3212*7c478bd9Sstevel@tonic-gate /* 3213*7c478bd9Sstevel@tonic-gate * notsame() check if extract file extent is invalid 3214*7c478bd9Sstevel@tonic-gate * 3215*7c478bd9Sstevel@tonic-gate * returns true if anything differs between savedblock and dblock 3216*7c478bd9Sstevel@tonic-gate * except extno (extent number), checksum, or size (extent size). 3217*7c478bd9Sstevel@tonic-gate * Determines if this header belongs to the same file as the one we're 3218*7c478bd9Sstevel@tonic-gate * extracting. 3219*7c478bd9Sstevel@tonic-gate * 3220*7c478bd9Sstevel@tonic-gate * NOTE: though rather bulky, it is only called once per file 3221*7c478bd9Sstevel@tonic-gate * extension, and it can withstand changes in the definition 3222*7c478bd9Sstevel@tonic-gate * of the header structure. 3223*7c478bd9Sstevel@tonic-gate * 3224*7c478bd9Sstevel@tonic-gate * WARNING: this routine is local to xsfile() above 3225*7c478bd9Sstevel@tonic-gate */ 3226*7c478bd9Sstevel@tonic-gate 3227*7c478bd9Sstevel@tonic-gate static int 3228*7c478bd9Sstevel@tonic-gate notsame(void) 3229*7c478bd9Sstevel@tonic-gate { 3230*7c478bd9Sstevel@tonic-gate return ( 3231*7c478bd9Sstevel@tonic-gate (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) || 3232*7c478bd9Sstevel@tonic-gate (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) || 3233*7c478bd9Sstevel@tonic-gate (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) || 3234*7c478bd9Sstevel@tonic-gate (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) || 3235*7c478bd9Sstevel@tonic-gate (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) || 3236*7c478bd9Sstevel@tonic-gate (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) || 3237*7c478bd9Sstevel@tonic-gate (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) || 3238*7c478bd9Sstevel@tonic-gate (savedblock.dbuf.extotal != dblock.dbuf.extotal) || 3239*7c478bd9Sstevel@tonic-gate (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize))); 3240*7c478bd9Sstevel@tonic-gate } 3241*7c478bd9Sstevel@tonic-gate 3242*7c478bd9Sstevel@tonic-gate 3243*7c478bd9Sstevel@tonic-gate static void 3244*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 3245*7c478bd9Sstevel@tonic-gate dotable(char *argv[], int tbl_cnt) 3246*7c478bd9Sstevel@tonic-gate #else 3247*7c478bd9Sstevel@tonic-gate dotable(char *argv[]) 3248*7c478bd9Sstevel@tonic-gate #endif 3249*7c478bd9Sstevel@tonic-gate 3250*7c478bd9Sstevel@tonic-gate { 3251*7c478bd9Sstevel@tonic-gate int tcnt; /* count # files tabled */ 3252*7c478bd9Sstevel@tonic-gate int fcnt; /* count # files in argv list */ 3253*7c478bd9Sstevel@tonic-gate char *namep, *dirp, *comp; 3254*7c478bd9Sstevel@tonic-gate int want; 3255*7c478bd9Sstevel@tonic-gate char aclchar = ' '; /* either blank or '+' */ 3256*7c478bd9Sstevel@tonic-gate char templink[PATH_MAX+1]; 3257*7c478bd9Sstevel@tonic-gate char *np; 3258*7c478bd9Sstevel@tonic-gate 3259*7c478bd9Sstevel@tonic-gate dumping = 0; 3260*7c478bd9Sstevel@tonic-gate 3261*7c478bd9Sstevel@tonic-gate /* if not on magtape, maximize seek speed */ 3262*7c478bd9Sstevel@tonic-gate if (NotTape && !bflag) { 3263*7c478bd9Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 3264*7c478bd9Sstevel@tonic-gate nblock = SYS_BLOCK / TBLOCK; 3265*7c478bd9Sstevel@tonic-gate #else 3266*7c478bd9Sstevel@tonic-gate nblock = 1; 3267*7c478bd9Sstevel@tonic-gate #endif 3268*7c478bd9Sstevel@tonic-gate } 3269*7c478bd9Sstevel@tonic-gate /* 3270*7c478bd9Sstevel@tonic-gate * Count the number of files that are to be tabled 3271*7c478bd9Sstevel@tonic-gate */ 3272*7c478bd9Sstevel@tonic-gate fcnt = tcnt = 0; 3273*7c478bd9Sstevel@tonic-gate 3274*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 3275*7c478bd9Sstevel@tonic-gate initarg(argv, Filefile); 3276*7c478bd9Sstevel@tonic-gate while (nextarg() != NULL) 3277*7c478bd9Sstevel@tonic-gate ++fcnt; 3278*7c478bd9Sstevel@tonic-gate fcnt += tbl_cnt; 3279*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 3280*7c478bd9Sstevel@tonic-gate 3281*7c478bd9Sstevel@tonic-gate for (;;) { 3282*7c478bd9Sstevel@tonic-gate 3283*7c478bd9Sstevel@tonic-gate /* namep is set by wantit to point to the full name */ 3284*7c478bd9Sstevel@tonic-gate if ((want = wantit(argv, &namep, &dirp, &comp)) == 0) 3285*7c478bd9Sstevel@tonic-gate continue; 3286*7c478bd9Sstevel@tonic-gate if (want == -1) 3287*7c478bd9Sstevel@tonic-gate break; 3288*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag != 'A') 3289*7c478bd9Sstevel@tonic-gate ++tcnt; 3290*7c478bd9Sstevel@tonic-gate 3291*7c478bd9Sstevel@tonic-gate /* 3292*7c478bd9Sstevel@tonic-gate * ACL support: 3293*7c478bd9Sstevel@tonic-gate * aclchar is introduced to indicate if there are 3294*7c478bd9Sstevel@tonic-gate * acl entries. longt() now takes one extra argument. 3295*7c478bd9Sstevel@tonic-gate */ 3296*7c478bd9Sstevel@tonic-gate if (vflag) { 3297*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == 'A') { 3298*7c478bd9Sstevel@tonic-gate aclchar = '+'; 3299*7c478bd9Sstevel@tonic-gate passtape(); 3300*7c478bd9Sstevel@tonic-gate continue; 3301*7c478bd9Sstevel@tonic-gate } 3302*7c478bd9Sstevel@tonic-gate longt(&stbuf, aclchar); 3303*7c478bd9Sstevel@tonic-gate aclchar = ' '; 3304*7c478bd9Sstevel@tonic-gate } 3305*7c478bd9Sstevel@tonic-gate 3306*7c478bd9Sstevel@tonic-gate 3307*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 3308*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 3309*7c478bd9Sstevel@tonic-gate np = xattrp->h_names + strlen(xattrp->h_names) + 1; 3310*7c478bd9Sstevel@tonic-gate (void) printf(gettext("%s attribute %s"), 3311*7c478bd9Sstevel@tonic-gate xattrp->h_names, np); 3312*7c478bd9Sstevel@tonic-gate 3313*7c478bd9Sstevel@tonic-gate } else { 3314*7c478bd9Sstevel@tonic-gate (void) printf("%s", namep); 3315*7c478bd9Sstevel@tonic-gate } 3316*7c478bd9Sstevel@tonic-gate #else 3317*7c478bd9Sstevel@tonic-gate (void) printf("%s", namep); 3318*7c478bd9Sstevel@tonic-gate #endif 3319*7c478bd9Sstevel@tonic-gate 3320*7c478bd9Sstevel@tonic-gate if (extno != 0) { 3321*7c478bd9Sstevel@tonic-gate if (vflag) { 3322*7c478bd9Sstevel@tonic-gate /* keep the '\n' for backwards compatibility */ 3323*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 3324*7c478bd9Sstevel@tonic-gate "\n [extent #%d of %d]"), extno, extotal); 3325*7c478bd9Sstevel@tonic-gate } else { 3326*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 3327*7c478bd9Sstevel@tonic-gate " [extent #%d of %d]"), extno, extotal); 3328*7c478bd9Sstevel@tonic-gate } 3329*7c478bd9Sstevel@tonic-gate } 3330*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) { 3331*7c478bd9Sstevel@tonic-gate (void) strcpy(templink, Xtarhdr.x_linkpath); 3332*7c478bd9Sstevel@tonic-gate } else { 3333*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 3334*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 3335*7c478bd9Sstevel@tonic-gate (void) sprintf(templink, 3336*7c478bd9Sstevel@tonic-gate "file %.*s", NAMSIZ, xattrp->h_names); 3337*7c478bd9Sstevel@tonic-gate } else { 3338*7c478bd9Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 3339*7c478bd9Sstevel@tonic-gate dblock.dbuf.linkname); 3340*7c478bd9Sstevel@tonic-gate } 3341*7c478bd9Sstevel@tonic-gate #else 3342*7c478bd9Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 3343*7c478bd9Sstevel@tonic-gate dblock.dbuf.linkname); 3344*7c478bd9Sstevel@tonic-gate #endif 3345*7c478bd9Sstevel@tonic-gate templink[NAMSIZ] = '\0'; 3346*7c478bd9Sstevel@tonic-gate } 3347*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1') { 3348*7c478bd9Sstevel@tonic-gate /* 3349*7c478bd9Sstevel@tonic-gate * TRANSLATION_NOTE 3350*7c478bd9Sstevel@tonic-gate * Subject is omitted here. 3351*7c478bd9Sstevel@tonic-gate * Translate this as if 3352*7c478bd9Sstevel@tonic-gate * <subject> linked to %s 3353*7c478bd9Sstevel@tonic-gate */ 3354*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 3355*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 3356*7c478bd9Sstevel@tonic-gate (void) printf( 3357*7c478bd9Sstevel@tonic-gate gettext(" linked to attribute %s"), 3358*7c478bd9Sstevel@tonic-gate xattr_linkp->h_names + 3359*7c478bd9Sstevel@tonic-gate strlen(xattr_linkp->h_names) + 1); 3360*7c478bd9Sstevel@tonic-gate } else { 3361*7c478bd9Sstevel@tonic-gate (void) printf( 3362*7c478bd9Sstevel@tonic-gate gettext(" linked to %s"), templink); 3363*7c478bd9Sstevel@tonic-gate } 3364*7c478bd9Sstevel@tonic-gate #else 3365*7c478bd9Sstevel@tonic-gate (void) printf( 3366*7c478bd9Sstevel@tonic-gate gettext(" linked to %s"), templink); 3367*7c478bd9Sstevel@tonic-gate 3368*7c478bd9Sstevel@tonic-gate #endif 3369*7c478bd9Sstevel@tonic-gate } 3370*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2') 3371*7c478bd9Sstevel@tonic-gate (void) printf(gettext( 3372*7c478bd9Sstevel@tonic-gate /* 3373*7c478bd9Sstevel@tonic-gate * TRANSLATION_NOTE 3374*7c478bd9Sstevel@tonic-gate * Subject is omitted here. 3375*7c478bd9Sstevel@tonic-gate * Translate this as if 3376*7c478bd9Sstevel@tonic-gate * <subject> symbolic link to %s 3377*7c478bd9Sstevel@tonic-gate */ 3378*7c478bd9Sstevel@tonic-gate " symbolic link to %s"), templink); 3379*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 3380*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 3381*7c478bd9Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 3382*7c478bd9Sstevel@tonic-gate free(xattrhead); 3383*7c478bd9Sstevel@tonic-gate xattrp = NULL; 3384*7c478bd9Sstevel@tonic-gate xattrhead = NULL; 3385*7c478bd9Sstevel@tonic-gate } 3386*7c478bd9Sstevel@tonic-gate #endif 3387*7c478bd9Sstevel@tonic-gate passtape(); 3388*7c478bd9Sstevel@tonic-gate } 3389*7c478bd9Sstevel@tonic-gate /* 3390*7c478bd9Sstevel@tonic-gate * Check if the number of files tabled is different from the 3391*7c478bd9Sstevel@tonic-gate * number of files listed on the command line 3392*7c478bd9Sstevel@tonic-gate */ 3393*7c478bd9Sstevel@tonic-gate if (fcnt > tcnt) { 3394*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3395*7c478bd9Sstevel@tonic-gate "tar: %d file(s) not found\n"), fcnt-tcnt); 3396*7c478bd9Sstevel@tonic-gate Errflg = 1; 3397*7c478bd9Sstevel@tonic-gate } 3398*7c478bd9Sstevel@tonic-gate } 3399*7c478bd9Sstevel@tonic-gate 3400*7c478bd9Sstevel@tonic-gate static void 3401*7c478bd9Sstevel@tonic-gate putempty(blkcnt_t n) 3402*7c478bd9Sstevel@tonic-gate { 3403*7c478bd9Sstevel@tonic-gate char buf[TBLOCK]; 3404*7c478bd9Sstevel@tonic-gate char *cp; 3405*7c478bd9Sstevel@tonic-gate 3406*7c478bd9Sstevel@tonic-gate for (cp = buf; cp < &buf[TBLOCK]; ) 3407*7c478bd9Sstevel@tonic-gate *cp++ = '\0'; 3408*7c478bd9Sstevel@tonic-gate while (n-- > 0) 3409*7c478bd9Sstevel@tonic-gate (void) writetbuf(buf, 1); 3410*7c478bd9Sstevel@tonic-gate } 3411*7c478bd9Sstevel@tonic-gate 3412*7c478bd9Sstevel@tonic-gate static ushort_t Ftype = S_IFMT; 3413*7c478bd9Sstevel@tonic-gate 3414*7c478bd9Sstevel@tonic-gate static void 3415*7c478bd9Sstevel@tonic-gate verbose(struct stat *st, char aclchar) 3416*7c478bd9Sstevel@tonic-gate { 3417*7c478bd9Sstevel@tonic-gate int i, j, temp; 3418*7c478bd9Sstevel@tonic-gate mode_t mode; 3419*7c478bd9Sstevel@tonic-gate char modestr[12]; 3420*7c478bd9Sstevel@tonic-gate 3421*7c478bd9Sstevel@tonic-gate for (i = 0; i < 11; i++) 3422*7c478bd9Sstevel@tonic-gate modestr[i] = '-'; 3423*7c478bd9Sstevel@tonic-gate modestr[i] = '\0'; 3424*7c478bd9Sstevel@tonic-gate 3425*7c478bd9Sstevel@tonic-gate /* a '+' sign is printed if there is ACL */ 3426*7c478bd9Sstevel@tonic-gate modestr[i-1] = aclchar; 3427*7c478bd9Sstevel@tonic-gate 3428*7c478bd9Sstevel@tonic-gate mode = st->st_mode; 3429*7c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) { 3430*7c478bd9Sstevel@tonic-gate temp = (mode >> (6 - (i * 3))); 3431*7c478bd9Sstevel@tonic-gate j = (i * 3) + 1; 3432*7c478bd9Sstevel@tonic-gate if (S_IROTH & temp) 3433*7c478bd9Sstevel@tonic-gate modestr[j] = 'r'; 3434*7c478bd9Sstevel@tonic-gate if (S_IWOTH & temp) 3435*7c478bd9Sstevel@tonic-gate modestr[j + 1] = 'w'; 3436*7c478bd9Sstevel@tonic-gate if (S_IXOTH & temp) 3437*7c478bd9Sstevel@tonic-gate modestr[j + 2] = 'x'; 3438*7c478bd9Sstevel@tonic-gate } 3439*7c478bd9Sstevel@tonic-gate temp = st->st_mode & Ftype; 3440*7c478bd9Sstevel@tonic-gate switch (temp) { 3441*7c478bd9Sstevel@tonic-gate case (S_IFIFO): 3442*7c478bd9Sstevel@tonic-gate modestr[0] = 'p'; 3443*7c478bd9Sstevel@tonic-gate break; 3444*7c478bd9Sstevel@tonic-gate case (S_IFCHR): 3445*7c478bd9Sstevel@tonic-gate modestr[0] = 'c'; 3446*7c478bd9Sstevel@tonic-gate break; 3447*7c478bd9Sstevel@tonic-gate case (S_IFDIR): 3448*7c478bd9Sstevel@tonic-gate modestr[0] = 'd'; 3449*7c478bd9Sstevel@tonic-gate break; 3450*7c478bd9Sstevel@tonic-gate case (S_IFBLK): 3451*7c478bd9Sstevel@tonic-gate modestr[0] = 'b'; 3452*7c478bd9Sstevel@tonic-gate break; 3453*7c478bd9Sstevel@tonic-gate case (S_IFREG): /* was initialized to '-' */ 3454*7c478bd9Sstevel@tonic-gate break; 3455*7c478bd9Sstevel@tonic-gate case (S_IFLNK): 3456*7c478bd9Sstevel@tonic-gate modestr[0] = 'l'; 3457*7c478bd9Sstevel@tonic-gate break; 3458*7c478bd9Sstevel@tonic-gate default: 3459*7c478bd9Sstevel@tonic-gate /* This field may be zero in old archives. */ 3460*7c478bd9Sstevel@tonic-gate if (is_posix && dblock.dbuf.typeflag != '1') { 3461*7c478bd9Sstevel@tonic-gate /* 3462*7c478bd9Sstevel@tonic-gate * For POSIX compliant archives, the mode field 3463*7c478bd9Sstevel@tonic-gate * consists of 12 bits, ie: the file type bits 3464*7c478bd9Sstevel@tonic-gate * are not stored in dblock.dbuf.mode. 3465*7c478bd9Sstevel@tonic-gate * For files other than hard links, getdir() sets 3466*7c478bd9Sstevel@tonic-gate * the file type bits in the st_mode field of the 3467*7c478bd9Sstevel@tonic-gate * stat structure based upon dblock.dbuf.typeflag. 3468*7c478bd9Sstevel@tonic-gate */ 3469*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3470*7c478bd9Sstevel@tonic-gate "tar: impossible file type")); 3471*7c478bd9Sstevel@tonic-gate } 3472*7c478bd9Sstevel@tonic-gate } 3473*7c478bd9Sstevel@tonic-gate 3474*7c478bd9Sstevel@tonic-gate if ((S_ISUID & Gen.g_mode) == S_ISUID) 3475*7c478bd9Sstevel@tonic-gate modestr[3] = 's'; 3476*7c478bd9Sstevel@tonic-gate if ((S_ISVTX & Gen.g_mode) == S_ISVTX) 3477*7c478bd9Sstevel@tonic-gate modestr[9] = 't'; 3478*7c478bd9Sstevel@tonic-gate if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x') 3479*7c478bd9Sstevel@tonic-gate modestr[6] = 's'; 3480*7c478bd9Sstevel@tonic-gate else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x') 3481*7c478bd9Sstevel@tonic-gate modestr[6] = 'l'; 3482*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%s", modestr); 3483*7c478bd9Sstevel@tonic-gate } 3484*7c478bd9Sstevel@tonic-gate 3485*7c478bd9Sstevel@tonic-gate static void 3486*7c478bd9Sstevel@tonic-gate longt(struct stat *st, char aclchar) 3487*7c478bd9Sstevel@tonic-gate { 3488*7c478bd9Sstevel@tonic-gate char fileDate[30]; 3489*7c478bd9Sstevel@tonic-gate struct tm *tm; 3490*7c478bd9Sstevel@tonic-gate 3491*7c478bd9Sstevel@tonic-gate verbose(st, aclchar); 3492*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid); 3493*7c478bd9Sstevel@tonic-gate 3494*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2') { 3495*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) 3496*7c478bd9Sstevel@tonic-gate st->st_size = (off_t)strlen(Xtarhdr.x_linkpath); 3497*7c478bd9Sstevel@tonic-gate else 3498*7c478bd9Sstevel@tonic-gate st->st_size = (off_t)(memchr(dblock.dbuf.linkname, 3499*7c478bd9Sstevel@tonic-gate '\0', NAMSIZ) ? 3500*7c478bd9Sstevel@tonic-gate (strlen(dblock.dbuf.linkname)) : (NAMSIZ)); 3501*7c478bd9Sstevel@tonic-gate } 3502*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, " %6" FMT_off_t, st->st_size); 3503*7c478bd9Sstevel@tonic-gate 3504*7c478bd9Sstevel@tonic-gate tm = localtime(&(st->st_mtime)); 3505*7c478bd9Sstevel@tonic-gate (void) strftime(fileDate, sizeof (fileDate), 3506*7c478bd9Sstevel@tonic-gate dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm); 3507*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, " %s ", fileDate); 3508*7c478bd9Sstevel@tonic-gate } 3509*7c478bd9Sstevel@tonic-gate 3510*7c478bd9Sstevel@tonic-gate 3511*7c478bd9Sstevel@tonic-gate /* 3512*7c478bd9Sstevel@tonic-gate * checkdir - Attempt to ensure that the path represented in name 3513*7c478bd9Sstevel@tonic-gate * exists, and return 1 if this is true and name itself is a 3514*7c478bd9Sstevel@tonic-gate * directory. 3515*7c478bd9Sstevel@tonic-gate * Return 0 if this path cannot be created or if name is not 3516*7c478bd9Sstevel@tonic-gate * a directory. 3517*7c478bd9Sstevel@tonic-gate */ 3518*7c478bd9Sstevel@tonic-gate 3519*7c478bd9Sstevel@tonic-gate static int 3520*7c478bd9Sstevel@tonic-gate checkdir(char *name) 3521*7c478bd9Sstevel@tonic-gate { 3522*7c478bd9Sstevel@tonic-gate char lastChar; /* the last character in name */ 3523*7c478bd9Sstevel@tonic-gate char *cp; /* scratch pointer into name */ 3524*7c478bd9Sstevel@tonic-gate char *firstSlash = NULL; /* first slash in name */ 3525*7c478bd9Sstevel@tonic-gate char *lastSlash = NULL; /* last slash in name */ 3526*7c478bd9Sstevel@tonic-gate int nameLen; /* length of name */ 3527*7c478bd9Sstevel@tonic-gate int trailingSlash; /* true if name ends in slash */ 3528*7c478bd9Sstevel@tonic-gate int leadingSlash; /* true if name begins with slash */ 3529*7c478bd9Sstevel@tonic-gate int markedDir; /* true if name denotes a directory */ 3530*7c478bd9Sstevel@tonic-gate int success; /* status of makeDir call */ 3531*7c478bd9Sstevel@tonic-gate 3532*7c478bd9Sstevel@tonic-gate 3533*7c478bd9Sstevel@tonic-gate /* 3534*7c478bd9Sstevel@tonic-gate * Scan through the name, and locate first and last slashes. 3535*7c478bd9Sstevel@tonic-gate */ 3536*7c478bd9Sstevel@tonic-gate 3537*7c478bd9Sstevel@tonic-gate for (cp = name; *cp; cp++) { 3538*7c478bd9Sstevel@tonic-gate if (*cp == '/') { 3539*7c478bd9Sstevel@tonic-gate if (! firstSlash) { 3540*7c478bd9Sstevel@tonic-gate firstSlash = cp; 3541*7c478bd9Sstevel@tonic-gate } 3542*7c478bd9Sstevel@tonic-gate lastSlash = cp; 3543*7c478bd9Sstevel@tonic-gate } 3544*7c478bd9Sstevel@tonic-gate } 3545*7c478bd9Sstevel@tonic-gate 3546*7c478bd9Sstevel@tonic-gate /* 3547*7c478bd9Sstevel@tonic-gate * Determine what you can from the proceeds of the scan. 3548*7c478bd9Sstevel@tonic-gate */ 3549*7c478bd9Sstevel@tonic-gate 3550*7c478bd9Sstevel@tonic-gate lastChar = *(cp - 1); 3551*7c478bd9Sstevel@tonic-gate nameLen = (int)(cp - name); 3552*7c478bd9Sstevel@tonic-gate trailingSlash = (lastChar == '/'); 3553*7c478bd9Sstevel@tonic-gate leadingSlash = (*name == '/'); 3554*7c478bd9Sstevel@tonic-gate markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash); 3555*7c478bd9Sstevel@tonic-gate 3556*7c478bd9Sstevel@tonic-gate if (! lastSlash && ! markedDir) { 3557*7c478bd9Sstevel@tonic-gate /* 3558*7c478bd9Sstevel@tonic-gate * The named file does not have any subdrectory 3559*7c478bd9Sstevel@tonic-gate * structure; just bail out. 3560*7c478bd9Sstevel@tonic-gate */ 3561*7c478bd9Sstevel@tonic-gate 3562*7c478bd9Sstevel@tonic-gate return (0); 3563*7c478bd9Sstevel@tonic-gate } 3564*7c478bd9Sstevel@tonic-gate 3565*7c478bd9Sstevel@tonic-gate /* 3566*7c478bd9Sstevel@tonic-gate * Make sure that name doesn`t end with slash for the loop. 3567*7c478bd9Sstevel@tonic-gate * This ensures that the makeDir attempt after the loop is 3568*7c478bd9Sstevel@tonic-gate * meaningful. 3569*7c478bd9Sstevel@tonic-gate */ 3570*7c478bd9Sstevel@tonic-gate 3571*7c478bd9Sstevel@tonic-gate if (trailingSlash) { 3572*7c478bd9Sstevel@tonic-gate name[nameLen-1] = '\0'; 3573*7c478bd9Sstevel@tonic-gate } 3574*7c478bd9Sstevel@tonic-gate 3575*7c478bd9Sstevel@tonic-gate /* 3576*7c478bd9Sstevel@tonic-gate * Make the path one component at a time. 3577*7c478bd9Sstevel@tonic-gate */ 3578*7c478bd9Sstevel@tonic-gate 3579*7c478bd9Sstevel@tonic-gate for (cp = strchr(leadingSlash ? name+1 : name, '/'); 3580*7c478bd9Sstevel@tonic-gate cp; 3581*7c478bd9Sstevel@tonic-gate cp = strchr(cp+1, '/')) { 3582*7c478bd9Sstevel@tonic-gate *cp = '\0'; 3583*7c478bd9Sstevel@tonic-gate success = makeDir(name); 3584*7c478bd9Sstevel@tonic-gate *cp = '/'; 3585*7c478bd9Sstevel@tonic-gate 3586*7c478bd9Sstevel@tonic-gate if (!success) { 3587*7c478bd9Sstevel@tonic-gate name[nameLen-1] = lastChar; 3588*7c478bd9Sstevel@tonic-gate return (0); 3589*7c478bd9Sstevel@tonic-gate } 3590*7c478bd9Sstevel@tonic-gate } 3591*7c478bd9Sstevel@tonic-gate 3592*7c478bd9Sstevel@tonic-gate /* 3593*7c478bd9Sstevel@tonic-gate * This makes the last component of the name, if it is a 3594*7c478bd9Sstevel@tonic-gate * directory. 3595*7c478bd9Sstevel@tonic-gate */ 3596*7c478bd9Sstevel@tonic-gate 3597*7c478bd9Sstevel@tonic-gate if (markedDir) { 3598*7c478bd9Sstevel@tonic-gate if (! makeDir(name)) { 3599*7c478bd9Sstevel@tonic-gate name[nameLen-1] = lastChar; 3600*7c478bd9Sstevel@tonic-gate return (0); 3601*7c478bd9Sstevel@tonic-gate } 3602*7c478bd9Sstevel@tonic-gate } 3603*7c478bd9Sstevel@tonic-gate 3604*7c478bd9Sstevel@tonic-gate name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar; 3605*7c478bd9Sstevel@tonic-gate return (markedDir); 3606*7c478bd9Sstevel@tonic-gate } 3607*7c478bd9Sstevel@tonic-gate 3608*7c478bd9Sstevel@tonic-gate /* 3609*7c478bd9Sstevel@tonic-gate * resugname - Restore the user name and group name. Search the NIS 3610*7c478bd9Sstevel@tonic-gate * before using the uid and gid. 3611*7c478bd9Sstevel@tonic-gate * (It is presumed that an archive entry cannot be 3612*7c478bd9Sstevel@tonic-gate * simultaneously a symlink and some other type.) 3613*7c478bd9Sstevel@tonic-gate */ 3614*7c478bd9Sstevel@tonic-gate 3615*7c478bd9Sstevel@tonic-gate static void 3616*7c478bd9Sstevel@tonic-gate resugname(int dirfd, /* dir fd file resides in */ 3617*7c478bd9Sstevel@tonic-gate char *name, /* name of the file to be modified */ 3618*7c478bd9Sstevel@tonic-gate int symflag) /* true if file is a symbolic link */ 3619*7c478bd9Sstevel@tonic-gate { 3620*7c478bd9Sstevel@tonic-gate uid_t duid; 3621*7c478bd9Sstevel@tonic-gate gid_t dgid; 3622*7c478bd9Sstevel@tonic-gate struct stat *sp = &stbuf; 3623*7c478bd9Sstevel@tonic-gate char *u_g_name; 3624*7c478bd9Sstevel@tonic-gate 3625*7c478bd9Sstevel@tonic-gate if (checkflag == 1) { /* Extended tar format and euid == 0 */ 3626*7c478bd9Sstevel@tonic-gate 3627*7c478bd9Sstevel@tonic-gate /* 3628*7c478bd9Sstevel@tonic-gate * Try and extract the intended uid and gid from the name 3629*7c478bd9Sstevel@tonic-gate * service before believing the uid and gid in the header. 3630*7c478bd9Sstevel@tonic-gate * 3631*7c478bd9Sstevel@tonic-gate * In the case where we archived a setuid or setgid file 3632*7c478bd9Sstevel@tonic-gate * owned by someone with a large uid, then it will 3633*7c478bd9Sstevel@tonic-gate * have made it into the archive with a uid of nobody. If 3634*7c478bd9Sstevel@tonic-gate * the corresponding username doesn't appear to exist, then we 3635*7c478bd9Sstevel@tonic-gate * want to make sure it *doesn't* end up as setuid nobody! 3636*7c478bd9Sstevel@tonic-gate * 3637*7c478bd9Sstevel@tonic-gate * Our caller will print an error message about the fact 3638*7c478bd9Sstevel@tonic-gate * that the restore didn't work out quite right .. 3639*7c478bd9Sstevel@tonic-gate */ 3640*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_UNAME) 3641*7c478bd9Sstevel@tonic-gate u_g_name = Xtarhdr.x_uname; 3642*7c478bd9Sstevel@tonic-gate else 3643*7c478bd9Sstevel@tonic-gate u_g_name = dblock.dbuf.uname; 3644*7c478bd9Sstevel@tonic-gate if ((duid = getuidbyname(u_g_name)) == -1) { 3645*7c478bd9Sstevel@tonic-gate if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY && 3646*7c478bd9Sstevel@tonic-gate (sp->st_mode & S_ISUID) == S_ISUID) 3647*7c478bd9Sstevel@tonic-gate (void) chmod(name, 3648*7c478bd9Sstevel@tonic-gate MODEMASK & sp->st_mode & ~S_ISUID); 3649*7c478bd9Sstevel@tonic-gate duid = sp->st_uid; 3650*7c478bd9Sstevel@tonic-gate } 3651*7c478bd9Sstevel@tonic-gate 3652*7c478bd9Sstevel@tonic-gate /* (Ditto for gids) */ 3653*7c478bd9Sstevel@tonic-gate 3654*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_GNAME) 3655*7c478bd9Sstevel@tonic-gate u_g_name = Xtarhdr.x_gname; 3656*7c478bd9Sstevel@tonic-gate else 3657*7c478bd9Sstevel@tonic-gate u_g_name = dblock.dbuf.gname; 3658*7c478bd9Sstevel@tonic-gate if ((dgid = getgidbyname(u_g_name)) == -1) { 3659*7c478bd9Sstevel@tonic-gate if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY && 3660*7c478bd9Sstevel@tonic-gate (sp->st_mode & S_ISGID) == S_ISGID) 3661*7c478bd9Sstevel@tonic-gate (void) chmod(name, 3662*7c478bd9Sstevel@tonic-gate MODEMASK & sp->st_mode & ~S_ISGID); 3663*7c478bd9Sstevel@tonic-gate dgid = sp->st_gid; 3664*7c478bd9Sstevel@tonic-gate } 3665*7c478bd9Sstevel@tonic-gate } else if (checkflag == 2) { /* tar format and euid == 0 */ 3666*7c478bd9Sstevel@tonic-gate duid = sp->st_uid; 3667*7c478bd9Sstevel@tonic-gate dgid = sp->st_gid; 3668*7c478bd9Sstevel@tonic-gate } 3669*7c478bd9Sstevel@tonic-gate if ((checkflag == 1) || (checkflag == 2)) 3670*7c478bd9Sstevel@tonic-gate (void) fchownat(dirfd, name, duid, dgid, symflag); 3671*7c478bd9Sstevel@tonic-gate } 3672*7c478bd9Sstevel@tonic-gate 3673*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3674*7c478bd9Sstevel@tonic-gate static void 3675*7c478bd9Sstevel@tonic-gate onintr(int sig) 3676*7c478bd9Sstevel@tonic-gate { 3677*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); 3678*7c478bd9Sstevel@tonic-gate term++; 3679*7c478bd9Sstevel@tonic-gate } 3680*7c478bd9Sstevel@tonic-gate 3681*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3682*7c478bd9Sstevel@tonic-gate static void 3683*7c478bd9Sstevel@tonic-gate onquit(int sig) 3684*7c478bd9Sstevel@tonic-gate { 3685*7c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN); 3686*7c478bd9Sstevel@tonic-gate term++; 3687*7c478bd9Sstevel@tonic-gate } 3688*7c478bd9Sstevel@tonic-gate 3689*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3690*7c478bd9Sstevel@tonic-gate static void 3691*7c478bd9Sstevel@tonic-gate onhup(int sig) 3692*7c478bd9Sstevel@tonic-gate { 3693*7c478bd9Sstevel@tonic-gate (void) signal(SIGHUP, SIG_IGN); 3694*7c478bd9Sstevel@tonic-gate term++; 3695*7c478bd9Sstevel@tonic-gate } 3696*7c478bd9Sstevel@tonic-gate 3697*7c478bd9Sstevel@tonic-gate static void 3698*7c478bd9Sstevel@tonic-gate tomodes(struct stat *sp) 3699*7c478bd9Sstevel@tonic-gate { 3700*7c478bd9Sstevel@tonic-gate uid_t uid; 3701*7c478bd9Sstevel@tonic-gate gid_t gid; 3702*7c478bd9Sstevel@tonic-gate 3703*7c478bd9Sstevel@tonic-gate bzero(dblock.dummy, TBLOCK); 3704*7c478bd9Sstevel@tonic-gate 3705*7c478bd9Sstevel@tonic-gate /* 3706*7c478bd9Sstevel@tonic-gate * If the uid or gid is too large, we can't put it into 3707*7c478bd9Sstevel@tonic-gate * the archive. We could fail to put anything in the 3708*7c478bd9Sstevel@tonic-gate * archive at all .. but most of the time the name service 3709*7c478bd9Sstevel@tonic-gate * will save the day when we do a lookup at restore time. 3710*7c478bd9Sstevel@tonic-gate * 3711*7c478bd9Sstevel@tonic-gate * Instead we choose a "safe" uid and gid, and fix up whether 3712*7c478bd9Sstevel@tonic-gate * or not the setuid and setgid bits are left set to extraction 3713*7c478bd9Sstevel@tonic-gate * time. 3714*7c478bd9Sstevel@tonic-gate */ 3715*7c478bd9Sstevel@tonic-gate if (Eflag) { 3716*7c478bd9Sstevel@tonic-gate if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) { 3717*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_UID; 3718*7c478bd9Sstevel@tonic-gate Xtarhdr.x_uid = uid; 3719*7c478bd9Sstevel@tonic-gate } 3720*7c478bd9Sstevel@tonic-gate if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) { 3721*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_GID; 3722*7c478bd9Sstevel@tonic-gate Xtarhdr.x_gid = gid; 3723*7c478bd9Sstevel@tonic-gate } 3724*7c478bd9Sstevel@tonic-gate if (sp->st_size > TAR_OFFSET_MAX) { 3725*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_SIZE; 3726*7c478bd9Sstevel@tonic-gate Xtarhdr.x_filesz = sp->st_size; 3727*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, 3728*7c478bd9Sstevel@tonic-gate (off_t)0); 3729*7c478bd9Sstevel@tonic-gate } else 3730*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, 3731*7c478bd9Sstevel@tonic-gate sp->st_size); 3732*7c478bd9Sstevel@tonic-gate } else { 3733*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, 3734*7c478bd9Sstevel@tonic-gate sp->st_size); 3735*7c478bd9Sstevel@tonic-gate } 3736*7c478bd9Sstevel@tonic-gate if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) 3737*7c478bd9Sstevel@tonic-gate uid = UID_NOBODY; 3738*7c478bd9Sstevel@tonic-gate if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) 3739*7c478bd9Sstevel@tonic-gate gid = GID_NOBODY; 3740*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.gid, "%07lo", gid); 3741*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.uid, "%07lo", uid); 3742*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES); 3743*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime); 3744*7c478bd9Sstevel@tonic-gate } 3745*7c478bd9Sstevel@tonic-gate 3746*7c478bd9Sstevel@tonic-gate static int 3747*7c478bd9Sstevel@tonic-gate #ifdef EUC 3748*7c478bd9Sstevel@tonic-gate /* 3749*7c478bd9Sstevel@tonic-gate * Warning: the result of this function depends whether 'char' is a 3750*7c478bd9Sstevel@tonic-gate * signed or unsigned data type. This a source of potential 3751*7c478bd9Sstevel@tonic-gate * non-portability among heterogeneous systems. It is retained here 3752*7c478bd9Sstevel@tonic-gate * for backward compatibility. 3753*7c478bd9Sstevel@tonic-gate */ 3754*7c478bd9Sstevel@tonic-gate checksum_signed(union hblock *dblockp) 3755*7c478bd9Sstevel@tonic-gate #else 3756*7c478bd9Sstevel@tonic-gate checksum(union hblock *dblockp) 3757*7c478bd9Sstevel@tonic-gate #endif /* EUC */ 3758*7c478bd9Sstevel@tonic-gate { 3759*7c478bd9Sstevel@tonic-gate int i; 3760*7c478bd9Sstevel@tonic-gate char *cp; 3761*7c478bd9Sstevel@tonic-gate 3762*7c478bd9Sstevel@tonic-gate for (cp = dblockp->dbuf.chksum; 3763*7c478bd9Sstevel@tonic-gate cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++) 3764*7c478bd9Sstevel@tonic-gate *cp = ' '; 3765*7c478bd9Sstevel@tonic-gate i = 0; 3766*7c478bd9Sstevel@tonic-gate for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++) 3767*7c478bd9Sstevel@tonic-gate i += *cp; 3768*7c478bd9Sstevel@tonic-gate return (i); 3769*7c478bd9Sstevel@tonic-gate } 3770*7c478bd9Sstevel@tonic-gate 3771*7c478bd9Sstevel@tonic-gate #ifdef EUC 3772*7c478bd9Sstevel@tonic-gate /* 3773*7c478bd9Sstevel@tonic-gate * Generate unsigned checksum, regardless of what C compiler is 3774*7c478bd9Sstevel@tonic-gate * used. Survives in the face of arbitrary 8-bit clean filenames, 3775*7c478bd9Sstevel@tonic-gate * e.g., internationalized filenames. 3776*7c478bd9Sstevel@tonic-gate */ 3777*7c478bd9Sstevel@tonic-gate static int 3778*7c478bd9Sstevel@tonic-gate checksum(union hblock *dblockp) 3779*7c478bd9Sstevel@tonic-gate { 3780*7c478bd9Sstevel@tonic-gate unsigned i; 3781*7c478bd9Sstevel@tonic-gate unsigned char *cp; 3782*7c478bd9Sstevel@tonic-gate 3783*7c478bd9Sstevel@tonic-gate for (cp = (unsigned char *) dblockp->dbuf.chksum; 3784*7c478bd9Sstevel@tonic-gate cp < (unsigned char *) 3785*7c478bd9Sstevel@tonic-gate &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++) 3786*7c478bd9Sstevel@tonic-gate *cp = ' '; 3787*7c478bd9Sstevel@tonic-gate i = 0; 3788*7c478bd9Sstevel@tonic-gate for (cp = (unsigned char *) dblockp->dummy; 3789*7c478bd9Sstevel@tonic-gate cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++) 3790*7c478bd9Sstevel@tonic-gate i += *cp; 3791*7c478bd9Sstevel@tonic-gate 3792*7c478bd9Sstevel@tonic-gate return (i); 3793*7c478bd9Sstevel@tonic-gate } 3794*7c478bd9Sstevel@tonic-gate #endif /* EUC */ 3795*7c478bd9Sstevel@tonic-gate 3796*7c478bd9Sstevel@tonic-gate /* 3797*7c478bd9Sstevel@tonic-gate * If the w flag is set, output the action to be taken and the name of the 3798*7c478bd9Sstevel@tonic-gate * file. Perform the action if the user response is affirmative. 3799*7c478bd9Sstevel@tonic-gate */ 3800*7c478bd9Sstevel@tonic-gate 3801*7c478bd9Sstevel@tonic-gate static int 3802*7c478bd9Sstevel@tonic-gate checkw(char c, char *name) 3803*7c478bd9Sstevel@tonic-gate { 3804*7c478bd9Sstevel@tonic-gate if (wflag) { 3805*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%c ", c); 3806*7c478bd9Sstevel@tonic-gate if (vflag) 3807*7c478bd9Sstevel@tonic-gate longt(&stbuf, ' '); /* do we have acl info here */ 3808*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, "%s: ", name); 3809*7c478bd9Sstevel@tonic-gate if (response() == 'y') { 3810*7c478bd9Sstevel@tonic-gate return (1); 3811*7c478bd9Sstevel@tonic-gate } 3812*7c478bd9Sstevel@tonic-gate return (0); 3813*7c478bd9Sstevel@tonic-gate } 3814*7c478bd9Sstevel@tonic-gate return (1); 3815*7c478bd9Sstevel@tonic-gate } 3816*7c478bd9Sstevel@tonic-gate 3817*7c478bd9Sstevel@tonic-gate /* 3818*7c478bd9Sstevel@tonic-gate * When the F flag is set, exclude RCS and SCCS directories. If F is set 3819*7c478bd9Sstevel@tonic-gate * twice, also exclude .o files, and files names errs, core, and a.out. 3820*7c478bd9Sstevel@tonic-gate */ 3821*7c478bd9Sstevel@tonic-gate 3822*7c478bd9Sstevel@tonic-gate static int 3823*7c478bd9Sstevel@tonic-gate checkf(char *name, int mode, int howmuch) 3824*7c478bd9Sstevel@tonic-gate { 3825*7c478bd9Sstevel@tonic-gate int l; 3826*7c478bd9Sstevel@tonic-gate 3827*7c478bd9Sstevel@tonic-gate if ((mode & S_IFMT) == S_IFDIR) { 3828*7c478bd9Sstevel@tonic-gate if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0)) 3829*7c478bd9Sstevel@tonic-gate return (0); 3830*7c478bd9Sstevel@tonic-gate return (1); 3831*7c478bd9Sstevel@tonic-gate } 3832*7c478bd9Sstevel@tonic-gate if ((l = (int)strlen(name)) < 3) 3833*7c478bd9Sstevel@tonic-gate return (1); 3834*7c478bd9Sstevel@tonic-gate if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 3835*7c478bd9Sstevel@tonic-gate return (0); 3836*7c478bd9Sstevel@tonic-gate if (howmuch > 1) { 3837*7c478bd9Sstevel@tonic-gate if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 || 3838*7c478bd9Sstevel@tonic-gate strcmp(name, "a.out") == 0) 3839*7c478bd9Sstevel@tonic-gate return (0); 3840*7c478bd9Sstevel@tonic-gate } 3841*7c478bd9Sstevel@tonic-gate 3842*7c478bd9Sstevel@tonic-gate /* SHOULD CHECK IF IT IS EXECUTABLE */ 3843*7c478bd9Sstevel@tonic-gate return (1); 3844*7c478bd9Sstevel@tonic-gate } 3845*7c478bd9Sstevel@tonic-gate 3846*7c478bd9Sstevel@tonic-gate static int 3847*7c478bd9Sstevel@tonic-gate response(void) 3848*7c478bd9Sstevel@tonic-gate { 3849*7c478bd9Sstevel@tonic-gate int c; 3850*7c478bd9Sstevel@tonic-gate 3851*7c478bd9Sstevel@tonic-gate c = getchar(); 3852*7c478bd9Sstevel@tonic-gate if (c != '\n') 3853*7c478bd9Sstevel@tonic-gate while (getchar() != '\n'); 3854*7c478bd9Sstevel@tonic-gate else c = 'n'; 3855*7c478bd9Sstevel@tonic-gate return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c); 3856*7c478bd9Sstevel@tonic-gate } 3857*7c478bd9Sstevel@tonic-gate 3858*7c478bd9Sstevel@tonic-gate /* Has file been modified since being put into archive? If so, return > 0. */ 3859*7c478bd9Sstevel@tonic-gate 3860*7c478bd9Sstevel@tonic-gate static int 3861*7c478bd9Sstevel@tonic-gate checkupdate(char *arg) 3862*7c478bd9Sstevel@tonic-gate { 3863*7c478bd9Sstevel@tonic-gate char name[PATH_MAX+1]; 3864*7c478bd9Sstevel@tonic-gate time_t mtime; 3865*7c478bd9Sstevel@tonic-gate long nsecs; 3866*7c478bd9Sstevel@tonic-gate off_t seekp; 3867*7c478bd9Sstevel@tonic-gate static off_t lookup(char *); 3868*7c478bd9Sstevel@tonic-gate 3869*7c478bd9Sstevel@tonic-gate rewind(tfile); 3870*7c478bd9Sstevel@tonic-gate if ((seekp = lookup(arg)) < 0) 3871*7c478bd9Sstevel@tonic-gate return (1); 3872*7c478bd9Sstevel@tonic-gate (void) fseek(tfile, seekp, 0); 3873*7c478bd9Sstevel@tonic-gate (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs); 3874*7c478bd9Sstevel@tonic-gate 3875*7c478bd9Sstevel@tonic-gate /* 3876*7c478bd9Sstevel@tonic-gate * Unless nanoseconds were stored in the file, only use seconds for 3877*7c478bd9Sstevel@tonic-gate * comparison of time. Nanoseconds are stored when -E is specified. 3878*7c478bd9Sstevel@tonic-gate */ 3879*7c478bd9Sstevel@tonic-gate if (Eflag == 0) 3880*7c478bd9Sstevel@tonic-gate return (stbuf.st_mtime > mtime); 3881*7c478bd9Sstevel@tonic-gate 3882*7c478bd9Sstevel@tonic-gate if ((stbuf.st_mtime < mtime) || 3883*7c478bd9Sstevel@tonic-gate ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs))) 3884*7c478bd9Sstevel@tonic-gate return (0); 3885*7c478bd9Sstevel@tonic-gate return (1); 3886*7c478bd9Sstevel@tonic-gate } 3887*7c478bd9Sstevel@tonic-gate 3888*7c478bd9Sstevel@tonic-gate 3889*7c478bd9Sstevel@tonic-gate /* 3890*7c478bd9Sstevel@tonic-gate * newvol get new floppy (or tape) volume 3891*7c478bd9Sstevel@tonic-gate * 3892*7c478bd9Sstevel@tonic-gate * newvol(); resets tapepos and first to TRUE, prompts for 3893*7c478bd9Sstevel@tonic-gate * for new volume, and waits. 3894*7c478bd9Sstevel@tonic-gate * if dumping, end-of-file is written onto the tape. 3895*7c478bd9Sstevel@tonic-gate */ 3896*7c478bd9Sstevel@tonic-gate 3897*7c478bd9Sstevel@tonic-gate static void 3898*7c478bd9Sstevel@tonic-gate newvol(void) 3899*7c478bd9Sstevel@tonic-gate { 3900*7c478bd9Sstevel@tonic-gate int c; 3901*7c478bd9Sstevel@tonic-gate 3902*7c478bd9Sstevel@tonic-gate if (dumping) { 3903*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3904*7c478bd9Sstevel@tonic-gate DEBUG("newvol called with 'dumping' set\n", 0, 0); 3905*7c478bd9Sstevel@tonic-gate #endif 3906*7c478bd9Sstevel@tonic-gate putempty((blkcnt_t)2); /* 2 EOT marks */ 3907*7c478bd9Sstevel@tonic-gate closevol(); 3908*7c478bd9Sstevel@tonic-gate flushtape(); 3909*7c478bd9Sstevel@tonic-gate sync(); 3910*7c478bd9Sstevel@tonic-gate tapepos = 0; 3911*7c478bd9Sstevel@tonic-gate } else 3912*7c478bd9Sstevel@tonic-gate first = TRUE; 3913*7c478bd9Sstevel@tonic-gate if (close(mt) != 0) 3914*7c478bd9Sstevel@tonic-gate vperror(2, gettext("close error")); 3915*7c478bd9Sstevel@tonic-gate mt = 0; 3916*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3917*7c478bd9Sstevel@tonic-gate "tar: \007please insert new volume, then press RETURN.")); 3918*7c478bd9Sstevel@tonic-gate (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */ 3919*7c478bd9Sstevel@tonic-gate while ((c = getchar()) != '\n' && ! term) 3920*7c478bd9Sstevel@tonic-gate if (c == EOF) 3921*7c478bd9Sstevel@tonic-gate done(Errflg); 3922*7c478bd9Sstevel@tonic-gate if (term) 3923*7c478bd9Sstevel@tonic-gate done(Errflg); 3924*7c478bd9Sstevel@tonic-gate 3925*7c478bd9Sstevel@tonic-gate errno = 0; 3926*7c478bd9Sstevel@tonic-gate 3927*7c478bd9Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) { 3928*7c478bd9Sstevel@tonic-gate mt = dup(1); 3929*7c478bd9Sstevel@tonic-gate } else { 3930*7c478bd9Sstevel@tonic-gate mt = open(usefile, dumping ? update : 0); 3931*7c478bd9Sstevel@tonic-gate } 3932*7c478bd9Sstevel@tonic-gate 3933*7c478bd9Sstevel@tonic-gate if (mt < 0) { 3934*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3935*7c478bd9Sstevel@tonic-gate "tar: cannot reopen %s (%s)\n"), 3936*7c478bd9Sstevel@tonic-gate dumping ? gettext("output") : gettext("input"), usefile); 3937*7c478bd9Sstevel@tonic-gate 3938*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "update=%d, usefile=%s, mt=%d, [%s]\n", 3939*7c478bd9Sstevel@tonic-gate update, usefile, mt, strerror(errno)); 3940*7c478bd9Sstevel@tonic-gate 3941*7c478bd9Sstevel@tonic-gate done(2); 3942*7c478bd9Sstevel@tonic-gate } 3943*7c478bd9Sstevel@tonic-gate } 3944*7c478bd9Sstevel@tonic-gate 3945*7c478bd9Sstevel@tonic-gate /* 3946*7c478bd9Sstevel@tonic-gate * Write a trailer portion to close out the current output volume. 3947*7c478bd9Sstevel@tonic-gate */ 3948*7c478bd9Sstevel@tonic-gate 3949*7c478bd9Sstevel@tonic-gate static void 3950*7c478bd9Sstevel@tonic-gate closevol(void) 3951*7c478bd9Sstevel@tonic-gate { 3952*7c478bd9Sstevel@tonic-gate if (mulvol) { 3953*7c478bd9Sstevel@tonic-gate /* 3954*7c478bd9Sstevel@tonic-gate * blocklim does not count the 2 EOT marks; 3955*7c478bd9Sstevel@tonic-gate * tapepos does count the 2 EOT marks; 3956*7c478bd9Sstevel@tonic-gate * therefore we need the +2 below. 3957*7c478bd9Sstevel@tonic-gate */ 3958*7c478bd9Sstevel@tonic-gate putempty(blocklim + (blkcnt_t)2 - tapepos); 3959*7c478bd9Sstevel@tonic-gate } 3960*7c478bd9Sstevel@tonic-gate } 3961*7c478bd9Sstevel@tonic-gate 3962*7c478bd9Sstevel@tonic-gate static void 3963*7c478bd9Sstevel@tonic-gate done(int n) 3964*7c478bd9Sstevel@tonic-gate { 3965*7c478bd9Sstevel@tonic-gate (void) unlink(tname); 3966*7c478bd9Sstevel@tonic-gate if (mt > 0) { 3967*7c478bd9Sstevel@tonic-gate if ((close(mt) != 0) || (fclose(stdout) != 0)) { 3968*7c478bd9Sstevel@tonic-gate perror(gettext("tar: close error")); 3969*7c478bd9Sstevel@tonic-gate exit(2); 3970*7c478bd9Sstevel@tonic-gate } 3971*7c478bd9Sstevel@tonic-gate } 3972*7c478bd9Sstevel@tonic-gate exit(n); 3973*7c478bd9Sstevel@tonic-gate } 3974*7c478bd9Sstevel@tonic-gate 3975*7c478bd9Sstevel@tonic-gate /* 3976*7c478bd9Sstevel@tonic-gate * Determine if s1 is a prefix portion of s2 (or the same as s2). 3977*7c478bd9Sstevel@tonic-gate */ 3978*7c478bd9Sstevel@tonic-gate 3979*7c478bd9Sstevel@tonic-gate static int 3980*7c478bd9Sstevel@tonic-gate is_prefix(char *s1, char *s2) 3981*7c478bd9Sstevel@tonic-gate { 3982*7c478bd9Sstevel@tonic-gate while (*s1) 3983*7c478bd9Sstevel@tonic-gate if (*s1++ != *s2++) 3984*7c478bd9Sstevel@tonic-gate return (0); 3985*7c478bd9Sstevel@tonic-gate if (*s2) 3986*7c478bd9Sstevel@tonic-gate return (*s2 == '/'); 3987*7c478bd9Sstevel@tonic-gate return (1); 3988*7c478bd9Sstevel@tonic-gate } 3989*7c478bd9Sstevel@tonic-gate 3990*7c478bd9Sstevel@tonic-gate /* 3991*7c478bd9Sstevel@tonic-gate * lookup and bsrch look through tfile entries to find a match for a name. 3992*7c478bd9Sstevel@tonic-gate * The name can be up to PATH_MAX bytes. bsrch compares what it sees between 3993*7c478bd9Sstevel@tonic-gate * a pair of newline chars, so the buffer it uses must be long enough for 3994*7c478bd9Sstevel@tonic-gate * two lines: name and modification time as well as period, newline and space. 3995*7c478bd9Sstevel@tonic-gate * 3996*7c478bd9Sstevel@tonic-gate * A kludge was added to bsrch to take care of matching on the first entry 3997*7c478bd9Sstevel@tonic-gate * in the file--there is no leading newline. So, if we are reading from the 3998*7c478bd9Sstevel@tonic-gate * start of the file, read into byte two and set the first byte to a newline. 3999*7c478bd9Sstevel@tonic-gate * Otherwise, the first entry cannot be matched. 4000*7c478bd9Sstevel@tonic-gate * 4001*7c478bd9Sstevel@tonic-gate */ 4002*7c478bd9Sstevel@tonic-gate 4003*7c478bd9Sstevel@tonic-gate #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3)) 4004*7c478bd9Sstevel@tonic-gate static off_t 4005*7c478bd9Sstevel@tonic-gate lookup(char *s) 4006*7c478bd9Sstevel@tonic-gate { 4007*7c478bd9Sstevel@tonic-gate int i; 4008*7c478bd9Sstevel@tonic-gate off_t a; 4009*7c478bd9Sstevel@tonic-gate 4010*7c478bd9Sstevel@tonic-gate for (i = 0; s[i]; i++) 4011*7c478bd9Sstevel@tonic-gate if (s[i] == ' ') 4012*7c478bd9Sstevel@tonic-gate break; 4013*7c478bd9Sstevel@tonic-gate a = bsrch(s, i, low, high); 4014*7c478bd9Sstevel@tonic-gate return (a); 4015*7c478bd9Sstevel@tonic-gate } 4016*7c478bd9Sstevel@tonic-gate 4017*7c478bd9Sstevel@tonic-gate static off_t 4018*7c478bd9Sstevel@tonic-gate bsrch(char *s, int n, off_t l, off_t h) 4019*7c478bd9Sstevel@tonic-gate { 4020*7c478bd9Sstevel@tonic-gate int i, j; 4021*7c478bd9Sstevel@tonic-gate char b[N]; 4022*7c478bd9Sstevel@tonic-gate off_t m, m1; 4023*7c478bd9Sstevel@tonic-gate 4024*7c478bd9Sstevel@tonic-gate 4025*7c478bd9Sstevel@tonic-gate loop: 4026*7c478bd9Sstevel@tonic-gate if (l >= h) 4027*7c478bd9Sstevel@tonic-gate return ((off_t)-1); 4028*7c478bd9Sstevel@tonic-gate m = l + (h-l)/2 - N/2; 4029*7c478bd9Sstevel@tonic-gate if (m < l) 4030*7c478bd9Sstevel@tonic-gate m = l; 4031*7c478bd9Sstevel@tonic-gate (void) fseek(tfile, m, 0); 4032*7c478bd9Sstevel@tonic-gate if (m == 0) { 4033*7c478bd9Sstevel@tonic-gate (void) fread(b+1, 1, N-1, tfile); 4034*7c478bd9Sstevel@tonic-gate b[0] = '\n'; 4035*7c478bd9Sstevel@tonic-gate m--; 4036*7c478bd9Sstevel@tonic-gate } else 4037*7c478bd9Sstevel@tonic-gate (void) fread(b, 1, N, tfile); 4038*7c478bd9Sstevel@tonic-gate for (i = 0; i < N; i++) { 4039*7c478bd9Sstevel@tonic-gate if (b[i] == '\n') 4040*7c478bd9Sstevel@tonic-gate break; 4041*7c478bd9Sstevel@tonic-gate m++; 4042*7c478bd9Sstevel@tonic-gate } 4043*7c478bd9Sstevel@tonic-gate if (m >= h) 4044*7c478bd9Sstevel@tonic-gate return ((off_t)-1); 4045*7c478bd9Sstevel@tonic-gate m1 = m; 4046*7c478bd9Sstevel@tonic-gate j = i; 4047*7c478bd9Sstevel@tonic-gate for (i++; i < N; i++) { 4048*7c478bd9Sstevel@tonic-gate m1++; 4049*7c478bd9Sstevel@tonic-gate if (b[i] == '\n') 4050*7c478bd9Sstevel@tonic-gate break; 4051*7c478bd9Sstevel@tonic-gate } 4052*7c478bd9Sstevel@tonic-gate i = cmp(b+j, s, n); 4053*7c478bd9Sstevel@tonic-gate if (i < 0) { 4054*7c478bd9Sstevel@tonic-gate h = m; 4055*7c478bd9Sstevel@tonic-gate goto loop; 4056*7c478bd9Sstevel@tonic-gate } 4057*7c478bd9Sstevel@tonic-gate if (i > 0) { 4058*7c478bd9Sstevel@tonic-gate l = m1; 4059*7c478bd9Sstevel@tonic-gate goto loop; 4060*7c478bd9Sstevel@tonic-gate } 4061*7c478bd9Sstevel@tonic-gate if (m < 0) 4062*7c478bd9Sstevel@tonic-gate m = 0; 4063*7c478bd9Sstevel@tonic-gate return (m); 4064*7c478bd9Sstevel@tonic-gate } 4065*7c478bd9Sstevel@tonic-gate 4066*7c478bd9Sstevel@tonic-gate static int 4067*7c478bd9Sstevel@tonic-gate cmp(char *b, char *s, int n) 4068*7c478bd9Sstevel@tonic-gate { 4069*7c478bd9Sstevel@tonic-gate int i; 4070*7c478bd9Sstevel@tonic-gate 4071*7c478bd9Sstevel@tonic-gate assert(b[0] == '\n'); 4072*7c478bd9Sstevel@tonic-gate 4073*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 4074*7c478bd9Sstevel@tonic-gate if (b[i+1] > s[i]) 4075*7c478bd9Sstevel@tonic-gate return (-1); 4076*7c478bd9Sstevel@tonic-gate if (b[i+1] < s[i]) 4077*7c478bd9Sstevel@tonic-gate return (1); 4078*7c478bd9Sstevel@tonic-gate } 4079*7c478bd9Sstevel@tonic-gate return (b[i+1] == ' '? 0 : -1); 4080*7c478bd9Sstevel@tonic-gate } 4081*7c478bd9Sstevel@tonic-gate 4082*7c478bd9Sstevel@tonic-gate 4083*7c478bd9Sstevel@tonic-gate /* 4084*7c478bd9Sstevel@tonic-gate * seekdisk seek to next file on archive 4085*7c478bd9Sstevel@tonic-gate * 4086*7c478bd9Sstevel@tonic-gate * called by passtape() only 4087*7c478bd9Sstevel@tonic-gate * 4088*7c478bd9Sstevel@tonic-gate * WARNING: expects "nblock" to be set, that is, readtape() to have 4089*7c478bd9Sstevel@tonic-gate * already been called. Since passtape() is only called 4090*7c478bd9Sstevel@tonic-gate * after a file header block has been read (why else would 4091*7c478bd9Sstevel@tonic-gate * we skip to next file?), this is currently safe. 4092*7c478bd9Sstevel@tonic-gate * 4093*7c478bd9Sstevel@tonic-gate * changed to guarantee SYS_BLOCK boundary 4094*7c478bd9Sstevel@tonic-gate */ 4095*7c478bd9Sstevel@tonic-gate 4096*7c478bd9Sstevel@tonic-gate static void 4097*7c478bd9Sstevel@tonic-gate seekdisk(blkcnt_t blocks) 4098*7c478bd9Sstevel@tonic-gate { 4099*7c478bd9Sstevel@tonic-gate off_t seekval; 4100*7c478bd9Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 4101*7c478bd9Sstevel@tonic-gate /* handle non-multiple of SYS_BLOCK */ 4102*7c478bd9Sstevel@tonic-gate blkcnt_t nxb; /* # extra blocks */ 4103*7c478bd9Sstevel@tonic-gate #endif 4104*7c478bd9Sstevel@tonic-gate 4105*7c478bd9Sstevel@tonic-gate tapepos += blocks; 4106*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4107*7c478bd9Sstevel@tonic-gate DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0); 4108*7c478bd9Sstevel@tonic-gate #endif 4109*7c478bd9Sstevel@tonic-gate if (recno + blocks <= nblock) { 4110*7c478bd9Sstevel@tonic-gate recno += blocks; 4111*7c478bd9Sstevel@tonic-gate return; 4112*7c478bd9Sstevel@tonic-gate } 4113*7c478bd9Sstevel@tonic-gate if (recno > nblock) 4114*7c478bd9Sstevel@tonic-gate recno = nblock; 4115*7c478bd9Sstevel@tonic-gate seekval = (off_t)blocks - (nblock - recno); 4116*7c478bd9Sstevel@tonic-gate recno = nblock; /* so readtape() reads next time through */ 4117*7c478bd9Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 4118*7c478bd9Sstevel@tonic-gate nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK)); 4119*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4120*7c478bd9Sstevel@tonic-gate DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n", 4121*7c478bd9Sstevel@tonic-gate nxb, seekval); 4122*7c478bd9Sstevel@tonic-gate #endif 4123*7c478bd9Sstevel@tonic-gate if (nxb && nxb > seekval) /* don't seek--we'll read */ 4124*7c478bd9Sstevel@tonic-gate goto noseek; 4125*7c478bd9Sstevel@tonic-gate seekval -= nxb; /* don't seek quite so far */ 4126*7c478bd9Sstevel@tonic-gate #endif 4127*7c478bd9Sstevel@tonic-gate if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) { 4128*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4129*7c478bd9Sstevel@tonic-gate "tar: device seek error\n")); 4130*7c478bd9Sstevel@tonic-gate done(3); 4131*7c478bd9Sstevel@tonic-gate } 4132*7c478bd9Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 4133*7c478bd9Sstevel@tonic-gate /* read those extra blocks */ 4134*7c478bd9Sstevel@tonic-gate noseek: 4135*7c478bd9Sstevel@tonic-gate if (nxb) { 4136*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4137*7c478bd9Sstevel@tonic-gate DEBUG("reading extra blocks\n", 0, 0); 4138*7c478bd9Sstevel@tonic-gate #endif 4139*7c478bd9Sstevel@tonic-gate if (read(mt, tbuf, TBLOCK*nblock) < 0) { 4140*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4141*7c478bd9Sstevel@tonic-gate "tar: read error while skipping file\n")); 4142*7c478bd9Sstevel@tonic-gate done(8); 4143*7c478bd9Sstevel@tonic-gate } 4144*7c478bd9Sstevel@tonic-gate recno = nxb; /* so we don't read in next readtape() */ 4145*7c478bd9Sstevel@tonic-gate } 4146*7c478bd9Sstevel@tonic-gate #endif 4147*7c478bd9Sstevel@tonic-gate } 4148*7c478bd9Sstevel@tonic-gate 4149*7c478bd9Sstevel@tonic-gate static void 4150*7c478bd9Sstevel@tonic-gate readtape(char *buffer) 4151*7c478bd9Sstevel@tonic-gate { 4152*7c478bd9Sstevel@tonic-gate int i, j; 4153*7c478bd9Sstevel@tonic-gate 4154*7c478bd9Sstevel@tonic-gate ++tapepos; 4155*7c478bd9Sstevel@tonic-gate if (recno >= nblock || first) { 4156*7c478bd9Sstevel@tonic-gate if (first) { 4157*7c478bd9Sstevel@tonic-gate /* 4158*7c478bd9Sstevel@tonic-gate * set the number of blocks to read initially, based on 4159*7c478bd9Sstevel@tonic-gate * the defined defaults for the device, or on the 4160*7c478bd9Sstevel@tonic-gate * explicit block factor given. 4161*7c478bd9Sstevel@tonic-gate */ 4162*7c478bd9Sstevel@tonic-gate if (bflag || defaults_used) 4163*7c478bd9Sstevel@tonic-gate j = nblock; 4164*7c478bd9Sstevel@tonic-gate else 4165*7c478bd9Sstevel@tonic-gate j = NBLOCK; 4166*7c478bd9Sstevel@tonic-gate } else 4167*7c478bd9Sstevel@tonic-gate j = nblock; 4168*7c478bd9Sstevel@tonic-gate 4169*7c478bd9Sstevel@tonic-gate if ((i = read(mt, tbuf, TBLOCK*j)) < 0) { 4170*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4171*7c478bd9Sstevel@tonic-gate "tar: tape read error\n")); 4172*7c478bd9Sstevel@tonic-gate done(3); 4173*7c478bd9Sstevel@tonic-gate /* 4174*7c478bd9Sstevel@tonic-gate * i == 0 means EOF reached and !rflag means that when 4175*7c478bd9Sstevel@tonic-gate * tar command uses 'r' as a function letter, we are trying 4176*7c478bd9Sstevel@tonic-gate * to update or replace an empty tar file which will fail. 4177*7c478bd9Sstevel@tonic-gate * So this fix is not for 'r' function letter. 4178*7c478bd9Sstevel@tonic-gate */ 4179*7c478bd9Sstevel@tonic-gate } else if (i == 0 && !rflag) { 4180*7c478bd9Sstevel@tonic-gate if (first) { 4181*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4182*7c478bd9Sstevel@tonic-gate "tar: blocksize = %d\n"), i); 4183*7c478bd9Sstevel@tonic-gate done(Errflg); 4184*7c478bd9Sstevel@tonic-gate } 4185*7c478bd9Sstevel@tonic-gate else 4186*7c478bd9Sstevel@tonic-gate mterr("read", 0, 2); 4187*7c478bd9Sstevel@tonic-gate } else if ((!first || Bflag) && i != TBLOCK*j) { 4188*7c478bd9Sstevel@tonic-gate /* 4189*7c478bd9Sstevel@tonic-gate * Short read - try to get the remaining bytes. 4190*7c478bd9Sstevel@tonic-gate */ 4191*7c478bd9Sstevel@tonic-gate 4192*7c478bd9Sstevel@tonic-gate int remaining = (TBLOCK * j) - i; 4193*7c478bd9Sstevel@tonic-gate char *b = (char *)tbuf + i; 4194*7c478bd9Sstevel@tonic-gate int r; 4195*7c478bd9Sstevel@tonic-gate 4196*7c478bd9Sstevel@tonic-gate do { 4197*7c478bd9Sstevel@tonic-gate if ((r = read(mt, b, remaining)) < 0) { 4198*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4199*7c478bd9Sstevel@tonic-gate gettext("tar: tape read error\n")); 4200*7c478bd9Sstevel@tonic-gate done(3); 4201*7c478bd9Sstevel@tonic-gate } 4202*7c478bd9Sstevel@tonic-gate b += r; 4203*7c478bd9Sstevel@tonic-gate remaining -= r; 4204*7c478bd9Sstevel@tonic-gate i += r; 4205*7c478bd9Sstevel@tonic-gate } while (remaining > 0 && r != 0); 4206*7c478bd9Sstevel@tonic-gate } 4207*7c478bd9Sstevel@tonic-gate if (first) { 4208*7c478bd9Sstevel@tonic-gate if ((i % TBLOCK) != 0) { 4209*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4210*7c478bd9Sstevel@tonic-gate "tar: tape blocksize error\n")); 4211*7c478bd9Sstevel@tonic-gate done(3); 4212*7c478bd9Sstevel@tonic-gate } 4213*7c478bd9Sstevel@tonic-gate i /= TBLOCK; 4214*7c478bd9Sstevel@tonic-gate if (vflag && i != nblock && i != 1) { 4215*7c478bd9Sstevel@tonic-gate if (!NotTape) 4216*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4217*7c478bd9Sstevel@tonic-gate "tar: blocksize = %d\n"), i); 4218*7c478bd9Sstevel@tonic-gate } 4219*7c478bd9Sstevel@tonic-gate 4220*7c478bd9Sstevel@tonic-gate /* 4221*7c478bd9Sstevel@tonic-gate * If we are reading a tape, then a short read is 4222*7c478bd9Sstevel@tonic-gate * understood to signify that the amount read is 4223*7c478bd9Sstevel@tonic-gate * the tape's actual blocking factor. We adapt 4224*7c478bd9Sstevel@tonic-gate * nblock accordingly. There is no reason to do 4225*7c478bd9Sstevel@tonic-gate * this when the device is not blocked. 4226*7c478bd9Sstevel@tonic-gate */ 4227*7c478bd9Sstevel@tonic-gate 4228*7c478bd9Sstevel@tonic-gate if (!NotTape) 4229*7c478bd9Sstevel@tonic-gate nblock = i; 4230*7c478bd9Sstevel@tonic-gate } 4231*7c478bd9Sstevel@tonic-gate recno = 0; 4232*7c478bd9Sstevel@tonic-gate } 4233*7c478bd9Sstevel@tonic-gate 4234*7c478bd9Sstevel@tonic-gate first = FALSE; 4235*7c478bd9Sstevel@tonic-gate copy(buffer, &tbuf[recno++]); 4236*7c478bd9Sstevel@tonic-gate } 4237*7c478bd9Sstevel@tonic-gate 4238*7c478bd9Sstevel@tonic-gate 4239*7c478bd9Sstevel@tonic-gate /* 4240*7c478bd9Sstevel@tonic-gate * replacement for writetape. 4241*7c478bd9Sstevel@tonic-gate */ 4242*7c478bd9Sstevel@tonic-gate 4243*7c478bd9Sstevel@tonic-gate static int 4244*7c478bd9Sstevel@tonic-gate writetbuf(char *buffer, int n) 4245*7c478bd9Sstevel@tonic-gate { 4246*7c478bd9Sstevel@tonic-gate int i; 4247*7c478bd9Sstevel@tonic-gate 4248*7c478bd9Sstevel@tonic-gate tapepos += n; /* output block count */ 4249*7c478bd9Sstevel@tonic-gate 4250*7c478bd9Sstevel@tonic-gate if (recno >= nblock) { 4251*7c478bd9Sstevel@tonic-gate i = write(mt, (char *)tbuf, TBLOCK*nblock); 4252*7c478bd9Sstevel@tonic-gate if (i != TBLOCK*nblock) 4253*7c478bd9Sstevel@tonic-gate mterr("write", i, 2); 4254*7c478bd9Sstevel@tonic-gate recno = 0; 4255*7c478bd9Sstevel@tonic-gate } 4256*7c478bd9Sstevel@tonic-gate 4257*7c478bd9Sstevel@tonic-gate /* 4258*7c478bd9Sstevel@tonic-gate * Special case: We have an empty tape buffer, and the 4259*7c478bd9Sstevel@tonic-gate * users data size is >= the tape block size: Avoid 4260*7c478bd9Sstevel@tonic-gate * the bcopy and dma direct to tape. BIG WIN. Add the 4261*7c478bd9Sstevel@tonic-gate * residual to the tape buffer. 4262*7c478bd9Sstevel@tonic-gate */ 4263*7c478bd9Sstevel@tonic-gate while (recno == 0 && n >= nblock) { 4264*7c478bd9Sstevel@tonic-gate i = (int)write(mt, buffer, TBLOCK*nblock); 4265*7c478bd9Sstevel@tonic-gate if (i != TBLOCK*nblock) 4266*7c478bd9Sstevel@tonic-gate mterr("write", i, 2); 4267*7c478bd9Sstevel@tonic-gate n -= nblock; 4268*7c478bd9Sstevel@tonic-gate buffer += (nblock * TBLOCK); 4269*7c478bd9Sstevel@tonic-gate } 4270*7c478bd9Sstevel@tonic-gate 4271*7c478bd9Sstevel@tonic-gate while (n-- > 0) { 4272*7c478bd9Sstevel@tonic-gate (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK); 4273*7c478bd9Sstevel@tonic-gate buffer += TBLOCK; 4274*7c478bd9Sstevel@tonic-gate if (recno >= nblock) { 4275*7c478bd9Sstevel@tonic-gate i = (int)write(mt, (char *)tbuf, TBLOCK*nblock); 4276*7c478bd9Sstevel@tonic-gate if (i != TBLOCK*nblock) 4277*7c478bd9Sstevel@tonic-gate mterr("write", i, 2); 4278*7c478bd9Sstevel@tonic-gate recno = 0; 4279*7c478bd9Sstevel@tonic-gate } 4280*7c478bd9Sstevel@tonic-gate } 4281*7c478bd9Sstevel@tonic-gate 4282*7c478bd9Sstevel@tonic-gate /* Tell the user how much to write to get in sync */ 4283*7c478bd9Sstevel@tonic-gate return (nblock - recno); 4284*7c478bd9Sstevel@tonic-gate } 4285*7c478bd9Sstevel@tonic-gate 4286*7c478bd9Sstevel@tonic-gate /* 4287*7c478bd9Sstevel@tonic-gate * backtape - reposition tape after reading soft "EOF" record 4288*7c478bd9Sstevel@tonic-gate * 4289*7c478bd9Sstevel@tonic-gate * Backtape tries to reposition the tape back over the EOF 4290*7c478bd9Sstevel@tonic-gate * record. This is for the 'u' and 'r' function letters so that the 4291*7c478bd9Sstevel@tonic-gate * tape can be extended. This code is not well designed, but 4292*7c478bd9Sstevel@tonic-gate * I'm confident that the only callers who care about the 4293*7c478bd9Sstevel@tonic-gate * backspace-over-EOF feature are those involved in 'u' and 'r'. 4294*7c478bd9Sstevel@tonic-gate * 4295*7c478bd9Sstevel@tonic-gate * The proper way to backup the tape is through the use of mtio. 4296*7c478bd9Sstevel@tonic-gate * Earlier spins used lseek combined with reads in a confusing 4297*7c478bd9Sstevel@tonic-gate * maneuver that only worked on 4.x, but shouldn't have, even 4298*7c478bd9Sstevel@tonic-gate * there. Lseeks are explicitly not supported for tape devices. 4299*7c478bd9Sstevel@tonic-gate */ 4300*7c478bd9Sstevel@tonic-gate 4301*7c478bd9Sstevel@tonic-gate static void 4302*7c478bd9Sstevel@tonic-gate backtape(void) 4303*7c478bd9Sstevel@tonic-gate { 4304*7c478bd9Sstevel@tonic-gate struct mtop mtcmd; 4305*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4306*7c478bd9Sstevel@tonic-gate DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno, 4307*7c478bd9Sstevel@tonic-gate nblock); 4308*7c478bd9Sstevel@tonic-gate #endif 4309*7c478bd9Sstevel@tonic-gate /* 4310*7c478bd9Sstevel@tonic-gate * Backup to the position in the archive where the record 4311*7c478bd9Sstevel@tonic-gate * currently sitting in the tbuf buffer is situated. 4312*7c478bd9Sstevel@tonic-gate */ 4313*7c478bd9Sstevel@tonic-gate 4314*7c478bd9Sstevel@tonic-gate if (NotTape) { 4315*7c478bd9Sstevel@tonic-gate /* 4316*7c478bd9Sstevel@tonic-gate * For non-tape devices, this means lseeking to the 4317*7c478bd9Sstevel@tonic-gate * correct position. The absolute location tapepos-recno 4318*7c478bd9Sstevel@tonic-gate * should be the beginning of the current record. 4319*7c478bd9Sstevel@tonic-gate */ 4320*7c478bd9Sstevel@tonic-gate 4321*7c478bd9Sstevel@tonic-gate if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) == 4322*7c478bd9Sstevel@tonic-gate (off_t)-1) { 4323*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4324*7c478bd9Sstevel@tonic-gate gettext("tar: lseek to end of archive failed\n")); 4325*7c478bd9Sstevel@tonic-gate done(4); 4326*7c478bd9Sstevel@tonic-gate } 4327*7c478bd9Sstevel@tonic-gate } else { 4328*7c478bd9Sstevel@tonic-gate /* 4329*7c478bd9Sstevel@tonic-gate * For tape devices, we backup over the most recently 4330*7c478bd9Sstevel@tonic-gate * read record. 4331*7c478bd9Sstevel@tonic-gate */ 4332*7c478bd9Sstevel@tonic-gate 4333*7c478bd9Sstevel@tonic-gate mtcmd.mt_op = MTBSR; 4334*7c478bd9Sstevel@tonic-gate mtcmd.mt_count = 1; 4335*7c478bd9Sstevel@tonic-gate 4336*7c478bd9Sstevel@tonic-gate if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) { 4337*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4338*7c478bd9Sstevel@tonic-gate gettext("tar: backspace over record failed\n")); 4339*7c478bd9Sstevel@tonic-gate done(4); 4340*7c478bd9Sstevel@tonic-gate } 4341*7c478bd9Sstevel@tonic-gate } 4342*7c478bd9Sstevel@tonic-gate 4343*7c478bd9Sstevel@tonic-gate /* 4344*7c478bd9Sstevel@tonic-gate * Decrement the tape and tbuf buffer indices to prepare for the 4345*7c478bd9Sstevel@tonic-gate * coming write to overwrite the soft EOF record. 4346*7c478bd9Sstevel@tonic-gate */ 4347*7c478bd9Sstevel@tonic-gate 4348*7c478bd9Sstevel@tonic-gate recno--; 4349*7c478bd9Sstevel@tonic-gate tapepos--; 4350*7c478bd9Sstevel@tonic-gate } 4351*7c478bd9Sstevel@tonic-gate 4352*7c478bd9Sstevel@tonic-gate 4353*7c478bd9Sstevel@tonic-gate /* 4354*7c478bd9Sstevel@tonic-gate * flushtape write buffered block(s) onto tape 4355*7c478bd9Sstevel@tonic-gate * 4356*7c478bd9Sstevel@tonic-gate * recno points to next free block in tbuf. If nonzero, a write is done. 4357*7c478bd9Sstevel@tonic-gate * Care is taken to write in multiples of SYS_BLOCK when device is 4358*7c478bd9Sstevel@tonic-gate * non-magtape in case raw i/o is used. 4359*7c478bd9Sstevel@tonic-gate * 4360*7c478bd9Sstevel@tonic-gate * NOTE: this is called by writetape() to do the actual writing 4361*7c478bd9Sstevel@tonic-gate */ 4362*7c478bd9Sstevel@tonic-gate 4363*7c478bd9Sstevel@tonic-gate static void 4364*7c478bd9Sstevel@tonic-gate flushtape(void) 4365*7c478bd9Sstevel@tonic-gate { 4366*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4367*7c478bd9Sstevel@tonic-gate DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0); 4368*7c478bd9Sstevel@tonic-gate #endif 4369*7c478bd9Sstevel@tonic-gate if (recno > 0) { /* anything buffered? */ 4370*7c478bd9Sstevel@tonic-gate if (NotTape) { 4371*7c478bd9Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 4372*7c478bd9Sstevel@tonic-gate int i; 4373*7c478bd9Sstevel@tonic-gate 4374*7c478bd9Sstevel@tonic-gate /* 4375*7c478bd9Sstevel@tonic-gate * an odd-block write can only happen when 4376*7c478bd9Sstevel@tonic-gate * we are at the end of a volume that is not a tape. 4377*7c478bd9Sstevel@tonic-gate * Here we round recno up to an even SYS_BLOCK 4378*7c478bd9Sstevel@tonic-gate * boundary. 4379*7c478bd9Sstevel@tonic-gate */ 4380*7c478bd9Sstevel@tonic-gate if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) { 4381*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4382*7c478bd9Sstevel@tonic-gate DEBUG("flushtape() %d rounding blocks\n", i, 0); 4383*7c478bd9Sstevel@tonic-gate #endif 4384*7c478bd9Sstevel@tonic-gate recno += i; /* round up to even SYS_BLOCK */ 4385*7c478bd9Sstevel@tonic-gate } 4386*7c478bd9Sstevel@tonic-gate #endif 4387*7c478bd9Sstevel@tonic-gate if (recno > nblock) 4388*7c478bd9Sstevel@tonic-gate recno = nblock; 4389*7c478bd9Sstevel@tonic-gate } 4390*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4391*7c478bd9Sstevel@tonic-gate DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t 4392*7c478bd9Sstevel@tonic-gate " bytes\n", (blkcnt_t)(NotTape ? recno : nblock), 4393*7c478bd9Sstevel@tonic-gate (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK); 4394*7c478bd9Sstevel@tonic-gate #endif 4395*7c478bd9Sstevel@tonic-gate if (write(mt, tbuf, 4396*7c478bd9Sstevel@tonic-gate (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) { 4397*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4398*7c478bd9Sstevel@tonic-gate "tar: tape write error\n")); 4399*7c478bd9Sstevel@tonic-gate done(2); 4400*7c478bd9Sstevel@tonic-gate } 4401*7c478bd9Sstevel@tonic-gate recno = 0; 4402*7c478bd9Sstevel@tonic-gate } 4403*7c478bd9Sstevel@tonic-gate } 4404*7c478bd9Sstevel@tonic-gate 4405*7c478bd9Sstevel@tonic-gate static void 4406*7c478bd9Sstevel@tonic-gate copy(void *dst, void *src) 4407*7c478bd9Sstevel@tonic-gate { 4408*7c478bd9Sstevel@tonic-gate (void) memcpy(dst, src, TBLOCK); 4409*7c478bd9Sstevel@tonic-gate } 4410*7c478bd9Sstevel@tonic-gate 4411*7c478bd9Sstevel@tonic-gate #ifdef _iBCS2 4412*7c478bd9Sstevel@tonic-gate /* 4413*7c478bd9Sstevel@tonic-gate * initarg -- initialize things for nextarg. 4414*7c478bd9Sstevel@tonic-gate * 4415*7c478bd9Sstevel@tonic-gate * argv filename list, a la argv. 4416*7c478bd9Sstevel@tonic-gate * filefile name of file containing filenames. Unless doing 4417*7c478bd9Sstevel@tonic-gate * a create, seeks must be allowable (e.g. no named pipes). 4418*7c478bd9Sstevel@tonic-gate * 4419*7c478bd9Sstevel@tonic-gate * - if filefile is non-NULL, it will be used first, and argv will 4420*7c478bd9Sstevel@tonic-gate * be used when the data in filefile are exhausted. 4421*7c478bd9Sstevel@tonic-gate * - otherwise argv will be used. 4422*7c478bd9Sstevel@tonic-gate */ 4423*7c478bd9Sstevel@tonic-gate static char **Cmdargv = NULL; 4424*7c478bd9Sstevel@tonic-gate static FILE *FILEFile = NULL; 4425*7c478bd9Sstevel@tonic-gate static long seekFile = -1; 4426*7c478bd9Sstevel@tonic-gate static char *ptrtoFile, *begofFile, *endofFile; 4427*7c478bd9Sstevel@tonic-gate 4428*7c478bd9Sstevel@tonic-gate static void 4429*7c478bd9Sstevel@tonic-gate initarg(char *argv[], char *filefile) 4430*7c478bd9Sstevel@tonic-gate { 4431*7c478bd9Sstevel@tonic-gate struct stat statbuf; 4432*7c478bd9Sstevel@tonic-gate char *p; 4433*7c478bd9Sstevel@tonic-gate int nbytes; 4434*7c478bd9Sstevel@tonic-gate 4435*7c478bd9Sstevel@tonic-gate Cmdargv = argv; 4436*7c478bd9Sstevel@tonic-gate if (filefile == NULL) 4437*7c478bd9Sstevel@tonic-gate return; /* no -F file */ 4438*7c478bd9Sstevel@tonic-gate if (FILEFile != NULL) { 4439*7c478bd9Sstevel@tonic-gate /* 4440*7c478bd9Sstevel@tonic-gate * need to REinitialize 4441*7c478bd9Sstevel@tonic-gate */ 4442*7c478bd9Sstevel@tonic-gate if (seekFile != -1) 4443*7c478bd9Sstevel@tonic-gate (void) fseek(FILEFile, seekFile, 0); 4444*7c478bd9Sstevel@tonic-gate ptrtoFile = begofFile; 4445*7c478bd9Sstevel@tonic-gate return; 4446*7c478bd9Sstevel@tonic-gate } 4447*7c478bd9Sstevel@tonic-gate /* 4448*7c478bd9Sstevel@tonic-gate * first time initialization 4449*7c478bd9Sstevel@tonic-gate */ 4450*7c478bd9Sstevel@tonic-gate if ((FILEFile = fopen(filefile, "r")) == NULL) 4451*7c478bd9Sstevel@tonic-gate fatal(gettext("cannot open (%s)"), filefile); 4452*7c478bd9Sstevel@tonic-gate (void) fstat(fileno(FILEFile), &statbuf); 4453*7c478bd9Sstevel@tonic-gate if ((statbuf.st_mode & S_IFMT) != S_IFREG) { 4454*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4455*7c478bd9Sstevel@tonic-gate "tar: %s is not a regular file\n"), filefile); 4456*7c478bd9Sstevel@tonic-gate (void) fclose(FILEFile); 4457*7c478bd9Sstevel@tonic-gate done(1); 4458*7c478bd9Sstevel@tonic-gate } 4459*7c478bd9Sstevel@tonic-gate ptrtoFile = begofFile = endofFile; 4460*7c478bd9Sstevel@tonic-gate seekFile = 0; 4461*7c478bd9Sstevel@tonic-gate if (!xflag) 4462*7c478bd9Sstevel@tonic-gate return; /* the file will be read only once anyway */ 4463*7c478bd9Sstevel@tonic-gate nbytes = statbuf.st_size; 4464*7c478bd9Sstevel@tonic-gate while ((begofFile = calloc(nbytes, sizeof (char))) == NULL) 4465*7c478bd9Sstevel@tonic-gate nbytes -= 20; 4466*7c478bd9Sstevel@tonic-gate if (nbytes < 50) { 4467*7c478bd9Sstevel@tonic-gate free(begofFile); 4468*7c478bd9Sstevel@tonic-gate begofFile = endofFile; 4469*7c478bd9Sstevel@tonic-gate return; /* no room so just do plain reads */ 4470*7c478bd9Sstevel@tonic-gate } 4471*7c478bd9Sstevel@tonic-gate if (fread(begofFile, 1, nbytes, FILEFile) != nbytes) 4472*7c478bd9Sstevel@tonic-gate fatal(gettext("could not read %s"), filefile); 4473*7c478bd9Sstevel@tonic-gate ptrtoFile = begofFile; 4474*7c478bd9Sstevel@tonic-gate endofFile = begofFile + nbytes; 4475*7c478bd9Sstevel@tonic-gate for (p = begofFile; p < endofFile; ++p) 4476*7c478bd9Sstevel@tonic-gate if (*p == '\n') 4477*7c478bd9Sstevel@tonic-gate *p = '\0'; 4478*7c478bd9Sstevel@tonic-gate if (nbytes != statbuf.st_size) 4479*7c478bd9Sstevel@tonic-gate seekFile = nbytes + 1; 4480*7c478bd9Sstevel@tonic-gate else 4481*7c478bd9Sstevel@tonic-gate (void) fclose(FILEFile); 4482*7c478bd9Sstevel@tonic-gate } 4483*7c478bd9Sstevel@tonic-gate 4484*7c478bd9Sstevel@tonic-gate /* 4485*7c478bd9Sstevel@tonic-gate * nextarg -- get next argument of arglist. 4486*7c478bd9Sstevel@tonic-gate * 4487*7c478bd9Sstevel@tonic-gate * The argument is taken from wherever is appropriate. 4488*7c478bd9Sstevel@tonic-gate * 4489*7c478bd9Sstevel@tonic-gate * If the 'F file' function modifier has been specified, the argument 4490*7c478bd9Sstevel@tonic-gate * will be taken from the file, unless EOF has been reached. 4491*7c478bd9Sstevel@tonic-gate * Otherwise the argument will be taken from argv. 4492*7c478bd9Sstevel@tonic-gate * 4493*7c478bd9Sstevel@tonic-gate * WARNING: 4494*7c478bd9Sstevel@tonic-gate * Return value may point to static data, whose contents are over- 4495*7c478bd9Sstevel@tonic-gate * written on each call. 4496*7c478bd9Sstevel@tonic-gate */ 4497*7c478bd9Sstevel@tonic-gate static char * 4498*7c478bd9Sstevel@tonic-gate nextarg(void) 4499*7c478bd9Sstevel@tonic-gate { 4500*7c478bd9Sstevel@tonic-gate static char nameFile[PATH_MAX + 1]; 4501*7c478bd9Sstevel@tonic-gate int n; 4502*7c478bd9Sstevel@tonic-gate char *p; 4503*7c478bd9Sstevel@tonic-gate 4504*7c478bd9Sstevel@tonic-gate if (FILEFile) { 4505*7c478bd9Sstevel@tonic-gate if (ptrtoFile < endofFile) { 4506*7c478bd9Sstevel@tonic-gate p = ptrtoFile; 4507*7c478bd9Sstevel@tonic-gate while (*ptrtoFile) 4508*7c478bd9Sstevel@tonic-gate ++ptrtoFile; 4509*7c478bd9Sstevel@tonic-gate ++ptrtoFile; 4510*7c478bd9Sstevel@tonic-gate return (p); 4511*7c478bd9Sstevel@tonic-gate } 4512*7c478bd9Sstevel@tonic-gate if (fgets(nameFile, PATH_MAX + 1, FILEFile) != NULL) { 4513*7c478bd9Sstevel@tonic-gate n = strlen(nameFile); 4514*7c478bd9Sstevel@tonic-gate if (n > 0 && nameFile[n-1] == '\n') 4515*7c478bd9Sstevel@tonic-gate nameFile[n-1] = '\0'; 4516*7c478bd9Sstevel@tonic-gate return (nameFile); 4517*7c478bd9Sstevel@tonic-gate } 4518*7c478bd9Sstevel@tonic-gate } 4519*7c478bd9Sstevel@tonic-gate return (*Cmdargv++); 4520*7c478bd9Sstevel@tonic-gate } 4521*7c478bd9Sstevel@tonic-gate #endif /* _iBCS2 */ 4522*7c478bd9Sstevel@tonic-gate 4523*7c478bd9Sstevel@tonic-gate /* 4524*7c478bd9Sstevel@tonic-gate * kcheck() 4525*7c478bd9Sstevel@tonic-gate * - checks the validity of size values for non-tape devices 4526*7c478bd9Sstevel@tonic-gate * - if size is zero, mulvol tar is disabled and size is 4527*7c478bd9Sstevel@tonic-gate * assumed to be infinite. 4528*7c478bd9Sstevel@tonic-gate * - returns volume size in TBLOCKS 4529*7c478bd9Sstevel@tonic-gate */ 4530*7c478bd9Sstevel@tonic-gate 4531*7c478bd9Sstevel@tonic-gate static blkcnt_t 4532*7c478bd9Sstevel@tonic-gate kcheck(char *kstr) 4533*7c478bd9Sstevel@tonic-gate { 4534*7c478bd9Sstevel@tonic-gate blkcnt_t kval; 4535*7c478bd9Sstevel@tonic-gate 4536*7c478bd9Sstevel@tonic-gate kval = strtoll(kstr, NULL, 0); 4537*7c478bd9Sstevel@tonic-gate if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */ 4538*7c478bd9Sstevel@tonic-gate mulvol = 0; /* definitely not mulvol, but we must */ 4539*7c478bd9Sstevel@tonic-gate return (0); /* took out setting of NotTape */ 4540*7c478bd9Sstevel@tonic-gate } 4541*7c478bd9Sstevel@tonic-gate if (kval < (blkcnt_t)MINSIZE) { 4542*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4543*7c478bd9Sstevel@tonic-gate "tar: sizes below %luK not supported (%" FMT_blkcnt_t 4544*7c478bd9Sstevel@tonic-gate ").\n"), (ulong_t)MINSIZE, kval); 4545*7c478bd9Sstevel@tonic-gate if (!kflag) 4546*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4547*7c478bd9Sstevel@tonic-gate "bad size entry for %s in %s.\n"), 4548*7c478bd9Sstevel@tonic-gate archive, DEF_FILE); 4549*7c478bd9Sstevel@tonic-gate done(1); 4550*7c478bd9Sstevel@tonic-gate } 4551*7c478bd9Sstevel@tonic-gate mulvol++; 4552*7c478bd9Sstevel@tonic-gate NotTape++; /* implies non-tape */ 4553*7c478bd9Sstevel@tonic-gate return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */ 4554*7c478bd9Sstevel@tonic-gate } 4555*7c478bd9Sstevel@tonic-gate 4556*7c478bd9Sstevel@tonic-gate 4557*7c478bd9Sstevel@tonic-gate /* 4558*7c478bd9Sstevel@tonic-gate * bcheck() 4559*7c478bd9Sstevel@tonic-gate * - checks the validity of blocking factors 4560*7c478bd9Sstevel@tonic-gate * - returns blocking factor 4561*7c478bd9Sstevel@tonic-gate */ 4562*7c478bd9Sstevel@tonic-gate 4563*7c478bd9Sstevel@tonic-gate static int 4564*7c478bd9Sstevel@tonic-gate bcheck(char *bstr) 4565*7c478bd9Sstevel@tonic-gate { 4566*7c478bd9Sstevel@tonic-gate blkcnt_t bval; 4567*7c478bd9Sstevel@tonic-gate 4568*7c478bd9Sstevel@tonic-gate bval = strtoll(bstr, NULL, 0); 4569*7c478bd9Sstevel@tonic-gate if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) { 4570*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4571*7c478bd9Sstevel@tonic-gate "tar: invalid blocksize \"%s\".\n"), bstr); 4572*7c478bd9Sstevel@tonic-gate if (!bflag) 4573*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4574*7c478bd9Sstevel@tonic-gate "bad blocksize entry for '%s' in %s.\n"), 4575*7c478bd9Sstevel@tonic-gate archive, DEF_FILE); 4576*7c478bd9Sstevel@tonic-gate done(1); 4577*7c478bd9Sstevel@tonic-gate } 4578*7c478bd9Sstevel@tonic-gate 4579*7c478bd9Sstevel@tonic-gate return ((int)bval); 4580*7c478bd9Sstevel@tonic-gate } 4581*7c478bd9Sstevel@tonic-gate 4582*7c478bd9Sstevel@tonic-gate 4583*7c478bd9Sstevel@tonic-gate /* 4584*7c478bd9Sstevel@tonic-gate * defset() 4585*7c478bd9Sstevel@tonic-gate * - reads DEF_FILE for the set of default values specified. 4586*7c478bd9Sstevel@tonic-gate * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'. 4587*7c478bd9Sstevel@tonic-gate * - 'usefile' points to static data, so will be overwritten 4588*7c478bd9Sstevel@tonic-gate * if this routine is called a second time. 4589*7c478bd9Sstevel@tonic-gate * - the pattern specified by 'arch' must be followed by four 4590*7c478bd9Sstevel@tonic-gate * blank-separated fields (1) device (2) blocking, 4591*7c478bd9Sstevel@tonic-gate * (3) size(K), and (4) tape 4592*7c478bd9Sstevel@tonic-gate * for example: archive0=/dev/fd 1 400 n 4593*7c478bd9Sstevel@tonic-gate */ 4594*7c478bd9Sstevel@tonic-gate 4595*7c478bd9Sstevel@tonic-gate static int 4596*7c478bd9Sstevel@tonic-gate defset(char *arch) 4597*7c478bd9Sstevel@tonic-gate { 4598*7c478bd9Sstevel@tonic-gate char *bp; 4599*7c478bd9Sstevel@tonic-gate 4600*7c478bd9Sstevel@tonic-gate if (defopen(DEF_FILE) != 0) 4601*7c478bd9Sstevel@tonic-gate return (FALSE); 4602*7c478bd9Sstevel@tonic-gate if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) { 4603*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4604*7c478bd9Sstevel@tonic-gate "tar: error setting parameters for %s.\n"), DEF_FILE); 4605*7c478bd9Sstevel@tonic-gate return (FALSE); /* & following ones too */ 4606*7c478bd9Sstevel@tonic-gate } 4607*7c478bd9Sstevel@tonic-gate if ((bp = defread(arch)) == NULL) { 4608*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4609*7c478bd9Sstevel@tonic-gate "tar: missing or invalid '%s' entry in %s.\n"), 4610*7c478bd9Sstevel@tonic-gate arch, DEF_FILE); 4611*7c478bd9Sstevel@tonic-gate return (FALSE); 4612*7c478bd9Sstevel@tonic-gate } 4613*7c478bd9Sstevel@tonic-gate if ((usefile = strtok(bp, " \t")) == NULL) { 4614*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4615*7c478bd9Sstevel@tonic-gate "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE); 4616*7c478bd9Sstevel@tonic-gate return (FALSE); 4617*7c478bd9Sstevel@tonic-gate } 4618*7c478bd9Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) == NULL) { 4619*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4620*7c478bd9Sstevel@tonic-gate "tar: block component missing in '%s' entry in %s.\n"), 4621*7c478bd9Sstevel@tonic-gate arch, DEF_FILE); 4622*7c478bd9Sstevel@tonic-gate return (FALSE); 4623*7c478bd9Sstevel@tonic-gate } 4624*7c478bd9Sstevel@tonic-gate nblock = bcheck(bp); 4625*7c478bd9Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) == NULL) { 4626*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4627*7c478bd9Sstevel@tonic-gate "tar: size component missing in '%s' entry in %s.\n"), 4628*7c478bd9Sstevel@tonic-gate arch, DEF_FILE); 4629*7c478bd9Sstevel@tonic-gate return (FALSE); 4630*7c478bd9Sstevel@tonic-gate } 4631*7c478bd9Sstevel@tonic-gate blocklim = kcheck(bp); 4632*7c478bd9Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) != NULL) 4633*7c478bd9Sstevel@tonic-gate NotTape = (*bp == 'n' || *bp == 'N'); 4634*7c478bd9Sstevel@tonic-gate else 4635*7c478bd9Sstevel@tonic-gate NotTape = (blocklim != 0); 4636*7c478bd9Sstevel@tonic-gate (void) defopen(NULL); 4637*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4638*7c478bd9Sstevel@tonic-gate DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile); 4639*7c478bd9Sstevel@tonic-gate DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n", 4640*7c478bd9Sstevel@tonic-gate nblock, blocklim); 4641*7c478bd9Sstevel@tonic-gate DEBUG("defset: not tape = %d\n", NotTape, 0); 4642*7c478bd9Sstevel@tonic-gate #endif 4643*7c478bd9Sstevel@tonic-gate return (TRUE); 4644*7c478bd9Sstevel@tonic-gate } 4645*7c478bd9Sstevel@tonic-gate 4646*7c478bd9Sstevel@tonic-gate 4647*7c478bd9Sstevel@tonic-gate /* 4648*7c478bd9Sstevel@tonic-gate * Following code handles excluded and included files. 4649*7c478bd9Sstevel@tonic-gate * A hash table of file names to be {in,ex}cluded is built. 4650*7c478bd9Sstevel@tonic-gate * For excluded files, before writing or extracting a file 4651*7c478bd9Sstevel@tonic-gate * check to see if it is in the exclude_tbl. 4652*7c478bd9Sstevel@tonic-gate * For included files, the wantit() procedure will check to 4653*7c478bd9Sstevel@tonic-gate * see if the named file is in the include_tbl. 4654*7c478bd9Sstevel@tonic-gate */ 4655*7c478bd9Sstevel@tonic-gate 4656*7c478bd9Sstevel@tonic-gate static void 4657*7c478bd9Sstevel@tonic-gate build_table(struct file_list *table[], char *file) 4658*7c478bd9Sstevel@tonic-gate { 4659*7c478bd9Sstevel@tonic-gate FILE *fp; 4660*7c478bd9Sstevel@tonic-gate char buf[PATH_MAX + 1]; 4661*7c478bd9Sstevel@tonic-gate 4662*7c478bd9Sstevel@tonic-gate if ((fp = fopen(file, "r")) == (FILE *)NULL) 4663*7c478bd9Sstevel@tonic-gate vperror(1, gettext("could not open %s"), file); 4664*7c478bd9Sstevel@tonic-gate while (fgets(buf, sizeof (buf), fp) != NULL) { 4665*7c478bd9Sstevel@tonic-gate if (buf[strlen(buf) - 1] == '\n') 4666*7c478bd9Sstevel@tonic-gate buf[strlen(buf) - 1] = '\0'; 4667*7c478bd9Sstevel@tonic-gate /* Only add to table if line has something in it */ 4668*7c478bd9Sstevel@tonic-gate if (strspn(buf, " \t") != strlen(buf)) 4669*7c478bd9Sstevel@tonic-gate add_file_to_table(table, buf); 4670*7c478bd9Sstevel@tonic-gate } 4671*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 4672*7c478bd9Sstevel@tonic-gate } 4673*7c478bd9Sstevel@tonic-gate 4674*7c478bd9Sstevel@tonic-gate 4675*7c478bd9Sstevel@tonic-gate /* 4676*7c478bd9Sstevel@tonic-gate * Add a file name to the the specified table, if the file name has any 4677*7c478bd9Sstevel@tonic-gate * trailing '/'s then delete them before inserting into the table 4678*7c478bd9Sstevel@tonic-gate */ 4679*7c478bd9Sstevel@tonic-gate 4680*7c478bd9Sstevel@tonic-gate static void 4681*7c478bd9Sstevel@tonic-gate add_file_to_table(struct file_list *table[], char *str) 4682*7c478bd9Sstevel@tonic-gate { 4683*7c478bd9Sstevel@tonic-gate char name[PATH_MAX + 1]; 4684*7c478bd9Sstevel@tonic-gate unsigned int h; 4685*7c478bd9Sstevel@tonic-gate struct file_list *exp; 4686*7c478bd9Sstevel@tonic-gate 4687*7c478bd9Sstevel@tonic-gate (void) strcpy(name, str); 4688*7c478bd9Sstevel@tonic-gate while (name[strlen(name) - 1] == '/') { 4689*7c478bd9Sstevel@tonic-gate name[strlen(name) - 1] = NULL; 4690*7c478bd9Sstevel@tonic-gate } 4691*7c478bd9Sstevel@tonic-gate 4692*7c478bd9Sstevel@tonic-gate h = hash(name); 4693*7c478bd9Sstevel@tonic-gate if ((exp = (struct file_list *)calloc(sizeof (struct file_list), 4694*7c478bd9Sstevel@tonic-gate sizeof (char))) == NULL) { 4695*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4696*7c478bd9Sstevel@tonic-gate "tar: out of memory, exclude/include table(entry)\n")); 4697*7c478bd9Sstevel@tonic-gate exit(1); 4698*7c478bd9Sstevel@tonic-gate } 4699*7c478bd9Sstevel@tonic-gate 4700*7c478bd9Sstevel@tonic-gate if ((exp->name = strdup(name)) == NULL) { 4701*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4702*7c478bd9Sstevel@tonic-gate "tar: out of memory, exclude/include table(file name)\n")); 4703*7c478bd9Sstevel@tonic-gate exit(1); 4704*7c478bd9Sstevel@tonic-gate } 4705*7c478bd9Sstevel@tonic-gate 4706*7c478bd9Sstevel@tonic-gate exp->next = table[h]; 4707*7c478bd9Sstevel@tonic-gate table[h] = exp; 4708*7c478bd9Sstevel@tonic-gate } 4709*7c478bd9Sstevel@tonic-gate 4710*7c478bd9Sstevel@tonic-gate 4711*7c478bd9Sstevel@tonic-gate /* 4712*7c478bd9Sstevel@tonic-gate * See if a file name or any of the file's parent directories is in the 4713*7c478bd9Sstevel@tonic-gate * specified table, if the file name has any trailing '/'s then delete 4714*7c478bd9Sstevel@tonic-gate * them before searching the table 4715*7c478bd9Sstevel@tonic-gate */ 4716*7c478bd9Sstevel@tonic-gate 4717*7c478bd9Sstevel@tonic-gate static int 4718*7c478bd9Sstevel@tonic-gate is_in_table(struct file_list *table[], char *str) 4719*7c478bd9Sstevel@tonic-gate { 4720*7c478bd9Sstevel@tonic-gate char name[PATH_MAX + 1]; 4721*7c478bd9Sstevel@tonic-gate unsigned int h; 4722*7c478bd9Sstevel@tonic-gate struct file_list *exp; 4723*7c478bd9Sstevel@tonic-gate char *ptr; 4724*7c478bd9Sstevel@tonic-gate 4725*7c478bd9Sstevel@tonic-gate (void) strcpy(name, str); 4726*7c478bd9Sstevel@tonic-gate while (name[strlen(name) - 1] == '/') { 4727*7c478bd9Sstevel@tonic-gate name[strlen(name) - 1] = NULL; 4728*7c478bd9Sstevel@tonic-gate } 4729*7c478bd9Sstevel@tonic-gate 4730*7c478bd9Sstevel@tonic-gate /* 4731*7c478bd9Sstevel@tonic-gate * check for the file name in the passed list 4732*7c478bd9Sstevel@tonic-gate */ 4733*7c478bd9Sstevel@tonic-gate h = hash(name); 4734*7c478bd9Sstevel@tonic-gate exp = table[h]; 4735*7c478bd9Sstevel@tonic-gate while (exp != NULL) { 4736*7c478bd9Sstevel@tonic-gate if (strcmp(name, exp->name) == 0) { 4737*7c478bd9Sstevel@tonic-gate return (1); 4738*7c478bd9Sstevel@tonic-gate } 4739*7c478bd9Sstevel@tonic-gate exp = exp->next; 4740*7c478bd9Sstevel@tonic-gate } 4741*7c478bd9Sstevel@tonic-gate 4742*7c478bd9Sstevel@tonic-gate /* 4743*7c478bd9Sstevel@tonic-gate * check for any parent directories in the file list 4744*7c478bd9Sstevel@tonic-gate */ 4745*7c478bd9Sstevel@tonic-gate while ((ptr = strrchr(name, '/'))) { 4746*7c478bd9Sstevel@tonic-gate *ptr = NULL; 4747*7c478bd9Sstevel@tonic-gate h = hash(name); 4748*7c478bd9Sstevel@tonic-gate exp = table[h]; 4749*7c478bd9Sstevel@tonic-gate while (exp != NULL) { 4750*7c478bd9Sstevel@tonic-gate if (strcmp(name, exp->name) == 0) { 4751*7c478bd9Sstevel@tonic-gate return (1); 4752*7c478bd9Sstevel@tonic-gate } 4753*7c478bd9Sstevel@tonic-gate exp = exp->next; 4754*7c478bd9Sstevel@tonic-gate } 4755*7c478bd9Sstevel@tonic-gate } 4756*7c478bd9Sstevel@tonic-gate 4757*7c478bd9Sstevel@tonic-gate return (0); 4758*7c478bd9Sstevel@tonic-gate } 4759*7c478bd9Sstevel@tonic-gate 4760*7c478bd9Sstevel@tonic-gate 4761*7c478bd9Sstevel@tonic-gate /* 4762*7c478bd9Sstevel@tonic-gate * Compute a hash from a string. 4763*7c478bd9Sstevel@tonic-gate */ 4764*7c478bd9Sstevel@tonic-gate 4765*7c478bd9Sstevel@tonic-gate static unsigned int 4766*7c478bd9Sstevel@tonic-gate hash(char *str) 4767*7c478bd9Sstevel@tonic-gate { 4768*7c478bd9Sstevel@tonic-gate char *cp; 4769*7c478bd9Sstevel@tonic-gate unsigned int h; 4770*7c478bd9Sstevel@tonic-gate 4771*7c478bd9Sstevel@tonic-gate h = 0; 4772*7c478bd9Sstevel@tonic-gate for (cp = str; *cp; cp++) { 4773*7c478bd9Sstevel@tonic-gate h += *cp; 4774*7c478bd9Sstevel@tonic-gate } 4775*7c478bd9Sstevel@tonic-gate return (h % TABLE_SIZE); 4776*7c478bd9Sstevel@tonic-gate } 4777*7c478bd9Sstevel@tonic-gate 4778*7c478bd9Sstevel@tonic-gate static void * 4779*7c478bd9Sstevel@tonic-gate getmem(size_t size) 4780*7c478bd9Sstevel@tonic-gate { 4781*7c478bd9Sstevel@tonic-gate void *p = calloc((unsigned)size, sizeof (char)); 4782*7c478bd9Sstevel@tonic-gate 4783*7c478bd9Sstevel@tonic-gate if (p == NULL && freemem) { 4784*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4785*7c478bd9Sstevel@tonic-gate "tar: out of memory, link and directory modtime " 4786*7c478bd9Sstevel@tonic-gate "info lost\n")); 4787*7c478bd9Sstevel@tonic-gate freemem = 0; 4788*7c478bd9Sstevel@tonic-gate if (errflag) 4789*7c478bd9Sstevel@tonic-gate done(1); 4790*7c478bd9Sstevel@tonic-gate else 4791*7c478bd9Sstevel@tonic-gate Errflg = 1; 4792*7c478bd9Sstevel@tonic-gate } 4793*7c478bd9Sstevel@tonic-gate return (p); 4794*7c478bd9Sstevel@tonic-gate } 4795*7c478bd9Sstevel@tonic-gate 4796*7c478bd9Sstevel@tonic-gate /* 4797*7c478bd9Sstevel@tonic-gate * vperror() --variable argument perror. 4798*7c478bd9Sstevel@tonic-gate * Takes 3 args: exit_status, formats, args. If exit_status is 0, then 4799*7c478bd9Sstevel@tonic-gate * the errflag (exit on error) is checked -- if it is non-zero, tar exits 4800*7c478bd9Sstevel@tonic-gate * with the value of whatever "errno" is set to. If exit_status is not 4801*7c478bd9Sstevel@tonic-gate * zero, then tar exits with that error status. If errflag and exit_status 4802*7c478bd9Sstevel@tonic-gate * are both zero, the routine returns to where it was called and sets Errflg 4803*7c478bd9Sstevel@tonic-gate * to errno. 4804*7c478bd9Sstevel@tonic-gate */ 4805*7c478bd9Sstevel@tonic-gate 4806*7c478bd9Sstevel@tonic-gate static void 4807*7c478bd9Sstevel@tonic-gate vperror(int exit_status, char *fmt, ...) 4808*7c478bd9Sstevel@tonic-gate { 4809*7c478bd9Sstevel@tonic-gate va_list ap; 4810*7c478bd9Sstevel@tonic-gate 4811*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 4812*7c478bd9Sstevel@tonic-gate (void) fputs("tar: ", stderr); 4813*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 4814*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, ": %s\n", strerror(errno)); 4815*7c478bd9Sstevel@tonic-gate va_end(ap); 4816*7c478bd9Sstevel@tonic-gate if (exit_status) 4817*7c478bd9Sstevel@tonic-gate done(exit_status); 4818*7c478bd9Sstevel@tonic-gate else 4819*7c478bd9Sstevel@tonic-gate if (errflag) 4820*7c478bd9Sstevel@tonic-gate done(errno); 4821*7c478bd9Sstevel@tonic-gate else 4822*7c478bd9Sstevel@tonic-gate Errflg = errno; 4823*7c478bd9Sstevel@tonic-gate } 4824*7c478bd9Sstevel@tonic-gate 4825*7c478bd9Sstevel@tonic-gate 4826*7c478bd9Sstevel@tonic-gate static void 4827*7c478bd9Sstevel@tonic-gate fatal(char *format, ...) 4828*7c478bd9Sstevel@tonic-gate { 4829*7c478bd9Sstevel@tonic-gate va_list ap; 4830*7c478bd9Sstevel@tonic-gate 4831*7c478bd9Sstevel@tonic-gate va_start(ap, format); 4832*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "tar: "); 4833*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 4834*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 4835*7c478bd9Sstevel@tonic-gate va_end(ap); 4836*7c478bd9Sstevel@tonic-gate done(1); 4837*7c478bd9Sstevel@tonic-gate } 4838*7c478bd9Sstevel@tonic-gate 4839*7c478bd9Sstevel@tonic-gate 4840*7c478bd9Sstevel@tonic-gate /* 4841*7c478bd9Sstevel@tonic-gate * Check to make sure that argument is a char * ptr. 4842*7c478bd9Sstevel@tonic-gate * Actually, we just check to see that it is non-null. 4843*7c478bd9Sstevel@tonic-gate * If it is null, print out the message and call usage(), bailing out. 4844*7c478bd9Sstevel@tonic-gate */ 4845*7c478bd9Sstevel@tonic-gate 4846*7c478bd9Sstevel@tonic-gate static void 4847*7c478bd9Sstevel@tonic-gate assert_string(char *s, char *msg) 4848*7c478bd9Sstevel@tonic-gate { 4849*7c478bd9Sstevel@tonic-gate if (s == NULL) { 4850*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, msg); 4851*7c478bd9Sstevel@tonic-gate usage(); 4852*7c478bd9Sstevel@tonic-gate } 4853*7c478bd9Sstevel@tonic-gate } 4854*7c478bd9Sstevel@tonic-gate 4855*7c478bd9Sstevel@tonic-gate 4856*7c478bd9Sstevel@tonic-gate static void 4857*7c478bd9Sstevel@tonic-gate mterr(char *operation, int i, int exitcode) 4858*7c478bd9Sstevel@tonic-gate { 4859*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4860*7c478bd9Sstevel@tonic-gate "tar: %s error: "), operation); 4861*7c478bd9Sstevel@tonic-gate if (i < 0) 4862*7c478bd9Sstevel@tonic-gate perror(""); 4863*7c478bd9Sstevel@tonic-gate else 4864*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("unexpected EOF\n")); 4865*7c478bd9Sstevel@tonic-gate done(exitcode); 4866*7c478bd9Sstevel@tonic-gate } 4867*7c478bd9Sstevel@tonic-gate 4868*7c478bd9Sstevel@tonic-gate static int 4869*7c478bd9Sstevel@tonic-gate wantit(char *argv[], char **namep, char **dirp, char **component) 4870*7c478bd9Sstevel@tonic-gate { 4871*7c478bd9Sstevel@tonic-gate char **cp; 4872*7c478bd9Sstevel@tonic-gate int gotit; /* true if we've found a match */ 4873*7c478bd9Sstevel@tonic-gate 4874*7c478bd9Sstevel@tonic-gate top: 4875*7c478bd9Sstevel@tonic-gate xhdr_flgs = 0; 4876*7c478bd9Sstevel@tonic-gate getdir(); 4877*7c478bd9Sstevel@tonic-gate if (Xhdrflag > 0) { 4878*7c478bd9Sstevel@tonic-gate if (get_xdata() != 0) { /* Xhdr items and regular header */ 4879*7c478bd9Sstevel@tonic-gate passtape(); 4880*7c478bd9Sstevel@tonic-gate return (0); /* Error--don't want to extract */ 4881*7c478bd9Sstevel@tonic-gate } 4882*7c478bd9Sstevel@tonic-gate } 4883*7c478bd9Sstevel@tonic-gate 4884*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 4885*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) { 4886*7c478bd9Sstevel@tonic-gate if (atflag || tflag) { 4887*7c478bd9Sstevel@tonic-gate (void) read_xattr_hdr(); 4888*7c478bd9Sstevel@tonic-gate } else { 4889*7c478bd9Sstevel@tonic-gate passtape(); 4890*7c478bd9Sstevel@tonic-gate } 4891*7c478bd9Sstevel@tonic-gate goto top; 4892*7c478bd9Sstevel@tonic-gate } 4893*7c478bd9Sstevel@tonic-gate #endif 4894*7c478bd9Sstevel@tonic-gate 4895*7c478bd9Sstevel@tonic-gate /* sets *namep to point at the proper name */ 4896*7c478bd9Sstevel@tonic-gate check_prefix(namep, dirp, component); 4897*7c478bd9Sstevel@tonic-gate 4898*7c478bd9Sstevel@tonic-gate if (endtape()) { 4899*7c478bd9Sstevel@tonic-gate if (Bflag) { 4900*7c478bd9Sstevel@tonic-gate /* 4901*7c478bd9Sstevel@tonic-gate * Logically at EOT - consume any extra blocks 4902*7c478bd9Sstevel@tonic-gate * so that write to our stdin won't fail and 4903*7c478bd9Sstevel@tonic-gate * emit an error message; otherwise something 4904*7c478bd9Sstevel@tonic-gate * like "dd if=foo.tar | (cd bar; tar xvf -)" 4905*7c478bd9Sstevel@tonic-gate * will produce a bogus error message from "dd". 4906*7c478bd9Sstevel@tonic-gate */ 4907*7c478bd9Sstevel@tonic-gate 4908*7c478bd9Sstevel@tonic-gate while (read(mt, tbuf, TBLOCK*nblock) > 0) { 4909*7c478bd9Sstevel@tonic-gate /* empty body */ 4910*7c478bd9Sstevel@tonic-gate } 4911*7c478bd9Sstevel@tonic-gate } 4912*7c478bd9Sstevel@tonic-gate return (-1); 4913*7c478bd9Sstevel@tonic-gate } 4914*7c478bd9Sstevel@tonic-gate 4915*7c478bd9Sstevel@tonic-gate gotit = 0; 4916*7c478bd9Sstevel@tonic-gate 4917*7c478bd9Sstevel@tonic-gate if ((Iflag && is_in_table(include_tbl, *namep)) || 4918*7c478bd9Sstevel@tonic-gate (! Iflag && *argv == NULL)) { 4919*7c478bd9Sstevel@tonic-gate gotit = 1; 4920*7c478bd9Sstevel@tonic-gate } else { 4921*7c478bd9Sstevel@tonic-gate for (cp = argv; *cp; cp++) { 4922*7c478bd9Sstevel@tonic-gate if (is_prefix(*cp, *namep)) { 4923*7c478bd9Sstevel@tonic-gate gotit = 1; 4924*7c478bd9Sstevel@tonic-gate break; 4925*7c478bd9Sstevel@tonic-gate } 4926*7c478bd9Sstevel@tonic-gate } 4927*7c478bd9Sstevel@tonic-gate } 4928*7c478bd9Sstevel@tonic-gate 4929*7c478bd9Sstevel@tonic-gate if (! gotit) { 4930*7c478bd9Sstevel@tonic-gate passtape(); 4931*7c478bd9Sstevel@tonic-gate return (0); 4932*7c478bd9Sstevel@tonic-gate } 4933*7c478bd9Sstevel@tonic-gate 4934*7c478bd9Sstevel@tonic-gate if (Xflag && is_in_table(exclude_tbl, *namep)) { 4935*7c478bd9Sstevel@tonic-gate if (vflag) { 4936*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s excluded\n"), 4937*7c478bd9Sstevel@tonic-gate *namep); 4938*7c478bd9Sstevel@tonic-gate } 4939*7c478bd9Sstevel@tonic-gate passtape(); 4940*7c478bd9Sstevel@tonic-gate return (0); 4941*7c478bd9Sstevel@tonic-gate } 4942*7c478bd9Sstevel@tonic-gate 4943*7c478bd9Sstevel@tonic-gate return (1); 4944*7c478bd9Sstevel@tonic-gate } 4945*7c478bd9Sstevel@tonic-gate 4946*7c478bd9Sstevel@tonic-gate 4947*7c478bd9Sstevel@tonic-gate /* 4948*7c478bd9Sstevel@tonic-gate * Return through *namep a pointer to the proper fullname (i.e "<name> | 4949*7c478bd9Sstevel@tonic-gate * <prefix>/<name>"), as represented in the header entry dblock.dbuf. 4950*7c478bd9Sstevel@tonic-gate */ 4951*7c478bd9Sstevel@tonic-gate 4952*7c478bd9Sstevel@tonic-gate static void 4953*7c478bd9Sstevel@tonic-gate check_prefix(char **namep, char **dirp, char **compp) 4954*7c478bd9Sstevel@tonic-gate { 4955*7c478bd9Sstevel@tonic-gate static char fullname[PATH_MAX + 1]; 4956*7c478bd9Sstevel@tonic-gate static char dir[PATH_MAX + 1]; 4957*7c478bd9Sstevel@tonic-gate static char component[PATH_MAX + 1]; 4958*7c478bd9Sstevel@tonic-gate static char savename[PATH_MAX + 1]; 4959*7c478bd9Sstevel@tonic-gate char *s; 4960*7c478bd9Sstevel@tonic-gate 4961*7c478bd9Sstevel@tonic-gate (void) memset(dir, 0, sizeof (dir)); 4962*7c478bd9Sstevel@tonic-gate (void) memset(component, 0, sizeof (component)); 4963*7c478bd9Sstevel@tonic-gate 4964*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) { 4965*7c478bd9Sstevel@tonic-gate (void) strcpy(fullname, Xtarhdr.x_path); 4966*7c478bd9Sstevel@tonic-gate } else { 4967*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.prefix[0] != '\0') 4968*7c478bd9Sstevel@tonic-gate (void) sprintf(fullname, "%.*s/%.*s", PRESIZ, 4969*7c478bd9Sstevel@tonic-gate dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name); 4970*7c478bd9Sstevel@tonic-gate else 4971*7c478bd9Sstevel@tonic-gate (void) sprintf(fullname, "%.*s", NAMSIZ, 4972*7c478bd9Sstevel@tonic-gate dblock.dbuf.name); 4973*7c478bd9Sstevel@tonic-gate } 4974*7c478bd9Sstevel@tonic-gate 4975*7c478bd9Sstevel@tonic-gate /* 4976*7c478bd9Sstevel@tonic-gate * Set dir and component names 4977*7c478bd9Sstevel@tonic-gate */ 4978*7c478bd9Sstevel@tonic-gate 4979*7c478bd9Sstevel@tonic-gate get_parent(fullname, dir); 4980*7c478bd9Sstevel@tonic-gate 4981*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 4982*7c478bd9Sstevel@tonic-gate if (xattrp == (struct xattr_buf *)NULL) { 4983*7c478bd9Sstevel@tonic-gate #endif 4984*7c478bd9Sstevel@tonic-gate /* 4985*7c478bd9Sstevel@tonic-gate * Save of real name since were going to chop off the 4986*7c478bd9Sstevel@tonic-gate * trailing slashes. 4987*7c478bd9Sstevel@tonic-gate */ 4988*7c478bd9Sstevel@tonic-gate (void) strcpy(savename, fullname); 4989*7c478bd9Sstevel@tonic-gate /* 4990*7c478bd9Sstevel@tonic-gate * first strip of trailing slashes. 4991*7c478bd9Sstevel@tonic-gate */ 4992*7c478bd9Sstevel@tonic-gate chop_endslashes(savename); 4993*7c478bd9Sstevel@tonic-gate s = get_component(savename); 4994*7c478bd9Sstevel@tonic-gate (void) strcpy(component, s); 4995*7c478bd9Sstevel@tonic-gate 4996*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 4997*7c478bd9Sstevel@tonic-gate } else { 4998*7c478bd9Sstevel@tonic-gate (void) strcpy(fullname, xattrp->h_names); 4999*7c478bd9Sstevel@tonic-gate (void) strcpy(dir, fullname); 5000*7c478bd9Sstevel@tonic-gate (void) strcpy(component, xattrp->h_names + 5001*7c478bd9Sstevel@tonic-gate strlen(xattrp->h_names) + 1); 5002*7c478bd9Sstevel@tonic-gate } 5003*7c478bd9Sstevel@tonic-gate #endif 5004*7c478bd9Sstevel@tonic-gate *namep = fullname; 5005*7c478bd9Sstevel@tonic-gate *dirp = dir; 5006*7c478bd9Sstevel@tonic-gate *compp = component; 5007*7c478bd9Sstevel@tonic-gate } 5008*7c478bd9Sstevel@tonic-gate 5009*7c478bd9Sstevel@tonic-gate 5010*7c478bd9Sstevel@tonic-gate static wchar_t 5011*7c478bd9Sstevel@tonic-gate yesnoresponse(void) 5012*7c478bd9Sstevel@tonic-gate { 5013*7c478bd9Sstevel@tonic-gate wchar_t c; 5014*7c478bd9Sstevel@tonic-gate 5015*7c478bd9Sstevel@tonic-gate c = getwchar(); 5016*7c478bd9Sstevel@tonic-gate if (c != '\n') 5017*7c478bd9Sstevel@tonic-gate while (getwchar() != '\n'); 5018*7c478bd9Sstevel@tonic-gate else c = 0; 5019*7c478bd9Sstevel@tonic-gate return (c); 5020*7c478bd9Sstevel@tonic-gate } 5021*7c478bd9Sstevel@tonic-gate 5022*7c478bd9Sstevel@tonic-gate 5023*7c478bd9Sstevel@tonic-gate /* 5024*7c478bd9Sstevel@tonic-gate * Return true if the object indicated by the file descriptor and type 5025*7c478bd9Sstevel@tonic-gate * is a tape device, false otherwise 5026*7c478bd9Sstevel@tonic-gate */ 5027*7c478bd9Sstevel@tonic-gate 5028*7c478bd9Sstevel@tonic-gate static int 5029*7c478bd9Sstevel@tonic-gate istape(int fd, int type) 5030*7c478bd9Sstevel@tonic-gate { 5031*7c478bd9Sstevel@tonic-gate int result = 0; 5032*7c478bd9Sstevel@tonic-gate 5033*7c478bd9Sstevel@tonic-gate if (type & S_IFCHR) { 5034*7c478bd9Sstevel@tonic-gate struct mtget mtg; 5035*7c478bd9Sstevel@tonic-gate 5036*7c478bd9Sstevel@tonic-gate if (ioctl(fd, MTIOCGET, &mtg) != -1) { 5037*7c478bd9Sstevel@tonic-gate result = 1; 5038*7c478bd9Sstevel@tonic-gate } 5039*7c478bd9Sstevel@tonic-gate } 5040*7c478bd9Sstevel@tonic-gate 5041*7c478bd9Sstevel@tonic-gate return (result); 5042*7c478bd9Sstevel@tonic-gate } 5043*7c478bd9Sstevel@tonic-gate 5044*7c478bd9Sstevel@tonic-gate #include <utmpx.h> 5045*7c478bd9Sstevel@tonic-gate 5046*7c478bd9Sstevel@tonic-gate struct utmpx utmpx; 5047*7c478bd9Sstevel@tonic-gate 5048*7c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmpx.ut_name)) 5049*7c478bd9Sstevel@tonic-gate 5050*7c478bd9Sstevel@tonic-gate typedef struct cachenode { /* this struct must be zeroed before using */ 5051*7c478bd9Sstevel@tonic-gate struct cachenode *next; /* next in hash chain */ 5052*7c478bd9Sstevel@tonic-gate int val; /* the uid or gid of this entry */ 5053*7c478bd9Sstevel@tonic-gate int namehash; /* name's hash signature */ 5054*7c478bd9Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 5055*7c478bd9Sstevel@tonic-gate } cachenode_t; 5056*7c478bd9Sstevel@tonic-gate 5057*7c478bd9Sstevel@tonic-gate #define HASHSIZE 256 5058*7c478bd9Sstevel@tonic-gate 5059*7c478bd9Sstevel@tonic-gate static cachenode_t *names[HASHSIZE]; 5060*7c478bd9Sstevel@tonic-gate static cachenode_t *groups[HASHSIZE]; 5061*7c478bd9Sstevel@tonic-gate static cachenode_t *uids[HASHSIZE]; 5062*7c478bd9Sstevel@tonic-gate static cachenode_t *gids[HASHSIZE]; 5063*7c478bd9Sstevel@tonic-gate 5064*7c478bd9Sstevel@tonic-gate static int 5065*7c478bd9Sstevel@tonic-gate hash_byname(char *name) 5066*7c478bd9Sstevel@tonic-gate { 5067*7c478bd9Sstevel@tonic-gate int i, c, h = 0; 5068*7c478bd9Sstevel@tonic-gate 5069*7c478bd9Sstevel@tonic-gate for (i = 0; i < NMAX; i++) { 5070*7c478bd9Sstevel@tonic-gate c = name[i]; 5071*7c478bd9Sstevel@tonic-gate if (c == '\0') 5072*7c478bd9Sstevel@tonic-gate break; 5073*7c478bd9Sstevel@tonic-gate h = (h << 4) + h + c; 5074*7c478bd9Sstevel@tonic-gate } 5075*7c478bd9Sstevel@tonic-gate return (h); 5076*7c478bd9Sstevel@tonic-gate } 5077*7c478bd9Sstevel@tonic-gate 5078*7c478bd9Sstevel@tonic-gate static cachenode_t * 5079*7c478bd9Sstevel@tonic-gate hash_lookup_byval(cachenode_t *table[], int val) 5080*7c478bd9Sstevel@tonic-gate { 5081*7c478bd9Sstevel@tonic-gate int h = val; 5082*7c478bd9Sstevel@tonic-gate cachenode_t *c; 5083*7c478bd9Sstevel@tonic-gate 5084*7c478bd9Sstevel@tonic-gate for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) { 5085*7c478bd9Sstevel@tonic-gate if (c->val == val) 5086*7c478bd9Sstevel@tonic-gate return (c); 5087*7c478bd9Sstevel@tonic-gate } 5088*7c478bd9Sstevel@tonic-gate return (NULL); 5089*7c478bd9Sstevel@tonic-gate } 5090*7c478bd9Sstevel@tonic-gate 5091*7c478bd9Sstevel@tonic-gate static cachenode_t * 5092*7c478bd9Sstevel@tonic-gate hash_lookup_byname(cachenode_t *table[], char *name) 5093*7c478bd9Sstevel@tonic-gate { 5094*7c478bd9Sstevel@tonic-gate int h = hash_byname(name); 5095*7c478bd9Sstevel@tonic-gate cachenode_t *c; 5096*7c478bd9Sstevel@tonic-gate 5097*7c478bd9Sstevel@tonic-gate for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) { 5098*7c478bd9Sstevel@tonic-gate if (c->namehash == h && strcmp(c->name, name) == 0) 5099*7c478bd9Sstevel@tonic-gate return (c); 5100*7c478bd9Sstevel@tonic-gate } 5101*7c478bd9Sstevel@tonic-gate return (NULL); 5102*7c478bd9Sstevel@tonic-gate } 5103*7c478bd9Sstevel@tonic-gate 5104*7c478bd9Sstevel@tonic-gate static cachenode_t * 5105*7c478bd9Sstevel@tonic-gate hash_insert(cachenode_t *table[], char *name, int value) 5106*7c478bd9Sstevel@tonic-gate { 5107*7c478bd9Sstevel@tonic-gate cachenode_t *c; 5108*7c478bd9Sstevel@tonic-gate int signature; 5109*7c478bd9Sstevel@tonic-gate 5110*7c478bd9Sstevel@tonic-gate c = calloc(1, sizeof (cachenode_t)); 5111*7c478bd9Sstevel@tonic-gate if (c == NULL) { 5112*7c478bd9Sstevel@tonic-gate perror("malloc"); 5113*7c478bd9Sstevel@tonic-gate exit(1); 5114*7c478bd9Sstevel@tonic-gate } 5115*7c478bd9Sstevel@tonic-gate if (name != NULL) { 5116*7c478bd9Sstevel@tonic-gate (void) strncpy(c->name, name, NMAX); 5117*7c478bd9Sstevel@tonic-gate c->namehash = hash_byname(name); 5118*7c478bd9Sstevel@tonic-gate } 5119*7c478bd9Sstevel@tonic-gate c->val = value; 5120*7c478bd9Sstevel@tonic-gate if (table == uids || table == gids) 5121*7c478bd9Sstevel@tonic-gate signature = c->val; 5122*7c478bd9Sstevel@tonic-gate else 5123*7c478bd9Sstevel@tonic-gate signature = c->namehash; 5124*7c478bd9Sstevel@tonic-gate c->next = table[signature & (HASHSIZE - 1)]; 5125*7c478bd9Sstevel@tonic-gate table[signature & (HASHSIZE - 1)] = c; 5126*7c478bd9Sstevel@tonic-gate return (c); 5127*7c478bd9Sstevel@tonic-gate } 5128*7c478bd9Sstevel@tonic-gate 5129*7c478bd9Sstevel@tonic-gate static char * 5130*7c478bd9Sstevel@tonic-gate getname(uid_t uid) 5131*7c478bd9Sstevel@tonic-gate { 5132*7c478bd9Sstevel@tonic-gate cachenode_t *c; 5133*7c478bd9Sstevel@tonic-gate 5134*7c478bd9Sstevel@tonic-gate if ((c = hash_lookup_byval(uids, uid)) == NULL) { 5135*7c478bd9Sstevel@tonic-gate struct passwd *pwent = getpwuid(uid); 5136*7c478bd9Sstevel@tonic-gate c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid); 5137*7c478bd9Sstevel@tonic-gate } 5138*7c478bd9Sstevel@tonic-gate return (c->name); 5139*7c478bd9Sstevel@tonic-gate } 5140*7c478bd9Sstevel@tonic-gate 5141*7c478bd9Sstevel@tonic-gate static char * 5142*7c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 5143*7c478bd9Sstevel@tonic-gate { 5144*7c478bd9Sstevel@tonic-gate cachenode_t *c; 5145*7c478bd9Sstevel@tonic-gate 5146*7c478bd9Sstevel@tonic-gate if ((c = hash_lookup_byval(gids, gid)) == NULL) { 5147*7c478bd9Sstevel@tonic-gate struct group *grent = getgrgid(gid); 5148*7c478bd9Sstevel@tonic-gate c = hash_insert(gids, grent ? grent->gr_name : NULL, gid); 5149*7c478bd9Sstevel@tonic-gate } 5150*7c478bd9Sstevel@tonic-gate return (c->name); 5151*7c478bd9Sstevel@tonic-gate } 5152*7c478bd9Sstevel@tonic-gate 5153*7c478bd9Sstevel@tonic-gate static uid_t 5154*7c478bd9Sstevel@tonic-gate getuidbyname(char *name) 5155*7c478bd9Sstevel@tonic-gate { 5156*7c478bd9Sstevel@tonic-gate cachenode_t *c; 5157*7c478bd9Sstevel@tonic-gate 5158*7c478bd9Sstevel@tonic-gate if ((c = hash_lookup_byname(names, name)) == NULL) { 5159*7c478bd9Sstevel@tonic-gate struct passwd *pwent = getpwnam(name); 5160*7c478bd9Sstevel@tonic-gate c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1); 5161*7c478bd9Sstevel@tonic-gate } 5162*7c478bd9Sstevel@tonic-gate return ((uid_t)c->val); 5163*7c478bd9Sstevel@tonic-gate } 5164*7c478bd9Sstevel@tonic-gate 5165*7c478bd9Sstevel@tonic-gate static gid_t 5166*7c478bd9Sstevel@tonic-gate getgidbyname(char *group) 5167*7c478bd9Sstevel@tonic-gate { 5168*7c478bd9Sstevel@tonic-gate cachenode_t *c; 5169*7c478bd9Sstevel@tonic-gate 5170*7c478bd9Sstevel@tonic-gate if ((c = hash_lookup_byname(groups, group)) == NULL) { 5171*7c478bd9Sstevel@tonic-gate struct group *grent = getgrnam(group); 5172*7c478bd9Sstevel@tonic-gate c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1); 5173*7c478bd9Sstevel@tonic-gate } 5174*7c478bd9Sstevel@tonic-gate return ((gid_t)c->val); 5175*7c478bd9Sstevel@tonic-gate } 5176*7c478bd9Sstevel@tonic-gate 5177*7c478bd9Sstevel@tonic-gate /* 5178*7c478bd9Sstevel@tonic-gate * Build the header. 5179*7c478bd9Sstevel@tonic-gate * Determine whether or not an extended header is also needed. If needed, 5180*7c478bd9Sstevel@tonic-gate * create and write the extended header and its data. 5181*7c478bd9Sstevel@tonic-gate * Writing of the extended header assumes that "tomodes" has been called and 5182*7c478bd9Sstevel@tonic-gate * the relevant information has been placed in the header block. 5183*7c478bd9Sstevel@tonic-gate */ 5184*7c478bd9Sstevel@tonic-gate 5185*7c478bd9Sstevel@tonic-gate static int 5186*7c478bd9Sstevel@tonic-gate build_dblock( 5187*7c478bd9Sstevel@tonic-gate const char *name, 5188*7c478bd9Sstevel@tonic-gate const char *linkname, 5189*7c478bd9Sstevel@tonic-gate const char typeflag, 5190*7c478bd9Sstevel@tonic-gate const int filetype, 5191*7c478bd9Sstevel@tonic-gate const struct stat *sp, 5192*7c478bd9Sstevel@tonic-gate const dev_t device, 5193*7c478bd9Sstevel@tonic-gate const char *prefix) 5194*7c478bd9Sstevel@tonic-gate { 5195*7c478bd9Sstevel@tonic-gate int nblks; 5196*7c478bd9Sstevel@tonic-gate major_t dev; 5197*7c478bd9Sstevel@tonic-gate const char *filename; 5198*7c478bd9Sstevel@tonic-gate const char *lastslash; 5199*7c478bd9Sstevel@tonic-gate 5200*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) 5201*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = _XATTR_HDRTYPE; 5202*7c478bd9Sstevel@tonic-gate else 5203*7c478bd9Sstevel@tonic-gate dblock.dbuf.typeflag = typeflag; 5204*7c478bd9Sstevel@tonic-gate (void) memset(dblock.dbuf.name, '\0', NAMSIZ); 5205*7c478bd9Sstevel@tonic-gate (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ); 5206*7c478bd9Sstevel@tonic-gate (void) memset(dblock.dbuf.prefix, '\0', PRESIZ); 5207*7c478bd9Sstevel@tonic-gate 5208*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 5209*7c478bd9Sstevel@tonic-gate filename = Xtarhdr.x_path; 5210*7c478bd9Sstevel@tonic-gate else 5211*7c478bd9Sstevel@tonic-gate filename = name; 5212*7c478bd9Sstevel@tonic-gate 5213*7c478bd9Sstevel@tonic-gate if ((dev = major(device)) > OCTAL7CHAR) { 5214*7c478bd9Sstevel@tonic-gate if (Eflag) { 5215*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_DEVMAJOR; 5216*7c478bd9Sstevel@tonic-gate Xtarhdr.x_devmajor = dev; 5217*7c478bd9Sstevel@tonic-gate } else { 5218*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5219*7c478bd9Sstevel@tonic-gate "Device major too large for %s. Use -E flag."), 5220*7c478bd9Sstevel@tonic-gate filename); 5221*7c478bd9Sstevel@tonic-gate if (errflag) 5222*7c478bd9Sstevel@tonic-gate done(1); 5223*7c478bd9Sstevel@tonic-gate else 5224*7c478bd9Sstevel@tonic-gate Errflg = 1; 5225*7c478bd9Sstevel@tonic-gate } 5226*7c478bd9Sstevel@tonic-gate dev = 0; 5227*7c478bd9Sstevel@tonic-gate } 5228*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev); 5229*7c478bd9Sstevel@tonic-gate if ((dev = minor(device)) > OCTAL7CHAR) { 5230*7c478bd9Sstevel@tonic-gate if (Eflag) { 5231*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_DEVMINOR; 5232*7c478bd9Sstevel@tonic-gate Xtarhdr.x_devminor = dev; 5233*7c478bd9Sstevel@tonic-gate } else { 5234*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5235*7c478bd9Sstevel@tonic-gate "Device minor too large for %s. Use -E flag."), 5236*7c478bd9Sstevel@tonic-gate filename); 5237*7c478bd9Sstevel@tonic-gate if (errflag) 5238*7c478bd9Sstevel@tonic-gate done(1); 5239*7c478bd9Sstevel@tonic-gate else 5240*7c478bd9Sstevel@tonic-gate Errflg = 1; 5241*7c478bd9Sstevel@tonic-gate } 5242*7c478bd9Sstevel@tonic-gate dev = 0; 5243*7c478bd9Sstevel@tonic-gate } 5244*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.devminor, "%07lo", dev); 5245*7c478bd9Sstevel@tonic-gate 5246*7c478bd9Sstevel@tonic-gate (void) strncpy(dblock.dbuf.name, name, NAMSIZ); 5247*7c478bd9Sstevel@tonic-gate (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ); 5248*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type); 5249*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.version, "00"); 5250*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid)); 5251*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid)); 5252*7c478bd9Sstevel@tonic-gate (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ); 5253*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 5254*7c478bd9Sstevel@tonic-gate 5255*7c478bd9Sstevel@tonic-gate if (Eflag) { 5256*7c478bd9Sstevel@tonic-gate (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK); 5257*7c478bd9Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ); 5258*7c478bd9Sstevel@tonic-gate lastslash = strrchr(name, '/'); 5259*7c478bd9Sstevel@tonic-gate if (lastslash == NULL) 5260*7c478bd9Sstevel@tonic-gate lastslash = name; 5261*7c478bd9Sstevel@tonic-gate else 5262*7c478bd9Sstevel@tonic-gate lastslash++; 5263*7c478bd9Sstevel@tonic-gate (void) strcpy(xhdr_buf.dbuf.name, lastslash); 5264*7c478bd9Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ); 5265*7c478bd9Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ); 5266*7c478bd9Sstevel@tonic-gate (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname); 5267*7c478bd9Sstevel@tonic-gate xhdr_count++; 5268*7c478bd9Sstevel@tonic-gate xrec_offset = 0; 5269*7c478bd9Sstevel@tonic-gate gen_date("mtime", sp->st_mtim); 5270*7c478bd9Sstevel@tonic-gate xhdr_buf.dbuf.typeflag = 'X'; 5271*7c478bd9Sstevel@tonic-gate if (gen_utf8_names(filename) != 0) 5272*7c478bd9Sstevel@tonic-gate return (1); 5273*7c478bd9Sstevel@tonic-gate 5274*7c478bd9Sstevel@tonic-gate #ifdef XHDR_DEBUG 5275*7c478bd9Sstevel@tonic-gate Xtarhdr.x_uname = dblock.dbuf.uname; 5276*7c478bd9Sstevel@tonic-gate Xtarhdr.x_gname = dblock.dbuf.gname; 5277*7c478bd9Sstevel@tonic-gate xhdr_flgs |= (_X_UNAME | _X_GNAME); 5278*7c478bd9Sstevel@tonic-gate #endif 5279*7c478bd9Sstevel@tonic-gate if (xhdr_flgs) { 5280*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMAJOR) 5281*7c478bd9Sstevel@tonic-gate gen_num("SUN.devmajor", Xtarhdr.x_devmajor); 5282*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMINOR) 5283*7c478bd9Sstevel@tonic-gate gen_num("SUN.devminor", Xtarhdr.x_devminor); 5284*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_GID) 5285*7c478bd9Sstevel@tonic-gate gen_num("gid", Xtarhdr.x_gid); 5286*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_UID) 5287*7c478bd9Sstevel@tonic-gate gen_num("uid", Xtarhdr.x_uid); 5288*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_SIZE) 5289*7c478bd9Sstevel@tonic-gate gen_num("size", Xtarhdr.x_filesz); 5290*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 5291*7c478bd9Sstevel@tonic-gate gen_string("path", Xtarhdr.x_path); 5292*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) 5293*7c478bd9Sstevel@tonic-gate gen_string("linkpath", Xtarhdr.x_linkpath); 5294*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_GNAME) 5295*7c478bd9Sstevel@tonic-gate gen_string("gname", Xtarhdr.x_gname); 5296*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_UNAME) 5297*7c478bd9Sstevel@tonic-gate gen_string("uname", Xtarhdr.x_uname); 5298*7c478bd9Sstevel@tonic-gate } 5299*7c478bd9Sstevel@tonic-gate (void) sprintf(xhdr_buf.dbuf.size, 5300*7c478bd9Sstevel@tonic-gate "%011" FMT_off_t_o, xrec_offset); 5301*7c478bd9Sstevel@tonic-gate (void) sprintf(xhdr_buf.dbuf.chksum, "%07o", 5302*7c478bd9Sstevel@tonic-gate checksum(&xhdr_buf)); 5303*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)&xhdr_buf, 1); 5304*7c478bd9Sstevel@tonic-gate nblks = TBLOCKS(xrec_offset); 5305*7c478bd9Sstevel@tonic-gate (void) writetbuf(xrec_ptr, nblks); 5306*7c478bd9Sstevel@tonic-gate } 5307*7c478bd9Sstevel@tonic-gate return (0); 5308*7c478bd9Sstevel@tonic-gate } 5309*7c478bd9Sstevel@tonic-gate 5310*7c478bd9Sstevel@tonic-gate 5311*7c478bd9Sstevel@tonic-gate /* 5312*7c478bd9Sstevel@tonic-gate * makeDir - ensure that a directory with the pathname denoted by name 5313*7c478bd9Sstevel@tonic-gate * exists, and return 1 on success, and 0 on failure (e.g., 5314*7c478bd9Sstevel@tonic-gate * read-only file system, exists but not-a-directory). 5315*7c478bd9Sstevel@tonic-gate */ 5316*7c478bd9Sstevel@tonic-gate 5317*7c478bd9Sstevel@tonic-gate static int 5318*7c478bd9Sstevel@tonic-gate makeDir(char *name) 5319*7c478bd9Sstevel@tonic-gate { 5320*7c478bd9Sstevel@tonic-gate struct stat buf; 5321*7c478bd9Sstevel@tonic-gate 5322*7c478bd9Sstevel@tonic-gate if (access(name, 0) < 0) { /* name doesn't exist */ 5323*7c478bd9Sstevel@tonic-gate if (mkdir(name, 0777) < 0) { 5324*7c478bd9Sstevel@tonic-gate vperror(0, "%s", name); 5325*7c478bd9Sstevel@tonic-gate return (0); 5326*7c478bd9Sstevel@tonic-gate } 5327*7c478bd9Sstevel@tonic-gate } else { /* name exists */ 5328*7c478bd9Sstevel@tonic-gate if (stat(name, &buf) < 0) { 5329*7c478bd9Sstevel@tonic-gate vperror(0, "%s", name); 5330*7c478bd9Sstevel@tonic-gate return (0); 5331*7c478bd9Sstevel@tonic-gate } 5332*7c478bd9Sstevel@tonic-gate 5333*7c478bd9Sstevel@tonic-gate return ((buf.st_mode & S_IFMT) == S_IFDIR); 5334*7c478bd9Sstevel@tonic-gate } 5335*7c478bd9Sstevel@tonic-gate 5336*7c478bd9Sstevel@tonic-gate return (1); 5337*7c478bd9Sstevel@tonic-gate } 5338*7c478bd9Sstevel@tonic-gate 5339*7c478bd9Sstevel@tonic-gate 5340*7c478bd9Sstevel@tonic-gate /* 5341*7c478bd9Sstevel@tonic-gate * Save this directory and its mtime on the stack, popping and setting 5342*7c478bd9Sstevel@tonic-gate * the mtimes of any stacked dirs which aren't parents of this one. 5343*7c478bd9Sstevel@tonic-gate * A null name causes the entire stack to be unwound and set. 5344*7c478bd9Sstevel@tonic-gate * 5345*7c478bd9Sstevel@tonic-gate * Since all the elements of the directory "stack" share a common 5346*7c478bd9Sstevel@tonic-gate * prefix, we can make do with one string. We keep only the current 5347*7c478bd9Sstevel@tonic-gate * directory path, with an associated array of mtime's. A negative 5348*7c478bd9Sstevel@tonic-gate * mtime means no mtime. 5349*7c478bd9Sstevel@tonic-gate * 5350*7c478bd9Sstevel@tonic-gate * This stack algorithm is not guaranteed to work for tapes created 5351*7c478bd9Sstevel@tonic-gate * with the 'r' function letter, but the vast majority of tapes with 5352*7c478bd9Sstevel@tonic-gate * directories are not. This avoids saving every directory record on 5353*7c478bd9Sstevel@tonic-gate * the tape and setting all the times at the end. 5354*7c478bd9Sstevel@tonic-gate * 5355*7c478bd9Sstevel@tonic-gate * (This was borrowed from the 4.1.3 source, and adapted to the 5.x 5356*7c478bd9Sstevel@tonic-gate * environment) 5357*7c478bd9Sstevel@tonic-gate */ 5358*7c478bd9Sstevel@tonic-gate 5359*7c478bd9Sstevel@tonic-gate static void 5360*7c478bd9Sstevel@tonic-gate doDirTimes(char *name, timestruc_t modTime) 5361*7c478bd9Sstevel@tonic-gate { 5362*7c478bd9Sstevel@tonic-gate static char dirstack[PATH_MAX+2]; 5363*7c478bd9Sstevel@tonic-gate /* Add spaces for the last slash and last NULL */ 5364*7c478bd9Sstevel@tonic-gate static timestruc_t modtimes[PATH_MAX+1]; /* hash table */ 5365*7c478bd9Sstevel@tonic-gate char *p = dirstack; 5366*7c478bd9Sstevel@tonic-gate char *q = name; 5367*7c478bd9Sstevel@tonic-gate char *savp; 5368*7c478bd9Sstevel@tonic-gate 5369*7c478bd9Sstevel@tonic-gate if (q) { 5370*7c478bd9Sstevel@tonic-gate /* 5371*7c478bd9Sstevel@tonic-gate * Find common prefix 5372*7c478bd9Sstevel@tonic-gate */ 5373*7c478bd9Sstevel@tonic-gate 5374*7c478bd9Sstevel@tonic-gate while (*p == *q && *p) { 5375*7c478bd9Sstevel@tonic-gate p++; q++; 5376*7c478bd9Sstevel@tonic-gate } 5377*7c478bd9Sstevel@tonic-gate } 5378*7c478bd9Sstevel@tonic-gate 5379*7c478bd9Sstevel@tonic-gate savp = p; 5380*7c478bd9Sstevel@tonic-gate while (*p) { 5381*7c478bd9Sstevel@tonic-gate /* 5382*7c478bd9Sstevel@tonic-gate * Not a child: unwind the stack, setting the times. 5383*7c478bd9Sstevel@tonic-gate * The order we do this doesn't matter, so we go "forward." 5384*7c478bd9Sstevel@tonic-gate */ 5385*7c478bd9Sstevel@tonic-gate 5386*7c478bd9Sstevel@tonic-gate if (*p == '/') 5387*7c478bd9Sstevel@tonic-gate if (modtimes[p - dirstack].tv_sec >= 0) { 5388*7c478bd9Sstevel@tonic-gate *p = '\0'; /* zap the slash */ 5389*7c478bd9Sstevel@tonic-gate setPathTimes(AT_FDCWD, dirstack, 5390*7c478bd9Sstevel@tonic-gate modtimes[p - dirstack]); 5391*7c478bd9Sstevel@tonic-gate *p = '/'; 5392*7c478bd9Sstevel@tonic-gate } 5393*7c478bd9Sstevel@tonic-gate ++p; 5394*7c478bd9Sstevel@tonic-gate } 5395*7c478bd9Sstevel@tonic-gate 5396*7c478bd9Sstevel@tonic-gate p = savp; 5397*7c478bd9Sstevel@tonic-gate 5398*7c478bd9Sstevel@tonic-gate /* 5399*7c478bd9Sstevel@tonic-gate * Push this one on the "stack" 5400*7c478bd9Sstevel@tonic-gate */ 5401*7c478bd9Sstevel@tonic-gate 5402*7c478bd9Sstevel@tonic-gate if (q) { 5403*7c478bd9Sstevel@tonic-gate 5404*7c478bd9Sstevel@tonic-gate /* 5405*7c478bd9Sstevel@tonic-gate * Since the name parameter points the dir pathname 5406*7c478bd9Sstevel@tonic-gate * which is limited only to contain PATH_MAX chars 5407*7c478bd9Sstevel@tonic-gate * at maximum, we can ignore the overflow case of p. 5408*7c478bd9Sstevel@tonic-gate */ 5409*7c478bd9Sstevel@tonic-gate 5410*7c478bd9Sstevel@tonic-gate while ((*p = *q++)) { /* append the rest of the new dir */ 5411*7c478bd9Sstevel@tonic-gate modtimes[p - dirstack].tv_sec = -1; 5412*7c478bd9Sstevel@tonic-gate p++; 5413*7c478bd9Sstevel@tonic-gate } 5414*7c478bd9Sstevel@tonic-gate 5415*7c478bd9Sstevel@tonic-gate /* 5416*7c478bd9Sstevel@tonic-gate * If the tar file had used 'P' or 'E' function modifier, 5417*7c478bd9Sstevel@tonic-gate * append the last slash. 5418*7c478bd9Sstevel@tonic-gate */ 5419*7c478bd9Sstevel@tonic-gate if (*(p - 1) != '/') { 5420*7c478bd9Sstevel@tonic-gate *p++ = '/'; 5421*7c478bd9Sstevel@tonic-gate *p = '\0'; 5422*7c478bd9Sstevel@tonic-gate } 5423*7c478bd9Sstevel@tonic-gate /* overwrite the last one */ 5424*7c478bd9Sstevel@tonic-gate modtimes[p - dirstack - 1] = modTime; 5425*7c478bd9Sstevel@tonic-gate } 5426*7c478bd9Sstevel@tonic-gate } 5427*7c478bd9Sstevel@tonic-gate 5428*7c478bd9Sstevel@tonic-gate 5429*7c478bd9Sstevel@tonic-gate /* 5430*7c478bd9Sstevel@tonic-gate * setPathTimes - set the modification time for given path. Return 1 if 5431*7c478bd9Sstevel@tonic-gate * successful and 0 if not successful. 5432*7c478bd9Sstevel@tonic-gate */ 5433*7c478bd9Sstevel@tonic-gate 5434*7c478bd9Sstevel@tonic-gate static void 5435*7c478bd9Sstevel@tonic-gate setPathTimes(int dirfd, char *path, timestruc_t modTime) 5436*7c478bd9Sstevel@tonic-gate 5437*7c478bd9Sstevel@tonic-gate { 5438*7c478bd9Sstevel@tonic-gate struct timeval timebuf[2]; 5439*7c478bd9Sstevel@tonic-gate 5440*7c478bd9Sstevel@tonic-gate /* 5441*7c478bd9Sstevel@tonic-gate * futimesat takes an array of two timeval structs. 5442*7c478bd9Sstevel@tonic-gate * The first entry contains access time. 5443*7c478bd9Sstevel@tonic-gate * The second entry contains modification time. 5444*7c478bd9Sstevel@tonic-gate * Unlike a timestruc_t, which uses nanoseconds, timeval uses 5445*7c478bd9Sstevel@tonic-gate * microseconds. 5446*7c478bd9Sstevel@tonic-gate */ 5447*7c478bd9Sstevel@tonic-gate timebuf[0].tv_sec = time((time_t *)0); 5448*7c478bd9Sstevel@tonic-gate timebuf[0].tv_usec = 0; 5449*7c478bd9Sstevel@tonic-gate timebuf[1].tv_sec = modTime.tv_sec; 5450*7c478bd9Sstevel@tonic-gate 5451*7c478bd9Sstevel@tonic-gate /* Extended header: use microseconds */ 5452*7c478bd9Sstevel@tonic-gate timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0; 5453*7c478bd9Sstevel@tonic-gate 5454*7c478bd9Sstevel@tonic-gate if (futimesat(dirfd, path, timebuf) < 0) 5455*7c478bd9Sstevel@tonic-gate vperror(0, "can't set time on %s", path); 5456*7c478bd9Sstevel@tonic-gate } 5457*7c478bd9Sstevel@tonic-gate 5458*7c478bd9Sstevel@tonic-gate 5459*7c478bd9Sstevel@tonic-gate /* 5460*7c478bd9Sstevel@tonic-gate * If hflag is set then delete the symbolic link's target. 5461*7c478bd9Sstevel@tonic-gate * If !hflag then delete the target. 5462*7c478bd9Sstevel@tonic-gate */ 5463*7c478bd9Sstevel@tonic-gate 5464*7c478bd9Sstevel@tonic-gate static void 5465*7c478bd9Sstevel@tonic-gate delete_target(int fd, char *namep) 5466*7c478bd9Sstevel@tonic-gate { 5467*7c478bd9Sstevel@tonic-gate struct stat xtractbuf; 5468*7c478bd9Sstevel@tonic-gate char buf[PATH_MAX + 1]; 5469*7c478bd9Sstevel@tonic-gate int n; 5470*7c478bd9Sstevel@tonic-gate 5471*7c478bd9Sstevel@tonic-gate 5472*7c478bd9Sstevel@tonic-gate if (unlinkat(fd, namep, AT_REMOVEDIR) < 0) { 5473*7c478bd9Sstevel@tonic-gate if (errno == ENOTDIR && !hflag) { 5474*7c478bd9Sstevel@tonic-gate (void) unlinkat(fd, namep, 0); 5475*7c478bd9Sstevel@tonic-gate } else if (errno == ENOTDIR && hflag) { 5476*7c478bd9Sstevel@tonic-gate if (!lstat(namep, &xtractbuf)) { 5477*7c478bd9Sstevel@tonic-gate if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) { 5478*7c478bd9Sstevel@tonic-gate (void) unlinkat(fd, namep, 0); 5479*7c478bd9Sstevel@tonic-gate } else if ((n = readlink(namep, buf, 5480*7c478bd9Sstevel@tonic-gate PATH_MAX)) != -1) { 5481*7c478bd9Sstevel@tonic-gate buf[n] = (char)NULL; 5482*7c478bd9Sstevel@tonic-gate (void) unlinkat(fd, buf, 5483*7c478bd9Sstevel@tonic-gate AT_REMOVEDIR); 5484*7c478bd9Sstevel@tonic-gate if (errno == ENOTDIR) 5485*7c478bd9Sstevel@tonic-gate (void) unlinkat(fd, buf, 0); 5486*7c478bd9Sstevel@tonic-gate } else { 5487*7c478bd9Sstevel@tonic-gate (void) unlinkat(fd, namep, 0); 5488*7c478bd9Sstevel@tonic-gate } 5489*7c478bd9Sstevel@tonic-gate } else { 5490*7c478bd9Sstevel@tonic-gate (void) unlinkat(fd, namep, 0); 5491*7c478bd9Sstevel@tonic-gate } 5492*7c478bd9Sstevel@tonic-gate } 5493*7c478bd9Sstevel@tonic-gate } 5494*7c478bd9Sstevel@tonic-gate } 5495*7c478bd9Sstevel@tonic-gate 5496*7c478bd9Sstevel@tonic-gate 5497*7c478bd9Sstevel@tonic-gate /* 5498*7c478bd9Sstevel@tonic-gate * ACL changes: 5499*7c478bd9Sstevel@tonic-gate * putfile(): 5500*7c478bd9Sstevel@tonic-gate * Get acl info after stat. Write out ancillary file 5501*7c478bd9Sstevel@tonic-gate * before the normal file, i.e. directory, regular, FIFO, 5502*7c478bd9Sstevel@tonic-gate * link, special. If acl count is less than 4, no need to 5503*7c478bd9Sstevel@tonic-gate * create ancillary file. (i.e. standard permission is in 5504*7c478bd9Sstevel@tonic-gate * use. 5505*7c478bd9Sstevel@tonic-gate * doxtract(): 5506*7c478bd9Sstevel@tonic-gate * Process ancillary file. Read it in and set acl info. 5507*7c478bd9Sstevel@tonic-gate * watch out for 'o' function modifier. 5508*7c478bd9Sstevel@tonic-gate * 't' function letter to display table 5509*7c478bd9Sstevel@tonic-gate */ 5510*7c478bd9Sstevel@tonic-gate 5511*7c478bd9Sstevel@tonic-gate /* 5512*7c478bd9Sstevel@tonic-gate * New functions for ACLs and other security attributes 5513*7c478bd9Sstevel@tonic-gate */ 5514*7c478bd9Sstevel@tonic-gate 5515*7c478bd9Sstevel@tonic-gate /* 5516*7c478bd9Sstevel@tonic-gate * The function appends the new security attribute info to the end of 5517*7c478bd9Sstevel@tonic-gate * existing secinfo. 5518*7c478bd9Sstevel@tonic-gate */ 5519*7c478bd9Sstevel@tonic-gate int 5520*7c478bd9Sstevel@tonic-gate append_secattr( 5521*7c478bd9Sstevel@tonic-gate char **secinfo, /* existing security info */ 5522*7c478bd9Sstevel@tonic-gate int *secinfo_len, /* length of existing security info */ 5523*7c478bd9Sstevel@tonic-gate int size, /* new attribute size: unit depends on type */ 5524*7c478bd9Sstevel@tonic-gate aclent_t *attrp, /* new attribute data pointer */ 5525*7c478bd9Sstevel@tonic-gate char attr_type) /* new attribute type */ 5526*7c478bd9Sstevel@tonic-gate { 5527*7c478bd9Sstevel@tonic-gate char *new_secinfo; 5528*7c478bd9Sstevel@tonic-gate char *attrtext; 5529*7c478bd9Sstevel@tonic-gate int newattrsize; 5530*7c478bd9Sstevel@tonic-gate int oldsize; 5531*7c478bd9Sstevel@tonic-gate 5532*7c478bd9Sstevel@tonic-gate /* no need to add */ 5533*7c478bd9Sstevel@tonic-gate if (attrp == NULL) 5534*7c478bd9Sstevel@tonic-gate return (0); 5535*7c478bd9Sstevel@tonic-gate 5536*7c478bd9Sstevel@tonic-gate switch (attr_type) { 5537*7c478bd9Sstevel@tonic-gate case UFSD_ACL: 5538*7c478bd9Sstevel@tonic-gate attrtext = acltotext((aclent_t *)attrp, size); 5539*7c478bd9Sstevel@tonic-gate if (attrtext == NULL) { 5540*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "acltotext failed\n"); 5541*7c478bd9Sstevel@tonic-gate return (-1); 5542*7c478bd9Sstevel@tonic-gate } 5543*7c478bd9Sstevel@tonic-gate /* header: type + size = 8 */ 5544*7c478bd9Sstevel@tonic-gate newattrsize = 8 + (int)strlen(attrtext) + 1; 5545*7c478bd9Sstevel@tonic-gate attr = (struct sec_attr *)malloc(newattrsize); 5546*7c478bd9Sstevel@tonic-gate if (attr == NULL) { 5547*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "can't allocate memory\n"); 5548*7c478bd9Sstevel@tonic-gate return (-1); 5549*7c478bd9Sstevel@tonic-gate } 5550*7c478bd9Sstevel@tonic-gate attr->attr_type = UFSD_ACL; 5551*7c478bd9Sstevel@tonic-gate (void) sprintf(attr->attr_len, 5552*7c478bd9Sstevel@tonic-gate "%06o", size); /* acl entry count */ 5553*7c478bd9Sstevel@tonic-gate (void) strcpy((char *)&attr->attr_info[0], attrtext); 5554*7c478bd9Sstevel@tonic-gate free(attrtext); 5555*7c478bd9Sstevel@tonic-gate break; 5556*7c478bd9Sstevel@tonic-gate 5557*7c478bd9Sstevel@tonic-gate /* SunFed's case goes here */ 5558*7c478bd9Sstevel@tonic-gate 5559*7c478bd9Sstevel@tonic-gate default: 5560*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "unrecognized attribute type\n"); 5561*7c478bd9Sstevel@tonic-gate return (-1); 5562*7c478bd9Sstevel@tonic-gate } 5563*7c478bd9Sstevel@tonic-gate 5564*7c478bd9Sstevel@tonic-gate /* old security info + new attr header(8) + new attr */ 5565*7c478bd9Sstevel@tonic-gate oldsize = *secinfo_len; 5566*7c478bd9Sstevel@tonic-gate *secinfo_len += newattrsize; 5567*7c478bd9Sstevel@tonic-gate new_secinfo = (char *)malloc(*secinfo_len); 5568*7c478bd9Sstevel@tonic-gate if (new_secinfo == NULL) { 5569*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "can't allocate memory\n"); 5570*7c478bd9Sstevel@tonic-gate *secinfo_len -= newattrsize; 5571*7c478bd9Sstevel@tonic-gate return (-1); 5572*7c478bd9Sstevel@tonic-gate } 5573*7c478bd9Sstevel@tonic-gate 5574*7c478bd9Sstevel@tonic-gate (void) memcpy(new_secinfo, *secinfo, oldsize); 5575*7c478bd9Sstevel@tonic-gate (void) memcpy(new_secinfo + oldsize, attr, newattrsize); 5576*7c478bd9Sstevel@tonic-gate 5577*7c478bd9Sstevel@tonic-gate free(*secinfo); 5578*7c478bd9Sstevel@tonic-gate *secinfo = new_secinfo; 5579*7c478bd9Sstevel@tonic-gate return (0); 5580*7c478bd9Sstevel@tonic-gate } 5581*7c478bd9Sstevel@tonic-gate 5582*7c478bd9Sstevel@tonic-gate /* 5583*7c478bd9Sstevel@tonic-gate * write_ancillary(): write out an ancillary file. 5584*7c478bd9Sstevel@tonic-gate * The file has the same header as normal file except the type and size 5585*7c478bd9Sstevel@tonic-gate * fields. The type is 'A' and size is the sum of all attributes 5586*7c478bd9Sstevel@tonic-gate * in bytes. 5587*7c478bd9Sstevel@tonic-gate * The body contains a list of attribute type, size and info. Currently, 5588*7c478bd9Sstevel@tonic-gate * there is only ACL info. This file is put before the normal file. 5589*7c478bd9Sstevel@tonic-gate */ 5590*7c478bd9Sstevel@tonic-gate void 5591*7c478bd9Sstevel@tonic-gate write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype) 5592*7c478bd9Sstevel@tonic-gate { 5593*7c478bd9Sstevel@tonic-gate long blocks; 5594*7c478bd9Sstevel@tonic-gate int savflag; 5595*7c478bd9Sstevel@tonic-gate int savsize; 5596*7c478bd9Sstevel@tonic-gate 5597*7c478bd9Sstevel@tonic-gate /* Just tranditional permissions or no security attribute info */ 5598*7c478bd9Sstevel@tonic-gate if (len == 0 || secinfo == NULL) 5599*7c478bd9Sstevel@tonic-gate return; 5600*7c478bd9Sstevel@tonic-gate 5601*7c478bd9Sstevel@tonic-gate /* save flag and size */ 5602*7c478bd9Sstevel@tonic-gate savflag = (dblockp->dbuf).typeflag; 5603*7c478bd9Sstevel@tonic-gate (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize); 5604*7c478bd9Sstevel@tonic-gate 5605*7c478bd9Sstevel@tonic-gate /* special flag for ancillary file */ 5606*7c478bd9Sstevel@tonic-gate if (hdrtype == _XATTR_HDRTYPE) 5607*7c478bd9Sstevel@tonic-gate dblockp->dbuf.typeflag = _XATTR_HDRTYPE; 5608*7c478bd9Sstevel@tonic-gate else 5609*7c478bd9Sstevel@tonic-gate dblockp->dbuf.typeflag = 'A'; 5610*7c478bd9Sstevel@tonic-gate 5611*7c478bd9Sstevel@tonic-gate /* for pre-2.5 versions of tar, need to make sure */ 5612*7c478bd9Sstevel@tonic-gate /* the ACL file is readable */ 5613*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo", 5614*7c478bd9Sstevel@tonic-gate (stbuf.st_mode & POSIXMODES) | 0000200); 5615*7c478bd9Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.size, "%011o", len); 5616*7c478bd9Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp)); 5617*7c478bd9Sstevel@tonic-gate 5618*7c478bd9Sstevel@tonic-gate /* write out the header */ 5619*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)dblockp, 1); 5620*7c478bd9Sstevel@tonic-gate 5621*7c478bd9Sstevel@tonic-gate /* write out security info */ 5622*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(len); 5623*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)secinfo, (int)blocks); 5624*7c478bd9Sstevel@tonic-gate 5625*7c478bd9Sstevel@tonic-gate /* restore mode, flag and size */ 5626*7c478bd9Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES); 5627*7c478bd9Sstevel@tonic-gate dblockp->dbuf.typeflag = savflag; 5628*7c478bd9Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.size, "%011o", savsize); 5629*7c478bd9Sstevel@tonic-gate } 5630*7c478bd9Sstevel@tonic-gate 5631*7c478bd9Sstevel@tonic-gate /* 5632*7c478bd9Sstevel@tonic-gate * Read the data record for extended headers and then the regular header. 5633*7c478bd9Sstevel@tonic-gate * The data are read into the buffer and then null-terminated. Entries 5634*7c478bd9Sstevel@tonic-gate * are of the format: 5635*7c478bd9Sstevel@tonic-gate * "%d %s=%s\n" 5636*7c478bd9Sstevel@tonic-gate * 5637*7c478bd9Sstevel@tonic-gate * When an extended header record is found, the extended header must 5638*7c478bd9Sstevel@tonic-gate * be processed and its values used to override the values in the 5639*7c478bd9Sstevel@tonic-gate * normal header. The way this is done is to process the extended 5640*7c478bd9Sstevel@tonic-gate * header data record and set the data values, then call getdir 5641*7c478bd9Sstevel@tonic-gate * to process the regular header, then then to reconcile the two 5642*7c478bd9Sstevel@tonic-gate * sets of data. 5643*7c478bd9Sstevel@tonic-gate */ 5644*7c478bd9Sstevel@tonic-gate 5645*7c478bd9Sstevel@tonic-gate static int 5646*7c478bd9Sstevel@tonic-gate get_xdata(void) 5647*7c478bd9Sstevel@tonic-gate { 5648*7c478bd9Sstevel@tonic-gate struct keylist_pair { 5649*7c478bd9Sstevel@tonic-gate int keynum; 5650*7c478bd9Sstevel@tonic-gate char *keylist; 5651*7c478bd9Sstevel@tonic-gate } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor", 5652*7c478bd9Sstevel@tonic-gate _X_DEVMINOR, "SUN.devminor", 5653*7c478bd9Sstevel@tonic-gate _X_GID, "gid", 5654*7c478bd9Sstevel@tonic-gate _X_GNAME, "gname", 5655*7c478bd9Sstevel@tonic-gate _X_LINKPATH, "linkpath", 5656*7c478bd9Sstevel@tonic-gate _X_PATH, "path", 5657*7c478bd9Sstevel@tonic-gate _X_SIZE, "size", 5658*7c478bd9Sstevel@tonic-gate _X_UID, "uid", 5659*7c478bd9Sstevel@tonic-gate _X_UNAME, "uname", 5660*7c478bd9Sstevel@tonic-gate _X_MTIME, "mtime", 5661*7c478bd9Sstevel@tonic-gate _X_LAST, "NULL" }; 5662*7c478bd9Sstevel@tonic-gate char *lineloc; 5663*7c478bd9Sstevel@tonic-gate int length, i; 5664*7c478bd9Sstevel@tonic-gate char *keyword, *value; 5665*7c478bd9Sstevel@tonic-gate blkcnt_t nblocks; 5666*7c478bd9Sstevel@tonic-gate int bufneeded; 5667*7c478bd9Sstevel@tonic-gate struct stat *sp = &stbuf; 5668*7c478bd9Sstevel@tonic-gate int errors; 5669*7c478bd9Sstevel@tonic-gate 5670*7c478bd9Sstevel@tonic-gate Xtarhdr.x_uid = 0; 5671*7c478bd9Sstevel@tonic-gate Xtarhdr.x_gid = 0; 5672*7c478bd9Sstevel@tonic-gate Xtarhdr.x_devmajor = 0; 5673*7c478bd9Sstevel@tonic-gate Xtarhdr.x_devminor = 0; 5674*7c478bd9Sstevel@tonic-gate Xtarhdr.x_filesz = 0; 5675*7c478bd9Sstevel@tonic-gate Xtarhdr.x_uname = NULL; 5676*7c478bd9Sstevel@tonic-gate Xtarhdr.x_gname = NULL; 5677*7c478bd9Sstevel@tonic-gate Xtarhdr.x_linkpath = NULL; 5678*7c478bd9Sstevel@tonic-gate Xtarhdr.x_path = NULL; 5679*7c478bd9Sstevel@tonic-gate Xtarhdr.x_mtime.tv_sec = 0; 5680*7c478bd9Sstevel@tonic-gate Xtarhdr.x_mtime.tv_nsec = 0; 5681*7c478bd9Sstevel@tonic-gate xhdr_count++; 5682*7c478bd9Sstevel@tonic-gate errors = 0; 5683*7c478bd9Sstevel@tonic-gate 5684*7c478bd9Sstevel@tonic-gate nblocks = TBLOCKS(stbuf.st_size); 5685*7c478bd9Sstevel@tonic-gate bufneeded = nblocks * TBLOCK; 5686*7c478bd9Sstevel@tonic-gate if (bufneeded >= xrec_size) { 5687*7c478bd9Sstevel@tonic-gate free(xrec_ptr); 5688*7c478bd9Sstevel@tonic-gate xrec_size = bufneeded + 1; 5689*7c478bd9Sstevel@tonic-gate if ((xrec_ptr = malloc(xrec_size)) == NULL) 5690*7c478bd9Sstevel@tonic-gate fatal(gettext("cannot allocate buffer")); 5691*7c478bd9Sstevel@tonic-gate } 5692*7c478bd9Sstevel@tonic-gate 5693*7c478bd9Sstevel@tonic-gate lineloc = xrec_ptr; 5694*7c478bd9Sstevel@tonic-gate 5695*7c478bd9Sstevel@tonic-gate while (nblocks-- > 0) { 5696*7c478bd9Sstevel@tonic-gate readtape(lineloc); 5697*7c478bd9Sstevel@tonic-gate lineloc += TBLOCK; 5698*7c478bd9Sstevel@tonic-gate } 5699*7c478bd9Sstevel@tonic-gate lineloc = xrec_ptr; 5700*7c478bd9Sstevel@tonic-gate xrec_ptr[stbuf.st_size] = '\0'; 5701*7c478bd9Sstevel@tonic-gate while (lineloc < xrec_ptr + stbuf.st_size) { 5702*7c478bd9Sstevel@tonic-gate length = atoi(lineloc); 5703*7c478bd9Sstevel@tonic-gate *(lineloc + length - 1) = '\0'; 5704*7c478bd9Sstevel@tonic-gate keyword = strchr(lineloc, ' ') + 1; 5705*7c478bd9Sstevel@tonic-gate value = strchr(keyword, '=') + 1; 5706*7c478bd9Sstevel@tonic-gate *(value - 1) = '\0'; 5707*7c478bd9Sstevel@tonic-gate i = 0; 5708*7c478bd9Sstevel@tonic-gate lineloc += length; 5709*7c478bd9Sstevel@tonic-gate while (keylist_pair[i].keynum != (int)_X_LAST) { 5710*7c478bd9Sstevel@tonic-gate if (strcmp(keyword, keylist_pair[i].keylist) == 0) 5711*7c478bd9Sstevel@tonic-gate break; 5712*7c478bd9Sstevel@tonic-gate i++; 5713*7c478bd9Sstevel@tonic-gate } 5714*7c478bd9Sstevel@tonic-gate errno = 0; 5715*7c478bd9Sstevel@tonic-gate switch (keylist_pair[i].keynum) { 5716*7c478bd9Sstevel@tonic-gate case _X_DEVMAJOR: 5717*7c478bd9Sstevel@tonic-gate Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0); 5718*7c478bd9Sstevel@tonic-gate if (errno) { 5719*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5720*7c478bd9Sstevel@tonic-gate "tar: Extended header major value error " 5721*7c478bd9Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5722*7c478bd9Sstevel@tonic-gate errors++; 5723*7c478bd9Sstevel@tonic-gate } else 5724*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_DEVMAJOR; 5725*7c478bd9Sstevel@tonic-gate break; 5726*7c478bd9Sstevel@tonic-gate case _X_DEVMINOR: 5727*7c478bd9Sstevel@tonic-gate Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0); 5728*7c478bd9Sstevel@tonic-gate if (errno) { 5729*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5730*7c478bd9Sstevel@tonic-gate "tar: Extended header minor value error " 5731*7c478bd9Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5732*7c478bd9Sstevel@tonic-gate errors++; 5733*7c478bd9Sstevel@tonic-gate } else 5734*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_DEVMINOR; 5735*7c478bd9Sstevel@tonic-gate break; 5736*7c478bd9Sstevel@tonic-gate case _X_GID: 5737*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_GID; 5738*7c478bd9Sstevel@tonic-gate Xtarhdr.x_gid = strtol(value, NULL, 0); 5739*7c478bd9Sstevel@tonic-gate if ((errno) || (Xtarhdr.x_gid > UID_MAX)) { 5740*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5741*7c478bd9Sstevel@tonic-gate "tar: Extended header gid value error " 5742*7c478bd9Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5743*7c478bd9Sstevel@tonic-gate Xtarhdr.x_gid = GID_NOBODY; 5744*7c478bd9Sstevel@tonic-gate } 5745*7c478bd9Sstevel@tonic-gate break; 5746*7c478bd9Sstevel@tonic-gate case _X_GNAME: 5747*7c478bd9Sstevel@tonic-gate if (utf8_local("gname", &Xtarhdr.x_gname, 5748*7c478bd9Sstevel@tonic-gate local_gname, value, _POSIX_NAME_MAX) == 0) 5749*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_GNAME; 5750*7c478bd9Sstevel@tonic-gate break; 5751*7c478bd9Sstevel@tonic-gate case _X_LINKPATH: 5752*7c478bd9Sstevel@tonic-gate if (utf8_local("linkpath", &Xtarhdr.x_linkpath, 5753*7c478bd9Sstevel@tonic-gate local_linkpath, value, PATH_MAX) == 0) 5754*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH; 5755*7c478bd9Sstevel@tonic-gate else 5756*7c478bd9Sstevel@tonic-gate errors++; 5757*7c478bd9Sstevel@tonic-gate break; 5758*7c478bd9Sstevel@tonic-gate case _X_PATH: 5759*7c478bd9Sstevel@tonic-gate if (utf8_local("path", &Xtarhdr.x_path, 5760*7c478bd9Sstevel@tonic-gate local_path, value, PATH_MAX) == 0) 5761*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_PATH; 5762*7c478bd9Sstevel@tonic-gate else 5763*7c478bd9Sstevel@tonic-gate errors++; 5764*7c478bd9Sstevel@tonic-gate break; 5765*7c478bd9Sstevel@tonic-gate case _X_SIZE: 5766*7c478bd9Sstevel@tonic-gate Xtarhdr.x_filesz = strtoull(value, NULL, 0); 5767*7c478bd9Sstevel@tonic-gate if (errno) { 5768*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5769*7c478bd9Sstevel@tonic-gate "tar: Extended header invalid filesize " 5770*7c478bd9Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5771*7c478bd9Sstevel@tonic-gate errors++; 5772*7c478bd9Sstevel@tonic-gate } else 5773*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_SIZE; 5774*7c478bd9Sstevel@tonic-gate break; 5775*7c478bd9Sstevel@tonic-gate case _X_UID: 5776*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_UID; 5777*7c478bd9Sstevel@tonic-gate Xtarhdr.x_uid = strtol(value, NULL, 0); 5778*7c478bd9Sstevel@tonic-gate if ((errno) || (Xtarhdr.x_uid > UID_MAX)) { 5779*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5780*7c478bd9Sstevel@tonic-gate "tar: Extended header uid value error " 5781*7c478bd9Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5782*7c478bd9Sstevel@tonic-gate Xtarhdr.x_uid = UID_NOBODY; 5783*7c478bd9Sstevel@tonic-gate } 5784*7c478bd9Sstevel@tonic-gate break; 5785*7c478bd9Sstevel@tonic-gate case _X_UNAME: 5786*7c478bd9Sstevel@tonic-gate if (utf8_local("uname", &Xtarhdr.x_uname, 5787*7c478bd9Sstevel@tonic-gate local_uname, value, _POSIX_NAME_MAX) == 0) 5788*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_UNAME; 5789*7c478bd9Sstevel@tonic-gate break; 5790*7c478bd9Sstevel@tonic-gate case _X_MTIME: 5791*7c478bd9Sstevel@tonic-gate get_xtime(value, &(Xtarhdr.x_mtime)); 5792*7c478bd9Sstevel@tonic-gate if (errno) 5793*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5794*7c478bd9Sstevel@tonic-gate "tar: Extended header modification time " 5795*7c478bd9Sstevel@tonic-gate "value error for file # %llu.\n"), 5796*7c478bd9Sstevel@tonic-gate xhdr_count); 5797*7c478bd9Sstevel@tonic-gate else 5798*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_MTIME; 5799*7c478bd9Sstevel@tonic-gate break; 5800*7c478bd9Sstevel@tonic-gate default: 5801*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 5802*7c478bd9Sstevel@tonic-gate gettext("tar: unrecognized extended" 5803*7c478bd9Sstevel@tonic-gate " header keyword '%s'. Ignored.\n"), keyword); 5804*7c478bd9Sstevel@tonic-gate break; 5805*7c478bd9Sstevel@tonic-gate } 5806*7c478bd9Sstevel@tonic-gate } 5807*7c478bd9Sstevel@tonic-gate 5808*7c478bd9Sstevel@tonic-gate getdir(); /* get regular header */ 5809*7c478bd9Sstevel@tonic-gate 5810*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMAJOR) { 5811*7c478bd9Sstevel@tonic-gate Gen.g_devmajor = Xtarhdr.x_devmajor; 5812*7c478bd9Sstevel@tonic-gate } 5813*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMINOR) { 5814*7c478bd9Sstevel@tonic-gate Gen.g_devminor = Xtarhdr.x_devminor; 5815*7c478bd9Sstevel@tonic-gate } 5816*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_GID) { 5817*7c478bd9Sstevel@tonic-gate Gen.g_gid = Xtarhdr.x_gid; 5818*7c478bd9Sstevel@tonic-gate sp->st_gid = Gen.g_gid; 5819*7c478bd9Sstevel@tonic-gate } 5820*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_UID) { 5821*7c478bd9Sstevel@tonic-gate Gen.g_uid = Xtarhdr.x_uid; 5822*7c478bd9Sstevel@tonic-gate sp->st_uid = Gen.g_uid; 5823*7c478bd9Sstevel@tonic-gate } 5824*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_SIZE) { 5825*7c478bd9Sstevel@tonic-gate Gen.g_filesz = Xtarhdr.x_filesz; 5826*7c478bd9Sstevel@tonic-gate sp->st_size = Gen.g_filesz; 5827*7c478bd9Sstevel@tonic-gate } 5828*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_MTIME) { 5829*7c478bd9Sstevel@tonic-gate Gen.g_mtime = Xtarhdr.x_mtime.tv_sec; 5830*7c478bd9Sstevel@tonic-gate sp->st_mtim.tv_sec = Gen.g_mtime; 5831*7c478bd9Sstevel@tonic-gate sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec; 5832*7c478bd9Sstevel@tonic-gate } 5833*7c478bd9Sstevel@tonic-gate 5834*7c478bd9Sstevel@tonic-gate if (errors && errflag) 5835*7c478bd9Sstevel@tonic-gate done(1); 5836*7c478bd9Sstevel@tonic-gate else 5837*7c478bd9Sstevel@tonic-gate if (errors) 5838*7c478bd9Sstevel@tonic-gate Errflg = 1; 5839*7c478bd9Sstevel@tonic-gate return (errors); 5840*7c478bd9Sstevel@tonic-gate } 5841*7c478bd9Sstevel@tonic-gate 5842*7c478bd9Sstevel@tonic-gate /* 5843*7c478bd9Sstevel@tonic-gate * gen_num creates a string from a keyword and an usigned long long in the 5844*7c478bd9Sstevel@tonic-gate * format: %d %s=%s\n 5845*7c478bd9Sstevel@tonic-gate * This is part of the extended header data record. 5846*7c478bd9Sstevel@tonic-gate */ 5847*7c478bd9Sstevel@tonic-gate 5848*7c478bd9Sstevel@tonic-gate void 5849*7c478bd9Sstevel@tonic-gate gen_num(const char *keyword, const u_longlong_t number) 5850*7c478bd9Sstevel@tonic-gate { 5851*7c478bd9Sstevel@tonic-gate char save_val[ULONGLONG_MAX_DIGITS + 1]; 5852*7c478bd9Sstevel@tonic-gate int len; 5853*7c478bd9Sstevel@tonic-gate char *curr_ptr; 5854*7c478bd9Sstevel@tonic-gate 5855*7c478bd9Sstevel@tonic-gate (void) sprintf(save_val, "%llu", number); 5856*7c478bd9Sstevel@tonic-gate /* 5857*7c478bd9Sstevel@tonic-gate * len = length of entire line, including itself. len will be 5858*7c478bd9Sstevel@tonic-gate * two digits. So, add the string lengths plus the length of len, 5859*7c478bd9Sstevel@tonic-gate * plus a blank, an equal sign, and a newline. 5860*7c478bd9Sstevel@tonic-gate */ 5861*7c478bd9Sstevel@tonic-gate len = strlen(save_val) + strlen(keyword) + 5; 5862*7c478bd9Sstevel@tonic-gate if (xrec_offset + len > xrec_size) { 5863*7c478bd9Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL)) 5864*7c478bd9Sstevel@tonic-gate fatal(gettext( 5865*7c478bd9Sstevel@tonic-gate "cannot allocate extended header buffer")); 5866*7c478bd9Sstevel@tonic-gate xrec_ptr = curr_ptr; 5867*7c478bd9Sstevel@tonic-gate xrec_size *= 2; 5868*7c478bd9Sstevel@tonic-gate } 5869*7c478bd9Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset], 5870*7c478bd9Sstevel@tonic-gate "%d %s=%s\n", len, keyword, save_val); 5871*7c478bd9Sstevel@tonic-gate xrec_offset += len; 5872*7c478bd9Sstevel@tonic-gate } 5873*7c478bd9Sstevel@tonic-gate 5874*7c478bd9Sstevel@tonic-gate /* 5875*7c478bd9Sstevel@tonic-gate * gen_date creates a string from a keyword and a timestruc_t in the 5876*7c478bd9Sstevel@tonic-gate * format: %d %s=%s\n 5877*7c478bd9Sstevel@tonic-gate * This is part of the extended header data record. 5878*7c478bd9Sstevel@tonic-gate * Currently, granularity is only microseconds, so the low-order three digits 5879*7c478bd9Sstevel@tonic-gate * will be truncated. 5880*7c478bd9Sstevel@tonic-gate */ 5881*7c478bd9Sstevel@tonic-gate 5882*7c478bd9Sstevel@tonic-gate void 5883*7c478bd9Sstevel@tonic-gate gen_date(const char *keyword, const timestruc_t time_value) 5884*7c478bd9Sstevel@tonic-gate { 5885*7c478bd9Sstevel@tonic-gate /* Allow for <seconds>.<nanoseconds>\n */ 5886*7c478bd9Sstevel@tonic-gate char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2]; 5887*7c478bd9Sstevel@tonic-gate int len; 5888*7c478bd9Sstevel@tonic-gate char *curr_ptr; 5889*7c478bd9Sstevel@tonic-gate 5890*7c478bd9Sstevel@tonic-gate (void) sprintf(save_val, "%ld", time_value.tv_sec); 5891*7c478bd9Sstevel@tonic-gate len = strlen(save_val); 5892*7c478bd9Sstevel@tonic-gate save_val[len] = '.'; 5893*7c478bd9Sstevel@tonic-gate (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec); 5894*7c478bd9Sstevel@tonic-gate 5895*7c478bd9Sstevel@tonic-gate /* 5896*7c478bd9Sstevel@tonic-gate * len = length of entire line, including itself. len will be 5897*7c478bd9Sstevel@tonic-gate * two digits. So, add the string lengths plus the length of len, 5898*7c478bd9Sstevel@tonic-gate * plus a blank, an equal sign, and a newline. 5899*7c478bd9Sstevel@tonic-gate */ 5900*7c478bd9Sstevel@tonic-gate len = strlen(save_val) + strlen(keyword) + 5; 5901*7c478bd9Sstevel@tonic-gate if (xrec_offset + len > xrec_size) { 5902*7c478bd9Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL)) 5903*7c478bd9Sstevel@tonic-gate fatal(gettext( 5904*7c478bd9Sstevel@tonic-gate "cannot allocate extended header buffer")); 5905*7c478bd9Sstevel@tonic-gate xrec_ptr = curr_ptr; 5906*7c478bd9Sstevel@tonic-gate xrec_size *= 2; 5907*7c478bd9Sstevel@tonic-gate } 5908*7c478bd9Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset], 5909*7c478bd9Sstevel@tonic-gate "%d %s=%s\n", len, keyword, save_val); 5910*7c478bd9Sstevel@tonic-gate xrec_offset += len; 5911*7c478bd9Sstevel@tonic-gate } 5912*7c478bd9Sstevel@tonic-gate 5913*7c478bd9Sstevel@tonic-gate /* 5914*7c478bd9Sstevel@tonic-gate * gen_string creates a string from a keyword and a char * in the 5915*7c478bd9Sstevel@tonic-gate * format: %d %s=%s\n 5916*7c478bd9Sstevel@tonic-gate * This is part of the extended header data record. 5917*7c478bd9Sstevel@tonic-gate */ 5918*7c478bd9Sstevel@tonic-gate 5919*7c478bd9Sstevel@tonic-gate void 5920*7c478bd9Sstevel@tonic-gate gen_string(const char *keyword, const char *value) 5921*7c478bd9Sstevel@tonic-gate { 5922*7c478bd9Sstevel@tonic-gate int len; 5923*7c478bd9Sstevel@tonic-gate char *curr_ptr; 5924*7c478bd9Sstevel@tonic-gate 5925*7c478bd9Sstevel@tonic-gate /* 5926*7c478bd9Sstevel@tonic-gate * len = length of entire line, including itself. The character length 5927*7c478bd9Sstevel@tonic-gate * of len must be 1-4 characters, because the maximum size of the path 5928*7c478bd9Sstevel@tonic-gate * or the name is PATH_MAX, which is 1024. So, assume 1 character 5929*7c478bd9Sstevel@tonic-gate * for len, one for the space, one for the "=", and one for the newline. 5930*7c478bd9Sstevel@tonic-gate * Then adjust as needed. 5931*7c478bd9Sstevel@tonic-gate */ 5932*7c478bd9Sstevel@tonic-gate /* LINTED constant expression */ 5933*7c478bd9Sstevel@tonic-gate assert(PATH_MAX <= 9996); 5934*7c478bd9Sstevel@tonic-gate len = strlen(value) + strlen(keyword) + 4; 5935*7c478bd9Sstevel@tonic-gate if (len > 997) 5936*7c478bd9Sstevel@tonic-gate len += 3; 5937*7c478bd9Sstevel@tonic-gate else if (len > 98) 5938*7c478bd9Sstevel@tonic-gate len += 2; 5939*7c478bd9Sstevel@tonic-gate else if (len > 9) 5940*7c478bd9Sstevel@tonic-gate len += 1; 5941*7c478bd9Sstevel@tonic-gate if (xrec_offset + len > xrec_size) { 5942*7c478bd9Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL)) 5943*7c478bd9Sstevel@tonic-gate fatal(gettext( 5944*7c478bd9Sstevel@tonic-gate "cannot allocate extended header buffer")); 5945*7c478bd9Sstevel@tonic-gate xrec_ptr = curr_ptr; 5946*7c478bd9Sstevel@tonic-gate xrec_size *= 2; 5947*7c478bd9Sstevel@tonic-gate } 5948*7c478bd9Sstevel@tonic-gate #ifdef XHDR_DEBUG 5949*7c478bd9Sstevel@tonic-gate if (strcmp(keyword+1, "name") != 0) 5950*7c478bd9Sstevel@tonic-gate #endif 5951*7c478bd9Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset], 5952*7c478bd9Sstevel@tonic-gate "%d %s=%s\n", len, keyword, value); 5953*7c478bd9Sstevel@tonic-gate #ifdef XHDR_DEBUG 5954*7c478bd9Sstevel@tonic-gate else { 5955*7c478bd9Sstevel@tonic-gate len += 11; 5956*7c478bd9Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset], 5957*7c478bd9Sstevel@tonic-gate "%d %s=%snametoolong\n", len, keyword, value); 5958*7c478bd9Sstevel@tonic-gate } 5959*7c478bd9Sstevel@tonic-gate #endif 5960*7c478bd9Sstevel@tonic-gate xrec_offset += len; 5961*7c478bd9Sstevel@tonic-gate } 5962*7c478bd9Sstevel@tonic-gate 5963*7c478bd9Sstevel@tonic-gate /* 5964*7c478bd9Sstevel@tonic-gate * Convert time found in the extended header data to seconds and nanoseconds. 5965*7c478bd9Sstevel@tonic-gate */ 5966*7c478bd9Sstevel@tonic-gate 5967*7c478bd9Sstevel@tonic-gate void 5968*7c478bd9Sstevel@tonic-gate get_xtime(char *value, timestruc_t *xtime) 5969*7c478bd9Sstevel@tonic-gate { 5970*7c478bd9Sstevel@tonic-gate char nanosec[10]; 5971*7c478bd9Sstevel@tonic-gate char *period; 5972*7c478bd9Sstevel@tonic-gate int i; 5973*7c478bd9Sstevel@tonic-gate 5974*7c478bd9Sstevel@tonic-gate (void) memset(nanosec, '0', 9); 5975*7c478bd9Sstevel@tonic-gate nanosec[9] = '\0'; 5976*7c478bd9Sstevel@tonic-gate 5977*7c478bd9Sstevel@tonic-gate period = strchr(value, '.'); 5978*7c478bd9Sstevel@tonic-gate if (period != NULL) 5979*7c478bd9Sstevel@tonic-gate period[0] = '\0'; 5980*7c478bd9Sstevel@tonic-gate xtime->tv_sec = strtol(value, NULL, 10); 5981*7c478bd9Sstevel@tonic-gate if (period == NULL) 5982*7c478bd9Sstevel@tonic-gate xtime->tv_nsec = 0; 5983*7c478bd9Sstevel@tonic-gate else { 5984*7c478bd9Sstevel@tonic-gate i = strlen(period +1); 5985*7c478bd9Sstevel@tonic-gate (void) strncpy(nanosec, period + 1, min(i, 9)); 5986*7c478bd9Sstevel@tonic-gate xtime->tv_nsec = strtol(nanosec, NULL, 10); 5987*7c478bd9Sstevel@tonic-gate } 5988*7c478bd9Sstevel@tonic-gate } 5989*7c478bd9Sstevel@tonic-gate 5990*7c478bd9Sstevel@tonic-gate /* 5991*7c478bd9Sstevel@tonic-gate * Check linkpath for length. 5992*7c478bd9Sstevel@tonic-gate * Emit an error message and return 1 if too long. 5993*7c478bd9Sstevel@tonic-gate */ 5994*7c478bd9Sstevel@tonic-gate 5995*7c478bd9Sstevel@tonic-gate int 5996*7c478bd9Sstevel@tonic-gate chk_path_build( 5997*7c478bd9Sstevel@tonic-gate char *name, 5998*7c478bd9Sstevel@tonic-gate char *longname, 5999*7c478bd9Sstevel@tonic-gate char *linkname, 6000*7c478bd9Sstevel@tonic-gate char *prefix, 6001*7c478bd9Sstevel@tonic-gate char type, 6002*7c478bd9Sstevel@tonic-gate int filetype) 6003*7c478bd9Sstevel@tonic-gate { 6004*7c478bd9Sstevel@tonic-gate 6005*7c478bd9Sstevel@tonic-gate if (strlen(linkname) > (size_t)NAMSIZ) { 6006*7c478bd9Sstevel@tonic-gate if (Eflag > 0) { 6007*7c478bd9Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH; 6008*7c478bd9Sstevel@tonic-gate Xtarhdr.x_linkpath = linkname; 6009*7c478bd9Sstevel@tonic-gate } else { 6010*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6011*7c478bd9Sstevel@tonic-gate "tar: %s: linked to %s\n"), longname, linkname); 6012*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6013*7c478bd9Sstevel@tonic-gate "tar: %s: linked name too long\n"), linkname); 6014*7c478bd9Sstevel@tonic-gate if (errflag) 6015*7c478bd9Sstevel@tonic-gate done(1); 6016*7c478bd9Sstevel@tonic-gate else 6017*7c478bd9Sstevel@tonic-gate Errflg = 1; 6018*7c478bd9Sstevel@tonic-gate return (1); 6019*7c478bd9Sstevel@tonic-gate } 6020*7c478bd9Sstevel@tonic-gate } 6021*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) 6022*7c478bd9Sstevel@tonic-gate return (build_dblock(name, tchar, type, 6023*7c478bd9Sstevel@tonic-gate filetype, &stbuf, stbuf.st_dev, 6024*7c478bd9Sstevel@tonic-gate prefix)); 6025*7c478bd9Sstevel@tonic-gate else 6026*7c478bd9Sstevel@tonic-gate return (build_dblock(name, linkname, type, 6027*7c478bd9Sstevel@tonic-gate filetype, &stbuf, stbuf.st_dev, prefix)); 6028*7c478bd9Sstevel@tonic-gate } 6029*7c478bd9Sstevel@tonic-gate 6030*7c478bd9Sstevel@tonic-gate /* 6031*7c478bd9Sstevel@tonic-gate * Convert from UTF-8 to local character set. 6032*7c478bd9Sstevel@tonic-gate */ 6033*7c478bd9Sstevel@tonic-gate 6034*7c478bd9Sstevel@tonic-gate static int 6035*7c478bd9Sstevel@tonic-gate utf8_local( 6036*7c478bd9Sstevel@tonic-gate char *option, 6037*7c478bd9Sstevel@tonic-gate char **Xhdr_ptrptr, 6038*7c478bd9Sstevel@tonic-gate char *target, 6039*7c478bd9Sstevel@tonic-gate const char *source, 6040*7c478bd9Sstevel@tonic-gate int max_val) 6041*7c478bd9Sstevel@tonic-gate { 6042*7c478bd9Sstevel@tonic-gate static iconv_t iconv_cd; 6043*7c478bd9Sstevel@tonic-gate char *nl_target; 6044*7c478bd9Sstevel@tonic-gate const char *iconv_src; 6045*7c478bd9Sstevel@tonic-gate char *iconv_trg; 6046*7c478bd9Sstevel@tonic-gate size_t inlen, 6047*7c478bd9Sstevel@tonic-gate outlen; 6048*7c478bd9Sstevel@tonic-gate 6049*7c478bd9Sstevel@tonic-gate if (charset_type == -1) { /* iconv_open failed in earlier try */ 6050*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6051*7c478bd9Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"), 6052*7c478bd9Sstevel@tonic-gate xhdr_count, source); 6053*7c478bd9Sstevel@tonic-gate return (1); 6054*7c478bd9Sstevel@tonic-gate } else if (charset_type == 0) { /* iconv_open has not yet been done */ 6055*7c478bd9Sstevel@tonic-gate nl_target = nl_langinfo(CODESET); 6056*7c478bd9Sstevel@tonic-gate if (strlen(nl_target) == 0) /* locale using 7-bit codeset */ 6057*7c478bd9Sstevel@tonic-gate nl_target = "646"; 6058*7c478bd9Sstevel@tonic-gate if (strcmp(nl_target, "646") == 0) 6059*7c478bd9Sstevel@tonic-gate charset_type = 1; 6060*7c478bd9Sstevel@tonic-gate else if (strcmp(nl_target, "UTF-8") == 0) 6061*7c478bd9Sstevel@tonic-gate charset_type = 3; 6062*7c478bd9Sstevel@tonic-gate else { 6063*7c478bd9Sstevel@tonic-gate if (strncmp(nl_target, "ISO", 3) == 0) 6064*7c478bd9Sstevel@tonic-gate nl_target += 3; 6065*7c478bd9Sstevel@tonic-gate charset_type = 2; 6066*7c478bd9Sstevel@tonic-gate errno = 0; 6067*7c478bd9Sstevel@tonic-gate if ((iconv_cd = iconv_open(nl_target, "UTF-8")) == 6068*7c478bd9Sstevel@tonic-gate (iconv_t)-1) { 6069*7c478bd9Sstevel@tonic-gate if (errno == EINVAL) 6070*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6071*7c478bd9Sstevel@tonic-gate "tar: conversion routines not " 6072*7c478bd9Sstevel@tonic-gate "available for current locale. ")); 6073*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6074*7c478bd9Sstevel@tonic-gate "file # %llu: (%s) UTF-8 conversion" 6075*7c478bd9Sstevel@tonic-gate " failed.\n"), xhdr_count, source); 6076*7c478bd9Sstevel@tonic-gate charset_type = -1; 6077*7c478bd9Sstevel@tonic-gate return (1); 6078*7c478bd9Sstevel@tonic-gate } 6079*7c478bd9Sstevel@tonic-gate } 6080*7c478bd9Sstevel@tonic-gate } 6081*7c478bd9Sstevel@tonic-gate 6082*7c478bd9Sstevel@tonic-gate /* locale using 7-bit codeset or UTF-8 locale */ 6083*7c478bd9Sstevel@tonic-gate if (charset_type == 1 || charset_type == 3) { 6084*7c478bd9Sstevel@tonic-gate if (strlen(source) > max_val) { 6085*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6086*7c478bd9Sstevel@tonic-gate "tar: file # %llu: Extended header %s too long.\n"), 6087*7c478bd9Sstevel@tonic-gate xhdr_count, option); 6088*7c478bd9Sstevel@tonic-gate return (1); 6089*7c478bd9Sstevel@tonic-gate } 6090*7c478bd9Sstevel@tonic-gate if (charset_type == 3) 6091*7c478bd9Sstevel@tonic-gate (void) strcpy(target, source); 6092*7c478bd9Sstevel@tonic-gate else if (c_utf8(target, source) != 0) { 6093*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6094*7c478bd9Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion" 6095*7c478bd9Sstevel@tonic-gate " failed.\n"), xhdr_count, source); 6096*7c478bd9Sstevel@tonic-gate return (1); 6097*7c478bd9Sstevel@tonic-gate } 6098*7c478bd9Sstevel@tonic-gate *Xhdr_ptrptr = target; 6099*7c478bd9Sstevel@tonic-gate return (0); 6100*7c478bd9Sstevel@tonic-gate } 6101*7c478bd9Sstevel@tonic-gate 6102*7c478bd9Sstevel@tonic-gate iconv_src = source; 6103*7c478bd9Sstevel@tonic-gate iconv_trg = target; 6104*7c478bd9Sstevel@tonic-gate inlen = strlen(source); 6105*7c478bd9Sstevel@tonic-gate outlen = max_val * UTF_8_FACTOR; 6106*7c478bd9Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) == 6107*7c478bd9Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */ 6108*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6109*7c478bd9Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"), 6110*7c478bd9Sstevel@tonic-gate xhdr_count, source); 6111*7c478bd9Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */ 6112*7c478bd9Sstevel@tonic-gate iconv_src = (const char *)NULL; 6113*7c478bd9Sstevel@tonic-gate inlen = 0; 6114*7c478bd9Sstevel@tonic-gate (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen); 6115*7c478bd9Sstevel@tonic-gate return (1); 6116*7c478bd9Sstevel@tonic-gate } 6117*7c478bd9Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */ 6118*7c478bd9Sstevel@tonic-gate iconv_src = (const char *)NULL; 6119*7c478bd9Sstevel@tonic-gate inlen = 0; 6120*7c478bd9Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) == 6121*7c478bd9Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */ 6122*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6123*7c478bd9Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"), 6124*7c478bd9Sstevel@tonic-gate xhdr_count, source); 6125*7c478bd9Sstevel@tonic-gate return (1); 6126*7c478bd9Sstevel@tonic-gate } 6127*7c478bd9Sstevel@tonic-gate 6128*7c478bd9Sstevel@tonic-gate *iconv_trg = '\0'; /* Null-terminate iconv output string */ 6129*7c478bd9Sstevel@tonic-gate if (strlen(target) > max_val) { 6130*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6131*7c478bd9Sstevel@tonic-gate "tar: file # %llu: Extended header %s too long.\n"), 6132*7c478bd9Sstevel@tonic-gate xhdr_count, option); 6133*7c478bd9Sstevel@tonic-gate return (1); 6134*7c478bd9Sstevel@tonic-gate } 6135*7c478bd9Sstevel@tonic-gate *Xhdr_ptrptr = target; 6136*7c478bd9Sstevel@tonic-gate return (0); 6137*7c478bd9Sstevel@tonic-gate } 6138*7c478bd9Sstevel@tonic-gate 6139*7c478bd9Sstevel@tonic-gate /* 6140*7c478bd9Sstevel@tonic-gate * Check gname, uname, path, and linkpath to see if they need to go in an 6141*7c478bd9Sstevel@tonic-gate * extended header. If they are already slated to be in an extended header, 6142*7c478bd9Sstevel@tonic-gate * or if they are not ascii, then they need to be in the extended header. 6143*7c478bd9Sstevel@tonic-gate * Then, convert all extended names to UTF-8. 6144*7c478bd9Sstevel@tonic-gate */ 6145*7c478bd9Sstevel@tonic-gate 6146*7c478bd9Sstevel@tonic-gate int 6147*7c478bd9Sstevel@tonic-gate gen_utf8_names(const char *filename) 6148*7c478bd9Sstevel@tonic-gate { 6149*7c478bd9Sstevel@tonic-gate static iconv_t iconv_cd; 6150*7c478bd9Sstevel@tonic-gate char *nl_target; 6151*7c478bd9Sstevel@tonic-gate char tempbuf[MAXNAM + 1]; 6152*7c478bd9Sstevel@tonic-gate int nbytes, 6153*7c478bd9Sstevel@tonic-gate errors; 6154*7c478bd9Sstevel@tonic-gate 6155*7c478bd9Sstevel@tonic-gate if (charset_type == -1) { /* Previous failure to open. */ 6156*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6157*7c478bd9Sstevel@tonic-gate "tar: file # %llu: UTF-8 conversion failed.\n"), 6158*7c478bd9Sstevel@tonic-gate xhdr_count); 6159*7c478bd9Sstevel@tonic-gate return (1); 6160*7c478bd9Sstevel@tonic-gate } 6161*7c478bd9Sstevel@tonic-gate 6162*7c478bd9Sstevel@tonic-gate if (charset_type == 0) { /* Need to get conversion descriptor */ 6163*7c478bd9Sstevel@tonic-gate nl_target = nl_langinfo(CODESET); 6164*7c478bd9Sstevel@tonic-gate if (strlen(nl_target) == 0) /* locale using 7-bit codeset */ 6165*7c478bd9Sstevel@tonic-gate nl_target = "646"; 6166*7c478bd9Sstevel@tonic-gate if (strcmp(nl_target, "646") == 0) 6167*7c478bd9Sstevel@tonic-gate charset_type = 1; 6168*7c478bd9Sstevel@tonic-gate else if (strcmp(nl_target, "UTF-8") == 0) 6169*7c478bd9Sstevel@tonic-gate charset_type = 3; 6170*7c478bd9Sstevel@tonic-gate else { 6171*7c478bd9Sstevel@tonic-gate if (strncmp(nl_target, "ISO", 3) == 0) 6172*7c478bd9Sstevel@tonic-gate nl_target += 3; 6173*7c478bd9Sstevel@tonic-gate charset_type = 2; 6174*7c478bd9Sstevel@tonic-gate errno = 0; 6175*7c478bd9Sstevel@tonic-gate #ifdef ICONV_DEBUG 6176*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6177*7c478bd9Sstevel@tonic-gate "Opening iconv_cd with target %s\n", 6178*7c478bd9Sstevel@tonic-gate nl_target); 6179*7c478bd9Sstevel@tonic-gate #endif 6180*7c478bd9Sstevel@tonic-gate if ((iconv_cd = iconv_open("UTF-8", nl_target)) == 6181*7c478bd9Sstevel@tonic-gate (iconv_t)-1) { 6182*7c478bd9Sstevel@tonic-gate if (errno == EINVAL) 6183*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6184*7c478bd9Sstevel@tonic-gate "tar: conversion routines not " 6185*7c478bd9Sstevel@tonic-gate "available for current locale. ")); 6186*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6187*7c478bd9Sstevel@tonic-gate "file (%s): UTF-8 conversion failed.\n"), 6188*7c478bd9Sstevel@tonic-gate filename); 6189*7c478bd9Sstevel@tonic-gate charset_type = -1; 6190*7c478bd9Sstevel@tonic-gate return (1); 6191*7c478bd9Sstevel@tonic-gate } 6192*7c478bd9Sstevel@tonic-gate } 6193*7c478bd9Sstevel@tonic-gate } 6194*7c478bd9Sstevel@tonic-gate 6195*7c478bd9Sstevel@tonic-gate errors = 0; 6196*7c478bd9Sstevel@tonic-gate 6197*7c478bd9Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_gname, local_gname, 6198*7c478bd9Sstevel@tonic-gate dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX); 6199*7c478bd9Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_uname, local_uname, 6200*7c478bd9Sstevel@tonic-gate dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX); 6201*7c478bd9Sstevel@tonic-gate if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */ 6202*7c478bd9Sstevel@tonic-gate (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ); 6203*7c478bd9Sstevel@tonic-gate tempbuf[NAMSIZ] = '\0'; 6204*7c478bd9Sstevel@tonic-gate } 6205*7c478bd9Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath, 6206*7c478bd9Sstevel@tonic-gate tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX); 6207*7c478bd9Sstevel@tonic-gate if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */ 6208*7c478bd9Sstevel@tonic-gate (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ); 6209*7c478bd9Sstevel@tonic-gate tempbuf[NAMSIZ] = '\0'; 6210*7c478bd9Sstevel@tonic-gate nbytes = strlen(tempbuf); 6211*7c478bd9Sstevel@tonic-gate if (nbytes > 0) { 6212*7c478bd9Sstevel@tonic-gate tempbuf[nbytes++] = '/'; 6213*7c478bd9Sstevel@tonic-gate tempbuf[nbytes] = '\0'; 6214*7c478bd9Sstevel@tonic-gate } 6215*7c478bd9Sstevel@tonic-gate (void) strncat(tempbuf + nbytes, dblock.dbuf.name, NAMSIZ); 6216*7c478bd9Sstevel@tonic-gate tempbuf[nbytes + NAMSIZ] = '\0'; 6217*7c478bd9Sstevel@tonic-gate } 6218*7c478bd9Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_path, local_path, 6219*7c478bd9Sstevel@tonic-gate tempbuf, iconv_cd, _X_PATH, PATH_MAX); 6220*7c478bd9Sstevel@tonic-gate 6221*7c478bd9Sstevel@tonic-gate if (errors > 0) 6222*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6223*7c478bd9Sstevel@tonic-gate "tar: file (%s): UTF-8 conversion failed.\n"), filename); 6224*7c478bd9Sstevel@tonic-gate 6225*7c478bd9Sstevel@tonic-gate if (errors && errflag) 6226*7c478bd9Sstevel@tonic-gate done(1); 6227*7c478bd9Sstevel@tonic-gate else 6228*7c478bd9Sstevel@tonic-gate if (errors) 6229*7c478bd9Sstevel@tonic-gate Errflg = 1; 6230*7c478bd9Sstevel@tonic-gate return (errors); 6231*7c478bd9Sstevel@tonic-gate } 6232*7c478bd9Sstevel@tonic-gate 6233*7c478bd9Sstevel@tonic-gate static int 6234*7c478bd9Sstevel@tonic-gate local_utf8( 6235*7c478bd9Sstevel@tonic-gate char **Xhdr_ptrptr, 6236*7c478bd9Sstevel@tonic-gate char *target, 6237*7c478bd9Sstevel@tonic-gate const char *source, 6238*7c478bd9Sstevel@tonic-gate iconv_t iconv_cd, 6239*7c478bd9Sstevel@tonic-gate int xhdrflg, 6240*7c478bd9Sstevel@tonic-gate int max_val) 6241*7c478bd9Sstevel@tonic-gate { 6242*7c478bd9Sstevel@tonic-gate const char *iconv_src; 6243*7c478bd9Sstevel@tonic-gate const char *starting_src; 6244*7c478bd9Sstevel@tonic-gate char *iconv_trg; 6245*7c478bd9Sstevel@tonic-gate size_t inlen, 6246*7c478bd9Sstevel@tonic-gate outlen; 6247*7c478bd9Sstevel@tonic-gate #ifdef ICONV_DEBUG 6248*7c478bd9Sstevel@tonic-gate unsigned char c_to_hex; 6249*7c478bd9Sstevel@tonic-gate #endif 6250*7c478bd9Sstevel@tonic-gate 6251*7c478bd9Sstevel@tonic-gate /* 6252*7c478bd9Sstevel@tonic-gate * If the item is already slated for extended format, get the string 6253*7c478bd9Sstevel@tonic-gate * to convert from the extended header record. Otherwise, get it from 6254*7c478bd9Sstevel@tonic-gate * the regular (dblock) area. 6255*7c478bd9Sstevel@tonic-gate */ 6256*7c478bd9Sstevel@tonic-gate if (xhdr_flgs & xhdrflg) { 6257*7c478bd9Sstevel@tonic-gate if (charset_type == 3) { /* Already UTF-8, just copy */ 6258*7c478bd9Sstevel@tonic-gate (void) strcpy(target, *Xhdr_ptrptr); 6259*7c478bd9Sstevel@tonic-gate *Xhdr_ptrptr = target; 6260*7c478bd9Sstevel@tonic-gate return (0); 6261*7c478bd9Sstevel@tonic-gate } else 6262*7c478bd9Sstevel@tonic-gate iconv_src = (const char *) *Xhdr_ptrptr; 6263*7c478bd9Sstevel@tonic-gate } else { 6264*7c478bd9Sstevel@tonic-gate if (charset_type == 3) /* Already in UTF-8 format */ 6265*7c478bd9Sstevel@tonic-gate return (0); /* Don't create xhdr record */ 6266*7c478bd9Sstevel@tonic-gate iconv_src = source; 6267*7c478bd9Sstevel@tonic-gate } 6268*7c478bd9Sstevel@tonic-gate starting_src = iconv_src; 6269*7c478bd9Sstevel@tonic-gate iconv_trg = target; 6270*7c478bd9Sstevel@tonic-gate if ((inlen = strlen(iconv_src)) == 0) 6271*7c478bd9Sstevel@tonic-gate return (0); 6272*7c478bd9Sstevel@tonic-gate 6273*7c478bd9Sstevel@tonic-gate if (charset_type == 1) { /* locale using 7-bit codeset */ 6274*7c478bd9Sstevel@tonic-gate if (c_utf8(target, starting_src) != 0) { 6275*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6276*7c478bd9Sstevel@tonic-gate gettext("tar: invalid character in" 6277*7c478bd9Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src); 6278*7c478bd9Sstevel@tonic-gate return (1); 6279*7c478bd9Sstevel@tonic-gate } 6280*7c478bd9Sstevel@tonic-gate return (0); 6281*7c478bd9Sstevel@tonic-gate } 6282*7c478bd9Sstevel@tonic-gate 6283*7c478bd9Sstevel@tonic-gate outlen = max_val * UTF_8_FACTOR; 6284*7c478bd9Sstevel@tonic-gate errno = 0; 6285*7c478bd9Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) == 6286*7c478bd9Sstevel@tonic-gate (size_t)-1) { 6287*7c478bd9Sstevel@tonic-gate /* An error occurred, or not all characters were converted */ 6288*7c478bd9Sstevel@tonic-gate if (errno == EILSEQ) 6289*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6290*7c478bd9Sstevel@tonic-gate gettext("tar: invalid character in" 6291*7c478bd9Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src); 6292*7c478bd9Sstevel@tonic-gate else 6293*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6294*7c478bd9Sstevel@tonic-gate "tar: conversion to UTF-8 aborted for '%s'.\n"), 6295*7c478bd9Sstevel@tonic-gate starting_src); 6296*7c478bd9Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */ 6297*7c478bd9Sstevel@tonic-gate iconv_src = (const char *)NULL; 6298*7c478bd9Sstevel@tonic-gate inlen = 0; 6299*7c478bd9Sstevel@tonic-gate (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen); 6300*7c478bd9Sstevel@tonic-gate return (1); 6301*7c478bd9Sstevel@tonic-gate } 6302*7c478bd9Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */ 6303*7c478bd9Sstevel@tonic-gate iconv_src = (const char *)NULL; 6304*7c478bd9Sstevel@tonic-gate inlen = 0; 6305*7c478bd9Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) == 6306*7c478bd9Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */ 6307*7c478bd9Sstevel@tonic-gate if (errno == EILSEQ) 6308*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6309*7c478bd9Sstevel@tonic-gate gettext("tar: invalid character in" 6310*7c478bd9Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src); 6311*7c478bd9Sstevel@tonic-gate else 6312*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6313*7c478bd9Sstevel@tonic-gate "tar: conversion to UTF-8 aborted for '%s'.\n"), 6314*7c478bd9Sstevel@tonic-gate starting_src); 6315*7c478bd9Sstevel@tonic-gate return (1); 6316*7c478bd9Sstevel@tonic-gate } 6317*7c478bd9Sstevel@tonic-gate 6318*7c478bd9Sstevel@tonic-gate *iconv_trg = '\0'; /* Null-terminate iconv output string */ 6319*7c478bd9Sstevel@tonic-gate if (strcmp(starting_src, target) != 0) { 6320*7c478bd9Sstevel@tonic-gate *Xhdr_ptrptr = target; 6321*7c478bd9Sstevel@tonic-gate xhdr_flgs |= xhdrflg; 6322*7c478bd9Sstevel@tonic-gate #ifdef ICONV_DEBUG 6323*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n", 6324*7c478bd9Sstevel@tonic-gate strlen(starting_src), inlen, max_val, outlen); 6325*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Input string:\n "); 6326*7c478bd9Sstevel@tonic-gate for (inlen = 0; inlen < strlen(starting_src); inlen++) { 6327*7c478bd9Sstevel@tonic-gate c_to_hex = (unsigned char)starting_src[inlen]; 6328*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " %2.2x", c_to_hex); 6329*7c478bd9Sstevel@tonic-gate if (inlen % 20 == 19) 6330*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n "); 6331*7c478bd9Sstevel@tonic-gate } 6332*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\nOutput string:\n "); 6333*7c478bd9Sstevel@tonic-gate for (inlen = 0; inlen < strlen(target); inlen++) { 6334*7c478bd9Sstevel@tonic-gate c_to_hex = (unsigned char)target[inlen]; 6335*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " %2.2x", c_to_hex); 6336*7c478bd9Sstevel@tonic-gate if (inlen % 20 == 19) 6337*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n "); 6338*7c478bd9Sstevel@tonic-gate } 6339*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 6340*7c478bd9Sstevel@tonic-gate #endif 6341*7c478bd9Sstevel@tonic-gate } 6342*7c478bd9Sstevel@tonic-gate 6343*7c478bd9Sstevel@tonic-gate return (0); 6344*7c478bd9Sstevel@tonic-gate } 6345*7c478bd9Sstevel@tonic-gate 6346*7c478bd9Sstevel@tonic-gate /* 6347*7c478bd9Sstevel@tonic-gate * Function to test each byte of the source string to make sure it is 6348*7c478bd9Sstevel@tonic-gate * in within bounds (value between 0 and 127). 6349*7c478bd9Sstevel@tonic-gate * If valid, copy source to target. 6350*7c478bd9Sstevel@tonic-gate */ 6351*7c478bd9Sstevel@tonic-gate 6352*7c478bd9Sstevel@tonic-gate int 6353*7c478bd9Sstevel@tonic-gate c_utf8(char *target, const char *source) 6354*7c478bd9Sstevel@tonic-gate { 6355*7c478bd9Sstevel@tonic-gate size_t len; 6356*7c478bd9Sstevel@tonic-gate const char *thischar; 6357*7c478bd9Sstevel@tonic-gate 6358*7c478bd9Sstevel@tonic-gate len = strlen(source); 6359*7c478bd9Sstevel@tonic-gate thischar = source; 6360*7c478bd9Sstevel@tonic-gate while (len-- > 0) { 6361*7c478bd9Sstevel@tonic-gate if (!isascii((int)(*thischar++))) 6362*7c478bd9Sstevel@tonic-gate return (1); 6363*7c478bd9Sstevel@tonic-gate } 6364*7c478bd9Sstevel@tonic-gate 6365*7c478bd9Sstevel@tonic-gate (void) strcpy(target, source); 6366*7c478bd9Sstevel@tonic-gate return (0); 6367*7c478bd9Sstevel@tonic-gate } 6368*7c478bd9Sstevel@tonic-gate 6369*7c478bd9Sstevel@tonic-gate 6370*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 6371*7c478bd9Sstevel@tonic-gate #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1)) 6372*7c478bd9Sstevel@tonic-gate 6373*7c478bd9Sstevel@tonic-gate static void 6374*7c478bd9Sstevel@tonic-gate prepare_xattr( 6375*7c478bd9Sstevel@tonic-gate char **attrbuf, 6376*7c478bd9Sstevel@tonic-gate char *filename, 6377*7c478bd9Sstevel@tonic-gate char *attrname, 6378*7c478bd9Sstevel@tonic-gate char typeflag, 6379*7c478bd9Sstevel@tonic-gate struct linkbuf *linkinfo, 6380*7c478bd9Sstevel@tonic-gate int *rlen) 6381*7c478bd9Sstevel@tonic-gate { 6382*7c478bd9Sstevel@tonic-gate char *bufhead; /* ptr to full buffer */ 6383*7c478bd9Sstevel@tonic-gate struct xattr_hdr *hptr; /* ptr to header in bufhead */ 6384*7c478bd9Sstevel@tonic-gate struct xattr_buf *tptr; /* ptr to pathing pieces */ 6385*7c478bd9Sstevel@tonic-gate int totalen; /* total buffer length */ 6386*7c478bd9Sstevel@tonic-gate int len; /* length returned to user */ 6387*7c478bd9Sstevel@tonic-gate int stringlen; /* length of filename + attr */ 6388*7c478bd9Sstevel@tonic-gate /* 6389*7c478bd9Sstevel@tonic-gate * length of filename + attr 6390*7c478bd9Sstevel@tonic-gate * in link section 6391*7c478bd9Sstevel@tonic-gate */ 6392*7c478bd9Sstevel@tonic-gate int linkstringlen; 6393*7c478bd9Sstevel@tonic-gate int complen; /* length of pathing section */ 6394*7c478bd9Sstevel@tonic-gate int linklen; /* length of link section */ 6395*7c478bd9Sstevel@tonic-gate 6396*7c478bd9Sstevel@tonic-gate /* 6397*7c478bd9Sstevel@tonic-gate * Release previous buffer 6398*7c478bd9Sstevel@tonic-gate */ 6399*7c478bd9Sstevel@tonic-gate 6400*7c478bd9Sstevel@tonic-gate if (*attrbuf != (char *)NULL) { 6401*7c478bd9Sstevel@tonic-gate free(*attrbuf); 6402*7c478bd9Sstevel@tonic-gate *attrbuf = NULL; 6403*7c478bd9Sstevel@tonic-gate } 6404*7c478bd9Sstevel@tonic-gate 6405*7c478bd9Sstevel@tonic-gate /* 6406*7c478bd9Sstevel@tonic-gate * First add in fixed size stuff 6407*7c478bd9Sstevel@tonic-gate */ 6408*7c478bd9Sstevel@tonic-gate len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf); 6409*7c478bd9Sstevel@tonic-gate 6410*7c478bd9Sstevel@tonic-gate /* 6411*7c478bd9Sstevel@tonic-gate * Add space for two nulls 6412*7c478bd9Sstevel@tonic-gate */ 6413*7c478bd9Sstevel@tonic-gate stringlen = strlen(attrname) + strlen(filename) + 2; 6414*7c478bd9Sstevel@tonic-gate complen = stringlen + sizeof (struct xattr_buf); 6415*7c478bd9Sstevel@tonic-gate 6416*7c478bd9Sstevel@tonic-gate len += stringlen; 6417*7c478bd9Sstevel@tonic-gate 6418*7c478bd9Sstevel@tonic-gate /* 6419*7c478bd9Sstevel@tonic-gate * Now add on space for link info if any 6420*7c478bd9Sstevel@tonic-gate */ 6421*7c478bd9Sstevel@tonic-gate 6422*7c478bd9Sstevel@tonic-gate if (linkinfo != NULL) { 6423*7c478bd9Sstevel@tonic-gate /* 6424*7c478bd9Sstevel@tonic-gate * Again add space for two nulls 6425*7c478bd9Sstevel@tonic-gate */ 6426*7c478bd9Sstevel@tonic-gate linkstringlen = strlen(linkinfo->pathname) + 6427*7c478bd9Sstevel@tonic-gate strlen(linkinfo->attrname) + 2; 6428*7c478bd9Sstevel@tonic-gate len += linkstringlen; 6429*7c478bd9Sstevel@tonic-gate } 6430*7c478bd9Sstevel@tonic-gate 6431*7c478bd9Sstevel@tonic-gate /* 6432*7c478bd9Sstevel@tonic-gate * Now add padding to end to fill out TBLOCK 6433*7c478bd9Sstevel@tonic-gate * 6434*7c478bd9Sstevel@tonic-gate * Function returns size of real data and not size + padding. 6435*7c478bd9Sstevel@tonic-gate */ 6436*7c478bd9Sstevel@tonic-gate 6437*7c478bd9Sstevel@tonic-gate totalen = ROUNDTOTBLOCK(len); 6438*7c478bd9Sstevel@tonic-gate 6439*7c478bd9Sstevel@tonic-gate if ((bufhead = calloc(1, totalen)) == NULL) { 6440*7c478bd9Sstevel@tonic-gate fatal(gettext("Out of memory.")); 6441*7c478bd9Sstevel@tonic-gate } 6442*7c478bd9Sstevel@tonic-gate 6443*7c478bd9Sstevel@tonic-gate 6444*7c478bd9Sstevel@tonic-gate /* 6445*7c478bd9Sstevel@tonic-gate * Now we can fill in the necessary pieces 6446*7c478bd9Sstevel@tonic-gate */ 6447*7c478bd9Sstevel@tonic-gate 6448*7c478bd9Sstevel@tonic-gate if (linkinfo != (struct linkbuf *)NULL) { 6449*7c478bd9Sstevel@tonic-gate linklen = linkstringlen + (sizeof (struct xattr_buf)); 6450*7c478bd9Sstevel@tonic-gate } else { 6451*7c478bd9Sstevel@tonic-gate linklen = 0; 6452*7c478bd9Sstevel@tonic-gate } 6453*7c478bd9Sstevel@tonic-gate 6454*7c478bd9Sstevel@tonic-gate /* 6455*7c478bd9Sstevel@tonic-gate * first fill in the fixed header 6456*7c478bd9Sstevel@tonic-gate */ 6457*7c478bd9Sstevel@tonic-gate hptr = (struct xattr_hdr *)bufhead; 6458*7c478bd9Sstevel@tonic-gate (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS); 6459*7c478bd9Sstevel@tonic-gate (void) sprintf(hptr->h_component_len, "%0*d", 6460*7c478bd9Sstevel@tonic-gate sizeof (hptr->h_component_len) - 1, complen); 6461*7c478bd9Sstevel@tonic-gate (void) sprintf(hptr->h_link_component_len, "%0*d", 6462*7c478bd9Sstevel@tonic-gate sizeof (hptr->h_link_component_len) - 1, linklen); 6463*7c478bd9Sstevel@tonic-gate (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len); 6464*7c478bd9Sstevel@tonic-gate 6465*7c478bd9Sstevel@tonic-gate /* 6466*7c478bd9Sstevel@tonic-gate * Now fill in the filename + attrnames section 6467*7c478bd9Sstevel@tonic-gate */ 6468*7c478bd9Sstevel@tonic-gate 6469*7c478bd9Sstevel@tonic-gate tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr)); 6470*7c478bd9Sstevel@tonic-gate (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1, 6471*7c478bd9Sstevel@tonic-gate stringlen); 6472*7c478bd9Sstevel@tonic-gate (void) strcpy(tptr->h_names, filename); 6473*7c478bd9Sstevel@tonic-gate (void) strcpy(&tptr->h_names[strlen(filename) + 1], attrname); 6474*7c478bd9Sstevel@tonic-gate tptr->h_typeflag = typeflag; 6475*7c478bd9Sstevel@tonic-gate 6476*7c478bd9Sstevel@tonic-gate /* 6477*7c478bd9Sstevel@tonic-gate * Now fill in the optional link section if we have one 6478*7c478bd9Sstevel@tonic-gate */ 6479*7c478bd9Sstevel@tonic-gate 6480*7c478bd9Sstevel@tonic-gate if (linkinfo != (struct linkbuf *)NULL) { 6481*7c478bd9Sstevel@tonic-gate tptr = (struct xattr_buf *)(bufhead + 6482*7c478bd9Sstevel@tonic-gate sizeof (struct xattr_hdr) + complen); 6483*7c478bd9Sstevel@tonic-gate 6484*7c478bd9Sstevel@tonic-gate (void) sprintf(tptr->h_namesz, "%0*d", 6485*7c478bd9Sstevel@tonic-gate sizeof (tptr->h_namesz) - 1, linkstringlen); 6486*7c478bd9Sstevel@tonic-gate (void) strcpy(tptr->h_names, linkinfo->pathname); 6487*7c478bd9Sstevel@tonic-gate (void) strcpy( 6488*7c478bd9Sstevel@tonic-gate &tptr->h_names[strlen(linkinfo->pathname) + 1], 6489*7c478bd9Sstevel@tonic-gate linkinfo->attrname); 6490*7c478bd9Sstevel@tonic-gate tptr->h_typeflag = typeflag; 6491*7c478bd9Sstevel@tonic-gate } 6492*7c478bd9Sstevel@tonic-gate *attrbuf = (char *)bufhead; 6493*7c478bd9Sstevel@tonic-gate *rlen = len; 6494*7c478bd9Sstevel@tonic-gate } 6495*7c478bd9Sstevel@tonic-gate 6496*7c478bd9Sstevel@tonic-gate #else 6497*7c478bd9Sstevel@tonic-gate static void 6498*7c478bd9Sstevel@tonic-gate prepare_xattr( 6499*7c478bd9Sstevel@tonic-gate char **attrbuf, 6500*7c478bd9Sstevel@tonic-gate char *filename, 6501*7c478bd9Sstevel@tonic-gate char *attrname, 6502*7c478bd9Sstevel@tonic-gate char typeflag, 6503*7c478bd9Sstevel@tonic-gate struct linkbuf *linkinfo, 6504*7c478bd9Sstevel@tonic-gate int *rlen) 6505*7c478bd9Sstevel@tonic-gate { 6506*7c478bd9Sstevel@tonic-gate *attrbuf = NULL; 6507*7c478bd9Sstevel@tonic-gate *rlen = 0; 6508*7c478bd9Sstevel@tonic-gate } 6509*7c478bd9Sstevel@tonic-gate #endif 6510*7c478bd9Sstevel@tonic-gate 6511*7c478bd9Sstevel@tonic-gate int 6512*7c478bd9Sstevel@tonic-gate getstat(int dirfd, char *longname, char *shortname) 6513*7c478bd9Sstevel@tonic-gate { 6514*7c478bd9Sstevel@tonic-gate 6515*7c478bd9Sstevel@tonic-gate int i, j; 6516*7c478bd9Sstevel@tonic-gate int printerr; 6517*7c478bd9Sstevel@tonic-gate int slnkerr; 6518*7c478bd9Sstevel@tonic-gate struct stat symlnbuf; 6519*7c478bd9Sstevel@tonic-gate 6520*7c478bd9Sstevel@tonic-gate if (!hflag) 6521*7c478bd9Sstevel@tonic-gate i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW); 6522*7c478bd9Sstevel@tonic-gate else 6523*7c478bd9Sstevel@tonic-gate i = fstatat(dirfd, shortname, &stbuf, 0); 6524*7c478bd9Sstevel@tonic-gate 6525*7c478bd9Sstevel@tonic-gate 6526*7c478bd9Sstevel@tonic-gate if (i < 0) { 6527*7c478bd9Sstevel@tonic-gate /* Initialize flag to print error mesg. */ 6528*7c478bd9Sstevel@tonic-gate printerr = 1; 6529*7c478bd9Sstevel@tonic-gate /* 6530*7c478bd9Sstevel@tonic-gate * If stat is done, then need to do lstat 6531*7c478bd9Sstevel@tonic-gate * to determine whether it's a sym link 6532*7c478bd9Sstevel@tonic-gate */ 6533*7c478bd9Sstevel@tonic-gate if (hflag) { 6534*7c478bd9Sstevel@tonic-gate /* Save returned error */ 6535*7c478bd9Sstevel@tonic-gate slnkerr = errno; 6536*7c478bd9Sstevel@tonic-gate 6537*7c478bd9Sstevel@tonic-gate j = fstatat(dirfd, shortname, 6538*7c478bd9Sstevel@tonic-gate &symlnbuf, AT_SYMLINK_NOFOLLOW); 6539*7c478bd9Sstevel@tonic-gate /* 6540*7c478bd9Sstevel@tonic-gate * Suppress error message when file is a symbolic link 6541*7c478bd9Sstevel@tonic-gate * and function modifier 'l' is off. Exception: when 6542*7c478bd9Sstevel@tonic-gate * a symlink points to a symlink points to a 6543*7c478bd9Sstevel@tonic-gate * symlink ... and we get past MAXSYMLINKS. That 6544*7c478bd9Sstevel@tonic-gate * error will cause a file not to be archived, and 6545*7c478bd9Sstevel@tonic-gate * needs to be printed. 6546*7c478bd9Sstevel@tonic-gate */ 6547*7c478bd9Sstevel@tonic-gate if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) && 6548*7c478bd9Sstevel@tonic-gate (S_ISLNK(symlnbuf.st_mode))) 6549*7c478bd9Sstevel@tonic-gate printerr = 0; 6550*7c478bd9Sstevel@tonic-gate 6551*7c478bd9Sstevel@tonic-gate /* 6552*7c478bd9Sstevel@tonic-gate * Restore errno in case the lstat 6553*7c478bd9Sstevel@tonic-gate * on symbolic link change 6554*7c478bd9Sstevel@tonic-gate */ 6555*7c478bd9Sstevel@tonic-gate errno = slnkerr; 6556*7c478bd9Sstevel@tonic-gate } 6557*7c478bd9Sstevel@tonic-gate 6558*7c478bd9Sstevel@tonic-gate if (printerr) { 6559*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6560*7c478bd9Sstevel@tonic-gate "tar: %s: %s\n"), longname, strerror(errno)); 6561*7c478bd9Sstevel@tonic-gate Errflg = 1; 6562*7c478bd9Sstevel@tonic-gate } 6563*7c478bd9Sstevel@tonic-gate return (1); 6564*7c478bd9Sstevel@tonic-gate } 6565*7c478bd9Sstevel@tonic-gate return (0); 6566*7c478bd9Sstevel@tonic-gate } 6567*7c478bd9Sstevel@tonic-gate 6568*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 6569*7c478bd9Sstevel@tonic-gate static void 6570*7c478bd9Sstevel@tonic-gate xattrs_put(char *longname, char *shortname, char *parent) 6571*7c478bd9Sstevel@tonic-gate { 6572*7c478bd9Sstevel@tonic-gate int dirfd; 6573*7c478bd9Sstevel@tonic-gate DIR *dirp; 6574*7c478bd9Sstevel@tonic-gate struct dirent *dp; 6575*7c478bd9Sstevel@tonic-gate 6576*7c478bd9Sstevel@tonic-gate if (pathconf(shortname, _PC_XATTR_EXISTS) != 1) { 6577*7c478bd9Sstevel@tonic-gate return; 6578*7c478bd9Sstevel@tonic-gate } 6579*7c478bd9Sstevel@tonic-gate 6580*7c478bd9Sstevel@tonic-gate if ((dirfd = attropen(shortname, ".", O_RDONLY)) < 0) { 6581*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6582*7c478bd9Sstevel@tonic-gate "tar: unable to open attribute directory for file %s\n"), 6583*7c478bd9Sstevel@tonic-gate longname); 6584*7c478bd9Sstevel@tonic-gate return; 6585*7c478bd9Sstevel@tonic-gate } 6586*7c478bd9Sstevel@tonic-gate 6587*7c478bd9Sstevel@tonic-gate if ((dirp = fdopendir(dirfd)) == NULL) { 6588*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6589*7c478bd9Sstevel@tonic-gate "tar: unable to open dir pointer for file %s\n"), longname); 6590*7c478bd9Sstevel@tonic-gate return; 6591*7c478bd9Sstevel@tonic-gate } 6592*7c478bd9Sstevel@tonic-gate 6593*7c478bd9Sstevel@tonic-gate while (dp = readdir(dirp)) { 6594*7c478bd9Sstevel@tonic-gate if (dp->d_name[0] == '.' && dp->d_name[1] == '.' && 6595*7c478bd9Sstevel@tonic-gate dp->d_name[2] == '\0') 6596*7c478bd9Sstevel@tonic-gate continue; 6597*7c478bd9Sstevel@tonic-gate 6598*7c478bd9Sstevel@tonic-gate if (dp->d_name[0] == '.' && dp->d_name[1] == '\0') 6599*7c478bd9Sstevel@tonic-gate Hiddendir = 1; 6600*7c478bd9Sstevel@tonic-gate else 6601*7c478bd9Sstevel@tonic-gate Hiddendir = 0; 6602*7c478bd9Sstevel@tonic-gate 6603*7c478bd9Sstevel@tonic-gate (void) putfile(longname, dp->d_name, parent, 6604*7c478bd9Sstevel@tonic-gate XATTR_FILE, LEV0, SYMLINK_LEV0); 6605*7c478bd9Sstevel@tonic-gate 6606*7c478bd9Sstevel@tonic-gate if (exitflag) 6607*7c478bd9Sstevel@tonic-gate break; 6608*7c478bd9Sstevel@tonic-gate } 6609*7c478bd9Sstevel@tonic-gate 6610*7c478bd9Sstevel@tonic-gate (void) closedir(dirp); 6611*7c478bd9Sstevel@tonic-gate } 6612*7c478bd9Sstevel@tonic-gate #else 6613*7c478bd9Sstevel@tonic-gate static void 6614*7c478bd9Sstevel@tonic-gate xattrs_put(char *longname, char *shortname, char *parent) 6615*7c478bd9Sstevel@tonic-gate { 6616*7c478bd9Sstevel@tonic-gate } 6617*7c478bd9Sstevel@tonic-gate #endif /* O_XATTR */ 6618*7c478bd9Sstevel@tonic-gate 6619*7c478bd9Sstevel@tonic-gate static int 6620*7c478bd9Sstevel@tonic-gate put_link(char *name, char *longname, char *component, 6621*7c478bd9Sstevel@tonic-gate char *prefix, int filetype, char type) 6622*7c478bd9Sstevel@tonic-gate { 6623*7c478bd9Sstevel@tonic-gate 6624*7c478bd9Sstevel@tonic-gate if (stbuf.st_nlink > 1) { 6625*7c478bd9Sstevel@tonic-gate struct linkbuf *lp; 6626*7c478bd9Sstevel@tonic-gate int found = 0; 6627*7c478bd9Sstevel@tonic-gate 6628*7c478bd9Sstevel@tonic-gate for (lp = ihead; lp != NULL; lp = lp->nextp) 6629*7c478bd9Sstevel@tonic-gate if (lp->inum == stbuf.st_ino && 6630*7c478bd9Sstevel@tonic-gate lp->devnum == stbuf.st_dev) { 6631*7c478bd9Sstevel@tonic-gate found++; 6632*7c478bd9Sstevel@tonic-gate break; 6633*7c478bd9Sstevel@tonic-gate } 6634*7c478bd9Sstevel@tonic-gate if (found) { 6635*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 6636*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) 6637*7c478bd9Sstevel@tonic-gate if (put_xattr_hdr(longname, component, prefix, 6638*7c478bd9Sstevel@tonic-gate type, filetype, lp)) { 6639*7c478bd9Sstevel@tonic-gate goto out; 6640*7c478bd9Sstevel@tonic-gate } 6641*7c478bd9Sstevel@tonic-gate #endif 6642*7c478bd9Sstevel@tonic-gate stbuf.st_size = (off_t)0; 6643*7c478bd9Sstevel@tonic-gate if (filetype != XATTR_FILE) { 6644*7c478bd9Sstevel@tonic-gate tomodes(&stbuf); 6645*7c478bd9Sstevel@tonic-gate if (chk_path_build(name, longname, lp->pathname, 6646*7c478bd9Sstevel@tonic-gate prefix, type, filetype) > 0) { 6647*7c478bd9Sstevel@tonic-gate goto out; 6648*7c478bd9Sstevel@tonic-gate } 6649*7c478bd9Sstevel@tonic-gate } 6650*7c478bd9Sstevel@tonic-gate 6651*7c478bd9Sstevel@tonic-gate if (mulvol && tapepos + 1 >= blocklim) 6652*7c478bd9Sstevel@tonic-gate newvol(); 6653*7c478bd9Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 6654*7c478bd9Sstevel@tonic-gate /* 6655*7c478bd9Sstevel@tonic-gate * write_ancillary() is not needed here. 6656*7c478bd9Sstevel@tonic-gate * The first link is handled in the following 6657*7c478bd9Sstevel@tonic-gate * else statement. No need to process ACLs 6658*7c478bd9Sstevel@tonic-gate * for other hard links since they are the 6659*7c478bd9Sstevel@tonic-gate * same file. 6660*7c478bd9Sstevel@tonic-gate */ 6661*7c478bd9Sstevel@tonic-gate 6662*7c478bd9Sstevel@tonic-gate if (vflag) { 6663*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 6664*7c478bd9Sstevel@tonic-gate if (NotTape) 6665*7c478bd9Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t 6666*7c478bd9Sstevel@tonic-gate "K\t", K(tapepos), 0); 6667*7c478bd9Sstevel@tonic-gate #endif 6668*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) { 6669*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 6670*7c478bd9Sstevel@tonic-gate "a %s attribute %s link to " 6671*7c478bd9Sstevel@tonic-gate "attribute %s\n"), 6672*7c478bd9Sstevel@tonic-gate name, component, lp->attrname); 6673*7c478bd9Sstevel@tonic-gate } else { 6674*7c478bd9Sstevel@tonic-gate (void) fprintf(vfile, gettext( 6675*7c478bd9Sstevel@tonic-gate "a %s link to %s\n"), 6676*7c478bd9Sstevel@tonic-gate longname, lp->pathname); 6677*7c478bd9Sstevel@tonic-gate } 6678*7c478bd9Sstevel@tonic-gate } 6679*7c478bd9Sstevel@tonic-gate lp->count--; 6680*7c478bd9Sstevel@tonic-gate return (0); 6681*7c478bd9Sstevel@tonic-gate } else { 6682*7c478bd9Sstevel@tonic-gate lp = (struct linkbuf *)getmem(sizeof (*lp)); 6683*7c478bd9Sstevel@tonic-gate if (lp != (struct linkbuf *)NULL) { 6684*7c478bd9Sstevel@tonic-gate lp->nextp = ihead; 6685*7c478bd9Sstevel@tonic-gate ihead = lp; 6686*7c478bd9Sstevel@tonic-gate lp->inum = stbuf.st_ino; 6687*7c478bd9Sstevel@tonic-gate lp->devnum = stbuf.st_dev; 6688*7c478bd9Sstevel@tonic-gate lp->count = stbuf.st_nlink - 1; 6689*7c478bd9Sstevel@tonic-gate if (filetype == XATTR_FILE) { 6690*7c478bd9Sstevel@tonic-gate (void) strcpy(lp->pathname, longname); 6691*7c478bd9Sstevel@tonic-gate (void) strcpy(lp->attrname, component); 6692*7c478bd9Sstevel@tonic-gate } else { 6693*7c478bd9Sstevel@tonic-gate (void) strcpy(lp->pathname, longname); 6694*7c478bd9Sstevel@tonic-gate (void) strcpy(lp->attrname, ""); 6695*7c478bd9Sstevel@tonic-gate } 6696*7c478bd9Sstevel@tonic-gate } 6697*7c478bd9Sstevel@tonic-gate } 6698*7c478bd9Sstevel@tonic-gate } 6699*7c478bd9Sstevel@tonic-gate 6700*7c478bd9Sstevel@tonic-gate out: 6701*7c478bd9Sstevel@tonic-gate return (1); 6702*7c478bd9Sstevel@tonic-gate } 6703*7c478bd9Sstevel@tonic-gate 6704*7c478bd9Sstevel@tonic-gate static int 6705*7c478bd9Sstevel@tonic-gate put_extra_attributes(char *longname, char *shortname, char *prefix, 6706*7c478bd9Sstevel@tonic-gate int filetype, char typeflag) 6707*7c478bd9Sstevel@tonic-gate { 6708*7c478bd9Sstevel@tonic-gate int aclcnt; 6709*7c478bd9Sstevel@tonic-gate static aclent_t *aclp; 6710*7c478bd9Sstevel@tonic-gate 6711*7c478bd9Sstevel@tonic-gate if (aclp != (aclent_t *)NULL) { 6712*7c478bd9Sstevel@tonic-gate free(aclp); 6713*7c478bd9Sstevel@tonic-gate aclp = NULL; 6714*7c478bd9Sstevel@tonic-gate } 6715*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 6716*7c478bd9Sstevel@tonic-gate if (atflag && filetype == XATTR_FILE) { 6717*7c478bd9Sstevel@tonic-gate if (put_xattr_hdr(longname, shortname, prefix, 6718*7c478bd9Sstevel@tonic-gate typeflag, filetype, NULL)) { 6719*7c478bd9Sstevel@tonic-gate return (1); 6720*7c478bd9Sstevel@tonic-gate } 6721*7c478bd9Sstevel@tonic-gate } 6722*7c478bd9Sstevel@tonic-gate #endif 6723*7c478bd9Sstevel@tonic-gate 6724*7c478bd9Sstevel@tonic-gate /* ACL support */ 6725*7c478bd9Sstevel@tonic-gate if (pflag) { 6726*7c478bd9Sstevel@tonic-gate char *secinfo = NULL; 6727*7c478bd9Sstevel@tonic-gate int len = 0; 6728*7c478bd9Sstevel@tonic-gate 6729*7c478bd9Sstevel@tonic-gate /* ACL support */ 6730*7c478bd9Sstevel@tonic-gate if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) { 6731*7c478bd9Sstevel@tonic-gate /* 6732*7c478bd9Sstevel@tonic-gate * Get ACL info: dont bother allocating space if 6733*7c478bd9Sstevel@tonic-gate * there are only standard permissions, i.e. ACL 6734*7c478bd9Sstevel@tonic-gate * count <= 4 6735*7c478bd9Sstevel@tonic-gate */ 6736*7c478bd9Sstevel@tonic-gate if ((aclcnt = acl(shortname, GETACLCNT, 0, NULL)) < 0) { 6737*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6738*7c478bd9Sstevel@tonic-gate "%s: failed to get acl count\n"), longname); 6739*7c478bd9Sstevel@tonic-gate return (1); 6740*7c478bd9Sstevel@tonic-gate } 6741*7c478bd9Sstevel@tonic-gate if (aclcnt > MIN_ACL_ENTRIES) { 6742*7c478bd9Sstevel@tonic-gate if ((aclp = (aclent_t *)malloc( 6743*7c478bd9Sstevel@tonic-gate sizeof (aclent_t) * aclcnt)) == NULL) { 6744*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6745*7c478bd9Sstevel@tonic-gate "Insufficient memory\n")); 6746*7c478bd9Sstevel@tonic-gate return (1); 6747*7c478bd9Sstevel@tonic-gate } 6748*7c478bd9Sstevel@tonic-gate if (acl(shortname, GETACL, aclcnt, aclp) < 0) { 6749*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6750*7c478bd9Sstevel@tonic-gate "%s: failed to get acl entries\n"), 6751*7c478bd9Sstevel@tonic-gate longname); 6752*7c478bd9Sstevel@tonic-gate return (1); 6753*7c478bd9Sstevel@tonic-gate } 6754*7c478bd9Sstevel@tonic-gate } 6755*7c478bd9Sstevel@tonic-gate } 6756*7c478bd9Sstevel@tonic-gate 6757*7c478bd9Sstevel@tonic-gate /* append security attributes if any */ 6758*7c478bd9Sstevel@tonic-gate if (aclp != (aclent_t *)NULL) { 6759*7c478bd9Sstevel@tonic-gate (void) append_secattr(&secinfo, &len, aclcnt, 6760*7c478bd9Sstevel@tonic-gate aclp, UFSD_ACL); 6761*7c478bd9Sstevel@tonic-gate (void) write_ancillary(&dblock, secinfo, len, ACL_HDR); 6762*7c478bd9Sstevel@tonic-gate } 6763*7c478bd9Sstevel@tonic-gate } 6764*7c478bd9Sstevel@tonic-gate return (0); 6765*7c478bd9Sstevel@tonic-gate } 6766*7c478bd9Sstevel@tonic-gate 6767*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 6768*7c478bd9Sstevel@tonic-gate static int 6769*7c478bd9Sstevel@tonic-gate put_xattr_hdr(char *longname, char *shortname, char *prefix, 6770*7c478bd9Sstevel@tonic-gate int typeflag, int filetype, struct linkbuf *lp) 6771*7c478bd9Sstevel@tonic-gate { 6772*7c478bd9Sstevel@tonic-gate char *lname = NULL; 6773*7c478bd9Sstevel@tonic-gate char *sname = NULL; 6774*7c478bd9Sstevel@tonic-gate int error = 0; 6775*7c478bd9Sstevel@tonic-gate static char *attrbuf = NULL; 6776*7c478bd9Sstevel@tonic-gate int attrlen; 6777*7c478bd9Sstevel@tonic-gate 6778*7c478bd9Sstevel@tonic-gate lname = malloc(sizeof (char) * strlen("/dev/null") + 1 + 6779*7c478bd9Sstevel@tonic-gate strlen(shortname) + strlen(".hdr") + 1); 6780*7c478bd9Sstevel@tonic-gate 6781*7c478bd9Sstevel@tonic-gate if (lname == NULL) { 6782*7c478bd9Sstevel@tonic-gate fatal(gettext("Out of Memory.")); 6783*7c478bd9Sstevel@tonic-gate } 6784*7c478bd9Sstevel@tonic-gate sname = malloc(sizeof (char) * strlen(shortname) + 6785*7c478bd9Sstevel@tonic-gate strlen(".hdr")); 6786*7c478bd9Sstevel@tonic-gate if (sname == NULL) { 6787*7c478bd9Sstevel@tonic-gate fatal(gettext("Out of Memory.")); 6788*7c478bd9Sstevel@tonic-gate } 6789*7c478bd9Sstevel@tonic-gate 6790*7c478bd9Sstevel@tonic-gate (void) sprintf(sname, "%s.hdr", shortname); 6791*7c478bd9Sstevel@tonic-gate (void) sprintf(lname, "/dev/null/%s", sname); 6792*7c478bd9Sstevel@tonic-gate 6793*7c478bd9Sstevel@tonic-gate if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >= 6794*7c478bd9Sstevel@tonic-gate sizeof (dblock.dbuf.name)) { 6795*7c478bd9Sstevel@tonic-gate fatal(gettext( 6796*7c478bd9Sstevel@tonic-gate "Buffer overflow writing extended attribute file name")); 6797*7c478bd9Sstevel@tonic-gate } 6798*7c478bd9Sstevel@tonic-gate 6799*7c478bd9Sstevel@tonic-gate /* 6800*7c478bd9Sstevel@tonic-gate * dump extended attr lookup info 6801*7c478bd9Sstevel@tonic-gate */ 6802*7c478bd9Sstevel@tonic-gate prepare_xattr(&attrbuf, longname, shortname, typeflag, lp, &attrlen); 6803*7c478bd9Sstevel@tonic-gate write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE); 6804*7c478bd9Sstevel@tonic-gate 6805*7c478bd9Sstevel@tonic-gate (void) sprintf(lname, "/dev/null/%s", shortname); 6806*7c478bd9Sstevel@tonic-gate (void) strncpy(dblock.dbuf.name, sname, NAMSIZ); 6807*7c478bd9Sstevel@tonic-gate 6808*7c478bd9Sstevel@tonic-gate /* 6809*7c478bd9Sstevel@tonic-gate * Set up filename for attribute 6810*7c478bd9Sstevel@tonic-gate */ 6811*7c478bd9Sstevel@tonic-gate 6812*7c478bd9Sstevel@tonic-gate error = build_dblock(lname, tchar, '0', filetype, 6813*7c478bd9Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix); 6814*7c478bd9Sstevel@tonic-gate free(lname); 6815*7c478bd9Sstevel@tonic-gate free(sname); 6816*7c478bd9Sstevel@tonic-gate 6817*7c478bd9Sstevel@tonic-gate return (error); 6818*7c478bd9Sstevel@tonic-gate } 6819*7c478bd9Sstevel@tonic-gate #endif 6820*7c478bd9Sstevel@tonic-gate 6821*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 6822*7c478bd9Sstevel@tonic-gate static int 6823*7c478bd9Sstevel@tonic-gate read_xattr_hdr() 6824*7c478bd9Sstevel@tonic-gate { 6825*7c478bd9Sstevel@tonic-gate char buf[TBLOCK]; 6826*7c478bd9Sstevel@tonic-gate blkcnt_t blocks; 6827*7c478bd9Sstevel@tonic-gate char *tp; 6828*7c478bd9Sstevel@tonic-gate off_t bytes; 6829*7c478bd9Sstevel@tonic-gate int comp_len, link_len; 6830*7c478bd9Sstevel@tonic-gate int namelen; 6831*7c478bd9Sstevel@tonic-gate 6832*7c478bd9Sstevel@tonic-gate 6833*7c478bd9Sstevel@tonic-gate if (dblock.dbuf.typeflag != _XATTR_HDRTYPE) 6834*7c478bd9Sstevel@tonic-gate return (1); 6835*7c478bd9Sstevel@tonic-gate 6836*7c478bd9Sstevel@tonic-gate bytes = stbuf.st_size; 6837*7c478bd9Sstevel@tonic-gate if ((xattrhead = calloc(1, (int)bytes)) == NULL) { 6838*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6839*7c478bd9Sstevel@tonic-gate "Insufficient memory for extended attribute\n")); 6840*7c478bd9Sstevel@tonic-gate return (1); 6841*7c478bd9Sstevel@tonic-gate } 6842*7c478bd9Sstevel@tonic-gate 6843*7c478bd9Sstevel@tonic-gate tp = (char *)xattrhead; 6844*7c478bd9Sstevel@tonic-gate blocks = TBLOCKS(bytes); 6845*7c478bd9Sstevel@tonic-gate while (blocks-- > 0) { 6846*7c478bd9Sstevel@tonic-gate readtape(buf); 6847*7c478bd9Sstevel@tonic-gate if (bytes <= TBLOCK) { 6848*7c478bd9Sstevel@tonic-gate (void) memcpy(tp, buf, (size_t)bytes); 6849*7c478bd9Sstevel@tonic-gate break; 6850*7c478bd9Sstevel@tonic-gate } else { 6851*7c478bd9Sstevel@tonic-gate (void) memcpy(tp, buf, TBLOCK); 6852*7c478bd9Sstevel@tonic-gate tp += TBLOCK; 6853*7c478bd9Sstevel@tonic-gate } 6854*7c478bd9Sstevel@tonic-gate bytes -= TBLOCK; 6855*7c478bd9Sstevel@tonic-gate } 6856*7c478bd9Sstevel@tonic-gate 6857*7c478bd9Sstevel@tonic-gate /* 6858*7c478bd9Sstevel@tonic-gate * Validate that we can handle header format 6859*7c478bd9Sstevel@tonic-gate */ 6860*7c478bd9Sstevel@tonic-gate if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) { 6861*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6862*7c478bd9Sstevel@tonic-gate gettext("Unknown extended attribute format encountered\n")); 6863*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6864*7c478bd9Sstevel@tonic-gate gettext("Disabling extended attribute parsing\n")); 6865*7c478bd9Sstevel@tonic-gate xattrbadhead = 1; 6866*7c478bd9Sstevel@tonic-gate return (0); 6867*7c478bd9Sstevel@tonic-gate } 6868*7c478bd9Sstevel@tonic-gate (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len); 6869*7c478bd9Sstevel@tonic-gate (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len); 6870*7c478bd9Sstevel@tonic-gate xattrp = (struct xattr_buf *)(((char *)xattrhead) + 6871*7c478bd9Sstevel@tonic-gate sizeof (struct xattr_hdr)); 6872*7c478bd9Sstevel@tonic-gate (void) sscanf(xattrp->h_namesz, "%7d", &namelen); 6873*7c478bd9Sstevel@tonic-gate if (link_len > 0) 6874*7c478bd9Sstevel@tonic-gate xattr_linkp = (struct xattr_buf *) 6875*7c478bd9Sstevel@tonic-gate ((int)xattrp + (int)comp_len); 6876*7c478bd9Sstevel@tonic-gate else 6877*7c478bd9Sstevel@tonic-gate xattr_linkp = NULL; 6878*7c478bd9Sstevel@tonic-gate 6879*7c478bd9Sstevel@tonic-gate xattraname = xattrp->h_names + strlen(xattrp->h_names) + 1; 6880*7c478bd9Sstevel@tonic-gate if (xattr_linkp) { 6881*7c478bd9Sstevel@tonic-gate xattr_linkaname = xattr_linkp->h_names + 6882*7c478bd9Sstevel@tonic-gate strlen(xattr_linkp->h_names) + 1; 6883*7c478bd9Sstevel@tonic-gate } else { 6884*7c478bd9Sstevel@tonic-gate xattr_linkaname = NULL; 6885*7c478bd9Sstevel@tonic-gate } 6886*7c478bd9Sstevel@tonic-gate return (0); 6887*7c478bd9Sstevel@tonic-gate } 6888*7c478bd9Sstevel@tonic-gate #else 6889*7c478bd9Sstevel@tonic-gate static int 6890*7c478bd9Sstevel@tonic-gate read_xattr_hdr() 6891*7c478bd9Sstevel@tonic-gate { 6892*7c478bd9Sstevel@tonic-gate return (0); 6893*7c478bd9Sstevel@tonic-gate } 6894*7c478bd9Sstevel@tonic-gate #endif 6895*7c478bd9Sstevel@tonic-gate 6896*7c478bd9Sstevel@tonic-gate /* 6897*7c478bd9Sstevel@tonic-gate * skip over extra slashes in string. 6898*7c478bd9Sstevel@tonic-gate * 6899*7c478bd9Sstevel@tonic-gate * For example: 6900*7c478bd9Sstevel@tonic-gate * /usr/tmp///// 6901*7c478bd9Sstevel@tonic-gate * 6902*7c478bd9Sstevel@tonic-gate * would return pointer at 6903*7c478bd9Sstevel@tonic-gate * /usr/tmp///// 6904*7c478bd9Sstevel@tonic-gate * ^ 6905*7c478bd9Sstevel@tonic-gate */ 6906*7c478bd9Sstevel@tonic-gate static char * 6907*7c478bd9Sstevel@tonic-gate skipslashes(char *string, char *start) 6908*7c478bd9Sstevel@tonic-gate { 6909*7c478bd9Sstevel@tonic-gate while ((string > start) && *(string - 1) == '/') { 6910*7c478bd9Sstevel@tonic-gate string--; 6911*7c478bd9Sstevel@tonic-gate } 6912*7c478bd9Sstevel@tonic-gate 6913*7c478bd9Sstevel@tonic-gate return (string); 6914*7c478bd9Sstevel@tonic-gate } 6915*7c478bd9Sstevel@tonic-gate 6916*7c478bd9Sstevel@tonic-gate /* 6917*7c478bd9Sstevel@tonic-gate * Return the parent directory of a given path. 6918*7c478bd9Sstevel@tonic-gate * 6919*7c478bd9Sstevel@tonic-gate * Examples: 6920*7c478bd9Sstevel@tonic-gate * /usr/tmp return /usr 6921*7c478bd9Sstevel@tonic-gate * /usr/tmp/file return /usr/tmp 6922*7c478bd9Sstevel@tonic-gate * / returns . 6923*7c478bd9Sstevel@tonic-gate * /usr returns / 6924*7c478bd9Sstevel@tonic-gate * file returns . 6925*7c478bd9Sstevel@tonic-gate * 6926*7c478bd9Sstevel@tonic-gate * dir is assumed to be at least as big as path. 6927*7c478bd9Sstevel@tonic-gate */ 6928*7c478bd9Sstevel@tonic-gate static void 6929*7c478bd9Sstevel@tonic-gate get_parent(char *path, char *dir) 6930*7c478bd9Sstevel@tonic-gate { 6931*7c478bd9Sstevel@tonic-gate char *s; 6932*7c478bd9Sstevel@tonic-gate char tmpdir[PATH_MAX + 1]; 6933*7c478bd9Sstevel@tonic-gate 6934*7c478bd9Sstevel@tonic-gate if (strlen(path) > PATH_MAX) { 6935*7c478bd9Sstevel@tonic-gate fatal(gettext("pathname is too long")); 6936*7c478bd9Sstevel@tonic-gate } 6937*7c478bd9Sstevel@tonic-gate (void) strcpy(tmpdir, path); 6938*7c478bd9Sstevel@tonic-gate chop_endslashes(tmpdir); 6939*7c478bd9Sstevel@tonic-gate 6940*7c478bd9Sstevel@tonic-gate if ((s = strrchr(tmpdir, '/')) == NULL) { 6941*7c478bd9Sstevel@tonic-gate (void) strcpy(dir, "."); 6942*7c478bd9Sstevel@tonic-gate } else { 6943*7c478bd9Sstevel@tonic-gate s = skipslashes(s, tmpdir); 6944*7c478bd9Sstevel@tonic-gate *s = '\0'; 6945*7c478bd9Sstevel@tonic-gate if (s == tmpdir) 6946*7c478bd9Sstevel@tonic-gate (void) strcpy(dir, "/"); 6947*7c478bd9Sstevel@tonic-gate else 6948*7c478bd9Sstevel@tonic-gate (void) strcpy(dir, tmpdir); 6949*7c478bd9Sstevel@tonic-gate } 6950*7c478bd9Sstevel@tonic-gate } 6951*7c478bd9Sstevel@tonic-gate 6952*7c478bd9Sstevel@tonic-gate #if defined(O_XATTR) 6953*7c478bd9Sstevel@tonic-gate static char * 6954*7c478bd9Sstevel@tonic-gate get_component(char *path) 6955*7c478bd9Sstevel@tonic-gate { 6956*7c478bd9Sstevel@tonic-gate char *ptr; 6957*7c478bd9Sstevel@tonic-gate 6958*7c478bd9Sstevel@tonic-gate ptr = strrchr(path, '/'); 6959*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 6960*7c478bd9Sstevel@tonic-gate return (path); 6961*7c478bd9Sstevel@tonic-gate } else { 6962*7c478bd9Sstevel@tonic-gate /* 6963*7c478bd9Sstevel@tonic-gate * Handle trailing slash 6964*7c478bd9Sstevel@tonic-gate */ 6965*7c478bd9Sstevel@tonic-gate if (*(ptr + 1) == '\0') 6966*7c478bd9Sstevel@tonic-gate return (ptr); 6967*7c478bd9Sstevel@tonic-gate else 6968*7c478bd9Sstevel@tonic-gate return (ptr + 1); 6969*7c478bd9Sstevel@tonic-gate } 6970*7c478bd9Sstevel@tonic-gate } 6971*7c478bd9Sstevel@tonic-gate #else 6972*7c478bd9Sstevel@tonic-gate static char * 6973*7c478bd9Sstevel@tonic-gate get_component(char *path) 6974*7c478bd9Sstevel@tonic-gate { 6975*7c478bd9Sstevel@tonic-gate return (path); 6976*7c478bd9Sstevel@tonic-gate } 6977*7c478bd9Sstevel@tonic-gate #endif 6978*7c478bd9Sstevel@tonic-gate 6979*7c478bd9Sstevel@tonic-gate static int 6980*7c478bd9Sstevel@tonic-gate retry_attrdir_open(char *name) 6981*7c478bd9Sstevel@tonic-gate { 6982*7c478bd9Sstevel@tonic-gate int dirfd = -1; 6983*7c478bd9Sstevel@tonic-gate struct timeval times[2]; 6984*7c478bd9Sstevel@tonic-gate mode_t newmode; 6985*7c478bd9Sstevel@tonic-gate struct stat parentstat; 6986*7c478bd9Sstevel@tonic-gate 6987*7c478bd9Sstevel@tonic-gate /* 6988*7c478bd9Sstevel@tonic-gate * We couldn't get to attrdir. See if its 6989*7c478bd9Sstevel@tonic-gate * just a mode problem on the parent file. 6990*7c478bd9Sstevel@tonic-gate * for example: a mode such as r-xr--r-- 6991*7c478bd9Sstevel@tonic-gate * won't let us create an attribute dir 6992*7c478bd9Sstevel@tonic-gate * if it doesn't already exist. 6993*7c478bd9Sstevel@tonic-gate */ 6994*7c478bd9Sstevel@tonic-gate 6995*7c478bd9Sstevel@tonic-gate if (stat(name, &parentstat) == -1) { 6996*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Cannot stat file %s %s\n"), 6997*7c478bd9Sstevel@tonic-gate name, strerror(errno)); 6998*7c478bd9Sstevel@tonic-gate return (1); 6999*7c478bd9Sstevel@tonic-gate } 7000*7c478bd9Sstevel@tonic-gate newmode = S_IWUSR | parentstat.st_mode; 7001*7c478bd9Sstevel@tonic-gate if (chmod(name, newmode) == -1) { 7002*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7003*7c478bd9Sstevel@tonic-gate gettext("Cannot chmod file %s to %o %s\n"), 7004*7c478bd9Sstevel@tonic-gate name, newmode, strerror(errno)); 7005*7c478bd9Sstevel@tonic-gate return (1); 7006*7c478bd9Sstevel@tonic-gate 7007*7c478bd9Sstevel@tonic-gate } 7008*7c478bd9Sstevel@tonic-gate 7009*7c478bd9Sstevel@tonic-gate dirfd = attropen(name, ".", O_RDONLY); 7010*7c478bd9Sstevel@tonic-gate if (dirfd == -1) { 7011*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7012*7c478bd9Sstevel@tonic-gate gettext("Cannot open attribute directory of" 7013*7c478bd9Sstevel@tonic-gate " file %s %s\n"), name, strerror(errno)); 7014*7c478bd9Sstevel@tonic-gate return (1); 7015*7c478bd9Sstevel@tonic-gate } else { 7016*7c478bd9Sstevel@tonic-gate 7017*7c478bd9Sstevel@tonic-gate /* 7018*7c478bd9Sstevel@tonic-gate * Put mode back to original 7019*7c478bd9Sstevel@tonic-gate */ 7020*7c478bd9Sstevel@tonic-gate (void) chmod(name, parentstat.st_mode); 7021*7c478bd9Sstevel@tonic-gate 7022*7c478bd9Sstevel@tonic-gate /* 7023*7c478bd9Sstevel@tonic-gate * Put back time stamps 7024*7c478bd9Sstevel@tonic-gate */ 7025*7c478bd9Sstevel@tonic-gate 7026*7c478bd9Sstevel@tonic-gate times[0].tv_sec = parentstat.st_atime; 7027*7c478bd9Sstevel@tonic-gate times[0].tv_usec = 0; 7028*7c478bd9Sstevel@tonic-gate times[1].tv_sec = parentstat.st_mtime; 7029*7c478bd9Sstevel@tonic-gate times[1].tv_usec = 0; 7030*7c478bd9Sstevel@tonic-gate (void) utimes(name, times); 7031*7c478bd9Sstevel@tonic-gate } 7032*7c478bd9Sstevel@tonic-gate 7033*7c478bd9Sstevel@tonic-gate return (dirfd); 7034*7c478bd9Sstevel@tonic-gate } 7035*7c478bd9Sstevel@tonic-gate 7036*7c478bd9Sstevel@tonic-gate #if !defined(O_XATTR) 7037*7c478bd9Sstevel@tonic-gate static int 7038*7c478bd9Sstevel@tonic-gate openat64(int fd, const char *name, int oflag, mode_t cmode) 7039*7c478bd9Sstevel@tonic-gate { 7040*7c478bd9Sstevel@tonic-gate return (open64(name, oflag, cmode)); 7041*7c478bd9Sstevel@tonic-gate } 7042*7c478bd9Sstevel@tonic-gate 7043*7c478bd9Sstevel@tonic-gate static int 7044*7c478bd9Sstevel@tonic-gate openat(int fd, const char *name, int oflag, mode_t cmode) 7045*7c478bd9Sstevel@tonic-gate { 7046*7c478bd9Sstevel@tonic-gate return (open(name, oflag, cmode)); 7047*7c478bd9Sstevel@tonic-gate } 7048*7c478bd9Sstevel@tonic-gate 7049*7c478bd9Sstevel@tonic-gate static int 7050*7c478bd9Sstevel@tonic-gate fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag) 7051*7c478bd9Sstevel@tonic-gate { 7052*7c478bd9Sstevel@tonic-gate if (flag == AT_SYMLINK_NOFOLLOW) 7053*7c478bd9Sstevel@tonic-gate return (lchown(name, owner, group)); 7054*7c478bd9Sstevel@tonic-gate else 7055*7c478bd9Sstevel@tonic-gate return (chown(name, owner, group)); 7056*7c478bd9Sstevel@tonic-gate } 7057*7c478bd9Sstevel@tonic-gate 7058*7c478bd9Sstevel@tonic-gate static int 7059*7c478bd9Sstevel@tonic-gate renameat(int fromfd, char *old, int tofd, char *new) 7060*7c478bd9Sstevel@tonic-gate { 7061*7c478bd9Sstevel@tonic-gate return (rename(old, new)); 7062*7c478bd9Sstevel@tonic-gate } 7063*7c478bd9Sstevel@tonic-gate 7064*7c478bd9Sstevel@tonic-gate static int 7065*7c478bd9Sstevel@tonic-gate futimesat(int fd, char *path, struct timeval times[2]) 7066*7c478bd9Sstevel@tonic-gate { 7067*7c478bd9Sstevel@tonic-gate return (utimes(path, times)); 7068*7c478bd9Sstevel@tonic-gate } 7069*7c478bd9Sstevel@tonic-gate 7070*7c478bd9Sstevel@tonic-gate static int 7071*7c478bd9Sstevel@tonic-gate unlinkat(int dirfd, char *path, int flag) 7072*7c478bd9Sstevel@tonic-gate { 7073*7c478bd9Sstevel@tonic-gate if (flag == AT_REMOVEDIR) 7074*7c478bd9Sstevel@tonic-gate return (rmdir(path)); 7075*7c478bd9Sstevel@tonic-gate else 7076*7c478bd9Sstevel@tonic-gate return (unlink(path)); 7077*7c478bd9Sstevel@tonic-gate } 7078*7c478bd9Sstevel@tonic-gate 7079*7c478bd9Sstevel@tonic-gate static int 7080*7c478bd9Sstevel@tonic-gate fstatat(int fd, char *path, struct stat *buf, int flag) 7081*7c478bd9Sstevel@tonic-gate { 7082*7c478bd9Sstevel@tonic-gate if (flag == AT_SYMLINK_NOFOLLOW) 7083*7c478bd9Sstevel@tonic-gate return (lstat(path, buf)); 7084*7c478bd9Sstevel@tonic-gate else 7085*7c478bd9Sstevel@tonic-gate return (stat(path, buf)); 7086*7c478bd9Sstevel@tonic-gate } 7087*7c478bd9Sstevel@tonic-gate 7088*7c478bd9Sstevel@tonic-gate static int 7089*7c478bd9Sstevel@tonic-gate attropen(char *file, char *attr, int omode, mode_t cmode) 7090*7c478bd9Sstevel@tonic-gate { 7091*7c478bd9Sstevel@tonic-gate errno = ENOTSUP; 7092*7c478bd9Sstevel@tonic-gate return (-1); 7093*7c478bd9Sstevel@tonic-gate } 7094*7c478bd9Sstevel@tonic-gate #endif 7095*7c478bd9Sstevel@tonic-gate 7096*7c478bd9Sstevel@tonic-gate static void 7097*7c478bd9Sstevel@tonic-gate chop_endslashes(char *path) 7098*7c478bd9Sstevel@tonic-gate { 7099*7c478bd9Sstevel@tonic-gate char *end, *ptr; 7100*7c478bd9Sstevel@tonic-gate 7101*7c478bd9Sstevel@tonic-gate /* 7102*7c478bd9Sstevel@tonic-gate * Chop of slashes, but not if all we have is slashes 7103*7c478bd9Sstevel@tonic-gate * for example: //// 7104*7c478bd9Sstevel@tonic-gate * should make no changes, otherwise it will screw up 7105*7c478bd9Sstevel@tonic-gate * checkdir 7106*7c478bd9Sstevel@tonic-gate */ 7107*7c478bd9Sstevel@tonic-gate end = &path[strlen(path) -1]; 7108*7c478bd9Sstevel@tonic-gate if (*end == '/' && end != path) { 7109*7c478bd9Sstevel@tonic-gate ptr = skipslashes(end, path); 7110*7c478bd9Sstevel@tonic-gate if (ptr != NULL && ptr != path) { 7111*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 7112*7c478bd9Sstevel@tonic-gate } 7113*7c478bd9Sstevel@tonic-gate } 7114*7c478bd9Sstevel@tonic-gate } 7115