1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 31*0Sstevel@tonic-gate /* All Rights Reserved */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate /* 34*0Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 35*0Sstevel@tonic-gate * under license from the Regents of the University of California. 36*0Sstevel@tonic-gate */ 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #include <unistd.h> 41*0Sstevel@tonic-gate #include <sys/types.h> 42*0Sstevel@tonic-gate #include <sys/param.h> 43*0Sstevel@tonic-gate #include <sys/stat.h> 44*0Sstevel@tonic-gate #include <sys/mkdev.h> 45*0Sstevel@tonic-gate #include <sys/wait.h> 46*0Sstevel@tonic-gate #include <dirent.h> 47*0Sstevel@tonic-gate #include <errno.h> 48*0Sstevel@tonic-gate #include <stdio.h> 49*0Sstevel@tonic-gate #include <signal.h> 50*0Sstevel@tonic-gate #include <ctype.h> 51*0Sstevel@tonic-gate #include <locale.h> 52*0Sstevel@tonic-gate #include <nl_types.h> 53*0Sstevel@tonic-gate #include <langinfo.h> 54*0Sstevel@tonic-gate #include <pwd.h> 55*0Sstevel@tonic-gate #include <grp.h> 56*0Sstevel@tonic-gate #include <fcntl.h> 57*0Sstevel@tonic-gate #include <string.h> 58*0Sstevel@tonic-gate #include <malloc.h> 59*0Sstevel@tonic-gate #include <time.h> 60*0Sstevel@tonic-gate #include <utime.h> 61*0Sstevel@tonic-gate #include <stdlib.h> 62*0Sstevel@tonic-gate #include <stdarg.h> 63*0Sstevel@tonic-gate #include <widec.h> 64*0Sstevel@tonic-gate #include <sys/mtio.h> 65*0Sstevel@tonic-gate #include <libintl.h> 66*0Sstevel@tonic-gate #include <sys/acl.h> 67*0Sstevel@tonic-gate #include <strings.h> 68*0Sstevel@tonic-gate #include <deflt.h> 69*0Sstevel@tonic-gate #include <limits.h> 70*0Sstevel@tonic-gate #include <iconv.h> 71*0Sstevel@tonic-gate #include <assert.h> 72*0Sstevel@tonic-gate #if defined(__SunOS_5_6) || defined(__SunOS_5_7) 73*0Sstevel@tonic-gate extern int defcntl(); 74*0Sstevel@tonic-gate #endif 75*0Sstevel@tonic-gate #include <archives.h> 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate /* 78*0Sstevel@tonic-gate * Source compatibility 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate /* 82*0Sstevel@tonic-gate * These constants come from archives.h and sys/fcntl.h 83*0Sstevel@tonic-gate * and were introduced by the extended attributes project 84*0Sstevel@tonic-gate * in Solaris 9. 85*0Sstevel@tonic-gate */ 86*0Sstevel@tonic-gate #if !defined(O_XATTR) 87*0Sstevel@tonic-gate #define AT_SYMLINK_NOFOLLOW 0x1000 88*0Sstevel@tonic-gate #define AT_REMOVEDIR 0x1 89*0Sstevel@tonic-gate #define AT_FDCWD 0xffd19553 90*0Sstevel@tonic-gate #define _XATTR_HDRTYPE 'E' 91*0Sstevel@tonic-gate static int attropen(); 92*0Sstevel@tonic-gate static int fstatat(); 93*0Sstevel@tonic-gate static int renameat(); 94*0Sstevel@tonic-gate static int unlinkat(); 95*0Sstevel@tonic-gate static int openat(); 96*0Sstevel@tonic-gate static int fchownat(); 97*0Sstevel@tonic-gate static int futimesat(); 98*0Sstevel@tonic-gate #endif 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * Compiling with -D_XPG4_2 gets this but produces other problems, so 102*0Sstevel@tonic-gate * instead of including sys/time.h and compiling with -D_XPG4_2, I'm 103*0Sstevel@tonic-gate * explicitly doing the declaration here. 104*0Sstevel@tonic-gate */ 105*0Sstevel@tonic-gate int utimes(const char *path, const struct timeval timeval_ptr[]); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate #ifndef MINSIZE 108*0Sstevel@tonic-gate #define MINSIZE 250 109*0Sstevel@tonic-gate #endif 110*0Sstevel@tonic-gate #define DEF_FILE "/etc/default/tar" 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate #define min(a, b) ((a) < (b) ? (a) : (b)) 113*0Sstevel@tonic-gate #define max(a, b) ((a) > (b) ? (a) : (b)) 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate /* -DDEBUG ONLY for debugging */ 116*0Sstevel@tonic-gate #ifdef DEBUG 117*0Sstevel@tonic-gate #undef DEBUG 118*0Sstevel@tonic-gate #define DEBUG(a, b, c)\ 119*0Sstevel@tonic-gate (void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c) 120*0Sstevel@tonic-gate #endif 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate #define TBLOCK 512 /* tape block size--should be universal */ 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate #ifdef BSIZE 125*0Sstevel@tonic-gate #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */ 126*0Sstevel@tonic-gate #else /* BSIZE */ 127*0Sstevel@tonic-gate #define SYS_BLOCK 512 /* default if no BSIZE in param.h */ 128*0Sstevel@tonic-gate #endif /* BSIZE */ 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate #define NBLOCK 20 131*0Sstevel@tonic-gate #define NAMSIZ 100 132*0Sstevel@tonic-gate #define PRESIZ 155 133*0Sstevel@tonic-gate #define MAXNAM 256 134*0Sstevel@tonic-gate #define MODEMASK 0777777 /* file creation mode mask */ 135*0Sstevel@tonic-gate #define POSIXMODES 07777 /* mask for POSIX mode bits */ 136*0Sstevel@tonic-gate #define MAXEXT 9 /* reasonable max # extents for a file */ 137*0Sstevel@tonic-gate #define EXTMIN 50 /* min blks left on floppy to split a file */ 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate /* max value dblock.dbuf.efsize can store */ 140*0Sstevel@tonic-gate #define TAR_EFSIZE_MAX 0777777777 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate /* 143*0Sstevel@tonic-gate * Symbols which specify the values at which the use of the 'E' function 144*0Sstevel@tonic-gate * modifier is required to properly store a file. 145*0Sstevel@tonic-gate * 146*0Sstevel@tonic-gate * TAR_OFFSET_MAX - the largest file size we can archive 147*0Sstevel@tonic-gate * OCTAL7CHAR - the limit for ustar gid, uid, dev 148*0Sstevel@tonic-gate */ 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate #ifdef XHDR_DEBUG 151*0Sstevel@tonic-gate /* tiny values which force the creation of extended header entries */ 152*0Sstevel@tonic-gate #define TAR_OFFSET_MAX 9 153*0Sstevel@tonic-gate #define OCTAL7CHAR 2 154*0Sstevel@tonic-gate #else 155*0Sstevel@tonic-gate /* normal values */ 156*0Sstevel@tonic-gate #define TAR_OFFSET_MAX 077777777777 157*0Sstevel@tonic-gate #define OCTAL7CHAR 07777777 158*0Sstevel@tonic-gate #endif 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK) 161*0Sstevel@tonic-gate #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */ 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate #define MAXLEV (PATH_MAX / 2) 164*0Sstevel@tonic-gate #define LEV0 1 165*0Sstevel@tonic-gate #define SYMLINK_LEV0 0 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate #define TRUE 1 168*0Sstevel@tonic-gate #define FALSE 0 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate #define XATTR_FILE 1 171*0Sstevel@tonic-gate #define NORMAL_FILE 0 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate #define PUT_AS_LINK 1 174*0Sstevel@tonic-gate #define PUT_NOTAS_LINK 0 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate #if _FILE_OFFSET_BITS == 64 177*0Sstevel@tonic-gate #define FMT_off_t "lld" 178*0Sstevel@tonic-gate #define FMT_off_t_o "llo" 179*0Sstevel@tonic-gate #define FMT_blkcnt_t "lld" 180*0Sstevel@tonic-gate #else 181*0Sstevel@tonic-gate #define FMT_off_t "ld" 182*0Sstevel@tonic-gate #define FMT_off_t_o "lo" 183*0Sstevel@tonic-gate #define FMT_blkcnt_t "ld" 184*0Sstevel@tonic-gate #endif 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate /* ACL support */ 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate static 189*0Sstevel@tonic-gate struct sec_attr { 190*0Sstevel@tonic-gate char attr_type; 191*0Sstevel@tonic-gate char attr_len[7]; 192*0Sstevel@tonic-gate char attr_info[1]; 193*0Sstevel@tonic-gate } *attr; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate #define ACL_HDR 'A' 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * 199*0Sstevel@tonic-gate * Tar has been changed to support extended attributes. 200*0Sstevel@tonic-gate * 201*0Sstevel@tonic-gate * As part of this change tar now uses the new *at() syscalls 202*0Sstevel@tonic-gate * such as openat, fchownat(), unlinkat()... 203*0Sstevel@tonic-gate * 204*0Sstevel@tonic-gate * This was done so that attributes can be handled with as few code changes 205*0Sstevel@tonic-gate * as possible. 206*0Sstevel@tonic-gate * 207*0Sstevel@tonic-gate * What this means is that tar now opens the directory that a file or directory 208*0Sstevel@tonic-gate * resides in and then performs *at() functions to manipulate the entry. 209*0Sstevel@tonic-gate * 210*0Sstevel@tonic-gate * For example a new file is now created like this: 211*0Sstevel@tonic-gate * 212*0Sstevel@tonic-gate * dfd = open(<some dir path>) 213*0Sstevel@tonic-gate * fd = openat(dfd, <name>,....); 214*0Sstevel@tonic-gate * 215*0Sstevel@tonic-gate * or in the case of an extended attribute 216*0Sstevel@tonic-gate * 217*0Sstevel@tonic-gate * dfd = attropen(<pathname>, ".", ....) 218*0Sstevel@tonic-gate * 219*0Sstevel@tonic-gate * Once we have a directory file descriptor all of the *at() functions can 220*0Sstevel@tonic-gate * be applied to it. 221*0Sstevel@tonic-gate * 222*0Sstevel@tonic-gate * unlinkat(dfd, <component name>,...) 223*0Sstevel@tonic-gate * fchownat(dfd, <component name>,..) 224*0Sstevel@tonic-gate * 225*0Sstevel@tonic-gate * This works for both normal namespace files and extended attribute file 226*0Sstevel@tonic-gate * 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate /* 230*0Sstevel@tonic-gate * 231*0Sstevel@tonic-gate * Extended attribute Format 232*0Sstevel@tonic-gate * 233*0Sstevel@tonic-gate * Extended attributes are stored in two pieces. 234*0Sstevel@tonic-gate * 1. An attribute header which has information about 235*0Sstevel@tonic-gate * what file the attribute is for and what the attribute 236*0Sstevel@tonic-gate * is named. 237*0Sstevel@tonic-gate * 2. The attribute record itself. Stored as a normal file type 238*0Sstevel@tonic-gate * of entry. 239*0Sstevel@tonic-gate * Both the header and attribute record have special modes/typeflags 240*0Sstevel@tonic-gate * associated with them. 241*0Sstevel@tonic-gate * 242*0Sstevel@tonic-gate * The names of the header in the archive look like: 243*0Sstevel@tonic-gate * /dev/null/attr.hdr 244*0Sstevel@tonic-gate * 245*0Sstevel@tonic-gate * The name of the attribute looks like: 246*0Sstevel@tonic-gate * /dev/null/attr 247*0Sstevel@tonic-gate * 248*0Sstevel@tonic-gate * This is done so that an archiver that doesn't understand these formats 249*0Sstevel@tonic-gate * can just dispose of the attribute records. 250*0Sstevel@tonic-gate * 251*0Sstevel@tonic-gate * The format is composed of a fixed size header followed 252*0Sstevel@tonic-gate * by a variable sized xattr_buf. If the attribute is a hard link 253*0Sstevel@tonic-gate * to another attribute then another xattr_buf section is included 254*0Sstevel@tonic-gate * for the link. 255*0Sstevel@tonic-gate * 256*0Sstevel@tonic-gate * The xattr_buf is used to define the necessary "pathing" steps 257*0Sstevel@tonic-gate * to get to the extended attribute. This is necessary to support 258*0Sstevel@tonic-gate * a fully recursive attribute model where an attribute may itself 259*0Sstevel@tonic-gate * have an attribute. 260*0Sstevel@tonic-gate * 261*0Sstevel@tonic-gate * The basic layout looks like this. 262*0Sstevel@tonic-gate * 263*0Sstevel@tonic-gate * -------------------------------- 264*0Sstevel@tonic-gate * | | 265*0Sstevel@tonic-gate * | xattr_hdr | 266*0Sstevel@tonic-gate * | | 267*0Sstevel@tonic-gate * -------------------------------- 268*0Sstevel@tonic-gate * -------------------------------- 269*0Sstevel@tonic-gate * | | 270*0Sstevel@tonic-gate * | xattr_buf | 271*0Sstevel@tonic-gate * | | 272*0Sstevel@tonic-gate * -------------------------------- 273*0Sstevel@tonic-gate * -------------------------------- 274*0Sstevel@tonic-gate * | | 275*0Sstevel@tonic-gate * | (optional link info) | 276*0Sstevel@tonic-gate * | | 277*0Sstevel@tonic-gate * -------------------------------- 278*0Sstevel@tonic-gate * -------------------------------- 279*0Sstevel@tonic-gate * | | 280*0Sstevel@tonic-gate * | attribute itself | 281*0Sstevel@tonic-gate * | stored as normal tar | 282*0Sstevel@tonic-gate * | or cpio data with | 283*0Sstevel@tonic-gate * | special mode or | 284*0Sstevel@tonic-gate * | typeflag | 285*0Sstevel@tonic-gate * | | 286*0Sstevel@tonic-gate * -------------------------------- 287*0Sstevel@tonic-gate * 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate /* 291*0Sstevel@tonic-gate * xattrhead is a pointer to the xattr_hdr 292*0Sstevel@tonic-gate * 293*0Sstevel@tonic-gate * xattrp is a pointer to the xattr_buf structure 294*0Sstevel@tonic-gate * which contains the "pathing" steps to get to attributes 295*0Sstevel@tonic-gate * 296*0Sstevel@tonic-gate * xattr_linkp is a pointer to another xattr_buf structure that is 297*0Sstevel@tonic-gate * only used when an attribute is actually linked to another attribute 298*0Sstevel@tonic-gate * 299*0Sstevel@tonic-gate */ 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate static struct xattr_hdr *xattrhead; 302*0Sstevel@tonic-gate static struct xattr_buf *xattrp; 303*0Sstevel@tonic-gate static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */ 304*0Sstevel@tonic-gate static char *xattraname; /* attribute name */ 305*0Sstevel@tonic-gate static char *xattr_linkaname; /* attribute attribute is linked to */ 306*0Sstevel@tonic-gate static char Hiddendir; /* are we processing hidden xattr dir */ 307*0Sstevel@tonic-gate static char xattrbadhead; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* Was statically allocated tbuf[NBLOCK] */ 310*0Sstevel@tonic-gate static 311*0Sstevel@tonic-gate union hblock { 312*0Sstevel@tonic-gate char dummy[TBLOCK]; 313*0Sstevel@tonic-gate struct header { 314*0Sstevel@tonic-gate char name[NAMSIZ]; /* If non-null prefix, path is */ 315*0Sstevel@tonic-gate /* <prefix>/<name>; otherwise */ 316*0Sstevel@tonic-gate /* <name> */ 317*0Sstevel@tonic-gate char mode[8]; 318*0Sstevel@tonic-gate char uid[8]; 319*0Sstevel@tonic-gate char gid[8]; 320*0Sstevel@tonic-gate char size[12]; /* size of this extent if file split */ 321*0Sstevel@tonic-gate char mtime[12]; 322*0Sstevel@tonic-gate char chksum[8]; 323*0Sstevel@tonic-gate char typeflag; 324*0Sstevel@tonic-gate char linkname[NAMSIZ]; 325*0Sstevel@tonic-gate char magic[6]; 326*0Sstevel@tonic-gate char version[2]; 327*0Sstevel@tonic-gate char uname[32]; 328*0Sstevel@tonic-gate char gname[32]; 329*0Sstevel@tonic-gate char devmajor[8]; 330*0Sstevel@tonic-gate char devminor[8]; 331*0Sstevel@tonic-gate char prefix[PRESIZ]; /* Together with "name", the path of */ 332*0Sstevel@tonic-gate /* the file: <prefix>/<name> */ 333*0Sstevel@tonic-gate char extno; /* extent #, null if not split */ 334*0Sstevel@tonic-gate char extotal; /* total extents */ 335*0Sstevel@tonic-gate char efsize[10]; /* size of entire file */ 336*0Sstevel@tonic-gate } dbuf; 337*0Sstevel@tonic-gate } dblock, *tbuf, xhdr_buf; 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate static 340*0Sstevel@tonic-gate struct xtar_hdr { 341*0Sstevel@tonic-gate uid_t x_uid, /* Uid of file */ 342*0Sstevel@tonic-gate x_gid; /* Gid of file */ 343*0Sstevel@tonic-gate major_t x_devmajor; /* Device major node */ 344*0Sstevel@tonic-gate minor_t x_devminor; /* Device minor node */ 345*0Sstevel@tonic-gate off_t x_filesz; /* Length of file */ 346*0Sstevel@tonic-gate char *x_uname, /* Pointer to name of user */ 347*0Sstevel@tonic-gate *x_gname, /* Pointer to gid of user */ 348*0Sstevel@tonic-gate *x_linkpath, /* Path for a hard/symbolic link */ 349*0Sstevel@tonic-gate *x_path; /* Path of file */ 350*0Sstevel@tonic-gate timestruc_t x_mtime; /* Seconds and nanoseconds */ 351*0Sstevel@tonic-gate } Xtarhdr; 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate static 354*0Sstevel@tonic-gate struct gen_hdr { 355*0Sstevel@tonic-gate ulong_t g_mode; /* Mode of file */ 356*0Sstevel@tonic-gate uid_t g_uid, /* Uid of file */ 357*0Sstevel@tonic-gate g_gid; /* Gid of file */ 358*0Sstevel@tonic-gate off_t g_filesz; /* Length of file */ 359*0Sstevel@tonic-gate time_t g_mtime; /* Modification time */ 360*0Sstevel@tonic-gate uint_t g_cksum; /* Checksum of file */ 361*0Sstevel@tonic-gate ulong_t g_devmajor, /* File system of file */ 362*0Sstevel@tonic-gate g_devminor; /* Major/minor of special files */ 363*0Sstevel@tonic-gate } Gen; 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate static 366*0Sstevel@tonic-gate struct linkbuf { 367*0Sstevel@tonic-gate ino_t inum; 368*0Sstevel@tonic-gate dev_t devnum; 369*0Sstevel@tonic-gate int count; 370*0Sstevel@tonic-gate char pathname[MAXNAM+1]; /* added 1 for last NULL */ 371*0Sstevel@tonic-gate char attrname[MAXNAM+1]; 372*0Sstevel@tonic-gate struct linkbuf *nextp; 373*0Sstevel@tonic-gate } *ihead; 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate /* see comments before build_table() */ 376*0Sstevel@tonic-gate #define TABLE_SIZE 512 377*0Sstevel@tonic-gate struct file_list { 378*0Sstevel@tonic-gate char *name; /* Name of file to {in,ex}clude */ 379*0Sstevel@tonic-gate struct file_list *next; /* Linked list */ 380*0Sstevel@tonic-gate }; 381*0Sstevel@tonic-gate static struct file_list *exclude_tbl[TABLE_SIZE], 382*0Sstevel@tonic-gate *include_tbl[TABLE_SIZE]; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate static int append_secattr(char **, int *, int, aclent_t *, char); 385*0Sstevel@tonic-gate static void write_ancillary(union hblock *, char *, int, char); 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate static void add_file_to_table(struct file_list *table[], char *str); 388*0Sstevel@tonic-gate static void assert_string(char *s, char *msg); 389*0Sstevel@tonic-gate static int istape(int fd, int type); 390*0Sstevel@tonic-gate static void backtape(void); 391*0Sstevel@tonic-gate static void build_table(struct file_list *table[], char *file); 392*0Sstevel@tonic-gate static void check_prefix(char **namep, char **dirp, char **compp); 393*0Sstevel@tonic-gate static void closevol(void); 394*0Sstevel@tonic-gate static void copy(void *dst, void *src); 395*0Sstevel@tonic-gate static int convtoreg(off_t); 396*0Sstevel@tonic-gate static void delete_target(int fd, char *namep); 397*0Sstevel@tonic-gate static void doDirTimes(char *name, timestruc_t modTime); 398*0Sstevel@tonic-gate static void done(int n); 399*0Sstevel@tonic-gate static void dorep(char *argv[]); 400*0Sstevel@tonic-gate #ifdef _iBCS2 401*0Sstevel@tonic-gate static void dotable(char *argv[], int cnt); 402*0Sstevel@tonic-gate static void doxtract(char *argv[], int cnt); 403*0Sstevel@tonic-gate #else 404*0Sstevel@tonic-gate static void dotable(char *argv[]); 405*0Sstevel@tonic-gate static void doxtract(char *argv[]); 406*0Sstevel@tonic-gate #endif 407*0Sstevel@tonic-gate static void fatal(char *format, ...); 408*0Sstevel@tonic-gate static void vperror(int exit_status, char *fmt, ...); 409*0Sstevel@tonic-gate static void flushtape(void); 410*0Sstevel@tonic-gate static void getdir(void); 411*0Sstevel@tonic-gate static void *getmem(size_t); 412*0Sstevel@tonic-gate static void longt(struct stat *st, char aclchar); 413*0Sstevel@tonic-gate static int makeDir(char *name); 414*0Sstevel@tonic-gate static void mterr(char *operation, int i, int exitcode); 415*0Sstevel@tonic-gate static void newvol(void); 416*0Sstevel@tonic-gate static void passtape(void); 417*0Sstevel@tonic-gate static void putempty(blkcnt_t n); 418*0Sstevel@tonic-gate static int putfile(char *longname, char *shortname, char *parent, 419*0Sstevel@tonic-gate int filetype, int lev, int symlink_lev); 420*0Sstevel@tonic-gate static void readtape(char *buffer); 421*0Sstevel@tonic-gate static void seekdisk(blkcnt_t blocks); 422*0Sstevel@tonic-gate static void setPathTimes(int dirfd, char *path, timestruc_t modTime); 423*0Sstevel@tonic-gate static void splitfile(char *longname, int ifd, char *name, 424*0Sstevel@tonic-gate char *prefix, int filetype); 425*0Sstevel@tonic-gate static void tomodes(struct stat *sp); 426*0Sstevel@tonic-gate static void usage(void); 427*0Sstevel@tonic-gate static void xblocks(off_t bytes, int ofile); 428*0Sstevel@tonic-gate static void xsfile(int ofd); 429*0Sstevel@tonic-gate static void resugname(int dirfd, char *name, int symflag); 430*0Sstevel@tonic-gate static int bcheck(char *bstr); 431*0Sstevel@tonic-gate static int checkdir(char *name); 432*0Sstevel@tonic-gate static int checksum(union hblock *dblockp); 433*0Sstevel@tonic-gate #ifdef EUC 434*0Sstevel@tonic-gate static int checksum_signed(union hblock *dblockp); 435*0Sstevel@tonic-gate #endif /* EUC */ 436*0Sstevel@tonic-gate static int checkupdate(char *arg); 437*0Sstevel@tonic-gate static int checkw(char c, char *name); 438*0Sstevel@tonic-gate static int cmp(char *b, char *s, int n); 439*0Sstevel@tonic-gate static int defset(char *arch); 440*0Sstevel@tonic-gate static int endtape(void); 441*0Sstevel@tonic-gate static int is_in_table(struct file_list *table[], char *str); 442*0Sstevel@tonic-gate static int notsame(void); 443*0Sstevel@tonic-gate static int is_prefix(char *s1, char *s2); 444*0Sstevel@tonic-gate static int response(void); 445*0Sstevel@tonic-gate static int build_dblock(const char *, const char *, const char, 446*0Sstevel@tonic-gate const int filetype, const struct stat *, const dev_t, const char *); 447*0Sstevel@tonic-gate static wchar_t yesnoresponse(void); 448*0Sstevel@tonic-gate static unsigned int hash(char *str); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate #ifdef _iBCS2 451*0Sstevel@tonic-gate static void initarg(char *argv[], char *file); 452*0Sstevel@tonic-gate static char *nextarg(); 453*0Sstevel@tonic-gate #endif 454*0Sstevel@tonic-gate static blkcnt_t kcheck(char *kstr); 455*0Sstevel@tonic-gate static off_t bsrch(char *s, int n, off_t l, off_t h); 456*0Sstevel@tonic-gate static void onintr(int sig); 457*0Sstevel@tonic-gate static void onquit(int sig); 458*0Sstevel@tonic-gate static void onhup(int sig); 459*0Sstevel@tonic-gate static uid_t getuidbyname(char *); 460*0Sstevel@tonic-gate static gid_t getgidbyname(char *); 461*0Sstevel@tonic-gate static char *getname(gid_t); 462*0Sstevel@tonic-gate static char *getgroup(gid_t); 463*0Sstevel@tonic-gate static int checkf(char *name, int mode, int howmuch); 464*0Sstevel@tonic-gate static int writetbuf(char *buffer, int n); 465*0Sstevel@tonic-gate static int wantit(char *argv[], char **namep, char **dirp, char **comp); 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate static int get_xdata(void); 468*0Sstevel@tonic-gate static void gen_num(const char *keyword, const u_longlong_t number); 469*0Sstevel@tonic-gate static void gen_date(const char *keyword, const timestruc_t time_value); 470*0Sstevel@tonic-gate static void gen_string(const char *keyword, const char *value); 471*0Sstevel@tonic-gate static void get_xtime(char *value, timestruc_t *xtime); 472*0Sstevel@tonic-gate static int chk_path_build(char *name, char *longname, char *linkname, 473*0Sstevel@tonic-gate char *prefix, char type, int filetype); 474*0Sstevel@tonic-gate static int gen_utf8_names(const char *filename); 475*0Sstevel@tonic-gate static int utf8_local(char *option, char **Xhdr_ptrptr, char *target, 476*0Sstevel@tonic-gate const char *src, int max_val); 477*0Sstevel@tonic-gate static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src, 478*0Sstevel@tonic-gate iconv_t iconv_cd, int xhdrflg, int max_val); 479*0Sstevel@tonic-gate static int c_utf8(char *target, const char *source); 480*0Sstevel@tonic-gate static int getstat(int dirfd, char *longname, char *shortname); 481*0Sstevel@tonic-gate static void xattrs_put(char *, char *, char *); 482*0Sstevel@tonic-gate static void prepare_xattr(char **, char *, char *, 483*0Sstevel@tonic-gate char, struct linkbuf *, int *); 484*0Sstevel@tonic-gate static int put_link(char *name, char *longname, char *component, char *prefix, 485*0Sstevel@tonic-gate int filetype, char typeflag); 486*0Sstevel@tonic-gate static int put_extra_attributes(char *longname, char *shortname, 487*0Sstevel@tonic-gate char *prefix, int filetype, char typeflag); 488*0Sstevel@tonic-gate static int put_xattr_hdr(char *longname, char *shortname, char *prefix, 489*0Sstevel@tonic-gate int typeflag, int filetype, struct linkbuf *lp); 490*0Sstevel@tonic-gate static int read_xattr_hdr(); 491*0Sstevel@tonic-gate static void get_parent(char *path, char *dir); 492*0Sstevel@tonic-gate static char *get_component(char *path); 493*0Sstevel@tonic-gate static int retry_attrdir_open(char *name); 494*0Sstevel@tonic-gate static char *skipslashes(char *string, char *start); 495*0Sstevel@tonic-gate static void chop_endslashes(char *path); 496*0Sstevel@tonic-gate static struct stat stbuf; 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate static int checkflag = 0; 499*0Sstevel@tonic-gate #ifdef _iBCS2 500*0Sstevel@tonic-gate static int Fileflag; 501*0Sstevel@tonic-gate char *sysv3_env; 502*0Sstevel@tonic-gate #endif 503*0Sstevel@tonic-gate static int Xflag, Fflag, iflag, hflag, Bflag, Iflag; 504*0Sstevel@tonic-gate static int rflag, xflag, vflag, tflag, mt, cflag, mflag, pflag; 505*0Sstevel@tonic-gate static int uflag; 506*0Sstevel@tonic-gate static int eflag, errflag, qflag; 507*0Sstevel@tonic-gate static int oflag; 508*0Sstevel@tonic-gate static int bflag, kflag, Aflag; 509*0Sstevel@tonic-gate static int Pflag; /* POSIX conformant archive */ 510*0Sstevel@tonic-gate static int Eflag; /* Allow files greater than 8GB */ 511*0Sstevel@tonic-gate static int atflag; /* traverse extended attributes */ 512*0Sstevel@tonic-gate static int Dflag; /* Data change flag */ 513*0Sstevel@tonic-gate static int term, chksum, wflag, 514*0Sstevel@tonic-gate first = TRUE, defaults_used = FALSE, linkerrok; 515*0Sstevel@tonic-gate static blkcnt_t recno; 516*0Sstevel@tonic-gate static int freemem = 1; 517*0Sstevel@tonic-gate static int nblock = NBLOCK; 518*0Sstevel@tonic-gate static int Errflg = 0; 519*0Sstevel@tonic-gate static int exitflag = 0; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate static dev_t mt_dev; /* device containing output file */ 522*0Sstevel@tonic-gate static ino_t mt_ino; /* inode number of output file */ 523*0Sstevel@tonic-gate static int mt_devtype; /* dev type of archive, from stat structure */ 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate static int update = 1; /* for `open' call */ 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate static off_t low; 528*0Sstevel@tonic-gate static off_t high; 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate static FILE *tfile; 531*0Sstevel@tonic-gate static FILE *vfile = stdout; 532*0Sstevel@tonic-gate static char tname[] = "/tmp/tarXXXXXX"; 533*0Sstevel@tonic-gate static char archive[] = "archive0="; 534*0Sstevel@tonic-gate static char *Xfile; 535*0Sstevel@tonic-gate static char *usefile; 536*0Sstevel@tonic-gate static char *Filefile; 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate static int mulvol; /* multi-volume option selected */ 539*0Sstevel@tonic-gate static blkcnt_t blocklim; /* number of blocks to accept per volume */ 540*0Sstevel@tonic-gate static blkcnt_t tapepos; /* current block number to be written */ 541*0Sstevel@tonic-gate static int NotTape; /* true if tape is a disk */ 542*0Sstevel@tonic-gate static int dumping; /* true if writing a tape or other archive */ 543*0Sstevel@tonic-gate static int extno; /* number of extent: starts at 1 */ 544*0Sstevel@tonic-gate static int extotal; /* total extents in this file */ 545*0Sstevel@tonic-gate static off_t extsize; /* size of current extent during extraction */ 546*0Sstevel@tonic-gate static ushort_t Oumask = 0; /* old umask value */ 547*0Sstevel@tonic-gate static int is_posix; /* true if archive we're reading is POSIX-conformant */ 548*0Sstevel@tonic-gate static const char *magic_type = "ustar"; 549*0Sstevel@tonic-gate static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */ 550*0Sstevel@tonic-gate static char *xrec_ptr; 551*0Sstevel@tonic-gate static off_t xrec_offset = 0; 552*0Sstevel@tonic-gate static int Xhdrflag; 553*0Sstevel@tonic-gate static int charset_type = 0; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate static u_longlong_t xhdr_flgs; /* Bits set determine which items */ 556*0Sstevel@tonic-gate /* need to be in extended header. */ 557*0Sstevel@tonic-gate #define _X_DEVMAJOR 0x1 558*0Sstevel@tonic-gate #define _X_DEVMINOR 0x2 559*0Sstevel@tonic-gate #define _X_GID 0x4 560*0Sstevel@tonic-gate #define _X_GNAME 0x8 561*0Sstevel@tonic-gate #define _X_LINKPATH 0x10 562*0Sstevel@tonic-gate #define _X_PATH 0x20 563*0Sstevel@tonic-gate #define _X_SIZE 0x40 564*0Sstevel@tonic-gate #define _X_UID 0x80 565*0Sstevel@tonic-gate #define _X_UNAME 0x100 566*0Sstevel@tonic-gate #define _X_ATIME 0x200 567*0Sstevel@tonic-gate #define _X_CTIME 0x400 568*0Sstevel@tonic-gate #define _X_MTIME 0x800 569*0Sstevel@tonic-gate #define _X_LAST 0x40000000 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4) 572*0Sstevel@tonic-gate #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4) 573*0Sstevel@tonic-gate #define LONG_MAX_DIGITS (10 * sizeof (long) / 4) 574*0Sstevel@tonic-gate #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4) 575*0Sstevel@tonic-gate /* 576*0Sstevel@tonic-gate * UTF_8 encoding requires more space than the current codeset equivalent. 577*0Sstevel@tonic-gate * Currently a factor of 2-3 would suffice, but it is possible for a factor 578*0Sstevel@tonic-gate * of 6 to be needed in the future, so for saftey, we use that here. 579*0Sstevel@tonic-gate */ 580*0Sstevel@tonic-gate #define UTF_8_FACTOR 6 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate static u_longlong_t xhdr_count = 0; 583*0Sstevel@tonic-gate static char xhdr_dirname[PRESIZ + 1]; 584*0Sstevel@tonic-gate static char pidchars[PID_MAX_DIGITS + 1]; 585*0Sstevel@tonic-gate static char *tchar = ""; /* null linkpath */ 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate static char local_path[UTF_8_FACTOR * PATH_MAX + 1]; 588*0Sstevel@tonic-gate static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1]; 589*0Sstevel@tonic-gate static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1]; 590*0Sstevel@tonic-gate static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1]; 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* 593*0Sstevel@tonic-gate * The following mechanism is provided to allow us to debug tar in complicated 594*0Sstevel@tonic-gate * situations, like when it is part of a pipe. The idea is that you compile 595*0Sstevel@tonic-gate * with -DWAITAROUND defined, and then add the 'z' function modifier to the 596*0Sstevel@tonic-gate * target tar invocation, eg. "tar czf tarfile file". If stderr is available, 597*0Sstevel@tonic-gate * it will tell you to which pid to attach the debugger; otherwise, use ps to 598*0Sstevel@tonic-gate * find it. Attach to the process from the debugger, and, *PRESTO*, you are 599*0Sstevel@tonic-gate * there! 600*0Sstevel@tonic-gate * 601*0Sstevel@tonic-gate * Simply assign "waitaround = 0" once you attach to the process, and then 602*0Sstevel@tonic-gate * proceed from there as usual. 603*0Sstevel@tonic-gate */ 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate #ifdef WAITAROUND 606*0Sstevel@tonic-gate int waitaround = 0; /* wait for rendezvous with the debugger */ 607*0Sstevel@tonic-gate #endif 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate int 611*0Sstevel@tonic-gate main(int argc, char *argv[]) 612*0Sstevel@tonic-gate { 613*0Sstevel@tonic-gate char *cp; 614*0Sstevel@tonic-gate char *tmpdirp; 615*0Sstevel@tonic-gate pid_t thispid; 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate #ifdef _iBCS2 618*0Sstevel@tonic-gate int tbl_cnt = 0; 619*0Sstevel@tonic-gate sysv3_env = getenv("SYSV3"); 620*0Sstevel@tonic-gate #endif 621*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 622*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 623*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 624*0Sstevel@tonic-gate #endif 625*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 626*0Sstevel@tonic-gate if (argc < 2) 627*0Sstevel@tonic-gate usage(); 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate tfile = NULL; 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate /* 632*0Sstevel@tonic-gate * For XPG4 compatibility, we must be able to accept the "--" 633*0Sstevel@tonic-gate * argument normally recognized by getopt; it is used to delimit 634*0Sstevel@tonic-gate * the end opt the options section, and so can only appear in 635*0Sstevel@tonic-gate * the position of the first argument. We simply skip it. 636*0Sstevel@tonic-gate */ 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate if (strcmp(argv[1], "--") == 0) { 639*0Sstevel@tonic-gate argv++; 640*0Sstevel@tonic-gate argc--; 641*0Sstevel@tonic-gate if (argc < 3) 642*0Sstevel@tonic-gate usage(); 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate argv[argc] = NULL; 646*0Sstevel@tonic-gate argv++; 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* 649*0Sstevel@tonic-gate * Set up default values. 650*0Sstevel@tonic-gate * Search the operand string looking for the first digit or an 'f'. 651*0Sstevel@tonic-gate * If you find a digit, use the 'archive#' entry in DEF_FILE. 652*0Sstevel@tonic-gate * If 'f' is given, bypass looking in DEF_FILE altogether. 653*0Sstevel@tonic-gate * If no digit or 'f' is given, still look in DEF_FILE but use '0'. 654*0Sstevel@tonic-gate */ 655*0Sstevel@tonic-gate if ((usefile = getenv("TAPE")) == (char *)NULL) { 656*0Sstevel@tonic-gate for (cp = *argv; *cp; ++cp) 657*0Sstevel@tonic-gate if (isdigit(*cp) || *cp == 'f') 658*0Sstevel@tonic-gate break; 659*0Sstevel@tonic-gate if (*cp != 'f') { 660*0Sstevel@tonic-gate archive[7] = (*cp)? *cp: '0'; 661*0Sstevel@tonic-gate if (!(defaults_used = defset(archive))) { 662*0Sstevel@tonic-gate usefile = NULL; 663*0Sstevel@tonic-gate nblock = 1; 664*0Sstevel@tonic-gate blocklim = 0; 665*0Sstevel@tonic-gate NotTape = 0; 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate } 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate for (cp = *argv++; *cp; cp++) 671*0Sstevel@tonic-gate switch (*cp) { 672*0Sstevel@tonic-gate #ifdef WAITAROUND 673*0Sstevel@tonic-gate case 'z': 674*0Sstevel@tonic-gate /* rendezvous with the debugger */ 675*0Sstevel@tonic-gate waitaround = 1; 676*0Sstevel@tonic-gate break; 677*0Sstevel@tonic-gate #endif 678*0Sstevel@tonic-gate case 'f': 679*0Sstevel@tonic-gate assert_string(*argv, gettext( 680*0Sstevel@tonic-gate "tar: tarfile must be specified with 'f' " 681*0Sstevel@tonic-gate "function modifier\n")); 682*0Sstevel@tonic-gate usefile = *argv++; 683*0Sstevel@tonic-gate break; 684*0Sstevel@tonic-gate case 'F': 685*0Sstevel@tonic-gate #ifdef _iBCS2 686*0Sstevel@tonic-gate if (sysv3_env) { 687*0Sstevel@tonic-gate assert_string(*argv, gettext( 688*0Sstevel@tonic-gate "tar: 'F' requires a file name\n")); 689*0Sstevel@tonic-gate Filefile = *argv++; 690*0Sstevel@tonic-gate Fileflag++; 691*0Sstevel@tonic-gate } else 692*0Sstevel@tonic-gate #endif /* _iBCS2 */ 693*0Sstevel@tonic-gate Fflag++; 694*0Sstevel@tonic-gate break; 695*0Sstevel@tonic-gate case 'c': 696*0Sstevel@tonic-gate cflag++; 697*0Sstevel@tonic-gate rflag++; 698*0Sstevel@tonic-gate update = 1; 699*0Sstevel@tonic-gate break; 700*0Sstevel@tonic-gate #if defined(O_XATTR) 701*0Sstevel@tonic-gate case '@': 702*0Sstevel@tonic-gate atflag++; 703*0Sstevel@tonic-gate break; 704*0Sstevel@tonic-gate #endif 705*0Sstevel@tonic-gate case 'u': 706*0Sstevel@tonic-gate uflag++; /* moved code after signals caught */ 707*0Sstevel@tonic-gate rflag++; 708*0Sstevel@tonic-gate update = 2; 709*0Sstevel@tonic-gate break; 710*0Sstevel@tonic-gate case 'r': 711*0Sstevel@tonic-gate rflag++; 712*0Sstevel@tonic-gate update = 2; 713*0Sstevel@tonic-gate break; 714*0Sstevel@tonic-gate case 'v': 715*0Sstevel@tonic-gate vflag++; 716*0Sstevel@tonic-gate break; 717*0Sstevel@tonic-gate case 'w': 718*0Sstevel@tonic-gate wflag++; 719*0Sstevel@tonic-gate break; 720*0Sstevel@tonic-gate case 'x': 721*0Sstevel@tonic-gate xflag++; 722*0Sstevel@tonic-gate break; 723*0Sstevel@tonic-gate case 'X': 724*0Sstevel@tonic-gate assert_string(*argv, gettext( 725*0Sstevel@tonic-gate "tar: exclude file must be specified with 'X' " 726*0Sstevel@tonic-gate "function modifier\n")); 727*0Sstevel@tonic-gate Xflag = 1; 728*0Sstevel@tonic-gate Xfile = *argv++; 729*0Sstevel@tonic-gate build_table(exclude_tbl, Xfile); 730*0Sstevel@tonic-gate break; 731*0Sstevel@tonic-gate case 't': 732*0Sstevel@tonic-gate tflag++; 733*0Sstevel@tonic-gate break; 734*0Sstevel@tonic-gate case 'm': 735*0Sstevel@tonic-gate mflag++; 736*0Sstevel@tonic-gate break; 737*0Sstevel@tonic-gate case 'p': 738*0Sstevel@tonic-gate pflag++; 739*0Sstevel@tonic-gate break; 740*0Sstevel@tonic-gate case 'D': 741*0Sstevel@tonic-gate Dflag++; 742*0Sstevel@tonic-gate break; 743*0Sstevel@tonic-gate case '-': 744*0Sstevel@tonic-gate /* ignore this silently */ 745*0Sstevel@tonic-gate break; 746*0Sstevel@tonic-gate case '0': /* numeric entries used only for defaults */ 747*0Sstevel@tonic-gate case '1': 748*0Sstevel@tonic-gate case '2': 749*0Sstevel@tonic-gate case '3': 750*0Sstevel@tonic-gate case '4': 751*0Sstevel@tonic-gate case '5': 752*0Sstevel@tonic-gate case '6': 753*0Sstevel@tonic-gate case '7': 754*0Sstevel@tonic-gate break; 755*0Sstevel@tonic-gate case 'b': 756*0Sstevel@tonic-gate assert_string(*argv, gettext( 757*0Sstevel@tonic-gate "tar: blocking factor must be specified " 758*0Sstevel@tonic-gate "with 'b' function modifier\n")); 759*0Sstevel@tonic-gate bflag++; 760*0Sstevel@tonic-gate nblock = bcheck(*argv++); 761*0Sstevel@tonic-gate break; 762*0Sstevel@tonic-gate case 'q': 763*0Sstevel@tonic-gate qflag++; 764*0Sstevel@tonic-gate break; 765*0Sstevel@tonic-gate case 'k': 766*0Sstevel@tonic-gate assert_string(*argv, gettext( 767*0Sstevel@tonic-gate "tar: size value must be specified with 'k' " 768*0Sstevel@tonic-gate "function modifier\n")); 769*0Sstevel@tonic-gate kflag++; 770*0Sstevel@tonic-gate blocklim = kcheck(*argv++); 771*0Sstevel@tonic-gate break; 772*0Sstevel@tonic-gate case 'n': /* not a magtape (instead of 'k') */ 773*0Sstevel@tonic-gate NotTape++; /* assume non-magtape */ 774*0Sstevel@tonic-gate break; 775*0Sstevel@tonic-gate case 'l': 776*0Sstevel@tonic-gate linkerrok++; 777*0Sstevel@tonic-gate break; 778*0Sstevel@tonic-gate case 'e': 779*0Sstevel@tonic-gate #ifdef _iBCS2 780*0Sstevel@tonic-gate /* If sysv3 IS set, don't be as verbose */ 781*0Sstevel@tonic-gate if (!sysv3_env) 782*0Sstevel@tonic-gate #endif /* _iBCS2 */ 783*0Sstevel@tonic-gate errflag++; 784*0Sstevel@tonic-gate eflag++; 785*0Sstevel@tonic-gate break; 786*0Sstevel@tonic-gate case 'o': 787*0Sstevel@tonic-gate oflag++; 788*0Sstevel@tonic-gate break; 789*0Sstevel@tonic-gate case 'h': 790*0Sstevel@tonic-gate hflag++; 791*0Sstevel@tonic-gate break; 792*0Sstevel@tonic-gate case 'i': 793*0Sstevel@tonic-gate iflag++; 794*0Sstevel@tonic-gate break; 795*0Sstevel@tonic-gate case 'B': 796*0Sstevel@tonic-gate Bflag++; 797*0Sstevel@tonic-gate break; 798*0Sstevel@tonic-gate case 'P': 799*0Sstevel@tonic-gate Pflag++; 800*0Sstevel@tonic-gate break; 801*0Sstevel@tonic-gate case 'E': 802*0Sstevel@tonic-gate Eflag++; 803*0Sstevel@tonic-gate Pflag++; /* Only POSIX archive made */ 804*0Sstevel@tonic-gate break; 805*0Sstevel@tonic-gate default: 806*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 807*0Sstevel@tonic-gate "tar: %c: unknown function modifier\n"), *cp); 808*0Sstevel@tonic-gate usage(); 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate #ifdef _iBCS2 812*0Sstevel@tonic-gate if (Xflag && Fileflag) { 813*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 814*0Sstevel@tonic-gate "tar: specify only one of X or F.\n")); 815*0Sstevel@tonic-gate usage(); 816*0Sstevel@tonic-gate } 817*0Sstevel@tonic-gate #endif /* _iBCS2 */ 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate if (!rflag && !xflag && !tflag) 820*0Sstevel@tonic-gate usage(); 821*0Sstevel@tonic-gate if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) { 822*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 823*0Sstevel@tonic-gate "tar: specify only one of [ctxru].\n")); 824*0Sstevel@tonic-gate usage(); 825*0Sstevel@tonic-gate } 826*0Sstevel@tonic-gate if (cflag && *argv == NULL && Filefile == NULL) 827*0Sstevel@tonic-gate fatal(gettext("Missing filenames")); 828*0Sstevel@tonic-gate if (usefile == NULL) 829*0Sstevel@tonic-gate fatal(gettext("device argument required")); 830*0Sstevel@tonic-gate 831*0Sstevel@tonic-gate /* alloc a buffer of the right size */ 832*0Sstevel@tonic-gate if ((tbuf = (union hblock *) 833*0Sstevel@tonic-gate calloc(sizeof (union hblock) * nblock, sizeof (char))) == 834*0Sstevel@tonic-gate (union hblock *)NULL) { 835*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 836*0Sstevel@tonic-gate "tar: cannot allocate physio buffer\n")); 837*0Sstevel@tonic-gate exit(1); 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate if ((xrec_ptr = malloc(xrec_size)) == NULL) { 841*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 842*0Sstevel@tonic-gate "tar: cannot allocate extended header buffer\n")); 843*0Sstevel@tonic-gate exit(1); 844*0Sstevel@tonic-gate } 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate #ifdef WAITAROUND 847*0Sstevel@tonic-gate if (waitaround) { 848*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Rendezvous with tar on pid" 849*0Sstevel@tonic-gate " %d\n"), getpid()); 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate while (waitaround) { 852*0Sstevel@tonic-gate (void) sleep(10); 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate #endif 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate thispid = getpid(); 858*0Sstevel@tonic-gate (void) sprintf(pidchars, "%ld", thispid); 859*0Sstevel@tonic-gate thispid = strlen(pidchars); 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL) 862*0Sstevel@tonic-gate (void) strcpy(xhdr_dirname, "/tmp"); 863*0Sstevel@tonic-gate else { 864*0Sstevel@tonic-gate /* 865*0Sstevel@tonic-gate * Make sure that dir is no longer than what can 866*0Sstevel@tonic-gate * fit in the prefix part of the header. 867*0Sstevel@tonic-gate */ 868*0Sstevel@tonic-gate if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) { 869*0Sstevel@tonic-gate (void) strcpy(xhdr_dirname, "/tmp"); 870*0Sstevel@tonic-gate if ((vflag > 0) && (Eflag > 0)) 871*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 872*0Sstevel@tonic-gate "Ignoring TMPDIR\n")); 873*0Sstevel@tonic-gate } else 874*0Sstevel@tonic-gate (void) strcpy(xhdr_dirname, tmpdirp); 875*0Sstevel@tonic-gate } 876*0Sstevel@tonic-gate (void) strcat(xhdr_dirname, "/PaxHeaders."); 877*0Sstevel@tonic-gate (void) strcat(xhdr_dirname, pidchars); 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate if (rflag) { 880*0Sstevel@tonic-gate if (cflag && tfile != NULL) 881*0Sstevel@tonic-gate usage(); 882*0Sstevel@tonic-gate if (signal(SIGINT, SIG_IGN) != SIG_IGN) 883*0Sstevel@tonic-gate (void) signal(SIGINT, onintr); 884*0Sstevel@tonic-gate if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 885*0Sstevel@tonic-gate (void) signal(SIGHUP, onhup); 886*0Sstevel@tonic-gate if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 887*0Sstevel@tonic-gate (void) signal(SIGQUIT, onquit); 888*0Sstevel@tonic-gate if (uflag) { 889*0Sstevel@tonic-gate int tnum; 890*0Sstevel@tonic-gate if ((tnum = mkstemp(tname)) == -1) 891*0Sstevel@tonic-gate vperror(1, "%s", tname); 892*0Sstevel@tonic-gate if ((tfile = fdopen(tnum, "w")) == NULL) 893*0Sstevel@tonic-gate vperror(1, "%s", tname); 894*0Sstevel@tonic-gate } 895*0Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) { 896*0Sstevel@tonic-gate if (cflag == 0) 897*0Sstevel@tonic-gate fatal(gettext( 898*0Sstevel@tonic-gate "can only create standard output archives.")); 899*0Sstevel@tonic-gate vfile = stderr; 900*0Sstevel@tonic-gate mt = dup(1); 901*0Sstevel@tonic-gate ++bflag; 902*0Sstevel@tonic-gate } else { 903*0Sstevel@tonic-gate if (cflag) 904*0Sstevel@tonic-gate mt = open(usefile, 905*0Sstevel@tonic-gate O_RDWR|O_CREAT|O_TRUNC, 0666); 906*0Sstevel@tonic-gate else 907*0Sstevel@tonic-gate mt = open(usefile, O_RDWR); 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate if (mt < 0) { 910*0Sstevel@tonic-gate if (cflag == 0 || (mt = creat(usefile, 0666)) 911*0Sstevel@tonic-gate < 0) 912*0Sstevel@tonic-gate vperror(1, "%s", usefile); 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate } 915*0Sstevel@tonic-gate /* Get inode and device number of output file */ 916*0Sstevel@tonic-gate (void) fstat(mt, &stbuf); 917*0Sstevel@tonic-gate mt_ino = stbuf.st_ino; 918*0Sstevel@tonic-gate mt_dev = stbuf.st_dev; 919*0Sstevel@tonic-gate mt_devtype = stbuf.st_mode & S_IFMT; 920*0Sstevel@tonic-gate NotTape = !istape(mt, mt_devtype); 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate if (rflag && !cflag && (mt_devtype == S_IFIFO)) 923*0Sstevel@tonic-gate fatal(gettext("cannot append to pipe or FIFO.")); 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate if (Aflag && vflag) 926*0Sstevel@tonic-gate (void) printf( 927*0Sstevel@tonic-gate gettext("Suppressing absolute pathnames\n")); 928*0Sstevel@tonic-gate dorep(argv); 929*0Sstevel@tonic-gate } else if (xflag || tflag) { 930*0Sstevel@tonic-gate /* 931*0Sstevel@tonic-gate * for each argument, check to see if there is a "-I file" pair. 932*0Sstevel@tonic-gate * if so, move the 3rd argument into "-I"'s place, build_table() 933*0Sstevel@tonic-gate * using "file"'s name and increment argc one (the second 934*0Sstevel@tonic-gate * increment appears in the for loop) which removes the two 935*0Sstevel@tonic-gate * args "-I" and "file" from the argument vector. 936*0Sstevel@tonic-gate */ 937*0Sstevel@tonic-gate for (argc = 0; argv[argc]; argc++) { 938*0Sstevel@tonic-gate if (strcmp(argv[argc], "-I") == 0) { 939*0Sstevel@tonic-gate if (!argv[argc+1]) { 940*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 941*0Sstevel@tonic-gate "tar: missing argument for -I flag\n")); 942*0Sstevel@tonic-gate done(2); 943*0Sstevel@tonic-gate } else { 944*0Sstevel@tonic-gate Iflag = 1; 945*0Sstevel@tonic-gate argv[argc] = argv[argc+2]; 946*0Sstevel@tonic-gate build_table(include_tbl, argv[++argc]); 947*0Sstevel@tonic-gate #ifdef _iBCS2 948*0Sstevel@tonic-gate if (Fileflag) { 949*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 950*0Sstevel@tonic-gate "tar: only one of I or F.\n")); 951*0Sstevel@tonic-gate usage(); 952*0Sstevel@tonic-gate } 953*0Sstevel@tonic-gate #endif /* _iBCS2 */ 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate } 956*0Sstevel@tonic-gate } 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) { 959*0Sstevel@tonic-gate mt = dup(0); 960*0Sstevel@tonic-gate ++bflag; 961*0Sstevel@tonic-gate /* try to recover from short reads when reading stdin */ 962*0Sstevel@tonic-gate ++Bflag; 963*0Sstevel@tonic-gate } else if ((mt = open(usefile, 0)) < 0) 964*0Sstevel@tonic-gate vperror(1, "%s", usefile); 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate if (xflag) { 967*0Sstevel@tonic-gate if (Aflag && vflag) 968*0Sstevel@tonic-gate (void) printf(gettext 969*0Sstevel@tonic-gate ("Suppressing absolute pathnames.\n")); 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate #ifdef _iBCS2 972*0Sstevel@tonic-gate doxtract(argv, tbl_cnt); 973*0Sstevel@tonic-gate #else 974*0Sstevel@tonic-gate doxtract(argv); 975*0Sstevel@tonic-gate #endif 976*0Sstevel@tonic-gate } else if (tflag) 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate #ifdef _iBCS2 979*0Sstevel@tonic-gate dotable(argv, tbl_cnt); 980*0Sstevel@tonic-gate #else 981*0Sstevel@tonic-gate dotable(argv); 982*0Sstevel@tonic-gate #endif 983*0Sstevel@tonic-gate } 984*0Sstevel@tonic-gate else 985*0Sstevel@tonic-gate usage(); 986*0Sstevel@tonic-gate 987*0Sstevel@tonic-gate done(Errflg); 988*0Sstevel@tonic-gate 989*0Sstevel@tonic-gate /* Not reached: keep compiler quiet */ 990*0Sstevel@tonic-gate return (1); 991*0Sstevel@tonic-gate } 992*0Sstevel@tonic-gate 993*0Sstevel@tonic-gate static void 994*0Sstevel@tonic-gate usage(void) 995*0Sstevel@tonic-gate { 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate #ifdef _iBCS2 998*0Sstevel@tonic-gate if (sysv3_env) { 999*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1000*0Sstevel@tonic-gate #if defined(O_XATTR) 1001*0Sstevel@tonic-gate "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqvw@[0-7]][bfFk][X...] " 1002*0Sstevel@tonic-gate #else 1003*0Sstevel@tonic-gate "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqvw[0-7]][bfFk][X...] " 1004*0Sstevel@tonic-gate #endif 1005*0Sstevel@tonic-gate "[blocksize] [tarfile] [filename] [size] [exclude-file...] " 1006*0Sstevel@tonic-gate "{file | -I include-file | -C directory file}...\n")); 1007*0Sstevel@tonic-gate } else 1008*0Sstevel@tonic-gate #endif /* _iBCS2 */ 1009*0Sstevel@tonic-gate { 1010*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1011*0Sstevel@tonic-gate #if defined(O_XATTR) 1012*0Sstevel@tonic-gate "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqvw@[0-7]][bfk][X...] " 1013*0Sstevel@tonic-gate #else 1014*0Sstevel@tonic-gate "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqvw[0-7]][bfk][X...] " 1015*0Sstevel@tonic-gate #endif 1016*0Sstevel@tonic-gate "[blocksize] [tarfile] [size] [exclude-file...] " 1017*0Sstevel@tonic-gate "{file | -I include-file | -C directory file}...\n")); 1018*0Sstevel@tonic-gate } 1019*0Sstevel@tonic-gate done(1); 1020*0Sstevel@tonic-gate } 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate /* 1023*0Sstevel@tonic-gate * dorep - do "replacements" 1024*0Sstevel@tonic-gate * 1025*0Sstevel@tonic-gate * Dorep is responsible for creating ('c'), appending ('r') 1026*0Sstevel@tonic-gate * and updating ('u'); 1027*0Sstevel@tonic-gate */ 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate static void 1030*0Sstevel@tonic-gate dorep(char *argv[]) 1031*0Sstevel@tonic-gate { 1032*0Sstevel@tonic-gate char *cp, *cp2, *p; 1033*0Sstevel@tonic-gate char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent; 1034*0Sstevel@tonic-gate char file[PATH_MAX*2], origdir[PATH_MAX+1]; 1035*0Sstevel@tonic-gate FILE *fp = (FILE *)NULL; 1036*0Sstevel@tonic-gate FILE *ff = (FILE *)NULL; 1037*0Sstevel@tonic-gate int archtype; 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate 1040*0Sstevel@tonic-gate if (!cflag) { 1041*0Sstevel@tonic-gate xhdr_flgs = 0; 1042*0Sstevel@tonic-gate getdir(); /* read header for next file */ 1043*0Sstevel@tonic-gate if (Xhdrflag > 0) { 1044*0Sstevel@tonic-gate if (!Eflag) 1045*0Sstevel@tonic-gate fatal(gettext("Archive contains extended" 1046*0Sstevel@tonic-gate " header. -E flag required.\n")); 1047*0Sstevel@tonic-gate (void) get_xdata(); /* Get extended header items */ 1048*0Sstevel@tonic-gate /* and regular header */ 1049*0Sstevel@tonic-gate } else { 1050*0Sstevel@tonic-gate if (Eflag) 1051*0Sstevel@tonic-gate fatal(gettext("Archive contains no extended" 1052*0Sstevel@tonic-gate " header. -E flag not allowed.\n")); 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate while (!endtape()) { /* changed from a do while */ 1055*0Sstevel@tonic-gate passtape(); /* skip the file data */ 1056*0Sstevel@tonic-gate if (term) 1057*0Sstevel@tonic-gate done(Errflg); /* received signal to stop */ 1058*0Sstevel@tonic-gate xhdr_flgs = 0; 1059*0Sstevel@tonic-gate getdir(); 1060*0Sstevel@tonic-gate if (Xhdrflag > 0) 1061*0Sstevel@tonic-gate (void) get_xdata(); 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate backtape(); /* was called by endtape */ 1064*0Sstevel@tonic-gate if (tfile != NULL) { 1065*0Sstevel@tonic-gate char buf[200]; 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate (void) sprintf(buf, "sort +0 -1 +1nr %s -o %s; awk '$1 " 1068*0Sstevel@tonic-gate "!= prev {print; prev=$1}' %s >%sX;mv %sX %s", 1069*0Sstevel@tonic-gate tname, tname, tname, tname, tname, tname); 1070*0Sstevel@tonic-gate (void) fflush(tfile); 1071*0Sstevel@tonic-gate (void) system(buf); 1072*0Sstevel@tonic-gate (void) freopen(tname, "r", tfile); 1073*0Sstevel@tonic-gate (void) fstat(fileno(tfile), &stbuf); 1074*0Sstevel@tonic-gate high = stbuf.st_size; 1075*0Sstevel@tonic-gate } 1076*0Sstevel@tonic-gate } 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate dumping = 1; 1079*0Sstevel@tonic-gate if (mulvol) { /* SP-1 */ 1080*0Sstevel@tonic-gate if (nblock && (blocklim%nblock) != 0) 1081*0Sstevel@tonic-gate fatal(gettext( 1082*0Sstevel@tonic-gate "Volume size not a multiple of block size.")); 1083*0Sstevel@tonic-gate blocklim -= 2; /* for trailer records */ 1084*0Sstevel@tonic-gate if (vflag) 1085*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("Volume ends at %" 1086*0Sstevel@tonic-gate FMT_blkcnt_t "K, blocking factor = %dK\n"), 1087*0Sstevel@tonic-gate K((blocklim - 1)), K(nblock)); 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate 1090*0Sstevel@tonic-gate #ifdef _iBCS2 1091*0Sstevel@tonic-gate if (Fileflag) { 1092*0Sstevel@tonic-gate if (Filefile != NULL) { 1093*0Sstevel@tonic-gate if ((ff = fopen(Filefile, "r")) == NULL) 1094*0Sstevel@tonic-gate vperror(0, "%s", Filefile); 1095*0Sstevel@tonic-gate } else { 1096*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1097*0Sstevel@tonic-gate "tar: F requires a file name.\n")); 1098*0Sstevel@tonic-gate usage(); 1099*0Sstevel@tonic-gate } 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate #endif /* _iBCS2 */ 1102*0Sstevel@tonic-gate 1103*0Sstevel@tonic-gate /* 1104*0Sstevel@tonic-gate * Save the original directory before it gets 1105*0Sstevel@tonic-gate * changed. 1106*0Sstevel@tonic-gate */ 1107*0Sstevel@tonic-gate if (getcwd(origdir, (PATH_MAX+1)) == NULL) { 1108*0Sstevel@tonic-gate vperror(0, gettext("A parent directory cannot be read")); 1109*0Sstevel@tonic-gate exit(1); 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate 1112*0Sstevel@tonic-gate (void) strcpy(wdir, origdir); 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate while ((*argv || fp || ff) && !term) { 1115*0Sstevel@tonic-gate if (fp || (strcmp(*argv, "-I") == 0)) { 1116*0Sstevel@tonic-gate #ifdef _iBCS2 1117*0Sstevel@tonic-gate if (Fileflag) { 1118*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1119*0Sstevel@tonic-gate "tar: only one of I or F.\n")); 1120*0Sstevel@tonic-gate usage(); 1121*0Sstevel@tonic-gate } 1122*0Sstevel@tonic-gate #endif /* _iBCS2 */ 1123*0Sstevel@tonic-gate if (fp == NULL) { 1124*0Sstevel@tonic-gate if (*++argv == NULL) 1125*0Sstevel@tonic-gate fatal(gettext( 1126*0Sstevel@tonic-gate "missing file name for -I flag.")); 1127*0Sstevel@tonic-gate else if ((fp = fopen(*argv++, "r")) == NULL) 1128*0Sstevel@tonic-gate vperror(0, "%s", argv[-1]); 1129*0Sstevel@tonic-gate continue; 1130*0Sstevel@tonic-gate } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) { 1131*0Sstevel@tonic-gate (void) fclose(fp); 1132*0Sstevel@tonic-gate fp = NULL; 1133*0Sstevel@tonic-gate continue; 1134*0Sstevel@tonic-gate } else { 1135*0Sstevel@tonic-gate cp = cp2 = file; 1136*0Sstevel@tonic-gate if ((p = strchr(cp2, '\n'))) 1137*0Sstevel@tonic-gate *p = 0; 1138*0Sstevel@tonic-gate } 1139*0Sstevel@tonic-gate } else if ((strcmp(*argv, "-C") == 0) && argv[1]) { 1140*0Sstevel@tonic-gate #ifdef _iBCS2 1141*0Sstevel@tonic-gate if (Fileflag) { 1142*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1143*0Sstevel@tonic-gate "tar: only one of F or C\n")); 1144*0Sstevel@tonic-gate usage(); 1145*0Sstevel@tonic-gate } 1146*0Sstevel@tonic-gate #endif /* _iBCS2 */ 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate if (chdir(*++argv) < 0) 1149*0Sstevel@tonic-gate vperror(0, gettext( 1150*0Sstevel@tonic-gate "can't change directories to %s"), *argv); 1151*0Sstevel@tonic-gate else 1152*0Sstevel@tonic-gate (void) getcwd(wdir, (sizeof (wdir))); 1153*0Sstevel@tonic-gate argv++; 1154*0Sstevel@tonic-gate continue; 1155*0Sstevel@tonic-gate #ifdef _iBCS2 1156*0Sstevel@tonic-gate } else if (Fileflag && (ff != NULL)) { 1157*0Sstevel@tonic-gate if ((fgets(file, PATH_MAX-1, ff)) == NULL) { 1158*0Sstevel@tonic-gate (void) fclose(ff); 1159*0Sstevel@tonic-gate ff = NULL; 1160*0Sstevel@tonic-gate continue; 1161*0Sstevel@tonic-gate } else { 1162*0Sstevel@tonic-gate cp = cp2 = file; 1163*0Sstevel@tonic-gate if (p = strchr(cp2, '\n')) 1164*0Sstevel@tonic-gate *p = 0; 1165*0Sstevel@tonic-gate } 1166*0Sstevel@tonic-gate #endif /* _iBCS2 */ 1167*0Sstevel@tonic-gate } else 1168*0Sstevel@tonic-gate cp = cp2 = strcpy(file, *argv++); 1169*0Sstevel@tonic-gate 1170*0Sstevel@tonic-gate /* 1171*0Sstevel@tonic-gate * point cp2 to the last '/' in file, but not 1172*0Sstevel@tonic-gate * to a trailing '/' 1173*0Sstevel@tonic-gate */ 1174*0Sstevel@tonic-gate for (; *cp; cp++) { 1175*0Sstevel@tonic-gate if (*cp == '/') { 1176*0Sstevel@tonic-gate while (*(cp+1) == '/') { 1177*0Sstevel@tonic-gate ++cp; 1178*0Sstevel@tonic-gate } 1179*0Sstevel@tonic-gate if (*(cp+1) != '\0') { 1180*0Sstevel@tonic-gate /* not trailing slash */ 1181*0Sstevel@tonic-gate cp2 = cp; 1182*0Sstevel@tonic-gate } 1183*0Sstevel@tonic-gate } 1184*0Sstevel@tonic-gate } 1185*0Sstevel@tonic-gate if (cp2 != file) { 1186*0Sstevel@tonic-gate *cp2 = '\0'; 1187*0Sstevel@tonic-gate if (chdir(file) < 0) { 1188*0Sstevel@tonic-gate vperror(0, gettext( 1189*0Sstevel@tonic-gate "can't change directories to %s"), file); 1190*0Sstevel@tonic-gate continue; 1191*0Sstevel@tonic-gate } 1192*0Sstevel@tonic-gate *cp2 = '/'; 1193*0Sstevel@tonic-gate cp2++; 1194*0Sstevel@tonic-gate } 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate parent = getcwd(tempdir, (sizeof (tempdir))); 1197*0Sstevel@tonic-gate archtype = putfile(file, cp2, parent, NORMAL_FILE, 1198*0Sstevel@tonic-gate LEV0, SYMLINK_LEV0); 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate #if defined(O_XATTR) 1201*0Sstevel@tonic-gate if (!exitflag) { 1202*0Sstevel@tonic-gate if (atflag && archtype == PUT_NOTAS_LINK) { 1203*0Sstevel@tonic-gate xattrs_put(file, cp2, parent); 1204*0Sstevel@tonic-gate } 1205*0Sstevel@tonic-gate } 1206*0Sstevel@tonic-gate #endif 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate if (chdir(origdir) < 0) 1209*0Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"), origdir); 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate if (exitflag) { 1212*0Sstevel@tonic-gate /* 1213*0Sstevel@tonic-gate * If e function modifier has been specified 1214*0Sstevel@tonic-gate * write the files (that are listed before the 1215*0Sstevel@tonic-gate * file causing the error) to tape. exitflag is 1216*0Sstevel@tonic-gate * used because only some of the error conditions 1217*0Sstevel@tonic-gate * in putfile() recognize the e function modifier. 1218*0Sstevel@tonic-gate */ 1219*0Sstevel@tonic-gate break; 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate putempty((blkcnt_t)2); 1224*0Sstevel@tonic-gate flushtape(); 1225*0Sstevel@tonic-gate closevol(); /* SP-1 */ 1226*0Sstevel@tonic-gate if (linkerrok == 1) 1227*0Sstevel@tonic-gate for (; ihead != NULL; ihead = ihead->nextp) { 1228*0Sstevel@tonic-gate if (ihead->count == 0) 1229*0Sstevel@tonic-gate continue; 1230*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1231*0Sstevel@tonic-gate "tar: missing links to %s\n"), ihead->pathname); 1232*0Sstevel@tonic-gate if (errflag) 1233*0Sstevel@tonic-gate done(1); 1234*0Sstevel@tonic-gate else 1235*0Sstevel@tonic-gate Errflg = 1; 1236*0Sstevel@tonic-gate } 1237*0Sstevel@tonic-gate } 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate /* 1241*0Sstevel@tonic-gate * endtape - check for tape at end 1242*0Sstevel@tonic-gate * 1243*0Sstevel@tonic-gate * endtape checks the entry in dblock.dbuf to see if its the 1244*0Sstevel@tonic-gate * special EOT entry. Endtape is usually called after getdir(). 1245*0Sstevel@tonic-gate * 1246*0Sstevel@tonic-gate * endtape used to call backtape; it no longer does, he who 1247*0Sstevel@tonic-gate * wants it backed up must call backtape himself 1248*0Sstevel@tonic-gate * RETURNS: 0 if not EOT, tape position unaffected 1249*0Sstevel@tonic-gate * 1 if EOT, tape position unaffected 1250*0Sstevel@tonic-gate */ 1251*0Sstevel@tonic-gate 1252*0Sstevel@tonic-gate static int 1253*0Sstevel@tonic-gate endtape(void) 1254*0Sstevel@tonic-gate { 1255*0Sstevel@tonic-gate if (dblock.dbuf.name[0] == '\0') { /* null header = EOT */ 1256*0Sstevel@tonic-gate return (1); 1257*0Sstevel@tonic-gate } else 1258*0Sstevel@tonic-gate return (0); 1259*0Sstevel@tonic-gate } 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate /* 1262*0Sstevel@tonic-gate * getdir - get directory entry from tar tape 1263*0Sstevel@tonic-gate * 1264*0Sstevel@tonic-gate * getdir reads the next tarblock off the tape and cracks 1265*0Sstevel@tonic-gate * it as a directory. The checksum must match properly. 1266*0Sstevel@tonic-gate * 1267*0Sstevel@tonic-gate * If tfile is non-null getdir writes the file name and mod date 1268*0Sstevel@tonic-gate * to tfile. 1269*0Sstevel@tonic-gate */ 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate static void 1272*0Sstevel@tonic-gate getdir(void) 1273*0Sstevel@tonic-gate { 1274*0Sstevel@tonic-gate struct stat *sp; 1275*0Sstevel@tonic-gate #ifdef EUC 1276*0Sstevel@tonic-gate static int warn_chksum_sign = 0; 1277*0Sstevel@tonic-gate #endif /* EUC */ 1278*0Sstevel@tonic-gate 1279*0Sstevel@tonic-gate top: 1280*0Sstevel@tonic-gate readtape((char *)&dblock); 1281*0Sstevel@tonic-gate if (dblock.dbuf.name[0] == '\0') 1282*0Sstevel@tonic-gate return; 1283*0Sstevel@tonic-gate sp = &stbuf; 1284*0Sstevel@tonic-gate (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode); 1285*0Sstevel@tonic-gate (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid); 1286*0Sstevel@tonic-gate (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid); 1287*0Sstevel@tonic-gate (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz); 1288*0Sstevel@tonic-gate (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime); 1289*0Sstevel@tonic-gate (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum); 1290*0Sstevel@tonic-gate (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor); 1291*0Sstevel@tonic-gate (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor); 1292*0Sstevel@tonic-gate 1293*0Sstevel@tonic-gate is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0); 1294*0Sstevel@tonic-gate 1295*0Sstevel@tonic-gate sp->st_mode = Gen.g_mode; 1296*0Sstevel@tonic-gate if (is_posix && (sp->st_mode & S_IFMT) == 0) 1297*0Sstevel@tonic-gate switch (dblock.dbuf.typeflag) { 1298*0Sstevel@tonic-gate case '0': case 0: case _XATTR_HDRTYPE: 1299*0Sstevel@tonic-gate sp->st_mode |= S_IFREG; 1300*0Sstevel@tonic-gate break; 1301*0Sstevel@tonic-gate case '1': /* hard link */ 1302*0Sstevel@tonic-gate break; 1303*0Sstevel@tonic-gate case '2': 1304*0Sstevel@tonic-gate sp->st_mode |= S_IFLNK; 1305*0Sstevel@tonic-gate break; 1306*0Sstevel@tonic-gate case '3': 1307*0Sstevel@tonic-gate sp->st_mode |= S_IFCHR; 1308*0Sstevel@tonic-gate break; 1309*0Sstevel@tonic-gate case '4': 1310*0Sstevel@tonic-gate sp->st_mode |= S_IFBLK; 1311*0Sstevel@tonic-gate break; 1312*0Sstevel@tonic-gate case '5': 1313*0Sstevel@tonic-gate sp->st_mode |= S_IFDIR; 1314*0Sstevel@tonic-gate break; 1315*0Sstevel@tonic-gate case '6': 1316*0Sstevel@tonic-gate sp->st_mode |= S_IFIFO; 1317*0Sstevel@tonic-gate break; 1318*0Sstevel@tonic-gate default: 1319*0Sstevel@tonic-gate if (convtoreg(Gen.g_filesz)) 1320*0Sstevel@tonic-gate sp->st_mode |= S_IFREG; 1321*0Sstevel@tonic-gate break; 1322*0Sstevel@tonic-gate } 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == 'X') 1325*0Sstevel@tonic-gate Xhdrflag = 1; /* Currently processing extended header */ 1326*0Sstevel@tonic-gate else 1327*0Sstevel@tonic-gate Xhdrflag = 0; 1328*0Sstevel@tonic-gate 1329*0Sstevel@tonic-gate sp->st_uid = Gen.g_uid; 1330*0Sstevel@tonic-gate sp->st_gid = Gen.g_gid; 1331*0Sstevel@tonic-gate sp->st_size = Gen.g_filesz; 1332*0Sstevel@tonic-gate sp->st_mtime = Gen.g_mtime; 1333*0Sstevel@tonic-gate chksum = Gen.g_cksum; 1334*0Sstevel@tonic-gate 1335*0Sstevel@tonic-gate if (dblock.dbuf.extno != '\0') { /* split file? */ 1336*0Sstevel@tonic-gate extno = dblock.dbuf.extno; 1337*0Sstevel@tonic-gate extsize = Gen.g_filesz; 1338*0Sstevel@tonic-gate extotal = dblock.dbuf.extotal; 1339*0Sstevel@tonic-gate } else { 1340*0Sstevel@tonic-gate extno = 0; /* tell others file not split */ 1341*0Sstevel@tonic-gate extsize = 0; 1342*0Sstevel@tonic-gate extotal = 0; 1343*0Sstevel@tonic-gate } 1344*0Sstevel@tonic-gate 1345*0Sstevel@tonic-gate #ifdef EUC 1346*0Sstevel@tonic-gate if (chksum != checksum(&dblock)) { 1347*0Sstevel@tonic-gate if (chksum != checksum_signed(&dblock)) { 1348*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1349*0Sstevel@tonic-gate "tar: directory checksum error\n")); 1350*0Sstevel@tonic-gate if (iflag) 1351*0Sstevel@tonic-gate goto top; 1352*0Sstevel@tonic-gate done(2); 1353*0Sstevel@tonic-gate } else { 1354*0Sstevel@tonic-gate if (! warn_chksum_sign) { 1355*0Sstevel@tonic-gate warn_chksum_sign = 1; 1356*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1357*0Sstevel@tonic-gate "tar: warning: tar file made with signed checksum\n")); 1358*0Sstevel@tonic-gate } 1359*0Sstevel@tonic-gate } 1360*0Sstevel@tonic-gate } 1361*0Sstevel@tonic-gate #else 1362*0Sstevel@tonic-gate if (chksum != checksum(&dblock)) { 1363*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1364*0Sstevel@tonic-gate "tar: directory checksum error\n")); 1365*0Sstevel@tonic-gate if (iflag) 1366*0Sstevel@tonic-gate goto top; 1367*0Sstevel@tonic-gate done(2); 1368*0Sstevel@tonic-gate } 1369*0Sstevel@tonic-gate #endif /* EUC */ 1370*0Sstevel@tonic-gate if (tfile != NULL && Xhdrflag == 0) { 1371*0Sstevel@tonic-gate /* 1372*0Sstevel@tonic-gate * If an extended header is present, then time is available 1373*0Sstevel@tonic-gate * in nanoseconds in the extended header data, so set it. 1374*0Sstevel@tonic-gate * Otherwise, give an invalid value so that checkupdate will 1375*0Sstevel@tonic-gate * not test beyond seconds. 1376*0Sstevel@tonic-gate */ 1377*0Sstevel@tonic-gate if ((xhdr_flgs & _X_MTIME)) 1378*0Sstevel@tonic-gate sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec; 1379*0Sstevel@tonic-gate else 1380*0Sstevel@tonic-gate sp->st_mtim.tv_nsec = -1; 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 1383*0Sstevel@tonic-gate (void) fprintf(tfile, "%s %10ld.%9.9ld\n", 1384*0Sstevel@tonic-gate Xtarhdr.x_path, sp->st_mtim.tv_sec, 1385*0Sstevel@tonic-gate sp->st_mtim.tv_nsec); 1386*0Sstevel@tonic-gate else 1387*0Sstevel@tonic-gate (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n", 1388*0Sstevel@tonic-gate NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec, 1389*0Sstevel@tonic-gate sp->st_mtim.tv_nsec); 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate 1392*0Sstevel@tonic-gate #if defined(O_XATTR) 1393*0Sstevel@tonic-gate Hiddendir = 0; 1394*0Sstevel@tonic-gate if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) { 1395*0Sstevel@tonic-gate if (xattrbadhead) { 1396*0Sstevel@tonic-gate free(xattrhead); 1397*0Sstevel@tonic-gate xattrp = NULL; 1398*0Sstevel@tonic-gate xattr_linkp = NULL; 1399*0Sstevel@tonic-gate xattrhead = NULL; 1400*0Sstevel@tonic-gate } else { 1401*0Sstevel@tonic-gate if (xattraname[0] == '.' && xattraname[1] == '\0' && 1402*0Sstevel@tonic-gate xattrp->h_typeflag == '5') { 1403*0Sstevel@tonic-gate Hiddendir = 1; 1404*0Sstevel@tonic-gate sp->st_mode = 1405*0Sstevel@tonic-gate (S_IFDIR | (sp->st_mode & S_IAMB)); 1406*0Sstevel@tonic-gate } 1407*0Sstevel@tonic-gate dblock.dbuf.typeflag = xattrp->h_typeflag; 1408*0Sstevel@tonic-gate } 1409*0Sstevel@tonic-gate } 1410*0Sstevel@tonic-gate #endif 1411*0Sstevel@tonic-gate } 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate 1414*0Sstevel@tonic-gate /* 1415*0Sstevel@tonic-gate * passtape - skip over a file on the tape 1416*0Sstevel@tonic-gate * 1417*0Sstevel@tonic-gate * passtape skips over the next data file on the tape. 1418*0Sstevel@tonic-gate * The tape directory entry must be in dblock.dbuf. This 1419*0Sstevel@tonic-gate * routine just eats the number of blocks computed from the 1420*0Sstevel@tonic-gate * directory size entry; the tape must be (logically) positioned 1421*0Sstevel@tonic-gate * right after thee directory info. 1422*0Sstevel@tonic-gate */ 1423*0Sstevel@tonic-gate 1424*0Sstevel@tonic-gate static void 1425*0Sstevel@tonic-gate passtape(void) 1426*0Sstevel@tonic-gate { 1427*0Sstevel@tonic-gate blkcnt_t blocks; 1428*0Sstevel@tonic-gate char buf[TBLOCK]; 1429*0Sstevel@tonic-gate 1430*0Sstevel@tonic-gate /* 1431*0Sstevel@tonic-gate * Types link(1), sym-link(2), char special(3), blk special(4), 1432*0Sstevel@tonic-gate * directory(5), and FIFO(6) do not have data blocks associated 1433*0Sstevel@tonic-gate * with them so just skip reading the data block. 1434*0Sstevel@tonic-gate */ 1435*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' || 1436*0Sstevel@tonic-gate dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' || 1437*0Sstevel@tonic-gate dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6') 1438*0Sstevel@tonic-gate return; 1439*0Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 1440*0Sstevel@tonic-gate 1441*0Sstevel@tonic-gate /* if operating on disk, seek instead of reading */ 1442*0Sstevel@tonic-gate if (NotTape) 1443*0Sstevel@tonic-gate seekdisk(blocks); 1444*0Sstevel@tonic-gate else 1445*0Sstevel@tonic-gate while (blocks-- > 0) 1446*0Sstevel@tonic-gate readtape(buf); 1447*0Sstevel@tonic-gate } 1448*0Sstevel@tonic-gate 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate static int 1451*0Sstevel@tonic-gate putfile(char *longname, char *shortname, char *parent, 1452*0Sstevel@tonic-gate int filetype, int lev, int symlink_lev) 1453*0Sstevel@tonic-gate { 1454*0Sstevel@tonic-gate int infile = -1; /* deliberately invalid */ 1455*0Sstevel@tonic-gate blkcnt_t blocks; 1456*0Sstevel@tonic-gate char buf[PATH_MAX + 2]; /* Add trailing slash and null */ 1457*0Sstevel@tonic-gate char *bigbuf; 1458*0Sstevel@tonic-gate int maxread; 1459*0Sstevel@tonic-gate int hint; /* amount to write to get "in sync" */ 1460*0Sstevel@tonic-gate char filetmp[PATH_MAX + 1]; 1461*0Sstevel@tonic-gate char *cp; 1462*0Sstevel@tonic-gate char *name; 1463*0Sstevel@tonic-gate struct dirent *dp; 1464*0Sstevel@tonic-gate DIR *dirp; 1465*0Sstevel@tonic-gate int i; 1466*0Sstevel@tonic-gate long l; 1467*0Sstevel@tonic-gate int split; 1468*0Sstevel@tonic-gate int dirfd = -1; 1469*0Sstevel@tonic-gate int rc = PUT_NOTAS_LINK; 1470*0Sstevel@tonic-gate int archtype = 0; 1471*0Sstevel@tonic-gate char newparent[PATH_MAX + MAXNAMLEN + 1]; 1472*0Sstevel@tonic-gate char *prefix = ""; 1473*0Sstevel@tonic-gate char *tmpbuf; 1474*0Sstevel@tonic-gate char goodbuf[PRESIZ + 2]; 1475*0Sstevel@tonic-gate char junkbuf[MAXNAM+1]; 1476*0Sstevel@tonic-gate char *lastslash; 1477*0Sstevel@tonic-gate int j; 1478*0Sstevel@tonic-gate struct stat sbuf; 1479*0Sstevel@tonic-gate int readlink_max; 1480*0Sstevel@tonic-gate 1481*0Sstevel@tonic-gate (void) memset(goodbuf, '\0', sizeof (goodbuf)); 1482*0Sstevel@tonic-gate (void) memset(junkbuf, '\0', sizeof (junkbuf)); 1483*0Sstevel@tonic-gate 1484*0Sstevel@tonic-gate xhdr_flgs = 0; 1485*0Sstevel@tonic-gate 1486*0Sstevel@tonic-gate if (filetype == XATTR_FILE) { 1487*0Sstevel@tonic-gate dirfd = attropen(get_component(longname), ".", O_RDONLY); 1488*0Sstevel@tonic-gate } else { 1489*0Sstevel@tonic-gate dirfd = open(".", O_RDONLY); 1490*0Sstevel@tonic-gate } 1491*0Sstevel@tonic-gate 1492*0Sstevel@tonic-gate if (dirfd == -1) { 1493*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1494*0Sstevel@tonic-gate "tar: unable to open%sdirectory %s\n"), 1495*0Sstevel@tonic-gate (filetype == XATTR_FILE) ? gettext(" attribute ") : " ", 1496*0Sstevel@tonic-gate (filetype == XATTR_FILE) ? longname : parent); 1497*0Sstevel@tonic-gate goto out; 1498*0Sstevel@tonic-gate } 1499*0Sstevel@tonic-gate 1500*0Sstevel@tonic-gate if (filetype == XATTR_FILE) { 1501*0Sstevel@tonic-gate if (fchdir(dirfd) < 0) { 1502*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1503*0Sstevel@tonic-gate "tar: unable to fchdir into attribute directory" 1504*0Sstevel@tonic-gate " of file %s\n"), longname); 1505*0Sstevel@tonic-gate goto out; 1506*0Sstevel@tonic-gate } 1507*0Sstevel@tonic-gate } 1508*0Sstevel@tonic-gate 1509*0Sstevel@tonic-gate if (lev > MAXLEV) { 1510*0Sstevel@tonic-gate (void) fprintf(stderr, 1511*0Sstevel@tonic-gate gettext("tar: directory nesting too deep, %s not dumped\n"), 1512*0Sstevel@tonic-gate longname); 1513*0Sstevel@tonic-gate goto out; 1514*0Sstevel@tonic-gate } 1515*0Sstevel@tonic-gate 1516*0Sstevel@tonic-gate if (getstat(dirfd, longname, shortname)) 1517*0Sstevel@tonic-gate goto out; 1518*0Sstevel@tonic-gate 1519*0Sstevel@tonic-gate if (hflag) { 1520*0Sstevel@tonic-gate /* 1521*0Sstevel@tonic-gate * Catch nesting where a file is a symlink to its directory. 1522*0Sstevel@tonic-gate */ 1523*0Sstevel@tonic-gate j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW); 1524*0Sstevel@tonic-gate if (S_ISLNK(sbuf.st_mode)) { 1525*0Sstevel@tonic-gate if (symlink_lev++ >= MAXSYMLINKS) { 1526*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1527*0Sstevel@tonic-gate "tar: %s: Number of symbolic links " 1528*0Sstevel@tonic-gate "encountered during path name traversal " 1529*0Sstevel@tonic-gate "exceeds MAXSYMLINKS\n"), longname); 1530*0Sstevel@tonic-gate Errflg = 1; 1531*0Sstevel@tonic-gate goto out; 1532*0Sstevel@tonic-gate } 1533*0Sstevel@tonic-gate } 1534*0Sstevel@tonic-gate } 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gate /* 1537*0Sstevel@tonic-gate * Check if the input file is the same as the tar file we 1538*0Sstevel@tonic-gate * are creating 1539*0Sstevel@tonic-gate */ 1540*0Sstevel@tonic-gate if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) { 1541*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1542*0Sstevel@tonic-gate "tar: %s same as archive file\n"), longname); 1543*0Sstevel@tonic-gate Errflg = 1; 1544*0Sstevel@tonic-gate goto out; 1545*0Sstevel@tonic-gate } 1546*0Sstevel@tonic-gate /* 1547*0Sstevel@tonic-gate * Check size limit - we can't archive files that 1548*0Sstevel@tonic-gate * exceed TAR_OFFSET_MAX bytes because of header 1549*0Sstevel@tonic-gate * limitations. Exclude file types that set 1550*0Sstevel@tonic-gate * st_size to zero below because they take no 1551*0Sstevel@tonic-gate * archive space to represent contents. 1552*0Sstevel@tonic-gate */ 1553*0Sstevel@tonic-gate if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) && 1554*0Sstevel@tonic-gate !S_ISDIR(stbuf.st_mode) && 1555*0Sstevel@tonic-gate !S_ISCHR(stbuf.st_mode) && 1556*0Sstevel@tonic-gate !S_ISBLK(stbuf.st_mode) && 1557*0Sstevel@tonic-gate (Eflag == 0)) { 1558*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1559*0Sstevel@tonic-gate "tar: %s too large to archive. " 1560*0Sstevel@tonic-gate "Use E function modifier.\n"), longname); 1561*0Sstevel@tonic-gate if (errflag) 1562*0Sstevel@tonic-gate exitflag = 1; 1563*0Sstevel@tonic-gate Errflg = 1; 1564*0Sstevel@tonic-gate goto out; 1565*0Sstevel@tonic-gate } 1566*0Sstevel@tonic-gate 1567*0Sstevel@tonic-gate if (tfile != NULL && checkupdate(longname) == 0) { 1568*0Sstevel@tonic-gate goto out; 1569*0Sstevel@tonic-gate } 1570*0Sstevel@tonic-gate if (checkw('r', longname) == 0) { 1571*0Sstevel@tonic-gate goto out; 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate 1574*0Sstevel@tonic-gate if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 1575*0Sstevel@tonic-gate goto out; 1576*0Sstevel@tonic-gate 1577*0Sstevel@tonic-gate if (Xflag) { 1578*0Sstevel@tonic-gate if (is_in_table(exclude_tbl, longname)) { 1579*0Sstevel@tonic-gate if (vflag) { 1580*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 1581*0Sstevel@tonic-gate "a %s excluded\n"), longname); 1582*0Sstevel@tonic-gate } 1583*0Sstevel@tonic-gate goto out; 1584*0Sstevel@tonic-gate } 1585*0Sstevel@tonic-gate } 1586*0Sstevel@tonic-gate 1587*0Sstevel@tonic-gate /* 1588*0Sstevel@tonic-gate * If the length of the fullname is greater than MAXNAM, 1589*0Sstevel@tonic-gate * print out a message and return (unless extended headers are used, 1590*0Sstevel@tonic-gate * in which case fullname is limited to PATH_MAX). 1591*0Sstevel@tonic-gate */ 1592*0Sstevel@tonic-gate 1593*0Sstevel@tonic-gate if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) || 1594*0Sstevel@tonic-gate (split > PATH_MAX)) { 1595*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1596*0Sstevel@tonic-gate "tar: %s: file name too long\n"), longname); 1597*0Sstevel@tonic-gate if (errflag) 1598*0Sstevel@tonic-gate exitflag = 1; 1599*0Sstevel@tonic-gate Errflg = 1; 1600*0Sstevel@tonic-gate goto out; 1601*0Sstevel@tonic-gate } 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gate /* 1604*0Sstevel@tonic-gate * We split the fullname into prefix and name components if any one 1605*0Sstevel@tonic-gate * of three conditions holds: 1606*0Sstevel@tonic-gate * -- the length of the fullname exceeds NAMSIZ, 1607*0Sstevel@tonic-gate * -- the length of the fullname equals NAMSIZ, and the shortname 1608*0Sstevel@tonic-gate * is less than NAMSIZ, (splitting in this case preserves 1609*0Sstevel@tonic-gate * compatibility with 5.6 and 5.5.1 tar), or 1610*0Sstevel@tonic-gate * -- the length of the fullname equals NAMSIZ, the file is a 1611*0Sstevel@tonic-gate * directory and we are not in POSIX-conformant mode (where 1612*0Sstevel@tonic-gate * trailing slashes are removed from directories). 1613*0Sstevel@tonic-gate */ 1614*0Sstevel@tonic-gate if ((split > NAMSIZ) || 1615*0Sstevel@tonic-gate (split == NAMSIZ && strlen(shortname) < NAMSIZ) || 1616*0Sstevel@tonic-gate (split == NAMSIZ && (stbuf.st_mode & S_IFDIR) && !Pflag)) { 1617*0Sstevel@tonic-gate /* 1618*0Sstevel@tonic-gate * Since path is limited to PRESIZ characters, look for the 1619*0Sstevel@tonic-gate * last slash within PRESIZ + 1 characters only. 1620*0Sstevel@tonic-gate */ 1621*0Sstevel@tonic-gate (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1)); 1622*0Sstevel@tonic-gate tmpbuf = goodbuf; 1623*0Sstevel@tonic-gate lastslash = strrchr(tmpbuf, '/'); 1624*0Sstevel@tonic-gate if (lastslash == NULL) { 1625*0Sstevel@tonic-gate i = split; /* Length of name */ 1626*0Sstevel@tonic-gate j = 0; /* Length of prefix */ 1627*0Sstevel@tonic-gate goodbuf[0] = '\0'; 1628*0Sstevel@tonic-gate } else { 1629*0Sstevel@tonic-gate *lastslash = '\0'; /* Terminate the prefix */ 1630*0Sstevel@tonic-gate j = strlen(tmpbuf); 1631*0Sstevel@tonic-gate i = split - j - 1; 1632*0Sstevel@tonic-gate } 1633*0Sstevel@tonic-gate /* 1634*0Sstevel@tonic-gate * If the filename is greater than NAMSIZ we can't 1635*0Sstevel@tonic-gate * archive the file unless we are using extended headers. 1636*0Sstevel@tonic-gate */ 1637*0Sstevel@tonic-gate if ((i > NAMSIZ) || (i == NAMSIZ && (stbuf.st_mode & S_IFDIR) && 1638*0Sstevel@tonic-gate !Pflag)) { 1639*0Sstevel@tonic-gate /* Determine which (filename or path) is too long. */ 1640*0Sstevel@tonic-gate lastslash = strrchr(longname, '/'); 1641*0Sstevel@tonic-gate if (lastslash != NULL) 1642*0Sstevel@tonic-gate i = strlen(lastslash + 1); 1643*0Sstevel@tonic-gate if (Eflag > 0) { 1644*0Sstevel@tonic-gate xhdr_flgs |= _X_PATH; 1645*0Sstevel@tonic-gate Xtarhdr.x_path = longname; 1646*0Sstevel@tonic-gate if (i <= NAMSIZ) 1647*0Sstevel@tonic-gate (void) strcpy(junkbuf, lastslash + 1); 1648*0Sstevel@tonic-gate else 1649*0Sstevel@tonic-gate (void) sprintf(junkbuf, "%llu", 1650*0Sstevel@tonic-gate xhdr_count + 1); 1651*0Sstevel@tonic-gate if (split - i - 1 > PRESIZ) 1652*0Sstevel@tonic-gate (void) strcpy(goodbuf, xhdr_dirname); 1653*0Sstevel@tonic-gate } else { 1654*0Sstevel@tonic-gate if ((i > NAMSIZ) || (i == NAMSIZ && 1655*0Sstevel@tonic-gate (stbuf.st_mode & S_IFDIR) && !Pflag)) 1656*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1657*0Sstevel@tonic-gate "tar: %s: filename is greater than " 1658*0Sstevel@tonic-gate "%d\n"), lastslash == NULL ? 1659*0Sstevel@tonic-gate longname : lastslash + 1, NAMSIZ); 1660*0Sstevel@tonic-gate else 1661*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1662*0Sstevel@tonic-gate "tar: %s: prefix is greater than %d" 1663*0Sstevel@tonic-gate "\n"), longname, PRESIZ); 1664*0Sstevel@tonic-gate if (errflag) 1665*0Sstevel@tonic-gate exitflag = 1; 1666*0Sstevel@tonic-gate Errflg = 1; 1667*0Sstevel@tonic-gate goto out; 1668*0Sstevel@tonic-gate } 1669*0Sstevel@tonic-gate } else 1670*0Sstevel@tonic-gate (void) strncpy(&junkbuf[0], longname + j + 1, 1671*0Sstevel@tonic-gate strlen(longname + j + 1)); 1672*0Sstevel@tonic-gate name = junkbuf; 1673*0Sstevel@tonic-gate prefix = goodbuf; 1674*0Sstevel@tonic-gate } else { 1675*0Sstevel@tonic-gate name = longname; 1676*0Sstevel@tonic-gate } 1677*0Sstevel@tonic-gate if (Aflag) { 1678*0Sstevel@tonic-gate if ((prefix != NULL) && (*prefix != '\0')) 1679*0Sstevel@tonic-gate while (*prefix == '/') 1680*0Sstevel@tonic-gate ++prefix; 1681*0Sstevel@tonic-gate else 1682*0Sstevel@tonic-gate while (*name == '/') 1683*0Sstevel@tonic-gate ++name; 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate switch (stbuf.st_mode & S_IFMT) { 1687*0Sstevel@tonic-gate case S_IFDIR: 1688*0Sstevel@tonic-gate stbuf.st_size = (off_t)0; 1689*0Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 1690*0Sstevel@tonic-gate 1691*0Sstevel@tonic-gate if (filetype != XATTR_FILE && Hiddendir == 0) { 1692*0Sstevel@tonic-gate i = 0; 1693*0Sstevel@tonic-gate cp = buf; 1694*0Sstevel@tonic-gate while ((*cp++ = longname[i++])) 1695*0Sstevel@tonic-gate ; 1696*0Sstevel@tonic-gate *--cp = '/'; 1697*0Sstevel@tonic-gate *++cp = 0; 1698*0Sstevel@tonic-gate } 1699*0Sstevel@tonic-gate if (!oflag) { 1700*0Sstevel@tonic-gate tomodes(&stbuf); 1701*0Sstevel@tonic-gate if (build_dblock(name, tchar, '5', filetype, 1702*0Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) { 1703*0Sstevel@tonic-gate goto out; 1704*0Sstevel@tonic-gate } 1705*0Sstevel@tonic-gate if (!Pflag) { 1706*0Sstevel@tonic-gate /* 1707*0Sstevel@tonic-gate * Old archives require a slash at the end 1708*0Sstevel@tonic-gate * of a directory name. 1709*0Sstevel@tonic-gate * 1710*0Sstevel@tonic-gate * XXX 1711*0Sstevel@tonic-gate * If directory name is too long, will 1712*0Sstevel@tonic-gate * slash overfill field? 1713*0Sstevel@tonic-gate */ 1714*0Sstevel@tonic-gate if (strlen(name) > (unsigned)NAMSIZ-1) { 1715*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1716*0Sstevel@tonic-gate "tar: %s: filename is greater " 1717*0Sstevel@tonic-gate "than %d\n"), name, NAMSIZ); 1718*0Sstevel@tonic-gate if (errflag) 1719*0Sstevel@tonic-gate exitflag = 1; 1720*0Sstevel@tonic-gate Errflg = 1; 1721*0Sstevel@tonic-gate goto out; 1722*0Sstevel@tonic-gate } else { 1723*0Sstevel@tonic-gate if (strlen(name) == (NAMSIZ - 1)) { 1724*0Sstevel@tonic-gate (void) memcpy(dblock.dbuf.name, 1725*0Sstevel@tonic-gate name, NAMSIZ); 1726*0Sstevel@tonic-gate dblock.dbuf.name[NAMSIZ-1] 1727*0Sstevel@tonic-gate = '/'; 1728*0Sstevel@tonic-gate } else 1729*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.name, 1730*0Sstevel@tonic-gate "%s/", name); 1731*0Sstevel@tonic-gate 1732*0Sstevel@tonic-gate /* 1733*0Sstevel@tonic-gate * need to recalculate checksum 1734*0Sstevel@tonic-gate * because the name changed. 1735*0Sstevel@tonic-gate */ 1736*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, 1737*0Sstevel@tonic-gate "%07o", checksum(&dblock)); 1738*0Sstevel@tonic-gate } 1739*0Sstevel@tonic-gate } 1740*0Sstevel@tonic-gate 1741*0Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, prefix, 1742*0Sstevel@tonic-gate filetype, '5') != 0) 1743*0Sstevel@tonic-gate goto out; 1744*0Sstevel@tonic-gate 1745*0Sstevel@tonic-gate #if defined(O_XATTR) 1746*0Sstevel@tonic-gate /* 1747*0Sstevel@tonic-gate * Reset header typeflag when archiving directory, since 1748*0Sstevel@tonic-gate * build_dblock changed it on us. 1749*0Sstevel@tonic-gate */ 1750*0Sstevel@tonic-gate if (filetype == XATTR_FILE) { 1751*0Sstevel@tonic-gate dblock.dbuf.typeflag = _XATTR_HDRTYPE; 1752*0Sstevel@tonic-gate } else { 1753*0Sstevel@tonic-gate dblock.dbuf.typeflag = '5'; 1754*0Sstevel@tonic-gate } 1755*0Sstevel@tonic-gate #else 1756*0Sstevel@tonic-gate dblock.dbuf.typeflag = '5'; 1757*0Sstevel@tonic-gate #endif 1758*0Sstevel@tonic-gate 1759*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", 1760*0Sstevel@tonic-gate checksum(&dblock)); 1761*0Sstevel@tonic-gate 1762*0Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 1763*0Sstevel@tonic-gate } 1764*0Sstevel@tonic-gate if (vflag) { 1765*0Sstevel@tonic-gate #ifdef DEBUG 1766*0Sstevel@tonic-gate if (NotTape) 1767*0Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 1768*0Sstevel@tonic-gate 0); 1769*0Sstevel@tonic-gate #endif 1770*0Sstevel@tonic-gate if (filetype == XATTR_FILE && Hiddendir) { 1771*0Sstevel@tonic-gate (void) fprintf(vfile, "a %s attribute . ", 1772*0Sstevel@tonic-gate longname); 1773*0Sstevel@tonic-gate 1774*0Sstevel@tonic-gate } else { 1775*0Sstevel@tonic-gate (void) fprintf(vfile, "a %s/ ", longname); 1776*0Sstevel@tonic-gate } 1777*0Sstevel@tonic-gate if (NotTape) 1778*0Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n", 1779*0Sstevel@tonic-gate K(blocks)); 1780*0Sstevel@tonic-gate else 1781*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" FMT_blkcnt_t 1782*0Sstevel@tonic-gate " tape blocks\n"), blocks); 1783*0Sstevel@tonic-gate } 1784*0Sstevel@tonic-gate 1785*0Sstevel@tonic-gate /* 1786*0Sstevel@tonic-gate * If hidden dir then break now since xattrs_put() will do 1787*0Sstevel@tonic-gate * the iterating of the directory. 1788*0Sstevel@tonic-gate * 1789*0Sstevel@tonic-gate * At the moment, there can't be attributes on attributes 1790*0Sstevel@tonic-gate * or directories within the attributes hidden directory 1791*0Sstevel@tonic-gate * hierarchy. 1792*0Sstevel@tonic-gate */ 1793*0Sstevel@tonic-gate if (filetype == XATTR_FILE) 1794*0Sstevel@tonic-gate break; 1795*0Sstevel@tonic-gate 1796*0Sstevel@tonic-gate if (*shortname != '/') 1797*0Sstevel@tonic-gate (void) sprintf(newparent, "%s/%s", parent, shortname); 1798*0Sstevel@tonic-gate else 1799*0Sstevel@tonic-gate (void) sprintf(newparent, "%s", shortname); 1800*0Sstevel@tonic-gate 1801*0Sstevel@tonic-gate if (chdir(shortname) < 0) { 1802*0Sstevel@tonic-gate vperror(0, "%s", newparent); 1803*0Sstevel@tonic-gate goto out; 1804*0Sstevel@tonic-gate } 1805*0Sstevel@tonic-gate 1806*0Sstevel@tonic-gate if ((dirp = opendir(".")) == NULL) { 1807*0Sstevel@tonic-gate vperror(0, gettext( 1808*0Sstevel@tonic-gate "can't open directory %s"), longname); 1809*0Sstevel@tonic-gate if (chdir(parent) < 0) 1810*0Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"), 1811*0Sstevel@tonic-gate parent); 1812*0Sstevel@tonic-gate goto out; 1813*0Sstevel@tonic-gate } 1814*0Sstevel@tonic-gate 1815*0Sstevel@tonic-gate while ((dp = readdir(dirp)) != NULL && !term) { 1816*0Sstevel@tonic-gate if ((strcmp(".", dp->d_name) == 0) || 1817*0Sstevel@tonic-gate (strcmp("..", dp->d_name) == 0)) 1818*0Sstevel@tonic-gate continue; 1819*0Sstevel@tonic-gate (void) strcpy(cp, dp->d_name); 1820*0Sstevel@tonic-gate if (stat(dp->d_name, &sbuf) < 0 || 1821*0Sstevel@tonic-gate (sbuf.st_mode & S_IFMT) == S_IFDIR) { 1822*0Sstevel@tonic-gate l = telldir(dirp); 1823*0Sstevel@tonic-gate (void) closedir(dirp); 1824*0Sstevel@tonic-gate } else 1825*0Sstevel@tonic-gate l = -1; 1826*0Sstevel@tonic-gate 1827*0Sstevel@tonic-gate archtype = putfile(buf, cp, newparent, 1828*0Sstevel@tonic-gate NORMAL_FILE, lev + 1, symlink_lev); 1829*0Sstevel@tonic-gate 1830*0Sstevel@tonic-gate if (!exitflag) { 1831*0Sstevel@tonic-gate if (atflag && archtype == PUT_NOTAS_LINK) { 1832*0Sstevel@tonic-gate xattrs_put(buf, cp, newparent); 1833*0Sstevel@tonic-gate } 1834*0Sstevel@tonic-gate } 1835*0Sstevel@tonic-gate if (exitflag) 1836*0Sstevel@tonic-gate break; 1837*0Sstevel@tonic-gate 1838*0Sstevel@tonic-gate /* 1839*0Sstevel@tonic-gate * If the directory was not closed, then it does 1840*0Sstevel@tonic-gate * not need to be reopened. 1841*0Sstevel@tonic-gate */ 1842*0Sstevel@tonic-gate if (l < 0) 1843*0Sstevel@tonic-gate continue; 1844*0Sstevel@tonic-gate if ((dirp = opendir(".")) == NULL) { 1845*0Sstevel@tonic-gate vperror(0, gettext( 1846*0Sstevel@tonic-gate "can't open directory %s"), longname); 1847*0Sstevel@tonic-gate if (chdir(parent) < 0) 1848*0Sstevel@tonic-gate vperror(0, 1849*0Sstevel@tonic-gate gettext("cannot change back?: %s"), 1850*0Sstevel@tonic-gate parent); 1851*0Sstevel@tonic-gate goto out; 1852*0Sstevel@tonic-gate } 1853*0Sstevel@tonic-gate seekdir(dirp, l); 1854*0Sstevel@tonic-gate 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate (void) closedir(dirp); 1857*0Sstevel@tonic-gate 1858*0Sstevel@tonic-gate if (chdir(parent) < 0) { 1859*0Sstevel@tonic-gate vperror(0, gettext("cannot change back?: %s"), parent); 1860*0Sstevel@tonic-gate } 1861*0Sstevel@tonic-gate 1862*0Sstevel@tonic-gate break; 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate case S_IFLNK: 1865*0Sstevel@tonic-gate readlink_max = NAMSIZ; 1866*0Sstevel@tonic-gate if (stbuf.st_size > NAMSIZ) { 1867*0Sstevel@tonic-gate if (Eflag > 0) { 1868*0Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH; 1869*0Sstevel@tonic-gate readlink_max = PATH_MAX; 1870*0Sstevel@tonic-gate } else { 1871*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1872*0Sstevel@tonic-gate "tar: %s: symbolic link too long\n"), 1873*0Sstevel@tonic-gate longname); 1874*0Sstevel@tonic-gate if (errflag) 1875*0Sstevel@tonic-gate exitflag = 1; 1876*0Sstevel@tonic-gate Errflg = 1; 1877*0Sstevel@tonic-gate goto out; 1878*0Sstevel@tonic-gate } 1879*0Sstevel@tonic-gate } 1880*0Sstevel@tonic-gate /* 1881*0Sstevel@tonic-gate * Sym-links need header size of zero since you 1882*0Sstevel@tonic-gate * don't store any data for this type. 1883*0Sstevel@tonic-gate */ 1884*0Sstevel@tonic-gate stbuf.st_size = (off_t)0; 1885*0Sstevel@tonic-gate tomodes(&stbuf); 1886*0Sstevel@tonic-gate i = readlink(shortname, filetmp, readlink_max); 1887*0Sstevel@tonic-gate if (i < 0) { 1888*0Sstevel@tonic-gate vperror(0, gettext( 1889*0Sstevel@tonic-gate "can't read symbolic link %s"), longname); 1890*0Sstevel@tonic-gate goto out; 1891*0Sstevel@tonic-gate } else { 1892*0Sstevel@tonic-gate filetmp[i] = 0; 1893*0Sstevel@tonic-gate } 1894*0Sstevel@tonic-gate if (vflag) 1895*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 1896*0Sstevel@tonic-gate "a %s symbolic link to %s\n"), 1897*0Sstevel@tonic-gate longname, filetmp); 1898*0Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) { 1899*0Sstevel@tonic-gate Xtarhdr.x_linkpath = filetmp; 1900*0Sstevel@tonic-gate if (build_dblock(name, tchar, '2', filetype, &stbuf, 1901*0Sstevel@tonic-gate stbuf.st_dev, prefix) != 0) 1902*0Sstevel@tonic-gate goto out; 1903*0Sstevel@tonic-gate } else 1904*0Sstevel@tonic-gate if (build_dblock(name, filetmp, '2', filetype, &stbuf, 1905*0Sstevel@tonic-gate stbuf.st_dev, prefix) != 0) 1906*0Sstevel@tonic-gate goto out; 1907*0Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 1908*0Sstevel@tonic-gate /* 1909*0Sstevel@tonic-gate * No acls for symlinks: mode is always 777 1910*0Sstevel@tonic-gate * dont call write ancillary 1911*0Sstevel@tonic-gate */ 1912*0Sstevel@tonic-gate rc = PUT_AS_LINK; 1913*0Sstevel@tonic-gate break; 1914*0Sstevel@tonic-gate case S_IFREG: 1915*0Sstevel@tonic-gate if ((infile = openat(dirfd, shortname, 0)) < 0) { 1916*0Sstevel@tonic-gate vperror(0, "%s%s%s", longname, 1917*0Sstevel@tonic-gate (filetype == XATTR_FILE) ? 1918*0Sstevel@tonic-gate gettext(" attribute ") : "", 1919*0Sstevel@tonic-gate (filetype == XATTR_FILE) ? 1920*0Sstevel@tonic-gate shortname : ""); 1921*0Sstevel@tonic-gate goto out; 1922*0Sstevel@tonic-gate } 1923*0Sstevel@tonic-gate 1924*0Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 1925*0Sstevel@tonic-gate 1926*0Sstevel@tonic-gate if (put_link(name, longname, shortname, 1927*0Sstevel@tonic-gate prefix, filetype, '1') == 0) { 1928*0Sstevel@tonic-gate (void) close(infile); 1929*0Sstevel@tonic-gate rc = PUT_AS_LINK; 1930*0Sstevel@tonic-gate goto out; 1931*0Sstevel@tonic-gate } 1932*0Sstevel@tonic-gate 1933*0Sstevel@tonic-gate tomodes(&stbuf); 1934*0Sstevel@tonic-gate 1935*0Sstevel@tonic-gate /* correctly handle end of volume */ 1936*0Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) { 1937*0Sstevel@tonic-gate /* file won't fit */ 1938*0Sstevel@tonic-gate if (eflag) { 1939*0Sstevel@tonic-gate if (blocks <= blocklim) { 1940*0Sstevel@tonic-gate newvol(); 1941*0Sstevel@tonic-gate break; 1942*0Sstevel@tonic-gate } 1943*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1944*0Sstevel@tonic-gate "tar: Single file cannot fit on volume\n")); 1945*0Sstevel@tonic-gate done(3); 1946*0Sstevel@tonic-gate } 1947*0Sstevel@tonic-gate /* split if floppy has some room and file is large */ 1948*0Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) && 1949*0Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) { 1950*0Sstevel@tonic-gate splitfile(longname, infile, 1951*0Sstevel@tonic-gate name, prefix, filetype); 1952*0Sstevel@tonic-gate (void) close(dirfd); 1953*0Sstevel@tonic-gate (void) close(infile); 1954*0Sstevel@tonic-gate goto out; 1955*0Sstevel@tonic-gate } 1956*0Sstevel@tonic-gate newvol(); /* not worth it--just get new volume */ 1957*0Sstevel@tonic-gate } 1958*0Sstevel@tonic-gate #ifdef DEBUG 1959*0Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname, 1960*0Sstevel@tonic-gate blocks); 1961*0Sstevel@tonic-gate #endif 1962*0Sstevel@tonic-gate if (build_dblock(name, tchar, '0', filetype, 1963*0Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) { 1964*0Sstevel@tonic-gate goto out; 1965*0Sstevel@tonic-gate } 1966*0Sstevel@tonic-gate if (vflag) { 1967*0Sstevel@tonic-gate #ifdef DEBUG 1968*0Sstevel@tonic-gate if (NotTape) 1969*0Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 1970*0Sstevel@tonic-gate 0); 1971*0Sstevel@tonic-gate #endif 1972*0Sstevel@tonic-gate (void) fprintf(vfile, "a %s%s%s ", longname, 1973*0Sstevel@tonic-gate (filetype == XATTR_FILE) ? 1974*0Sstevel@tonic-gate gettext(" attribute ") : "", 1975*0Sstevel@tonic-gate (filetype == XATTR_FILE) ? 1976*0Sstevel@tonic-gate shortname : ""); 1977*0Sstevel@tonic-gate if (NotTape) 1978*0Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n", 1979*0Sstevel@tonic-gate K(blocks)); 1980*0Sstevel@tonic-gate else 1981*0Sstevel@tonic-gate (void) fprintf(vfile, 1982*0Sstevel@tonic-gate gettext("%" FMT_blkcnt_t " tape blocks\n"), 1983*0Sstevel@tonic-gate blocks); 1984*0Sstevel@tonic-gate } 1985*0Sstevel@tonic-gate 1986*0Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, prefix, 1987*0Sstevel@tonic-gate filetype, '0') != 0) 1988*0Sstevel@tonic-gate goto out; 1989*0Sstevel@tonic-gate 1990*0Sstevel@tonic-gate /* 1991*0Sstevel@tonic-gate * No need to reset typeflag for extended attribute here, since 1992*0Sstevel@tonic-gate * put_extra_attributes already set it and we haven't called 1993*0Sstevel@tonic-gate * build_dblock(). 1994*0Sstevel@tonic-gate */ 1995*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 1996*0Sstevel@tonic-gate hint = writetbuf((char *)&dblock, 1); 1997*0Sstevel@tonic-gate maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 1998*0Sstevel@tonic-gate if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) { 1999*0Sstevel@tonic-gate maxread = TBLOCK; 2000*0Sstevel@tonic-gate bigbuf = buf; 2001*0Sstevel@tonic-gate } 2002*0Sstevel@tonic-gate 2003*0Sstevel@tonic-gate while (((i = (int) 2004*0Sstevel@tonic-gate read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) && 2005*0Sstevel@tonic-gate blocks) { 2006*0Sstevel@tonic-gate blkcnt_t nblks; 2007*0Sstevel@tonic-gate 2008*0Sstevel@tonic-gate nblks = ((i-1)/TBLOCK)+1; 2009*0Sstevel@tonic-gate if (nblks > blocks) 2010*0Sstevel@tonic-gate nblks = blocks; 2011*0Sstevel@tonic-gate hint = writetbuf(bigbuf, nblks); 2012*0Sstevel@tonic-gate blocks -= nblks; 2013*0Sstevel@tonic-gate } 2014*0Sstevel@tonic-gate (void) close(infile); 2015*0Sstevel@tonic-gate if (bigbuf != buf) 2016*0Sstevel@tonic-gate free(bigbuf); 2017*0Sstevel@tonic-gate if (i < 0) 2018*0Sstevel@tonic-gate vperror(0, gettext("Read error on %s"), longname); 2019*0Sstevel@tonic-gate else if (blocks != 0 || i != 0) { 2020*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2021*0Sstevel@tonic-gate "tar: %s: file changed size\n"), longname); 2022*0Sstevel@tonic-gate if (errflag) { 2023*0Sstevel@tonic-gate exitflag = 1; 2024*0Sstevel@tonic-gate Errflg = 1; 2025*0Sstevel@tonic-gate } else if (!Dflag) { 2026*0Sstevel@tonic-gate Errflg = 1; 2027*0Sstevel@tonic-gate } 2028*0Sstevel@tonic-gate } 2029*0Sstevel@tonic-gate putempty(blocks); 2030*0Sstevel@tonic-gate break; 2031*0Sstevel@tonic-gate case S_IFIFO: 2032*0Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 2033*0Sstevel@tonic-gate stbuf.st_size = (off_t)0; 2034*0Sstevel@tonic-gate 2035*0Sstevel@tonic-gate if (put_link(name, longname, shortname, 2036*0Sstevel@tonic-gate prefix, filetype, '6') == 0) { 2037*0Sstevel@tonic-gate rc = PUT_AS_LINK; 2038*0Sstevel@tonic-gate goto out; 2039*0Sstevel@tonic-gate } 2040*0Sstevel@tonic-gate tomodes(&stbuf); 2041*0Sstevel@tonic-gate 2042*0Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) { 2043*0Sstevel@tonic-gate if (eflag) { 2044*0Sstevel@tonic-gate if (blocks <= blocklim) { 2045*0Sstevel@tonic-gate newvol(); 2046*0Sstevel@tonic-gate break; 2047*0Sstevel@tonic-gate } 2048*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2049*0Sstevel@tonic-gate "tar: Single file cannot fit on volume\n")); 2050*0Sstevel@tonic-gate done(3); 2051*0Sstevel@tonic-gate } 2052*0Sstevel@tonic-gate 2053*0Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) && 2054*0Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) { 2055*0Sstevel@tonic-gate splitfile(longname, infile, name, 2056*0Sstevel@tonic-gate prefix, filetype); 2057*0Sstevel@tonic-gate (void) close(dirfd); 2058*0Sstevel@tonic-gate (void) close(infile); 2059*0Sstevel@tonic-gate goto out; 2060*0Sstevel@tonic-gate } 2061*0Sstevel@tonic-gate newvol(); 2062*0Sstevel@tonic-gate } 2063*0Sstevel@tonic-gate #ifdef DEBUG 2064*0Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname, 2065*0Sstevel@tonic-gate blocks); 2066*0Sstevel@tonic-gate #endif 2067*0Sstevel@tonic-gate if (vflag) { 2068*0Sstevel@tonic-gate #ifdef DEBUG 2069*0Sstevel@tonic-gate if (NotTape) 2070*0Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 2071*0Sstevel@tonic-gate 0); 2072*0Sstevel@tonic-gate #endif 2073*0Sstevel@tonic-gate if (NotTape) 2074*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" 2075*0Sstevel@tonic-gate FMT_blkcnt_t "K\n "), longname, K(blocks)); 2076*0Sstevel@tonic-gate else 2077*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2078*0Sstevel@tonic-gate "a %s %" FMT_blkcnt_t " tape blocks\n"), 2079*0Sstevel@tonic-gate longname, blocks); 2080*0Sstevel@tonic-gate } 2081*0Sstevel@tonic-gate if (build_dblock(name, tchar, '6', filetype, 2082*0Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) 2083*0Sstevel@tonic-gate goto out; 2084*0Sstevel@tonic-gate 2085*0Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, prefix, 2086*0Sstevel@tonic-gate filetype, '6') != 0) 2087*0Sstevel@tonic-gate goto out; 2088*0Sstevel@tonic-gate 2089*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 2090*0Sstevel@tonic-gate dblock.dbuf.typeflag = '6'; 2091*0Sstevel@tonic-gate 2092*0Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 2093*0Sstevel@tonic-gate break; 2094*0Sstevel@tonic-gate case S_IFCHR: 2095*0Sstevel@tonic-gate stbuf.st_size = (off_t)0; 2096*0Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 2097*0Sstevel@tonic-gate if (put_link(name, longname, 2098*0Sstevel@tonic-gate shortname, prefix, filetype, '3') == 0) { 2099*0Sstevel@tonic-gate rc = PUT_AS_LINK; 2100*0Sstevel@tonic-gate goto out; 2101*0Sstevel@tonic-gate } 2102*0Sstevel@tonic-gate tomodes(&stbuf); 2103*0Sstevel@tonic-gate 2104*0Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) { 2105*0Sstevel@tonic-gate if (eflag) { 2106*0Sstevel@tonic-gate if (blocks <= blocklim) { 2107*0Sstevel@tonic-gate newvol(); 2108*0Sstevel@tonic-gate break; 2109*0Sstevel@tonic-gate } 2110*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2111*0Sstevel@tonic-gate "tar: Single file cannot fit on volume\n")); 2112*0Sstevel@tonic-gate done(3); 2113*0Sstevel@tonic-gate } 2114*0Sstevel@tonic-gate 2115*0Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) && 2116*0Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) { 2117*0Sstevel@tonic-gate splitfile(longname, infile, name, 2118*0Sstevel@tonic-gate prefix, filetype); 2119*0Sstevel@tonic-gate (void) close(dirfd); 2120*0Sstevel@tonic-gate goto out; 2121*0Sstevel@tonic-gate } 2122*0Sstevel@tonic-gate newvol(); 2123*0Sstevel@tonic-gate } 2124*0Sstevel@tonic-gate #ifdef DEBUG 2125*0Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname, 2126*0Sstevel@tonic-gate blocks); 2127*0Sstevel@tonic-gate #endif 2128*0Sstevel@tonic-gate if (vflag) { 2129*0Sstevel@tonic-gate #ifdef DEBUG 2130*0Sstevel@tonic-gate if (NotTape) 2131*0Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 2132*0Sstevel@tonic-gate 0); 2133*0Sstevel@tonic-gate #endif 2134*0Sstevel@tonic-gate if (NotTape) 2135*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" 2136*0Sstevel@tonic-gate FMT_blkcnt_t "K\n"), longname, K(blocks)); 2137*0Sstevel@tonic-gate else 2138*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" 2139*0Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), longname, 2140*0Sstevel@tonic-gate blocks); 2141*0Sstevel@tonic-gate } 2142*0Sstevel@tonic-gate if (build_dblock(name, tchar, '3', 2143*0Sstevel@tonic-gate filetype, &stbuf, stbuf.st_rdev, prefix) != 0) 2144*0Sstevel@tonic-gate goto out; 2145*0Sstevel@tonic-gate 2146*0Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, 2147*0Sstevel@tonic-gate prefix, filetype, '3') != 0) 2148*0Sstevel@tonic-gate goto out; 2149*0Sstevel@tonic-gate 2150*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 2151*0Sstevel@tonic-gate dblock.dbuf.typeflag = '3'; 2152*0Sstevel@tonic-gate 2153*0Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 2154*0Sstevel@tonic-gate break; 2155*0Sstevel@tonic-gate case S_IFBLK: 2156*0Sstevel@tonic-gate stbuf.st_size = (off_t)0; 2157*0Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); 2158*0Sstevel@tonic-gate if (put_link(name, longname, 2159*0Sstevel@tonic-gate shortname, prefix, filetype, '4') == 0) { 2160*0Sstevel@tonic-gate rc = PUT_AS_LINK; 2161*0Sstevel@tonic-gate goto out; 2162*0Sstevel@tonic-gate } 2163*0Sstevel@tonic-gate tomodes(&stbuf); 2164*0Sstevel@tonic-gate 2165*0Sstevel@tonic-gate while (mulvol && tapepos + blocks + 1 > blocklim) { 2166*0Sstevel@tonic-gate if (eflag) { 2167*0Sstevel@tonic-gate if (blocks <= blocklim) { 2168*0Sstevel@tonic-gate newvol(); 2169*0Sstevel@tonic-gate break; 2170*0Sstevel@tonic-gate } 2171*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2172*0Sstevel@tonic-gate "tar: Single file cannot fit on volume\n")); 2173*0Sstevel@tonic-gate done(3); 2174*0Sstevel@tonic-gate } 2175*0Sstevel@tonic-gate 2176*0Sstevel@tonic-gate if (((blocklim - tapepos) >= EXTMIN) && 2177*0Sstevel@tonic-gate ((blocks + 1) >= blocklim/10)) { 2178*0Sstevel@tonic-gate splitfile(longname, infile, 2179*0Sstevel@tonic-gate name, prefix, filetype); 2180*0Sstevel@tonic-gate (void) close(dirfd); 2181*0Sstevel@tonic-gate goto out; 2182*0Sstevel@tonic-gate } 2183*0Sstevel@tonic-gate newvol(); 2184*0Sstevel@tonic-gate } 2185*0Sstevel@tonic-gate #ifdef DEBUG 2186*0Sstevel@tonic-gate DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname, 2187*0Sstevel@tonic-gate blocks); 2188*0Sstevel@tonic-gate #endif 2189*0Sstevel@tonic-gate if (vflag) { 2190*0Sstevel@tonic-gate #ifdef DEBUG 2191*0Sstevel@tonic-gate if (NotTape) 2192*0Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos), 2193*0Sstevel@tonic-gate 0); 2194*0Sstevel@tonic-gate #endif 2195*0Sstevel@tonic-gate (void) fprintf(vfile, "a %s ", longname); 2196*0Sstevel@tonic-gate if (NotTape) 2197*0Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n", 2198*0Sstevel@tonic-gate K(blocks)); 2199*0Sstevel@tonic-gate else 2200*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2201*0Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), blocks); 2202*0Sstevel@tonic-gate } 2203*0Sstevel@tonic-gate if (build_dblock(name, tchar, '4', 2204*0Sstevel@tonic-gate filetype, &stbuf, stbuf.st_rdev, prefix) != 0) 2205*0Sstevel@tonic-gate goto out; 2206*0Sstevel@tonic-gate 2207*0Sstevel@tonic-gate if (put_extra_attributes(longname, shortname, 2208*0Sstevel@tonic-gate prefix, filetype, '4') != 0) 2209*0Sstevel@tonic-gate goto out; 2210*0Sstevel@tonic-gate 2211*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 2212*0Sstevel@tonic-gate dblock.dbuf.typeflag = '4'; 2213*0Sstevel@tonic-gate 2214*0Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 2215*0Sstevel@tonic-gate break; 2216*0Sstevel@tonic-gate default: 2217*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2218*0Sstevel@tonic-gate "tar: %s is not a file. Not dumped\n"), longname); 2219*0Sstevel@tonic-gate if (errflag) 2220*0Sstevel@tonic-gate exitflag = 1; 2221*0Sstevel@tonic-gate Errflg = 1; 2222*0Sstevel@tonic-gate goto out; 2223*0Sstevel@tonic-gate } 2224*0Sstevel@tonic-gate 2225*0Sstevel@tonic-gate out: 2226*0Sstevel@tonic-gate if (dirfd != -1) { 2227*0Sstevel@tonic-gate if (filetype == XATTR_FILE) 2228*0Sstevel@tonic-gate (void) chdir(parent); 2229*0Sstevel@tonic-gate (void) close(dirfd); 2230*0Sstevel@tonic-gate } 2231*0Sstevel@tonic-gate return (rc); 2232*0Sstevel@tonic-gate } 2233*0Sstevel@tonic-gate 2234*0Sstevel@tonic-gate 2235*0Sstevel@tonic-gate /* 2236*0Sstevel@tonic-gate * splitfile dump a large file across volumes 2237*0Sstevel@tonic-gate * 2238*0Sstevel@tonic-gate * splitfile(longname, fd); 2239*0Sstevel@tonic-gate * char *longname; full name of file 2240*0Sstevel@tonic-gate * int ifd; input file descriptor 2241*0Sstevel@tonic-gate * 2242*0Sstevel@tonic-gate * NOTE: only called by putfile() to dump a large file. 2243*0Sstevel@tonic-gate */ 2244*0Sstevel@tonic-gate 2245*0Sstevel@tonic-gate static void 2246*0Sstevel@tonic-gate splitfile(char *longname, int ifd, char *name, char *prefix, int filetype) 2247*0Sstevel@tonic-gate { 2248*0Sstevel@tonic-gate blkcnt_t blocks; 2249*0Sstevel@tonic-gate off_t bytes, s; 2250*0Sstevel@tonic-gate char buf[TBLOCK]; 2251*0Sstevel@tonic-gate int i, extents; 2252*0Sstevel@tonic-gate 2253*0Sstevel@tonic-gate blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */ 2254*0Sstevel@tonic-gate 2255*0Sstevel@tonic-gate /* 2256*0Sstevel@tonic-gate * # extents = 2257*0Sstevel@tonic-gate * size of file after using up rest of this floppy 2258*0Sstevel@tonic-gate * blocks - (blocklim - tapepos) + 1 (for header) 2259*0Sstevel@tonic-gate * plus roundup value before divide by blocklim-1 2260*0Sstevel@tonic-gate * + (blocklim - 1) - 1 2261*0Sstevel@tonic-gate * all divided by blocklim-1 (one block for each header). 2262*0Sstevel@tonic-gate * this gives 2263*0Sstevel@tonic-gate * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1) 2264*0Sstevel@tonic-gate * which reduces to the expression used. 2265*0Sstevel@tonic-gate * one is added to account for this first extent. 2266*0Sstevel@tonic-gate * 2267*0Sstevel@tonic-gate * When one is dealing with extremely large archives, one may want 2268*0Sstevel@tonic-gate * to allow for a large number of extents. This code should be 2269*0Sstevel@tonic-gate * revisited to determine if extents should be changed to something 2270*0Sstevel@tonic-gate * larger than an int. 2271*0Sstevel@tonic-gate */ 2272*0Sstevel@tonic-gate extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1); 2273*0Sstevel@tonic-gate 2274*0Sstevel@tonic-gate if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */ 2275*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2276*0Sstevel@tonic-gate "tar: %s needs unusual number of volumes to split\n" 2277*0Sstevel@tonic-gate "tar: %s not dumped\n"), longname, longname); 2278*0Sstevel@tonic-gate return; 2279*0Sstevel@tonic-gate } 2280*0Sstevel@tonic-gate if (build_dblock(name, tchar, '0', filetype, 2281*0Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix) != 0) 2282*0Sstevel@tonic-gate return; 2283*0Sstevel@tonic-gate 2284*0Sstevel@tonic-gate dblock.dbuf.extotal = extents; 2285*0Sstevel@tonic-gate bytes = stbuf.st_size; 2286*0Sstevel@tonic-gate 2287*0Sstevel@tonic-gate /* 2288*0Sstevel@tonic-gate * The value contained in dblock.dbuf.efsize was formerly used when the 2289*0Sstevel@tonic-gate * v flag was specified in conjunction with the t flag. Although it is 2290*0Sstevel@tonic-gate * no longer used, older versions of tar will expect the former 2291*0Sstevel@tonic-gate * behaviour, so we must continue to write it to the archive. 2292*0Sstevel@tonic-gate * 2293*0Sstevel@tonic-gate * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it 2294*0Sstevel@tonic-gate * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply 2295*0Sstevel@tonic-gate * store 0. 2296*0Sstevel@tonic-gate */ 2297*0Sstevel@tonic-gate if (bytes <= TAR_EFSIZE_MAX) 2298*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes); 2299*0Sstevel@tonic-gate else 2300*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0); 2301*0Sstevel@tonic-gate 2302*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2303*0Sstevel@tonic-gate "tar: large file %s needs %d extents.\n" 2304*0Sstevel@tonic-gate "tar: current device seek position = %" FMT_blkcnt_t "K\n"), 2305*0Sstevel@tonic-gate longname, extents, K(tapepos)); 2306*0Sstevel@tonic-gate 2307*0Sstevel@tonic-gate s = (off_t)(blocklim - tapepos - 1) * TBLOCK; 2308*0Sstevel@tonic-gate for (i = 1; i <= extents; i++) { 2309*0Sstevel@tonic-gate if (i > 1) { 2310*0Sstevel@tonic-gate newvol(); 2311*0Sstevel@tonic-gate if (i == extents) 2312*0Sstevel@tonic-gate s = bytes; /* last ext. gets true bytes */ 2313*0Sstevel@tonic-gate else 2314*0Sstevel@tonic-gate s = (off_t)(blocklim - 1)*TBLOCK; /* all */ 2315*0Sstevel@tonic-gate } 2316*0Sstevel@tonic-gate bytes -= s; 2317*0Sstevel@tonic-gate blocks = TBLOCKS(s); 2318*0Sstevel@tonic-gate 2319*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s); 2320*0Sstevel@tonic-gate dblock.dbuf.extno = i; 2321*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 2322*0Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 2323*0Sstevel@tonic-gate 2324*0Sstevel@tonic-gate if (vflag) 2325*0Sstevel@tonic-gate (void) fprintf(vfile, 2326*0Sstevel@tonic-gate "+++ a %s %" FMT_blkcnt_t "K [extent #%d of %d]\n", 2327*0Sstevel@tonic-gate longname, K(blocks), i, extents); 2328*0Sstevel@tonic-gate while (blocks && read(ifd, buf, TBLOCK) > 0) { 2329*0Sstevel@tonic-gate blocks--; 2330*0Sstevel@tonic-gate (void) writetbuf(buf, 1); 2331*0Sstevel@tonic-gate } 2332*0Sstevel@tonic-gate if (blocks != 0) { 2333*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2334*0Sstevel@tonic-gate "tar: %s: file changed size\n"), longname); 2335*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2336*0Sstevel@tonic-gate "tar: aborting split file %s\n"), longname); 2337*0Sstevel@tonic-gate (void) close(ifd); 2338*0Sstevel@tonic-gate return; 2339*0Sstevel@tonic-gate } 2340*0Sstevel@tonic-gate } 2341*0Sstevel@tonic-gate (void) close(ifd); 2342*0Sstevel@tonic-gate if (vflag) 2343*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d " 2344*0Sstevel@tonic-gate "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)), 2345*0Sstevel@tonic-gate extents); 2346*0Sstevel@tonic-gate } 2347*0Sstevel@tonic-gate 2348*0Sstevel@tonic-gate /* 2349*0Sstevel@tonic-gate * convtoreg - determines whether the file should be converted to a 2350*0Sstevel@tonic-gate * regular file when extracted 2351*0Sstevel@tonic-gate * 2352*0Sstevel@tonic-gate * Returns 1 when file size > 0 and typeflag is not recognized 2353*0Sstevel@tonic-gate * Otherwise returns 0 2354*0Sstevel@tonic-gate */ 2355*0Sstevel@tonic-gate static int 2356*0Sstevel@tonic-gate convtoreg(off_t size) 2357*0Sstevel@tonic-gate { 2358*0Sstevel@tonic-gate if ((size > 0) && (dblock.dbuf.typeflag != '0') && 2359*0Sstevel@tonic-gate (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') && 2360*0Sstevel@tonic-gate (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') && 2361*0Sstevel@tonic-gate (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') && 2362*0Sstevel@tonic-gate (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') && 2363*0Sstevel@tonic-gate (dblock.dbuf.typeflag != _XATTR_HDRTYPE) && 2364*0Sstevel@tonic-gate (dblock.dbuf.typeflag != 'X')) { 2365*0Sstevel@tonic-gate return (1); 2366*0Sstevel@tonic-gate } 2367*0Sstevel@tonic-gate return (0); 2368*0Sstevel@tonic-gate } 2369*0Sstevel@tonic-gate 2370*0Sstevel@tonic-gate static void 2371*0Sstevel@tonic-gate #ifdef _iBCS2 2372*0Sstevel@tonic-gate doxtract(char *argv[], int tbl_cnt) 2373*0Sstevel@tonic-gate #else 2374*0Sstevel@tonic-gate doxtract(char *argv[]) 2375*0Sstevel@tonic-gate #endif 2376*0Sstevel@tonic-gate { 2377*0Sstevel@tonic-gate struct stat xtractbuf; /* stat on file after extracting */ 2378*0Sstevel@tonic-gate blkcnt_t blocks; 2379*0Sstevel@tonic-gate off_t bytes; 2380*0Sstevel@tonic-gate int ofile; 2381*0Sstevel@tonic-gate int newfile; /* Does the file already exist */ 2382*0Sstevel@tonic-gate int xcnt = 0; /* count # files extracted */ 2383*0Sstevel@tonic-gate int fcnt = 0; /* count # files in argv list */ 2384*0Sstevel@tonic-gate int dir; 2385*0Sstevel@tonic-gate int dirfd = -1; 2386*0Sstevel@tonic-gate uid_t Uid; 2387*0Sstevel@tonic-gate char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */ 2388*0Sstevel@tonic-gate char dirname[PATH_MAX+1]; 2389*0Sstevel@tonic-gate char templink[PATH_MAX+1]; /* temp link with terminating NULL */ 2390*0Sstevel@tonic-gate char origdir[PATH_MAX+1]; 2391*0Sstevel@tonic-gate int once = 1; 2392*0Sstevel@tonic-gate int error; 2393*0Sstevel@tonic-gate int symflag; 2394*0Sstevel@tonic-gate int want; 2395*0Sstevel@tonic-gate aclent_t *aclp = NULL; /* acl buffer pointer */ 2396*0Sstevel@tonic-gate int aclcnt = 0; /* acl entries count */ 2397*0Sstevel@tonic-gate timestruc_t time_zero; /* used for call to doDirTimes */ 2398*0Sstevel@tonic-gate int dircreate; 2399*0Sstevel@tonic-gate int convflag; 2400*0Sstevel@tonic-gate 2401*0Sstevel@tonic-gate time_zero.tv_sec = 0; 2402*0Sstevel@tonic-gate time_zero.tv_nsec = 0; 2403*0Sstevel@tonic-gate 2404*0Sstevel@tonic-gate dumping = 0; /* for newvol(), et al: we are not writing */ 2405*0Sstevel@tonic-gate 2406*0Sstevel@tonic-gate /* 2407*0Sstevel@tonic-gate * Count the number of files that are to be extracted 2408*0Sstevel@tonic-gate */ 2409*0Sstevel@tonic-gate Uid = getuid(); 2410*0Sstevel@tonic-gate 2411*0Sstevel@tonic-gate #ifdef _iBCS2 2412*0Sstevel@tonic-gate initarg(argv, Filefile); 2413*0Sstevel@tonic-gate while (nextarg() != NULL) 2414*0Sstevel@tonic-gate ++fcnt; 2415*0Sstevel@tonic-gate fcnt += tbl_cnt; 2416*0Sstevel@tonic-gate #endif /* _iBCS2 */ 2417*0Sstevel@tonic-gate 2418*0Sstevel@tonic-gate for (;;) { 2419*0Sstevel@tonic-gate convflag = 0; 2420*0Sstevel@tonic-gate symflag = 0; 2421*0Sstevel@tonic-gate dir = 0; 2422*0Sstevel@tonic-gate ofile = -1; 2423*0Sstevel@tonic-gate 2424*0Sstevel@tonic-gate /* namep is set by wantit to point to the full name */ 2425*0Sstevel@tonic-gate if ((want = wantit(argv, &namep, &dirp, &comp)) == 0) { 2426*0Sstevel@tonic-gate #if defined(O_XATTR) 2427*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2428*0Sstevel@tonic-gate free(xattrhead); 2429*0Sstevel@tonic-gate xattrp = NULL; 2430*0Sstevel@tonic-gate xattr_linkp = NULL; 2431*0Sstevel@tonic-gate xattrhead = NULL; 2432*0Sstevel@tonic-gate } 2433*0Sstevel@tonic-gate #endif 2434*0Sstevel@tonic-gate continue; 2435*0Sstevel@tonic-gate } 2436*0Sstevel@tonic-gate if (want == -1) 2437*0Sstevel@tonic-gate break; 2438*0Sstevel@tonic-gate 2439*0Sstevel@tonic-gate if (dirfd != -1) 2440*0Sstevel@tonic-gate (void) close(dirfd); 2441*0Sstevel@tonic-gate 2442*0Sstevel@tonic-gate (void) strcpy(&dirname[0], namep); 2443*0Sstevel@tonic-gate dircreate = checkdir(&dirname[0]); 2444*0Sstevel@tonic-gate 2445*0Sstevel@tonic-gate #if defined(O_XATTR) 2446*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2447*0Sstevel@tonic-gate dirfd = attropen(dirp, ".", O_RDONLY); 2448*0Sstevel@tonic-gate } else { 2449*0Sstevel@tonic-gate dirfd = open(dirp, O_RDONLY); 2450*0Sstevel@tonic-gate } 2451*0Sstevel@tonic-gate #else 2452*0Sstevel@tonic-gate dirfd = open(dirp, O_RDONLY); 2453*0Sstevel@tonic-gate #endif 2454*0Sstevel@tonic-gate 2455*0Sstevel@tonic-gate if (dirfd == -1) { 2456*0Sstevel@tonic-gate #if defined(O_XATTR) 2457*0Sstevel@tonic-gate if (xattrp) { 2458*0Sstevel@tonic-gate dirfd = retry_attrdir_open(dirp); 2459*0Sstevel@tonic-gate } 2460*0Sstevel@tonic-gate #endif 2461*0Sstevel@tonic-gate if (dirfd == -1) { 2462*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2463*0Sstevel@tonic-gate "tar: cannot open %s %s\n"), dirp, 2464*0Sstevel@tonic-gate strerror(errno)); 2465*0Sstevel@tonic-gate passtape(); 2466*0Sstevel@tonic-gate continue; 2467*0Sstevel@tonic-gate } 2468*0Sstevel@tonic-gate } 2469*0Sstevel@tonic-gate 2470*0Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) 2471*0Sstevel@tonic-gate (void) strcpy(templink, Xtarhdr.x_linkpath); 2472*0Sstevel@tonic-gate else { 2473*0Sstevel@tonic-gate #if defined(O_XATTR) 2474*0Sstevel@tonic-gate if (xattrp && dblock.dbuf.typeflag == '1') { 2475*0Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 2476*0Sstevel@tonic-gate xattrp->h_names); 2477*0Sstevel@tonic-gate } else { 2478*0Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 2479*0Sstevel@tonic-gate dblock.dbuf.linkname); 2480*0Sstevel@tonic-gate } 2481*0Sstevel@tonic-gate #else 2482*0Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 2483*0Sstevel@tonic-gate dblock.dbuf.linkname); 2484*0Sstevel@tonic-gate #endif 2485*0Sstevel@tonic-gate } 2486*0Sstevel@tonic-gate 2487*0Sstevel@tonic-gate if (Fflag) { 2488*0Sstevel@tonic-gate char *s; 2489*0Sstevel@tonic-gate 2490*0Sstevel@tonic-gate if ((s = strrchr(namep, '/')) == 0) 2491*0Sstevel@tonic-gate s = namep; 2492*0Sstevel@tonic-gate 2493*0Sstevel@tonic-gate else 2494*0Sstevel@tonic-gate s++; 2495*0Sstevel@tonic-gate if (checkf(s, stbuf.st_mode, Fflag) == 0) { 2496*0Sstevel@tonic-gate passtape(); 2497*0Sstevel@tonic-gate continue; 2498*0Sstevel@tonic-gate } 2499*0Sstevel@tonic-gate } 2500*0Sstevel@tonic-gate 2501*0Sstevel@tonic-gate if (checkw('x', namep) == 0) { 2502*0Sstevel@tonic-gate passtape(); 2503*0Sstevel@tonic-gate continue; 2504*0Sstevel@tonic-gate } 2505*0Sstevel@tonic-gate if (once) { 2506*0Sstevel@tonic-gate if (strcmp(dblock.dbuf.magic, magic_type) == 0) { 2507*0Sstevel@tonic-gate if (geteuid() == (uid_t)0) { 2508*0Sstevel@tonic-gate checkflag = 1; 2509*0Sstevel@tonic-gate pflag = 1; 2510*0Sstevel@tonic-gate } else { 2511*0Sstevel@tonic-gate /* get file creation mask */ 2512*0Sstevel@tonic-gate Oumask = umask(0); 2513*0Sstevel@tonic-gate (void) umask(Oumask); 2514*0Sstevel@tonic-gate } 2515*0Sstevel@tonic-gate once = 0; 2516*0Sstevel@tonic-gate } else { 2517*0Sstevel@tonic-gate if (geteuid() == (uid_t)0) { 2518*0Sstevel@tonic-gate pflag = 1; 2519*0Sstevel@tonic-gate checkflag = 2; 2520*0Sstevel@tonic-gate } 2521*0Sstevel@tonic-gate if (!pflag) { 2522*0Sstevel@tonic-gate /* get file creation mask */ 2523*0Sstevel@tonic-gate Oumask = umask(0); 2524*0Sstevel@tonic-gate (void) umask(Oumask); 2525*0Sstevel@tonic-gate } 2526*0Sstevel@tonic-gate once = 0; 2527*0Sstevel@tonic-gate } 2528*0Sstevel@tonic-gate } 2529*0Sstevel@tonic-gate 2530*0Sstevel@tonic-gate #if defined(O_XATTR) 2531*0Sstevel@tonic-gate /* 2532*0Sstevel@tonic-gate * Handle extraction of hidden attr dir. 2533*0Sstevel@tonic-gate * Dir is automatically created, we only 2534*0Sstevel@tonic-gate * need to update mode and perm's. 2535*0Sstevel@tonic-gate */ 2536*0Sstevel@tonic-gate if ((xattrp != (struct xattr_buf *)NULL) && Hiddendir == 1) { 2537*0Sstevel@tonic-gate if (fchownat(dirfd, ".", stbuf.st_uid, 2538*0Sstevel@tonic-gate stbuf.st_gid, 0) != 0) { 2539*0Sstevel@tonic-gate vperror(0, gettext( 2540*0Sstevel@tonic-gate "%s: failed to set ownership of attribute" 2541*0Sstevel@tonic-gate " directory"), namep); 2542*0Sstevel@tonic-gate } 2543*0Sstevel@tonic-gate 2544*0Sstevel@tonic-gate if (fchmod(dirfd, stbuf.st_mode) != 0) { 2545*0Sstevel@tonic-gate vperror(0, gettext( 2546*0Sstevel@tonic-gate "%s: failed to set permissions of" 2547*0Sstevel@tonic-gate " attribute directory"), namep); 2548*0Sstevel@tonic-gate } 2549*0Sstevel@tonic-gate goto filedone; 2550*0Sstevel@tonic-gate } 2551*0Sstevel@tonic-gate #endif 2552*0Sstevel@tonic-gate 2553*0Sstevel@tonic-gate if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) { 2554*0Sstevel@tonic-gate dir = 1; 2555*0Sstevel@tonic-gate if (vflag) { 2556*0Sstevel@tonic-gate (void) fprintf(vfile, "x %s, 0 bytes, ", 2557*0Sstevel@tonic-gate &dirname[0]); 2558*0Sstevel@tonic-gate if (NotTape) 2559*0Sstevel@tonic-gate (void) fprintf(vfile, "0K\n"); 2560*0Sstevel@tonic-gate else 2561*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2562*0Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), 2563*0Sstevel@tonic-gate (blkcnt_t)0); 2564*0Sstevel@tonic-gate } 2565*0Sstevel@tonic-gate goto filedone; 2566*0Sstevel@tonic-gate } 2567*0Sstevel@tonic-gate 2568*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '6') { /* FIFO */ 2569*0Sstevel@tonic-gate if (rmdir(namep) < 0) { 2570*0Sstevel@tonic-gate if (errno == ENOTDIR) 2571*0Sstevel@tonic-gate (void) unlink(namep); 2572*0Sstevel@tonic-gate } 2573*0Sstevel@tonic-gate linkp = templink; 2574*0Sstevel@tonic-gate if (*linkp != NULL) { 2575*0Sstevel@tonic-gate if (Aflag && *linkp == '/') 2576*0Sstevel@tonic-gate linkp++; 2577*0Sstevel@tonic-gate if (link(linkp, namep) < 0) { 2578*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2579*0Sstevel@tonic-gate "tar: %s: cannot link\n"), namep); 2580*0Sstevel@tonic-gate continue; 2581*0Sstevel@tonic-gate } 2582*0Sstevel@tonic-gate if (vflag) 2583*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2584*0Sstevel@tonic-gate "%s linked to %s\n"), namep, linkp); 2585*0Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2586*0Sstevel@tonic-gate continue; 2587*0Sstevel@tonic-gate } 2588*0Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFIFO), 2589*0Sstevel@tonic-gate (int)Gen.g_devmajor) < 0) { 2590*0Sstevel@tonic-gate vperror(0, gettext("%s: mknod failed"), namep); 2591*0Sstevel@tonic-gate continue; 2592*0Sstevel@tonic-gate } 2593*0Sstevel@tonic-gate bytes = stbuf.st_size; 2594*0Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2595*0Sstevel@tonic-gate if (vflag) { 2596*0Sstevel@tonic-gate (void) fprintf(vfile, "x %s, %" FMT_off_t 2597*0Sstevel@tonic-gate " bytes, ", namep, bytes); 2598*0Sstevel@tonic-gate if (NotTape) 2599*0Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t 2600*0Sstevel@tonic-gate "K\n", K(blocks)); 2601*0Sstevel@tonic-gate else 2602*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2603*0Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), 2604*0Sstevel@tonic-gate blocks); 2605*0Sstevel@tonic-gate } 2606*0Sstevel@tonic-gate goto filedone; 2607*0Sstevel@tonic-gate } 2608*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */ 2609*0Sstevel@tonic-gate if (rmdir(namep) < 0) { 2610*0Sstevel@tonic-gate if (errno == ENOTDIR) 2611*0Sstevel@tonic-gate (void) unlink(namep); 2612*0Sstevel@tonic-gate } 2613*0Sstevel@tonic-gate linkp = templink; 2614*0Sstevel@tonic-gate if (*linkp != NULL) { 2615*0Sstevel@tonic-gate if (Aflag && *linkp == '/') 2616*0Sstevel@tonic-gate linkp++; 2617*0Sstevel@tonic-gate if (link(linkp, namep) < 0) { 2618*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2619*0Sstevel@tonic-gate "tar: %s: cannot link\n"), namep); 2620*0Sstevel@tonic-gate continue; 2621*0Sstevel@tonic-gate } 2622*0Sstevel@tonic-gate if (vflag) 2623*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2624*0Sstevel@tonic-gate "%s linked to %s\n"), namep, linkp); 2625*0Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2626*0Sstevel@tonic-gate continue; 2627*0Sstevel@tonic-gate } 2628*0Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFCHR), 2629*0Sstevel@tonic-gate (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) { 2630*0Sstevel@tonic-gate vperror(0, gettext( 2631*0Sstevel@tonic-gate "%s: mknod failed"), namep); 2632*0Sstevel@tonic-gate continue; 2633*0Sstevel@tonic-gate } 2634*0Sstevel@tonic-gate bytes = stbuf.st_size; 2635*0Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2636*0Sstevel@tonic-gate if (vflag) { 2637*0Sstevel@tonic-gate (void) fprintf(vfile, "x %s, %" FMT_off_t 2638*0Sstevel@tonic-gate " bytes, ", namep, bytes); 2639*0Sstevel@tonic-gate if (NotTape) 2640*0Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t 2641*0Sstevel@tonic-gate "K\n", K(blocks)); 2642*0Sstevel@tonic-gate else 2643*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2644*0Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), 2645*0Sstevel@tonic-gate blocks); 2646*0Sstevel@tonic-gate } 2647*0Sstevel@tonic-gate goto filedone; 2648*0Sstevel@tonic-gate } else if (dblock.dbuf.typeflag == '3' && Uid) { 2649*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2650*0Sstevel@tonic-gate "Can't create special %s\n"), namep); 2651*0Sstevel@tonic-gate continue; 2652*0Sstevel@tonic-gate } 2653*0Sstevel@tonic-gate 2654*0Sstevel@tonic-gate /* BLOCK SPECIAL */ 2655*0Sstevel@tonic-gate 2656*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '4' && !Uid) { 2657*0Sstevel@tonic-gate if (rmdir(namep) < 0) { 2658*0Sstevel@tonic-gate if (errno == ENOTDIR) 2659*0Sstevel@tonic-gate (void) unlink(namep); 2660*0Sstevel@tonic-gate } 2661*0Sstevel@tonic-gate linkp = templink; 2662*0Sstevel@tonic-gate if (*linkp != NULL) { 2663*0Sstevel@tonic-gate if (Aflag && *linkp == '/') 2664*0Sstevel@tonic-gate linkp++; 2665*0Sstevel@tonic-gate if (link(linkp, namep) < 0) { 2666*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2667*0Sstevel@tonic-gate "tar: %s: cannot link\n"), namep); 2668*0Sstevel@tonic-gate continue; 2669*0Sstevel@tonic-gate } 2670*0Sstevel@tonic-gate if (vflag) 2671*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2672*0Sstevel@tonic-gate "%s linked to %s\n"), namep, linkp); 2673*0Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2674*0Sstevel@tonic-gate continue; 2675*0Sstevel@tonic-gate } 2676*0Sstevel@tonic-gate if (mknod(namep, (int)(Gen.g_mode|S_IFBLK), 2677*0Sstevel@tonic-gate (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) { 2678*0Sstevel@tonic-gate vperror(0, gettext("%s: mknod failed"), namep); 2679*0Sstevel@tonic-gate continue; 2680*0Sstevel@tonic-gate } 2681*0Sstevel@tonic-gate bytes = stbuf.st_size; 2682*0Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2683*0Sstevel@tonic-gate if (vflag) { 2684*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("x %s, %" 2685*0Sstevel@tonic-gate FMT_off_t " bytes, "), namep, bytes); 2686*0Sstevel@tonic-gate if (NotTape) 2687*0Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t 2688*0Sstevel@tonic-gate "K\n", K(blocks)); 2689*0Sstevel@tonic-gate else 2690*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2691*0Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), 2692*0Sstevel@tonic-gate blocks); 2693*0Sstevel@tonic-gate } 2694*0Sstevel@tonic-gate goto filedone; 2695*0Sstevel@tonic-gate } else if (dblock.dbuf.typeflag == '4' && Uid) { 2696*0Sstevel@tonic-gate (void) fprintf(stderr, 2697*0Sstevel@tonic-gate gettext("Can't create special %s\n"), namep); 2698*0Sstevel@tonic-gate continue; 2699*0Sstevel@tonic-gate } 2700*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2') { /* symlink */ 2701*0Sstevel@tonic-gate linkp = templink; 2702*0Sstevel@tonic-gate if (Aflag && *linkp == '/') 2703*0Sstevel@tonic-gate linkp++; 2704*0Sstevel@tonic-gate if (rmdir(namep) < 0) { 2705*0Sstevel@tonic-gate if (errno == ENOTDIR) 2706*0Sstevel@tonic-gate (void) unlink(namep); 2707*0Sstevel@tonic-gate } 2708*0Sstevel@tonic-gate if (symlink(linkp, namep) < 0) { 2709*0Sstevel@tonic-gate vperror(0, gettext("%s: symbolic link failed"), 2710*0Sstevel@tonic-gate namep); 2711*0Sstevel@tonic-gate continue; 2712*0Sstevel@tonic-gate } 2713*0Sstevel@tonic-gate if (vflag) 2714*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2715*0Sstevel@tonic-gate "x %s symbolic link to %s\n"), 2716*0Sstevel@tonic-gate namep, linkp); 2717*0Sstevel@tonic-gate 2718*0Sstevel@tonic-gate symflag = AT_SYMLINK_NOFOLLOW; 2719*0Sstevel@tonic-gate goto filedone; 2720*0Sstevel@tonic-gate } 2721*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1') { 2722*0Sstevel@tonic-gate linkp = templink; 2723*0Sstevel@tonic-gate if (Aflag && *linkp == '/') 2724*0Sstevel@tonic-gate linkp++; 2725*0Sstevel@tonic-gate if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) { 2726*0Sstevel@tonic-gate if (errno == ENOTDIR) 2727*0Sstevel@tonic-gate (void) unlinkat(dirfd, comp, 0); 2728*0Sstevel@tonic-gate } 2729*0Sstevel@tonic-gate #if defined(O_XATTR) 2730*0Sstevel@tonic-gate if (xattrp && xattr_linkp) { 2731*0Sstevel@tonic-gate if (getcwd(origdir, (PATH_MAX+1)) == 2732*0Sstevel@tonic-gate (char *)NULL) { 2733*0Sstevel@tonic-gate vperror(0, gettext( 2734*0Sstevel@tonic-gate "A parent directory cannot" 2735*0Sstevel@tonic-gate " be read")); 2736*0Sstevel@tonic-gate exit(1); 2737*0Sstevel@tonic-gate } 2738*0Sstevel@tonic-gate 2739*0Sstevel@tonic-gate if (fchdir(dirfd) < 0) { 2740*0Sstevel@tonic-gate vperror(0, gettext( 2741*0Sstevel@tonic-gate "Cannot fchdir to attribute " 2742*0Sstevel@tonic-gate "directory")); 2743*0Sstevel@tonic-gate exit(1); 2744*0Sstevel@tonic-gate } 2745*0Sstevel@tonic-gate 2746*0Sstevel@tonic-gate error = link(xattr_linkaname, xattraname); 2747*0Sstevel@tonic-gate if (chdir(origdir) < 0) { 2748*0Sstevel@tonic-gate vperror(0, gettext( 2749*0Sstevel@tonic-gate "Cannot chdir out of attribute " 2750*0Sstevel@tonic-gate "directory")); 2751*0Sstevel@tonic-gate exit(1); 2752*0Sstevel@tonic-gate } 2753*0Sstevel@tonic-gate } else { 2754*0Sstevel@tonic-gate error = link(linkp, namep); 2755*0Sstevel@tonic-gate } 2756*0Sstevel@tonic-gate #else 2757*0Sstevel@tonic-gate error = link(linkp, namep); 2758*0Sstevel@tonic-gate #endif 2759*0Sstevel@tonic-gate 2760*0Sstevel@tonic-gate if (error < 0) { 2761*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2762*0Sstevel@tonic-gate "tar: %s%s%s: cannot link\n"), 2763*0Sstevel@tonic-gate namep, (xattr_linkp != NULL) ? 2764*0Sstevel@tonic-gate gettext(" attribute ") : "", 2765*0Sstevel@tonic-gate (xattr_linkp != NULL) ? 2766*0Sstevel@tonic-gate xattraname : ""); 2767*0Sstevel@tonic-gate continue; 2768*0Sstevel@tonic-gate } 2769*0Sstevel@tonic-gate if (vflag) 2770*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2771*0Sstevel@tonic-gate "%s%s%s linked to %s%s%s\n"), namep, 2772*0Sstevel@tonic-gate (xattr_linkp != NULL) ? 2773*0Sstevel@tonic-gate gettext(" attribute ") : "", 2774*0Sstevel@tonic-gate (xattr_linkp != NULL) ? 2775*0Sstevel@tonic-gate xattr_linkaname : "", 2776*0Sstevel@tonic-gate linkp, (xattr_linkp != NULL) ? 2777*0Sstevel@tonic-gate gettext(" attribute ") : "", 2778*0Sstevel@tonic-gate (xattr_linkp != NULL) ? 2779*0Sstevel@tonic-gate xattraname : ""); 2780*0Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2781*0Sstevel@tonic-gate #if defined(O_XATTR) 2782*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2783*0Sstevel@tonic-gate free(xattrhead); 2784*0Sstevel@tonic-gate xattrp = NULL; 2785*0Sstevel@tonic-gate xattr_linkp = NULL; 2786*0Sstevel@tonic-gate xattrhead = NULL; 2787*0Sstevel@tonic-gate } 2788*0Sstevel@tonic-gate #endif 2789*0Sstevel@tonic-gate continue; 2790*0Sstevel@tonic-gate } 2791*0Sstevel@tonic-gate 2792*0Sstevel@tonic-gate /* REGULAR FILES */ 2793*0Sstevel@tonic-gate 2794*0Sstevel@tonic-gate if (convtoreg(stbuf.st_size)) { 2795*0Sstevel@tonic-gate convflag = 1; 2796*0Sstevel@tonic-gate if (errflag) { 2797*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2798*0Sstevel@tonic-gate "tar: %s: typeflag '%c' not recognized\n"), 2799*0Sstevel@tonic-gate namep, dblock.dbuf.typeflag); 2800*0Sstevel@tonic-gate done(1); 2801*0Sstevel@tonic-gate } else { 2802*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2803*0Sstevel@tonic-gate "tar: %s: typeflag '%c' not recognized, " 2804*0Sstevel@tonic-gate "converting to regular file\n"), namep, 2805*0Sstevel@tonic-gate dblock.dbuf.typeflag); 2806*0Sstevel@tonic-gate Errflg = 1; 2807*0Sstevel@tonic-gate } 2808*0Sstevel@tonic-gate } 2809*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '0' || 2810*0Sstevel@tonic-gate dblock.dbuf.typeflag == NULL || convflag) { 2811*0Sstevel@tonic-gate delete_target(dirfd, comp); 2812*0Sstevel@tonic-gate linkp = templink; 2813*0Sstevel@tonic-gate if (*linkp != NULL) { 2814*0Sstevel@tonic-gate if (Aflag && *linkp == '/') 2815*0Sstevel@tonic-gate linkp++; 2816*0Sstevel@tonic-gate if (link(linkp, comp) < 0) { 2817*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2818*0Sstevel@tonic-gate "tar: %s: cannot link\n"), namep); 2819*0Sstevel@tonic-gate continue; 2820*0Sstevel@tonic-gate } 2821*0Sstevel@tonic-gate if (vflag) 2822*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 2823*0Sstevel@tonic-gate "%s linked to %s\n"), comp, linkp); 2824*0Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2825*0Sstevel@tonic-gate continue; 2826*0Sstevel@tonic-gate } 2827*0Sstevel@tonic-gate newfile = ((fstatat(dirfd, comp, 2828*0Sstevel@tonic-gate &xtractbuf, 0) == -1) ? TRUE : FALSE); 2829*0Sstevel@tonic-gate if ((ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC, 2830*0Sstevel@tonic-gate stbuf.st_mode & MODEMASK)) < 0) { 2831*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2832*0Sstevel@tonic-gate "tar: %s - cannot create\n"), comp); 2833*0Sstevel@tonic-gate if (errflag) 2834*0Sstevel@tonic-gate done(1); 2835*0Sstevel@tonic-gate else 2836*0Sstevel@tonic-gate Errflg = 1; 2837*0Sstevel@tonic-gate passtape(); 2838*0Sstevel@tonic-gate continue; 2839*0Sstevel@tonic-gate } 2840*0Sstevel@tonic-gate 2841*0Sstevel@tonic-gate if (extno != 0) { /* file is in pieces */ 2842*0Sstevel@tonic-gate if (extotal < 1 || extotal > MAXEXT) 2843*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2844*0Sstevel@tonic-gate "tar: ignoring bad extent info for %s\n"), 2845*0Sstevel@tonic-gate comp); 2846*0Sstevel@tonic-gate else { 2847*0Sstevel@tonic-gate xsfile(ofile); /* extract it */ 2848*0Sstevel@tonic-gate goto filedone; 2849*0Sstevel@tonic-gate } 2850*0Sstevel@tonic-gate } 2851*0Sstevel@tonic-gate extno = 0; /* let everyone know file is not split */ 2852*0Sstevel@tonic-gate bytes = stbuf.st_size; 2853*0Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2854*0Sstevel@tonic-gate if (vflag) { 2855*0Sstevel@tonic-gate (void) fprintf(vfile, 2856*0Sstevel@tonic-gate "x %s%s%s, %" FMT_off_t " bytes, ", 2857*0Sstevel@tonic-gate (xattrp == NULL) ? "" : dirp, 2858*0Sstevel@tonic-gate (xattrp == NULL) ? "" : gettext(" attribute "), 2859*0Sstevel@tonic-gate (xattrp == NULL) ? namep : comp, bytes); 2860*0Sstevel@tonic-gate if (NotTape) 2861*0Sstevel@tonic-gate (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n", 2862*0Sstevel@tonic-gate K(blocks)); 2863*0Sstevel@tonic-gate else 2864*0Sstevel@tonic-gate (void) fprintf(vfile, gettext("%" 2865*0Sstevel@tonic-gate FMT_blkcnt_t " tape blocks\n"), blocks); 2866*0Sstevel@tonic-gate } 2867*0Sstevel@tonic-gate 2868*0Sstevel@tonic-gate xblocks(bytes, ofile); 2869*0Sstevel@tonic-gate filedone: 2870*0Sstevel@tonic-gate if (mflag == 0 && !symflag) { 2871*0Sstevel@tonic-gate if (dir) 2872*0Sstevel@tonic-gate doDirTimes(namep, stbuf.st_mtim); 2873*0Sstevel@tonic-gate else 2874*0Sstevel@tonic-gate setPathTimes(dirfd, comp, stbuf.st_mtim); 2875*0Sstevel@tonic-gate } 2876*0Sstevel@tonic-gate 2877*0Sstevel@tonic-gate /* moved this code from above */ 2878*0Sstevel@tonic-gate if (pflag && !symflag && Hiddendir == 0) { 2879*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) 2880*0Sstevel@tonic-gate (void) fchmod(ofile, stbuf.st_mode & MODEMASK); 2881*0Sstevel@tonic-gate else 2882*0Sstevel@tonic-gate (void) chmod(namep, stbuf.st_mode & MODEMASK); 2883*0Sstevel@tonic-gate } 2884*0Sstevel@tonic-gate 2885*0Sstevel@tonic-gate 2886*0Sstevel@tonic-gate /* 2887*0Sstevel@tonic-gate * Because ancillary file preceeds the normal file, 2888*0Sstevel@tonic-gate * acl info may have been retrieved (in aclp). 2889*0Sstevel@tonic-gate * All file types are directed here (go filedone). 2890*0Sstevel@tonic-gate * Always restore ACLs if there are ACLs. 2891*0Sstevel@tonic-gate */ 2892*0Sstevel@tonic-gate if (aclp != NULL) { 2893*0Sstevel@tonic-gate int ret; 2894*0Sstevel@tonic-gate 2895*0Sstevel@tonic-gate #if defined(O_XATTR) 2896*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2897*0Sstevel@tonic-gate if (Hiddendir) 2898*0Sstevel@tonic-gate ret = facl(dirfd, SETACL, 2899*0Sstevel@tonic-gate aclcnt, aclp); 2900*0Sstevel@tonic-gate else 2901*0Sstevel@tonic-gate ret = facl(ofile, SETACL, 2902*0Sstevel@tonic-gate aclcnt, aclp); 2903*0Sstevel@tonic-gate } else { 2904*0Sstevel@tonic-gate ret = acl(namep, SETACL, aclcnt, aclp); 2905*0Sstevel@tonic-gate } 2906*0Sstevel@tonic-gate #else 2907*0Sstevel@tonic-gate ret = acl(namep, SETACL, aclcnt, aclp); 2908*0Sstevel@tonic-gate #endif 2909*0Sstevel@tonic-gate if (ret < 0) { 2910*0Sstevel@tonic-gate if (pflag) { 2911*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2912*0Sstevel@tonic-gate "%s: failed to set acl entries\n"), 2913*0Sstevel@tonic-gate namep); 2914*0Sstevel@tonic-gate } 2915*0Sstevel@tonic-gate /* else: silent and continue */ 2916*0Sstevel@tonic-gate } 2917*0Sstevel@tonic-gate free(aclp); 2918*0Sstevel@tonic-gate aclp = NULL; 2919*0Sstevel@tonic-gate } 2920*0Sstevel@tonic-gate 2921*0Sstevel@tonic-gate #if defined(O_XATTR) 2922*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 2923*0Sstevel@tonic-gate free(xattrhead); 2924*0Sstevel@tonic-gate xattrp = NULL; 2925*0Sstevel@tonic-gate xattr_linkp = NULL; 2926*0Sstevel@tonic-gate xattrhead = NULL; 2927*0Sstevel@tonic-gate } 2928*0Sstevel@tonic-gate #endif 2929*0Sstevel@tonic-gate 2930*0Sstevel@tonic-gate if (!oflag) 2931*0Sstevel@tonic-gate resugname(dirfd, comp, symflag); /* set file ownership */ 2932*0Sstevel@tonic-gate 2933*0Sstevel@tonic-gate if (pflag && newfile == TRUE && !dir && 2934*0Sstevel@tonic-gate (dblock.dbuf.typeflag == '0' || 2935*0Sstevel@tonic-gate dblock.dbuf.typeflag == NULL || 2936*0Sstevel@tonic-gate convflag || dblock.dbuf.typeflag == '1')) { 2937*0Sstevel@tonic-gate if (fstat(ofile, &xtractbuf) == -1) 2938*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2939*0Sstevel@tonic-gate "tar: cannot stat extracted file %s\n"), 2940*0Sstevel@tonic-gate namep); 2941*0Sstevel@tonic-gate else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT)) 2942*0Sstevel@tonic-gate != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) { 2943*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2944*0Sstevel@tonic-gate "tar: warning - file permissions have " 2945*0Sstevel@tonic-gate "changed for %s (are 0%o, should be " 2946*0Sstevel@tonic-gate "0%o)\n"), 2947*0Sstevel@tonic-gate namep, xtractbuf.st_mode, stbuf.st_mode); 2948*0Sstevel@tonic-gate } 2949*0Sstevel@tonic-gate } 2950*0Sstevel@tonic-gate if (ofile != -1) { 2951*0Sstevel@tonic-gate (void) close(dirfd); 2952*0Sstevel@tonic-gate dirfd = -1; 2953*0Sstevel@tonic-gate if (close(ofile) != 0) 2954*0Sstevel@tonic-gate vperror(2, gettext("close error")); 2955*0Sstevel@tonic-gate } 2956*0Sstevel@tonic-gate xcnt++; /* increment # files extracted */ 2957*0Sstevel@tonic-gate } 2958*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == 'A') { /* acl info */ 2959*0Sstevel@tonic-gate char buf[TBLOCK]; 2960*0Sstevel@tonic-gate char *secp; 2961*0Sstevel@tonic-gate char *tp; 2962*0Sstevel@tonic-gate int attrsize; 2963*0Sstevel@tonic-gate int cnt; 2964*0Sstevel@tonic-gate 2965*0Sstevel@tonic-gate 2966*0Sstevel@tonic-gate if (pflag) { 2967*0Sstevel@tonic-gate bytes = stbuf.st_size; 2968*0Sstevel@tonic-gate if ((secp = malloc((int)bytes)) == NULL) { 2969*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2970*0Sstevel@tonic-gate "Insufficient memory for acl\n")); 2971*0Sstevel@tonic-gate passtape(); 2972*0Sstevel@tonic-gate continue; 2973*0Sstevel@tonic-gate } 2974*0Sstevel@tonic-gate tp = secp; 2975*0Sstevel@tonic-gate blocks = TBLOCKS(bytes); 2976*0Sstevel@tonic-gate while (blocks-- > 0) { 2977*0Sstevel@tonic-gate readtape(buf); 2978*0Sstevel@tonic-gate if (bytes <= TBLOCK) { 2979*0Sstevel@tonic-gate (void) memcpy(tp, buf, 2980*0Sstevel@tonic-gate (size_t)bytes); 2981*0Sstevel@tonic-gate break; 2982*0Sstevel@tonic-gate } else { 2983*0Sstevel@tonic-gate (void) memcpy(tp, buf, 2984*0Sstevel@tonic-gate TBLOCK); 2985*0Sstevel@tonic-gate tp += TBLOCK; 2986*0Sstevel@tonic-gate } 2987*0Sstevel@tonic-gate bytes -= TBLOCK; 2988*0Sstevel@tonic-gate } 2989*0Sstevel@tonic-gate /* got all attributes in secp */ 2990*0Sstevel@tonic-gate tp = secp; 2991*0Sstevel@tonic-gate do { 2992*0Sstevel@tonic-gate attr = (struct sec_attr *)tp; 2993*0Sstevel@tonic-gate switch (attr->attr_type) { 2994*0Sstevel@tonic-gate case UFSD_ACL: 2995*0Sstevel@tonic-gate (void) sscanf(attr->attr_len, 2996*0Sstevel@tonic-gate "%7o", (uint_t *)&aclcnt); 2997*0Sstevel@tonic-gate /* header is 8 */ 2998*0Sstevel@tonic-gate attrsize = 8 + (int)strlen( 2999*0Sstevel@tonic-gate &attr->attr_info[0]) + 1; 3000*0Sstevel@tonic-gate aclp = aclfromtext( 3001*0Sstevel@tonic-gate &attr->attr_info[0], &cnt); 3002*0Sstevel@tonic-gate if (aclp == NULL) { 3003*0Sstevel@tonic-gate (void) fprintf(stderr, 3004*0Sstevel@tonic-gate gettext( 3005*0Sstevel@tonic-gate "aclfromtext " 3006*0Sstevel@tonic-gate "failed\n")); 3007*0Sstevel@tonic-gate break; 3008*0Sstevel@tonic-gate } 3009*0Sstevel@tonic-gate if (aclcnt != cnt) { 3010*0Sstevel@tonic-gate (void) fprintf(stderr, 3011*0Sstevel@tonic-gate gettext( 3012*0Sstevel@tonic-gate "aclcnt error\n")); 3013*0Sstevel@tonic-gate break; 3014*0Sstevel@tonic-gate } 3015*0Sstevel@tonic-gate bytes -= attrsize; 3016*0Sstevel@tonic-gate break; 3017*0Sstevel@tonic-gate 3018*0Sstevel@tonic-gate /* SunFed case goes here */ 3019*0Sstevel@tonic-gate 3020*0Sstevel@tonic-gate default: 3021*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3022*0Sstevel@tonic-gate "unrecognized attr" 3023*0Sstevel@tonic-gate " type\n")); 3024*0Sstevel@tonic-gate bytes = (off_t)0; 3025*0Sstevel@tonic-gate break; 3026*0Sstevel@tonic-gate } 3027*0Sstevel@tonic-gate 3028*0Sstevel@tonic-gate /* next attributes */ 3029*0Sstevel@tonic-gate tp += attrsize; 3030*0Sstevel@tonic-gate } while (bytes != 0); 3031*0Sstevel@tonic-gate free(secp); 3032*0Sstevel@tonic-gate } else 3033*0Sstevel@tonic-gate passtape(); 3034*0Sstevel@tonic-gate } /* acl */ 3035*0Sstevel@tonic-gate 3036*0Sstevel@tonic-gate } /* for */ 3037*0Sstevel@tonic-gate 3038*0Sstevel@tonic-gate /* 3039*0Sstevel@tonic-gate * Ensure that all the directories still on the directory stack 3040*0Sstevel@tonic-gate * get their modification times set correctly by flushing the 3041*0Sstevel@tonic-gate * stack. 3042*0Sstevel@tonic-gate */ 3043*0Sstevel@tonic-gate 3044*0Sstevel@tonic-gate doDirTimes(NULL, time_zero); 3045*0Sstevel@tonic-gate 3046*0Sstevel@tonic-gate /* 3047*0Sstevel@tonic-gate * Check if the number of files extracted is different from the 3048*0Sstevel@tonic-gate * number of files listed on the command line 3049*0Sstevel@tonic-gate */ 3050*0Sstevel@tonic-gate if (fcnt > xcnt) { 3051*0Sstevel@tonic-gate (void) fprintf(stderr, 3052*0Sstevel@tonic-gate gettext("tar: %d file(s) not extracted\n"), 3053*0Sstevel@tonic-gate fcnt-xcnt); 3054*0Sstevel@tonic-gate Errflg = 1; 3055*0Sstevel@tonic-gate } 3056*0Sstevel@tonic-gate } 3057*0Sstevel@tonic-gate 3058*0Sstevel@tonic-gate /* 3059*0Sstevel@tonic-gate * xblocks extract file/extent from tape to output file 3060*0Sstevel@tonic-gate * 3061*0Sstevel@tonic-gate * xblocks(bytes, ofile); 3062*0Sstevel@tonic-gate * unsigned long long bytes; size of extent or file to be extracted 3063*0Sstevel@tonic-gate * 3064*0Sstevel@tonic-gate * called by doxtract() and xsfile() 3065*0Sstevel@tonic-gate */ 3066*0Sstevel@tonic-gate 3067*0Sstevel@tonic-gate static void 3068*0Sstevel@tonic-gate xblocks(off_t bytes, int ofile) 3069*0Sstevel@tonic-gate { 3070*0Sstevel@tonic-gate blkcnt_t blocks; 3071*0Sstevel@tonic-gate char buf[TBLOCK]; 3072*0Sstevel@tonic-gate char tempname[NAMSIZ+1]; 3073*0Sstevel@tonic-gate int write_count; 3074*0Sstevel@tonic-gate 3075*0Sstevel@tonic-gate blocks = TBLOCKS(bytes); 3076*0Sstevel@tonic-gate while (blocks-- > 0) { 3077*0Sstevel@tonic-gate readtape(buf); 3078*0Sstevel@tonic-gate if (bytes > TBLOCK) 3079*0Sstevel@tonic-gate write_count = TBLOCK; 3080*0Sstevel@tonic-gate else 3081*0Sstevel@tonic-gate write_count = bytes; 3082*0Sstevel@tonic-gate if (write(ofile, buf, write_count) < 0) { 3083*0Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 3084*0Sstevel@tonic-gate (void) strcpy(tempname, Xtarhdr.x_path); 3085*0Sstevel@tonic-gate else 3086*0Sstevel@tonic-gate (void) sprintf(tempname, "%.*s", NAMSIZ, 3087*0Sstevel@tonic-gate dblock.dbuf.name); 3088*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3089*0Sstevel@tonic-gate "tar: %s: HELP - extract write error\n"), tempname); 3090*0Sstevel@tonic-gate done(2); 3091*0Sstevel@tonic-gate } 3092*0Sstevel@tonic-gate bytes -= TBLOCK; 3093*0Sstevel@tonic-gate } 3094*0Sstevel@tonic-gate } 3095*0Sstevel@tonic-gate 3096*0Sstevel@tonic-gate 3097*0Sstevel@tonic-gate /* 3098*0Sstevel@tonic-gate * xsfile extract split file 3099*0Sstevel@tonic-gate * 3100*0Sstevel@tonic-gate * xsfile(ofd); ofd = output file descriptor 3101*0Sstevel@tonic-gate * 3102*0Sstevel@tonic-gate * file extracted and put in ofd via xblocks() 3103*0Sstevel@tonic-gate * 3104*0Sstevel@tonic-gate * NOTE: only called by doxtract() to extract one large file 3105*0Sstevel@tonic-gate */ 3106*0Sstevel@tonic-gate 3107*0Sstevel@tonic-gate static union hblock savedblock; /* to ensure same file across volumes */ 3108*0Sstevel@tonic-gate 3109*0Sstevel@tonic-gate static void 3110*0Sstevel@tonic-gate xsfile(int ofd) 3111*0Sstevel@tonic-gate { 3112*0Sstevel@tonic-gate int i, c; 3113*0Sstevel@tonic-gate char name[PATH_MAX+1]; /* holds name for diagnostics */ 3114*0Sstevel@tonic-gate int extents, totalext; 3115*0Sstevel@tonic-gate off_t bytes, totalbytes; 3116*0Sstevel@tonic-gate 3117*0Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 3118*0Sstevel@tonic-gate (void) strcpy(name, Xtarhdr.x_path); 3119*0Sstevel@tonic-gate else 3120*0Sstevel@tonic-gate (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name); 3121*0Sstevel@tonic-gate 3122*0Sstevel@tonic-gate totalbytes = (off_t)0; /* in case we read in half the file */ 3123*0Sstevel@tonic-gate totalext = 0; /* these keep count */ 3124*0Sstevel@tonic-gate 3125*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3126*0Sstevel@tonic-gate "tar: %s split across %d volumes\n"), name, extotal); 3127*0Sstevel@tonic-gate 3128*0Sstevel@tonic-gate /* make sure we do extractions in order */ 3129*0Sstevel@tonic-gate if (extno != 1) { /* starting in middle of file? */ 3130*0Sstevel@tonic-gate wchar_t yeschar; 3131*0Sstevel@tonic-gate wchar_t nochar; 3132*0Sstevel@tonic-gate (void) mbtowc(&yeschar, nl_langinfo(YESSTR), MB_LEN_MAX); 3133*0Sstevel@tonic-gate (void) mbtowc(&nochar, nl_langinfo(NOSTR), MB_LEN_MAX); 3134*0Sstevel@tonic-gate (void) printf(gettext( 3135*0Sstevel@tonic-gate "tar: first extent read is not #1\n" 3136*0Sstevel@tonic-gate "OK to read file beginning with extent #%d (%wc/%wc) ? "), 3137*0Sstevel@tonic-gate extno, yeschar, nochar); 3138*0Sstevel@tonic-gate if (yesnoresponse() != yeschar) { 3139*0Sstevel@tonic-gate canit: 3140*0Sstevel@tonic-gate passtape(); 3141*0Sstevel@tonic-gate if (close(ofd) != 0) 3142*0Sstevel@tonic-gate vperror(2, gettext("close error")); 3143*0Sstevel@tonic-gate return; 3144*0Sstevel@tonic-gate } 3145*0Sstevel@tonic-gate } 3146*0Sstevel@tonic-gate extents = extotal; 3147*0Sstevel@tonic-gate i = extno; 3148*0Sstevel@tonic-gate /*CONSTCOND*/ 3149*0Sstevel@tonic-gate while (1) { 3150*0Sstevel@tonic-gate if (xhdr_flgs & _X_SIZE) { 3151*0Sstevel@tonic-gate bytes = extsize; 3152*0Sstevel@tonic-gate } else { 3153*0Sstevel@tonic-gate bytes = stbuf.st_size; 3154*0Sstevel@tonic-gate } 3155*0Sstevel@tonic-gate 3156*0Sstevel@tonic-gate if (vflag) 3157*0Sstevel@tonic-gate (void) fprintf(vfile, "+++ x %s [extent #%d], %" 3158*0Sstevel@tonic-gate FMT_off_t " bytes, %ldK\n", name, extno, bytes, 3159*0Sstevel@tonic-gate (long)K(TBLOCKS(bytes))); 3160*0Sstevel@tonic-gate xblocks(bytes, ofd); 3161*0Sstevel@tonic-gate 3162*0Sstevel@tonic-gate totalbytes += bytes; 3163*0Sstevel@tonic-gate totalext++; 3164*0Sstevel@tonic-gate if (++i > extents) 3165*0Sstevel@tonic-gate break; 3166*0Sstevel@tonic-gate 3167*0Sstevel@tonic-gate /* get next volume and verify it's the right one */ 3168*0Sstevel@tonic-gate copy(&savedblock, &dblock); 3169*0Sstevel@tonic-gate tryagain: 3170*0Sstevel@tonic-gate newvol(); 3171*0Sstevel@tonic-gate xhdr_flgs = 0; 3172*0Sstevel@tonic-gate getdir(); 3173*0Sstevel@tonic-gate if (Xhdrflag > 0) 3174*0Sstevel@tonic-gate (void) get_xdata(); /* Get x-header & regular hdr */ 3175*0Sstevel@tonic-gate if (endtape()) { /* seemingly empty volume */ 3176*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3177*0Sstevel@tonic-gate "tar: first record is null\n")); 3178*0Sstevel@tonic-gate asknicely: 3179*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3180*0Sstevel@tonic-gate "tar: need volume with extent #%d of %s\n"), 3181*0Sstevel@tonic-gate i, name); 3182*0Sstevel@tonic-gate goto tryagain; 3183*0Sstevel@tonic-gate } 3184*0Sstevel@tonic-gate if (notsame()) { 3185*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3186*0Sstevel@tonic-gate "tar: first file on that volume is not " 3187*0Sstevel@tonic-gate "the same file\n")); 3188*0Sstevel@tonic-gate goto asknicely; 3189*0Sstevel@tonic-gate } 3190*0Sstevel@tonic-gate if (i != extno) { 3191*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3192*0Sstevel@tonic-gate "tar: extent #%d received out of order\ntar: should be #%d\n"), 3193*0Sstevel@tonic-gate extno, i); 3194*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3195*0Sstevel@tonic-gate "Ignore error, Abort this file, or " 3196*0Sstevel@tonic-gate "load New volume (i/a/n) ? ")); 3197*0Sstevel@tonic-gate c = response(); 3198*0Sstevel@tonic-gate if (c == 'a') 3199*0Sstevel@tonic-gate goto canit; 3200*0Sstevel@tonic-gate if (c != 'i') /* default to new volume */ 3201*0Sstevel@tonic-gate goto asknicely; 3202*0Sstevel@tonic-gate i = extno; /* okay, start from there */ 3203*0Sstevel@tonic-gate } 3204*0Sstevel@tonic-gate } 3205*0Sstevel@tonic-gate if (vflag) 3206*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 3207*0Sstevel@tonic-gate "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"), 3208*0Sstevel@tonic-gate name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes))); 3209*0Sstevel@tonic-gate } 3210*0Sstevel@tonic-gate 3211*0Sstevel@tonic-gate 3212*0Sstevel@tonic-gate /* 3213*0Sstevel@tonic-gate * notsame() check if extract file extent is invalid 3214*0Sstevel@tonic-gate * 3215*0Sstevel@tonic-gate * returns true if anything differs between savedblock and dblock 3216*0Sstevel@tonic-gate * except extno (extent number), checksum, or size (extent size). 3217*0Sstevel@tonic-gate * Determines if this header belongs to the same file as the one we're 3218*0Sstevel@tonic-gate * extracting. 3219*0Sstevel@tonic-gate * 3220*0Sstevel@tonic-gate * NOTE: though rather bulky, it is only called once per file 3221*0Sstevel@tonic-gate * extension, and it can withstand changes in the definition 3222*0Sstevel@tonic-gate * of the header structure. 3223*0Sstevel@tonic-gate * 3224*0Sstevel@tonic-gate * WARNING: this routine is local to xsfile() above 3225*0Sstevel@tonic-gate */ 3226*0Sstevel@tonic-gate 3227*0Sstevel@tonic-gate static int 3228*0Sstevel@tonic-gate notsame(void) 3229*0Sstevel@tonic-gate { 3230*0Sstevel@tonic-gate return ( 3231*0Sstevel@tonic-gate (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) || 3232*0Sstevel@tonic-gate (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) || 3233*0Sstevel@tonic-gate (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) || 3234*0Sstevel@tonic-gate (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) || 3235*0Sstevel@tonic-gate (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) || 3236*0Sstevel@tonic-gate (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) || 3237*0Sstevel@tonic-gate (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) || 3238*0Sstevel@tonic-gate (savedblock.dbuf.extotal != dblock.dbuf.extotal) || 3239*0Sstevel@tonic-gate (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize))); 3240*0Sstevel@tonic-gate } 3241*0Sstevel@tonic-gate 3242*0Sstevel@tonic-gate 3243*0Sstevel@tonic-gate static void 3244*0Sstevel@tonic-gate #ifdef _iBCS2 3245*0Sstevel@tonic-gate dotable(char *argv[], int tbl_cnt) 3246*0Sstevel@tonic-gate #else 3247*0Sstevel@tonic-gate dotable(char *argv[]) 3248*0Sstevel@tonic-gate #endif 3249*0Sstevel@tonic-gate 3250*0Sstevel@tonic-gate { 3251*0Sstevel@tonic-gate int tcnt; /* count # files tabled */ 3252*0Sstevel@tonic-gate int fcnt; /* count # files in argv list */ 3253*0Sstevel@tonic-gate char *namep, *dirp, *comp; 3254*0Sstevel@tonic-gate int want; 3255*0Sstevel@tonic-gate char aclchar = ' '; /* either blank or '+' */ 3256*0Sstevel@tonic-gate char templink[PATH_MAX+1]; 3257*0Sstevel@tonic-gate char *np; 3258*0Sstevel@tonic-gate 3259*0Sstevel@tonic-gate dumping = 0; 3260*0Sstevel@tonic-gate 3261*0Sstevel@tonic-gate /* if not on magtape, maximize seek speed */ 3262*0Sstevel@tonic-gate if (NotTape && !bflag) { 3263*0Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 3264*0Sstevel@tonic-gate nblock = SYS_BLOCK / TBLOCK; 3265*0Sstevel@tonic-gate #else 3266*0Sstevel@tonic-gate nblock = 1; 3267*0Sstevel@tonic-gate #endif 3268*0Sstevel@tonic-gate } 3269*0Sstevel@tonic-gate /* 3270*0Sstevel@tonic-gate * Count the number of files that are to be tabled 3271*0Sstevel@tonic-gate */ 3272*0Sstevel@tonic-gate fcnt = tcnt = 0; 3273*0Sstevel@tonic-gate 3274*0Sstevel@tonic-gate #ifdef _iBCS2 3275*0Sstevel@tonic-gate initarg(argv, Filefile); 3276*0Sstevel@tonic-gate while (nextarg() != NULL) 3277*0Sstevel@tonic-gate ++fcnt; 3278*0Sstevel@tonic-gate fcnt += tbl_cnt; 3279*0Sstevel@tonic-gate #endif /* _iBCS2 */ 3280*0Sstevel@tonic-gate 3281*0Sstevel@tonic-gate for (;;) { 3282*0Sstevel@tonic-gate 3283*0Sstevel@tonic-gate /* namep is set by wantit to point to the full name */ 3284*0Sstevel@tonic-gate if ((want = wantit(argv, &namep, &dirp, &comp)) == 0) 3285*0Sstevel@tonic-gate continue; 3286*0Sstevel@tonic-gate if (want == -1) 3287*0Sstevel@tonic-gate break; 3288*0Sstevel@tonic-gate if (dblock.dbuf.typeflag != 'A') 3289*0Sstevel@tonic-gate ++tcnt; 3290*0Sstevel@tonic-gate 3291*0Sstevel@tonic-gate /* 3292*0Sstevel@tonic-gate * ACL support: 3293*0Sstevel@tonic-gate * aclchar is introduced to indicate if there are 3294*0Sstevel@tonic-gate * acl entries. longt() now takes one extra argument. 3295*0Sstevel@tonic-gate */ 3296*0Sstevel@tonic-gate if (vflag) { 3297*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == 'A') { 3298*0Sstevel@tonic-gate aclchar = '+'; 3299*0Sstevel@tonic-gate passtape(); 3300*0Sstevel@tonic-gate continue; 3301*0Sstevel@tonic-gate } 3302*0Sstevel@tonic-gate longt(&stbuf, aclchar); 3303*0Sstevel@tonic-gate aclchar = ' '; 3304*0Sstevel@tonic-gate } 3305*0Sstevel@tonic-gate 3306*0Sstevel@tonic-gate 3307*0Sstevel@tonic-gate #if defined(O_XATTR) 3308*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 3309*0Sstevel@tonic-gate np = xattrp->h_names + strlen(xattrp->h_names) + 1; 3310*0Sstevel@tonic-gate (void) printf(gettext("%s attribute %s"), 3311*0Sstevel@tonic-gate xattrp->h_names, np); 3312*0Sstevel@tonic-gate 3313*0Sstevel@tonic-gate } else { 3314*0Sstevel@tonic-gate (void) printf("%s", namep); 3315*0Sstevel@tonic-gate } 3316*0Sstevel@tonic-gate #else 3317*0Sstevel@tonic-gate (void) printf("%s", namep); 3318*0Sstevel@tonic-gate #endif 3319*0Sstevel@tonic-gate 3320*0Sstevel@tonic-gate if (extno != 0) { 3321*0Sstevel@tonic-gate if (vflag) { 3322*0Sstevel@tonic-gate /* keep the '\n' for backwards compatibility */ 3323*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 3324*0Sstevel@tonic-gate "\n [extent #%d of %d]"), extno, extotal); 3325*0Sstevel@tonic-gate } else { 3326*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 3327*0Sstevel@tonic-gate " [extent #%d of %d]"), extno, extotal); 3328*0Sstevel@tonic-gate } 3329*0Sstevel@tonic-gate } 3330*0Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) { 3331*0Sstevel@tonic-gate (void) strcpy(templink, Xtarhdr.x_linkpath); 3332*0Sstevel@tonic-gate } else { 3333*0Sstevel@tonic-gate #if defined(O_XATTR) 3334*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 3335*0Sstevel@tonic-gate (void) sprintf(templink, 3336*0Sstevel@tonic-gate "file %.*s", NAMSIZ, xattrp->h_names); 3337*0Sstevel@tonic-gate } else { 3338*0Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 3339*0Sstevel@tonic-gate dblock.dbuf.linkname); 3340*0Sstevel@tonic-gate } 3341*0Sstevel@tonic-gate #else 3342*0Sstevel@tonic-gate (void) sprintf(templink, "%.*s", NAMSIZ, 3343*0Sstevel@tonic-gate dblock.dbuf.linkname); 3344*0Sstevel@tonic-gate #endif 3345*0Sstevel@tonic-gate templink[NAMSIZ] = '\0'; 3346*0Sstevel@tonic-gate } 3347*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '1') { 3348*0Sstevel@tonic-gate /* 3349*0Sstevel@tonic-gate * TRANSLATION_NOTE 3350*0Sstevel@tonic-gate * Subject is omitted here. 3351*0Sstevel@tonic-gate * Translate this as if 3352*0Sstevel@tonic-gate * <subject> linked to %s 3353*0Sstevel@tonic-gate */ 3354*0Sstevel@tonic-gate #if defined(O_XATTR) 3355*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 3356*0Sstevel@tonic-gate (void) printf( 3357*0Sstevel@tonic-gate gettext(" linked to attribute %s"), 3358*0Sstevel@tonic-gate xattr_linkp->h_names + 3359*0Sstevel@tonic-gate strlen(xattr_linkp->h_names) + 1); 3360*0Sstevel@tonic-gate } else { 3361*0Sstevel@tonic-gate (void) printf( 3362*0Sstevel@tonic-gate gettext(" linked to %s"), templink); 3363*0Sstevel@tonic-gate } 3364*0Sstevel@tonic-gate #else 3365*0Sstevel@tonic-gate (void) printf( 3366*0Sstevel@tonic-gate gettext(" linked to %s"), templink); 3367*0Sstevel@tonic-gate 3368*0Sstevel@tonic-gate #endif 3369*0Sstevel@tonic-gate } 3370*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2') 3371*0Sstevel@tonic-gate (void) printf(gettext( 3372*0Sstevel@tonic-gate /* 3373*0Sstevel@tonic-gate * TRANSLATION_NOTE 3374*0Sstevel@tonic-gate * Subject is omitted here. 3375*0Sstevel@tonic-gate * Translate this as if 3376*0Sstevel@tonic-gate * <subject> symbolic link to %s 3377*0Sstevel@tonic-gate */ 3378*0Sstevel@tonic-gate " symbolic link to %s"), templink); 3379*0Sstevel@tonic-gate (void) printf("\n"); 3380*0Sstevel@tonic-gate #if defined(O_XATTR) 3381*0Sstevel@tonic-gate if (xattrp != (struct xattr_buf *)NULL) { 3382*0Sstevel@tonic-gate free(xattrhead); 3383*0Sstevel@tonic-gate xattrp = NULL; 3384*0Sstevel@tonic-gate xattrhead = NULL; 3385*0Sstevel@tonic-gate } 3386*0Sstevel@tonic-gate #endif 3387*0Sstevel@tonic-gate passtape(); 3388*0Sstevel@tonic-gate } 3389*0Sstevel@tonic-gate /* 3390*0Sstevel@tonic-gate * Check if the number of files tabled is different from the 3391*0Sstevel@tonic-gate * number of files listed on the command line 3392*0Sstevel@tonic-gate */ 3393*0Sstevel@tonic-gate if (fcnt > tcnt) { 3394*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3395*0Sstevel@tonic-gate "tar: %d file(s) not found\n"), fcnt-tcnt); 3396*0Sstevel@tonic-gate Errflg = 1; 3397*0Sstevel@tonic-gate } 3398*0Sstevel@tonic-gate } 3399*0Sstevel@tonic-gate 3400*0Sstevel@tonic-gate static void 3401*0Sstevel@tonic-gate putempty(blkcnt_t n) 3402*0Sstevel@tonic-gate { 3403*0Sstevel@tonic-gate char buf[TBLOCK]; 3404*0Sstevel@tonic-gate char *cp; 3405*0Sstevel@tonic-gate 3406*0Sstevel@tonic-gate for (cp = buf; cp < &buf[TBLOCK]; ) 3407*0Sstevel@tonic-gate *cp++ = '\0'; 3408*0Sstevel@tonic-gate while (n-- > 0) 3409*0Sstevel@tonic-gate (void) writetbuf(buf, 1); 3410*0Sstevel@tonic-gate } 3411*0Sstevel@tonic-gate 3412*0Sstevel@tonic-gate static ushort_t Ftype = S_IFMT; 3413*0Sstevel@tonic-gate 3414*0Sstevel@tonic-gate static void 3415*0Sstevel@tonic-gate verbose(struct stat *st, char aclchar) 3416*0Sstevel@tonic-gate { 3417*0Sstevel@tonic-gate int i, j, temp; 3418*0Sstevel@tonic-gate mode_t mode; 3419*0Sstevel@tonic-gate char modestr[12]; 3420*0Sstevel@tonic-gate 3421*0Sstevel@tonic-gate for (i = 0; i < 11; i++) 3422*0Sstevel@tonic-gate modestr[i] = '-'; 3423*0Sstevel@tonic-gate modestr[i] = '\0'; 3424*0Sstevel@tonic-gate 3425*0Sstevel@tonic-gate /* a '+' sign is printed if there is ACL */ 3426*0Sstevel@tonic-gate modestr[i-1] = aclchar; 3427*0Sstevel@tonic-gate 3428*0Sstevel@tonic-gate mode = st->st_mode; 3429*0Sstevel@tonic-gate for (i = 0; i < 3; i++) { 3430*0Sstevel@tonic-gate temp = (mode >> (6 - (i * 3))); 3431*0Sstevel@tonic-gate j = (i * 3) + 1; 3432*0Sstevel@tonic-gate if (S_IROTH & temp) 3433*0Sstevel@tonic-gate modestr[j] = 'r'; 3434*0Sstevel@tonic-gate if (S_IWOTH & temp) 3435*0Sstevel@tonic-gate modestr[j + 1] = 'w'; 3436*0Sstevel@tonic-gate if (S_IXOTH & temp) 3437*0Sstevel@tonic-gate modestr[j + 2] = 'x'; 3438*0Sstevel@tonic-gate } 3439*0Sstevel@tonic-gate temp = st->st_mode & Ftype; 3440*0Sstevel@tonic-gate switch (temp) { 3441*0Sstevel@tonic-gate case (S_IFIFO): 3442*0Sstevel@tonic-gate modestr[0] = 'p'; 3443*0Sstevel@tonic-gate break; 3444*0Sstevel@tonic-gate case (S_IFCHR): 3445*0Sstevel@tonic-gate modestr[0] = 'c'; 3446*0Sstevel@tonic-gate break; 3447*0Sstevel@tonic-gate case (S_IFDIR): 3448*0Sstevel@tonic-gate modestr[0] = 'd'; 3449*0Sstevel@tonic-gate break; 3450*0Sstevel@tonic-gate case (S_IFBLK): 3451*0Sstevel@tonic-gate modestr[0] = 'b'; 3452*0Sstevel@tonic-gate break; 3453*0Sstevel@tonic-gate case (S_IFREG): /* was initialized to '-' */ 3454*0Sstevel@tonic-gate break; 3455*0Sstevel@tonic-gate case (S_IFLNK): 3456*0Sstevel@tonic-gate modestr[0] = 'l'; 3457*0Sstevel@tonic-gate break; 3458*0Sstevel@tonic-gate default: 3459*0Sstevel@tonic-gate /* This field may be zero in old archives. */ 3460*0Sstevel@tonic-gate if (is_posix && dblock.dbuf.typeflag != '1') { 3461*0Sstevel@tonic-gate /* 3462*0Sstevel@tonic-gate * For POSIX compliant archives, the mode field 3463*0Sstevel@tonic-gate * consists of 12 bits, ie: the file type bits 3464*0Sstevel@tonic-gate * are not stored in dblock.dbuf.mode. 3465*0Sstevel@tonic-gate * For files other than hard links, getdir() sets 3466*0Sstevel@tonic-gate * the file type bits in the st_mode field of the 3467*0Sstevel@tonic-gate * stat structure based upon dblock.dbuf.typeflag. 3468*0Sstevel@tonic-gate */ 3469*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3470*0Sstevel@tonic-gate "tar: impossible file type")); 3471*0Sstevel@tonic-gate } 3472*0Sstevel@tonic-gate } 3473*0Sstevel@tonic-gate 3474*0Sstevel@tonic-gate if ((S_ISUID & Gen.g_mode) == S_ISUID) 3475*0Sstevel@tonic-gate modestr[3] = 's'; 3476*0Sstevel@tonic-gate if ((S_ISVTX & Gen.g_mode) == S_ISVTX) 3477*0Sstevel@tonic-gate modestr[9] = 't'; 3478*0Sstevel@tonic-gate if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x') 3479*0Sstevel@tonic-gate modestr[6] = 's'; 3480*0Sstevel@tonic-gate else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x') 3481*0Sstevel@tonic-gate modestr[6] = 'l'; 3482*0Sstevel@tonic-gate (void) fprintf(vfile, "%s", modestr); 3483*0Sstevel@tonic-gate } 3484*0Sstevel@tonic-gate 3485*0Sstevel@tonic-gate static void 3486*0Sstevel@tonic-gate longt(struct stat *st, char aclchar) 3487*0Sstevel@tonic-gate { 3488*0Sstevel@tonic-gate char fileDate[30]; 3489*0Sstevel@tonic-gate struct tm *tm; 3490*0Sstevel@tonic-gate 3491*0Sstevel@tonic-gate verbose(st, aclchar); 3492*0Sstevel@tonic-gate (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid); 3493*0Sstevel@tonic-gate 3494*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == '2') { 3495*0Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) 3496*0Sstevel@tonic-gate st->st_size = (off_t)strlen(Xtarhdr.x_linkpath); 3497*0Sstevel@tonic-gate else 3498*0Sstevel@tonic-gate st->st_size = (off_t)(memchr(dblock.dbuf.linkname, 3499*0Sstevel@tonic-gate '\0', NAMSIZ) ? 3500*0Sstevel@tonic-gate (strlen(dblock.dbuf.linkname)) : (NAMSIZ)); 3501*0Sstevel@tonic-gate } 3502*0Sstevel@tonic-gate (void) fprintf(vfile, " %6" FMT_off_t, st->st_size); 3503*0Sstevel@tonic-gate 3504*0Sstevel@tonic-gate tm = localtime(&(st->st_mtime)); 3505*0Sstevel@tonic-gate (void) strftime(fileDate, sizeof (fileDate), 3506*0Sstevel@tonic-gate dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm); 3507*0Sstevel@tonic-gate (void) fprintf(vfile, " %s ", fileDate); 3508*0Sstevel@tonic-gate } 3509*0Sstevel@tonic-gate 3510*0Sstevel@tonic-gate 3511*0Sstevel@tonic-gate /* 3512*0Sstevel@tonic-gate * checkdir - Attempt to ensure that the path represented in name 3513*0Sstevel@tonic-gate * exists, and return 1 if this is true and name itself is a 3514*0Sstevel@tonic-gate * directory. 3515*0Sstevel@tonic-gate * Return 0 if this path cannot be created or if name is not 3516*0Sstevel@tonic-gate * a directory. 3517*0Sstevel@tonic-gate */ 3518*0Sstevel@tonic-gate 3519*0Sstevel@tonic-gate static int 3520*0Sstevel@tonic-gate checkdir(char *name) 3521*0Sstevel@tonic-gate { 3522*0Sstevel@tonic-gate char lastChar; /* the last character in name */ 3523*0Sstevel@tonic-gate char *cp; /* scratch pointer into name */ 3524*0Sstevel@tonic-gate char *firstSlash = NULL; /* first slash in name */ 3525*0Sstevel@tonic-gate char *lastSlash = NULL; /* last slash in name */ 3526*0Sstevel@tonic-gate int nameLen; /* length of name */ 3527*0Sstevel@tonic-gate int trailingSlash; /* true if name ends in slash */ 3528*0Sstevel@tonic-gate int leadingSlash; /* true if name begins with slash */ 3529*0Sstevel@tonic-gate int markedDir; /* true if name denotes a directory */ 3530*0Sstevel@tonic-gate int success; /* status of makeDir call */ 3531*0Sstevel@tonic-gate 3532*0Sstevel@tonic-gate 3533*0Sstevel@tonic-gate /* 3534*0Sstevel@tonic-gate * Scan through the name, and locate first and last slashes. 3535*0Sstevel@tonic-gate */ 3536*0Sstevel@tonic-gate 3537*0Sstevel@tonic-gate for (cp = name; *cp; cp++) { 3538*0Sstevel@tonic-gate if (*cp == '/') { 3539*0Sstevel@tonic-gate if (! firstSlash) { 3540*0Sstevel@tonic-gate firstSlash = cp; 3541*0Sstevel@tonic-gate } 3542*0Sstevel@tonic-gate lastSlash = cp; 3543*0Sstevel@tonic-gate } 3544*0Sstevel@tonic-gate } 3545*0Sstevel@tonic-gate 3546*0Sstevel@tonic-gate /* 3547*0Sstevel@tonic-gate * Determine what you can from the proceeds of the scan. 3548*0Sstevel@tonic-gate */ 3549*0Sstevel@tonic-gate 3550*0Sstevel@tonic-gate lastChar = *(cp - 1); 3551*0Sstevel@tonic-gate nameLen = (int)(cp - name); 3552*0Sstevel@tonic-gate trailingSlash = (lastChar == '/'); 3553*0Sstevel@tonic-gate leadingSlash = (*name == '/'); 3554*0Sstevel@tonic-gate markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash); 3555*0Sstevel@tonic-gate 3556*0Sstevel@tonic-gate if (! lastSlash && ! markedDir) { 3557*0Sstevel@tonic-gate /* 3558*0Sstevel@tonic-gate * The named file does not have any subdrectory 3559*0Sstevel@tonic-gate * structure; just bail out. 3560*0Sstevel@tonic-gate */ 3561*0Sstevel@tonic-gate 3562*0Sstevel@tonic-gate return (0); 3563*0Sstevel@tonic-gate } 3564*0Sstevel@tonic-gate 3565*0Sstevel@tonic-gate /* 3566*0Sstevel@tonic-gate * Make sure that name doesn`t end with slash for the loop. 3567*0Sstevel@tonic-gate * This ensures that the makeDir attempt after the loop is 3568*0Sstevel@tonic-gate * meaningful. 3569*0Sstevel@tonic-gate */ 3570*0Sstevel@tonic-gate 3571*0Sstevel@tonic-gate if (trailingSlash) { 3572*0Sstevel@tonic-gate name[nameLen-1] = '\0'; 3573*0Sstevel@tonic-gate } 3574*0Sstevel@tonic-gate 3575*0Sstevel@tonic-gate /* 3576*0Sstevel@tonic-gate * Make the path one component at a time. 3577*0Sstevel@tonic-gate */ 3578*0Sstevel@tonic-gate 3579*0Sstevel@tonic-gate for (cp = strchr(leadingSlash ? name+1 : name, '/'); 3580*0Sstevel@tonic-gate cp; 3581*0Sstevel@tonic-gate cp = strchr(cp+1, '/')) { 3582*0Sstevel@tonic-gate *cp = '\0'; 3583*0Sstevel@tonic-gate success = makeDir(name); 3584*0Sstevel@tonic-gate *cp = '/'; 3585*0Sstevel@tonic-gate 3586*0Sstevel@tonic-gate if (!success) { 3587*0Sstevel@tonic-gate name[nameLen-1] = lastChar; 3588*0Sstevel@tonic-gate return (0); 3589*0Sstevel@tonic-gate } 3590*0Sstevel@tonic-gate } 3591*0Sstevel@tonic-gate 3592*0Sstevel@tonic-gate /* 3593*0Sstevel@tonic-gate * This makes the last component of the name, if it is a 3594*0Sstevel@tonic-gate * directory. 3595*0Sstevel@tonic-gate */ 3596*0Sstevel@tonic-gate 3597*0Sstevel@tonic-gate if (markedDir) { 3598*0Sstevel@tonic-gate if (! makeDir(name)) { 3599*0Sstevel@tonic-gate name[nameLen-1] = lastChar; 3600*0Sstevel@tonic-gate return (0); 3601*0Sstevel@tonic-gate } 3602*0Sstevel@tonic-gate } 3603*0Sstevel@tonic-gate 3604*0Sstevel@tonic-gate name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar; 3605*0Sstevel@tonic-gate return (markedDir); 3606*0Sstevel@tonic-gate } 3607*0Sstevel@tonic-gate 3608*0Sstevel@tonic-gate /* 3609*0Sstevel@tonic-gate * resugname - Restore the user name and group name. Search the NIS 3610*0Sstevel@tonic-gate * before using the uid and gid. 3611*0Sstevel@tonic-gate * (It is presumed that an archive entry cannot be 3612*0Sstevel@tonic-gate * simultaneously a symlink and some other type.) 3613*0Sstevel@tonic-gate */ 3614*0Sstevel@tonic-gate 3615*0Sstevel@tonic-gate static void 3616*0Sstevel@tonic-gate resugname(int dirfd, /* dir fd file resides in */ 3617*0Sstevel@tonic-gate char *name, /* name of the file to be modified */ 3618*0Sstevel@tonic-gate int symflag) /* true if file is a symbolic link */ 3619*0Sstevel@tonic-gate { 3620*0Sstevel@tonic-gate uid_t duid; 3621*0Sstevel@tonic-gate gid_t dgid; 3622*0Sstevel@tonic-gate struct stat *sp = &stbuf; 3623*0Sstevel@tonic-gate char *u_g_name; 3624*0Sstevel@tonic-gate 3625*0Sstevel@tonic-gate if (checkflag == 1) { /* Extended tar format and euid == 0 */ 3626*0Sstevel@tonic-gate 3627*0Sstevel@tonic-gate /* 3628*0Sstevel@tonic-gate * Try and extract the intended uid and gid from the name 3629*0Sstevel@tonic-gate * service before believing the uid and gid in the header. 3630*0Sstevel@tonic-gate * 3631*0Sstevel@tonic-gate * In the case where we archived a setuid or setgid file 3632*0Sstevel@tonic-gate * owned by someone with a large uid, then it will 3633*0Sstevel@tonic-gate * have made it into the archive with a uid of nobody. If 3634*0Sstevel@tonic-gate * the corresponding username doesn't appear to exist, then we 3635*0Sstevel@tonic-gate * want to make sure it *doesn't* end up as setuid nobody! 3636*0Sstevel@tonic-gate * 3637*0Sstevel@tonic-gate * Our caller will print an error message about the fact 3638*0Sstevel@tonic-gate * that the restore didn't work out quite right .. 3639*0Sstevel@tonic-gate */ 3640*0Sstevel@tonic-gate if (xhdr_flgs & _X_UNAME) 3641*0Sstevel@tonic-gate u_g_name = Xtarhdr.x_uname; 3642*0Sstevel@tonic-gate else 3643*0Sstevel@tonic-gate u_g_name = dblock.dbuf.uname; 3644*0Sstevel@tonic-gate if ((duid = getuidbyname(u_g_name)) == -1) { 3645*0Sstevel@tonic-gate if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY && 3646*0Sstevel@tonic-gate (sp->st_mode & S_ISUID) == S_ISUID) 3647*0Sstevel@tonic-gate (void) chmod(name, 3648*0Sstevel@tonic-gate MODEMASK & sp->st_mode & ~S_ISUID); 3649*0Sstevel@tonic-gate duid = sp->st_uid; 3650*0Sstevel@tonic-gate } 3651*0Sstevel@tonic-gate 3652*0Sstevel@tonic-gate /* (Ditto for gids) */ 3653*0Sstevel@tonic-gate 3654*0Sstevel@tonic-gate if (xhdr_flgs & _X_GNAME) 3655*0Sstevel@tonic-gate u_g_name = Xtarhdr.x_gname; 3656*0Sstevel@tonic-gate else 3657*0Sstevel@tonic-gate u_g_name = dblock.dbuf.gname; 3658*0Sstevel@tonic-gate if ((dgid = getgidbyname(u_g_name)) == -1) { 3659*0Sstevel@tonic-gate if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY && 3660*0Sstevel@tonic-gate (sp->st_mode & S_ISGID) == S_ISGID) 3661*0Sstevel@tonic-gate (void) chmod(name, 3662*0Sstevel@tonic-gate MODEMASK & sp->st_mode & ~S_ISGID); 3663*0Sstevel@tonic-gate dgid = sp->st_gid; 3664*0Sstevel@tonic-gate } 3665*0Sstevel@tonic-gate } else if (checkflag == 2) { /* tar format and euid == 0 */ 3666*0Sstevel@tonic-gate duid = sp->st_uid; 3667*0Sstevel@tonic-gate dgid = sp->st_gid; 3668*0Sstevel@tonic-gate } 3669*0Sstevel@tonic-gate if ((checkflag == 1) || (checkflag == 2)) 3670*0Sstevel@tonic-gate (void) fchownat(dirfd, name, duid, dgid, symflag); 3671*0Sstevel@tonic-gate } 3672*0Sstevel@tonic-gate 3673*0Sstevel@tonic-gate /*ARGSUSED*/ 3674*0Sstevel@tonic-gate static void 3675*0Sstevel@tonic-gate onintr(int sig) 3676*0Sstevel@tonic-gate { 3677*0Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); 3678*0Sstevel@tonic-gate term++; 3679*0Sstevel@tonic-gate } 3680*0Sstevel@tonic-gate 3681*0Sstevel@tonic-gate /*ARGSUSED*/ 3682*0Sstevel@tonic-gate static void 3683*0Sstevel@tonic-gate onquit(int sig) 3684*0Sstevel@tonic-gate { 3685*0Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN); 3686*0Sstevel@tonic-gate term++; 3687*0Sstevel@tonic-gate } 3688*0Sstevel@tonic-gate 3689*0Sstevel@tonic-gate /*ARGSUSED*/ 3690*0Sstevel@tonic-gate static void 3691*0Sstevel@tonic-gate onhup(int sig) 3692*0Sstevel@tonic-gate { 3693*0Sstevel@tonic-gate (void) signal(SIGHUP, SIG_IGN); 3694*0Sstevel@tonic-gate term++; 3695*0Sstevel@tonic-gate } 3696*0Sstevel@tonic-gate 3697*0Sstevel@tonic-gate static void 3698*0Sstevel@tonic-gate tomodes(struct stat *sp) 3699*0Sstevel@tonic-gate { 3700*0Sstevel@tonic-gate uid_t uid; 3701*0Sstevel@tonic-gate gid_t gid; 3702*0Sstevel@tonic-gate 3703*0Sstevel@tonic-gate bzero(dblock.dummy, TBLOCK); 3704*0Sstevel@tonic-gate 3705*0Sstevel@tonic-gate /* 3706*0Sstevel@tonic-gate * If the uid or gid is too large, we can't put it into 3707*0Sstevel@tonic-gate * the archive. We could fail to put anything in the 3708*0Sstevel@tonic-gate * archive at all .. but most of the time the name service 3709*0Sstevel@tonic-gate * will save the day when we do a lookup at restore time. 3710*0Sstevel@tonic-gate * 3711*0Sstevel@tonic-gate * Instead we choose a "safe" uid and gid, and fix up whether 3712*0Sstevel@tonic-gate * or not the setuid and setgid bits are left set to extraction 3713*0Sstevel@tonic-gate * time. 3714*0Sstevel@tonic-gate */ 3715*0Sstevel@tonic-gate if (Eflag) { 3716*0Sstevel@tonic-gate if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) { 3717*0Sstevel@tonic-gate xhdr_flgs |= _X_UID; 3718*0Sstevel@tonic-gate Xtarhdr.x_uid = uid; 3719*0Sstevel@tonic-gate } 3720*0Sstevel@tonic-gate if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) { 3721*0Sstevel@tonic-gate xhdr_flgs |= _X_GID; 3722*0Sstevel@tonic-gate Xtarhdr.x_gid = gid; 3723*0Sstevel@tonic-gate } 3724*0Sstevel@tonic-gate if (sp->st_size > TAR_OFFSET_MAX) { 3725*0Sstevel@tonic-gate xhdr_flgs |= _X_SIZE; 3726*0Sstevel@tonic-gate Xtarhdr.x_filesz = sp->st_size; 3727*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, 3728*0Sstevel@tonic-gate (off_t)0); 3729*0Sstevel@tonic-gate } else 3730*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, 3731*0Sstevel@tonic-gate sp->st_size); 3732*0Sstevel@tonic-gate } else { 3733*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, 3734*0Sstevel@tonic-gate sp->st_size); 3735*0Sstevel@tonic-gate } 3736*0Sstevel@tonic-gate if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) 3737*0Sstevel@tonic-gate uid = UID_NOBODY; 3738*0Sstevel@tonic-gate if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) 3739*0Sstevel@tonic-gate gid = GID_NOBODY; 3740*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.gid, "%07lo", gid); 3741*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.uid, "%07lo", uid); 3742*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES); 3743*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime); 3744*0Sstevel@tonic-gate } 3745*0Sstevel@tonic-gate 3746*0Sstevel@tonic-gate static int 3747*0Sstevel@tonic-gate #ifdef EUC 3748*0Sstevel@tonic-gate /* 3749*0Sstevel@tonic-gate * Warning: the result of this function depends whether 'char' is a 3750*0Sstevel@tonic-gate * signed or unsigned data type. This a source of potential 3751*0Sstevel@tonic-gate * non-portability among heterogeneous systems. It is retained here 3752*0Sstevel@tonic-gate * for backward compatibility. 3753*0Sstevel@tonic-gate */ 3754*0Sstevel@tonic-gate checksum_signed(union hblock *dblockp) 3755*0Sstevel@tonic-gate #else 3756*0Sstevel@tonic-gate checksum(union hblock *dblockp) 3757*0Sstevel@tonic-gate #endif /* EUC */ 3758*0Sstevel@tonic-gate { 3759*0Sstevel@tonic-gate int i; 3760*0Sstevel@tonic-gate char *cp; 3761*0Sstevel@tonic-gate 3762*0Sstevel@tonic-gate for (cp = dblockp->dbuf.chksum; 3763*0Sstevel@tonic-gate cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++) 3764*0Sstevel@tonic-gate *cp = ' '; 3765*0Sstevel@tonic-gate i = 0; 3766*0Sstevel@tonic-gate for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++) 3767*0Sstevel@tonic-gate i += *cp; 3768*0Sstevel@tonic-gate return (i); 3769*0Sstevel@tonic-gate } 3770*0Sstevel@tonic-gate 3771*0Sstevel@tonic-gate #ifdef EUC 3772*0Sstevel@tonic-gate /* 3773*0Sstevel@tonic-gate * Generate unsigned checksum, regardless of what C compiler is 3774*0Sstevel@tonic-gate * used. Survives in the face of arbitrary 8-bit clean filenames, 3775*0Sstevel@tonic-gate * e.g., internationalized filenames. 3776*0Sstevel@tonic-gate */ 3777*0Sstevel@tonic-gate static int 3778*0Sstevel@tonic-gate checksum(union hblock *dblockp) 3779*0Sstevel@tonic-gate { 3780*0Sstevel@tonic-gate unsigned i; 3781*0Sstevel@tonic-gate unsigned char *cp; 3782*0Sstevel@tonic-gate 3783*0Sstevel@tonic-gate for (cp = (unsigned char *) dblockp->dbuf.chksum; 3784*0Sstevel@tonic-gate cp < (unsigned char *) 3785*0Sstevel@tonic-gate &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++) 3786*0Sstevel@tonic-gate *cp = ' '; 3787*0Sstevel@tonic-gate i = 0; 3788*0Sstevel@tonic-gate for (cp = (unsigned char *) dblockp->dummy; 3789*0Sstevel@tonic-gate cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++) 3790*0Sstevel@tonic-gate i += *cp; 3791*0Sstevel@tonic-gate 3792*0Sstevel@tonic-gate return (i); 3793*0Sstevel@tonic-gate } 3794*0Sstevel@tonic-gate #endif /* EUC */ 3795*0Sstevel@tonic-gate 3796*0Sstevel@tonic-gate /* 3797*0Sstevel@tonic-gate * If the w flag is set, output the action to be taken and the name of the 3798*0Sstevel@tonic-gate * file. Perform the action if the user response is affirmative. 3799*0Sstevel@tonic-gate */ 3800*0Sstevel@tonic-gate 3801*0Sstevel@tonic-gate static int 3802*0Sstevel@tonic-gate checkw(char c, char *name) 3803*0Sstevel@tonic-gate { 3804*0Sstevel@tonic-gate if (wflag) { 3805*0Sstevel@tonic-gate (void) fprintf(vfile, "%c ", c); 3806*0Sstevel@tonic-gate if (vflag) 3807*0Sstevel@tonic-gate longt(&stbuf, ' '); /* do we have acl info here */ 3808*0Sstevel@tonic-gate (void) fprintf(vfile, "%s: ", name); 3809*0Sstevel@tonic-gate if (response() == 'y') { 3810*0Sstevel@tonic-gate return (1); 3811*0Sstevel@tonic-gate } 3812*0Sstevel@tonic-gate return (0); 3813*0Sstevel@tonic-gate } 3814*0Sstevel@tonic-gate return (1); 3815*0Sstevel@tonic-gate } 3816*0Sstevel@tonic-gate 3817*0Sstevel@tonic-gate /* 3818*0Sstevel@tonic-gate * When the F flag is set, exclude RCS and SCCS directories. If F is set 3819*0Sstevel@tonic-gate * twice, also exclude .o files, and files names errs, core, and a.out. 3820*0Sstevel@tonic-gate */ 3821*0Sstevel@tonic-gate 3822*0Sstevel@tonic-gate static int 3823*0Sstevel@tonic-gate checkf(char *name, int mode, int howmuch) 3824*0Sstevel@tonic-gate { 3825*0Sstevel@tonic-gate int l; 3826*0Sstevel@tonic-gate 3827*0Sstevel@tonic-gate if ((mode & S_IFMT) == S_IFDIR) { 3828*0Sstevel@tonic-gate if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0)) 3829*0Sstevel@tonic-gate return (0); 3830*0Sstevel@tonic-gate return (1); 3831*0Sstevel@tonic-gate } 3832*0Sstevel@tonic-gate if ((l = (int)strlen(name)) < 3) 3833*0Sstevel@tonic-gate return (1); 3834*0Sstevel@tonic-gate if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 3835*0Sstevel@tonic-gate return (0); 3836*0Sstevel@tonic-gate if (howmuch > 1) { 3837*0Sstevel@tonic-gate if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 || 3838*0Sstevel@tonic-gate strcmp(name, "a.out") == 0) 3839*0Sstevel@tonic-gate return (0); 3840*0Sstevel@tonic-gate } 3841*0Sstevel@tonic-gate 3842*0Sstevel@tonic-gate /* SHOULD CHECK IF IT IS EXECUTABLE */ 3843*0Sstevel@tonic-gate return (1); 3844*0Sstevel@tonic-gate } 3845*0Sstevel@tonic-gate 3846*0Sstevel@tonic-gate static int 3847*0Sstevel@tonic-gate response(void) 3848*0Sstevel@tonic-gate { 3849*0Sstevel@tonic-gate int c; 3850*0Sstevel@tonic-gate 3851*0Sstevel@tonic-gate c = getchar(); 3852*0Sstevel@tonic-gate if (c != '\n') 3853*0Sstevel@tonic-gate while (getchar() != '\n'); 3854*0Sstevel@tonic-gate else c = 'n'; 3855*0Sstevel@tonic-gate return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c); 3856*0Sstevel@tonic-gate } 3857*0Sstevel@tonic-gate 3858*0Sstevel@tonic-gate /* Has file been modified since being put into archive? If so, return > 0. */ 3859*0Sstevel@tonic-gate 3860*0Sstevel@tonic-gate static int 3861*0Sstevel@tonic-gate checkupdate(char *arg) 3862*0Sstevel@tonic-gate { 3863*0Sstevel@tonic-gate char name[PATH_MAX+1]; 3864*0Sstevel@tonic-gate time_t mtime; 3865*0Sstevel@tonic-gate long nsecs; 3866*0Sstevel@tonic-gate off_t seekp; 3867*0Sstevel@tonic-gate static off_t lookup(char *); 3868*0Sstevel@tonic-gate 3869*0Sstevel@tonic-gate rewind(tfile); 3870*0Sstevel@tonic-gate if ((seekp = lookup(arg)) < 0) 3871*0Sstevel@tonic-gate return (1); 3872*0Sstevel@tonic-gate (void) fseek(tfile, seekp, 0); 3873*0Sstevel@tonic-gate (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs); 3874*0Sstevel@tonic-gate 3875*0Sstevel@tonic-gate /* 3876*0Sstevel@tonic-gate * Unless nanoseconds were stored in the file, only use seconds for 3877*0Sstevel@tonic-gate * comparison of time. Nanoseconds are stored when -E is specified. 3878*0Sstevel@tonic-gate */ 3879*0Sstevel@tonic-gate if (Eflag == 0) 3880*0Sstevel@tonic-gate return (stbuf.st_mtime > mtime); 3881*0Sstevel@tonic-gate 3882*0Sstevel@tonic-gate if ((stbuf.st_mtime < mtime) || 3883*0Sstevel@tonic-gate ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs))) 3884*0Sstevel@tonic-gate return (0); 3885*0Sstevel@tonic-gate return (1); 3886*0Sstevel@tonic-gate } 3887*0Sstevel@tonic-gate 3888*0Sstevel@tonic-gate 3889*0Sstevel@tonic-gate /* 3890*0Sstevel@tonic-gate * newvol get new floppy (or tape) volume 3891*0Sstevel@tonic-gate * 3892*0Sstevel@tonic-gate * newvol(); resets tapepos and first to TRUE, prompts for 3893*0Sstevel@tonic-gate * for new volume, and waits. 3894*0Sstevel@tonic-gate * if dumping, end-of-file is written onto the tape. 3895*0Sstevel@tonic-gate */ 3896*0Sstevel@tonic-gate 3897*0Sstevel@tonic-gate static void 3898*0Sstevel@tonic-gate newvol(void) 3899*0Sstevel@tonic-gate { 3900*0Sstevel@tonic-gate int c; 3901*0Sstevel@tonic-gate 3902*0Sstevel@tonic-gate if (dumping) { 3903*0Sstevel@tonic-gate #ifdef DEBUG 3904*0Sstevel@tonic-gate DEBUG("newvol called with 'dumping' set\n", 0, 0); 3905*0Sstevel@tonic-gate #endif 3906*0Sstevel@tonic-gate putempty((blkcnt_t)2); /* 2 EOT marks */ 3907*0Sstevel@tonic-gate closevol(); 3908*0Sstevel@tonic-gate flushtape(); 3909*0Sstevel@tonic-gate sync(); 3910*0Sstevel@tonic-gate tapepos = 0; 3911*0Sstevel@tonic-gate } else 3912*0Sstevel@tonic-gate first = TRUE; 3913*0Sstevel@tonic-gate if (close(mt) != 0) 3914*0Sstevel@tonic-gate vperror(2, gettext("close error")); 3915*0Sstevel@tonic-gate mt = 0; 3916*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3917*0Sstevel@tonic-gate "tar: \007please insert new volume, then press RETURN.")); 3918*0Sstevel@tonic-gate (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */ 3919*0Sstevel@tonic-gate while ((c = getchar()) != '\n' && ! term) 3920*0Sstevel@tonic-gate if (c == EOF) 3921*0Sstevel@tonic-gate done(Errflg); 3922*0Sstevel@tonic-gate if (term) 3923*0Sstevel@tonic-gate done(Errflg); 3924*0Sstevel@tonic-gate 3925*0Sstevel@tonic-gate errno = 0; 3926*0Sstevel@tonic-gate 3927*0Sstevel@tonic-gate if (strcmp(usefile, "-") == 0) { 3928*0Sstevel@tonic-gate mt = dup(1); 3929*0Sstevel@tonic-gate } else { 3930*0Sstevel@tonic-gate mt = open(usefile, dumping ? update : 0); 3931*0Sstevel@tonic-gate } 3932*0Sstevel@tonic-gate 3933*0Sstevel@tonic-gate if (mt < 0) { 3934*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3935*0Sstevel@tonic-gate "tar: cannot reopen %s (%s)\n"), 3936*0Sstevel@tonic-gate dumping ? gettext("output") : gettext("input"), usefile); 3937*0Sstevel@tonic-gate 3938*0Sstevel@tonic-gate (void) fprintf(stderr, "update=%d, usefile=%s, mt=%d, [%s]\n", 3939*0Sstevel@tonic-gate update, usefile, mt, strerror(errno)); 3940*0Sstevel@tonic-gate 3941*0Sstevel@tonic-gate done(2); 3942*0Sstevel@tonic-gate } 3943*0Sstevel@tonic-gate } 3944*0Sstevel@tonic-gate 3945*0Sstevel@tonic-gate /* 3946*0Sstevel@tonic-gate * Write a trailer portion to close out the current output volume. 3947*0Sstevel@tonic-gate */ 3948*0Sstevel@tonic-gate 3949*0Sstevel@tonic-gate static void 3950*0Sstevel@tonic-gate closevol(void) 3951*0Sstevel@tonic-gate { 3952*0Sstevel@tonic-gate if (mulvol) { 3953*0Sstevel@tonic-gate /* 3954*0Sstevel@tonic-gate * blocklim does not count the 2 EOT marks; 3955*0Sstevel@tonic-gate * tapepos does count the 2 EOT marks; 3956*0Sstevel@tonic-gate * therefore we need the +2 below. 3957*0Sstevel@tonic-gate */ 3958*0Sstevel@tonic-gate putempty(blocklim + (blkcnt_t)2 - tapepos); 3959*0Sstevel@tonic-gate } 3960*0Sstevel@tonic-gate } 3961*0Sstevel@tonic-gate 3962*0Sstevel@tonic-gate static void 3963*0Sstevel@tonic-gate done(int n) 3964*0Sstevel@tonic-gate { 3965*0Sstevel@tonic-gate (void) unlink(tname); 3966*0Sstevel@tonic-gate if (mt > 0) { 3967*0Sstevel@tonic-gate if ((close(mt) != 0) || (fclose(stdout) != 0)) { 3968*0Sstevel@tonic-gate perror(gettext("tar: close error")); 3969*0Sstevel@tonic-gate exit(2); 3970*0Sstevel@tonic-gate } 3971*0Sstevel@tonic-gate } 3972*0Sstevel@tonic-gate exit(n); 3973*0Sstevel@tonic-gate } 3974*0Sstevel@tonic-gate 3975*0Sstevel@tonic-gate /* 3976*0Sstevel@tonic-gate * Determine if s1 is a prefix portion of s2 (or the same as s2). 3977*0Sstevel@tonic-gate */ 3978*0Sstevel@tonic-gate 3979*0Sstevel@tonic-gate static int 3980*0Sstevel@tonic-gate is_prefix(char *s1, char *s2) 3981*0Sstevel@tonic-gate { 3982*0Sstevel@tonic-gate while (*s1) 3983*0Sstevel@tonic-gate if (*s1++ != *s2++) 3984*0Sstevel@tonic-gate return (0); 3985*0Sstevel@tonic-gate if (*s2) 3986*0Sstevel@tonic-gate return (*s2 == '/'); 3987*0Sstevel@tonic-gate return (1); 3988*0Sstevel@tonic-gate } 3989*0Sstevel@tonic-gate 3990*0Sstevel@tonic-gate /* 3991*0Sstevel@tonic-gate * lookup and bsrch look through tfile entries to find a match for a name. 3992*0Sstevel@tonic-gate * The name can be up to PATH_MAX bytes. bsrch compares what it sees between 3993*0Sstevel@tonic-gate * a pair of newline chars, so the buffer it uses must be long enough for 3994*0Sstevel@tonic-gate * two lines: name and modification time as well as period, newline and space. 3995*0Sstevel@tonic-gate * 3996*0Sstevel@tonic-gate * A kludge was added to bsrch to take care of matching on the first entry 3997*0Sstevel@tonic-gate * in the file--there is no leading newline. So, if we are reading from the 3998*0Sstevel@tonic-gate * start of the file, read into byte two and set the first byte to a newline. 3999*0Sstevel@tonic-gate * Otherwise, the first entry cannot be matched. 4000*0Sstevel@tonic-gate * 4001*0Sstevel@tonic-gate */ 4002*0Sstevel@tonic-gate 4003*0Sstevel@tonic-gate #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3)) 4004*0Sstevel@tonic-gate static off_t 4005*0Sstevel@tonic-gate lookup(char *s) 4006*0Sstevel@tonic-gate { 4007*0Sstevel@tonic-gate int i; 4008*0Sstevel@tonic-gate off_t a; 4009*0Sstevel@tonic-gate 4010*0Sstevel@tonic-gate for (i = 0; s[i]; i++) 4011*0Sstevel@tonic-gate if (s[i] == ' ') 4012*0Sstevel@tonic-gate break; 4013*0Sstevel@tonic-gate a = bsrch(s, i, low, high); 4014*0Sstevel@tonic-gate return (a); 4015*0Sstevel@tonic-gate } 4016*0Sstevel@tonic-gate 4017*0Sstevel@tonic-gate static off_t 4018*0Sstevel@tonic-gate bsrch(char *s, int n, off_t l, off_t h) 4019*0Sstevel@tonic-gate { 4020*0Sstevel@tonic-gate int i, j; 4021*0Sstevel@tonic-gate char b[N]; 4022*0Sstevel@tonic-gate off_t m, m1; 4023*0Sstevel@tonic-gate 4024*0Sstevel@tonic-gate 4025*0Sstevel@tonic-gate loop: 4026*0Sstevel@tonic-gate if (l >= h) 4027*0Sstevel@tonic-gate return ((off_t)-1); 4028*0Sstevel@tonic-gate m = l + (h-l)/2 - N/2; 4029*0Sstevel@tonic-gate if (m < l) 4030*0Sstevel@tonic-gate m = l; 4031*0Sstevel@tonic-gate (void) fseek(tfile, m, 0); 4032*0Sstevel@tonic-gate if (m == 0) { 4033*0Sstevel@tonic-gate (void) fread(b+1, 1, N-1, tfile); 4034*0Sstevel@tonic-gate b[0] = '\n'; 4035*0Sstevel@tonic-gate m--; 4036*0Sstevel@tonic-gate } else 4037*0Sstevel@tonic-gate (void) fread(b, 1, N, tfile); 4038*0Sstevel@tonic-gate for (i = 0; i < N; i++) { 4039*0Sstevel@tonic-gate if (b[i] == '\n') 4040*0Sstevel@tonic-gate break; 4041*0Sstevel@tonic-gate m++; 4042*0Sstevel@tonic-gate } 4043*0Sstevel@tonic-gate if (m >= h) 4044*0Sstevel@tonic-gate return ((off_t)-1); 4045*0Sstevel@tonic-gate m1 = m; 4046*0Sstevel@tonic-gate j = i; 4047*0Sstevel@tonic-gate for (i++; i < N; i++) { 4048*0Sstevel@tonic-gate m1++; 4049*0Sstevel@tonic-gate if (b[i] == '\n') 4050*0Sstevel@tonic-gate break; 4051*0Sstevel@tonic-gate } 4052*0Sstevel@tonic-gate i = cmp(b+j, s, n); 4053*0Sstevel@tonic-gate if (i < 0) { 4054*0Sstevel@tonic-gate h = m; 4055*0Sstevel@tonic-gate goto loop; 4056*0Sstevel@tonic-gate } 4057*0Sstevel@tonic-gate if (i > 0) { 4058*0Sstevel@tonic-gate l = m1; 4059*0Sstevel@tonic-gate goto loop; 4060*0Sstevel@tonic-gate } 4061*0Sstevel@tonic-gate if (m < 0) 4062*0Sstevel@tonic-gate m = 0; 4063*0Sstevel@tonic-gate return (m); 4064*0Sstevel@tonic-gate } 4065*0Sstevel@tonic-gate 4066*0Sstevel@tonic-gate static int 4067*0Sstevel@tonic-gate cmp(char *b, char *s, int n) 4068*0Sstevel@tonic-gate { 4069*0Sstevel@tonic-gate int i; 4070*0Sstevel@tonic-gate 4071*0Sstevel@tonic-gate assert(b[0] == '\n'); 4072*0Sstevel@tonic-gate 4073*0Sstevel@tonic-gate for (i = 0; i < n; i++) { 4074*0Sstevel@tonic-gate if (b[i+1] > s[i]) 4075*0Sstevel@tonic-gate return (-1); 4076*0Sstevel@tonic-gate if (b[i+1] < s[i]) 4077*0Sstevel@tonic-gate return (1); 4078*0Sstevel@tonic-gate } 4079*0Sstevel@tonic-gate return (b[i+1] == ' '? 0 : -1); 4080*0Sstevel@tonic-gate } 4081*0Sstevel@tonic-gate 4082*0Sstevel@tonic-gate 4083*0Sstevel@tonic-gate /* 4084*0Sstevel@tonic-gate * seekdisk seek to next file on archive 4085*0Sstevel@tonic-gate * 4086*0Sstevel@tonic-gate * called by passtape() only 4087*0Sstevel@tonic-gate * 4088*0Sstevel@tonic-gate * WARNING: expects "nblock" to be set, that is, readtape() to have 4089*0Sstevel@tonic-gate * already been called. Since passtape() is only called 4090*0Sstevel@tonic-gate * after a file header block has been read (why else would 4091*0Sstevel@tonic-gate * we skip to next file?), this is currently safe. 4092*0Sstevel@tonic-gate * 4093*0Sstevel@tonic-gate * changed to guarantee SYS_BLOCK boundary 4094*0Sstevel@tonic-gate */ 4095*0Sstevel@tonic-gate 4096*0Sstevel@tonic-gate static void 4097*0Sstevel@tonic-gate seekdisk(blkcnt_t blocks) 4098*0Sstevel@tonic-gate { 4099*0Sstevel@tonic-gate off_t seekval; 4100*0Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 4101*0Sstevel@tonic-gate /* handle non-multiple of SYS_BLOCK */ 4102*0Sstevel@tonic-gate blkcnt_t nxb; /* # extra blocks */ 4103*0Sstevel@tonic-gate #endif 4104*0Sstevel@tonic-gate 4105*0Sstevel@tonic-gate tapepos += blocks; 4106*0Sstevel@tonic-gate #ifdef DEBUG 4107*0Sstevel@tonic-gate DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0); 4108*0Sstevel@tonic-gate #endif 4109*0Sstevel@tonic-gate if (recno + blocks <= nblock) { 4110*0Sstevel@tonic-gate recno += blocks; 4111*0Sstevel@tonic-gate return; 4112*0Sstevel@tonic-gate } 4113*0Sstevel@tonic-gate if (recno > nblock) 4114*0Sstevel@tonic-gate recno = nblock; 4115*0Sstevel@tonic-gate seekval = (off_t)blocks - (nblock - recno); 4116*0Sstevel@tonic-gate recno = nblock; /* so readtape() reads next time through */ 4117*0Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 4118*0Sstevel@tonic-gate nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK)); 4119*0Sstevel@tonic-gate #ifdef DEBUG 4120*0Sstevel@tonic-gate DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n", 4121*0Sstevel@tonic-gate nxb, seekval); 4122*0Sstevel@tonic-gate #endif 4123*0Sstevel@tonic-gate if (nxb && nxb > seekval) /* don't seek--we'll read */ 4124*0Sstevel@tonic-gate goto noseek; 4125*0Sstevel@tonic-gate seekval -= nxb; /* don't seek quite so far */ 4126*0Sstevel@tonic-gate #endif 4127*0Sstevel@tonic-gate if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) { 4128*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4129*0Sstevel@tonic-gate "tar: device seek error\n")); 4130*0Sstevel@tonic-gate done(3); 4131*0Sstevel@tonic-gate } 4132*0Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 4133*0Sstevel@tonic-gate /* read those extra blocks */ 4134*0Sstevel@tonic-gate noseek: 4135*0Sstevel@tonic-gate if (nxb) { 4136*0Sstevel@tonic-gate #ifdef DEBUG 4137*0Sstevel@tonic-gate DEBUG("reading extra blocks\n", 0, 0); 4138*0Sstevel@tonic-gate #endif 4139*0Sstevel@tonic-gate if (read(mt, tbuf, TBLOCK*nblock) < 0) { 4140*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4141*0Sstevel@tonic-gate "tar: read error while skipping file\n")); 4142*0Sstevel@tonic-gate done(8); 4143*0Sstevel@tonic-gate } 4144*0Sstevel@tonic-gate recno = nxb; /* so we don't read in next readtape() */ 4145*0Sstevel@tonic-gate } 4146*0Sstevel@tonic-gate #endif 4147*0Sstevel@tonic-gate } 4148*0Sstevel@tonic-gate 4149*0Sstevel@tonic-gate static void 4150*0Sstevel@tonic-gate readtape(char *buffer) 4151*0Sstevel@tonic-gate { 4152*0Sstevel@tonic-gate int i, j; 4153*0Sstevel@tonic-gate 4154*0Sstevel@tonic-gate ++tapepos; 4155*0Sstevel@tonic-gate if (recno >= nblock || first) { 4156*0Sstevel@tonic-gate if (first) { 4157*0Sstevel@tonic-gate /* 4158*0Sstevel@tonic-gate * set the number of blocks to read initially, based on 4159*0Sstevel@tonic-gate * the defined defaults for the device, or on the 4160*0Sstevel@tonic-gate * explicit block factor given. 4161*0Sstevel@tonic-gate */ 4162*0Sstevel@tonic-gate if (bflag || defaults_used) 4163*0Sstevel@tonic-gate j = nblock; 4164*0Sstevel@tonic-gate else 4165*0Sstevel@tonic-gate j = NBLOCK; 4166*0Sstevel@tonic-gate } else 4167*0Sstevel@tonic-gate j = nblock; 4168*0Sstevel@tonic-gate 4169*0Sstevel@tonic-gate if ((i = read(mt, tbuf, TBLOCK*j)) < 0) { 4170*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4171*0Sstevel@tonic-gate "tar: tape read error\n")); 4172*0Sstevel@tonic-gate done(3); 4173*0Sstevel@tonic-gate /* 4174*0Sstevel@tonic-gate * i == 0 means EOF reached and !rflag means that when 4175*0Sstevel@tonic-gate * tar command uses 'r' as a function letter, we are trying 4176*0Sstevel@tonic-gate * to update or replace an empty tar file which will fail. 4177*0Sstevel@tonic-gate * So this fix is not for 'r' function letter. 4178*0Sstevel@tonic-gate */ 4179*0Sstevel@tonic-gate } else if (i == 0 && !rflag) { 4180*0Sstevel@tonic-gate if (first) { 4181*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4182*0Sstevel@tonic-gate "tar: blocksize = %d\n"), i); 4183*0Sstevel@tonic-gate done(Errflg); 4184*0Sstevel@tonic-gate } 4185*0Sstevel@tonic-gate else 4186*0Sstevel@tonic-gate mterr("read", 0, 2); 4187*0Sstevel@tonic-gate } else if ((!first || Bflag) && i != TBLOCK*j) { 4188*0Sstevel@tonic-gate /* 4189*0Sstevel@tonic-gate * Short read - try to get the remaining bytes. 4190*0Sstevel@tonic-gate */ 4191*0Sstevel@tonic-gate 4192*0Sstevel@tonic-gate int remaining = (TBLOCK * j) - i; 4193*0Sstevel@tonic-gate char *b = (char *)tbuf + i; 4194*0Sstevel@tonic-gate int r; 4195*0Sstevel@tonic-gate 4196*0Sstevel@tonic-gate do { 4197*0Sstevel@tonic-gate if ((r = read(mt, b, remaining)) < 0) { 4198*0Sstevel@tonic-gate (void) fprintf(stderr, 4199*0Sstevel@tonic-gate gettext("tar: tape read error\n")); 4200*0Sstevel@tonic-gate done(3); 4201*0Sstevel@tonic-gate } 4202*0Sstevel@tonic-gate b += r; 4203*0Sstevel@tonic-gate remaining -= r; 4204*0Sstevel@tonic-gate i += r; 4205*0Sstevel@tonic-gate } while (remaining > 0 && r != 0); 4206*0Sstevel@tonic-gate } 4207*0Sstevel@tonic-gate if (first) { 4208*0Sstevel@tonic-gate if ((i % TBLOCK) != 0) { 4209*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4210*0Sstevel@tonic-gate "tar: tape blocksize error\n")); 4211*0Sstevel@tonic-gate done(3); 4212*0Sstevel@tonic-gate } 4213*0Sstevel@tonic-gate i /= TBLOCK; 4214*0Sstevel@tonic-gate if (vflag && i != nblock && i != 1) { 4215*0Sstevel@tonic-gate if (!NotTape) 4216*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4217*0Sstevel@tonic-gate "tar: blocksize = %d\n"), i); 4218*0Sstevel@tonic-gate } 4219*0Sstevel@tonic-gate 4220*0Sstevel@tonic-gate /* 4221*0Sstevel@tonic-gate * If we are reading a tape, then a short read is 4222*0Sstevel@tonic-gate * understood to signify that the amount read is 4223*0Sstevel@tonic-gate * the tape's actual blocking factor. We adapt 4224*0Sstevel@tonic-gate * nblock accordingly. There is no reason to do 4225*0Sstevel@tonic-gate * this when the device is not blocked. 4226*0Sstevel@tonic-gate */ 4227*0Sstevel@tonic-gate 4228*0Sstevel@tonic-gate if (!NotTape) 4229*0Sstevel@tonic-gate nblock = i; 4230*0Sstevel@tonic-gate } 4231*0Sstevel@tonic-gate recno = 0; 4232*0Sstevel@tonic-gate } 4233*0Sstevel@tonic-gate 4234*0Sstevel@tonic-gate first = FALSE; 4235*0Sstevel@tonic-gate copy(buffer, &tbuf[recno++]); 4236*0Sstevel@tonic-gate } 4237*0Sstevel@tonic-gate 4238*0Sstevel@tonic-gate 4239*0Sstevel@tonic-gate /* 4240*0Sstevel@tonic-gate * replacement for writetape. 4241*0Sstevel@tonic-gate */ 4242*0Sstevel@tonic-gate 4243*0Sstevel@tonic-gate static int 4244*0Sstevel@tonic-gate writetbuf(char *buffer, int n) 4245*0Sstevel@tonic-gate { 4246*0Sstevel@tonic-gate int i; 4247*0Sstevel@tonic-gate 4248*0Sstevel@tonic-gate tapepos += n; /* output block count */ 4249*0Sstevel@tonic-gate 4250*0Sstevel@tonic-gate if (recno >= nblock) { 4251*0Sstevel@tonic-gate i = write(mt, (char *)tbuf, TBLOCK*nblock); 4252*0Sstevel@tonic-gate if (i != TBLOCK*nblock) 4253*0Sstevel@tonic-gate mterr("write", i, 2); 4254*0Sstevel@tonic-gate recno = 0; 4255*0Sstevel@tonic-gate } 4256*0Sstevel@tonic-gate 4257*0Sstevel@tonic-gate /* 4258*0Sstevel@tonic-gate * Special case: We have an empty tape buffer, and the 4259*0Sstevel@tonic-gate * users data size is >= the tape block size: Avoid 4260*0Sstevel@tonic-gate * the bcopy and dma direct to tape. BIG WIN. Add the 4261*0Sstevel@tonic-gate * residual to the tape buffer. 4262*0Sstevel@tonic-gate */ 4263*0Sstevel@tonic-gate while (recno == 0 && n >= nblock) { 4264*0Sstevel@tonic-gate i = (int)write(mt, buffer, TBLOCK*nblock); 4265*0Sstevel@tonic-gate if (i != TBLOCK*nblock) 4266*0Sstevel@tonic-gate mterr("write", i, 2); 4267*0Sstevel@tonic-gate n -= nblock; 4268*0Sstevel@tonic-gate buffer += (nblock * TBLOCK); 4269*0Sstevel@tonic-gate } 4270*0Sstevel@tonic-gate 4271*0Sstevel@tonic-gate while (n-- > 0) { 4272*0Sstevel@tonic-gate (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK); 4273*0Sstevel@tonic-gate buffer += TBLOCK; 4274*0Sstevel@tonic-gate if (recno >= nblock) { 4275*0Sstevel@tonic-gate i = (int)write(mt, (char *)tbuf, TBLOCK*nblock); 4276*0Sstevel@tonic-gate if (i != TBLOCK*nblock) 4277*0Sstevel@tonic-gate mterr("write", i, 2); 4278*0Sstevel@tonic-gate recno = 0; 4279*0Sstevel@tonic-gate } 4280*0Sstevel@tonic-gate } 4281*0Sstevel@tonic-gate 4282*0Sstevel@tonic-gate /* Tell the user how much to write to get in sync */ 4283*0Sstevel@tonic-gate return (nblock - recno); 4284*0Sstevel@tonic-gate } 4285*0Sstevel@tonic-gate 4286*0Sstevel@tonic-gate /* 4287*0Sstevel@tonic-gate * backtape - reposition tape after reading soft "EOF" record 4288*0Sstevel@tonic-gate * 4289*0Sstevel@tonic-gate * Backtape tries to reposition the tape back over the EOF 4290*0Sstevel@tonic-gate * record. This is for the 'u' and 'r' function letters so that the 4291*0Sstevel@tonic-gate * tape can be extended. This code is not well designed, but 4292*0Sstevel@tonic-gate * I'm confident that the only callers who care about the 4293*0Sstevel@tonic-gate * backspace-over-EOF feature are those involved in 'u' and 'r'. 4294*0Sstevel@tonic-gate * 4295*0Sstevel@tonic-gate * The proper way to backup the tape is through the use of mtio. 4296*0Sstevel@tonic-gate * Earlier spins used lseek combined with reads in a confusing 4297*0Sstevel@tonic-gate * maneuver that only worked on 4.x, but shouldn't have, even 4298*0Sstevel@tonic-gate * there. Lseeks are explicitly not supported for tape devices. 4299*0Sstevel@tonic-gate */ 4300*0Sstevel@tonic-gate 4301*0Sstevel@tonic-gate static void 4302*0Sstevel@tonic-gate backtape(void) 4303*0Sstevel@tonic-gate { 4304*0Sstevel@tonic-gate struct mtop mtcmd; 4305*0Sstevel@tonic-gate #ifdef DEBUG 4306*0Sstevel@tonic-gate DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno, 4307*0Sstevel@tonic-gate nblock); 4308*0Sstevel@tonic-gate #endif 4309*0Sstevel@tonic-gate /* 4310*0Sstevel@tonic-gate * Backup to the position in the archive where the record 4311*0Sstevel@tonic-gate * currently sitting in the tbuf buffer is situated. 4312*0Sstevel@tonic-gate */ 4313*0Sstevel@tonic-gate 4314*0Sstevel@tonic-gate if (NotTape) { 4315*0Sstevel@tonic-gate /* 4316*0Sstevel@tonic-gate * For non-tape devices, this means lseeking to the 4317*0Sstevel@tonic-gate * correct position. The absolute location tapepos-recno 4318*0Sstevel@tonic-gate * should be the beginning of the current record. 4319*0Sstevel@tonic-gate */ 4320*0Sstevel@tonic-gate 4321*0Sstevel@tonic-gate if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) == 4322*0Sstevel@tonic-gate (off_t)-1) { 4323*0Sstevel@tonic-gate (void) fprintf(stderr, 4324*0Sstevel@tonic-gate gettext("tar: lseek to end of archive failed\n")); 4325*0Sstevel@tonic-gate done(4); 4326*0Sstevel@tonic-gate } 4327*0Sstevel@tonic-gate } else { 4328*0Sstevel@tonic-gate /* 4329*0Sstevel@tonic-gate * For tape devices, we backup over the most recently 4330*0Sstevel@tonic-gate * read record. 4331*0Sstevel@tonic-gate */ 4332*0Sstevel@tonic-gate 4333*0Sstevel@tonic-gate mtcmd.mt_op = MTBSR; 4334*0Sstevel@tonic-gate mtcmd.mt_count = 1; 4335*0Sstevel@tonic-gate 4336*0Sstevel@tonic-gate if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) { 4337*0Sstevel@tonic-gate (void) fprintf(stderr, 4338*0Sstevel@tonic-gate gettext("tar: backspace over record failed\n")); 4339*0Sstevel@tonic-gate done(4); 4340*0Sstevel@tonic-gate } 4341*0Sstevel@tonic-gate } 4342*0Sstevel@tonic-gate 4343*0Sstevel@tonic-gate /* 4344*0Sstevel@tonic-gate * Decrement the tape and tbuf buffer indices to prepare for the 4345*0Sstevel@tonic-gate * coming write to overwrite the soft EOF record. 4346*0Sstevel@tonic-gate */ 4347*0Sstevel@tonic-gate 4348*0Sstevel@tonic-gate recno--; 4349*0Sstevel@tonic-gate tapepos--; 4350*0Sstevel@tonic-gate } 4351*0Sstevel@tonic-gate 4352*0Sstevel@tonic-gate 4353*0Sstevel@tonic-gate /* 4354*0Sstevel@tonic-gate * flushtape write buffered block(s) onto tape 4355*0Sstevel@tonic-gate * 4356*0Sstevel@tonic-gate * recno points to next free block in tbuf. If nonzero, a write is done. 4357*0Sstevel@tonic-gate * Care is taken to write in multiples of SYS_BLOCK when device is 4358*0Sstevel@tonic-gate * non-magtape in case raw i/o is used. 4359*0Sstevel@tonic-gate * 4360*0Sstevel@tonic-gate * NOTE: this is called by writetape() to do the actual writing 4361*0Sstevel@tonic-gate */ 4362*0Sstevel@tonic-gate 4363*0Sstevel@tonic-gate static void 4364*0Sstevel@tonic-gate flushtape(void) 4365*0Sstevel@tonic-gate { 4366*0Sstevel@tonic-gate #ifdef DEBUG 4367*0Sstevel@tonic-gate DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0); 4368*0Sstevel@tonic-gate #endif 4369*0Sstevel@tonic-gate if (recno > 0) { /* anything buffered? */ 4370*0Sstevel@tonic-gate if (NotTape) { 4371*0Sstevel@tonic-gate #if SYS_BLOCK > TBLOCK 4372*0Sstevel@tonic-gate int i; 4373*0Sstevel@tonic-gate 4374*0Sstevel@tonic-gate /* 4375*0Sstevel@tonic-gate * an odd-block write can only happen when 4376*0Sstevel@tonic-gate * we are at the end of a volume that is not a tape. 4377*0Sstevel@tonic-gate * Here we round recno up to an even SYS_BLOCK 4378*0Sstevel@tonic-gate * boundary. 4379*0Sstevel@tonic-gate */ 4380*0Sstevel@tonic-gate if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) { 4381*0Sstevel@tonic-gate #ifdef DEBUG 4382*0Sstevel@tonic-gate DEBUG("flushtape() %d rounding blocks\n", i, 0); 4383*0Sstevel@tonic-gate #endif 4384*0Sstevel@tonic-gate recno += i; /* round up to even SYS_BLOCK */ 4385*0Sstevel@tonic-gate } 4386*0Sstevel@tonic-gate #endif 4387*0Sstevel@tonic-gate if (recno > nblock) 4388*0Sstevel@tonic-gate recno = nblock; 4389*0Sstevel@tonic-gate } 4390*0Sstevel@tonic-gate #ifdef DEBUG 4391*0Sstevel@tonic-gate DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t 4392*0Sstevel@tonic-gate " bytes\n", (blkcnt_t)(NotTape ? recno : nblock), 4393*0Sstevel@tonic-gate (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK); 4394*0Sstevel@tonic-gate #endif 4395*0Sstevel@tonic-gate if (write(mt, tbuf, 4396*0Sstevel@tonic-gate (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) { 4397*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4398*0Sstevel@tonic-gate "tar: tape write error\n")); 4399*0Sstevel@tonic-gate done(2); 4400*0Sstevel@tonic-gate } 4401*0Sstevel@tonic-gate recno = 0; 4402*0Sstevel@tonic-gate } 4403*0Sstevel@tonic-gate } 4404*0Sstevel@tonic-gate 4405*0Sstevel@tonic-gate static void 4406*0Sstevel@tonic-gate copy(void *dst, void *src) 4407*0Sstevel@tonic-gate { 4408*0Sstevel@tonic-gate (void) memcpy(dst, src, TBLOCK); 4409*0Sstevel@tonic-gate } 4410*0Sstevel@tonic-gate 4411*0Sstevel@tonic-gate #ifdef _iBCS2 4412*0Sstevel@tonic-gate /* 4413*0Sstevel@tonic-gate * initarg -- initialize things for nextarg. 4414*0Sstevel@tonic-gate * 4415*0Sstevel@tonic-gate * argv filename list, a la argv. 4416*0Sstevel@tonic-gate * filefile name of file containing filenames. Unless doing 4417*0Sstevel@tonic-gate * a create, seeks must be allowable (e.g. no named pipes). 4418*0Sstevel@tonic-gate * 4419*0Sstevel@tonic-gate * - if filefile is non-NULL, it will be used first, and argv will 4420*0Sstevel@tonic-gate * be used when the data in filefile are exhausted. 4421*0Sstevel@tonic-gate * - otherwise argv will be used. 4422*0Sstevel@tonic-gate */ 4423*0Sstevel@tonic-gate static char **Cmdargv = NULL; 4424*0Sstevel@tonic-gate static FILE *FILEFile = NULL; 4425*0Sstevel@tonic-gate static long seekFile = -1; 4426*0Sstevel@tonic-gate static char *ptrtoFile, *begofFile, *endofFile; 4427*0Sstevel@tonic-gate 4428*0Sstevel@tonic-gate static void 4429*0Sstevel@tonic-gate initarg(char *argv[], char *filefile) 4430*0Sstevel@tonic-gate { 4431*0Sstevel@tonic-gate struct stat statbuf; 4432*0Sstevel@tonic-gate char *p; 4433*0Sstevel@tonic-gate int nbytes; 4434*0Sstevel@tonic-gate 4435*0Sstevel@tonic-gate Cmdargv = argv; 4436*0Sstevel@tonic-gate if (filefile == NULL) 4437*0Sstevel@tonic-gate return; /* no -F file */ 4438*0Sstevel@tonic-gate if (FILEFile != NULL) { 4439*0Sstevel@tonic-gate /* 4440*0Sstevel@tonic-gate * need to REinitialize 4441*0Sstevel@tonic-gate */ 4442*0Sstevel@tonic-gate if (seekFile != -1) 4443*0Sstevel@tonic-gate (void) fseek(FILEFile, seekFile, 0); 4444*0Sstevel@tonic-gate ptrtoFile = begofFile; 4445*0Sstevel@tonic-gate return; 4446*0Sstevel@tonic-gate } 4447*0Sstevel@tonic-gate /* 4448*0Sstevel@tonic-gate * first time initialization 4449*0Sstevel@tonic-gate */ 4450*0Sstevel@tonic-gate if ((FILEFile = fopen(filefile, "r")) == NULL) 4451*0Sstevel@tonic-gate fatal(gettext("cannot open (%s)"), filefile); 4452*0Sstevel@tonic-gate (void) fstat(fileno(FILEFile), &statbuf); 4453*0Sstevel@tonic-gate if ((statbuf.st_mode & S_IFMT) != S_IFREG) { 4454*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4455*0Sstevel@tonic-gate "tar: %s is not a regular file\n"), filefile); 4456*0Sstevel@tonic-gate (void) fclose(FILEFile); 4457*0Sstevel@tonic-gate done(1); 4458*0Sstevel@tonic-gate } 4459*0Sstevel@tonic-gate ptrtoFile = begofFile = endofFile; 4460*0Sstevel@tonic-gate seekFile = 0; 4461*0Sstevel@tonic-gate if (!xflag) 4462*0Sstevel@tonic-gate return; /* the file will be read only once anyway */ 4463*0Sstevel@tonic-gate nbytes = statbuf.st_size; 4464*0Sstevel@tonic-gate while ((begofFile = calloc(nbytes, sizeof (char))) == NULL) 4465*0Sstevel@tonic-gate nbytes -= 20; 4466*0Sstevel@tonic-gate if (nbytes < 50) { 4467*0Sstevel@tonic-gate free(begofFile); 4468*0Sstevel@tonic-gate begofFile = endofFile; 4469*0Sstevel@tonic-gate return; /* no room so just do plain reads */ 4470*0Sstevel@tonic-gate } 4471*0Sstevel@tonic-gate if (fread(begofFile, 1, nbytes, FILEFile) != nbytes) 4472*0Sstevel@tonic-gate fatal(gettext("could not read %s"), filefile); 4473*0Sstevel@tonic-gate ptrtoFile = begofFile; 4474*0Sstevel@tonic-gate endofFile = begofFile + nbytes; 4475*0Sstevel@tonic-gate for (p = begofFile; p < endofFile; ++p) 4476*0Sstevel@tonic-gate if (*p == '\n') 4477*0Sstevel@tonic-gate *p = '\0'; 4478*0Sstevel@tonic-gate if (nbytes != statbuf.st_size) 4479*0Sstevel@tonic-gate seekFile = nbytes + 1; 4480*0Sstevel@tonic-gate else 4481*0Sstevel@tonic-gate (void) fclose(FILEFile); 4482*0Sstevel@tonic-gate } 4483*0Sstevel@tonic-gate 4484*0Sstevel@tonic-gate /* 4485*0Sstevel@tonic-gate * nextarg -- get next argument of arglist. 4486*0Sstevel@tonic-gate * 4487*0Sstevel@tonic-gate * The argument is taken from wherever is appropriate. 4488*0Sstevel@tonic-gate * 4489*0Sstevel@tonic-gate * If the 'F file' function modifier has been specified, the argument 4490*0Sstevel@tonic-gate * will be taken from the file, unless EOF has been reached. 4491*0Sstevel@tonic-gate * Otherwise the argument will be taken from argv. 4492*0Sstevel@tonic-gate * 4493*0Sstevel@tonic-gate * WARNING: 4494*0Sstevel@tonic-gate * Return value may point to static data, whose contents are over- 4495*0Sstevel@tonic-gate * written on each call. 4496*0Sstevel@tonic-gate */ 4497*0Sstevel@tonic-gate static char * 4498*0Sstevel@tonic-gate nextarg(void) 4499*0Sstevel@tonic-gate { 4500*0Sstevel@tonic-gate static char nameFile[PATH_MAX + 1]; 4501*0Sstevel@tonic-gate int n; 4502*0Sstevel@tonic-gate char *p; 4503*0Sstevel@tonic-gate 4504*0Sstevel@tonic-gate if (FILEFile) { 4505*0Sstevel@tonic-gate if (ptrtoFile < endofFile) { 4506*0Sstevel@tonic-gate p = ptrtoFile; 4507*0Sstevel@tonic-gate while (*ptrtoFile) 4508*0Sstevel@tonic-gate ++ptrtoFile; 4509*0Sstevel@tonic-gate ++ptrtoFile; 4510*0Sstevel@tonic-gate return (p); 4511*0Sstevel@tonic-gate } 4512*0Sstevel@tonic-gate if (fgets(nameFile, PATH_MAX + 1, FILEFile) != NULL) { 4513*0Sstevel@tonic-gate n = strlen(nameFile); 4514*0Sstevel@tonic-gate if (n > 0 && nameFile[n-1] == '\n') 4515*0Sstevel@tonic-gate nameFile[n-1] = '\0'; 4516*0Sstevel@tonic-gate return (nameFile); 4517*0Sstevel@tonic-gate } 4518*0Sstevel@tonic-gate } 4519*0Sstevel@tonic-gate return (*Cmdargv++); 4520*0Sstevel@tonic-gate } 4521*0Sstevel@tonic-gate #endif /* _iBCS2 */ 4522*0Sstevel@tonic-gate 4523*0Sstevel@tonic-gate /* 4524*0Sstevel@tonic-gate * kcheck() 4525*0Sstevel@tonic-gate * - checks the validity of size values for non-tape devices 4526*0Sstevel@tonic-gate * - if size is zero, mulvol tar is disabled and size is 4527*0Sstevel@tonic-gate * assumed to be infinite. 4528*0Sstevel@tonic-gate * - returns volume size in TBLOCKS 4529*0Sstevel@tonic-gate */ 4530*0Sstevel@tonic-gate 4531*0Sstevel@tonic-gate static blkcnt_t 4532*0Sstevel@tonic-gate kcheck(char *kstr) 4533*0Sstevel@tonic-gate { 4534*0Sstevel@tonic-gate blkcnt_t kval; 4535*0Sstevel@tonic-gate 4536*0Sstevel@tonic-gate kval = strtoll(kstr, NULL, 0); 4537*0Sstevel@tonic-gate if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */ 4538*0Sstevel@tonic-gate mulvol = 0; /* definitely not mulvol, but we must */ 4539*0Sstevel@tonic-gate return (0); /* took out setting of NotTape */ 4540*0Sstevel@tonic-gate } 4541*0Sstevel@tonic-gate if (kval < (blkcnt_t)MINSIZE) { 4542*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4543*0Sstevel@tonic-gate "tar: sizes below %luK not supported (%" FMT_blkcnt_t 4544*0Sstevel@tonic-gate ").\n"), (ulong_t)MINSIZE, kval); 4545*0Sstevel@tonic-gate if (!kflag) 4546*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4547*0Sstevel@tonic-gate "bad size entry for %s in %s.\n"), 4548*0Sstevel@tonic-gate archive, DEF_FILE); 4549*0Sstevel@tonic-gate done(1); 4550*0Sstevel@tonic-gate } 4551*0Sstevel@tonic-gate mulvol++; 4552*0Sstevel@tonic-gate NotTape++; /* implies non-tape */ 4553*0Sstevel@tonic-gate return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */ 4554*0Sstevel@tonic-gate } 4555*0Sstevel@tonic-gate 4556*0Sstevel@tonic-gate 4557*0Sstevel@tonic-gate /* 4558*0Sstevel@tonic-gate * bcheck() 4559*0Sstevel@tonic-gate * - checks the validity of blocking factors 4560*0Sstevel@tonic-gate * - returns blocking factor 4561*0Sstevel@tonic-gate */ 4562*0Sstevel@tonic-gate 4563*0Sstevel@tonic-gate static int 4564*0Sstevel@tonic-gate bcheck(char *bstr) 4565*0Sstevel@tonic-gate { 4566*0Sstevel@tonic-gate blkcnt_t bval; 4567*0Sstevel@tonic-gate 4568*0Sstevel@tonic-gate bval = strtoll(bstr, NULL, 0); 4569*0Sstevel@tonic-gate if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) { 4570*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4571*0Sstevel@tonic-gate "tar: invalid blocksize \"%s\".\n"), bstr); 4572*0Sstevel@tonic-gate if (!bflag) 4573*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4574*0Sstevel@tonic-gate "bad blocksize entry for '%s' in %s.\n"), 4575*0Sstevel@tonic-gate archive, DEF_FILE); 4576*0Sstevel@tonic-gate done(1); 4577*0Sstevel@tonic-gate } 4578*0Sstevel@tonic-gate 4579*0Sstevel@tonic-gate return ((int)bval); 4580*0Sstevel@tonic-gate } 4581*0Sstevel@tonic-gate 4582*0Sstevel@tonic-gate 4583*0Sstevel@tonic-gate /* 4584*0Sstevel@tonic-gate * defset() 4585*0Sstevel@tonic-gate * - reads DEF_FILE for the set of default values specified. 4586*0Sstevel@tonic-gate * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'. 4587*0Sstevel@tonic-gate * - 'usefile' points to static data, so will be overwritten 4588*0Sstevel@tonic-gate * if this routine is called a second time. 4589*0Sstevel@tonic-gate * - the pattern specified by 'arch' must be followed by four 4590*0Sstevel@tonic-gate * blank-separated fields (1) device (2) blocking, 4591*0Sstevel@tonic-gate * (3) size(K), and (4) tape 4592*0Sstevel@tonic-gate * for example: archive0=/dev/fd 1 400 n 4593*0Sstevel@tonic-gate */ 4594*0Sstevel@tonic-gate 4595*0Sstevel@tonic-gate static int 4596*0Sstevel@tonic-gate defset(char *arch) 4597*0Sstevel@tonic-gate { 4598*0Sstevel@tonic-gate char *bp; 4599*0Sstevel@tonic-gate 4600*0Sstevel@tonic-gate if (defopen(DEF_FILE) != 0) 4601*0Sstevel@tonic-gate return (FALSE); 4602*0Sstevel@tonic-gate if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) { 4603*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4604*0Sstevel@tonic-gate "tar: error setting parameters for %s.\n"), DEF_FILE); 4605*0Sstevel@tonic-gate return (FALSE); /* & following ones too */ 4606*0Sstevel@tonic-gate } 4607*0Sstevel@tonic-gate if ((bp = defread(arch)) == NULL) { 4608*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4609*0Sstevel@tonic-gate "tar: missing or invalid '%s' entry in %s.\n"), 4610*0Sstevel@tonic-gate arch, DEF_FILE); 4611*0Sstevel@tonic-gate return (FALSE); 4612*0Sstevel@tonic-gate } 4613*0Sstevel@tonic-gate if ((usefile = strtok(bp, " \t")) == NULL) { 4614*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4615*0Sstevel@tonic-gate "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE); 4616*0Sstevel@tonic-gate return (FALSE); 4617*0Sstevel@tonic-gate } 4618*0Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) == NULL) { 4619*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4620*0Sstevel@tonic-gate "tar: block component missing in '%s' entry in %s.\n"), 4621*0Sstevel@tonic-gate arch, DEF_FILE); 4622*0Sstevel@tonic-gate return (FALSE); 4623*0Sstevel@tonic-gate } 4624*0Sstevel@tonic-gate nblock = bcheck(bp); 4625*0Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) == NULL) { 4626*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4627*0Sstevel@tonic-gate "tar: size component missing in '%s' entry in %s.\n"), 4628*0Sstevel@tonic-gate arch, DEF_FILE); 4629*0Sstevel@tonic-gate return (FALSE); 4630*0Sstevel@tonic-gate } 4631*0Sstevel@tonic-gate blocklim = kcheck(bp); 4632*0Sstevel@tonic-gate if ((bp = strtok(NULL, " \t")) != NULL) 4633*0Sstevel@tonic-gate NotTape = (*bp == 'n' || *bp == 'N'); 4634*0Sstevel@tonic-gate else 4635*0Sstevel@tonic-gate NotTape = (blocklim != 0); 4636*0Sstevel@tonic-gate (void) defopen(NULL); 4637*0Sstevel@tonic-gate #ifdef DEBUG 4638*0Sstevel@tonic-gate DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile); 4639*0Sstevel@tonic-gate DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n", 4640*0Sstevel@tonic-gate nblock, blocklim); 4641*0Sstevel@tonic-gate DEBUG("defset: not tape = %d\n", NotTape, 0); 4642*0Sstevel@tonic-gate #endif 4643*0Sstevel@tonic-gate return (TRUE); 4644*0Sstevel@tonic-gate } 4645*0Sstevel@tonic-gate 4646*0Sstevel@tonic-gate 4647*0Sstevel@tonic-gate /* 4648*0Sstevel@tonic-gate * Following code handles excluded and included files. 4649*0Sstevel@tonic-gate * A hash table of file names to be {in,ex}cluded is built. 4650*0Sstevel@tonic-gate * For excluded files, before writing or extracting a file 4651*0Sstevel@tonic-gate * check to see if it is in the exclude_tbl. 4652*0Sstevel@tonic-gate * For included files, the wantit() procedure will check to 4653*0Sstevel@tonic-gate * see if the named file is in the include_tbl. 4654*0Sstevel@tonic-gate */ 4655*0Sstevel@tonic-gate 4656*0Sstevel@tonic-gate static void 4657*0Sstevel@tonic-gate build_table(struct file_list *table[], char *file) 4658*0Sstevel@tonic-gate { 4659*0Sstevel@tonic-gate FILE *fp; 4660*0Sstevel@tonic-gate char buf[PATH_MAX + 1]; 4661*0Sstevel@tonic-gate 4662*0Sstevel@tonic-gate if ((fp = fopen(file, "r")) == (FILE *)NULL) 4663*0Sstevel@tonic-gate vperror(1, gettext("could not open %s"), file); 4664*0Sstevel@tonic-gate while (fgets(buf, sizeof (buf), fp) != NULL) { 4665*0Sstevel@tonic-gate if (buf[strlen(buf) - 1] == '\n') 4666*0Sstevel@tonic-gate buf[strlen(buf) - 1] = '\0'; 4667*0Sstevel@tonic-gate /* Only add to table if line has something in it */ 4668*0Sstevel@tonic-gate if (strspn(buf, " \t") != strlen(buf)) 4669*0Sstevel@tonic-gate add_file_to_table(table, buf); 4670*0Sstevel@tonic-gate } 4671*0Sstevel@tonic-gate (void) fclose(fp); 4672*0Sstevel@tonic-gate } 4673*0Sstevel@tonic-gate 4674*0Sstevel@tonic-gate 4675*0Sstevel@tonic-gate /* 4676*0Sstevel@tonic-gate * Add a file name to the the specified table, if the file name has any 4677*0Sstevel@tonic-gate * trailing '/'s then delete them before inserting into the table 4678*0Sstevel@tonic-gate */ 4679*0Sstevel@tonic-gate 4680*0Sstevel@tonic-gate static void 4681*0Sstevel@tonic-gate add_file_to_table(struct file_list *table[], char *str) 4682*0Sstevel@tonic-gate { 4683*0Sstevel@tonic-gate char name[PATH_MAX + 1]; 4684*0Sstevel@tonic-gate unsigned int h; 4685*0Sstevel@tonic-gate struct file_list *exp; 4686*0Sstevel@tonic-gate 4687*0Sstevel@tonic-gate (void) strcpy(name, str); 4688*0Sstevel@tonic-gate while (name[strlen(name) - 1] == '/') { 4689*0Sstevel@tonic-gate name[strlen(name) - 1] = NULL; 4690*0Sstevel@tonic-gate } 4691*0Sstevel@tonic-gate 4692*0Sstevel@tonic-gate h = hash(name); 4693*0Sstevel@tonic-gate if ((exp = (struct file_list *)calloc(sizeof (struct file_list), 4694*0Sstevel@tonic-gate sizeof (char))) == NULL) { 4695*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4696*0Sstevel@tonic-gate "tar: out of memory, exclude/include table(entry)\n")); 4697*0Sstevel@tonic-gate exit(1); 4698*0Sstevel@tonic-gate } 4699*0Sstevel@tonic-gate 4700*0Sstevel@tonic-gate if ((exp->name = strdup(name)) == NULL) { 4701*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4702*0Sstevel@tonic-gate "tar: out of memory, exclude/include table(file name)\n")); 4703*0Sstevel@tonic-gate exit(1); 4704*0Sstevel@tonic-gate } 4705*0Sstevel@tonic-gate 4706*0Sstevel@tonic-gate exp->next = table[h]; 4707*0Sstevel@tonic-gate table[h] = exp; 4708*0Sstevel@tonic-gate } 4709*0Sstevel@tonic-gate 4710*0Sstevel@tonic-gate 4711*0Sstevel@tonic-gate /* 4712*0Sstevel@tonic-gate * See if a file name or any of the file's parent directories is in the 4713*0Sstevel@tonic-gate * specified table, if the file name has any trailing '/'s then delete 4714*0Sstevel@tonic-gate * them before searching the table 4715*0Sstevel@tonic-gate */ 4716*0Sstevel@tonic-gate 4717*0Sstevel@tonic-gate static int 4718*0Sstevel@tonic-gate is_in_table(struct file_list *table[], char *str) 4719*0Sstevel@tonic-gate { 4720*0Sstevel@tonic-gate char name[PATH_MAX + 1]; 4721*0Sstevel@tonic-gate unsigned int h; 4722*0Sstevel@tonic-gate struct file_list *exp; 4723*0Sstevel@tonic-gate char *ptr; 4724*0Sstevel@tonic-gate 4725*0Sstevel@tonic-gate (void) strcpy(name, str); 4726*0Sstevel@tonic-gate while (name[strlen(name) - 1] == '/') { 4727*0Sstevel@tonic-gate name[strlen(name) - 1] = NULL; 4728*0Sstevel@tonic-gate } 4729*0Sstevel@tonic-gate 4730*0Sstevel@tonic-gate /* 4731*0Sstevel@tonic-gate * check for the file name in the passed list 4732*0Sstevel@tonic-gate */ 4733*0Sstevel@tonic-gate h = hash(name); 4734*0Sstevel@tonic-gate exp = table[h]; 4735*0Sstevel@tonic-gate while (exp != NULL) { 4736*0Sstevel@tonic-gate if (strcmp(name, exp->name) == 0) { 4737*0Sstevel@tonic-gate return (1); 4738*0Sstevel@tonic-gate } 4739*0Sstevel@tonic-gate exp = exp->next; 4740*0Sstevel@tonic-gate } 4741*0Sstevel@tonic-gate 4742*0Sstevel@tonic-gate /* 4743*0Sstevel@tonic-gate * check for any parent directories in the file list 4744*0Sstevel@tonic-gate */ 4745*0Sstevel@tonic-gate while ((ptr = strrchr(name, '/'))) { 4746*0Sstevel@tonic-gate *ptr = NULL; 4747*0Sstevel@tonic-gate h = hash(name); 4748*0Sstevel@tonic-gate exp = table[h]; 4749*0Sstevel@tonic-gate while (exp != NULL) { 4750*0Sstevel@tonic-gate if (strcmp(name, exp->name) == 0) { 4751*0Sstevel@tonic-gate return (1); 4752*0Sstevel@tonic-gate } 4753*0Sstevel@tonic-gate exp = exp->next; 4754*0Sstevel@tonic-gate } 4755*0Sstevel@tonic-gate } 4756*0Sstevel@tonic-gate 4757*0Sstevel@tonic-gate return (0); 4758*0Sstevel@tonic-gate } 4759*0Sstevel@tonic-gate 4760*0Sstevel@tonic-gate 4761*0Sstevel@tonic-gate /* 4762*0Sstevel@tonic-gate * Compute a hash from a string. 4763*0Sstevel@tonic-gate */ 4764*0Sstevel@tonic-gate 4765*0Sstevel@tonic-gate static unsigned int 4766*0Sstevel@tonic-gate hash(char *str) 4767*0Sstevel@tonic-gate { 4768*0Sstevel@tonic-gate char *cp; 4769*0Sstevel@tonic-gate unsigned int h; 4770*0Sstevel@tonic-gate 4771*0Sstevel@tonic-gate h = 0; 4772*0Sstevel@tonic-gate for (cp = str; *cp; cp++) { 4773*0Sstevel@tonic-gate h += *cp; 4774*0Sstevel@tonic-gate } 4775*0Sstevel@tonic-gate return (h % TABLE_SIZE); 4776*0Sstevel@tonic-gate } 4777*0Sstevel@tonic-gate 4778*0Sstevel@tonic-gate static void * 4779*0Sstevel@tonic-gate getmem(size_t size) 4780*0Sstevel@tonic-gate { 4781*0Sstevel@tonic-gate void *p = calloc((unsigned)size, sizeof (char)); 4782*0Sstevel@tonic-gate 4783*0Sstevel@tonic-gate if (p == NULL && freemem) { 4784*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4785*0Sstevel@tonic-gate "tar: out of memory, link and directory modtime " 4786*0Sstevel@tonic-gate "info lost\n")); 4787*0Sstevel@tonic-gate freemem = 0; 4788*0Sstevel@tonic-gate if (errflag) 4789*0Sstevel@tonic-gate done(1); 4790*0Sstevel@tonic-gate else 4791*0Sstevel@tonic-gate Errflg = 1; 4792*0Sstevel@tonic-gate } 4793*0Sstevel@tonic-gate return (p); 4794*0Sstevel@tonic-gate } 4795*0Sstevel@tonic-gate 4796*0Sstevel@tonic-gate /* 4797*0Sstevel@tonic-gate * vperror() --variable argument perror. 4798*0Sstevel@tonic-gate * Takes 3 args: exit_status, formats, args. If exit_status is 0, then 4799*0Sstevel@tonic-gate * the errflag (exit on error) is checked -- if it is non-zero, tar exits 4800*0Sstevel@tonic-gate * with the value of whatever "errno" is set to. If exit_status is not 4801*0Sstevel@tonic-gate * zero, then tar exits with that error status. If errflag and exit_status 4802*0Sstevel@tonic-gate * are both zero, the routine returns to where it was called and sets Errflg 4803*0Sstevel@tonic-gate * to errno. 4804*0Sstevel@tonic-gate */ 4805*0Sstevel@tonic-gate 4806*0Sstevel@tonic-gate static void 4807*0Sstevel@tonic-gate vperror(int exit_status, char *fmt, ...) 4808*0Sstevel@tonic-gate { 4809*0Sstevel@tonic-gate va_list ap; 4810*0Sstevel@tonic-gate 4811*0Sstevel@tonic-gate va_start(ap, fmt); 4812*0Sstevel@tonic-gate (void) fputs("tar: ", stderr); 4813*0Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 4814*0Sstevel@tonic-gate (void) fprintf(stderr, ": %s\n", strerror(errno)); 4815*0Sstevel@tonic-gate va_end(ap); 4816*0Sstevel@tonic-gate if (exit_status) 4817*0Sstevel@tonic-gate done(exit_status); 4818*0Sstevel@tonic-gate else 4819*0Sstevel@tonic-gate if (errflag) 4820*0Sstevel@tonic-gate done(errno); 4821*0Sstevel@tonic-gate else 4822*0Sstevel@tonic-gate Errflg = errno; 4823*0Sstevel@tonic-gate } 4824*0Sstevel@tonic-gate 4825*0Sstevel@tonic-gate 4826*0Sstevel@tonic-gate static void 4827*0Sstevel@tonic-gate fatal(char *format, ...) 4828*0Sstevel@tonic-gate { 4829*0Sstevel@tonic-gate va_list ap; 4830*0Sstevel@tonic-gate 4831*0Sstevel@tonic-gate va_start(ap, format); 4832*0Sstevel@tonic-gate (void) fprintf(stderr, "tar: "); 4833*0Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 4834*0Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 4835*0Sstevel@tonic-gate va_end(ap); 4836*0Sstevel@tonic-gate done(1); 4837*0Sstevel@tonic-gate } 4838*0Sstevel@tonic-gate 4839*0Sstevel@tonic-gate 4840*0Sstevel@tonic-gate /* 4841*0Sstevel@tonic-gate * Check to make sure that argument is a char * ptr. 4842*0Sstevel@tonic-gate * Actually, we just check to see that it is non-null. 4843*0Sstevel@tonic-gate * If it is null, print out the message and call usage(), bailing out. 4844*0Sstevel@tonic-gate */ 4845*0Sstevel@tonic-gate 4846*0Sstevel@tonic-gate static void 4847*0Sstevel@tonic-gate assert_string(char *s, char *msg) 4848*0Sstevel@tonic-gate { 4849*0Sstevel@tonic-gate if (s == NULL) { 4850*0Sstevel@tonic-gate (void) fprintf(stderr, msg); 4851*0Sstevel@tonic-gate usage(); 4852*0Sstevel@tonic-gate } 4853*0Sstevel@tonic-gate } 4854*0Sstevel@tonic-gate 4855*0Sstevel@tonic-gate 4856*0Sstevel@tonic-gate static void 4857*0Sstevel@tonic-gate mterr(char *operation, int i, int exitcode) 4858*0Sstevel@tonic-gate { 4859*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4860*0Sstevel@tonic-gate "tar: %s error: "), operation); 4861*0Sstevel@tonic-gate if (i < 0) 4862*0Sstevel@tonic-gate perror(""); 4863*0Sstevel@tonic-gate else 4864*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("unexpected EOF\n")); 4865*0Sstevel@tonic-gate done(exitcode); 4866*0Sstevel@tonic-gate } 4867*0Sstevel@tonic-gate 4868*0Sstevel@tonic-gate static int 4869*0Sstevel@tonic-gate wantit(char *argv[], char **namep, char **dirp, char **component) 4870*0Sstevel@tonic-gate { 4871*0Sstevel@tonic-gate char **cp; 4872*0Sstevel@tonic-gate int gotit; /* true if we've found a match */ 4873*0Sstevel@tonic-gate 4874*0Sstevel@tonic-gate top: 4875*0Sstevel@tonic-gate xhdr_flgs = 0; 4876*0Sstevel@tonic-gate getdir(); 4877*0Sstevel@tonic-gate if (Xhdrflag > 0) { 4878*0Sstevel@tonic-gate if (get_xdata() != 0) { /* Xhdr items and regular header */ 4879*0Sstevel@tonic-gate passtape(); 4880*0Sstevel@tonic-gate return (0); /* Error--don't want to extract */ 4881*0Sstevel@tonic-gate } 4882*0Sstevel@tonic-gate } 4883*0Sstevel@tonic-gate 4884*0Sstevel@tonic-gate #if defined(O_XATTR) 4885*0Sstevel@tonic-gate if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) { 4886*0Sstevel@tonic-gate if (atflag || tflag) { 4887*0Sstevel@tonic-gate (void) read_xattr_hdr(); 4888*0Sstevel@tonic-gate } else { 4889*0Sstevel@tonic-gate passtape(); 4890*0Sstevel@tonic-gate } 4891*0Sstevel@tonic-gate goto top; 4892*0Sstevel@tonic-gate } 4893*0Sstevel@tonic-gate #endif 4894*0Sstevel@tonic-gate 4895*0Sstevel@tonic-gate /* sets *namep to point at the proper name */ 4896*0Sstevel@tonic-gate check_prefix(namep, dirp, component); 4897*0Sstevel@tonic-gate 4898*0Sstevel@tonic-gate if (endtape()) { 4899*0Sstevel@tonic-gate if (Bflag) { 4900*0Sstevel@tonic-gate /* 4901*0Sstevel@tonic-gate * Logically at EOT - consume any extra blocks 4902*0Sstevel@tonic-gate * so that write to our stdin won't fail and 4903*0Sstevel@tonic-gate * emit an error message; otherwise something 4904*0Sstevel@tonic-gate * like "dd if=foo.tar | (cd bar; tar xvf -)" 4905*0Sstevel@tonic-gate * will produce a bogus error message from "dd". 4906*0Sstevel@tonic-gate */ 4907*0Sstevel@tonic-gate 4908*0Sstevel@tonic-gate while (read(mt, tbuf, TBLOCK*nblock) > 0) { 4909*0Sstevel@tonic-gate /* empty body */ 4910*0Sstevel@tonic-gate } 4911*0Sstevel@tonic-gate } 4912*0Sstevel@tonic-gate return (-1); 4913*0Sstevel@tonic-gate } 4914*0Sstevel@tonic-gate 4915*0Sstevel@tonic-gate gotit = 0; 4916*0Sstevel@tonic-gate 4917*0Sstevel@tonic-gate if ((Iflag && is_in_table(include_tbl, *namep)) || 4918*0Sstevel@tonic-gate (! Iflag && *argv == NULL)) { 4919*0Sstevel@tonic-gate gotit = 1; 4920*0Sstevel@tonic-gate } else { 4921*0Sstevel@tonic-gate for (cp = argv; *cp; cp++) { 4922*0Sstevel@tonic-gate if (is_prefix(*cp, *namep)) { 4923*0Sstevel@tonic-gate gotit = 1; 4924*0Sstevel@tonic-gate break; 4925*0Sstevel@tonic-gate } 4926*0Sstevel@tonic-gate } 4927*0Sstevel@tonic-gate } 4928*0Sstevel@tonic-gate 4929*0Sstevel@tonic-gate if (! gotit) { 4930*0Sstevel@tonic-gate passtape(); 4931*0Sstevel@tonic-gate return (0); 4932*0Sstevel@tonic-gate } 4933*0Sstevel@tonic-gate 4934*0Sstevel@tonic-gate if (Xflag && is_in_table(exclude_tbl, *namep)) { 4935*0Sstevel@tonic-gate if (vflag) { 4936*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s excluded\n"), 4937*0Sstevel@tonic-gate *namep); 4938*0Sstevel@tonic-gate } 4939*0Sstevel@tonic-gate passtape(); 4940*0Sstevel@tonic-gate return (0); 4941*0Sstevel@tonic-gate } 4942*0Sstevel@tonic-gate 4943*0Sstevel@tonic-gate return (1); 4944*0Sstevel@tonic-gate } 4945*0Sstevel@tonic-gate 4946*0Sstevel@tonic-gate 4947*0Sstevel@tonic-gate /* 4948*0Sstevel@tonic-gate * Return through *namep a pointer to the proper fullname (i.e "<name> | 4949*0Sstevel@tonic-gate * <prefix>/<name>"), as represented in the header entry dblock.dbuf. 4950*0Sstevel@tonic-gate */ 4951*0Sstevel@tonic-gate 4952*0Sstevel@tonic-gate static void 4953*0Sstevel@tonic-gate check_prefix(char **namep, char **dirp, char **compp) 4954*0Sstevel@tonic-gate { 4955*0Sstevel@tonic-gate static char fullname[PATH_MAX + 1]; 4956*0Sstevel@tonic-gate static char dir[PATH_MAX + 1]; 4957*0Sstevel@tonic-gate static char component[PATH_MAX + 1]; 4958*0Sstevel@tonic-gate static char savename[PATH_MAX + 1]; 4959*0Sstevel@tonic-gate char *s; 4960*0Sstevel@tonic-gate 4961*0Sstevel@tonic-gate (void) memset(dir, 0, sizeof (dir)); 4962*0Sstevel@tonic-gate (void) memset(component, 0, sizeof (component)); 4963*0Sstevel@tonic-gate 4964*0Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) { 4965*0Sstevel@tonic-gate (void) strcpy(fullname, Xtarhdr.x_path); 4966*0Sstevel@tonic-gate } else { 4967*0Sstevel@tonic-gate if (dblock.dbuf.prefix[0] != '\0') 4968*0Sstevel@tonic-gate (void) sprintf(fullname, "%.*s/%.*s", PRESIZ, 4969*0Sstevel@tonic-gate dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name); 4970*0Sstevel@tonic-gate else 4971*0Sstevel@tonic-gate (void) sprintf(fullname, "%.*s", NAMSIZ, 4972*0Sstevel@tonic-gate dblock.dbuf.name); 4973*0Sstevel@tonic-gate } 4974*0Sstevel@tonic-gate 4975*0Sstevel@tonic-gate /* 4976*0Sstevel@tonic-gate * Set dir and component names 4977*0Sstevel@tonic-gate */ 4978*0Sstevel@tonic-gate 4979*0Sstevel@tonic-gate get_parent(fullname, dir); 4980*0Sstevel@tonic-gate 4981*0Sstevel@tonic-gate #if defined(O_XATTR) 4982*0Sstevel@tonic-gate if (xattrp == (struct xattr_buf *)NULL) { 4983*0Sstevel@tonic-gate #endif 4984*0Sstevel@tonic-gate /* 4985*0Sstevel@tonic-gate * Save of real name since were going to chop off the 4986*0Sstevel@tonic-gate * trailing slashes. 4987*0Sstevel@tonic-gate */ 4988*0Sstevel@tonic-gate (void) strcpy(savename, fullname); 4989*0Sstevel@tonic-gate /* 4990*0Sstevel@tonic-gate * first strip of trailing slashes. 4991*0Sstevel@tonic-gate */ 4992*0Sstevel@tonic-gate chop_endslashes(savename); 4993*0Sstevel@tonic-gate s = get_component(savename); 4994*0Sstevel@tonic-gate (void) strcpy(component, s); 4995*0Sstevel@tonic-gate 4996*0Sstevel@tonic-gate #if defined(O_XATTR) 4997*0Sstevel@tonic-gate } else { 4998*0Sstevel@tonic-gate (void) strcpy(fullname, xattrp->h_names); 4999*0Sstevel@tonic-gate (void) strcpy(dir, fullname); 5000*0Sstevel@tonic-gate (void) strcpy(component, xattrp->h_names + 5001*0Sstevel@tonic-gate strlen(xattrp->h_names) + 1); 5002*0Sstevel@tonic-gate } 5003*0Sstevel@tonic-gate #endif 5004*0Sstevel@tonic-gate *namep = fullname; 5005*0Sstevel@tonic-gate *dirp = dir; 5006*0Sstevel@tonic-gate *compp = component; 5007*0Sstevel@tonic-gate } 5008*0Sstevel@tonic-gate 5009*0Sstevel@tonic-gate 5010*0Sstevel@tonic-gate static wchar_t 5011*0Sstevel@tonic-gate yesnoresponse(void) 5012*0Sstevel@tonic-gate { 5013*0Sstevel@tonic-gate wchar_t c; 5014*0Sstevel@tonic-gate 5015*0Sstevel@tonic-gate c = getwchar(); 5016*0Sstevel@tonic-gate if (c != '\n') 5017*0Sstevel@tonic-gate while (getwchar() != '\n'); 5018*0Sstevel@tonic-gate else c = 0; 5019*0Sstevel@tonic-gate return (c); 5020*0Sstevel@tonic-gate } 5021*0Sstevel@tonic-gate 5022*0Sstevel@tonic-gate 5023*0Sstevel@tonic-gate /* 5024*0Sstevel@tonic-gate * Return true if the object indicated by the file descriptor and type 5025*0Sstevel@tonic-gate * is a tape device, false otherwise 5026*0Sstevel@tonic-gate */ 5027*0Sstevel@tonic-gate 5028*0Sstevel@tonic-gate static int 5029*0Sstevel@tonic-gate istape(int fd, int type) 5030*0Sstevel@tonic-gate { 5031*0Sstevel@tonic-gate int result = 0; 5032*0Sstevel@tonic-gate 5033*0Sstevel@tonic-gate if (type & S_IFCHR) { 5034*0Sstevel@tonic-gate struct mtget mtg; 5035*0Sstevel@tonic-gate 5036*0Sstevel@tonic-gate if (ioctl(fd, MTIOCGET, &mtg) != -1) { 5037*0Sstevel@tonic-gate result = 1; 5038*0Sstevel@tonic-gate } 5039*0Sstevel@tonic-gate } 5040*0Sstevel@tonic-gate 5041*0Sstevel@tonic-gate return (result); 5042*0Sstevel@tonic-gate } 5043*0Sstevel@tonic-gate 5044*0Sstevel@tonic-gate #include <utmpx.h> 5045*0Sstevel@tonic-gate 5046*0Sstevel@tonic-gate struct utmpx utmpx; 5047*0Sstevel@tonic-gate 5048*0Sstevel@tonic-gate #define NMAX (sizeof (utmpx.ut_name)) 5049*0Sstevel@tonic-gate 5050*0Sstevel@tonic-gate typedef struct cachenode { /* this struct must be zeroed before using */ 5051*0Sstevel@tonic-gate struct cachenode *next; /* next in hash chain */ 5052*0Sstevel@tonic-gate int val; /* the uid or gid of this entry */ 5053*0Sstevel@tonic-gate int namehash; /* name's hash signature */ 5054*0Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 5055*0Sstevel@tonic-gate } cachenode_t; 5056*0Sstevel@tonic-gate 5057*0Sstevel@tonic-gate #define HASHSIZE 256 5058*0Sstevel@tonic-gate 5059*0Sstevel@tonic-gate static cachenode_t *names[HASHSIZE]; 5060*0Sstevel@tonic-gate static cachenode_t *groups[HASHSIZE]; 5061*0Sstevel@tonic-gate static cachenode_t *uids[HASHSIZE]; 5062*0Sstevel@tonic-gate static cachenode_t *gids[HASHSIZE]; 5063*0Sstevel@tonic-gate 5064*0Sstevel@tonic-gate static int 5065*0Sstevel@tonic-gate hash_byname(char *name) 5066*0Sstevel@tonic-gate { 5067*0Sstevel@tonic-gate int i, c, h = 0; 5068*0Sstevel@tonic-gate 5069*0Sstevel@tonic-gate for (i = 0; i < NMAX; i++) { 5070*0Sstevel@tonic-gate c = name[i]; 5071*0Sstevel@tonic-gate if (c == '\0') 5072*0Sstevel@tonic-gate break; 5073*0Sstevel@tonic-gate h = (h << 4) + h + c; 5074*0Sstevel@tonic-gate } 5075*0Sstevel@tonic-gate return (h); 5076*0Sstevel@tonic-gate } 5077*0Sstevel@tonic-gate 5078*0Sstevel@tonic-gate static cachenode_t * 5079*0Sstevel@tonic-gate hash_lookup_byval(cachenode_t *table[], int val) 5080*0Sstevel@tonic-gate { 5081*0Sstevel@tonic-gate int h = val; 5082*0Sstevel@tonic-gate cachenode_t *c; 5083*0Sstevel@tonic-gate 5084*0Sstevel@tonic-gate for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) { 5085*0Sstevel@tonic-gate if (c->val == val) 5086*0Sstevel@tonic-gate return (c); 5087*0Sstevel@tonic-gate } 5088*0Sstevel@tonic-gate return (NULL); 5089*0Sstevel@tonic-gate } 5090*0Sstevel@tonic-gate 5091*0Sstevel@tonic-gate static cachenode_t * 5092*0Sstevel@tonic-gate hash_lookup_byname(cachenode_t *table[], char *name) 5093*0Sstevel@tonic-gate { 5094*0Sstevel@tonic-gate int h = hash_byname(name); 5095*0Sstevel@tonic-gate cachenode_t *c; 5096*0Sstevel@tonic-gate 5097*0Sstevel@tonic-gate for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) { 5098*0Sstevel@tonic-gate if (c->namehash == h && strcmp(c->name, name) == 0) 5099*0Sstevel@tonic-gate return (c); 5100*0Sstevel@tonic-gate } 5101*0Sstevel@tonic-gate return (NULL); 5102*0Sstevel@tonic-gate } 5103*0Sstevel@tonic-gate 5104*0Sstevel@tonic-gate static cachenode_t * 5105*0Sstevel@tonic-gate hash_insert(cachenode_t *table[], char *name, int value) 5106*0Sstevel@tonic-gate { 5107*0Sstevel@tonic-gate cachenode_t *c; 5108*0Sstevel@tonic-gate int signature; 5109*0Sstevel@tonic-gate 5110*0Sstevel@tonic-gate c = calloc(1, sizeof (cachenode_t)); 5111*0Sstevel@tonic-gate if (c == NULL) { 5112*0Sstevel@tonic-gate perror("malloc"); 5113*0Sstevel@tonic-gate exit(1); 5114*0Sstevel@tonic-gate } 5115*0Sstevel@tonic-gate if (name != NULL) { 5116*0Sstevel@tonic-gate (void) strncpy(c->name, name, NMAX); 5117*0Sstevel@tonic-gate c->namehash = hash_byname(name); 5118*0Sstevel@tonic-gate } 5119*0Sstevel@tonic-gate c->val = value; 5120*0Sstevel@tonic-gate if (table == uids || table == gids) 5121*0Sstevel@tonic-gate signature = c->val; 5122*0Sstevel@tonic-gate else 5123*0Sstevel@tonic-gate signature = c->namehash; 5124*0Sstevel@tonic-gate c->next = table[signature & (HASHSIZE - 1)]; 5125*0Sstevel@tonic-gate table[signature & (HASHSIZE - 1)] = c; 5126*0Sstevel@tonic-gate return (c); 5127*0Sstevel@tonic-gate } 5128*0Sstevel@tonic-gate 5129*0Sstevel@tonic-gate static char * 5130*0Sstevel@tonic-gate getname(uid_t uid) 5131*0Sstevel@tonic-gate { 5132*0Sstevel@tonic-gate cachenode_t *c; 5133*0Sstevel@tonic-gate 5134*0Sstevel@tonic-gate if ((c = hash_lookup_byval(uids, uid)) == NULL) { 5135*0Sstevel@tonic-gate struct passwd *pwent = getpwuid(uid); 5136*0Sstevel@tonic-gate c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid); 5137*0Sstevel@tonic-gate } 5138*0Sstevel@tonic-gate return (c->name); 5139*0Sstevel@tonic-gate } 5140*0Sstevel@tonic-gate 5141*0Sstevel@tonic-gate static char * 5142*0Sstevel@tonic-gate getgroup(gid_t gid) 5143*0Sstevel@tonic-gate { 5144*0Sstevel@tonic-gate cachenode_t *c; 5145*0Sstevel@tonic-gate 5146*0Sstevel@tonic-gate if ((c = hash_lookup_byval(gids, gid)) == NULL) { 5147*0Sstevel@tonic-gate struct group *grent = getgrgid(gid); 5148*0Sstevel@tonic-gate c = hash_insert(gids, grent ? grent->gr_name : NULL, gid); 5149*0Sstevel@tonic-gate } 5150*0Sstevel@tonic-gate return (c->name); 5151*0Sstevel@tonic-gate } 5152*0Sstevel@tonic-gate 5153*0Sstevel@tonic-gate static uid_t 5154*0Sstevel@tonic-gate getuidbyname(char *name) 5155*0Sstevel@tonic-gate { 5156*0Sstevel@tonic-gate cachenode_t *c; 5157*0Sstevel@tonic-gate 5158*0Sstevel@tonic-gate if ((c = hash_lookup_byname(names, name)) == NULL) { 5159*0Sstevel@tonic-gate struct passwd *pwent = getpwnam(name); 5160*0Sstevel@tonic-gate c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1); 5161*0Sstevel@tonic-gate } 5162*0Sstevel@tonic-gate return ((uid_t)c->val); 5163*0Sstevel@tonic-gate } 5164*0Sstevel@tonic-gate 5165*0Sstevel@tonic-gate static gid_t 5166*0Sstevel@tonic-gate getgidbyname(char *group) 5167*0Sstevel@tonic-gate { 5168*0Sstevel@tonic-gate cachenode_t *c; 5169*0Sstevel@tonic-gate 5170*0Sstevel@tonic-gate if ((c = hash_lookup_byname(groups, group)) == NULL) { 5171*0Sstevel@tonic-gate struct group *grent = getgrnam(group); 5172*0Sstevel@tonic-gate c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1); 5173*0Sstevel@tonic-gate } 5174*0Sstevel@tonic-gate return ((gid_t)c->val); 5175*0Sstevel@tonic-gate } 5176*0Sstevel@tonic-gate 5177*0Sstevel@tonic-gate /* 5178*0Sstevel@tonic-gate * Build the header. 5179*0Sstevel@tonic-gate * Determine whether or not an extended header is also needed. If needed, 5180*0Sstevel@tonic-gate * create and write the extended header and its data. 5181*0Sstevel@tonic-gate * Writing of the extended header assumes that "tomodes" has been called and 5182*0Sstevel@tonic-gate * the relevant information has been placed in the header block. 5183*0Sstevel@tonic-gate */ 5184*0Sstevel@tonic-gate 5185*0Sstevel@tonic-gate static int 5186*0Sstevel@tonic-gate build_dblock( 5187*0Sstevel@tonic-gate const char *name, 5188*0Sstevel@tonic-gate const char *linkname, 5189*0Sstevel@tonic-gate const char typeflag, 5190*0Sstevel@tonic-gate const int filetype, 5191*0Sstevel@tonic-gate const struct stat *sp, 5192*0Sstevel@tonic-gate const dev_t device, 5193*0Sstevel@tonic-gate const char *prefix) 5194*0Sstevel@tonic-gate { 5195*0Sstevel@tonic-gate int nblks; 5196*0Sstevel@tonic-gate major_t dev; 5197*0Sstevel@tonic-gate const char *filename; 5198*0Sstevel@tonic-gate const char *lastslash; 5199*0Sstevel@tonic-gate 5200*0Sstevel@tonic-gate if (filetype == XATTR_FILE) 5201*0Sstevel@tonic-gate dblock.dbuf.typeflag = _XATTR_HDRTYPE; 5202*0Sstevel@tonic-gate else 5203*0Sstevel@tonic-gate dblock.dbuf.typeflag = typeflag; 5204*0Sstevel@tonic-gate (void) memset(dblock.dbuf.name, '\0', NAMSIZ); 5205*0Sstevel@tonic-gate (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ); 5206*0Sstevel@tonic-gate (void) memset(dblock.dbuf.prefix, '\0', PRESIZ); 5207*0Sstevel@tonic-gate 5208*0Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 5209*0Sstevel@tonic-gate filename = Xtarhdr.x_path; 5210*0Sstevel@tonic-gate else 5211*0Sstevel@tonic-gate filename = name; 5212*0Sstevel@tonic-gate 5213*0Sstevel@tonic-gate if ((dev = major(device)) > OCTAL7CHAR) { 5214*0Sstevel@tonic-gate if (Eflag) { 5215*0Sstevel@tonic-gate xhdr_flgs |= _X_DEVMAJOR; 5216*0Sstevel@tonic-gate Xtarhdr.x_devmajor = dev; 5217*0Sstevel@tonic-gate } else { 5218*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5219*0Sstevel@tonic-gate "Device major too large for %s. Use -E flag."), 5220*0Sstevel@tonic-gate filename); 5221*0Sstevel@tonic-gate if (errflag) 5222*0Sstevel@tonic-gate done(1); 5223*0Sstevel@tonic-gate else 5224*0Sstevel@tonic-gate Errflg = 1; 5225*0Sstevel@tonic-gate } 5226*0Sstevel@tonic-gate dev = 0; 5227*0Sstevel@tonic-gate } 5228*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev); 5229*0Sstevel@tonic-gate if ((dev = minor(device)) > OCTAL7CHAR) { 5230*0Sstevel@tonic-gate if (Eflag) { 5231*0Sstevel@tonic-gate xhdr_flgs |= _X_DEVMINOR; 5232*0Sstevel@tonic-gate Xtarhdr.x_devminor = dev; 5233*0Sstevel@tonic-gate } else { 5234*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5235*0Sstevel@tonic-gate "Device minor too large for %s. Use -E flag."), 5236*0Sstevel@tonic-gate filename); 5237*0Sstevel@tonic-gate if (errflag) 5238*0Sstevel@tonic-gate done(1); 5239*0Sstevel@tonic-gate else 5240*0Sstevel@tonic-gate Errflg = 1; 5241*0Sstevel@tonic-gate } 5242*0Sstevel@tonic-gate dev = 0; 5243*0Sstevel@tonic-gate } 5244*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.devminor, "%07lo", dev); 5245*0Sstevel@tonic-gate 5246*0Sstevel@tonic-gate (void) strncpy(dblock.dbuf.name, name, NAMSIZ); 5247*0Sstevel@tonic-gate (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ); 5248*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type); 5249*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.version, "00"); 5250*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid)); 5251*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid)); 5252*0Sstevel@tonic-gate (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ); 5253*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock)); 5254*0Sstevel@tonic-gate 5255*0Sstevel@tonic-gate if (Eflag) { 5256*0Sstevel@tonic-gate (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK); 5257*0Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ); 5258*0Sstevel@tonic-gate lastslash = strrchr(name, '/'); 5259*0Sstevel@tonic-gate if (lastslash == NULL) 5260*0Sstevel@tonic-gate lastslash = name; 5261*0Sstevel@tonic-gate else 5262*0Sstevel@tonic-gate lastslash++; 5263*0Sstevel@tonic-gate (void) strcpy(xhdr_buf.dbuf.name, lastslash); 5264*0Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ); 5265*0Sstevel@tonic-gate (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ); 5266*0Sstevel@tonic-gate (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname); 5267*0Sstevel@tonic-gate xhdr_count++; 5268*0Sstevel@tonic-gate xrec_offset = 0; 5269*0Sstevel@tonic-gate gen_date("mtime", sp->st_mtim); 5270*0Sstevel@tonic-gate xhdr_buf.dbuf.typeflag = 'X'; 5271*0Sstevel@tonic-gate if (gen_utf8_names(filename) != 0) 5272*0Sstevel@tonic-gate return (1); 5273*0Sstevel@tonic-gate 5274*0Sstevel@tonic-gate #ifdef XHDR_DEBUG 5275*0Sstevel@tonic-gate Xtarhdr.x_uname = dblock.dbuf.uname; 5276*0Sstevel@tonic-gate Xtarhdr.x_gname = dblock.dbuf.gname; 5277*0Sstevel@tonic-gate xhdr_flgs |= (_X_UNAME | _X_GNAME); 5278*0Sstevel@tonic-gate #endif 5279*0Sstevel@tonic-gate if (xhdr_flgs) { 5280*0Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMAJOR) 5281*0Sstevel@tonic-gate gen_num("SUN.devmajor", Xtarhdr.x_devmajor); 5282*0Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMINOR) 5283*0Sstevel@tonic-gate gen_num("SUN.devminor", Xtarhdr.x_devminor); 5284*0Sstevel@tonic-gate if (xhdr_flgs & _X_GID) 5285*0Sstevel@tonic-gate gen_num("gid", Xtarhdr.x_gid); 5286*0Sstevel@tonic-gate if (xhdr_flgs & _X_UID) 5287*0Sstevel@tonic-gate gen_num("uid", Xtarhdr.x_uid); 5288*0Sstevel@tonic-gate if (xhdr_flgs & _X_SIZE) 5289*0Sstevel@tonic-gate gen_num("size", Xtarhdr.x_filesz); 5290*0Sstevel@tonic-gate if (xhdr_flgs & _X_PATH) 5291*0Sstevel@tonic-gate gen_string("path", Xtarhdr.x_path); 5292*0Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) 5293*0Sstevel@tonic-gate gen_string("linkpath", Xtarhdr.x_linkpath); 5294*0Sstevel@tonic-gate if (xhdr_flgs & _X_GNAME) 5295*0Sstevel@tonic-gate gen_string("gname", Xtarhdr.x_gname); 5296*0Sstevel@tonic-gate if (xhdr_flgs & _X_UNAME) 5297*0Sstevel@tonic-gate gen_string("uname", Xtarhdr.x_uname); 5298*0Sstevel@tonic-gate } 5299*0Sstevel@tonic-gate (void) sprintf(xhdr_buf.dbuf.size, 5300*0Sstevel@tonic-gate "%011" FMT_off_t_o, xrec_offset); 5301*0Sstevel@tonic-gate (void) sprintf(xhdr_buf.dbuf.chksum, "%07o", 5302*0Sstevel@tonic-gate checksum(&xhdr_buf)); 5303*0Sstevel@tonic-gate (void) writetbuf((char *)&xhdr_buf, 1); 5304*0Sstevel@tonic-gate nblks = TBLOCKS(xrec_offset); 5305*0Sstevel@tonic-gate (void) writetbuf(xrec_ptr, nblks); 5306*0Sstevel@tonic-gate } 5307*0Sstevel@tonic-gate return (0); 5308*0Sstevel@tonic-gate } 5309*0Sstevel@tonic-gate 5310*0Sstevel@tonic-gate 5311*0Sstevel@tonic-gate /* 5312*0Sstevel@tonic-gate * makeDir - ensure that a directory with the pathname denoted by name 5313*0Sstevel@tonic-gate * exists, and return 1 on success, and 0 on failure (e.g., 5314*0Sstevel@tonic-gate * read-only file system, exists but not-a-directory). 5315*0Sstevel@tonic-gate */ 5316*0Sstevel@tonic-gate 5317*0Sstevel@tonic-gate static int 5318*0Sstevel@tonic-gate makeDir(char *name) 5319*0Sstevel@tonic-gate { 5320*0Sstevel@tonic-gate struct stat buf; 5321*0Sstevel@tonic-gate 5322*0Sstevel@tonic-gate if (access(name, 0) < 0) { /* name doesn't exist */ 5323*0Sstevel@tonic-gate if (mkdir(name, 0777) < 0) { 5324*0Sstevel@tonic-gate vperror(0, "%s", name); 5325*0Sstevel@tonic-gate return (0); 5326*0Sstevel@tonic-gate } 5327*0Sstevel@tonic-gate } else { /* name exists */ 5328*0Sstevel@tonic-gate if (stat(name, &buf) < 0) { 5329*0Sstevel@tonic-gate vperror(0, "%s", name); 5330*0Sstevel@tonic-gate return (0); 5331*0Sstevel@tonic-gate } 5332*0Sstevel@tonic-gate 5333*0Sstevel@tonic-gate return ((buf.st_mode & S_IFMT) == S_IFDIR); 5334*0Sstevel@tonic-gate } 5335*0Sstevel@tonic-gate 5336*0Sstevel@tonic-gate return (1); 5337*0Sstevel@tonic-gate } 5338*0Sstevel@tonic-gate 5339*0Sstevel@tonic-gate 5340*0Sstevel@tonic-gate /* 5341*0Sstevel@tonic-gate * Save this directory and its mtime on the stack, popping and setting 5342*0Sstevel@tonic-gate * the mtimes of any stacked dirs which aren't parents of this one. 5343*0Sstevel@tonic-gate * A null name causes the entire stack to be unwound and set. 5344*0Sstevel@tonic-gate * 5345*0Sstevel@tonic-gate * Since all the elements of the directory "stack" share a common 5346*0Sstevel@tonic-gate * prefix, we can make do with one string. We keep only the current 5347*0Sstevel@tonic-gate * directory path, with an associated array of mtime's. A negative 5348*0Sstevel@tonic-gate * mtime means no mtime. 5349*0Sstevel@tonic-gate * 5350*0Sstevel@tonic-gate * This stack algorithm is not guaranteed to work for tapes created 5351*0Sstevel@tonic-gate * with the 'r' function letter, but the vast majority of tapes with 5352*0Sstevel@tonic-gate * directories are not. This avoids saving every directory record on 5353*0Sstevel@tonic-gate * the tape and setting all the times at the end. 5354*0Sstevel@tonic-gate * 5355*0Sstevel@tonic-gate * (This was borrowed from the 4.1.3 source, and adapted to the 5.x 5356*0Sstevel@tonic-gate * environment) 5357*0Sstevel@tonic-gate */ 5358*0Sstevel@tonic-gate 5359*0Sstevel@tonic-gate static void 5360*0Sstevel@tonic-gate doDirTimes(char *name, timestruc_t modTime) 5361*0Sstevel@tonic-gate { 5362*0Sstevel@tonic-gate static char dirstack[PATH_MAX+2]; 5363*0Sstevel@tonic-gate /* Add spaces for the last slash and last NULL */ 5364*0Sstevel@tonic-gate static timestruc_t modtimes[PATH_MAX+1]; /* hash table */ 5365*0Sstevel@tonic-gate char *p = dirstack; 5366*0Sstevel@tonic-gate char *q = name; 5367*0Sstevel@tonic-gate char *savp; 5368*0Sstevel@tonic-gate 5369*0Sstevel@tonic-gate if (q) { 5370*0Sstevel@tonic-gate /* 5371*0Sstevel@tonic-gate * Find common prefix 5372*0Sstevel@tonic-gate */ 5373*0Sstevel@tonic-gate 5374*0Sstevel@tonic-gate while (*p == *q && *p) { 5375*0Sstevel@tonic-gate p++; q++; 5376*0Sstevel@tonic-gate } 5377*0Sstevel@tonic-gate } 5378*0Sstevel@tonic-gate 5379*0Sstevel@tonic-gate savp = p; 5380*0Sstevel@tonic-gate while (*p) { 5381*0Sstevel@tonic-gate /* 5382*0Sstevel@tonic-gate * Not a child: unwind the stack, setting the times. 5383*0Sstevel@tonic-gate * The order we do this doesn't matter, so we go "forward." 5384*0Sstevel@tonic-gate */ 5385*0Sstevel@tonic-gate 5386*0Sstevel@tonic-gate if (*p == '/') 5387*0Sstevel@tonic-gate if (modtimes[p - dirstack].tv_sec >= 0) { 5388*0Sstevel@tonic-gate *p = '\0'; /* zap the slash */ 5389*0Sstevel@tonic-gate setPathTimes(AT_FDCWD, dirstack, 5390*0Sstevel@tonic-gate modtimes[p - dirstack]); 5391*0Sstevel@tonic-gate *p = '/'; 5392*0Sstevel@tonic-gate } 5393*0Sstevel@tonic-gate ++p; 5394*0Sstevel@tonic-gate } 5395*0Sstevel@tonic-gate 5396*0Sstevel@tonic-gate p = savp; 5397*0Sstevel@tonic-gate 5398*0Sstevel@tonic-gate /* 5399*0Sstevel@tonic-gate * Push this one on the "stack" 5400*0Sstevel@tonic-gate */ 5401*0Sstevel@tonic-gate 5402*0Sstevel@tonic-gate if (q) { 5403*0Sstevel@tonic-gate 5404*0Sstevel@tonic-gate /* 5405*0Sstevel@tonic-gate * Since the name parameter points the dir pathname 5406*0Sstevel@tonic-gate * which is limited only to contain PATH_MAX chars 5407*0Sstevel@tonic-gate * at maximum, we can ignore the overflow case of p. 5408*0Sstevel@tonic-gate */ 5409*0Sstevel@tonic-gate 5410*0Sstevel@tonic-gate while ((*p = *q++)) { /* append the rest of the new dir */ 5411*0Sstevel@tonic-gate modtimes[p - dirstack].tv_sec = -1; 5412*0Sstevel@tonic-gate p++; 5413*0Sstevel@tonic-gate } 5414*0Sstevel@tonic-gate 5415*0Sstevel@tonic-gate /* 5416*0Sstevel@tonic-gate * If the tar file had used 'P' or 'E' function modifier, 5417*0Sstevel@tonic-gate * append the last slash. 5418*0Sstevel@tonic-gate */ 5419*0Sstevel@tonic-gate if (*(p - 1) != '/') { 5420*0Sstevel@tonic-gate *p++ = '/'; 5421*0Sstevel@tonic-gate *p = '\0'; 5422*0Sstevel@tonic-gate } 5423*0Sstevel@tonic-gate /* overwrite the last one */ 5424*0Sstevel@tonic-gate modtimes[p - dirstack - 1] = modTime; 5425*0Sstevel@tonic-gate } 5426*0Sstevel@tonic-gate } 5427*0Sstevel@tonic-gate 5428*0Sstevel@tonic-gate 5429*0Sstevel@tonic-gate /* 5430*0Sstevel@tonic-gate * setPathTimes - set the modification time for given path. Return 1 if 5431*0Sstevel@tonic-gate * successful and 0 if not successful. 5432*0Sstevel@tonic-gate */ 5433*0Sstevel@tonic-gate 5434*0Sstevel@tonic-gate static void 5435*0Sstevel@tonic-gate setPathTimes(int dirfd, char *path, timestruc_t modTime) 5436*0Sstevel@tonic-gate 5437*0Sstevel@tonic-gate { 5438*0Sstevel@tonic-gate struct timeval timebuf[2]; 5439*0Sstevel@tonic-gate 5440*0Sstevel@tonic-gate /* 5441*0Sstevel@tonic-gate * futimesat takes an array of two timeval structs. 5442*0Sstevel@tonic-gate * The first entry contains access time. 5443*0Sstevel@tonic-gate * The second entry contains modification time. 5444*0Sstevel@tonic-gate * Unlike a timestruc_t, which uses nanoseconds, timeval uses 5445*0Sstevel@tonic-gate * microseconds. 5446*0Sstevel@tonic-gate */ 5447*0Sstevel@tonic-gate timebuf[0].tv_sec = time((time_t *)0); 5448*0Sstevel@tonic-gate timebuf[0].tv_usec = 0; 5449*0Sstevel@tonic-gate timebuf[1].tv_sec = modTime.tv_sec; 5450*0Sstevel@tonic-gate 5451*0Sstevel@tonic-gate /* Extended header: use microseconds */ 5452*0Sstevel@tonic-gate timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0; 5453*0Sstevel@tonic-gate 5454*0Sstevel@tonic-gate if (futimesat(dirfd, path, timebuf) < 0) 5455*0Sstevel@tonic-gate vperror(0, "can't set time on %s", path); 5456*0Sstevel@tonic-gate } 5457*0Sstevel@tonic-gate 5458*0Sstevel@tonic-gate 5459*0Sstevel@tonic-gate /* 5460*0Sstevel@tonic-gate * If hflag is set then delete the symbolic link's target. 5461*0Sstevel@tonic-gate * If !hflag then delete the target. 5462*0Sstevel@tonic-gate */ 5463*0Sstevel@tonic-gate 5464*0Sstevel@tonic-gate static void 5465*0Sstevel@tonic-gate delete_target(int fd, char *namep) 5466*0Sstevel@tonic-gate { 5467*0Sstevel@tonic-gate struct stat xtractbuf; 5468*0Sstevel@tonic-gate char buf[PATH_MAX + 1]; 5469*0Sstevel@tonic-gate int n; 5470*0Sstevel@tonic-gate 5471*0Sstevel@tonic-gate 5472*0Sstevel@tonic-gate if (unlinkat(fd, namep, AT_REMOVEDIR) < 0) { 5473*0Sstevel@tonic-gate if (errno == ENOTDIR && !hflag) { 5474*0Sstevel@tonic-gate (void) unlinkat(fd, namep, 0); 5475*0Sstevel@tonic-gate } else if (errno == ENOTDIR && hflag) { 5476*0Sstevel@tonic-gate if (!lstat(namep, &xtractbuf)) { 5477*0Sstevel@tonic-gate if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) { 5478*0Sstevel@tonic-gate (void) unlinkat(fd, namep, 0); 5479*0Sstevel@tonic-gate } else if ((n = readlink(namep, buf, 5480*0Sstevel@tonic-gate PATH_MAX)) != -1) { 5481*0Sstevel@tonic-gate buf[n] = (char)NULL; 5482*0Sstevel@tonic-gate (void) unlinkat(fd, buf, 5483*0Sstevel@tonic-gate AT_REMOVEDIR); 5484*0Sstevel@tonic-gate if (errno == ENOTDIR) 5485*0Sstevel@tonic-gate (void) unlinkat(fd, buf, 0); 5486*0Sstevel@tonic-gate } else { 5487*0Sstevel@tonic-gate (void) unlinkat(fd, namep, 0); 5488*0Sstevel@tonic-gate } 5489*0Sstevel@tonic-gate } else { 5490*0Sstevel@tonic-gate (void) unlinkat(fd, namep, 0); 5491*0Sstevel@tonic-gate } 5492*0Sstevel@tonic-gate } 5493*0Sstevel@tonic-gate } 5494*0Sstevel@tonic-gate } 5495*0Sstevel@tonic-gate 5496*0Sstevel@tonic-gate 5497*0Sstevel@tonic-gate /* 5498*0Sstevel@tonic-gate * ACL changes: 5499*0Sstevel@tonic-gate * putfile(): 5500*0Sstevel@tonic-gate * Get acl info after stat. Write out ancillary file 5501*0Sstevel@tonic-gate * before the normal file, i.e. directory, regular, FIFO, 5502*0Sstevel@tonic-gate * link, special. If acl count is less than 4, no need to 5503*0Sstevel@tonic-gate * create ancillary file. (i.e. standard permission is in 5504*0Sstevel@tonic-gate * use. 5505*0Sstevel@tonic-gate * doxtract(): 5506*0Sstevel@tonic-gate * Process ancillary file. Read it in and set acl info. 5507*0Sstevel@tonic-gate * watch out for 'o' function modifier. 5508*0Sstevel@tonic-gate * 't' function letter to display table 5509*0Sstevel@tonic-gate */ 5510*0Sstevel@tonic-gate 5511*0Sstevel@tonic-gate /* 5512*0Sstevel@tonic-gate * New functions for ACLs and other security attributes 5513*0Sstevel@tonic-gate */ 5514*0Sstevel@tonic-gate 5515*0Sstevel@tonic-gate /* 5516*0Sstevel@tonic-gate * The function appends the new security attribute info to the end of 5517*0Sstevel@tonic-gate * existing secinfo. 5518*0Sstevel@tonic-gate */ 5519*0Sstevel@tonic-gate int 5520*0Sstevel@tonic-gate append_secattr( 5521*0Sstevel@tonic-gate char **secinfo, /* existing security info */ 5522*0Sstevel@tonic-gate int *secinfo_len, /* length of existing security info */ 5523*0Sstevel@tonic-gate int size, /* new attribute size: unit depends on type */ 5524*0Sstevel@tonic-gate aclent_t *attrp, /* new attribute data pointer */ 5525*0Sstevel@tonic-gate char attr_type) /* new attribute type */ 5526*0Sstevel@tonic-gate { 5527*0Sstevel@tonic-gate char *new_secinfo; 5528*0Sstevel@tonic-gate char *attrtext; 5529*0Sstevel@tonic-gate int newattrsize; 5530*0Sstevel@tonic-gate int oldsize; 5531*0Sstevel@tonic-gate 5532*0Sstevel@tonic-gate /* no need to add */ 5533*0Sstevel@tonic-gate if (attrp == NULL) 5534*0Sstevel@tonic-gate return (0); 5535*0Sstevel@tonic-gate 5536*0Sstevel@tonic-gate switch (attr_type) { 5537*0Sstevel@tonic-gate case UFSD_ACL: 5538*0Sstevel@tonic-gate attrtext = acltotext((aclent_t *)attrp, size); 5539*0Sstevel@tonic-gate if (attrtext == NULL) { 5540*0Sstevel@tonic-gate (void) fprintf(stderr, "acltotext failed\n"); 5541*0Sstevel@tonic-gate return (-1); 5542*0Sstevel@tonic-gate } 5543*0Sstevel@tonic-gate /* header: type + size = 8 */ 5544*0Sstevel@tonic-gate newattrsize = 8 + (int)strlen(attrtext) + 1; 5545*0Sstevel@tonic-gate attr = (struct sec_attr *)malloc(newattrsize); 5546*0Sstevel@tonic-gate if (attr == NULL) { 5547*0Sstevel@tonic-gate (void) fprintf(stderr, "can't allocate memory\n"); 5548*0Sstevel@tonic-gate return (-1); 5549*0Sstevel@tonic-gate } 5550*0Sstevel@tonic-gate attr->attr_type = UFSD_ACL; 5551*0Sstevel@tonic-gate (void) sprintf(attr->attr_len, 5552*0Sstevel@tonic-gate "%06o", size); /* acl entry count */ 5553*0Sstevel@tonic-gate (void) strcpy((char *)&attr->attr_info[0], attrtext); 5554*0Sstevel@tonic-gate free(attrtext); 5555*0Sstevel@tonic-gate break; 5556*0Sstevel@tonic-gate 5557*0Sstevel@tonic-gate /* SunFed's case goes here */ 5558*0Sstevel@tonic-gate 5559*0Sstevel@tonic-gate default: 5560*0Sstevel@tonic-gate (void) fprintf(stderr, "unrecognized attribute type\n"); 5561*0Sstevel@tonic-gate return (-1); 5562*0Sstevel@tonic-gate } 5563*0Sstevel@tonic-gate 5564*0Sstevel@tonic-gate /* old security info + new attr header(8) + new attr */ 5565*0Sstevel@tonic-gate oldsize = *secinfo_len; 5566*0Sstevel@tonic-gate *secinfo_len += newattrsize; 5567*0Sstevel@tonic-gate new_secinfo = (char *)malloc(*secinfo_len); 5568*0Sstevel@tonic-gate if (new_secinfo == NULL) { 5569*0Sstevel@tonic-gate (void) fprintf(stderr, "can't allocate memory\n"); 5570*0Sstevel@tonic-gate *secinfo_len -= newattrsize; 5571*0Sstevel@tonic-gate return (-1); 5572*0Sstevel@tonic-gate } 5573*0Sstevel@tonic-gate 5574*0Sstevel@tonic-gate (void) memcpy(new_secinfo, *secinfo, oldsize); 5575*0Sstevel@tonic-gate (void) memcpy(new_secinfo + oldsize, attr, newattrsize); 5576*0Sstevel@tonic-gate 5577*0Sstevel@tonic-gate free(*secinfo); 5578*0Sstevel@tonic-gate *secinfo = new_secinfo; 5579*0Sstevel@tonic-gate return (0); 5580*0Sstevel@tonic-gate } 5581*0Sstevel@tonic-gate 5582*0Sstevel@tonic-gate /* 5583*0Sstevel@tonic-gate * write_ancillary(): write out an ancillary file. 5584*0Sstevel@tonic-gate * The file has the same header as normal file except the type and size 5585*0Sstevel@tonic-gate * fields. The type is 'A' and size is the sum of all attributes 5586*0Sstevel@tonic-gate * in bytes. 5587*0Sstevel@tonic-gate * The body contains a list of attribute type, size and info. Currently, 5588*0Sstevel@tonic-gate * there is only ACL info. This file is put before the normal file. 5589*0Sstevel@tonic-gate */ 5590*0Sstevel@tonic-gate void 5591*0Sstevel@tonic-gate write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype) 5592*0Sstevel@tonic-gate { 5593*0Sstevel@tonic-gate long blocks; 5594*0Sstevel@tonic-gate int savflag; 5595*0Sstevel@tonic-gate int savsize; 5596*0Sstevel@tonic-gate 5597*0Sstevel@tonic-gate /* Just tranditional permissions or no security attribute info */ 5598*0Sstevel@tonic-gate if (len == 0 || secinfo == NULL) 5599*0Sstevel@tonic-gate return; 5600*0Sstevel@tonic-gate 5601*0Sstevel@tonic-gate /* save flag and size */ 5602*0Sstevel@tonic-gate savflag = (dblockp->dbuf).typeflag; 5603*0Sstevel@tonic-gate (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize); 5604*0Sstevel@tonic-gate 5605*0Sstevel@tonic-gate /* special flag for ancillary file */ 5606*0Sstevel@tonic-gate if (hdrtype == _XATTR_HDRTYPE) 5607*0Sstevel@tonic-gate dblockp->dbuf.typeflag = _XATTR_HDRTYPE; 5608*0Sstevel@tonic-gate else 5609*0Sstevel@tonic-gate dblockp->dbuf.typeflag = 'A'; 5610*0Sstevel@tonic-gate 5611*0Sstevel@tonic-gate /* for pre-2.5 versions of tar, need to make sure */ 5612*0Sstevel@tonic-gate /* the ACL file is readable */ 5613*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo", 5614*0Sstevel@tonic-gate (stbuf.st_mode & POSIXMODES) | 0000200); 5615*0Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.size, "%011o", len); 5616*0Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp)); 5617*0Sstevel@tonic-gate 5618*0Sstevel@tonic-gate /* write out the header */ 5619*0Sstevel@tonic-gate (void) writetbuf((char *)dblockp, 1); 5620*0Sstevel@tonic-gate 5621*0Sstevel@tonic-gate /* write out security info */ 5622*0Sstevel@tonic-gate blocks = TBLOCKS(len); 5623*0Sstevel@tonic-gate (void) writetbuf((char *)secinfo, (int)blocks); 5624*0Sstevel@tonic-gate 5625*0Sstevel@tonic-gate /* restore mode, flag and size */ 5626*0Sstevel@tonic-gate (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES); 5627*0Sstevel@tonic-gate dblockp->dbuf.typeflag = savflag; 5628*0Sstevel@tonic-gate (void) sprintf(dblockp->dbuf.size, "%011o", savsize); 5629*0Sstevel@tonic-gate } 5630*0Sstevel@tonic-gate 5631*0Sstevel@tonic-gate /* 5632*0Sstevel@tonic-gate * Read the data record for extended headers and then the regular header. 5633*0Sstevel@tonic-gate * The data are read into the buffer and then null-terminated. Entries 5634*0Sstevel@tonic-gate * are of the format: 5635*0Sstevel@tonic-gate * "%d %s=%s\n" 5636*0Sstevel@tonic-gate * 5637*0Sstevel@tonic-gate * When an extended header record is found, the extended header must 5638*0Sstevel@tonic-gate * be processed and its values used to override the values in the 5639*0Sstevel@tonic-gate * normal header. The way this is done is to process the extended 5640*0Sstevel@tonic-gate * header data record and set the data values, then call getdir 5641*0Sstevel@tonic-gate * to process the regular header, then then to reconcile the two 5642*0Sstevel@tonic-gate * sets of data. 5643*0Sstevel@tonic-gate */ 5644*0Sstevel@tonic-gate 5645*0Sstevel@tonic-gate static int 5646*0Sstevel@tonic-gate get_xdata(void) 5647*0Sstevel@tonic-gate { 5648*0Sstevel@tonic-gate struct keylist_pair { 5649*0Sstevel@tonic-gate int keynum; 5650*0Sstevel@tonic-gate char *keylist; 5651*0Sstevel@tonic-gate } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor", 5652*0Sstevel@tonic-gate _X_DEVMINOR, "SUN.devminor", 5653*0Sstevel@tonic-gate _X_GID, "gid", 5654*0Sstevel@tonic-gate _X_GNAME, "gname", 5655*0Sstevel@tonic-gate _X_LINKPATH, "linkpath", 5656*0Sstevel@tonic-gate _X_PATH, "path", 5657*0Sstevel@tonic-gate _X_SIZE, "size", 5658*0Sstevel@tonic-gate _X_UID, "uid", 5659*0Sstevel@tonic-gate _X_UNAME, "uname", 5660*0Sstevel@tonic-gate _X_MTIME, "mtime", 5661*0Sstevel@tonic-gate _X_LAST, "NULL" }; 5662*0Sstevel@tonic-gate char *lineloc; 5663*0Sstevel@tonic-gate int length, i; 5664*0Sstevel@tonic-gate char *keyword, *value; 5665*0Sstevel@tonic-gate blkcnt_t nblocks; 5666*0Sstevel@tonic-gate int bufneeded; 5667*0Sstevel@tonic-gate struct stat *sp = &stbuf; 5668*0Sstevel@tonic-gate int errors; 5669*0Sstevel@tonic-gate 5670*0Sstevel@tonic-gate Xtarhdr.x_uid = 0; 5671*0Sstevel@tonic-gate Xtarhdr.x_gid = 0; 5672*0Sstevel@tonic-gate Xtarhdr.x_devmajor = 0; 5673*0Sstevel@tonic-gate Xtarhdr.x_devminor = 0; 5674*0Sstevel@tonic-gate Xtarhdr.x_filesz = 0; 5675*0Sstevel@tonic-gate Xtarhdr.x_uname = NULL; 5676*0Sstevel@tonic-gate Xtarhdr.x_gname = NULL; 5677*0Sstevel@tonic-gate Xtarhdr.x_linkpath = NULL; 5678*0Sstevel@tonic-gate Xtarhdr.x_path = NULL; 5679*0Sstevel@tonic-gate Xtarhdr.x_mtime.tv_sec = 0; 5680*0Sstevel@tonic-gate Xtarhdr.x_mtime.tv_nsec = 0; 5681*0Sstevel@tonic-gate xhdr_count++; 5682*0Sstevel@tonic-gate errors = 0; 5683*0Sstevel@tonic-gate 5684*0Sstevel@tonic-gate nblocks = TBLOCKS(stbuf.st_size); 5685*0Sstevel@tonic-gate bufneeded = nblocks * TBLOCK; 5686*0Sstevel@tonic-gate if (bufneeded >= xrec_size) { 5687*0Sstevel@tonic-gate free(xrec_ptr); 5688*0Sstevel@tonic-gate xrec_size = bufneeded + 1; 5689*0Sstevel@tonic-gate if ((xrec_ptr = malloc(xrec_size)) == NULL) 5690*0Sstevel@tonic-gate fatal(gettext("cannot allocate buffer")); 5691*0Sstevel@tonic-gate } 5692*0Sstevel@tonic-gate 5693*0Sstevel@tonic-gate lineloc = xrec_ptr; 5694*0Sstevel@tonic-gate 5695*0Sstevel@tonic-gate while (nblocks-- > 0) { 5696*0Sstevel@tonic-gate readtape(lineloc); 5697*0Sstevel@tonic-gate lineloc += TBLOCK; 5698*0Sstevel@tonic-gate } 5699*0Sstevel@tonic-gate lineloc = xrec_ptr; 5700*0Sstevel@tonic-gate xrec_ptr[stbuf.st_size] = '\0'; 5701*0Sstevel@tonic-gate while (lineloc < xrec_ptr + stbuf.st_size) { 5702*0Sstevel@tonic-gate length = atoi(lineloc); 5703*0Sstevel@tonic-gate *(lineloc + length - 1) = '\0'; 5704*0Sstevel@tonic-gate keyword = strchr(lineloc, ' ') + 1; 5705*0Sstevel@tonic-gate value = strchr(keyword, '=') + 1; 5706*0Sstevel@tonic-gate *(value - 1) = '\0'; 5707*0Sstevel@tonic-gate i = 0; 5708*0Sstevel@tonic-gate lineloc += length; 5709*0Sstevel@tonic-gate while (keylist_pair[i].keynum != (int)_X_LAST) { 5710*0Sstevel@tonic-gate if (strcmp(keyword, keylist_pair[i].keylist) == 0) 5711*0Sstevel@tonic-gate break; 5712*0Sstevel@tonic-gate i++; 5713*0Sstevel@tonic-gate } 5714*0Sstevel@tonic-gate errno = 0; 5715*0Sstevel@tonic-gate switch (keylist_pair[i].keynum) { 5716*0Sstevel@tonic-gate case _X_DEVMAJOR: 5717*0Sstevel@tonic-gate Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0); 5718*0Sstevel@tonic-gate if (errno) { 5719*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5720*0Sstevel@tonic-gate "tar: Extended header major value error " 5721*0Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5722*0Sstevel@tonic-gate errors++; 5723*0Sstevel@tonic-gate } else 5724*0Sstevel@tonic-gate xhdr_flgs |= _X_DEVMAJOR; 5725*0Sstevel@tonic-gate break; 5726*0Sstevel@tonic-gate case _X_DEVMINOR: 5727*0Sstevel@tonic-gate Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0); 5728*0Sstevel@tonic-gate if (errno) { 5729*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5730*0Sstevel@tonic-gate "tar: Extended header minor value error " 5731*0Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5732*0Sstevel@tonic-gate errors++; 5733*0Sstevel@tonic-gate } else 5734*0Sstevel@tonic-gate xhdr_flgs |= _X_DEVMINOR; 5735*0Sstevel@tonic-gate break; 5736*0Sstevel@tonic-gate case _X_GID: 5737*0Sstevel@tonic-gate xhdr_flgs |= _X_GID; 5738*0Sstevel@tonic-gate Xtarhdr.x_gid = strtol(value, NULL, 0); 5739*0Sstevel@tonic-gate if ((errno) || (Xtarhdr.x_gid > UID_MAX)) { 5740*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5741*0Sstevel@tonic-gate "tar: Extended header gid value error " 5742*0Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5743*0Sstevel@tonic-gate Xtarhdr.x_gid = GID_NOBODY; 5744*0Sstevel@tonic-gate } 5745*0Sstevel@tonic-gate break; 5746*0Sstevel@tonic-gate case _X_GNAME: 5747*0Sstevel@tonic-gate if (utf8_local("gname", &Xtarhdr.x_gname, 5748*0Sstevel@tonic-gate local_gname, value, _POSIX_NAME_MAX) == 0) 5749*0Sstevel@tonic-gate xhdr_flgs |= _X_GNAME; 5750*0Sstevel@tonic-gate break; 5751*0Sstevel@tonic-gate case _X_LINKPATH: 5752*0Sstevel@tonic-gate if (utf8_local("linkpath", &Xtarhdr.x_linkpath, 5753*0Sstevel@tonic-gate local_linkpath, value, PATH_MAX) == 0) 5754*0Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH; 5755*0Sstevel@tonic-gate else 5756*0Sstevel@tonic-gate errors++; 5757*0Sstevel@tonic-gate break; 5758*0Sstevel@tonic-gate case _X_PATH: 5759*0Sstevel@tonic-gate if (utf8_local("path", &Xtarhdr.x_path, 5760*0Sstevel@tonic-gate local_path, value, PATH_MAX) == 0) 5761*0Sstevel@tonic-gate xhdr_flgs |= _X_PATH; 5762*0Sstevel@tonic-gate else 5763*0Sstevel@tonic-gate errors++; 5764*0Sstevel@tonic-gate break; 5765*0Sstevel@tonic-gate case _X_SIZE: 5766*0Sstevel@tonic-gate Xtarhdr.x_filesz = strtoull(value, NULL, 0); 5767*0Sstevel@tonic-gate if (errno) { 5768*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5769*0Sstevel@tonic-gate "tar: Extended header invalid filesize " 5770*0Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5771*0Sstevel@tonic-gate errors++; 5772*0Sstevel@tonic-gate } else 5773*0Sstevel@tonic-gate xhdr_flgs |= _X_SIZE; 5774*0Sstevel@tonic-gate break; 5775*0Sstevel@tonic-gate case _X_UID: 5776*0Sstevel@tonic-gate xhdr_flgs |= _X_UID; 5777*0Sstevel@tonic-gate Xtarhdr.x_uid = strtol(value, NULL, 0); 5778*0Sstevel@tonic-gate if ((errno) || (Xtarhdr.x_uid > UID_MAX)) { 5779*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5780*0Sstevel@tonic-gate "tar: Extended header uid value error " 5781*0Sstevel@tonic-gate "for file # %llu.\n"), xhdr_count); 5782*0Sstevel@tonic-gate Xtarhdr.x_uid = UID_NOBODY; 5783*0Sstevel@tonic-gate } 5784*0Sstevel@tonic-gate break; 5785*0Sstevel@tonic-gate case _X_UNAME: 5786*0Sstevel@tonic-gate if (utf8_local("uname", &Xtarhdr.x_uname, 5787*0Sstevel@tonic-gate local_uname, value, _POSIX_NAME_MAX) == 0) 5788*0Sstevel@tonic-gate xhdr_flgs |= _X_UNAME; 5789*0Sstevel@tonic-gate break; 5790*0Sstevel@tonic-gate case _X_MTIME: 5791*0Sstevel@tonic-gate get_xtime(value, &(Xtarhdr.x_mtime)); 5792*0Sstevel@tonic-gate if (errno) 5793*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5794*0Sstevel@tonic-gate "tar: Extended header modification time " 5795*0Sstevel@tonic-gate "value error for file # %llu.\n"), 5796*0Sstevel@tonic-gate xhdr_count); 5797*0Sstevel@tonic-gate else 5798*0Sstevel@tonic-gate xhdr_flgs |= _X_MTIME; 5799*0Sstevel@tonic-gate break; 5800*0Sstevel@tonic-gate default: 5801*0Sstevel@tonic-gate (void) fprintf(stderr, 5802*0Sstevel@tonic-gate gettext("tar: unrecognized extended" 5803*0Sstevel@tonic-gate " header keyword '%s'. Ignored.\n"), keyword); 5804*0Sstevel@tonic-gate break; 5805*0Sstevel@tonic-gate } 5806*0Sstevel@tonic-gate } 5807*0Sstevel@tonic-gate 5808*0Sstevel@tonic-gate getdir(); /* get regular header */ 5809*0Sstevel@tonic-gate 5810*0Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMAJOR) { 5811*0Sstevel@tonic-gate Gen.g_devmajor = Xtarhdr.x_devmajor; 5812*0Sstevel@tonic-gate } 5813*0Sstevel@tonic-gate if (xhdr_flgs & _X_DEVMINOR) { 5814*0Sstevel@tonic-gate Gen.g_devminor = Xtarhdr.x_devminor; 5815*0Sstevel@tonic-gate } 5816*0Sstevel@tonic-gate if (xhdr_flgs & _X_GID) { 5817*0Sstevel@tonic-gate Gen.g_gid = Xtarhdr.x_gid; 5818*0Sstevel@tonic-gate sp->st_gid = Gen.g_gid; 5819*0Sstevel@tonic-gate } 5820*0Sstevel@tonic-gate if (xhdr_flgs & _X_UID) { 5821*0Sstevel@tonic-gate Gen.g_uid = Xtarhdr.x_uid; 5822*0Sstevel@tonic-gate sp->st_uid = Gen.g_uid; 5823*0Sstevel@tonic-gate } 5824*0Sstevel@tonic-gate if (xhdr_flgs & _X_SIZE) { 5825*0Sstevel@tonic-gate Gen.g_filesz = Xtarhdr.x_filesz; 5826*0Sstevel@tonic-gate sp->st_size = Gen.g_filesz; 5827*0Sstevel@tonic-gate } 5828*0Sstevel@tonic-gate if (xhdr_flgs & _X_MTIME) { 5829*0Sstevel@tonic-gate Gen.g_mtime = Xtarhdr.x_mtime.tv_sec; 5830*0Sstevel@tonic-gate sp->st_mtim.tv_sec = Gen.g_mtime; 5831*0Sstevel@tonic-gate sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec; 5832*0Sstevel@tonic-gate } 5833*0Sstevel@tonic-gate 5834*0Sstevel@tonic-gate if (errors && errflag) 5835*0Sstevel@tonic-gate done(1); 5836*0Sstevel@tonic-gate else 5837*0Sstevel@tonic-gate if (errors) 5838*0Sstevel@tonic-gate Errflg = 1; 5839*0Sstevel@tonic-gate return (errors); 5840*0Sstevel@tonic-gate } 5841*0Sstevel@tonic-gate 5842*0Sstevel@tonic-gate /* 5843*0Sstevel@tonic-gate * gen_num creates a string from a keyword and an usigned long long in the 5844*0Sstevel@tonic-gate * format: %d %s=%s\n 5845*0Sstevel@tonic-gate * This is part of the extended header data record. 5846*0Sstevel@tonic-gate */ 5847*0Sstevel@tonic-gate 5848*0Sstevel@tonic-gate void 5849*0Sstevel@tonic-gate gen_num(const char *keyword, const u_longlong_t number) 5850*0Sstevel@tonic-gate { 5851*0Sstevel@tonic-gate char save_val[ULONGLONG_MAX_DIGITS + 1]; 5852*0Sstevel@tonic-gate int len; 5853*0Sstevel@tonic-gate char *curr_ptr; 5854*0Sstevel@tonic-gate 5855*0Sstevel@tonic-gate (void) sprintf(save_val, "%llu", number); 5856*0Sstevel@tonic-gate /* 5857*0Sstevel@tonic-gate * len = length of entire line, including itself. len will be 5858*0Sstevel@tonic-gate * two digits. So, add the string lengths plus the length of len, 5859*0Sstevel@tonic-gate * plus a blank, an equal sign, and a newline. 5860*0Sstevel@tonic-gate */ 5861*0Sstevel@tonic-gate len = strlen(save_val) + strlen(keyword) + 5; 5862*0Sstevel@tonic-gate if (xrec_offset + len > xrec_size) { 5863*0Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL)) 5864*0Sstevel@tonic-gate fatal(gettext( 5865*0Sstevel@tonic-gate "cannot allocate extended header buffer")); 5866*0Sstevel@tonic-gate xrec_ptr = curr_ptr; 5867*0Sstevel@tonic-gate xrec_size *= 2; 5868*0Sstevel@tonic-gate } 5869*0Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset], 5870*0Sstevel@tonic-gate "%d %s=%s\n", len, keyword, save_val); 5871*0Sstevel@tonic-gate xrec_offset += len; 5872*0Sstevel@tonic-gate } 5873*0Sstevel@tonic-gate 5874*0Sstevel@tonic-gate /* 5875*0Sstevel@tonic-gate * gen_date creates a string from a keyword and a timestruc_t in the 5876*0Sstevel@tonic-gate * format: %d %s=%s\n 5877*0Sstevel@tonic-gate * This is part of the extended header data record. 5878*0Sstevel@tonic-gate * Currently, granularity is only microseconds, so the low-order three digits 5879*0Sstevel@tonic-gate * will be truncated. 5880*0Sstevel@tonic-gate */ 5881*0Sstevel@tonic-gate 5882*0Sstevel@tonic-gate void 5883*0Sstevel@tonic-gate gen_date(const char *keyword, const timestruc_t time_value) 5884*0Sstevel@tonic-gate { 5885*0Sstevel@tonic-gate /* Allow for <seconds>.<nanoseconds>\n */ 5886*0Sstevel@tonic-gate char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2]; 5887*0Sstevel@tonic-gate int len; 5888*0Sstevel@tonic-gate char *curr_ptr; 5889*0Sstevel@tonic-gate 5890*0Sstevel@tonic-gate (void) sprintf(save_val, "%ld", time_value.tv_sec); 5891*0Sstevel@tonic-gate len = strlen(save_val); 5892*0Sstevel@tonic-gate save_val[len] = '.'; 5893*0Sstevel@tonic-gate (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec); 5894*0Sstevel@tonic-gate 5895*0Sstevel@tonic-gate /* 5896*0Sstevel@tonic-gate * len = length of entire line, including itself. len will be 5897*0Sstevel@tonic-gate * two digits. So, add the string lengths plus the length of len, 5898*0Sstevel@tonic-gate * plus a blank, an equal sign, and a newline. 5899*0Sstevel@tonic-gate */ 5900*0Sstevel@tonic-gate len = strlen(save_val) + strlen(keyword) + 5; 5901*0Sstevel@tonic-gate if (xrec_offset + len > xrec_size) { 5902*0Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL)) 5903*0Sstevel@tonic-gate fatal(gettext( 5904*0Sstevel@tonic-gate "cannot allocate extended header buffer")); 5905*0Sstevel@tonic-gate xrec_ptr = curr_ptr; 5906*0Sstevel@tonic-gate xrec_size *= 2; 5907*0Sstevel@tonic-gate } 5908*0Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset], 5909*0Sstevel@tonic-gate "%d %s=%s\n", len, keyword, save_val); 5910*0Sstevel@tonic-gate xrec_offset += len; 5911*0Sstevel@tonic-gate } 5912*0Sstevel@tonic-gate 5913*0Sstevel@tonic-gate /* 5914*0Sstevel@tonic-gate * gen_string creates a string from a keyword and a char * in the 5915*0Sstevel@tonic-gate * format: %d %s=%s\n 5916*0Sstevel@tonic-gate * This is part of the extended header data record. 5917*0Sstevel@tonic-gate */ 5918*0Sstevel@tonic-gate 5919*0Sstevel@tonic-gate void 5920*0Sstevel@tonic-gate gen_string(const char *keyword, const char *value) 5921*0Sstevel@tonic-gate { 5922*0Sstevel@tonic-gate int len; 5923*0Sstevel@tonic-gate char *curr_ptr; 5924*0Sstevel@tonic-gate 5925*0Sstevel@tonic-gate /* 5926*0Sstevel@tonic-gate * len = length of entire line, including itself. The character length 5927*0Sstevel@tonic-gate * of len must be 1-4 characters, because the maximum size of the path 5928*0Sstevel@tonic-gate * or the name is PATH_MAX, which is 1024. So, assume 1 character 5929*0Sstevel@tonic-gate * for len, one for the space, one for the "=", and one for the newline. 5930*0Sstevel@tonic-gate * Then adjust as needed. 5931*0Sstevel@tonic-gate */ 5932*0Sstevel@tonic-gate /* LINTED constant expression */ 5933*0Sstevel@tonic-gate assert(PATH_MAX <= 9996); 5934*0Sstevel@tonic-gate len = strlen(value) + strlen(keyword) + 4; 5935*0Sstevel@tonic-gate if (len > 997) 5936*0Sstevel@tonic-gate len += 3; 5937*0Sstevel@tonic-gate else if (len > 98) 5938*0Sstevel@tonic-gate len += 2; 5939*0Sstevel@tonic-gate else if (len > 9) 5940*0Sstevel@tonic-gate len += 1; 5941*0Sstevel@tonic-gate if (xrec_offset + len > xrec_size) { 5942*0Sstevel@tonic-gate if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL)) 5943*0Sstevel@tonic-gate fatal(gettext( 5944*0Sstevel@tonic-gate "cannot allocate extended header buffer")); 5945*0Sstevel@tonic-gate xrec_ptr = curr_ptr; 5946*0Sstevel@tonic-gate xrec_size *= 2; 5947*0Sstevel@tonic-gate } 5948*0Sstevel@tonic-gate #ifdef XHDR_DEBUG 5949*0Sstevel@tonic-gate if (strcmp(keyword+1, "name") != 0) 5950*0Sstevel@tonic-gate #endif 5951*0Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset], 5952*0Sstevel@tonic-gate "%d %s=%s\n", len, keyword, value); 5953*0Sstevel@tonic-gate #ifdef XHDR_DEBUG 5954*0Sstevel@tonic-gate else { 5955*0Sstevel@tonic-gate len += 11; 5956*0Sstevel@tonic-gate (void) sprintf(&xrec_ptr[xrec_offset], 5957*0Sstevel@tonic-gate "%d %s=%snametoolong\n", len, keyword, value); 5958*0Sstevel@tonic-gate } 5959*0Sstevel@tonic-gate #endif 5960*0Sstevel@tonic-gate xrec_offset += len; 5961*0Sstevel@tonic-gate } 5962*0Sstevel@tonic-gate 5963*0Sstevel@tonic-gate /* 5964*0Sstevel@tonic-gate * Convert time found in the extended header data to seconds and nanoseconds. 5965*0Sstevel@tonic-gate */ 5966*0Sstevel@tonic-gate 5967*0Sstevel@tonic-gate void 5968*0Sstevel@tonic-gate get_xtime(char *value, timestruc_t *xtime) 5969*0Sstevel@tonic-gate { 5970*0Sstevel@tonic-gate char nanosec[10]; 5971*0Sstevel@tonic-gate char *period; 5972*0Sstevel@tonic-gate int i; 5973*0Sstevel@tonic-gate 5974*0Sstevel@tonic-gate (void) memset(nanosec, '0', 9); 5975*0Sstevel@tonic-gate nanosec[9] = '\0'; 5976*0Sstevel@tonic-gate 5977*0Sstevel@tonic-gate period = strchr(value, '.'); 5978*0Sstevel@tonic-gate if (period != NULL) 5979*0Sstevel@tonic-gate period[0] = '\0'; 5980*0Sstevel@tonic-gate xtime->tv_sec = strtol(value, NULL, 10); 5981*0Sstevel@tonic-gate if (period == NULL) 5982*0Sstevel@tonic-gate xtime->tv_nsec = 0; 5983*0Sstevel@tonic-gate else { 5984*0Sstevel@tonic-gate i = strlen(period +1); 5985*0Sstevel@tonic-gate (void) strncpy(nanosec, period + 1, min(i, 9)); 5986*0Sstevel@tonic-gate xtime->tv_nsec = strtol(nanosec, NULL, 10); 5987*0Sstevel@tonic-gate } 5988*0Sstevel@tonic-gate } 5989*0Sstevel@tonic-gate 5990*0Sstevel@tonic-gate /* 5991*0Sstevel@tonic-gate * Check linkpath for length. 5992*0Sstevel@tonic-gate * Emit an error message and return 1 if too long. 5993*0Sstevel@tonic-gate */ 5994*0Sstevel@tonic-gate 5995*0Sstevel@tonic-gate int 5996*0Sstevel@tonic-gate chk_path_build( 5997*0Sstevel@tonic-gate char *name, 5998*0Sstevel@tonic-gate char *longname, 5999*0Sstevel@tonic-gate char *linkname, 6000*0Sstevel@tonic-gate char *prefix, 6001*0Sstevel@tonic-gate char type, 6002*0Sstevel@tonic-gate int filetype) 6003*0Sstevel@tonic-gate { 6004*0Sstevel@tonic-gate 6005*0Sstevel@tonic-gate if (strlen(linkname) > (size_t)NAMSIZ) { 6006*0Sstevel@tonic-gate if (Eflag > 0) { 6007*0Sstevel@tonic-gate xhdr_flgs |= _X_LINKPATH; 6008*0Sstevel@tonic-gate Xtarhdr.x_linkpath = linkname; 6009*0Sstevel@tonic-gate } else { 6010*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6011*0Sstevel@tonic-gate "tar: %s: linked to %s\n"), longname, linkname); 6012*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6013*0Sstevel@tonic-gate "tar: %s: linked name too long\n"), linkname); 6014*0Sstevel@tonic-gate if (errflag) 6015*0Sstevel@tonic-gate done(1); 6016*0Sstevel@tonic-gate else 6017*0Sstevel@tonic-gate Errflg = 1; 6018*0Sstevel@tonic-gate return (1); 6019*0Sstevel@tonic-gate } 6020*0Sstevel@tonic-gate } 6021*0Sstevel@tonic-gate if (xhdr_flgs & _X_LINKPATH) 6022*0Sstevel@tonic-gate return (build_dblock(name, tchar, type, 6023*0Sstevel@tonic-gate filetype, &stbuf, stbuf.st_dev, 6024*0Sstevel@tonic-gate prefix)); 6025*0Sstevel@tonic-gate else 6026*0Sstevel@tonic-gate return (build_dblock(name, linkname, type, 6027*0Sstevel@tonic-gate filetype, &stbuf, stbuf.st_dev, prefix)); 6028*0Sstevel@tonic-gate } 6029*0Sstevel@tonic-gate 6030*0Sstevel@tonic-gate /* 6031*0Sstevel@tonic-gate * Convert from UTF-8 to local character set. 6032*0Sstevel@tonic-gate */ 6033*0Sstevel@tonic-gate 6034*0Sstevel@tonic-gate static int 6035*0Sstevel@tonic-gate utf8_local( 6036*0Sstevel@tonic-gate char *option, 6037*0Sstevel@tonic-gate char **Xhdr_ptrptr, 6038*0Sstevel@tonic-gate char *target, 6039*0Sstevel@tonic-gate const char *source, 6040*0Sstevel@tonic-gate int max_val) 6041*0Sstevel@tonic-gate { 6042*0Sstevel@tonic-gate static iconv_t iconv_cd; 6043*0Sstevel@tonic-gate char *nl_target; 6044*0Sstevel@tonic-gate const char *iconv_src; 6045*0Sstevel@tonic-gate char *iconv_trg; 6046*0Sstevel@tonic-gate size_t inlen, 6047*0Sstevel@tonic-gate outlen; 6048*0Sstevel@tonic-gate 6049*0Sstevel@tonic-gate if (charset_type == -1) { /* iconv_open failed in earlier try */ 6050*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6051*0Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"), 6052*0Sstevel@tonic-gate xhdr_count, source); 6053*0Sstevel@tonic-gate return (1); 6054*0Sstevel@tonic-gate } else if (charset_type == 0) { /* iconv_open has not yet been done */ 6055*0Sstevel@tonic-gate nl_target = nl_langinfo(CODESET); 6056*0Sstevel@tonic-gate if (strlen(nl_target) == 0) /* locale using 7-bit codeset */ 6057*0Sstevel@tonic-gate nl_target = "646"; 6058*0Sstevel@tonic-gate if (strcmp(nl_target, "646") == 0) 6059*0Sstevel@tonic-gate charset_type = 1; 6060*0Sstevel@tonic-gate else if (strcmp(nl_target, "UTF-8") == 0) 6061*0Sstevel@tonic-gate charset_type = 3; 6062*0Sstevel@tonic-gate else { 6063*0Sstevel@tonic-gate if (strncmp(nl_target, "ISO", 3) == 0) 6064*0Sstevel@tonic-gate nl_target += 3; 6065*0Sstevel@tonic-gate charset_type = 2; 6066*0Sstevel@tonic-gate errno = 0; 6067*0Sstevel@tonic-gate if ((iconv_cd = iconv_open(nl_target, "UTF-8")) == 6068*0Sstevel@tonic-gate (iconv_t)-1) { 6069*0Sstevel@tonic-gate if (errno == EINVAL) 6070*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6071*0Sstevel@tonic-gate "tar: conversion routines not " 6072*0Sstevel@tonic-gate "available for current locale. ")); 6073*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6074*0Sstevel@tonic-gate "file # %llu: (%s) UTF-8 conversion" 6075*0Sstevel@tonic-gate " failed.\n"), xhdr_count, source); 6076*0Sstevel@tonic-gate charset_type = -1; 6077*0Sstevel@tonic-gate return (1); 6078*0Sstevel@tonic-gate } 6079*0Sstevel@tonic-gate } 6080*0Sstevel@tonic-gate } 6081*0Sstevel@tonic-gate 6082*0Sstevel@tonic-gate /* locale using 7-bit codeset or UTF-8 locale */ 6083*0Sstevel@tonic-gate if (charset_type == 1 || charset_type == 3) { 6084*0Sstevel@tonic-gate if (strlen(source) > max_val) { 6085*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6086*0Sstevel@tonic-gate "tar: file # %llu: Extended header %s too long.\n"), 6087*0Sstevel@tonic-gate xhdr_count, option); 6088*0Sstevel@tonic-gate return (1); 6089*0Sstevel@tonic-gate } 6090*0Sstevel@tonic-gate if (charset_type == 3) 6091*0Sstevel@tonic-gate (void) strcpy(target, source); 6092*0Sstevel@tonic-gate else if (c_utf8(target, source) != 0) { 6093*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6094*0Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion" 6095*0Sstevel@tonic-gate " failed.\n"), xhdr_count, source); 6096*0Sstevel@tonic-gate return (1); 6097*0Sstevel@tonic-gate } 6098*0Sstevel@tonic-gate *Xhdr_ptrptr = target; 6099*0Sstevel@tonic-gate return (0); 6100*0Sstevel@tonic-gate } 6101*0Sstevel@tonic-gate 6102*0Sstevel@tonic-gate iconv_src = source; 6103*0Sstevel@tonic-gate iconv_trg = target; 6104*0Sstevel@tonic-gate inlen = strlen(source); 6105*0Sstevel@tonic-gate outlen = max_val * UTF_8_FACTOR; 6106*0Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) == 6107*0Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */ 6108*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6109*0Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"), 6110*0Sstevel@tonic-gate xhdr_count, source); 6111*0Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */ 6112*0Sstevel@tonic-gate iconv_src = (const char *)NULL; 6113*0Sstevel@tonic-gate inlen = 0; 6114*0Sstevel@tonic-gate (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen); 6115*0Sstevel@tonic-gate return (1); 6116*0Sstevel@tonic-gate } 6117*0Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */ 6118*0Sstevel@tonic-gate iconv_src = (const char *)NULL; 6119*0Sstevel@tonic-gate inlen = 0; 6120*0Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) == 6121*0Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */ 6122*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6123*0Sstevel@tonic-gate "tar: file # %llu: (%s) UTF-8 conversion failed.\n"), 6124*0Sstevel@tonic-gate xhdr_count, source); 6125*0Sstevel@tonic-gate return (1); 6126*0Sstevel@tonic-gate } 6127*0Sstevel@tonic-gate 6128*0Sstevel@tonic-gate *iconv_trg = '\0'; /* Null-terminate iconv output string */ 6129*0Sstevel@tonic-gate if (strlen(target) > max_val) { 6130*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6131*0Sstevel@tonic-gate "tar: file # %llu: Extended header %s too long.\n"), 6132*0Sstevel@tonic-gate xhdr_count, option); 6133*0Sstevel@tonic-gate return (1); 6134*0Sstevel@tonic-gate } 6135*0Sstevel@tonic-gate *Xhdr_ptrptr = target; 6136*0Sstevel@tonic-gate return (0); 6137*0Sstevel@tonic-gate } 6138*0Sstevel@tonic-gate 6139*0Sstevel@tonic-gate /* 6140*0Sstevel@tonic-gate * Check gname, uname, path, and linkpath to see if they need to go in an 6141*0Sstevel@tonic-gate * extended header. If they are already slated to be in an extended header, 6142*0Sstevel@tonic-gate * or if they are not ascii, then they need to be in the extended header. 6143*0Sstevel@tonic-gate * Then, convert all extended names to UTF-8. 6144*0Sstevel@tonic-gate */ 6145*0Sstevel@tonic-gate 6146*0Sstevel@tonic-gate int 6147*0Sstevel@tonic-gate gen_utf8_names(const char *filename) 6148*0Sstevel@tonic-gate { 6149*0Sstevel@tonic-gate static iconv_t iconv_cd; 6150*0Sstevel@tonic-gate char *nl_target; 6151*0Sstevel@tonic-gate char tempbuf[MAXNAM + 1]; 6152*0Sstevel@tonic-gate int nbytes, 6153*0Sstevel@tonic-gate errors; 6154*0Sstevel@tonic-gate 6155*0Sstevel@tonic-gate if (charset_type == -1) { /* Previous failure to open. */ 6156*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6157*0Sstevel@tonic-gate "tar: file # %llu: UTF-8 conversion failed.\n"), 6158*0Sstevel@tonic-gate xhdr_count); 6159*0Sstevel@tonic-gate return (1); 6160*0Sstevel@tonic-gate } 6161*0Sstevel@tonic-gate 6162*0Sstevel@tonic-gate if (charset_type == 0) { /* Need to get conversion descriptor */ 6163*0Sstevel@tonic-gate nl_target = nl_langinfo(CODESET); 6164*0Sstevel@tonic-gate if (strlen(nl_target) == 0) /* locale using 7-bit codeset */ 6165*0Sstevel@tonic-gate nl_target = "646"; 6166*0Sstevel@tonic-gate if (strcmp(nl_target, "646") == 0) 6167*0Sstevel@tonic-gate charset_type = 1; 6168*0Sstevel@tonic-gate else if (strcmp(nl_target, "UTF-8") == 0) 6169*0Sstevel@tonic-gate charset_type = 3; 6170*0Sstevel@tonic-gate else { 6171*0Sstevel@tonic-gate if (strncmp(nl_target, "ISO", 3) == 0) 6172*0Sstevel@tonic-gate nl_target += 3; 6173*0Sstevel@tonic-gate charset_type = 2; 6174*0Sstevel@tonic-gate errno = 0; 6175*0Sstevel@tonic-gate #ifdef ICONV_DEBUG 6176*0Sstevel@tonic-gate (void) fprintf(stderr, 6177*0Sstevel@tonic-gate "Opening iconv_cd with target %s\n", 6178*0Sstevel@tonic-gate nl_target); 6179*0Sstevel@tonic-gate #endif 6180*0Sstevel@tonic-gate if ((iconv_cd = iconv_open("UTF-8", nl_target)) == 6181*0Sstevel@tonic-gate (iconv_t)-1) { 6182*0Sstevel@tonic-gate if (errno == EINVAL) 6183*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6184*0Sstevel@tonic-gate "tar: conversion routines not " 6185*0Sstevel@tonic-gate "available for current locale. ")); 6186*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6187*0Sstevel@tonic-gate "file (%s): UTF-8 conversion failed.\n"), 6188*0Sstevel@tonic-gate filename); 6189*0Sstevel@tonic-gate charset_type = -1; 6190*0Sstevel@tonic-gate return (1); 6191*0Sstevel@tonic-gate } 6192*0Sstevel@tonic-gate } 6193*0Sstevel@tonic-gate } 6194*0Sstevel@tonic-gate 6195*0Sstevel@tonic-gate errors = 0; 6196*0Sstevel@tonic-gate 6197*0Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_gname, local_gname, 6198*0Sstevel@tonic-gate dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX); 6199*0Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_uname, local_uname, 6200*0Sstevel@tonic-gate dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX); 6201*0Sstevel@tonic-gate if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */ 6202*0Sstevel@tonic-gate (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ); 6203*0Sstevel@tonic-gate tempbuf[NAMSIZ] = '\0'; 6204*0Sstevel@tonic-gate } 6205*0Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath, 6206*0Sstevel@tonic-gate tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX); 6207*0Sstevel@tonic-gate if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */ 6208*0Sstevel@tonic-gate (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ); 6209*0Sstevel@tonic-gate tempbuf[NAMSIZ] = '\0'; 6210*0Sstevel@tonic-gate nbytes = strlen(tempbuf); 6211*0Sstevel@tonic-gate if (nbytes > 0) { 6212*0Sstevel@tonic-gate tempbuf[nbytes++] = '/'; 6213*0Sstevel@tonic-gate tempbuf[nbytes] = '\0'; 6214*0Sstevel@tonic-gate } 6215*0Sstevel@tonic-gate (void) strncat(tempbuf + nbytes, dblock.dbuf.name, NAMSIZ); 6216*0Sstevel@tonic-gate tempbuf[nbytes + NAMSIZ] = '\0'; 6217*0Sstevel@tonic-gate } 6218*0Sstevel@tonic-gate errors += local_utf8(&Xtarhdr.x_path, local_path, 6219*0Sstevel@tonic-gate tempbuf, iconv_cd, _X_PATH, PATH_MAX); 6220*0Sstevel@tonic-gate 6221*0Sstevel@tonic-gate if (errors > 0) 6222*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6223*0Sstevel@tonic-gate "tar: file (%s): UTF-8 conversion failed.\n"), filename); 6224*0Sstevel@tonic-gate 6225*0Sstevel@tonic-gate if (errors && errflag) 6226*0Sstevel@tonic-gate done(1); 6227*0Sstevel@tonic-gate else 6228*0Sstevel@tonic-gate if (errors) 6229*0Sstevel@tonic-gate Errflg = 1; 6230*0Sstevel@tonic-gate return (errors); 6231*0Sstevel@tonic-gate } 6232*0Sstevel@tonic-gate 6233*0Sstevel@tonic-gate static int 6234*0Sstevel@tonic-gate local_utf8( 6235*0Sstevel@tonic-gate char **Xhdr_ptrptr, 6236*0Sstevel@tonic-gate char *target, 6237*0Sstevel@tonic-gate const char *source, 6238*0Sstevel@tonic-gate iconv_t iconv_cd, 6239*0Sstevel@tonic-gate int xhdrflg, 6240*0Sstevel@tonic-gate int max_val) 6241*0Sstevel@tonic-gate { 6242*0Sstevel@tonic-gate const char *iconv_src; 6243*0Sstevel@tonic-gate const char *starting_src; 6244*0Sstevel@tonic-gate char *iconv_trg; 6245*0Sstevel@tonic-gate size_t inlen, 6246*0Sstevel@tonic-gate outlen; 6247*0Sstevel@tonic-gate #ifdef ICONV_DEBUG 6248*0Sstevel@tonic-gate unsigned char c_to_hex; 6249*0Sstevel@tonic-gate #endif 6250*0Sstevel@tonic-gate 6251*0Sstevel@tonic-gate /* 6252*0Sstevel@tonic-gate * If the item is already slated for extended format, get the string 6253*0Sstevel@tonic-gate * to convert from the extended header record. Otherwise, get it from 6254*0Sstevel@tonic-gate * the regular (dblock) area. 6255*0Sstevel@tonic-gate */ 6256*0Sstevel@tonic-gate if (xhdr_flgs & xhdrflg) { 6257*0Sstevel@tonic-gate if (charset_type == 3) { /* Already UTF-8, just copy */ 6258*0Sstevel@tonic-gate (void) strcpy(target, *Xhdr_ptrptr); 6259*0Sstevel@tonic-gate *Xhdr_ptrptr = target; 6260*0Sstevel@tonic-gate return (0); 6261*0Sstevel@tonic-gate } else 6262*0Sstevel@tonic-gate iconv_src = (const char *) *Xhdr_ptrptr; 6263*0Sstevel@tonic-gate } else { 6264*0Sstevel@tonic-gate if (charset_type == 3) /* Already in UTF-8 format */ 6265*0Sstevel@tonic-gate return (0); /* Don't create xhdr record */ 6266*0Sstevel@tonic-gate iconv_src = source; 6267*0Sstevel@tonic-gate } 6268*0Sstevel@tonic-gate starting_src = iconv_src; 6269*0Sstevel@tonic-gate iconv_trg = target; 6270*0Sstevel@tonic-gate if ((inlen = strlen(iconv_src)) == 0) 6271*0Sstevel@tonic-gate return (0); 6272*0Sstevel@tonic-gate 6273*0Sstevel@tonic-gate if (charset_type == 1) { /* locale using 7-bit codeset */ 6274*0Sstevel@tonic-gate if (c_utf8(target, starting_src) != 0) { 6275*0Sstevel@tonic-gate (void) fprintf(stderr, 6276*0Sstevel@tonic-gate gettext("tar: invalid character in" 6277*0Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src); 6278*0Sstevel@tonic-gate return (1); 6279*0Sstevel@tonic-gate } 6280*0Sstevel@tonic-gate return (0); 6281*0Sstevel@tonic-gate } 6282*0Sstevel@tonic-gate 6283*0Sstevel@tonic-gate outlen = max_val * UTF_8_FACTOR; 6284*0Sstevel@tonic-gate errno = 0; 6285*0Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) == 6286*0Sstevel@tonic-gate (size_t)-1) { 6287*0Sstevel@tonic-gate /* An error occurred, or not all characters were converted */ 6288*0Sstevel@tonic-gate if (errno == EILSEQ) 6289*0Sstevel@tonic-gate (void) fprintf(stderr, 6290*0Sstevel@tonic-gate gettext("tar: invalid character in" 6291*0Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src); 6292*0Sstevel@tonic-gate else 6293*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6294*0Sstevel@tonic-gate "tar: conversion to UTF-8 aborted for '%s'.\n"), 6295*0Sstevel@tonic-gate starting_src); 6296*0Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */ 6297*0Sstevel@tonic-gate iconv_src = (const char *)NULL; 6298*0Sstevel@tonic-gate inlen = 0; 6299*0Sstevel@tonic-gate (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen); 6300*0Sstevel@tonic-gate return (1); 6301*0Sstevel@tonic-gate } 6302*0Sstevel@tonic-gate /* Get remaining output; reinitialize conversion descriptor */ 6303*0Sstevel@tonic-gate iconv_src = (const char *)NULL; 6304*0Sstevel@tonic-gate inlen = 0; 6305*0Sstevel@tonic-gate if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) == 6306*0Sstevel@tonic-gate (size_t)-1) { /* Error occurred: didn't convert */ 6307*0Sstevel@tonic-gate if (errno == EILSEQ) 6308*0Sstevel@tonic-gate (void) fprintf(stderr, 6309*0Sstevel@tonic-gate gettext("tar: invalid character in" 6310*0Sstevel@tonic-gate " UTF-8 conversion of '%s'\n"), starting_src); 6311*0Sstevel@tonic-gate else 6312*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6313*0Sstevel@tonic-gate "tar: conversion to UTF-8 aborted for '%s'.\n"), 6314*0Sstevel@tonic-gate starting_src); 6315*0Sstevel@tonic-gate return (1); 6316*0Sstevel@tonic-gate } 6317*0Sstevel@tonic-gate 6318*0Sstevel@tonic-gate *iconv_trg = '\0'; /* Null-terminate iconv output string */ 6319*0Sstevel@tonic-gate if (strcmp(starting_src, target) != 0) { 6320*0Sstevel@tonic-gate *Xhdr_ptrptr = target; 6321*0Sstevel@tonic-gate xhdr_flgs |= xhdrflg; 6322*0Sstevel@tonic-gate #ifdef ICONV_DEBUG 6323*0Sstevel@tonic-gate (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n", 6324*0Sstevel@tonic-gate strlen(starting_src), inlen, max_val, outlen); 6325*0Sstevel@tonic-gate (void) fprintf(stderr, "Input string:\n "); 6326*0Sstevel@tonic-gate for (inlen = 0; inlen < strlen(starting_src); inlen++) { 6327*0Sstevel@tonic-gate c_to_hex = (unsigned char)starting_src[inlen]; 6328*0Sstevel@tonic-gate (void) fprintf(stderr, " %2.2x", c_to_hex); 6329*0Sstevel@tonic-gate if (inlen % 20 == 19) 6330*0Sstevel@tonic-gate (void) fprintf(stderr, "\n "); 6331*0Sstevel@tonic-gate } 6332*0Sstevel@tonic-gate (void) fprintf(stderr, "\nOutput string:\n "); 6333*0Sstevel@tonic-gate for (inlen = 0; inlen < strlen(target); inlen++) { 6334*0Sstevel@tonic-gate c_to_hex = (unsigned char)target[inlen]; 6335*0Sstevel@tonic-gate (void) fprintf(stderr, " %2.2x", c_to_hex); 6336*0Sstevel@tonic-gate if (inlen % 20 == 19) 6337*0Sstevel@tonic-gate (void) fprintf(stderr, "\n "); 6338*0Sstevel@tonic-gate } 6339*0Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 6340*0Sstevel@tonic-gate #endif 6341*0Sstevel@tonic-gate } 6342*0Sstevel@tonic-gate 6343*0Sstevel@tonic-gate return (0); 6344*0Sstevel@tonic-gate } 6345*0Sstevel@tonic-gate 6346*0Sstevel@tonic-gate /* 6347*0Sstevel@tonic-gate * Function to test each byte of the source string to make sure it is 6348*0Sstevel@tonic-gate * in within bounds (value between 0 and 127). 6349*0Sstevel@tonic-gate * If valid, copy source to target. 6350*0Sstevel@tonic-gate */ 6351*0Sstevel@tonic-gate 6352*0Sstevel@tonic-gate int 6353*0Sstevel@tonic-gate c_utf8(char *target, const char *source) 6354*0Sstevel@tonic-gate { 6355*0Sstevel@tonic-gate size_t len; 6356*0Sstevel@tonic-gate const char *thischar; 6357*0Sstevel@tonic-gate 6358*0Sstevel@tonic-gate len = strlen(source); 6359*0Sstevel@tonic-gate thischar = source; 6360*0Sstevel@tonic-gate while (len-- > 0) { 6361*0Sstevel@tonic-gate if (!isascii((int)(*thischar++))) 6362*0Sstevel@tonic-gate return (1); 6363*0Sstevel@tonic-gate } 6364*0Sstevel@tonic-gate 6365*0Sstevel@tonic-gate (void) strcpy(target, source); 6366*0Sstevel@tonic-gate return (0); 6367*0Sstevel@tonic-gate } 6368*0Sstevel@tonic-gate 6369*0Sstevel@tonic-gate 6370*0Sstevel@tonic-gate #if defined(O_XATTR) 6371*0Sstevel@tonic-gate #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1)) 6372*0Sstevel@tonic-gate 6373*0Sstevel@tonic-gate static void 6374*0Sstevel@tonic-gate prepare_xattr( 6375*0Sstevel@tonic-gate char **attrbuf, 6376*0Sstevel@tonic-gate char *filename, 6377*0Sstevel@tonic-gate char *attrname, 6378*0Sstevel@tonic-gate char typeflag, 6379*0Sstevel@tonic-gate struct linkbuf *linkinfo, 6380*0Sstevel@tonic-gate int *rlen) 6381*0Sstevel@tonic-gate { 6382*0Sstevel@tonic-gate char *bufhead; /* ptr to full buffer */ 6383*0Sstevel@tonic-gate struct xattr_hdr *hptr; /* ptr to header in bufhead */ 6384*0Sstevel@tonic-gate struct xattr_buf *tptr; /* ptr to pathing pieces */ 6385*0Sstevel@tonic-gate int totalen; /* total buffer length */ 6386*0Sstevel@tonic-gate int len; /* length returned to user */ 6387*0Sstevel@tonic-gate int stringlen; /* length of filename + attr */ 6388*0Sstevel@tonic-gate /* 6389*0Sstevel@tonic-gate * length of filename + attr 6390*0Sstevel@tonic-gate * in link section 6391*0Sstevel@tonic-gate */ 6392*0Sstevel@tonic-gate int linkstringlen; 6393*0Sstevel@tonic-gate int complen; /* length of pathing section */ 6394*0Sstevel@tonic-gate int linklen; /* length of link section */ 6395*0Sstevel@tonic-gate 6396*0Sstevel@tonic-gate /* 6397*0Sstevel@tonic-gate * Release previous buffer 6398*0Sstevel@tonic-gate */ 6399*0Sstevel@tonic-gate 6400*0Sstevel@tonic-gate if (*attrbuf != (char *)NULL) { 6401*0Sstevel@tonic-gate free(*attrbuf); 6402*0Sstevel@tonic-gate *attrbuf = NULL; 6403*0Sstevel@tonic-gate } 6404*0Sstevel@tonic-gate 6405*0Sstevel@tonic-gate /* 6406*0Sstevel@tonic-gate * First add in fixed size stuff 6407*0Sstevel@tonic-gate */ 6408*0Sstevel@tonic-gate len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf); 6409*0Sstevel@tonic-gate 6410*0Sstevel@tonic-gate /* 6411*0Sstevel@tonic-gate * Add space for two nulls 6412*0Sstevel@tonic-gate */ 6413*0Sstevel@tonic-gate stringlen = strlen(attrname) + strlen(filename) + 2; 6414*0Sstevel@tonic-gate complen = stringlen + sizeof (struct xattr_buf); 6415*0Sstevel@tonic-gate 6416*0Sstevel@tonic-gate len += stringlen; 6417*0Sstevel@tonic-gate 6418*0Sstevel@tonic-gate /* 6419*0Sstevel@tonic-gate * Now add on space for link info if any 6420*0Sstevel@tonic-gate */ 6421*0Sstevel@tonic-gate 6422*0Sstevel@tonic-gate if (linkinfo != NULL) { 6423*0Sstevel@tonic-gate /* 6424*0Sstevel@tonic-gate * Again add space for two nulls 6425*0Sstevel@tonic-gate */ 6426*0Sstevel@tonic-gate linkstringlen = strlen(linkinfo->pathname) + 6427*0Sstevel@tonic-gate strlen(linkinfo->attrname) + 2; 6428*0Sstevel@tonic-gate len += linkstringlen; 6429*0Sstevel@tonic-gate } 6430*0Sstevel@tonic-gate 6431*0Sstevel@tonic-gate /* 6432*0Sstevel@tonic-gate * Now add padding to end to fill out TBLOCK 6433*0Sstevel@tonic-gate * 6434*0Sstevel@tonic-gate * Function returns size of real data and not size + padding. 6435*0Sstevel@tonic-gate */ 6436*0Sstevel@tonic-gate 6437*0Sstevel@tonic-gate totalen = ROUNDTOTBLOCK(len); 6438*0Sstevel@tonic-gate 6439*0Sstevel@tonic-gate if ((bufhead = calloc(1, totalen)) == NULL) { 6440*0Sstevel@tonic-gate fatal(gettext("Out of memory.")); 6441*0Sstevel@tonic-gate } 6442*0Sstevel@tonic-gate 6443*0Sstevel@tonic-gate 6444*0Sstevel@tonic-gate /* 6445*0Sstevel@tonic-gate * Now we can fill in the necessary pieces 6446*0Sstevel@tonic-gate */ 6447*0Sstevel@tonic-gate 6448*0Sstevel@tonic-gate if (linkinfo != (struct linkbuf *)NULL) { 6449*0Sstevel@tonic-gate linklen = linkstringlen + (sizeof (struct xattr_buf)); 6450*0Sstevel@tonic-gate } else { 6451*0Sstevel@tonic-gate linklen = 0; 6452*0Sstevel@tonic-gate } 6453*0Sstevel@tonic-gate 6454*0Sstevel@tonic-gate /* 6455*0Sstevel@tonic-gate * first fill in the fixed header 6456*0Sstevel@tonic-gate */ 6457*0Sstevel@tonic-gate hptr = (struct xattr_hdr *)bufhead; 6458*0Sstevel@tonic-gate (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS); 6459*0Sstevel@tonic-gate (void) sprintf(hptr->h_component_len, "%0*d", 6460*0Sstevel@tonic-gate sizeof (hptr->h_component_len) - 1, complen); 6461*0Sstevel@tonic-gate (void) sprintf(hptr->h_link_component_len, "%0*d", 6462*0Sstevel@tonic-gate sizeof (hptr->h_link_component_len) - 1, linklen); 6463*0Sstevel@tonic-gate (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len); 6464*0Sstevel@tonic-gate 6465*0Sstevel@tonic-gate /* 6466*0Sstevel@tonic-gate * Now fill in the filename + attrnames section 6467*0Sstevel@tonic-gate */ 6468*0Sstevel@tonic-gate 6469*0Sstevel@tonic-gate tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr)); 6470*0Sstevel@tonic-gate (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1, 6471*0Sstevel@tonic-gate stringlen); 6472*0Sstevel@tonic-gate (void) strcpy(tptr->h_names, filename); 6473*0Sstevel@tonic-gate (void) strcpy(&tptr->h_names[strlen(filename) + 1], attrname); 6474*0Sstevel@tonic-gate tptr->h_typeflag = typeflag; 6475*0Sstevel@tonic-gate 6476*0Sstevel@tonic-gate /* 6477*0Sstevel@tonic-gate * Now fill in the optional link section if we have one 6478*0Sstevel@tonic-gate */ 6479*0Sstevel@tonic-gate 6480*0Sstevel@tonic-gate if (linkinfo != (struct linkbuf *)NULL) { 6481*0Sstevel@tonic-gate tptr = (struct xattr_buf *)(bufhead + 6482*0Sstevel@tonic-gate sizeof (struct xattr_hdr) + complen); 6483*0Sstevel@tonic-gate 6484*0Sstevel@tonic-gate (void) sprintf(tptr->h_namesz, "%0*d", 6485*0Sstevel@tonic-gate sizeof (tptr->h_namesz) - 1, linkstringlen); 6486*0Sstevel@tonic-gate (void) strcpy(tptr->h_names, linkinfo->pathname); 6487*0Sstevel@tonic-gate (void) strcpy( 6488*0Sstevel@tonic-gate &tptr->h_names[strlen(linkinfo->pathname) + 1], 6489*0Sstevel@tonic-gate linkinfo->attrname); 6490*0Sstevel@tonic-gate tptr->h_typeflag = typeflag; 6491*0Sstevel@tonic-gate } 6492*0Sstevel@tonic-gate *attrbuf = (char *)bufhead; 6493*0Sstevel@tonic-gate *rlen = len; 6494*0Sstevel@tonic-gate } 6495*0Sstevel@tonic-gate 6496*0Sstevel@tonic-gate #else 6497*0Sstevel@tonic-gate static void 6498*0Sstevel@tonic-gate prepare_xattr( 6499*0Sstevel@tonic-gate char **attrbuf, 6500*0Sstevel@tonic-gate char *filename, 6501*0Sstevel@tonic-gate char *attrname, 6502*0Sstevel@tonic-gate char typeflag, 6503*0Sstevel@tonic-gate struct linkbuf *linkinfo, 6504*0Sstevel@tonic-gate int *rlen) 6505*0Sstevel@tonic-gate { 6506*0Sstevel@tonic-gate *attrbuf = NULL; 6507*0Sstevel@tonic-gate *rlen = 0; 6508*0Sstevel@tonic-gate } 6509*0Sstevel@tonic-gate #endif 6510*0Sstevel@tonic-gate 6511*0Sstevel@tonic-gate int 6512*0Sstevel@tonic-gate getstat(int dirfd, char *longname, char *shortname) 6513*0Sstevel@tonic-gate { 6514*0Sstevel@tonic-gate 6515*0Sstevel@tonic-gate int i, j; 6516*0Sstevel@tonic-gate int printerr; 6517*0Sstevel@tonic-gate int slnkerr; 6518*0Sstevel@tonic-gate struct stat symlnbuf; 6519*0Sstevel@tonic-gate 6520*0Sstevel@tonic-gate if (!hflag) 6521*0Sstevel@tonic-gate i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW); 6522*0Sstevel@tonic-gate else 6523*0Sstevel@tonic-gate i = fstatat(dirfd, shortname, &stbuf, 0); 6524*0Sstevel@tonic-gate 6525*0Sstevel@tonic-gate 6526*0Sstevel@tonic-gate if (i < 0) { 6527*0Sstevel@tonic-gate /* Initialize flag to print error mesg. */ 6528*0Sstevel@tonic-gate printerr = 1; 6529*0Sstevel@tonic-gate /* 6530*0Sstevel@tonic-gate * If stat is done, then need to do lstat 6531*0Sstevel@tonic-gate * to determine whether it's a sym link 6532*0Sstevel@tonic-gate */ 6533*0Sstevel@tonic-gate if (hflag) { 6534*0Sstevel@tonic-gate /* Save returned error */ 6535*0Sstevel@tonic-gate slnkerr = errno; 6536*0Sstevel@tonic-gate 6537*0Sstevel@tonic-gate j = fstatat(dirfd, shortname, 6538*0Sstevel@tonic-gate &symlnbuf, AT_SYMLINK_NOFOLLOW); 6539*0Sstevel@tonic-gate /* 6540*0Sstevel@tonic-gate * Suppress error message when file is a symbolic link 6541*0Sstevel@tonic-gate * and function modifier 'l' is off. Exception: when 6542*0Sstevel@tonic-gate * a symlink points to a symlink points to a 6543*0Sstevel@tonic-gate * symlink ... and we get past MAXSYMLINKS. That 6544*0Sstevel@tonic-gate * error will cause a file not to be archived, and 6545*0Sstevel@tonic-gate * needs to be printed. 6546*0Sstevel@tonic-gate */ 6547*0Sstevel@tonic-gate if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) && 6548*0Sstevel@tonic-gate (S_ISLNK(symlnbuf.st_mode))) 6549*0Sstevel@tonic-gate printerr = 0; 6550*0Sstevel@tonic-gate 6551*0Sstevel@tonic-gate /* 6552*0Sstevel@tonic-gate * Restore errno in case the lstat 6553*0Sstevel@tonic-gate * on symbolic link change 6554*0Sstevel@tonic-gate */ 6555*0Sstevel@tonic-gate errno = slnkerr; 6556*0Sstevel@tonic-gate } 6557*0Sstevel@tonic-gate 6558*0Sstevel@tonic-gate if (printerr) { 6559*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6560*0Sstevel@tonic-gate "tar: %s: %s\n"), longname, strerror(errno)); 6561*0Sstevel@tonic-gate Errflg = 1; 6562*0Sstevel@tonic-gate } 6563*0Sstevel@tonic-gate return (1); 6564*0Sstevel@tonic-gate } 6565*0Sstevel@tonic-gate return (0); 6566*0Sstevel@tonic-gate } 6567*0Sstevel@tonic-gate 6568*0Sstevel@tonic-gate #if defined(O_XATTR) 6569*0Sstevel@tonic-gate static void 6570*0Sstevel@tonic-gate xattrs_put(char *longname, char *shortname, char *parent) 6571*0Sstevel@tonic-gate { 6572*0Sstevel@tonic-gate int dirfd; 6573*0Sstevel@tonic-gate DIR *dirp; 6574*0Sstevel@tonic-gate struct dirent *dp; 6575*0Sstevel@tonic-gate 6576*0Sstevel@tonic-gate if (pathconf(shortname, _PC_XATTR_EXISTS) != 1) { 6577*0Sstevel@tonic-gate return; 6578*0Sstevel@tonic-gate } 6579*0Sstevel@tonic-gate 6580*0Sstevel@tonic-gate if ((dirfd = attropen(shortname, ".", O_RDONLY)) < 0) { 6581*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6582*0Sstevel@tonic-gate "tar: unable to open attribute directory for file %s\n"), 6583*0Sstevel@tonic-gate longname); 6584*0Sstevel@tonic-gate return; 6585*0Sstevel@tonic-gate } 6586*0Sstevel@tonic-gate 6587*0Sstevel@tonic-gate if ((dirp = fdopendir(dirfd)) == NULL) { 6588*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6589*0Sstevel@tonic-gate "tar: unable to open dir pointer for file %s\n"), longname); 6590*0Sstevel@tonic-gate return; 6591*0Sstevel@tonic-gate } 6592*0Sstevel@tonic-gate 6593*0Sstevel@tonic-gate while (dp = readdir(dirp)) { 6594*0Sstevel@tonic-gate if (dp->d_name[0] == '.' && dp->d_name[1] == '.' && 6595*0Sstevel@tonic-gate dp->d_name[2] == '\0') 6596*0Sstevel@tonic-gate continue; 6597*0Sstevel@tonic-gate 6598*0Sstevel@tonic-gate if (dp->d_name[0] == '.' && dp->d_name[1] == '\0') 6599*0Sstevel@tonic-gate Hiddendir = 1; 6600*0Sstevel@tonic-gate else 6601*0Sstevel@tonic-gate Hiddendir = 0; 6602*0Sstevel@tonic-gate 6603*0Sstevel@tonic-gate (void) putfile(longname, dp->d_name, parent, 6604*0Sstevel@tonic-gate XATTR_FILE, LEV0, SYMLINK_LEV0); 6605*0Sstevel@tonic-gate 6606*0Sstevel@tonic-gate if (exitflag) 6607*0Sstevel@tonic-gate break; 6608*0Sstevel@tonic-gate } 6609*0Sstevel@tonic-gate 6610*0Sstevel@tonic-gate (void) closedir(dirp); 6611*0Sstevel@tonic-gate } 6612*0Sstevel@tonic-gate #else 6613*0Sstevel@tonic-gate static void 6614*0Sstevel@tonic-gate xattrs_put(char *longname, char *shortname, char *parent) 6615*0Sstevel@tonic-gate { 6616*0Sstevel@tonic-gate } 6617*0Sstevel@tonic-gate #endif /* O_XATTR */ 6618*0Sstevel@tonic-gate 6619*0Sstevel@tonic-gate static int 6620*0Sstevel@tonic-gate put_link(char *name, char *longname, char *component, 6621*0Sstevel@tonic-gate char *prefix, int filetype, char type) 6622*0Sstevel@tonic-gate { 6623*0Sstevel@tonic-gate 6624*0Sstevel@tonic-gate if (stbuf.st_nlink > 1) { 6625*0Sstevel@tonic-gate struct linkbuf *lp; 6626*0Sstevel@tonic-gate int found = 0; 6627*0Sstevel@tonic-gate 6628*0Sstevel@tonic-gate for (lp = ihead; lp != NULL; lp = lp->nextp) 6629*0Sstevel@tonic-gate if (lp->inum == stbuf.st_ino && 6630*0Sstevel@tonic-gate lp->devnum == stbuf.st_dev) { 6631*0Sstevel@tonic-gate found++; 6632*0Sstevel@tonic-gate break; 6633*0Sstevel@tonic-gate } 6634*0Sstevel@tonic-gate if (found) { 6635*0Sstevel@tonic-gate #if defined(O_XATTR) 6636*0Sstevel@tonic-gate if (filetype == XATTR_FILE) 6637*0Sstevel@tonic-gate if (put_xattr_hdr(longname, component, prefix, 6638*0Sstevel@tonic-gate type, filetype, lp)) { 6639*0Sstevel@tonic-gate goto out; 6640*0Sstevel@tonic-gate } 6641*0Sstevel@tonic-gate #endif 6642*0Sstevel@tonic-gate stbuf.st_size = (off_t)0; 6643*0Sstevel@tonic-gate if (filetype != XATTR_FILE) { 6644*0Sstevel@tonic-gate tomodes(&stbuf); 6645*0Sstevel@tonic-gate if (chk_path_build(name, longname, lp->pathname, 6646*0Sstevel@tonic-gate prefix, type, filetype) > 0) { 6647*0Sstevel@tonic-gate goto out; 6648*0Sstevel@tonic-gate } 6649*0Sstevel@tonic-gate } 6650*0Sstevel@tonic-gate 6651*0Sstevel@tonic-gate if (mulvol && tapepos + 1 >= blocklim) 6652*0Sstevel@tonic-gate newvol(); 6653*0Sstevel@tonic-gate (void) writetbuf((char *)&dblock, 1); 6654*0Sstevel@tonic-gate /* 6655*0Sstevel@tonic-gate * write_ancillary() is not needed here. 6656*0Sstevel@tonic-gate * The first link is handled in the following 6657*0Sstevel@tonic-gate * else statement. No need to process ACLs 6658*0Sstevel@tonic-gate * for other hard links since they are the 6659*0Sstevel@tonic-gate * same file. 6660*0Sstevel@tonic-gate */ 6661*0Sstevel@tonic-gate 6662*0Sstevel@tonic-gate if (vflag) { 6663*0Sstevel@tonic-gate #ifdef DEBUG 6664*0Sstevel@tonic-gate if (NotTape) 6665*0Sstevel@tonic-gate DEBUG("seek = %" FMT_blkcnt_t 6666*0Sstevel@tonic-gate "K\t", K(tapepos), 0); 6667*0Sstevel@tonic-gate #endif 6668*0Sstevel@tonic-gate if (filetype == XATTR_FILE) { 6669*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 6670*0Sstevel@tonic-gate "a %s attribute %s link to " 6671*0Sstevel@tonic-gate "attribute %s\n"), 6672*0Sstevel@tonic-gate name, component, lp->attrname); 6673*0Sstevel@tonic-gate } else { 6674*0Sstevel@tonic-gate (void) fprintf(vfile, gettext( 6675*0Sstevel@tonic-gate "a %s link to %s\n"), 6676*0Sstevel@tonic-gate longname, lp->pathname); 6677*0Sstevel@tonic-gate } 6678*0Sstevel@tonic-gate } 6679*0Sstevel@tonic-gate lp->count--; 6680*0Sstevel@tonic-gate return (0); 6681*0Sstevel@tonic-gate } else { 6682*0Sstevel@tonic-gate lp = (struct linkbuf *)getmem(sizeof (*lp)); 6683*0Sstevel@tonic-gate if (lp != (struct linkbuf *)NULL) { 6684*0Sstevel@tonic-gate lp->nextp = ihead; 6685*0Sstevel@tonic-gate ihead = lp; 6686*0Sstevel@tonic-gate lp->inum = stbuf.st_ino; 6687*0Sstevel@tonic-gate lp->devnum = stbuf.st_dev; 6688*0Sstevel@tonic-gate lp->count = stbuf.st_nlink - 1; 6689*0Sstevel@tonic-gate if (filetype == XATTR_FILE) { 6690*0Sstevel@tonic-gate (void) strcpy(lp->pathname, longname); 6691*0Sstevel@tonic-gate (void) strcpy(lp->attrname, component); 6692*0Sstevel@tonic-gate } else { 6693*0Sstevel@tonic-gate (void) strcpy(lp->pathname, longname); 6694*0Sstevel@tonic-gate (void) strcpy(lp->attrname, ""); 6695*0Sstevel@tonic-gate } 6696*0Sstevel@tonic-gate } 6697*0Sstevel@tonic-gate } 6698*0Sstevel@tonic-gate } 6699*0Sstevel@tonic-gate 6700*0Sstevel@tonic-gate out: 6701*0Sstevel@tonic-gate return (1); 6702*0Sstevel@tonic-gate } 6703*0Sstevel@tonic-gate 6704*0Sstevel@tonic-gate static int 6705*0Sstevel@tonic-gate put_extra_attributes(char *longname, char *shortname, char *prefix, 6706*0Sstevel@tonic-gate int filetype, char typeflag) 6707*0Sstevel@tonic-gate { 6708*0Sstevel@tonic-gate int aclcnt; 6709*0Sstevel@tonic-gate static aclent_t *aclp; 6710*0Sstevel@tonic-gate 6711*0Sstevel@tonic-gate if (aclp != (aclent_t *)NULL) { 6712*0Sstevel@tonic-gate free(aclp); 6713*0Sstevel@tonic-gate aclp = NULL; 6714*0Sstevel@tonic-gate } 6715*0Sstevel@tonic-gate #if defined(O_XATTR) 6716*0Sstevel@tonic-gate if (atflag && filetype == XATTR_FILE) { 6717*0Sstevel@tonic-gate if (put_xattr_hdr(longname, shortname, prefix, 6718*0Sstevel@tonic-gate typeflag, filetype, NULL)) { 6719*0Sstevel@tonic-gate return (1); 6720*0Sstevel@tonic-gate } 6721*0Sstevel@tonic-gate } 6722*0Sstevel@tonic-gate #endif 6723*0Sstevel@tonic-gate 6724*0Sstevel@tonic-gate /* ACL support */ 6725*0Sstevel@tonic-gate if (pflag) { 6726*0Sstevel@tonic-gate char *secinfo = NULL; 6727*0Sstevel@tonic-gate int len = 0; 6728*0Sstevel@tonic-gate 6729*0Sstevel@tonic-gate /* ACL support */ 6730*0Sstevel@tonic-gate if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) { 6731*0Sstevel@tonic-gate /* 6732*0Sstevel@tonic-gate * Get ACL info: dont bother allocating space if 6733*0Sstevel@tonic-gate * there are only standard permissions, i.e. ACL 6734*0Sstevel@tonic-gate * count <= 4 6735*0Sstevel@tonic-gate */ 6736*0Sstevel@tonic-gate if ((aclcnt = acl(shortname, GETACLCNT, 0, NULL)) < 0) { 6737*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6738*0Sstevel@tonic-gate "%s: failed to get acl count\n"), longname); 6739*0Sstevel@tonic-gate return (1); 6740*0Sstevel@tonic-gate } 6741*0Sstevel@tonic-gate if (aclcnt > MIN_ACL_ENTRIES) { 6742*0Sstevel@tonic-gate if ((aclp = (aclent_t *)malloc( 6743*0Sstevel@tonic-gate sizeof (aclent_t) * aclcnt)) == NULL) { 6744*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6745*0Sstevel@tonic-gate "Insufficient memory\n")); 6746*0Sstevel@tonic-gate return (1); 6747*0Sstevel@tonic-gate } 6748*0Sstevel@tonic-gate if (acl(shortname, GETACL, aclcnt, aclp) < 0) { 6749*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6750*0Sstevel@tonic-gate "%s: failed to get acl entries\n"), 6751*0Sstevel@tonic-gate longname); 6752*0Sstevel@tonic-gate return (1); 6753*0Sstevel@tonic-gate } 6754*0Sstevel@tonic-gate } 6755*0Sstevel@tonic-gate } 6756*0Sstevel@tonic-gate 6757*0Sstevel@tonic-gate /* append security attributes if any */ 6758*0Sstevel@tonic-gate if (aclp != (aclent_t *)NULL) { 6759*0Sstevel@tonic-gate (void) append_secattr(&secinfo, &len, aclcnt, 6760*0Sstevel@tonic-gate aclp, UFSD_ACL); 6761*0Sstevel@tonic-gate (void) write_ancillary(&dblock, secinfo, len, ACL_HDR); 6762*0Sstevel@tonic-gate } 6763*0Sstevel@tonic-gate } 6764*0Sstevel@tonic-gate return (0); 6765*0Sstevel@tonic-gate } 6766*0Sstevel@tonic-gate 6767*0Sstevel@tonic-gate #if defined(O_XATTR) 6768*0Sstevel@tonic-gate static int 6769*0Sstevel@tonic-gate put_xattr_hdr(char *longname, char *shortname, char *prefix, 6770*0Sstevel@tonic-gate int typeflag, int filetype, struct linkbuf *lp) 6771*0Sstevel@tonic-gate { 6772*0Sstevel@tonic-gate char *lname = NULL; 6773*0Sstevel@tonic-gate char *sname = NULL; 6774*0Sstevel@tonic-gate int error = 0; 6775*0Sstevel@tonic-gate static char *attrbuf = NULL; 6776*0Sstevel@tonic-gate int attrlen; 6777*0Sstevel@tonic-gate 6778*0Sstevel@tonic-gate lname = malloc(sizeof (char) * strlen("/dev/null") + 1 + 6779*0Sstevel@tonic-gate strlen(shortname) + strlen(".hdr") + 1); 6780*0Sstevel@tonic-gate 6781*0Sstevel@tonic-gate if (lname == NULL) { 6782*0Sstevel@tonic-gate fatal(gettext("Out of Memory.")); 6783*0Sstevel@tonic-gate } 6784*0Sstevel@tonic-gate sname = malloc(sizeof (char) * strlen(shortname) + 6785*0Sstevel@tonic-gate strlen(".hdr")); 6786*0Sstevel@tonic-gate if (sname == NULL) { 6787*0Sstevel@tonic-gate fatal(gettext("Out of Memory.")); 6788*0Sstevel@tonic-gate } 6789*0Sstevel@tonic-gate 6790*0Sstevel@tonic-gate (void) sprintf(sname, "%s.hdr", shortname); 6791*0Sstevel@tonic-gate (void) sprintf(lname, "/dev/null/%s", sname); 6792*0Sstevel@tonic-gate 6793*0Sstevel@tonic-gate if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >= 6794*0Sstevel@tonic-gate sizeof (dblock.dbuf.name)) { 6795*0Sstevel@tonic-gate fatal(gettext( 6796*0Sstevel@tonic-gate "Buffer overflow writing extended attribute file name")); 6797*0Sstevel@tonic-gate } 6798*0Sstevel@tonic-gate 6799*0Sstevel@tonic-gate /* 6800*0Sstevel@tonic-gate * dump extended attr lookup info 6801*0Sstevel@tonic-gate */ 6802*0Sstevel@tonic-gate prepare_xattr(&attrbuf, longname, shortname, typeflag, lp, &attrlen); 6803*0Sstevel@tonic-gate write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE); 6804*0Sstevel@tonic-gate 6805*0Sstevel@tonic-gate (void) sprintf(lname, "/dev/null/%s", shortname); 6806*0Sstevel@tonic-gate (void) strncpy(dblock.dbuf.name, sname, NAMSIZ); 6807*0Sstevel@tonic-gate 6808*0Sstevel@tonic-gate /* 6809*0Sstevel@tonic-gate * Set up filename for attribute 6810*0Sstevel@tonic-gate */ 6811*0Sstevel@tonic-gate 6812*0Sstevel@tonic-gate error = build_dblock(lname, tchar, '0', filetype, 6813*0Sstevel@tonic-gate &stbuf, stbuf.st_dev, prefix); 6814*0Sstevel@tonic-gate free(lname); 6815*0Sstevel@tonic-gate free(sname); 6816*0Sstevel@tonic-gate 6817*0Sstevel@tonic-gate return (error); 6818*0Sstevel@tonic-gate } 6819*0Sstevel@tonic-gate #endif 6820*0Sstevel@tonic-gate 6821*0Sstevel@tonic-gate #if defined(O_XATTR) 6822*0Sstevel@tonic-gate static int 6823*0Sstevel@tonic-gate read_xattr_hdr() 6824*0Sstevel@tonic-gate { 6825*0Sstevel@tonic-gate char buf[TBLOCK]; 6826*0Sstevel@tonic-gate blkcnt_t blocks; 6827*0Sstevel@tonic-gate char *tp; 6828*0Sstevel@tonic-gate off_t bytes; 6829*0Sstevel@tonic-gate int comp_len, link_len; 6830*0Sstevel@tonic-gate int namelen; 6831*0Sstevel@tonic-gate 6832*0Sstevel@tonic-gate 6833*0Sstevel@tonic-gate if (dblock.dbuf.typeflag != _XATTR_HDRTYPE) 6834*0Sstevel@tonic-gate return (1); 6835*0Sstevel@tonic-gate 6836*0Sstevel@tonic-gate bytes = stbuf.st_size; 6837*0Sstevel@tonic-gate if ((xattrhead = calloc(1, (int)bytes)) == NULL) { 6838*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6839*0Sstevel@tonic-gate "Insufficient memory for extended attribute\n")); 6840*0Sstevel@tonic-gate return (1); 6841*0Sstevel@tonic-gate } 6842*0Sstevel@tonic-gate 6843*0Sstevel@tonic-gate tp = (char *)xattrhead; 6844*0Sstevel@tonic-gate blocks = TBLOCKS(bytes); 6845*0Sstevel@tonic-gate while (blocks-- > 0) { 6846*0Sstevel@tonic-gate readtape(buf); 6847*0Sstevel@tonic-gate if (bytes <= TBLOCK) { 6848*0Sstevel@tonic-gate (void) memcpy(tp, buf, (size_t)bytes); 6849*0Sstevel@tonic-gate break; 6850*0Sstevel@tonic-gate } else { 6851*0Sstevel@tonic-gate (void) memcpy(tp, buf, TBLOCK); 6852*0Sstevel@tonic-gate tp += TBLOCK; 6853*0Sstevel@tonic-gate } 6854*0Sstevel@tonic-gate bytes -= TBLOCK; 6855*0Sstevel@tonic-gate } 6856*0Sstevel@tonic-gate 6857*0Sstevel@tonic-gate /* 6858*0Sstevel@tonic-gate * Validate that we can handle header format 6859*0Sstevel@tonic-gate */ 6860*0Sstevel@tonic-gate if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) { 6861*0Sstevel@tonic-gate (void) fprintf(stderr, 6862*0Sstevel@tonic-gate gettext("Unknown extended attribute format encountered\n")); 6863*0Sstevel@tonic-gate (void) fprintf(stderr, 6864*0Sstevel@tonic-gate gettext("Disabling extended attribute parsing\n")); 6865*0Sstevel@tonic-gate xattrbadhead = 1; 6866*0Sstevel@tonic-gate return (0); 6867*0Sstevel@tonic-gate } 6868*0Sstevel@tonic-gate (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len); 6869*0Sstevel@tonic-gate (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len); 6870*0Sstevel@tonic-gate xattrp = (struct xattr_buf *)(((char *)xattrhead) + 6871*0Sstevel@tonic-gate sizeof (struct xattr_hdr)); 6872*0Sstevel@tonic-gate (void) sscanf(xattrp->h_namesz, "%7d", &namelen); 6873*0Sstevel@tonic-gate if (link_len > 0) 6874*0Sstevel@tonic-gate xattr_linkp = (struct xattr_buf *) 6875*0Sstevel@tonic-gate ((int)xattrp + (int)comp_len); 6876*0Sstevel@tonic-gate else 6877*0Sstevel@tonic-gate xattr_linkp = NULL; 6878*0Sstevel@tonic-gate 6879*0Sstevel@tonic-gate xattraname = xattrp->h_names + strlen(xattrp->h_names) + 1; 6880*0Sstevel@tonic-gate if (xattr_linkp) { 6881*0Sstevel@tonic-gate xattr_linkaname = xattr_linkp->h_names + 6882*0Sstevel@tonic-gate strlen(xattr_linkp->h_names) + 1; 6883*0Sstevel@tonic-gate } else { 6884*0Sstevel@tonic-gate xattr_linkaname = NULL; 6885*0Sstevel@tonic-gate } 6886*0Sstevel@tonic-gate return (0); 6887*0Sstevel@tonic-gate } 6888*0Sstevel@tonic-gate #else 6889*0Sstevel@tonic-gate static int 6890*0Sstevel@tonic-gate read_xattr_hdr() 6891*0Sstevel@tonic-gate { 6892*0Sstevel@tonic-gate return (0); 6893*0Sstevel@tonic-gate } 6894*0Sstevel@tonic-gate #endif 6895*0Sstevel@tonic-gate 6896*0Sstevel@tonic-gate /* 6897*0Sstevel@tonic-gate * skip over extra slashes in string. 6898*0Sstevel@tonic-gate * 6899*0Sstevel@tonic-gate * For example: 6900*0Sstevel@tonic-gate * /usr/tmp///// 6901*0Sstevel@tonic-gate * 6902*0Sstevel@tonic-gate * would return pointer at 6903*0Sstevel@tonic-gate * /usr/tmp///// 6904*0Sstevel@tonic-gate * ^ 6905*0Sstevel@tonic-gate */ 6906*0Sstevel@tonic-gate static char * 6907*0Sstevel@tonic-gate skipslashes(char *string, char *start) 6908*0Sstevel@tonic-gate { 6909*0Sstevel@tonic-gate while ((string > start) && *(string - 1) == '/') { 6910*0Sstevel@tonic-gate string--; 6911*0Sstevel@tonic-gate } 6912*0Sstevel@tonic-gate 6913*0Sstevel@tonic-gate return (string); 6914*0Sstevel@tonic-gate } 6915*0Sstevel@tonic-gate 6916*0Sstevel@tonic-gate /* 6917*0Sstevel@tonic-gate * Return the parent directory of a given path. 6918*0Sstevel@tonic-gate * 6919*0Sstevel@tonic-gate * Examples: 6920*0Sstevel@tonic-gate * /usr/tmp return /usr 6921*0Sstevel@tonic-gate * /usr/tmp/file return /usr/tmp 6922*0Sstevel@tonic-gate * / returns . 6923*0Sstevel@tonic-gate * /usr returns / 6924*0Sstevel@tonic-gate * file returns . 6925*0Sstevel@tonic-gate * 6926*0Sstevel@tonic-gate * dir is assumed to be at least as big as path. 6927*0Sstevel@tonic-gate */ 6928*0Sstevel@tonic-gate static void 6929*0Sstevel@tonic-gate get_parent(char *path, char *dir) 6930*0Sstevel@tonic-gate { 6931*0Sstevel@tonic-gate char *s; 6932*0Sstevel@tonic-gate char tmpdir[PATH_MAX + 1]; 6933*0Sstevel@tonic-gate 6934*0Sstevel@tonic-gate if (strlen(path) > PATH_MAX) { 6935*0Sstevel@tonic-gate fatal(gettext("pathname is too long")); 6936*0Sstevel@tonic-gate } 6937*0Sstevel@tonic-gate (void) strcpy(tmpdir, path); 6938*0Sstevel@tonic-gate chop_endslashes(tmpdir); 6939*0Sstevel@tonic-gate 6940*0Sstevel@tonic-gate if ((s = strrchr(tmpdir, '/')) == NULL) { 6941*0Sstevel@tonic-gate (void) strcpy(dir, "."); 6942*0Sstevel@tonic-gate } else { 6943*0Sstevel@tonic-gate s = skipslashes(s, tmpdir); 6944*0Sstevel@tonic-gate *s = '\0'; 6945*0Sstevel@tonic-gate if (s == tmpdir) 6946*0Sstevel@tonic-gate (void) strcpy(dir, "/"); 6947*0Sstevel@tonic-gate else 6948*0Sstevel@tonic-gate (void) strcpy(dir, tmpdir); 6949*0Sstevel@tonic-gate } 6950*0Sstevel@tonic-gate } 6951*0Sstevel@tonic-gate 6952*0Sstevel@tonic-gate #if defined(O_XATTR) 6953*0Sstevel@tonic-gate static char * 6954*0Sstevel@tonic-gate get_component(char *path) 6955*0Sstevel@tonic-gate { 6956*0Sstevel@tonic-gate char *ptr; 6957*0Sstevel@tonic-gate 6958*0Sstevel@tonic-gate ptr = strrchr(path, '/'); 6959*0Sstevel@tonic-gate if (ptr == NULL) { 6960*0Sstevel@tonic-gate return (path); 6961*0Sstevel@tonic-gate } else { 6962*0Sstevel@tonic-gate /* 6963*0Sstevel@tonic-gate * Handle trailing slash 6964*0Sstevel@tonic-gate */ 6965*0Sstevel@tonic-gate if (*(ptr + 1) == '\0') 6966*0Sstevel@tonic-gate return (ptr); 6967*0Sstevel@tonic-gate else 6968*0Sstevel@tonic-gate return (ptr + 1); 6969*0Sstevel@tonic-gate } 6970*0Sstevel@tonic-gate } 6971*0Sstevel@tonic-gate #else 6972*0Sstevel@tonic-gate static char * 6973*0Sstevel@tonic-gate get_component(char *path) 6974*0Sstevel@tonic-gate { 6975*0Sstevel@tonic-gate return (path); 6976*0Sstevel@tonic-gate } 6977*0Sstevel@tonic-gate #endif 6978*0Sstevel@tonic-gate 6979*0Sstevel@tonic-gate static int 6980*0Sstevel@tonic-gate retry_attrdir_open(char *name) 6981*0Sstevel@tonic-gate { 6982*0Sstevel@tonic-gate int dirfd = -1; 6983*0Sstevel@tonic-gate struct timeval times[2]; 6984*0Sstevel@tonic-gate mode_t newmode; 6985*0Sstevel@tonic-gate struct stat parentstat; 6986*0Sstevel@tonic-gate 6987*0Sstevel@tonic-gate /* 6988*0Sstevel@tonic-gate * We couldn't get to attrdir. See if its 6989*0Sstevel@tonic-gate * just a mode problem on the parent file. 6990*0Sstevel@tonic-gate * for example: a mode such as r-xr--r-- 6991*0Sstevel@tonic-gate * won't let us create an attribute dir 6992*0Sstevel@tonic-gate * if it doesn't already exist. 6993*0Sstevel@tonic-gate */ 6994*0Sstevel@tonic-gate 6995*0Sstevel@tonic-gate if (stat(name, &parentstat) == -1) { 6996*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Cannot stat file %s %s\n"), 6997*0Sstevel@tonic-gate name, strerror(errno)); 6998*0Sstevel@tonic-gate return (1); 6999*0Sstevel@tonic-gate } 7000*0Sstevel@tonic-gate newmode = S_IWUSR | parentstat.st_mode; 7001*0Sstevel@tonic-gate if (chmod(name, newmode) == -1) { 7002*0Sstevel@tonic-gate (void) fprintf(stderr, 7003*0Sstevel@tonic-gate gettext("Cannot chmod file %s to %o %s\n"), 7004*0Sstevel@tonic-gate name, newmode, strerror(errno)); 7005*0Sstevel@tonic-gate return (1); 7006*0Sstevel@tonic-gate 7007*0Sstevel@tonic-gate } 7008*0Sstevel@tonic-gate 7009*0Sstevel@tonic-gate dirfd = attropen(name, ".", O_RDONLY); 7010*0Sstevel@tonic-gate if (dirfd == -1) { 7011*0Sstevel@tonic-gate (void) fprintf(stderr, 7012*0Sstevel@tonic-gate gettext("Cannot open attribute directory of" 7013*0Sstevel@tonic-gate " file %s %s\n"), name, strerror(errno)); 7014*0Sstevel@tonic-gate return (1); 7015*0Sstevel@tonic-gate } else { 7016*0Sstevel@tonic-gate 7017*0Sstevel@tonic-gate /* 7018*0Sstevel@tonic-gate * Put mode back to original 7019*0Sstevel@tonic-gate */ 7020*0Sstevel@tonic-gate (void) chmod(name, parentstat.st_mode); 7021*0Sstevel@tonic-gate 7022*0Sstevel@tonic-gate /* 7023*0Sstevel@tonic-gate * Put back time stamps 7024*0Sstevel@tonic-gate */ 7025*0Sstevel@tonic-gate 7026*0Sstevel@tonic-gate times[0].tv_sec = parentstat.st_atime; 7027*0Sstevel@tonic-gate times[0].tv_usec = 0; 7028*0Sstevel@tonic-gate times[1].tv_sec = parentstat.st_mtime; 7029*0Sstevel@tonic-gate times[1].tv_usec = 0; 7030*0Sstevel@tonic-gate (void) utimes(name, times); 7031*0Sstevel@tonic-gate } 7032*0Sstevel@tonic-gate 7033*0Sstevel@tonic-gate return (dirfd); 7034*0Sstevel@tonic-gate } 7035*0Sstevel@tonic-gate 7036*0Sstevel@tonic-gate #if !defined(O_XATTR) 7037*0Sstevel@tonic-gate static int 7038*0Sstevel@tonic-gate openat64(int fd, const char *name, int oflag, mode_t cmode) 7039*0Sstevel@tonic-gate { 7040*0Sstevel@tonic-gate return (open64(name, oflag, cmode)); 7041*0Sstevel@tonic-gate } 7042*0Sstevel@tonic-gate 7043*0Sstevel@tonic-gate static int 7044*0Sstevel@tonic-gate openat(int fd, const char *name, int oflag, mode_t cmode) 7045*0Sstevel@tonic-gate { 7046*0Sstevel@tonic-gate return (open(name, oflag, cmode)); 7047*0Sstevel@tonic-gate } 7048*0Sstevel@tonic-gate 7049*0Sstevel@tonic-gate static int 7050*0Sstevel@tonic-gate fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag) 7051*0Sstevel@tonic-gate { 7052*0Sstevel@tonic-gate if (flag == AT_SYMLINK_NOFOLLOW) 7053*0Sstevel@tonic-gate return (lchown(name, owner, group)); 7054*0Sstevel@tonic-gate else 7055*0Sstevel@tonic-gate return (chown(name, owner, group)); 7056*0Sstevel@tonic-gate } 7057*0Sstevel@tonic-gate 7058*0Sstevel@tonic-gate static int 7059*0Sstevel@tonic-gate renameat(int fromfd, char *old, int tofd, char *new) 7060*0Sstevel@tonic-gate { 7061*0Sstevel@tonic-gate return (rename(old, new)); 7062*0Sstevel@tonic-gate } 7063*0Sstevel@tonic-gate 7064*0Sstevel@tonic-gate static int 7065*0Sstevel@tonic-gate futimesat(int fd, char *path, struct timeval times[2]) 7066*0Sstevel@tonic-gate { 7067*0Sstevel@tonic-gate return (utimes(path, times)); 7068*0Sstevel@tonic-gate } 7069*0Sstevel@tonic-gate 7070*0Sstevel@tonic-gate static int 7071*0Sstevel@tonic-gate unlinkat(int dirfd, char *path, int flag) 7072*0Sstevel@tonic-gate { 7073*0Sstevel@tonic-gate if (flag == AT_REMOVEDIR) 7074*0Sstevel@tonic-gate return (rmdir(path)); 7075*0Sstevel@tonic-gate else 7076*0Sstevel@tonic-gate return (unlink(path)); 7077*0Sstevel@tonic-gate } 7078*0Sstevel@tonic-gate 7079*0Sstevel@tonic-gate static int 7080*0Sstevel@tonic-gate fstatat(int fd, char *path, struct stat *buf, int flag) 7081*0Sstevel@tonic-gate { 7082*0Sstevel@tonic-gate if (flag == AT_SYMLINK_NOFOLLOW) 7083*0Sstevel@tonic-gate return (lstat(path, buf)); 7084*0Sstevel@tonic-gate else 7085*0Sstevel@tonic-gate return (stat(path, buf)); 7086*0Sstevel@tonic-gate } 7087*0Sstevel@tonic-gate 7088*0Sstevel@tonic-gate static int 7089*0Sstevel@tonic-gate attropen(char *file, char *attr, int omode, mode_t cmode) 7090*0Sstevel@tonic-gate { 7091*0Sstevel@tonic-gate errno = ENOTSUP; 7092*0Sstevel@tonic-gate return (-1); 7093*0Sstevel@tonic-gate } 7094*0Sstevel@tonic-gate #endif 7095*0Sstevel@tonic-gate 7096*0Sstevel@tonic-gate static void 7097*0Sstevel@tonic-gate chop_endslashes(char *path) 7098*0Sstevel@tonic-gate { 7099*0Sstevel@tonic-gate char *end, *ptr; 7100*0Sstevel@tonic-gate 7101*0Sstevel@tonic-gate /* 7102*0Sstevel@tonic-gate * Chop of slashes, but not if all we have is slashes 7103*0Sstevel@tonic-gate * for example: //// 7104*0Sstevel@tonic-gate * should make no changes, otherwise it will screw up 7105*0Sstevel@tonic-gate * checkdir 7106*0Sstevel@tonic-gate */ 7107*0Sstevel@tonic-gate end = &path[strlen(path) -1]; 7108*0Sstevel@tonic-gate if (*end == '/' && end != path) { 7109*0Sstevel@tonic-gate ptr = skipslashes(end, path); 7110*0Sstevel@tonic-gate if (ptr != NULL && ptr != path) { 7111*0Sstevel@tonic-gate *ptr = '\0'; 7112*0Sstevel@tonic-gate } 7113*0Sstevel@tonic-gate } 7114*0Sstevel@tonic-gate } 7115