1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 4*7c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 5*7c478bd9Sstevel@tonic-gate */ 6*7c478bd9Sstevel@tonic-gate 7*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 8*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 9*7c478bd9Sstevel@tonic-gate 10*7c478bd9Sstevel@tonic-gate /* 11*7c478bd9Sstevel@tonic-gate * Copyright (c) 1996,1998,2001 by Sun Microsystems, Inc. 12*7c478bd9Sstevel@tonic-gate * All rights reserved. 13*7c478bd9Sstevel@tonic-gate */ 14*7c478bd9Sstevel@tonic-gate 15*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate /* 18*7c478bd9Sstevel@tonic-gate * These routines maintain the symbol table which tracks the state 19*7c478bd9Sstevel@tonic-gate * of the file system being restored. They provide lookup by either 20*7c478bd9Sstevel@tonic-gate * name or inode number. They also provide for creation, deletion, 21*7c478bd9Sstevel@tonic-gate * and renaming of entries. Because of the dynamic nature of pathnames, 22*7c478bd9Sstevel@tonic-gate * names should not be saved, but always constructed just before they 23*7c478bd9Sstevel@tonic-gate * are needed, by calling "myname". 24*7c478bd9Sstevel@tonic-gate */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #include "restore.h" 27*7c478bd9Sstevel@tonic-gate #include <limits.h> 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * The following variables define the inode symbol table. 31*7c478bd9Sstevel@tonic-gate * The primary hash table is dynamically allocated based on 32*7c478bd9Sstevel@tonic-gate * the number of inodes in the file system (maxino), scaled by 33*7c478bd9Sstevel@tonic-gate * HASHFACTOR. The variable "entry" points to the hash table; 34*7c478bd9Sstevel@tonic-gate * the variable "entrytblsize" indicates its size (in entries). 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate #define HASHFACTOR 5 37*7c478bd9Sstevel@tonic-gate static struct entry **entry; 38*7c478bd9Sstevel@tonic-gate static uint_t entrytblsize; 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 41*7c478bd9Sstevel@tonic-gate static void addino(ino_t, struct entry *); 42*7c478bd9Sstevel@tonic-gate static struct entry *lookupparent(char *); 43*7c478bd9Sstevel@tonic-gate static void removeentry(struct entry *); 44*7c478bd9Sstevel@tonic-gate #else 45*7c478bd9Sstevel@tonic-gate static void addino(); 46*7c478bd9Sstevel@tonic-gate static struct entry *lookupparent(); 47*7c478bd9Sstevel@tonic-gate static void removeentry(); 48*7c478bd9Sstevel@tonic-gate #endif 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate * Look up an entry by inode number 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate struct entry * 54*7c478bd9Sstevel@tonic-gate lookupino(inum) 55*7c478bd9Sstevel@tonic-gate ino_t inum; 56*7c478bd9Sstevel@tonic-gate { 57*7c478bd9Sstevel@tonic-gate struct entry *ep; 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate if (inum < ROOTINO || inum >= maxino) 60*7c478bd9Sstevel@tonic-gate return (NIL); 61*7c478bd9Sstevel@tonic-gate for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next) 62*7c478bd9Sstevel@tonic-gate if (ep->e_ino == inum) 63*7c478bd9Sstevel@tonic-gate return (ep); 64*7c478bd9Sstevel@tonic-gate return (NIL); 65*7c478bd9Sstevel@tonic-gate } 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate * We now ignore inodes that are out of range. This 69*7c478bd9Sstevel@tonic-gate * allows us to attempt to proceed in the face of 70*7c478bd9Sstevel@tonic-gate * a corrupted archive, albeit with future complaints 71*7c478bd9Sstevel@tonic-gate * about failed inode lookups. We only complain once 72*7c478bd9Sstevel@tonic-gate * about range problems, to avoid irritating the user 73*7c478bd9Sstevel@tonic-gate * without providing any useful information. Failed 74*7c478bd9Sstevel@tonic-gate * lookups have the bogus name, which is useful, so 75*7c478bd9Sstevel@tonic-gate * they always happen. 76*7c478bd9Sstevel@tonic-gate */ 77*7c478bd9Sstevel@tonic-gate static int complained_about_range = 0; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * Add an entry into the entry table 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate static void 83*7c478bd9Sstevel@tonic-gate addino(inum, np) 84*7c478bd9Sstevel@tonic-gate ino_t inum; 85*7c478bd9Sstevel@tonic-gate struct entry *np; 86*7c478bd9Sstevel@tonic-gate { 87*7c478bd9Sstevel@tonic-gate struct entry **epp; 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate if (inum < ROOTINO || inum >= maxino) { 90*7c478bd9Sstevel@tonic-gate if (!complained_about_range) { 91*7c478bd9Sstevel@tonic-gate panic(gettext("%s: out of range %d\n"), 92*7c478bd9Sstevel@tonic-gate "addino", inum); 93*7c478bd9Sstevel@tonic-gate complained_about_range = 1; 94*7c478bd9Sstevel@tonic-gate } 95*7c478bd9Sstevel@tonic-gate return; 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate epp = &entry[inum % entrytblsize]; 98*7c478bd9Sstevel@tonic-gate np->e_ino = inum; 99*7c478bd9Sstevel@tonic-gate np->e_next = *epp; 100*7c478bd9Sstevel@tonic-gate *epp = np; 101*7c478bd9Sstevel@tonic-gate if (dflag) 102*7c478bd9Sstevel@tonic-gate for (np = np->e_next; np != NIL; np = np->e_next) 103*7c478bd9Sstevel@tonic-gate if (np->e_ino == inum) 104*7c478bd9Sstevel@tonic-gate badentry(np, gettext("duplicate inum")); 105*7c478bd9Sstevel@tonic-gate } 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * Delete an entry from the entry table. We assume our caller 109*7c478bd9Sstevel@tonic-gate * arranges for the necessary memory reclamation, if needed. 110*7c478bd9Sstevel@tonic-gate */ 111*7c478bd9Sstevel@tonic-gate void 112*7c478bd9Sstevel@tonic-gate deleteino(inum) 113*7c478bd9Sstevel@tonic-gate ino_t inum; 114*7c478bd9Sstevel@tonic-gate { 115*7c478bd9Sstevel@tonic-gate struct entry *next; 116*7c478bd9Sstevel@tonic-gate struct entry **prev; 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate if (inum < ROOTINO || inum >= maxino) { 119*7c478bd9Sstevel@tonic-gate if (!complained_about_range) { 120*7c478bd9Sstevel@tonic-gate panic(gettext("%s: out of range %d\n"), 121*7c478bd9Sstevel@tonic-gate "deleteino", inum); 122*7c478bd9Sstevel@tonic-gate complained_about_range = 1; 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate return; 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate prev = &entry[inum % entrytblsize]; 128*7c478bd9Sstevel@tonic-gate for (next = *prev; next != NIL; next = next->e_next) { 129*7c478bd9Sstevel@tonic-gate if (next->e_ino == inum) { 130*7c478bd9Sstevel@tonic-gate next->e_ino = 0; 131*7c478bd9Sstevel@tonic-gate *prev = next->e_next; 132*7c478bd9Sstevel@tonic-gate return; 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate prev = &next->e_next; 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate } 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* 139*7c478bd9Sstevel@tonic-gate * Look up an entry by name. 140*7c478bd9Sstevel@tonic-gate * NOTE: this function handles "complex" pathnames (as returned 141*7c478bd9Sstevel@tonic-gate * by myname()) for extended file attributes. The name string 142*7c478bd9Sstevel@tonic-gate * provided to this function should be terminated with *two* 143*7c478bd9Sstevel@tonic-gate * NULL characters. 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate struct entry * 146*7c478bd9Sstevel@tonic-gate lookupname(name) 147*7c478bd9Sstevel@tonic-gate char *name; 148*7c478bd9Sstevel@tonic-gate { 149*7c478bd9Sstevel@tonic-gate struct entry *ep; 150*7c478bd9Sstevel@tonic-gate char *np, *cp; 151*7c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate if (strlen(name) > (sizeof (buf) - 1)) { 154*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: ignoring too-long name\n"), 155*7c478bd9Sstevel@tonic-gate "lookupname"); 156*7c478bd9Sstevel@tonic-gate return (NIL); 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate cp = name; 160*7c478bd9Sstevel@tonic-gate for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) { 161*7c478bd9Sstevel@tonic-gate np = buf; 162*7c478bd9Sstevel@tonic-gate while (*cp != '/' && *cp != '\0') 163*7c478bd9Sstevel@tonic-gate *np++ = *cp++; 164*7c478bd9Sstevel@tonic-gate *np = '\0'; 165*7c478bd9Sstevel@tonic-gate for (; ep != NIL; ep = ep->e_sibling) 166*7c478bd9Sstevel@tonic-gate if (strcmp(ep->e_name, buf) == 0) 167*7c478bd9Sstevel@tonic-gate break; 168*7c478bd9Sstevel@tonic-gate if (*cp++ == '\0') { 169*7c478bd9Sstevel@tonic-gate if (*cp != '\0') { 170*7c478bd9Sstevel@tonic-gate ep = ep->e_xattrs; 171*7c478bd9Sstevel@tonic-gate /* 172*7c478bd9Sstevel@tonic-gate * skip over the "./" prefix on all 173*7c478bd9Sstevel@tonic-gate * extended attribute paths 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate cp += 2; 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate if (*cp == '\0') 178*7c478bd9Sstevel@tonic-gate return (ep); 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate if (ep == NIL) 181*7c478bd9Sstevel@tonic-gate break; 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate return (NIL); 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate * Look up the parent of a pathname. This routine accepts complex 188*7c478bd9Sstevel@tonic-gate * names so the provided name argument must terminate with two NULLs. 189*7c478bd9Sstevel@tonic-gate */ 190*7c478bd9Sstevel@tonic-gate static struct entry * 191*7c478bd9Sstevel@tonic-gate lookupparent(name) 192*7c478bd9Sstevel@tonic-gate char *name; 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate struct entry *ep; 195*7c478bd9Sstevel@tonic-gate char *tailindex, savechar, *lastpart; 196*7c478bd9Sstevel@tonic-gate int xattrparent = 0; 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate /* find the last component of the complex name */ 199*7c478bd9Sstevel@tonic-gate lastpart = name; 200*7c478bd9Sstevel@tonic-gate LASTPART(lastpart); 201*7c478bd9Sstevel@tonic-gate tailindex = strrchr(lastpart, '/'); 202*7c478bd9Sstevel@tonic-gate if (tailindex == 0) { 203*7c478bd9Sstevel@tonic-gate if (lastpart == name) 204*7c478bd9Sstevel@tonic-gate return (NIL); 205*7c478bd9Sstevel@tonic-gate /* 206*7c478bd9Sstevel@tonic-gate * tailindex normaly points to the '/' character 207*7c478bd9Sstevel@tonic-gate * dividing the path, but in the case of an extended 208*7c478bd9Sstevel@tonic-gate * attribute transition it will point to the NULL 209*7c478bd9Sstevel@tonic-gate * separator in front of the attribute path. 210*7c478bd9Sstevel@tonic-gate */ 211*7c478bd9Sstevel@tonic-gate tailindex = lastpart - 1; 212*7c478bd9Sstevel@tonic-gate xattrparent = 1; 213*7c478bd9Sstevel@tonic-gate } else { 214*7c478bd9Sstevel@tonic-gate *tailindex = '\0'; 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate savechar = *(tailindex+1); 217*7c478bd9Sstevel@tonic-gate *(tailindex+1) = '\0'; 218*7c478bd9Sstevel@tonic-gate ep = lookupname(name); 219*7c478bd9Sstevel@tonic-gate if (ep != NIL && !xattrparent && ep->e_type != NODE) 220*7c478bd9Sstevel@tonic-gate panic(gettext("%s is not a directory\n"), name); 221*7c478bd9Sstevel@tonic-gate if (!xattrparent) *tailindex = '/'; 222*7c478bd9Sstevel@tonic-gate *(tailindex+1) = savechar; 223*7c478bd9Sstevel@tonic-gate return (ep); 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * Determine the current pathname of a node or leaf. 228*7c478bd9Sstevel@tonic-gate * The returned pathname will be multiple strings with NULL separators: 229*7c478bd9Sstevel@tonic-gate * 230*7c478bd9Sstevel@tonic-gate * ./<path>/entry\0<path>/attrentry\0<path>/...\0\0 231*7c478bd9Sstevel@tonic-gate * ^ ^ ^ ^ 232*7c478bd9Sstevel@tonic-gate * return pntr entry attr recursive attr terminator 233*7c478bd9Sstevel@tonic-gate * 234*7c478bd9Sstevel@tonic-gate * Guaranteed to return a name that fits within MAXCOMPLEXLEN and is 235*7c478bd9Sstevel@tonic-gate * terminated with two NULLs. 236*7c478bd9Sstevel@tonic-gate */ 237*7c478bd9Sstevel@tonic-gate char * 238*7c478bd9Sstevel@tonic-gate myname(ep) 239*7c478bd9Sstevel@tonic-gate struct entry *ep; 240*7c478bd9Sstevel@tonic-gate { 241*7c478bd9Sstevel@tonic-gate char *cp; 242*7c478bd9Sstevel@tonic-gate struct entry *root = lookupino(ROOTINO); 243*7c478bd9Sstevel@tonic-gate static char namebuf[MAXCOMPLEXLEN]; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate cp = &namebuf[MAXCOMPLEXLEN - 3]; 246*7c478bd9Sstevel@tonic-gate *(cp + 1) = '\0'; 247*7c478bd9Sstevel@tonic-gate *(cp + 2) = '\0'; 248*7c478bd9Sstevel@tonic-gate while (cp > &namebuf[ep->e_namlen]) { 249*7c478bd9Sstevel@tonic-gate cp -= ep->e_namlen; 250*7c478bd9Sstevel@tonic-gate bcopy(ep->e_name, cp, (size_t)ep->e_namlen); 251*7c478bd9Sstevel@tonic-gate if (ep == root) 252*7c478bd9Sstevel@tonic-gate return (cp); 253*7c478bd9Sstevel@tonic-gate if (ep->e_flags & XATTRROOT) 254*7c478bd9Sstevel@tonic-gate *(--cp) = '\0'; 255*7c478bd9Sstevel@tonic-gate else 256*7c478bd9Sstevel@tonic-gate *(--cp) = '/'; 257*7c478bd9Sstevel@tonic-gate ep = ep->e_parent; 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate panic(gettext("%s%s: pathname too long\n"), "...", cp); 260*7c478bd9Sstevel@tonic-gate return (cp); 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate /* 264*7c478bd9Sstevel@tonic-gate * Unused symbol table entries are linked together on a freelist 265*7c478bd9Sstevel@tonic-gate * headed by the following pointer. 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate static struct entry *freelist = NIL; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* 270*7c478bd9Sstevel@tonic-gate * add an entry to the symbol table 271*7c478bd9Sstevel@tonic-gate */ 272*7c478bd9Sstevel@tonic-gate struct entry * 273*7c478bd9Sstevel@tonic-gate addentry(name, inum, type) 274*7c478bd9Sstevel@tonic-gate char *name; 275*7c478bd9Sstevel@tonic-gate ino_t inum; 276*7c478bd9Sstevel@tonic-gate int type; 277*7c478bd9Sstevel@tonic-gate { 278*7c478bd9Sstevel@tonic-gate struct entry *np, *ep; 279*7c478bd9Sstevel@tonic-gate char *cp; 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate if (freelist != NIL) { 282*7c478bd9Sstevel@tonic-gate np = freelist; 283*7c478bd9Sstevel@tonic-gate freelist = np->e_next; 284*7c478bd9Sstevel@tonic-gate (void) bzero((char *)np, (size_t)sizeof (*np)); 285*7c478bd9Sstevel@tonic-gate } else { 286*7c478bd9Sstevel@tonic-gate np = (struct entry *)calloc(1, sizeof (*np)); 287*7c478bd9Sstevel@tonic-gate if (np == NIL) { 288*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 289*7c478bd9Sstevel@tonic-gate gettext("no memory to extend symbol table\n")); 290*7c478bd9Sstevel@tonic-gate done(1); 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate } 293*7c478bd9Sstevel@tonic-gate np->e_type = type & ~(LINK|ROOT); 294*7c478bd9Sstevel@tonic-gate if (inattrspace) 295*7c478bd9Sstevel@tonic-gate np->e_flags |= XATTR; 296*7c478bd9Sstevel@tonic-gate ep = lookupparent(name); 297*7c478bd9Sstevel@tonic-gate if (ep == NIL) { 298*7c478bd9Sstevel@tonic-gate if (inum != ROOTINO || lookupino(ROOTINO) != NIL) { 299*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 300*7c478bd9Sstevel@tonic-gate "%s: bad name %s\n"), "addentry", name); 301*7c478bd9Sstevel@tonic-gate assert(0); 302*7c478bd9Sstevel@tonic-gate done(1); 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate np->e_name = savename(name); 305*7c478bd9Sstevel@tonic-gate /* LINTED: savename guarantees that strlen fits in e_namlen */ 306*7c478bd9Sstevel@tonic-gate np->e_namlen = strlen(name); 307*7c478bd9Sstevel@tonic-gate np->e_parent = np; 308*7c478bd9Sstevel@tonic-gate addino(ROOTINO, np); 309*7c478bd9Sstevel@tonic-gate return (np); 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate if (np->e_flags & XATTR) { 313*7c478bd9Sstevel@tonic-gate /* 314*7c478bd9Sstevel@tonic-gate * skip to the last part of the complex string: it 315*7c478bd9Sstevel@tonic-gate * containes the extended attribute file name. 316*7c478bd9Sstevel@tonic-gate */ 317*7c478bd9Sstevel@tonic-gate LASTPART(name); 318*7c478bd9Sstevel@tonic-gate } 319*7c478bd9Sstevel@tonic-gate cp = strrchr(name, '/'); 320*7c478bd9Sstevel@tonic-gate if (cp == NULL) 321*7c478bd9Sstevel@tonic-gate cp = name; 322*7c478bd9Sstevel@tonic-gate else 323*7c478bd9Sstevel@tonic-gate cp++; 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate np->e_name = savename(cp); 326*7c478bd9Sstevel@tonic-gate /* LINTED: savename guarantees that strlen will fit */ 327*7c478bd9Sstevel@tonic-gate np->e_namlen = strlen(np->e_name); 328*7c478bd9Sstevel@tonic-gate np->e_parent = ep; 329*7c478bd9Sstevel@tonic-gate /* 330*7c478bd9Sstevel@tonic-gate * Extended attribute root directories must be linked to their 331*7c478bd9Sstevel@tonic-gate * "parents" via the e_xattrs field. Other entries are simply 332*7c478bd9Sstevel@tonic-gate * added to their parent directories e_entries list. 333*7c478bd9Sstevel@tonic-gate */ 334*7c478bd9Sstevel@tonic-gate if ((type & ROOT) && (np->e_flags & XATTR)) { 335*7c478bd9Sstevel@tonic-gate /* link this extended attribute root dir to its "parent" */ 336*7c478bd9Sstevel@tonic-gate ep->e_xattrs = np; 337*7c478bd9Sstevel@tonic-gate } else { 338*7c478bd9Sstevel@tonic-gate /* add this entry to the entry list of the parent dir */ 339*7c478bd9Sstevel@tonic-gate np->e_sibling = ep->e_entries; 340*7c478bd9Sstevel@tonic-gate ep->e_entries = np; 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate if (type & LINK) { 343*7c478bd9Sstevel@tonic-gate ep = lookupino(inum); 344*7c478bd9Sstevel@tonic-gate if (ep == NIL) { 345*7c478bd9Sstevel@tonic-gate /* XXX just bail on this one and continue? */ 346*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 347*7c478bd9Sstevel@tonic-gate gettext("link to non-existent name\n")); 348*7c478bd9Sstevel@tonic-gate done(1); 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate np->e_ino = inum; 351*7c478bd9Sstevel@tonic-gate np->e_links = ep->e_links; 352*7c478bd9Sstevel@tonic-gate ep->e_links = np; 353*7c478bd9Sstevel@tonic-gate } else if (inum != 0) { 354*7c478bd9Sstevel@tonic-gate ep = lookupino(inum); 355*7c478bd9Sstevel@tonic-gate if (ep != NIL) 356*7c478bd9Sstevel@tonic-gate panic(gettext("duplicate entry\n")); 357*7c478bd9Sstevel@tonic-gate else 358*7c478bd9Sstevel@tonic-gate addino(inum, np); 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate return (np); 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* 364*7c478bd9Sstevel@tonic-gate * delete an entry from the symbol table 365*7c478bd9Sstevel@tonic-gate */ 366*7c478bd9Sstevel@tonic-gate void 367*7c478bd9Sstevel@tonic-gate freeentry(ep) 368*7c478bd9Sstevel@tonic-gate struct entry *ep; 369*7c478bd9Sstevel@tonic-gate { 370*7c478bd9Sstevel@tonic-gate struct entry *np; 371*7c478bd9Sstevel@tonic-gate ino_t inum; 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate if ((ep->e_flags & REMOVED) == 0) 374*7c478bd9Sstevel@tonic-gate badentry(ep, gettext("not marked REMOVED")); 375*7c478bd9Sstevel@tonic-gate if (ep->e_type == NODE) { 376*7c478bd9Sstevel@tonic-gate if (ep->e_links != NIL) 377*7c478bd9Sstevel@tonic-gate badentry(ep, gettext("freeing referenced directory")); 378*7c478bd9Sstevel@tonic-gate if (ep->e_entries != NIL) 379*7c478bd9Sstevel@tonic-gate badentry(ep, gettext("freeing non-empty directory")); 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate if (ep->e_ino != 0) { 382*7c478bd9Sstevel@tonic-gate np = lookupino(ep->e_ino); 383*7c478bd9Sstevel@tonic-gate if (np == NIL) 384*7c478bd9Sstevel@tonic-gate badentry(ep, gettext("lookupino failed")); 385*7c478bd9Sstevel@tonic-gate if (np == ep) { 386*7c478bd9Sstevel@tonic-gate inum = ep->e_ino; 387*7c478bd9Sstevel@tonic-gate deleteino(inum); 388*7c478bd9Sstevel@tonic-gate if (ep->e_links != NIL) 389*7c478bd9Sstevel@tonic-gate addino(inum, ep->e_links); 390*7c478bd9Sstevel@tonic-gate } else { 391*7c478bd9Sstevel@tonic-gate for (; np != NIL; np = np->e_links) { 392*7c478bd9Sstevel@tonic-gate if (np->e_links == ep) { 393*7c478bd9Sstevel@tonic-gate np->e_links = ep->e_links; 394*7c478bd9Sstevel@tonic-gate break; 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate if (np == NIL) 398*7c478bd9Sstevel@tonic-gate badentry(ep, gettext("link not found")); 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate removeentry(ep); 402*7c478bd9Sstevel@tonic-gate freename(ep->e_name); 403*7c478bd9Sstevel@tonic-gate ep->e_next = freelist; 404*7c478bd9Sstevel@tonic-gate freelist = ep; 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate /* 408*7c478bd9Sstevel@tonic-gate * Relocate an entry in the tree structure 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate void 411*7c478bd9Sstevel@tonic-gate moveentry(ep, newname) 412*7c478bd9Sstevel@tonic-gate struct entry *ep; 413*7c478bd9Sstevel@tonic-gate char *newname; 414*7c478bd9Sstevel@tonic-gate { 415*7c478bd9Sstevel@tonic-gate struct entry *np; 416*7c478bd9Sstevel@tonic-gate char *cp; 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate np = lookupparent(newname); 419*7c478bd9Sstevel@tonic-gate if (np == NIL) 420*7c478bd9Sstevel@tonic-gate badentry(ep, gettext("cannot move ROOT")); 421*7c478bd9Sstevel@tonic-gate if (np != ep->e_parent) { 422*7c478bd9Sstevel@tonic-gate removeentry(ep); 423*7c478bd9Sstevel@tonic-gate ep->e_parent = np; 424*7c478bd9Sstevel@tonic-gate ep->e_sibling = np->e_entries; 425*7c478bd9Sstevel@tonic-gate np->e_entries = ep; 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate /* find the last component of the complex name */ 428*7c478bd9Sstevel@tonic-gate LASTPART(newname); 429*7c478bd9Sstevel@tonic-gate cp = strrchr(newname, '/') + 1; 430*7c478bd9Sstevel@tonic-gate if (cp == (char *)1) 431*7c478bd9Sstevel@tonic-gate cp = newname; 432*7c478bd9Sstevel@tonic-gate freename(ep->e_name); 433*7c478bd9Sstevel@tonic-gate ep->e_name = savename(cp); 434*7c478bd9Sstevel@tonic-gate /* LINTED: savename guarantees that strlen will fit */ 435*7c478bd9Sstevel@tonic-gate ep->e_namlen = strlen(cp); 436*7c478bd9Sstevel@tonic-gate if (strcmp(gentempname(ep), ep->e_name) == 0) { 437*7c478bd9Sstevel@tonic-gate /* LINTED: result fits in a short */ 438*7c478bd9Sstevel@tonic-gate ep->e_flags |= TMPNAME; 439*7c478bd9Sstevel@tonic-gate } else { 440*7c478bd9Sstevel@tonic-gate /* LINTED: result fits in a short */ 441*7c478bd9Sstevel@tonic-gate ep->e_flags &= ~TMPNAME; 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate /* 446*7c478bd9Sstevel@tonic-gate * Remove an entry in the tree structure 447*7c478bd9Sstevel@tonic-gate */ 448*7c478bd9Sstevel@tonic-gate static void 449*7c478bd9Sstevel@tonic-gate removeentry(ep) 450*7c478bd9Sstevel@tonic-gate struct entry *ep; 451*7c478bd9Sstevel@tonic-gate { 452*7c478bd9Sstevel@tonic-gate struct entry *np; 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate np = ep->e_parent; 455*7c478bd9Sstevel@tonic-gate if (ep->e_flags & XATTRROOT) { 456*7c478bd9Sstevel@tonic-gate if (np->e_xattrs == ep) 457*7c478bd9Sstevel@tonic-gate np->e_xattrs = NIL; 458*7c478bd9Sstevel@tonic-gate else 459*7c478bd9Sstevel@tonic-gate badentry(ep, gettext( 460*7c478bd9Sstevel@tonic-gate "parent does not reference this xattr tree")); 461*7c478bd9Sstevel@tonic-gate } else if (np->e_entries == ep) { 462*7c478bd9Sstevel@tonic-gate np->e_entries = ep->e_sibling; 463*7c478bd9Sstevel@tonic-gate } else { 464*7c478bd9Sstevel@tonic-gate for (np = np->e_entries; np != NIL; np = np->e_sibling) { 465*7c478bd9Sstevel@tonic-gate if (np->e_sibling == ep) { 466*7c478bd9Sstevel@tonic-gate np->e_sibling = ep->e_sibling; 467*7c478bd9Sstevel@tonic-gate break; 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate } 470*7c478bd9Sstevel@tonic-gate if (np == NIL) 471*7c478bd9Sstevel@tonic-gate badentry(ep, gettext( 472*7c478bd9Sstevel@tonic-gate "cannot find entry in parent list")); 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate /* 477*7c478bd9Sstevel@tonic-gate * Table of unused string entries, sorted by length. 478*7c478bd9Sstevel@tonic-gate * 479*7c478bd9Sstevel@tonic-gate * Entries are allocated in STRTBLINCR sized pieces so that names 480*7c478bd9Sstevel@tonic-gate * of similar lengths can use the same entry. The value of STRTBLINCR 481*7c478bd9Sstevel@tonic-gate * is chosen so that every entry has at least enough space to hold 482*7c478bd9Sstevel@tonic-gate * a "struct strtbl" header. Thus every entry can be linked onto an 483*7c478bd9Sstevel@tonic-gate * apprpriate free list. 484*7c478bd9Sstevel@tonic-gate * 485*7c478bd9Sstevel@tonic-gate * NB. The macro "allocsize" below assumes that "struct strhdr" 486*7c478bd9Sstevel@tonic-gate * has a size that is a power of two. Also, an extra byte is 487*7c478bd9Sstevel@tonic-gate * allocated for the string to provide space for the two NULL 488*7c478bd9Sstevel@tonic-gate * string terminator required for extended attribute paths. 489*7c478bd9Sstevel@tonic-gate */ 490*7c478bd9Sstevel@tonic-gate struct strhdr { 491*7c478bd9Sstevel@tonic-gate struct strhdr *next; 492*7c478bd9Sstevel@tonic-gate }; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate #define STRTBLINCR ((size_t)sizeof (struct strhdr)) 495*7c478bd9Sstevel@tonic-gate #define allocsize(size) (((size) + 2 + STRTBLINCR - 1) & ~(STRTBLINCR - 1)) 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate static struct strhdr strtblhdr[allocsize(MAXCOMPLEXLEN) / STRTBLINCR]; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate /* 500*7c478bd9Sstevel@tonic-gate * Allocate space for a name. It first looks to see if it already 501*7c478bd9Sstevel@tonic-gate * has an appropriate sized entry, and if not allocates a new one. 502*7c478bd9Sstevel@tonic-gate */ 503*7c478bd9Sstevel@tonic-gate char * 504*7c478bd9Sstevel@tonic-gate savename(name) 505*7c478bd9Sstevel@tonic-gate char *name; 506*7c478bd9Sstevel@tonic-gate { 507*7c478bd9Sstevel@tonic-gate struct strhdr *np; 508*7c478bd9Sstevel@tonic-gate size_t len, as; 509*7c478bd9Sstevel@tonic-gate char *cp; 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate if (name == NULL) { 512*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("bad name\n")); 513*7c478bd9Sstevel@tonic-gate done(1); 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate len = strlen(name); 516*7c478bd9Sstevel@tonic-gate if (len > MAXPATHLEN) { 517*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("name too long\n")); 518*7c478bd9Sstevel@tonic-gate done(1); 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate as = allocsize(len); 521*7c478bd9Sstevel@tonic-gate np = strtblhdr[as / STRTBLINCR].next; 522*7c478bd9Sstevel@tonic-gate if (np != NULL) { 523*7c478bd9Sstevel@tonic-gate strtblhdr[as / STRTBLINCR].next = np->next; 524*7c478bd9Sstevel@tonic-gate cp = (char *)np; 525*7c478bd9Sstevel@tonic-gate } else { 526*7c478bd9Sstevel@tonic-gate /* Note that allocsize() adds 2 for the trailing \0s */ 527*7c478bd9Sstevel@tonic-gate cp = malloc(as); 528*7c478bd9Sstevel@tonic-gate if (cp == NULL) { 529*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 530*7c478bd9Sstevel@tonic-gate gettext("no space for string table\n")); 531*7c478bd9Sstevel@tonic-gate done(1); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate } 534*7c478bd9Sstevel@tonic-gate (void) strcpy(cp, name); 535*7c478bd9Sstevel@tonic-gate /* add an extra null for complex (attribute) name support */ 536*7c478bd9Sstevel@tonic-gate cp[len+1] = '\0'; 537*7c478bd9Sstevel@tonic-gate return (cp); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate /* 541*7c478bd9Sstevel@tonic-gate * Free space for a name. The resulting entry is linked onto the 542*7c478bd9Sstevel@tonic-gate * appropriate free list. 543*7c478bd9Sstevel@tonic-gate */ 544*7c478bd9Sstevel@tonic-gate void 545*7c478bd9Sstevel@tonic-gate freename(name) 546*7c478bd9Sstevel@tonic-gate char *name; 547*7c478bd9Sstevel@tonic-gate { 548*7c478bd9Sstevel@tonic-gate struct strhdr *tp, *np; 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* NULL case should never happen, but might as well be careful */ 551*7c478bd9Sstevel@tonic-gate if (name != NULL) { 552*7c478bd9Sstevel@tonic-gate tp = &strtblhdr[allocsize(strlen(name)) / STRTBLINCR]; 553*7c478bd9Sstevel@tonic-gate /*LINTED [name points to at least sizeof (struct strhdr)]*/ 554*7c478bd9Sstevel@tonic-gate np = (struct strhdr *)name; 555*7c478bd9Sstevel@tonic-gate np->next = tp->next; 556*7c478bd9Sstevel@tonic-gate tp->next = np; 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * Useful quantities placed at the end of a dumped symbol table. 562*7c478bd9Sstevel@tonic-gate */ 563*7c478bd9Sstevel@tonic-gate struct symtableheader { 564*7c478bd9Sstevel@tonic-gate int volno; 565*7c478bd9Sstevel@tonic-gate uint_t stringsize; 566*7c478bd9Sstevel@tonic-gate uint_t entrytblsize; 567*7c478bd9Sstevel@tonic-gate time_t dumptime; 568*7c478bd9Sstevel@tonic-gate time_t dumpdate; 569*7c478bd9Sstevel@tonic-gate ino_t maxino; 570*7c478bd9Sstevel@tonic-gate uint_t ntrec; 571*7c478bd9Sstevel@tonic-gate }; 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate /* 574*7c478bd9Sstevel@tonic-gate * dump a snapshot of the symbol table 575*7c478bd9Sstevel@tonic-gate */ 576*7c478bd9Sstevel@tonic-gate void 577*7c478bd9Sstevel@tonic-gate dumpsymtable(filename, checkpt) 578*7c478bd9Sstevel@tonic-gate char *filename; 579*7c478bd9Sstevel@tonic-gate int checkpt; 580*7c478bd9Sstevel@tonic-gate { 581*7c478bd9Sstevel@tonic-gate struct entry *ep, *tep; 582*7c478bd9Sstevel@tonic-gate ino_t i; 583*7c478bd9Sstevel@tonic-gate struct entry temp, *tentry; 584*7c478bd9Sstevel@tonic-gate int mynum = 1; 585*7c478bd9Sstevel@tonic-gate uint_t stroff; 586*7c478bd9Sstevel@tonic-gate FILE *fp; 587*7c478bd9Sstevel@tonic-gate struct symtableheader hdr; 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate vprintf(stdout, gettext("Check pointing the restore\n")); 590*7c478bd9Sstevel@tonic-gate if ((fp = safe_fopen(filename, "w", 0600)) == (FILE *)NULL) { 591*7c478bd9Sstevel@tonic-gate perror("fopen"); 592*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 593*7c478bd9Sstevel@tonic-gate gettext("cannot create save file %s for symbol table\n"), 594*7c478bd9Sstevel@tonic-gate filename); 595*7c478bd9Sstevel@tonic-gate done(1); 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate clearerr(fp); 598*7c478bd9Sstevel@tonic-gate /* 599*7c478bd9Sstevel@tonic-gate * Assign an index to each entry 600*7c478bd9Sstevel@tonic-gate * Write out the string entries 601*7c478bd9Sstevel@tonic-gate */ 602*7c478bd9Sstevel@tonic-gate for (i = ROOTINO; i < maxino; i++) { 603*7c478bd9Sstevel@tonic-gate for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 604*7c478bd9Sstevel@tonic-gate ep->e_index = mynum++; 605*7c478bd9Sstevel@tonic-gate (void) fwrite(ep->e_name, sizeof (ep->e_name[0]), 606*7c478bd9Sstevel@tonic-gate (size_t)allocsize(ep->e_namlen), fp); 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate /* 610*7c478bd9Sstevel@tonic-gate * Convert e_name pointers to offsets, other pointers 611*7c478bd9Sstevel@tonic-gate * to indices, and output 612*7c478bd9Sstevel@tonic-gate */ 613*7c478bd9Sstevel@tonic-gate tep = &temp; 614*7c478bd9Sstevel@tonic-gate stroff = 0; 615*7c478bd9Sstevel@tonic-gate for (i = ROOTINO; !ferror(fp) && i < maxino; i++) { 616*7c478bd9Sstevel@tonic-gate for (ep = lookupino(i); 617*7c478bd9Sstevel@tonic-gate !ferror(fp) && ep != NIL; 618*7c478bd9Sstevel@tonic-gate ep = ep->e_links) { 619*7c478bd9Sstevel@tonic-gate bcopy((char *)ep, (char *)tep, sizeof (*tep)); 620*7c478bd9Sstevel@tonic-gate /* LINTED: type pun ok */ 621*7c478bd9Sstevel@tonic-gate tep->e_name = (char *)stroff; 622*7c478bd9Sstevel@tonic-gate stroff += allocsize(ep->e_namlen); 623*7c478bd9Sstevel@tonic-gate tep->e_parent = (struct entry *)ep->e_parent->e_index; 624*7c478bd9Sstevel@tonic-gate if (ep->e_links != NIL) 625*7c478bd9Sstevel@tonic-gate tep->e_links = 626*7c478bd9Sstevel@tonic-gate (struct entry *)ep->e_links->e_index; 627*7c478bd9Sstevel@tonic-gate if (ep->e_sibling != NIL) 628*7c478bd9Sstevel@tonic-gate tep->e_sibling = 629*7c478bd9Sstevel@tonic-gate (struct entry *)ep->e_sibling->e_index; 630*7c478bd9Sstevel@tonic-gate if (ep->e_entries != NIL) 631*7c478bd9Sstevel@tonic-gate tep->e_entries = 632*7c478bd9Sstevel@tonic-gate (struct entry *)ep->e_entries->e_index; 633*7c478bd9Sstevel@tonic-gate if (ep->e_xattrs != NIL) 634*7c478bd9Sstevel@tonic-gate tep->e_xattrs = 635*7c478bd9Sstevel@tonic-gate (struct entry *)ep->e_xattrs->e_index; 636*7c478bd9Sstevel@tonic-gate if (ep->e_next != NIL) 637*7c478bd9Sstevel@tonic-gate tep->e_next = 638*7c478bd9Sstevel@tonic-gate (struct entry *)ep->e_next->e_index; 639*7c478bd9Sstevel@tonic-gate (void) fwrite((char *)tep, sizeof (*tep), 1, fp); 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate /* 643*7c478bd9Sstevel@tonic-gate * Convert entry pointers to indices, and output 644*7c478bd9Sstevel@tonic-gate */ 645*7c478bd9Sstevel@tonic-gate for (i = 0; !ferror(fp) && i < (ino_t)entrytblsize; i++) { 646*7c478bd9Sstevel@tonic-gate if (entry[i] == NIL) 647*7c478bd9Sstevel@tonic-gate tentry = NIL; 648*7c478bd9Sstevel@tonic-gate else 649*7c478bd9Sstevel@tonic-gate tentry = (struct entry *)entry[i]->e_index; 650*7c478bd9Sstevel@tonic-gate (void) fwrite((char *)&tentry, sizeof (tentry), 1, fp); 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate if (!ferror(fp)) { 654*7c478bd9Sstevel@tonic-gate /* Ought to have a checksum or magic number */ 655*7c478bd9Sstevel@tonic-gate hdr.volno = checkpt; 656*7c478bd9Sstevel@tonic-gate hdr.maxino = maxino; 657*7c478bd9Sstevel@tonic-gate hdr.entrytblsize = entrytblsize; 658*7c478bd9Sstevel@tonic-gate hdr.stringsize = stroff; 659*7c478bd9Sstevel@tonic-gate hdr.dumptime = dumptime; 660*7c478bd9Sstevel@tonic-gate hdr.dumpdate = dumpdate; 661*7c478bd9Sstevel@tonic-gate hdr.ntrec = ntrec; 662*7c478bd9Sstevel@tonic-gate (void) fwrite((char *)&hdr, sizeof (hdr), 1, fp); 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate if (ferror(fp)) { 666*7c478bd9Sstevel@tonic-gate perror("fwrite"); 667*7c478bd9Sstevel@tonic-gate panic(gettext("output error to file %s writing symbol table\n"), 668*7c478bd9Sstevel@tonic-gate filename); 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate /* 674*7c478bd9Sstevel@tonic-gate * Initialize a symbol table from a file 675*7c478bd9Sstevel@tonic-gate */ 676*7c478bd9Sstevel@tonic-gate void 677*7c478bd9Sstevel@tonic-gate initsymtable(filename) 678*7c478bd9Sstevel@tonic-gate char *filename; 679*7c478bd9Sstevel@tonic-gate { 680*7c478bd9Sstevel@tonic-gate char *base; 681*7c478bd9Sstevel@tonic-gate off64_t tblsize; 682*7c478bd9Sstevel@tonic-gate struct entry *ep; 683*7c478bd9Sstevel@tonic-gate struct entry *baseep, *lep; 684*7c478bd9Sstevel@tonic-gate struct symtableheader hdr; 685*7c478bd9Sstevel@tonic-gate struct stat64 stbuf; 686*7c478bd9Sstevel@tonic-gate uint_t i; 687*7c478bd9Sstevel@tonic-gate int fd; 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate vprintf(stdout, gettext("Initialize symbol table.\n")); 690*7c478bd9Sstevel@tonic-gate if (filename == NULL) { 691*7c478bd9Sstevel@tonic-gate if ((maxino / HASHFACTOR) > UINT_MAX) { 692*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 693*7c478bd9Sstevel@tonic-gate gettext("file system too large\n")); 694*7c478bd9Sstevel@tonic-gate done(1); 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate /* LINTED: result fits in entrytblsize */ 697*7c478bd9Sstevel@tonic-gate entrytblsize = maxino / HASHFACTOR; 698*7c478bd9Sstevel@tonic-gate entry = (struct entry **) 699*7c478bd9Sstevel@tonic-gate /* LINTED entrytblsize fits in a size_t */ 700*7c478bd9Sstevel@tonic-gate calloc((size_t)entrytblsize, sizeof (*entry)); 701*7c478bd9Sstevel@tonic-gate if (entry == (struct entry **)NULL) { 702*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 703*7c478bd9Sstevel@tonic-gate gettext("no memory for entry table\n")); 704*7c478bd9Sstevel@tonic-gate done(1); 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate ep = addentry(".", ROOTINO, NODE); 707*7c478bd9Sstevel@tonic-gate /* LINTED: result fits in a short */ 708*7c478bd9Sstevel@tonic-gate ep->e_flags |= NEW; 709*7c478bd9Sstevel@tonic-gate return; 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate if ((fd = open(filename, O_RDONLY|O_LARGEFILE)) < 0) { 712*7c478bd9Sstevel@tonic-gate perror("open"); 713*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 714*7c478bd9Sstevel@tonic-gate gettext("cannot open symbol table file %s\n"), filename); 715*7c478bd9Sstevel@tonic-gate done(1); 716*7c478bd9Sstevel@tonic-gate } 717*7c478bd9Sstevel@tonic-gate if (fstat64(fd, &stbuf) < 0) { 718*7c478bd9Sstevel@tonic-gate perror("stat"); 719*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 720*7c478bd9Sstevel@tonic-gate gettext("cannot stat symbol table file %s\n"), filename); 721*7c478bd9Sstevel@tonic-gate (void) close(fd); 722*7c478bd9Sstevel@tonic-gate done(1); 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate /* 725*7c478bd9Sstevel@tonic-gate * The symbol table file is too small so say we can't read it. 726*7c478bd9Sstevel@tonic-gate */ 727*7c478bd9Sstevel@tonic-gate if (stbuf.st_size < sizeof (hdr)) { 728*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 729*7c478bd9Sstevel@tonic-gate gettext("cannot read symbol table file %s\n"), filename); 730*7c478bd9Sstevel@tonic-gate (void) close(fd); 731*7c478bd9Sstevel@tonic-gate done(1); 732*7c478bd9Sstevel@tonic-gate } 733*7c478bd9Sstevel@tonic-gate tblsize = stbuf.st_size - sizeof (hdr); 734*7c478bd9Sstevel@tonic-gate if (tblsize > ULONG_MAX) { 735*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 736*7c478bd9Sstevel@tonic-gate gettext("symbol table file too large\n")); 737*7c478bd9Sstevel@tonic-gate (void) close(fd); 738*7c478bd9Sstevel@tonic-gate done(1); 739*7c478bd9Sstevel@tonic-gate } 740*7c478bd9Sstevel@tonic-gate /* LINTED tblsize fits in a size_t */ 741*7c478bd9Sstevel@tonic-gate base = calloc((size_t)sizeof (char), (size_t)tblsize); 742*7c478bd9Sstevel@tonic-gate if (base == NULL) { 743*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 744*7c478bd9Sstevel@tonic-gate gettext("cannot allocate space for symbol table\n")); 745*7c478bd9Sstevel@tonic-gate (void) close(fd); 746*7c478bd9Sstevel@tonic-gate done(1); 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate /* LINTED tblsize fits in a size_t */ 749*7c478bd9Sstevel@tonic-gate if (read(fd, base, (size_t)tblsize) < 0 || 750*7c478bd9Sstevel@tonic-gate read(fd, (char *)&hdr, sizeof (hdr)) < 0) { 751*7c478bd9Sstevel@tonic-gate perror("read"); 752*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 753*7c478bd9Sstevel@tonic-gate gettext("cannot read symbol table file %s\n"), filename); 754*7c478bd9Sstevel@tonic-gate (void) close(fd); 755*7c478bd9Sstevel@tonic-gate done(1); 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate (void) close(fd); 758*7c478bd9Sstevel@tonic-gate switch (command) { 759*7c478bd9Sstevel@tonic-gate case 'r': 760*7c478bd9Sstevel@tonic-gate case 'M': 761*7c478bd9Sstevel@tonic-gate /* 762*7c478bd9Sstevel@tonic-gate * For normal continuation, insure that we are using 763*7c478bd9Sstevel@tonic-gate * the next incremental tape 764*7c478bd9Sstevel@tonic-gate */ 765*7c478bd9Sstevel@tonic-gate if (hdr.dumpdate != dumptime) { 766*7c478bd9Sstevel@tonic-gate if (hdr.dumpdate < dumptime) 767*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 768*7c478bd9Sstevel@tonic-gate "Incremental volume too low\n")); 769*7c478bd9Sstevel@tonic-gate else 770*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 771*7c478bd9Sstevel@tonic-gate "Incremental volume too high\n")); 772*7c478bd9Sstevel@tonic-gate done(1); 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate break; 775*7c478bd9Sstevel@tonic-gate case 'R': 776*7c478bd9Sstevel@tonic-gate /* 777*7c478bd9Sstevel@tonic-gate * For restart, insure that we are using the same tape 778*7c478bd9Sstevel@tonic-gate */ 779*7c478bd9Sstevel@tonic-gate curfile.action = SKIP; 780*7c478bd9Sstevel@tonic-gate dumptime = hdr.dumptime; 781*7c478bd9Sstevel@tonic-gate dumpdate = hdr.dumpdate; 782*7c478bd9Sstevel@tonic-gate if (!bflag) 783*7c478bd9Sstevel@tonic-gate newtapebuf(hdr.ntrec); 784*7c478bd9Sstevel@tonic-gate getvol(hdr.volno); 785*7c478bd9Sstevel@tonic-gate break; 786*7c478bd9Sstevel@tonic-gate default: 787*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 788*7c478bd9Sstevel@tonic-gate gettext("initsymtable called from command %c\n"), 789*7c478bd9Sstevel@tonic-gate (uchar_t)command); 790*7c478bd9Sstevel@tonic-gate done(1); 791*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate maxino = hdr.maxino; 794*7c478bd9Sstevel@tonic-gate entrytblsize = hdr.entrytblsize; 795*7c478bd9Sstevel@tonic-gate /*LINTED [pointer cast alignment]*/ 796*7c478bd9Sstevel@tonic-gate entry = (struct entry **) 797*7c478bd9Sstevel@tonic-gate (base + tblsize - (entrytblsize * sizeof (*entry))); 798*7c478bd9Sstevel@tonic-gate if (((ulong_t)entry % 4) != 0) { 799*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 800*7c478bd9Sstevel@tonic-gate gettext("Symbol table file corrupted\n")); 801*7c478bd9Sstevel@tonic-gate done(1); 802*7c478bd9Sstevel@tonic-gate } 803*7c478bd9Sstevel@tonic-gate /*LINTED [rvalue % 4 == 0] */ 804*7c478bd9Sstevel@tonic-gate baseep = (struct entry *) 805*7c478bd9Sstevel@tonic-gate (base + hdr.stringsize - sizeof (*baseep)); 806*7c478bd9Sstevel@tonic-gate if (((ulong_t)baseep % 4) != 0) { 807*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 808*7c478bd9Sstevel@tonic-gate gettext("Symbol table file corrupted\n")); 809*7c478bd9Sstevel@tonic-gate done(1); 810*7c478bd9Sstevel@tonic-gate } 811*7c478bd9Sstevel@tonic-gate lep = (struct entry *)entry; 812*7c478bd9Sstevel@tonic-gate for (i = 0; i < entrytblsize; i++) { 813*7c478bd9Sstevel@tonic-gate if (entry[i] == NIL) 814*7c478bd9Sstevel@tonic-gate continue; 815*7c478bd9Sstevel@tonic-gate entry[i] = &baseep[(long)entry[i]]; 816*7c478bd9Sstevel@tonic-gate } 817*7c478bd9Sstevel@tonic-gate for (ep = &baseep[1]; ep < lep; ep++) { 818*7c478bd9Sstevel@tonic-gate ep->e_name = base + (long)ep->e_name; 819*7c478bd9Sstevel@tonic-gate ep->e_parent = &baseep[(long)ep->e_parent]; 820*7c478bd9Sstevel@tonic-gate if (ep->e_sibling != NIL) 821*7c478bd9Sstevel@tonic-gate ep->e_sibling = &baseep[(long)ep->e_sibling]; 822*7c478bd9Sstevel@tonic-gate if (ep->e_links != NIL) 823*7c478bd9Sstevel@tonic-gate ep->e_links = &baseep[(long)ep->e_links]; 824*7c478bd9Sstevel@tonic-gate if (ep->e_entries != NIL) 825*7c478bd9Sstevel@tonic-gate ep->e_entries = &baseep[(long)ep->e_entries]; 826*7c478bd9Sstevel@tonic-gate if (ep->e_xattrs != NIL) 827*7c478bd9Sstevel@tonic-gate ep->e_xattrs = &baseep[(long)ep->e_xattrs]; 828*7c478bd9Sstevel@tonic-gate if (ep->e_next != NIL) 829*7c478bd9Sstevel@tonic-gate ep->e_next = &baseep[(long)ep->e_next]; 830*7c478bd9Sstevel@tonic-gate } 831*7c478bd9Sstevel@tonic-gate } 832