1*10314Smckusick /* Copyright (c) 1983 Regents of the University of California */ 2*10314Smckusick 3*10314Smckusick #ifndef lint 4*10314Smckusick static char sccsid[] = "@(#)symtab.c 3.5 (Berkeley) 83/01/16"; 5*10314Smckusick #endif 6*10314Smckusick 7*10314Smckusick #include "restore.h" 8*10314Smckusick #include <sys/stat.h> 9*10314Smckusick 10*10314Smckusick struct symtableheader { 11*10314Smckusick long volno; 12*10314Smckusick long stringsize; 13*10314Smckusick long entrytblsize; 14*10314Smckusick time_t dumptime; 15*10314Smckusick time_t dumpdate; 16*10314Smckusick ino_t maxino; 17*10314Smckusick }; 18*10314Smckusick 19*10314Smckusick static struct entry *freelist = NIL; 20*10314Smckusick static struct entry **entry; 21*10314Smckusick static long entrytblsize; 22*10314Smckusick /* used to scale maxino to get inode hash table size */ 23*10314Smckusick #define HASHFACTOR 5 24*10314Smckusick 25*10314Smckusick /* 26*10314Smckusick * Look up an entry by inode number 27*10314Smckusick */ 28*10314Smckusick struct entry * 29*10314Smckusick lookupino(inum) 30*10314Smckusick ino_t inum; 31*10314Smckusick { 32*10314Smckusick register struct entry *ep; 33*10314Smckusick 34*10314Smckusick if (inum < ROOTINO || inum >= maxino) 35*10314Smckusick return (NIL); 36*10314Smckusick for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next) 37*10314Smckusick if (ep->e_ino == inum) 38*10314Smckusick return (ep); 39*10314Smckusick return (NIL); 40*10314Smckusick } 41*10314Smckusick 42*10314Smckusick /* 43*10314Smckusick * Add an entry into the entry table 44*10314Smckusick */ 45*10314Smckusick addino(inum, np) 46*10314Smckusick ino_t inum; 47*10314Smckusick struct entry *np; 48*10314Smckusick { 49*10314Smckusick struct entry **epp; 50*10314Smckusick 51*10314Smckusick if (inum < ROOTINO || inum >= maxino) 52*10314Smckusick panic("addino: out of range %d\n", inum); 53*10314Smckusick epp = &entry[inum % entrytblsize]; 54*10314Smckusick np->e_next = *epp; 55*10314Smckusick *epp = np; 56*10314Smckusick if (dflag) 57*10314Smckusick for (np = np->e_next; np != NIL; np = np->e_next) 58*10314Smckusick if (np->e_ino == inum) 59*10314Smckusick badentry(np, "duplicate inum"); 60*10314Smckusick } 61*10314Smckusick 62*10314Smckusick /* 63*10314Smckusick * Delete an entry from the entry table 64*10314Smckusick */ 65*10314Smckusick deleteino(inum) 66*10314Smckusick ino_t inum; 67*10314Smckusick { 68*10314Smckusick register struct entry *next; 69*10314Smckusick struct entry **prev; 70*10314Smckusick 71*10314Smckusick if (inum < ROOTINO || inum >= maxino) 72*10314Smckusick panic("deleteino: out of range %d\n", inum); 73*10314Smckusick prev = &entry[inum % entrytblsize]; 74*10314Smckusick for (next = *prev; next != NIL; next = next->e_next) { 75*10314Smckusick if (next->e_ino == inum) { 76*10314Smckusick *prev = next->e_next; 77*10314Smckusick return; 78*10314Smckusick } 79*10314Smckusick prev = &next->e_next; 80*10314Smckusick } 81*10314Smckusick panic("deleteino: %d not found\n", inum); 82*10314Smckusick } 83*10314Smckusick 84*10314Smckusick /* 85*10314Smckusick * Look up an entry by name 86*10314Smckusick */ 87*10314Smckusick struct entry * 88*10314Smckusick lookupname(name) 89*10314Smckusick char *name; 90*10314Smckusick { 91*10314Smckusick register struct entry *ep; 92*10314Smckusick register char *np, *cp; 93*10314Smckusick char buf[BUFSIZ]; 94*10314Smckusick 95*10314Smckusick cp = name; 96*10314Smckusick for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) { 97*10314Smckusick for (np = buf; *cp != '/' && *cp != '\0'; ) 98*10314Smckusick *np++ = *cp++; 99*10314Smckusick *np = '\0'; 100*10314Smckusick for ( ; ep != NIL; ep = ep->e_sibling) 101*10314Smckusick if (strcmp(ep->e_name, buf) == 0) 102*10314Smckusick break; 103*10314Smckusick if (ep == NIL) 104*10314Smckusick break; 105*10314Smckusick if (*cp++ == '\0') 106*10314Smckusick return (ep); 107*10314Smckusick } 108*10314Smckusick return (NIL); 109*10314Smckusick } 110*10314Smckusick 111*10314Smckusick /* 112*10314Smckusick * Look up the parent of a pathname 113*10314Smckusick */ 114*10314Smckusick struct entry * 115*10314Smckusick lookupparent(name) 116*10314Smckusick char *name; 117*10314Smckusick { 118*10314Smckusick struct entry *ep; 119*10314Smckusick char *tailindex; 120*10314Smckusick 121*10314Smckusick tailindex = rindex(name, '/'); 122*10314Smckusick if (tailindex == 0) 123*10314Smckusick return (NIL); 124*10314Smckusick *tailindex = '\0'; 125*10314Smckusick ep = lookupname(name); 126*10314Smckusick *tailindex = '/'; 127*10314Smckusick if (ep == NIL) 128*10314Smckusick return (NIL); 129*10314Smckusick if (ep->e_type != NODE) 130*10314Smckusick panic("%s is not a directory\n", name); 131*10314Smckusick return (ep); 132*10314Smckusick } 133*10314Smckusick 134*10314Smckusick /* 135*10314Smckusick * Determine the current pathname of a node or leaf 136*10314Smckusick */ 137*10314Smckusick char * 138*10314Smckusick myname(ep) 139*10314Smckusick register struct entry *ep; 140*10314Smckusick { 141*10314Smckusick register char *cp; 142*10314Smckusick static char namebuf[BUFSIZ]; 143*10314Smckusick 144*10314Smckusick for (cp = &namebuf[BUFSIZ - 2]; cp > &namebuf[ep->e_namlen]; ) { 145*10314Smckusick cp -= ep->e_namlen; 146*10314Smckusick bcopy(ep->e_name, cp, (long)ep->e_namlen); 147*10314Smckusick if (ep == lookupino(ROOTINO)) 148*10314Smckusick return (cp); 149*10314Smckusick *(--cp) = '/'; 150*10314Smckusick ep = ep->e_parent; 151*10314Smckusick } 152*10314Smckusick panic("%s: pathname too long\n", cp); 153*10314Smckusick return(cp); 154*10314Smckusick } 155*10314Smckusick 156*10314Smckusick /* 157*10314Smckusick * add an entry to the symbol table 158*10314Smckusick */ 159*10314Smckusick struct entry * 160*10314Smckusick addentry(name, inum, type) 161*10314Smckusick char *name; 162*10314Smckusick ino_t inum; 163*10314Smckusick int type; 164*10314Smckusick { 165*10314Smckusick register struct entry *np, *ep; 166*10314Smckusick 167*10314Smckusick if (freelist != NIL) { 168*10314Smckusick np = freelist; 169*10314Smckusick freelist = np->e_sibling; 170*10314Smckusick bzero((char *)np, (long)sizeof(struct entry)); 171*10314Smckusick } else { 172*10314Smckusick np = (struct entry *)calloc(1, sizeof(struct entry)); 173*10314Smckusick } 174*10314Smckusick np->e_ino = inum; 175*10314Smckusick np->e_type = type & ~LINK; 176*10314Smckusick ep = lookupparent(name); 177*10314Smckusick if (ep == NIL) { 178*10314Smckusick if (inum != ROOTINO || lookupino(ROOTINO) != NIL) 179*10314Smckusick panic("bad name to addentry %s\n", name); 180*10314Smckusick np->e_name = savename(name); 181*10314Smckusick np->e_namlen = strlen(name); 182*10314Smckusick np->e_parent = np; 183*10314Smckusick addino(ROOTINO, np); 184*10314Smckusick return (np); 185*10314Smckusick } 186*10314Smckusick np->e_name = savename(rindex(name, '/') + 1); 187*10314Smckusick np->e_namlen = strlen(np->e_name); 188*10314Smckusick np->e_parent = ep; 189*10314Smckusick np->e_sibling = ep->e_entries; 190*10314Smckusick ep->e_entries = np; 191*10314Smckusick if (type & LINK) { 192*10314Smckusick ep = lookupino(inum); 193*10314Smckusick if (ep == NIL) 194*10314Smckusick panic("link to non-existant name\n"); 195*10314Smckusick np->e_links = ep->e_links; 196*10314Smckusick ep->e_links = np; 197*10314Smckusick } else if (inum != 0) { 198*10314Smckusick if (lookupino(inum) != NIL) 199*10314Smckusick panic("duplicate entry\n"); 200*10314Smckusick addino(inum, np); 201*10314Smckusick } 202*10314Smckusick return (np); 203*10314Smckusick } 204*10314Smckusick 205*10314Smckusick /* 206*10314Smckusick * delete an entry from the symbol table 207*10314Smckusick */ 208*10314Smckusick freeentry(ep) 209*10314Smckusick register struct entry *ep; 210*10314Smckusick { 211*10314Smckusick register struct entry *np; 212*10314Smckusick 213*10314Smckusick np = lookupino(ep->e_ino); 214*10314Smckusick if (np == NIL) 215*10314Smckusick badentry(ep, "lookupino failed"); 216*10314Smckusick if (ep->e_flags != REMOVED) 217*10314Smckusick badentry(ep, "not marked REMOVED"); 218*10314Smckusick if (np->e_type == NODE) { 219*10314Smckusick if (np == ep && np->e_links != NIL) 220*10314Smckusick badentry(ep, "freeing referenced directory"); 221*10314Smckusick if (ep->e_entries != NIL) 222*10314Smckusick badentry(ep, "freeing non-empty directory"); 223*10314Smckusick } 224*10314Smckusick if (np == ep) { 225*10314Smckusick deleteino(ep->e_ino); 226*10314Smckusick addino(ep->e_ino, ep->e_links); 227*10314Smckusick } else { 228*10314Smckusick for (; np != NIL; np = np->e_links) { 229*10314Smckusick if (np->e_links == ep) { 230*10314Smckusick np->e_links = ep->e_links; 231*10314Smckusick break; 232*10314Smckusick } 233*10314Smckusick } 234*10314Smckusick if (np == NIL) 235*10314Smckusick badentry(ep, "link not found"); 236*10314Smckusick } 237*10314Smckusick removeentry(ep); 238*10314Smckusick free(ep->e_name); 239*10314Smckusick ep->e_sibling = freelist; 240*10314Smckusick freelist = ep; 241*10314Smckusick } 242*10314Smckusick 243*10314Smckusick /* 244*10314Smckusick * Relocate an entry in the tree structure 245*10314Smckusick */ 246*10314Smckusick moveentry(ep, newname) 247*10314Smckusick register struct entry *ep; 248*10314Smckusick char *newname; 249*10314Smckusick { 250*10314Smckusick struct entry *np; 251*10314Smckusick char *cp; 252*10314Smckusick long len; 253*10314Smckusick 254*10314Smckusick np = lookupparent(newname); 255*10314Smckusick if (np == NIL) 256*10314Smckusick badentry(ep, "cannot move ROOT"); 257*10314Smckusick if (np != ep->e_parent) { 258*10314Smckusick removeentry(ep); 259*10314Smckusick ep->e_parent = np; 260*10314Smckusick ep->e_sibling = np->e_entries; 261*10314Smckusick np->e_entries = ep; 262*10314Smckusick } 263*10314Smckusick cp = rindex(newname, '/') + 1; 264*10314Smckusick len = strlen(cp); 265*10314Smckusick if (ep->e_flags & TMPNAME) 266*10314Smckusick ep->e_namlen--; 267*10314Smckusick if (ep->e_namlen >= len) { 268*10314Smckusick strcpy(ep->e_name, cp); 269*10314Smckusick } else { 270*10314Smckusick free(ep->e_name); 271*10314Smckusick ep->e_name = savename(cp); 272*10314Smckusick } 273*10314Smckusick ep->e_namlen = len; 274*10314Smckusick if (cp[len - 1] == TMPCHAR) 275*10314Smckusick ep->e_flags |= TMPNAME; 276*10314Smckusick else 277*10314Smckusick ep->e_flags &= ~TMPNAME; 278*10314Smckusick } 279*10314Smckusick 280*10314Smckusick /* 281*10314Smckusick * Remove an entry in the tree structure 282*10314Smckusick */ 283*10314Smckusick removeentry(ep) 284*10314Smckusick register struct entry *ep; 285*10314Smckusick { 286*10314Smckusick register struct entry *np; 287*10314Smckusick 288*10314Smckusick np = ep->e_parent; 289*10314Smckusick if (np->e_entries == ep) { 290*10314Smckusick np->e_entries = ep->e_sibling; 291*10314Smckusick } else { 292*10314Smckusick for (np = np->e_entries; np != NIL; np = np->e_sibling) { 293*10314Smckusick if (np->e_sibling == ep) { 294*10314Smckusick np->e_sibling = ep->e_sibling; 295*10314Smckusick break; 296*10314Smckusick } 297*10314Smckusick } 298*10314Smckusick if (np == NIL) 299*10314Smckusick badentry(ep, "cannot find entry in parent list"); 300*10314Smckusick } 301*10314Smckusick } 302*10314Smckusick 303*10314Smckusick /* 304*10314Smckusick * allocate space for a name 305*10314Smckusick */ 306*10314Smckusick char * 307*10314Smckusick savename(name) 308*10314Smckusick char *name; 309*10314Smckusick { 310*10314Smckusick long len; 311*10314Smckusick char *cp; 312*10314Smckusick 313*10314Smckusick if (name == NULL) 314*10314Smckusick panic("bad name\n"); 315*10314Smckusick len = strlen(name) + 2; 316*10314Smckusick len = (len + 3) & ~3; 317*10314Smckusick cp = malloc((unsigned)len); 318*10314Smckusick (void) strcpy(cp, name); 319*10314Smckusick return (cp); 320*10314Smckusick } 321*10314Smckusick 322*10314Smckusick /* 323*10314Smckusick * dump a snapshot of the symbol table 324*10314Smckusick */ 325*10314Smckusick dumpsymtable(filename, checkpt) 326*10314Smckusick char *filename; 327*10314Smckusick long checkpt; 328*10314Smckusick { 329*10314Smckusick register struct entry *ep; 330*10314Smckusick register ino_t i; 331*10314Smckusick struct entry *next; 332*10314Smckusick long mynum = 0, stroff = 0; 333*10314Smckusick FILE *fd; 334*10314Smckusick struct symtableheader hdr; 335*10314Smckusick 336*10314Smckusick vprintf(stdout, "Check pointing the restore\n"); 337*10314Smckusick if ((fd = fopen(filename, "w")) == NULL) { 338*10314Smckusick perror("fopen"); 339*10314Smckusick panic("cannot create save file %s for symbol table\n", 340*10314Smckusick filename); 341*10314Smckusick } 342*10314Smckusick clearerr(fd); 343*10314Smckusick /* 344*10314Smckusick * Assign indicies to each entry 345*10314Smckusick * Write out the string entries 346*10314Smckusick */ 347*10314Smckusick for (i = ROOTINO; i < maxino; i++) { 348*10314Smckusick for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 349*10314Smckusick ep->e_index = mynum++; 350*10314Smckusick fwrite(ep->e_name, sizeof(char), (int)ep->e_namlen, fd); 351*10314Smckusick ep->e_name = (char *)stroff; 352*10314Smckusick stroff += ep->e_namlen; 353*10314Smckusick } 354*10314Smckusick } 355*10314Smckusick /* 356*10314Smckusick * Convert entry pointers to indexes, and output 357*10314Smckusick */ 358*10314Smckusick for (i = 0; i < entrytblsize; i++) { 359*10314Smckusick if (entry[i] == NIL) 360*10314Smckusick continue; 361*10314Smckusick entry[i] = (struct entry *)entry[i]->e_index; 362*10314Smckusick } 363*10314Smckusick fwrite((char *)entry, sizeof(struct entry *), (int)entrytblsize, fd); 364*10314Smckusick /* 365*10314Smckusick * Convert pointers to indexes, and output 366*10314Smckusick */ 367*10314Smckusick for (i = ROOTINO; i < maxino; i++) { 368*10314Smckusick for (ep = lookupino(i); ep != NIL; ep = next) { 369*10314Smckusick next = ep->e_links; 370*10314Smckusick ep->e_parent = (struct entry *)ep->e_parent->e_index; 371*10314Smckusick if (ep->e_links != NIL) 372*10314Smckusick ep->e_links = 373*10314Smckusick (struct entry *)ep->e_links->e_index; 374*10314Smckusick if (ep->e_sibling != NIL) 375*10314Smckusick ep->e_sibling = 376*10314Smckusick (struct entry *)ep->e_sibling->e_index; 377*10314Smckusick if (ep->e_entries != NIL) 378*10314Smckusick ep->e_entries = 379*10314Smckusick (struct entry *)ep->e_entries->e_index; 380*10314Smckusick if (ep->e_next != NIL) 381*10314Smckusick ep->e_next = 382*10314Smckusick (struct entry *)ep->e_next->e_index; 383*10314Smckusick fwrite((char *)ep, sizeof(struct entry), 1, fd); 384*10314Smckusick } 385*10314Smckusick } 386*10314Smckusick hdr.volno = checkpt; 387*10314Smckusick hdr.maxino = maxino; 388*10314Smckusick hdr.entrytblsize = entrytblsize; 389*10314Smckusick hdr.stringsize = stroff; 390*10314Smckusick hdr.dumptime = dumptime; 391*10314Smckusick hdr.dumpdate = dumpdate; 392*10314Smckusick fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd); 393*10314Smckusick if (ferror(fd)) { 394*10314Smckusick perror("fwrite"); 395*10314Smckusick panic("output error to file %s writing symbol table\n", 396*10314Smckusick filename); 397*10314Smckusick } 398*10314Smckusick fclose(fd); 399*10314Smckusick } 400*10314Smckusick 401*10314Smckusick /* 402*10314Smckusick * Initialize a symbol table from a file 403*10314Smckusick */ 404*10314Smckusick initsymtable(filename) 405*10314Smckusick char *filename; 406*10314Smckusick { 407*10314Smckusick char *base; 408*10314Smckusick long tblsize; 409*10314Smckusick register struct entry *ep; 410*10314Smckusick struct entry *baseep, *lep; 411*10314Smckusick struct symtableheader hdr; 412*10314Smckusick struct stat stbuf; 413*10314Smckusick register long i; 414*10314Smckusick int fd; 415*10314Smckusick 416*10314Smckusick vprintf(stdout, "Initialize symbol table.\n"); 417*10314Smckusick if (filename == NULL) { 418*10314Smckusick entrytblsize = maxino / HASHFACTOR; 419*10314Smckusick entry = (struct entry **) 420*10314Smckusick calloc((unsigned)entrytblsize, sizeof(struct entry *)); 421*10314Smckusick if (entry == (struct entry **)NIL) 422*10314Smckusick panic("no memory for entry table\n"); 423*10314Smckusick (void)addentry(".", ROOTINO, NODE); 424*10314Smckusick return; 425*10314Smckusick } 426*10314Smckusick if ((fd = open(filename, 0)) < 0) { 427*10314Smckusick perror("open"); 428*10314Smckusick panic("cannot open symbol table file %s\n", filename); 429*10314Smckusick } 430*10314Smckusick if (fstat(fd, &stbuf) < 0) { 431*10314Smckusick perror("stat"); 432*10314Smckusick panic("cannot stat symbol table file %s\n", filename); 433*10314Smckusick } 434*10314Smckusick tblsize = stbuf.st_size - sizeof(struct symtableheader); 435*10314Smckusick base = malloc((unsigned)tblsize); 436*10314Smckusick if (base == NULL) 437*10314Smckusick panic("cannot allocate space for symbol table\n"); 438*10314Smckusick if (read(fd, base, (int)tblsize) < 0 || 439*10314Smckusick read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) { 440*10314Smckusick perror("read"); 441*10314Smckusick panic("cannot read symbol table file %s\n", filename); 442*10314Smckusick } 443*10314Smckusick switch (command) { 444*10314Smckusick case 'r': 445*10314Smckusick /* 446*10314Smckusick * For normal continuation, insure that we are using 447*10314Smckusick * the next incremental tape 448*10314Smckusick */ 449*10314Smckusick if (hdr.dumptime != dumpdate) { 450*10314Smckusick if (hdr.dumptime < dumpdate) 451*10314Smckusick fprintf(stderr, "Incremental tape too low\n"); 452*10314Smckusick else 453*10314Smckusick fprintf(stderr, "Incremental tape too high\n"); 454*10314Smckusick done(1); 455*10314Smckusick } 456*10314Smckusick break; 457*10314Smckusick case 'R': 458*10314Smckusick /* 459*10314Smckusick * For restart, insure that we are using the same tape 460*10314Smckusick */ 461*10314Smckusick curfile.action = SKIP; 462*10314Smckusick dumptime = hdr.dumptime; 463*10314Smckusick dumpdate = hdr.dumpdate; 464*10314Smckusick getvol(hdr.volno); 465*10314Smckusick break; 466*10314Smckusick default: 467*10314Smckusick panic("initsymtable called from command %c\n", command); 468*10314Smckusick break; 469*10314Smckusick } 470*10314Smckusick maxino = hdr.maxino; 471*10314Smckusick entrytblsize = hdr.entrytblsize; 472*10314Smckusick entry = (struct entry **)(base + hdr.stringsize); 473*10314Smckusick baseep = (struct entry *)(&entry[entrytblsize]); 474*10314Smckusick lep = (struct entry *)(base + tblsize); 475*10314Smckusick for (i = 0; i < entrytblsize; i++) { 476*10314Smckusick if (entry[i] == NIL) 477*10314Smckusick continue; 478*10314Smckusick entry[i] = &baseep[(long)entry[i]]; 479*10314Smckusick } 480*10314Smckusick for (ep = baseep; ep < lep; ep++) { 481*10314Smckusick ep->e_name = base + (long)ep->e_name; 482*10314Smckusick ep->e_parent = &baseep[(long)ep->e_parent]; 483*10314Smckusick if (ep->e_sibling != NIL) 484*10314Smckusick ep->e_sibling = &baseep[(long)ep->e_sibling]; 485*10314Smckusick if (ep->e_links != NIL) 486*10314Smckusick ep->e_links = &baseep[(long)ep->e_links]; 487*10314Smckusick if (ep->e_entries != NIL) 488*10314Smckusick ep->e_entries = &baseep[(long)ep->e_entries]; 489*10314Smckusick if (ep->e_next != NIL) 490*10314Smckusick ep->e_next = &baseep[(long)ep->e_next]; 491*10314Smckusick } 492*10314Smckusick } 493