1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 1996-2001 by Sun Microsystems, Inc. 3*0Sstevel@tonic-gate * All rights reserved. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7*0Sstevel@tonic-gate /* All Rights Reserved */ 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gate /* 10*0Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 11*0Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 12*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 13*0Sstevel@tonic-gate */ 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #include "restore.h" 18*0Sstevel@tonic-gate #include <byteorder.h> 19*0Sstevel@tonic-gate #include <stdlib.h> 20*0Sstevel@tonic-gate #include <unistd.h> 21*0Sstevel@tonic-gate #include <utime.h> 22*0Sstevel@tonic-gate 23*0Sstevel@tonic-gate /* 24*0Sstevel@tonic-gate * Symbol table of directories read from tape. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate #define HASHSIZE 1000 27*0Sstevel@tonic-gate #define INOHASH(val) (val % HASHSIZE) 28*0Sstevel@tonic-gate struct inotab { 29*0Sstevel@tonic-gate struct inotab *t_next; 30*0Sstevel@tonic-gate ino_t t_ino; 31*0Sstevel@tonic-gate offset_t t_seekpt; 32*0Sstevel@tonic-gate offset_t t_size; 33*0Sstevel@tonic-gate struct inotab *t_xattr; 34*0Sstevel@tonic-gate }; 35*0Sstevel@tonic-gate static struct inotab *inotab[HASHSIZE]; 36*0Sstevel@tonic-gate static struct inotab *xattrlist = NULL; 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate /* 39*0Sstevel@tonic-gate * Information retained about directories. 40*0Sstevel@tonic-gate */ 41*0Sstevel@tonic-gate static struct modeinfo { 42*0Sstevel@tonic-gate ino_t ino; 43*0Sstevel@tonic-gate time_t timep[2]; 44*0Sstevel@tonic-gate mode_t mode; 45*0Sstevel@tonic-gate uid_t uid; 46*0Sstevel@tonic-gate gid_t gid; 47*0Sstevel@tonic-gate size_t metasize; 48*0Sstevel@tonic-gate } node; 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate /* 51*0Sstevel@tonic-gate * Global variables for this file. 52*0Sstevel@tonic-gate */ 53*0Sstevel@tonic-gate static off64_t g_seekpt; /* some people have a local seekpt */ 54*0Sstevel@tonic-gate static FILE *df, *mf; 55*0Sstevel@tonic-gate static char dirfile[MAXPATHLEN] = "#"; /* No file */ 56*0Sstevel@tonic-gate static char modefile[MAXPATHLEN] = "#"; /* No file */ 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static RST_DIR *dirp; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate #define INIT_TEMPFILE(name, type) \ 61*0Sstevel@tonic-gate if (name[0] == '#') { \ 62*0Sstevel@tonic-gate if (tmpdir == (char *)NULL) /* can't happen; be paranoid */ \ 63*0Sstevel@tonic-gate tmpdir = "/tmp"; \ 64*0Sstevel@tonic-gate (void) snprintf(name, sizeof (name), \ 65*0Sstevel@tonic-gate "%s/rst" type "%ld.XXXXXX", tmpdir, dumpdate); \ 66*0Sstevel@tonic-gate (void) mktemp(name); \ 67*0Sstevel@tonic-gate } 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #define INIT_DIRFILE() INIT_TEMPFILE(dirfile, "dir") 70*0Sstevel@tonic-gate #define INIT_MODEFILE() INIT_TEMPFILE(modefile, "mode") 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* 73*0Sstevel@tonic-gate * Format of old style directories. 74*0Sstevel@tonic-gate */ 75*0Sstevel@tonic-gate #define ODIRSIZ 14 76*0Sstevel@tonic-gate struct odirect { 77*0Sstevel@tonic-gate ushort_t d_ino; 78*0Sstevel@tonic-gate char d_name[ODIRSIZ]; 79*0Sstevel@tonic-gate }; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate #ifdef __STDC__ 82*0Sstevel@tonic-gate static ino_t search(ino_t, char *); 83*0Sstevel@tonic-gate static void putdir(char *, size_t); 84*0Sstevel@tonic-gate static void putent(struct direct *); 85*0Sstevel@tonic-gate static void skipmetadata(FILE *, size_t); 86*0Sstevel@tonic-gate static void flushent(void); 87*0Sstevel@tonic-gate static void dcvt(struct odirect *, struct direct *); 88*0Sstevel@tonic-gate static RST_DIR *rst_initdirfile(char *); 89*0Sstevel@tonic-gate static offset_t rst_telldir(RST_DIR *); 90*0Sstevel@tonic-gate static void rst_seekdir(RST_DIR *, offset_t, offset_t); 91*0Sstevel@tonic-gate static struct inotab *allocinotab(ino_t, struct dinode *, off64_t); 92*0Sstevel@tonic-gate static void nodeflush(void); 93*0Sstevel@tonic-gate static struct inotab *inotablookup(ino_t); 94*0Sstevel@tonic-gate #else 95*0Sstevel@tonic-gate static ino_t search(); 96*0Sstevel@tonic-gate static void putdir(); 97*0Sstevel@tonic-gate static void putent(); 98*0Sstevel@tonic-gate static void skipmetadata(); 99*0Sstevel@tonic-gate static void flushent(); 100*0Sstevel@tonic-gate static void dcvt(); 101*0Sstevel@tonic-gate static RST_DIR *rst_initdirfile(); 102*0Sstevel@tonic-gate static offset_t rst_telldir(); 103*0Sstevel@tonic-gate static void rst_seekdir(); 104*0Sstevel@tonic-gate static struct inotab *allocinotab(); 105*0Sstevel@tonic-gate static void nodeflush(); 106*0Sstevel@tonic-gate static struct inotab *inotablookup(); 107*0Sstevel@tonic-gate #endif 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate /* 110*0Sstevel@tonic-gate * Extract directory contents, building up a directory structure 111*0Sstevel@tonic-gate * on disk for extraction by name. 112*0Sstevel@tonic-gate * If genmode is requested, save mode, owner, and times for all 113*0Sstevel@tonic-gate * directories on the tape. 114*0Sstevel@tonic-gate */ 115*0Sstevel@tonic-gate void 116*0Sstevel@tonic-gate extractdirs(genmode) 117*0Sstevel@tonic-gate int genmode; 118*0Sstevel@tonic-gate { 119*0Sstevel@tonic-gate int ts; 120*0Sstevel@tonic-gate struct dinode *ip; 121*0Sstevel@tonic-gate int saverr; 122*0Sstevel@tonic-gate struct inotab *itp; 123*0Sstevel@tonic-gate struct direct nulldir; 124*0Sstevel@tonic-gate static char dotname[] = "."; /* dirlookup/psearch writes to its arg */ 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate vprintf(stdout, gettext("Extract directories from tape\n")); 127*0Sstevel@tonic-gate INIT_DIRFILE(); 128*0Sstevel@tonic-gate if ((df = safe_fopen(dirfile, "w", 0600)) == (FILE *)NULL) { 129*0Sstevel@tonic-gate saverr = errno; 130*0Sstevel@tonic-gate (void) fprintf(stderr, 131*0Sstevel@tonic-gate gettext("%s: %s - cannot create directory temporary\n"), 132*0Sstevel@tonic-gate progname, dirfile); 133*0Sstevel@tonic-gate errno = saverr; 134*0Sstevel@tonic-gate perror("fopen"); 135*0Sstevel@tonic-gate done(1); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate if (genmode != 0) { 138*0Sstevel@tonic-gate INIT_MODEFILE(); 139*0Sstevel@tonic-gate if ((mf = safe_fopen(modefile, "w", 0600)) == (FILE *)NULL) { 140*0Sstevel@tonic-gate saverr = errno; 141*0Sstevel@tonic-gate (void) fprintf(stderr, 142*0Sstevel@tonic-gate gettext("%s: %s - cannot create modefile \n"), 143*0Sstevel@tonic-gate progname, modefile); 144*0Sstevel@tonic-gate errno = saverr; 145*0Sstevel@tonic-gate perror("fopen"); 146*0Sstevel@tonic-gate done(1); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate nulldir.d_ino = 0; 150*0Sstevel@tonic-gate nulldir.d_namlen = 1; 151*0Sstevel@tonic-gate (void) strcpy(nulldir.d_name, "/"); 152*0Sstevel@tonic-gate /* LINTED DIRSIZ will always fit into a ushort_t */ 153*0Sstevel@tonic-gate nulldir.d_reclen = (ushort_t)DIRSIZ(&nulldir); 154*0Sstevel@tonic-gate /* LINTED sign extension ok in assert */ 155*0Sstevel@tonic-gate assert(DIRSIZ(&nulldir) == (ulong_t)nulldir.d_reclen); 156*0Sstevel@tonic-gate for (;;) { 157*0Sstevel@tonic-gate curfile.name = gettext("<directory file - name unknown>"); 158*0Sstevel@tonic-gate curfile.action = USING; 159*0Sstevel@tonic-gate ip = curfile.dip; 160*0Sstevel@tonic-gate ts = curfile.ts; 161*0Sstevel@tonic-gate if (ts != TS_END && ts != TS_INODE) { 162*0Sstevel@tonic-gate getfile(null, null); 163*0Sstevel@tonic-gate continue; 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate if (ts == TS_INODE && ip == NULL) { 166*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 167*0Sstevel@tonic-gate "%s: extractdirs: Failed internal consistency check, curfile.dip is NULL\n"), 168*0Sstevel@tonic-gate progname); 169*0Sstevel@tonic-gate done(1); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate if ((ts == TS_INODE && (ip->di_mode & IFMT) != IFDIR && 172*0Sstevel@tonic-gate (ip->di_mode & IFMT) != IFATTRDIR) || 173*0Sstevel@tonic-gate (ts == TS_END)) { 174*0Sstevel@tonic-gate (void) fflush(df); 175*0Sstevel@tonic-gate /* XXX Legitimate error, bad complaint string */ 176*0Sstevel@tonic-gate if (ferror(df)) 177*0Sstevel@tonic-gate panic("%s: %s\n", dirfile, strerror(errno)); 178*0Sstevel@tonic-gate (void) fclose(df); 179*0Sstevel@tonic-gate rst_closedir(dirp); 180*0Sstevel@tonic-gate dirp = rst_initdirfile(dirfile); 181*0Sstevel@tonic-gate if (dirp == NULL) 182*0Sstevel@tonic-gate perror("initdirfile"); 183*0Sstevel@tonic-gate if (mf != NULL) { 184*0Sstevel@tonic-gate (void) fflush(mf); 185*0Sstevel@tonic-gate /* XXX Legitimate error, bad complaint string */ 186*0Sstevel@tonic-gate if (ferror(mf)) 187*0Sstevel@tonic-gate panic("%s: %s\n", 188*0Sstevel@tonic-gate modefile, strerror(errno)); 189*0Sstevel@tonic-gate (void) fclose(mf); 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate if (dirlookup(dotname) == 0) { 192*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 193*0Sstevel@tonic-gate "Root directory is not on tape\n")); 194*0Sstevel@tonic-gate done(1); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate return; 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate itp = allocinotab(curfile.ino, ip, g_seekpt); 199*0Sstevel@tonic-gate getfile(putdir, null); 200*0Sstevel@tonic-gate if (mf != NULL) 201*0Sstevel@tonic-gate nodeflush(); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate putent(&nulldir); 204*0Sstevel@tonic-gate flushent(); 205*0Sstevel@tonic-gate itp->t_size = g_seekpt - itp->t_seekpt; 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * skip over all the directories on the tape 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate void 213*0Sstevel@tonic-gate skipdirs() 214*0Sstevel@tonic-gate { 215*0Sstevel@tonic-gate while (curfile.dip != NULL && 216*0Sstevel@tonic-gate ((curfile.dip->di_mode & IFMT) == IFDIR || 217*0Sstevel@tonic-gate (curfile.dip->di_mode & IFMT) == IFATTRDIR)) { 218*0Sstevel@tonic-gate skipfile(); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate /* 223*0Sstevel@tonic-gate * Recursively find names and inumbers of all files in subtree 224*0Sstevel@tonic-gate * pname and pass them off to be processed. 225*0Sstevel@tonic-gate */ 226*0Sstevel@tonic-gate void 227*0Sstevel@tonic-gate treescan(pname, ino, todo) 228*0Sstevel@tonic-gate char *pname; 229*0Sstevel@tonic-gate ino_t ino; 230*0Sstevel@tonic-gate long (*todo)(); 231*0Sstevel@tonic-gate { 232*0Sstevel@tonic-gate struct inotab *itp; 233*0Sstevel@tonic-gate struct direct *dp; 234*0Sstevel@tonic-gate uint_t loclen; 235*0Sstevel@tonic-gate offset_t bpt; 236*0Sstevel@tonic-gate char locname[MAXCOMPLEXLEN]; 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate itp = inotablookup(ino); 239*0Sstevel@tonic-gate if (itp == NULL) { 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * Pname is name of a simple file or an unchanged directory. 242*0Sstevel@tonic-gate */ 243*0Sstevel@tonic-gate (void) (*todo)(pname, ino, LEAF); 244*0Sstevel@tonic-gate return; 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * Pname is a dumped directory name. 248*0Sstevel@tonic-gate */ 249*0Sstevel@tonic-gate if ((*todo)(pname, ino, NODE) == FAIL) 250*0Sstevel@tonic-gate return; 251*0Sstevel@tonic-gate /* 252*0Sstevel@tonic-gate * begin search through the directory 253*0Sstevel@tonic-gate * skipping over "." and ".." 254*0Sstevel@tonic-gate */ 255*0Sstevel@tonic-gate loclen = complexcpy(locname, pname, MAXCOMPLEXLEN); 256*0Sstevel@tonic-gate locname[loclen-1] = '/'; 257*0Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 258*0Sstevel@tonic-gate dp = rst_readdir(dirp); /* "." */ 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate if (dp != NULL && strcmp(dp->d_name, ".") == 0) 261*0Sstevel@tonic-gate dp = rst_readdir(dirp); /* ".." */ 262*0Sstevel@tonic-gate else 263*0Sstevel@tonic-gate (void) fprintf(stderr, 264*0Sstevel@tonic-gate gettext("Warning: `.' missing from directory %s\n"), 265*0Sstevel@tonic-gate pname); 266*0Sstevel@tonic-gate if (dp != NULL && strcmp(dp->d_name, "..") == 0) 267*0Sstevel@tonic-gate dp = rst_readdir(dirp); /* first real entry */ 268*0Sstevel@tonic-gate else 269*0Sstevel@tonic-gate (void) fprintf(stderr, 270*0Sstevel@tonic-gate gettext("Warning: `..' missing from directory %s\n"), 271*0Sstevel@tonic-gate pname); 272*0Sstevel@tonic-gate bpt = rst_telldir(dirp); 273*0Sstevel@tonic-gate /* 274*0Sstevel@tonic-gate * a zero inode signals end of directory 275*0Sstevel@tonic-gate */ 276*0Sstevel@tonic-gate while (dp != NULL && dp->d_ino != 0) { 277*0Sstevel@tonic-gate locname[loclen] = '\0'; 278*0Sstevel@tonic-gate if ((loclen + dp->d_namlen) >= (sizeof (locname) - 2)) { 279*0Sstevel@tonic-gate (void) fprintf(stderr, 280*0Sstevel@tonic-gate gettext( 281*0Sstevel@tonic-gate "%s%s: ignoring name that exceeds %d char\n"), 282*0Sstevel@tonic-gate locname, dp->d_name, MAXCOMPLEXLEN); 283*0Sstevel@tonic-gate } else { 284*0Sstevel@tonic-gate /* Always fits by if() condition */ 285*0Sstevel@tonic-gate (void) strcpy(locname + loclen, dp->d_name); 286*0Sstevel@tonic-gate /* put a double null on string for lookupname() */ 287*0Sstevel@tonic-gate locname[loclen+dp->d_namlen+1] = '\0'; 288*0Sstevel@tonic-gate treescan(locname, dp->d_ino, todo); 289*0Sstevel@tonic-gate rst_seekdir(dirp, bpt, itp->t_seekpt); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate dp = rst_readdir(dirp); 292*0Sstevel@tonic-gate bpt = rst_telldir(dirp); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate if (dp == NULL) 295*0Sstevel@tonic-gate (void) fprintf(stderr, 296*0Sstevel@tonic-gate gettext("corrupted directory: %s.\n"), locname); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate /* 300*0Sstevel@tonic-gate * Scan the directory table looking for extended attribute trees. 301*0Sstevel@tonic-gate * Recursively find names and inumbers in each tree and pass them 302*0Sstevel@tonic-gate * off to be processed. If the always parameter is not set, only 303*0Sstevel@tonic-gate * process the attribute tree if the attribute tree parent is to 304*0Sstevel@tonic-gate * be extracted. 305*0Sstevel@tonic-gate */ 306*0Sstevel@tonic-gate void 307*0Sstevel@tonic-gate attrscan(always, todo) 308*0Sstevel@tonic-gate int always; 309*0Sstevel@tonic-gate long (*todo)(); 310*0Sstevel@tonic-gate { 311*0Sstevel@tonic-gate struct inotab *itp; 312*0Sstevel@tonic-gate struct entry *ep, *parent; 313*0Sstevel@tonic-gate struct direct *dp; 314*0Sstevel@tonic-gate char name[MAXCOMPLEXLEN]; 315*0Sstevel@tonic-gate int len; 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate for (itp = xattrlist; itp != NULL; itp = itp->t_xattr) { 318*0Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 319*0Sstevel@tonic-gate if ((dp = rst_readdir(dirp)) != NULL && /* "." */ 320*0Sstevel@tonic-gate (dp = rst_readdir(dirp)) != NULL && /* ".." */ 321*0Sstevel@tonic-gate strcmp(dp->d_name, "..") == 0) { 322*0Sstevel@tonic-gate if ((parent = lookupino(dp->d_ino)) != NULL) { 323*0Sstevel@tonic-gate if (!always && 324*0Sstevel@tonic-gate (parent->e_flags & (NEW|EXTRACT)) == 0) 325*0Sstevel@tonic-gate continue; 326*0Sstevel@tonic-gate len = complexcpy(name, myname(parent), 327*0Sstevel@tonic-gate MAXCOMPLEXLEN - 3); 328*0Sstevel@tonic-gate name[len] = '.'; 329*0Sstevel@tonic-gate name[len+1] = '\0'; 330*0Sstevel@tonic-gate name[len+2] = '\0'; 331*0Sstevel@tonic-gate inattrspace = 1; 332*0Sstevel@tonic-gate if ((ep = lookupino(itp->t_ino)) == NULL) { 333*0Sstevel@tonic-gate ep = addentry(name, itp->t_ino, 334*0Sstevel@tonic-gate NODE|ROOT); 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate ep->e_flags |= XATTRROOT; 337*0Sstevel@tonic-gate treescan(name, itp->t_ino, todo); 338*0Sstevel@tonic-gate inattrspace = 0; 339*0Sstevel@tonic-gate } else { 340*0Sstevel@tonic-gate (void) fprintf(stderr, 341*0Sstevel@tonic-gate gettext("Warning: orphaned attribute directory\n")); 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate } else { 344*0Sstevel@tonic-gate (void) fprintf(stderr, 345*0Sstevel@tonic-gate gettext("Warning: `..' missing from attribute directory\n")); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate /* 351*0Sstevel@tonic-gate * Search the directory tree rooted at inode ROOTINO 352*0Sstevel@tonic-gate * for the path pointed at by n. Note that n must be 353*0Sstevel@tonic-gate * modifiable, although it is returned in the same 354*0Sstevel@tonic-gate * condition it was given to us in. 355*0Sstevel@tonic-gate */ 356*0Sstevel@tonic-gate ino_t 357*0Sstevel@tonic-gate psearch(n) 358*0Sstevel@tonic-gate char *n; 359*0Sstevel@tonic-gate { 360*0Sstevel@tonic-gate char *cp, *cp1; 361*0Sstevel@tonic-gate ino_t ino; 362*0Sstevel@tonic-gate char c; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate ino = ROOTINO; 365*0Sstevel@tonic-gate if (*(cp = n) == '/') 366*0Sstevel@tonic-gate cp++; 367*0Sstevel@tonic-gate next: 368*0Sstevel@tonic-gate cp1 = cp + 1; 369*0Sstevel@tonic-gate while (*cp1 != '/' && *cp1) 370*0Sstevel@tonic-gate cp1++; 371*0Sstevel@tonic-gate c = *cp1; 372*0Sstevel@tonic-gate *cp1 = 0; 373*0Sstevel@tonic-gate ino = search(ino, cp); 374*0Sstevel@tonic-gate if (ino == 0) { 375*0Sstevel@tonic-gate *cp1 = c; 376*0Sstevel@tonic-gate return (0); 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate *cp1 = c; 379*0Sstevel@tonic-gate if (c == '/') { 380*0Sstevel@tonic-gate cp = cp1+1; 381*0Sstevel@tonic-gate goto next; 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate return (ino); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* 387*0Sstevel@tonic-gate * search the directory inode ino 388*0Sstevel@tonic-gate * looking for entry cp 389*0Sstevel@tonic-gate */ 390*0Sstevel@tonic-gate static ino_t 391*0Sstevel@tonic-gate search(inum, cp) 392*0Sstevel@tonic-gate ino_t inum; 393*0Sstevel@tonic-gate char *cp; 394*0Sstevel@tonic-gate { 395*0Sstevel@tonic-gate struct direct *dp; 396*0Sstevel@tonic-gate struct inotab *itp; 397*0Sstevel@tonic-gate uint_t len; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate itp = inotablookup(inum); 400*0Sstevel@tonic-gate if (itp == NULL) 401*0Sstevel@tonic-gate return (0); 402*0Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 403*0Sstevel@tonic-gate len = strlen(cp); 404*0Sstevel@tonic-gate do { 405*0Sstevel@tonic-gate dp = rst_readdir(dirp); 406*0Sstevel@tonic-gate if (dp == NULL || dp->d_ino == 0) 407*0Sstevel@tonic-gate return (0); 408*0Sstevel@tonic-gate } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0); 409*0Sstevel@tonic-gate return (dp->d_ino); 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate /* 413*0Sstevel@tonic-gate * Put the directory entries in the directory file 414*0Sstevel@tonic-gate */ 415*0Sstevel@tonic-gate static void 416*0Sstevel@tonic-gate putdir(buf, size) 417*0Sstevel@tonic-gate char *buf; 418*0Sstevel@tonic-gate size_t size; 419*0Sstevel@tonic-gate { 420*0Sstevel@tonic-gate struct direct cvtbuf; 421*0Sstevel@tonic-gate struct odirect *odp; 422*0Sstevel@tonic-gate struct odirect *eodp; 423*0Sstevel@tonic-gate struct direct *dp; 424*0Sstevel@tonic-gate size_t loc, i; 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate if (cvtflag) { 427*0Sstevel@tonic-gate /*LINTED [buf is char[] in getfile, size % fs_fsize == 0]*/ 428*0Sstevel@tonic-gate eodp = (struct odirect *)&buf[size]; 429*0Sstevel@tonic-gate /*LINTED [buf is char[] in getfile]*/ 430*0Sstevel@tonic-gate for (odp = (struct odirect *)buf; odp < eodp; odp++) 431*0Sstevel@tonic-gate if (odp->d_ino != 0) { 432*0Sstevel@tonic-gate dcvt(odp, &cvtbuf); 433*0Sstevel@tonic-gate putent(&cvtbuf); 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate } else { 436*0Sstevel@tonic-gate loc = 0; 437*0Sstevel@tonic-gate while (loc < size) { 438*0Sstevel@tonic-gate /*LINTED [buf is char[] in getfile, loc % 4 == 0]*/ 439*0Sstevel@tonic-gate dp = (struct direct *)(buf + loc); 440*0Sstevel@tonic-gate normdirect(byteorder, dp); 441*0Sstevel@tonic-gate i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 442*0Sstevel@tonic-gate if (dp->d_reclen == 0 || (long)dp->d_reclen > i) { 443*0Sstevel@tonic-gate loc += i; 444*0Sstevel@tonic-gate continue; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate loc += dp->d_reclen; 447*0Sstevel@tonic-gate if (dp->d_ino != 0) { 448*0Sstevel@tonic-gate putent(dp); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate /* 455*0Sstevel@tonic-gate * These variables are "local" to the following two functions. 456*0Sstevel@tonic-gate */ 457*0Sstevel@tonic-gate static char dirbuf[DIRBLKSIZ]; 458*0Sstevel@tonic-gate static int32_t dirloc = 0; 459*0Sstevel@tonic-gate static int32_t prev = 0; 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate /* 462*0Sstevel@tonic-gate * add a new directory entry to a file. 463*0Sstevel@tonic-gate */ 464*0Sstevel@tonic-gate static void 465*0Sstevel@tonic-gate putent(dp) 466*0Sstevel@tonic-gate struct direct *dp; 467*0Sstevel@tonic-gate { 468*0Sstevel@tonic-gate /* LINTED DIRSIZ will always fit in a ushort_t */ 469*0Sstevel@tonic-gate dp->d_reclen = (ushort_t)DIRSIZ(dp); 470*0Sstevel@tonic-gate /* LINTED sign extension ok in assert */ 471*0Sstevel@tonic-gate assert(DIRSIZ(dp) == (ulong_t)dp->d_reclen); 472*0Sstevel@tonic-gate if (dirloc + (long)dp->d_reclen > DIRBLKSIZ) { 473*0Sstevel@tonic-gate /*LINTED [prev += dp->d_reclen, prev % 4 == 0]*/ 474*0Sstevel@tonic-gate ((struct direct *)(dirbuf + prev))->d_reclen = 475*0Sstevel@tonic-gate DIRBLKSIZ - prev; 476*0Sstevel@tonic-gate (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 477*0Sstevel@tonic-gate if (ferror(df)) 478*0Sstevel@tonic-gate panic("%s: %s\n", dirfile, strerror(errno)); 479*0Sstevel@tonic-gate dirloc = 0; 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate bcopy((char *)dp, dirbuf + dirloc, (size_t)dp->d_reclen); 482*0Sstevel@tonic-gate prev = dirloc; 483*0Sstevel@tonic-gate dirloc += dp->d_reclen; 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate /* 487*0Sstevel@tonic-gate * flush out a directory that is finished. 488*0Sstevel@tonic-gate */ 489*0Sstevel@tonic-gate static void 490*0Sstevel@tonic-gate #ifdef __STDC__ 491*0Sstevel@tonic-gate flushent(void) 492*0Sstevel@tonic-gate #else 493*0Sstevel@tonic-gate flushent() 494*0Sstevel@tonic-gate #endif 495*0Sstevel@tonic-gate { 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate /* LINTED prev += dp->d_reclen, prev % 4 == 0 */ 498*0Sstevel@tonic-gate ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 499*0Sstevel@tonic-gate (void) fwrite(dirbuf, (size_t)dirloc, 1, df); 500*0Sstevel@tonic-gate if (ferror(df)) 501*0Sstevel@tonic-gate panic("%s: %s\n", dirfile, strerror(errno)); 502*0Sstevel@tonic-gate g_seekpt = ftello64(df); 503*0Sstevel@tonic-gate dirloc = 0; 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate static void 507*0Sstevel@tonic-gate dcvt(odp, ndp) 508*0Sstevel@tonic-gate struct odirect *odp; 509*0Sstevel@tonic-gate struct direct *ndp; 510*0Sstevel@tonic-gate { 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate (void) bzero((char *)ndp, sizeof (*ndp)); 513*0Sstevel@tonic-gate ndp->d_ino = odp->d_ino; 514*0Sstevel@tonic-gate /* Note that odp->d_name may not be null-terminated */ 515*0Sstevel@tonic-gate /* LINTED assertion always true */ 516*0Sstevel@tonic-gate assert(sizeof (ndp->d_name) > sizeof (odp->d_name)); 517*0Sstevel@tonic-gate (void) strncpy(ndp->d_name, odp->d_name, sizeof (odp->d_name)); 518*0Sstevel@tonic-gate ndp->d_name[sizeof (odp->d_name)] = '\0'; 519*0Sstevel@tonic-gate /* LINTED: strlen will fit into d_namlen */ 520*0Sstevel@tonic-gate ndp->d_namlen = strlen(ndp->d_name); 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate /* LINTED sign extension ok in assert */ 523*0Sstevel@tonic-gate assert(DIRSIZ(ndp) == (ulong_t)ndp->d_reclen); 524*0Sstevel@tonic-gate /* LINTED DIRSIZ always fits in ushort_t */ 525*0Sstevel@tonic-gate ndp->d_reclen = (ushort_t)DIRSIZ(ndp); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate /* 529*0Sstevel@tonic-gate * Initialize the directory file 530*0Sstevel@tonic-gate */ 531*0Sstevel@tonic-gate static RST_DIR * 532*0Sstevel@tonic-gate rst_initdirfile(name) 533*0Sstevel@tonic-gate char *name; 534*0Sstevel@tonic-gate { 535*0Sstevel@tonic-gate RST_DIR *dp; 536*0Sstevel@tonic-gate int fd; 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate if ((fd = open(name, O_RDONLY | O_LARGEFILE)) == -1) 539*0Sstevel@tonic-gate return ((RST_DIR *)0); 540*0Sstevel@tonic-gate if ((dp = (RST_DIR *)malloc(sizeof (*dp))) == NULL) { 541*0Sstevel@tonic-gate (void) close(fd); 542*0Sstevel@tonic-gate return ((RST_DIR *)0); 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate dp->dd_fd = fd; 545*0Sstevel@tonic-gate dp->dd_loc = 0; 546*0Sstevel@tonic-gate dp->dd_refcnt = 1; 547*0Sstevel@tonic-gate return (dp); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate /* 551*0Sstevel@tonic-gate * Simulate the opening of a directory 552*0Sstevel@tonic-gate */ 553*0Sstevel@tonic-gate RST_DIR * 554*0Sstevel@tonic-gate rst_opendir(name) 555*0Sstevel@tonic-gate char *name; 556*0Sstevel@tonic-gate { 557*0Sstevel@tonic-gate struct inotab *itp; 558*0Sstevel@tonic-gate ino_t ino; 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate if ((ino = dirlookup(name)) > 0 && 561*0Sstevel@tonic-gate (itp = inotablookup(ino)) != NULL) { 562*0Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 563*0Sstevel@tonic-gate dirp->dd_refcnt++; 564*0Sstevel@tonic-gate return (dirp); 565*0Sstevel@tonic-gate } 566*0Sstevel@tonic-gate return ((RST_DIR *)0); 567*0Sstevel@tonic-gate } 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate /* 570*0Sstevel@tonic-gate * Releases the hidden state created by rst_opendir(). 571*0Sstevel@tonic-gate * Specifically, the dirp it provided to the caller is malloc'd. 572*0Sstevel@tonic-gate */ 573*0Sstevel@tonic-gate void 574*0Sstevel@tonic-gate rst_closedir(cdirp) 575*0Sstevel@tonic-gate RST_DIR *cdirp; 576*0Sstevel@tonic-gate { 577*0Sstevel@tonic-gate if ((cdirp != NULL) && (--(cdirp->dd_refcnt) < 1)) 578*0Sstevel@tonic-gate free(cdirp); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* 582*0Sstevel@tonic-gate * return a pointer into a directory 583*0Sstevel@tonic-gate */ 584*0Sstevel@tonic-gate static offset_t 585*0Sstevel@tonic-gate rst_telldir(tdirp) 586*0Sstevel@tonic-gate RST_DIR *tdirp; 587*0Sstevel@tonic-gate { 588*0Sstevel@tonic-gate offset_t pos = llseek(tdirp->dd_fd, (offset_t)0, SEEK_CUR); 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate if (pos == (offset_t)-1) { 591*0Sstevel@tonic-gate perror("Could not determine position in directory file"); 592*0Sstevel@tonic-gate done(1); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate return ((pos - tdirp->dd_size) + tdirp->dd_loc); 596*0Sstevel@tonic-gate } 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate /* 599*0Sstevel@tonic-gate * Seek to an entry in a directory. 600*0Sstevel@tonic-gate * Only values returned by ``rst_telldir'' should be passed to rst_seekdir. 601*0Sstevel@tonic-gate * This routine handles many directories in a single file. 602*0Sstevel@tonic-gate * It takes the base of the directory in the file, plus 603*0Sstevel@tonic-gate * the desired seek offset into it. 604*0Sstevel@tonic-gate */ 605*0Sstevel@tonic-gate static void 606*0Sstevel@tonic-gate rst_seekdir(sdirp, loc, base) 607*0Sstevel@tonic-gate RST_DIR *sdirp; 608*0Sstevel@tonic-gate offset_t loc, base; 609*0Sstevel@tonic-gate { 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate if (loc == rst_telldir(sdirp)) 612*0Sstevel@tonic-gate return; 613*0Sstevel@tonic-gate loc -= base; 614*0Sstevel@tonic-gate if (loc < 0) 615*0Sstevel@tonic-gate (void) fprintf(stderr, 616*0Sstevel@tonic-gate gettext("bad seek pointer to rst_seekdir %d\n"), loc); 617*0Sstevel@tonic-gate (void) llseek(sdirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); 618*0Sstevel@tonic-gate sdirp->dd_loc = loc & (DIRBLKSIZ - 1); 619*0Sstevel@tonic-gate if (sdirp->dd_loc != 0) 620*0Sstevel@tonic-gate sdirp->dd_size = read(sdirp->dd_fd, sdirp->dd_buf, DIRBLKSIZ); 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate /* 624*0Sstevel@tonic-gate * get next entry in a directory. 625*0Sstevel@tonic-gate */ 626*0Sstevel@tonic-gate struct direct * 627*0Sstevel@tonic-gate rst_readdir(rdirp) 628*0Sstevel@tonic-gate RST_DIR *rdirp; 629*0Sstevel@tonic-gate { 630*0Sstevel@tonic-gate struct direct *dp; 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate for (;;) { 633*0Sstevel@tonic-gate if (rdirp->dd_loc == 0) { 634*0Sstevel@tonic-gate rdirp->dd_size = read(rdirp->dd_fd, rdirp->dd_buf, 635*0Sstevel@tonic-gate DIRBLKSIZ); 636*0Sstevel@tonic-gate if (rdirp->dd_size <= 0) { 637*0Sstevel@tonic-gate dprintf(stderr, 638*0Sstevel@tonic-gate gettext("error reading directory\n")); 639*0Sstevel@tonic-gate return ((struct direct *)0); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate if (rdirp->dd_loc >= rdirp->dd_size) { 643*0Sstevel@tonic-gate rdirp->dd_loc = 0; 644*0Sstevel@tonic-gate continue; 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate /*LINTED [rvalue will be aligned on int boundary]*/ 647*0Sstevel@tonic-gate dp = (struct direct *)(rdirp->dd_buf + rdirp->dd_loc); 648*0Sstevel@tonic-gate if (dp->d_reclen == 0 || 649*0Sstevel@tonic-gate (long)dp->d_reclen > (DIRBLKSIZ + 1 - rdirp->dd_loc)) { 650*0Sstevel@tonic-gate dprintf(stderr, 651*0Sstevel@tonic-gate gettext("corrupted directory: bad reclen %d\n"), 652*0Sstevel@tonic-gate dp->d_reclen); 653*0Sstevel@tonic-gate return ((struct direct *)0); 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate rdirp->dd_loc += dp->d_reclen; 656*0Sstevel@tonic-gate if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) 657*0Sstevel@tonic-gate continue; 658*0Sstevel@tonic-gate if ((ino_t)(dp->d_ino) >= maxino) { 659*0Sstevel@tonic-gate dprintf(stderr, 660*0Sstevel@tonic-gate gettext("corrupted directory: bad inum %lu\n"), 661*0Sstevel@tonic-gate dp->d_ino); 662*0Sstevel@tonic-gate continue; 663*0Sstevel@tonic-gate } 664*0Sstevel@tonic-gate return (dp); 665*0Sstevel@tonic-gate } 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate /* 669*0Sstevel@tonic-gate * Set the mode, owner, and times for all new or changed directories 670*0Sstevel@tonic-gate */ 671*0Sstevel@tonic-gate void 672*0Sstevel@tonic-gate #ifdef __STDC__ 673*0Sstevel@tonic-gate setdirmodes(void) 674*0Sstevel@tonic-gate #else 675*0Sstevel@tonic-gate setdirmodes() 676*0Sstevel@tonic-gate #endif 677*0Sstevel@tonic-gate { 678*0Sstevel@tonic-gate FILE *smf; 679*0Sstevel@tonic-gate struct entry *ep; 680*0Sstevel@tonic-gate char *cp, *metadata = NULL; 681*0Sstevel@tonic-gate size_t metasize = 0; 682*0Sstevel@tonic-gate int override = -1; 683*0Sstevel@tonic-gate int saverr; 684*0Sstevel@tonic-gate static int complained_chown = 0; 685*0Sstevel@tonic-gate static int complained_chmod = 0; 686*0Sstevel@tonic-gate int dfd; 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate vprintf(stdout, gettext("Set directory mode, owner, and times.\n")); 689*0Sstevel@tonic-gate /* XXX if modefile[0] == '#', shouldn't we just bail here? */ 690*0Sstevel@tonic-gate /* XXX why isn't it set already? */ 691*0Sstevel@tonic-gate INIT_MODEFILE(); 692*0Sstevel@tonic-gate smf = fopen64(modefile, "r"); 693*0Sstevel@tonic-gate if (smf == NULL) { 694*0Sstevel@tonic-gate perror("fopen"); 695*0Sstevel@tonic-gate (void) fprintf(stderr, 696*0Sstevel@tonic-gate gettext("cannot open mode file %s\n"), modefile); 697*0Sstevel@tonic-gate (void) fprintf(stderr, 698*0Sstevel@tonic-gate gettext("directory mode, owner, and times not set\n")); 699*0Sstevel@tonic-gate return; 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate clearerr(smf); 702*0Sstevel@tonic-gate for (;;) { 703*0Sstevel@tonic-gate (void) fread((char *)&node, 1, sizeof (node), smf); 704*0Sstevel@tonic-gate if (feof(smf)) 705*0Sstevel@tonic-gate break; 706*0Sstevel@tonic-gate ep = lookupino(node.ino); 707*0Sstevel@tonic-gate if (command == 'i' || command == 'x') { 708*0Sstevel@tonic-gate if (ep == NIL) { 709*0Sstevel@tonic-gate skipmetadata(smf, node.metasize); 710*0Sstevel@tonic-gate continue; 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate if (ep->e_flags & EXISTED) { 713*0Sstevel@tonic-gate if (override < 0) { 714*0Sstevel@tonic-gate if (reply(gettext( 715*0Sstevel@tonic-gate "Directories already exist, set modes anyway")) 716*0Sstevel@tonic-gate == FAIL) 717*0Sstevel@tonic-gate override = 0; 718*0Sstevel@tonic-gate else 719*0Sstevel@tonic-gate override = 1; 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate if (override == 0) { 722*0Sstevel@tonic-gate /* LINTED: result fits into short */ 723*0Sstevel@tonic-gate ep->e_flags &= ~NEW; 724*0Sstevel@tonic-gate skipmetadata(smf, node.metasize); 725*0Sstevel@tonic-gate continue; 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate if (node.ino == ROOTINO && 729*0Sstevel@tonic-gate reply(gettext("set owner/mode for '.'")) == FAIL) { 730*0Sstevel@tonic-gate skipmetadata(smf, node.metasize); 731*0Sstevel@tonic-gate continue; 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate } 734*0Sstevel@tonic-gate if (ep == NIL) { 735*0Sstevel@tonic-gate panic(gettext("cannot find directory inode %d\n"), 736*0Sstevel@tonic-gate node.ino); 737*0Sstevel@tonic-gate skipmetadata(smf, node.metasize); 738*0Sstevel@tonic-gate continue; 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate cp = myname(ep); 741*0Sstevel@tonic-gate resolve(myname(ep), &dfd, &cp); 742*0Sstevel@tonic-gate if (dfd != AT_FDCWD) { 743*0Sstevel@tonic-gate if (fchdir(dfd) < 0) { 744*0Sstevel@tonic-gate saverr = errno; 745*0Sstevel@tonic-gate (void) fprintf(stderr, 746*0Sstevel@tonic-gate gettext("Can not set attribute context: %s\n"), 747*0Sstevel@tonic-gate strerror(saverr)); 748*0Sstevel@tonic-gate (void) close(dfd); 749*0Sstevel@tonic-gate continue; 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate if (chmod(cp, node.mode) < 0 && !complained_chmod) { 753*0Sstevel@tonic-gate saverr = errno; 754*0Sstevel@tonic-gate (void) fprintf(stderr, 755*0Sstevel@tonic-gate gettext("Can not set directory permissions: %s\n"), 756*0Sstevel@tonic-gate strerror(saverr)); 757*0Sstevel@tonic-gate complained_chmod = 1; 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate if (node.metasize != 0) { 760*0Sstevel@tonic-gate if (node.metasize > metasize) 761*0Sstevel@tonic-gate metadata = realloc(metadata, 762*0Sstevel@tonic-gate metasize = node.metasize); 763*0Sstevel@tonic-gate if (metadata == NULL) { 764*0Sstevel@tonic-gate (void) fprintf(stderr, 765*0Sstevel@tonic-gate gettext("Cannot malloc metadata\n")); 766*0Sstevel@tonic-gate done(1); 767*0Sstevel@tonic-gate } 768*0Sstevel@tonic-gate (void) fread(metadata, 1, node.metasize, smf); 769*0Sstevel@tonic-gate metaproc(cp, metadata, node.metasize); 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate /* 773*0Sstevel@tonic-gate * BUG 4302943 774*0Sstevel@tonic-gate * Since the ACLs must be set before fixing the ownership, 775*0Sstevel@tonic-gate * chown should be called only after metaproc 776*0Sstevel@tonic-gate */ 777*0Sstevel@tonic-gate if (chown(cp, node.uid, node.gid) < 0 && !complained_chown) { 778*0Sstevel@tonic-gate saverr = errno; 779*0Sstevel@tonic-gate (void) fprintf(stderr, 780*0Sstevel@tonic-gate gettext("Can not set directory ownership: %s\n"), 781*0Sstevel@tonic-gate strerror(saverr)); 782*0Sstevel@tonic-gate complained_chown = 1; 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate utime(cp, (struct utimbuf *)node.timep); 785*0Sstevel@tonic-gate /* LINTED: result fits into short */ 786*0Sstevel@tonic-gate ep->e_flags &= ~NEW; 787*0Sstevel@tonic-gate if (dfd != AT_FDCWD) { 788*0Sstevel@tonic-gate fchdir(savepwd); 789*0Sstevel@tonic-gate (void) close(dfd); 790*0Sstevel@tonic-gate } 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate if (ferror(smf)) 793*0Sstevel@tonic-gate panic(gettext("error setting directory modes\n")); 794*0Sstevel@tonic-gate if (metadata != NULL) 795*0Sstevel@tonic-gate (void) free(metadata); 796*0Sstevel@tonic-gate (void) fclose(smf); 797*0Sstevel@tonic-gate } 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate void 800*0Sstevel@tonic-gate skipmetadata(f, size) 801*0Sstevel@tonic-gate FILE *f; 802*0Sstevel@tonic-gate size_t size; 803*0Sstevel@tonic-gate { 804*0Sstevel@tonic-gate /* XXX should we bail if this doesn't work? */ 805*0Sstevel@tonic-gate /* LINTED unsigned -> signed conversion ok here */ 806*0Sstevel@tonic-gate (void) fseeko(f, (off_t)size, SEEK_CUR); 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate /* 810*0Sstevel@tonic-gate * Generate a literal copy of a directory. 811*0Sstevel@tonic-gate */ 812*0Sstevel@tonic-gate genliteraldir(name, ino) 813*0Sstevel@tonic-gate char *name; 814*0Sstevel@tonic-gate ino_t ino; 815*0Sstevel@tonic-gate { 816*0Sstevel@tonic-gate struct inotab *itp; 817*0Sstevel@tonic-gate int ofile, dp; 818*0Sstevel@tonic-gate off64_t i; 819*0Sstevel@tonic-gate size_t size; 820*0Sstevel@tonic-gate char buf[BUFSIZ]; 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate itp = inotablookup(ino); 823*0Sstevel@tonic-gate if (itp == NULL) { 824*0Sstevel@tonic-gate (void) fprintf(stderr, 825*0Sstevel@tonic-gate gettext("Cannot find directory inode %d named %s\n"), 826*0Sstevel@tonic-gate ino, name); 827*0Sstevel@tonic-gate return (FAIL); 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate if ((ofile = creat(name, 0666)) < 0) { 830*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", name); 831*0Sstevel@tonic-gate (void) fflush(stderr); 832*0Sstevel@tonic-gate perror(gettext("cannot create file")); 833*0Sstevel@tonic-gate return (FAIL); 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 836*0Sstevel@tonic-gate dp = dup(dirp->dd_fd); 837*0Sstevel@tonic-gate if (dp < 0) { 838*0Sstevel@tonic-gate perror(gettext("dup(2) failed")); 839*0Sstevel@tonic-gate (void) close(ofile); 840*0Sstevel@tonic-gate (void) unlink(name); 841*0Sstevel@tonic-gate return (FAIL); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate for (i = itp->t_size; i != 0; i -= size) { 844*0Sstevel@tonic-gate /* LINTED cast is safe due to comparison */ 845*0Sstevel@tonic-gate size = i < BUFSIZ ? (size_t)i : BUFSIZ; 846*0Sstevel@tonic-gate /* XXX instead of done(), clean up and return FAIL? */ 847*0Sstevel@tonic-gate if (read(dp, buf, size) == -1) { 848*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 849*0Sstevel@tonic-gate "read error extracting inode %d, name %s\n"), 850*0Sstevel@tonic-gate curfile.ino, curfile.name); 851*0Sstevel@tonic-gate perror("read"); 852*0Sstevel@tonic-gate done(1); 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate if (write(ofile, buf, size) == -1) { 855*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 856*0Sstevel@tonic-gate "write error extracting inode %d, name %s\n"), 857*0Sstevel@tonic-gate curfile.ino, curfile.name); 858*0Sstevel@tonic-gate perror("write"); 859*0Sstevel@tonic-gate done(1); 860*0Sstevel@tonic-gate } 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate (void) close(dp); 863*0Sstevel@tonic-gate (void) close(ofile); 864*0Sstevel@tonic-gate return (GOOD); 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate /* 868*0Sstevel@tonic-gate * Determine the type of an inode 869*0Sstevel@tonic-gate */ 870*0Sstevel@tonic-gate inodetype(ino) 871*0Sstevel@tonic-gate ino_t ino; 872*0Sstevel@tonic-gate { 873*0Sstevel@tonic-gate struct inotab *itp; 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate itp = inotablookup(ino); 876*0Sstevel@tonic-gate if (itp == NULL) 877*0Sstevel@tonic-gate return (LEAF); 878*0Sstevel@tonic-gate return (NODE); 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gate /* 882*0Sstevel@tonic-gate * Allocate and initialize a directory inode entry. 883*0Sstevel@tonic-gate * If requested, save its pertinent mode, owner, and time info. 884*0Sstevel@tonic-gate */ 885*0Sstevel@tonic-gate static struct inotab * 886*0Sstevel@tonic-gate allocinotab(ino, dip, seekpt) 887*0Sstevel@tonic-gate ino_t ino; 888*0Sstevel@tonic-gate struct dinode *dip; 889*0Sstevel@tonic-gate off64_t seekpt; 890*0Sstevel@tonic-gate { 891*0Sstevel@tonic-gate struct inotab *itp; 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate itp = (struct inotab *)calloc(1, sizeof (*itp)); 894*0Sstevel@tonic-gate if (itp == 0) { 895*0Sstevel@tonic-gate (void) fprintf(stderr, 896*0Sstevel@tonic-gate gettext("no memory for directory table\n")); 897*0Sstevel@tonic-gate done(1); 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate itp->t_next = inotab[INOHASH(ino)]; 900*0Sstevel@tonic-gate inotab[INOHASH(ino)] = itp; 901*0Sstevel@tonic-gate itp->t_ino = ino; 902*0Sstevel@tonic-gate itp->t_seekpt = seekpt; 903*0Sstevel@tonic-gate if ((dip->di_mode & IFMT) == IFATTRDIR) { 904*0Sstevel@tonic-gate itp->t_xattr = xattrlist; 905*0Sstevel@tonic-gate xattrlist = itp; 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate if (mf == NULL) 908*0Sstevel@tonic-gate return (itp); 909*0Sstevel@tonic-gate node.ino = ino; 910*0Sstevel@tonic-gate node.timep[0] = dip->di_atime; 911*0Sstevel@tonic-gate node.timep[1] = dip->di_mtime; 912*0Sstevel@tonic-gate node.mode = dip->di_mode; 913*0Sstevel@tonic-gate node.uid = 914*0Sstevel@tonic-gate dip->di_suid == UID_LONG ? dip->di_uid : (uid_t)dip->di_suid; 915*0Sstevel@tonic-gate node.gid = 916*0Sstevel@tonic-gate dip->di_sgid == GID_LONG ? dip->di_gid : (gid_t)dip->di_sgid; 917*0Sstevel@tonic-gate return (itp); 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate 920*0Sstevel@tonic-gate void 921*0Sstevel@tonic-gate nodeflush() 922*0Sstevel@tonic-gate { 923*0Sstevel@tonic-gate char *metadata; 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate if (mf == NULL) { 926*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 927*0Sstevel@tonic-gate "Inconsistency detected: modefile pointer is NULL\n")); 928*0Sstevel@tonic-gate done(1); 929*0Sstevel@tonic-gate } 930*0Sstevel@tonic-gate metaget(&metadata, &(node.metasize)); 931*0Sstevel@tonic-gate (void) fwrite((char *)&node, 1, sizeof (node), mf); 932*0Sstevel@tonic-gate if (node.metasize != 0) 933*0Sstevel@tonic-gate (void) fwrite(metadata, 1, node.metasize, mf); 934*0Sstevel@tonic-gate if (ferror(mf)) 935*0Sstevel@tonic-gate panic("%s: %s\n", modefile, strerror(errno)); 936*0Sstevel@tonic-gate } 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate /* 939*0Sstevel@tonic-gate * Look up an inode in the table of directories 940*0Sstevel@tonic-gate */ 941*0Sstevel@tonic-gate static struct inotab * 942*0Sstevel@tonic-gate inotablookup(ino) 943*0Sstevel@tonic-gate ino_t ino; 944*0Sstevel@tonic-gate { 945*0Sstevel@tonic-gate struct inotab *itp; 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 948*0Sstevel@tonic-gate if (itp->t_ino == ino) 949*0Sstevel@tonic-gate return (itp); 950*0Sstevel@tonic-gate return ((struct inotab *)0); 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate /* 954*0Sstevel@tonic-gate * Clean up and exit 955*0Sstevel@tonic-gate */ 956*0Sstevel@tonic-gate void 957*0Sstevel@tonic-gate done(exitcode) 958*0Sstevel@tonic-gate int exitcode; 959*0Sstevel@tonic-gate { 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate closemt(); 962*0Sstevel@tonic-gate if (modefile[0] != '#') 963*0Sstevel@tonic-gate (void) unlink(modefile); 964*0Sstevel@tonic-gate if (dirfile[0] != '#') 965*0Sstevel@tonic-gate (void) unlink(dirfile); 966*0Sstevel@tonic-gate exit(exitcode); 967*0Sstevel@tonic-gate } 968