1 /* 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)symtab.c 5.5 (Berkeley) 6/1/90"; 36 #endif /* not lint */ 37 38 /* 39 * These routines maintain the symbol table which tracks the state 40 * of the file system being restored. They provide lookup by either 41 * name or inode number. They also provide for creation, deletion, 42 * and renaming of entries. Because of the dynamic nature of pathnames, 43 * names should not be saved, but always constructed just before they 44 * are needed, by calling "myname". 45 */ 46 47 #include "restore.h" 48 #include <sys/stat.h> 49 #include <ufs/dir.h> 50 51 /* 52 * The following variables define the inode symbol table. 53 * The primary hash table is dynamically allocated based on 54 * the number of inodes in the file system (maxino), scaled by 55 * HASHFACTOR. The variable "entry" points to the hash table; 56 * the variable "entrytblsize" indicates its size (in entries). 57 */ 58 #define HASHFACTOR 5 59 static struct entry **entry; 60 static long entrytblsize; 61 62 /* 63 * Look up an entry by inode number 64 */ 65 struct entry * 66 lookupino(inum) 67 ino_t inum; 68 { 69 register struct entry *ep; 70 71 if (inum < ROOTINO || inum >= maxino) 72 return (NIL); 73 for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next) 74 if (ep->e_ino == inum) 75 return (ep); 76 return (NIL); 77 } 78 79 /* 80 * Add an entry into the entry table 81 */ 82 addino(inum, np) 83 ino_t inum; 84 struct entry *np; 85 { 86 struct entry **epp; 87 88 if (inum < ROOTINO || inum >= maxino) 89 panic("addino: out of range %d\n", inum); 90 epp = &entry[inum % entrytblsize]; 91 np->e_ino = inum; 92 np->e_next = *epp; 93 *epp = np; 94 if (dflag) 95 for (np = np->e_next; np != NIL; np = np->e_next) 96 if (np->e_ino == inum) 97 badentry(np, "duplicate inum"); 98 } 99 100 /* 101 * Delete an entry from the entry table 102 */ 103 deleteino(inum) 104 ino_t inum; 105 { 106 register struct entry *next; 107 struct entry **prev; 108 109 if (inum < ROOTINO || inum >= maxino) 110 panic("deleteino: out of range %d\n", inum); 111 prev = &entry[inum % entrytblsize]; 112 for (next = *prev; next != NIL; next = next->e_next) { 113 if (next->e_ino == inum) { 114 next->e_ino = 0; 115 *prev = next->e_next; 116 return; 117 } 118 prev = &next->e_next; 119 } 120 panic("deleteino: %d not found\n", inum); 121 } 122 123 /* 124 * Look up an entry by name 125 */ 126 struct entry * 127 lookupname(name) 128 char *name; 129 { 130 register struct entry *ep; 131 register char *np, *cp; 132 char buf[MAXPATHLEN]; 133 134 cp = name; 135 for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) { 136 for (np = buf; *cp != '/' && *cp != '\0'; ) 137 *np++ = *cp++; 138 *np = '\0'; 139 for ( ; ep != NIL; ep = ep->e_sibling) 140 if (strcmp(ep->e_name, buf) == 0) 141 break; 142 if (ep == NIL) 143 break; 144 if (*cp++ == '\0') 145 return (ep); 146 } 147 return (NIL); 148 } 149 150 /* 151 * Look up the parent of a pathname 152 */ 153 struct entry * 154 lookupparent(name) 155 char *name; 156 { 157 struct entry *ep; 158 char *tailindex; 159 160 tailindex = rindex(name, '/'); 161 if (tailindex == 0) 162 return (NIL); 163 *tailindex = '\0'; 164 ep = lookupname(name); 165 *tailindex = '/'; 166 if (ep == NIL) 167 return (NIL); 168 if (ep->e_type != NODE) 169 panic("%s is not a directory\n", name); 170 return (ep); 171 } 172 173 /* 174 * Determine the current pathname of a node or leaf 175 */ 176 char * 177 myname(ep) 178 register struct entry *ep; 179 { 180 register char *cp; 181 static char namebuf[MAXPATHLEN]; 182 183 for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) { 184 cp -= ep->e_namlen; 185 bcopy(ep->e_name, cp, (long)ep->e_namlen); 186 if (ep == lookupino(ROOTINO)) 187 return (cp); 188 *(--cp) = '/'; 189 ep = ep->e_parent; 190 } 191 panic("%s: pathname too long\n", cp); 192 return(cp); 193 } 194 195 /* 196 * Unused symbol table entries are linked together on a freelist 197 * headed by the following pointer. 198 */ 199 static struct entry *freelist = NIL; 200 201 /* 202 * add an entry to the symbol table 203 */ 204 struct entry * 205 addentry(name, inum, type) 206 char *name; 207 ino_t inum; 208 int type; 209 { 210 register struct entry *np, *ep; 211 212 if (freelist != NIL) { 213 np = freelist; 214 freelist = np->e_next; 215 bzero((char *)np, (long)sizeof(struct entry)); 216 } else { 217 np = (struct entry *)calloc(1, sizeof(struct entry)); 218 if (np == NIL) 219 panic("no memory to extend symbol table\n"); 220 } 221 np->e_type = type & ~LINK; 222 ep = lookupparent(name); 223 if (ep == NIL) { 224 if (inum != ROOTINO || lookupino(ROOTINO) != NIL) 225 panic("bad name to addentry %s\n", name); 226 np->e_name = savename(name); 227 np->e_namlen = strlen(name); 228 np->e_parent = np; 229 addino(ROOTINO, np); 230 return (np); 231 } 232 np->e_name = savename(rindex(name, '/') + 1); 233 np->e_namlen = strlen(np->e_name); 234 np->e_parent = ep; 235 np->e_sibling = ep->e_entries; 236 ep->e_entries = np; 237 if (type & LINK) { 238 ep = lookupino(inum); 239 if (ep == NIL) 240 panic("link to non-existant name\n"); 241 np->e_ino = inum; 242 np->e_links = ep->e_links; 243 ep->e_links = np; 244 } else if (inum != 0) { 245 if (lookupino(inum) != NIL) 246 panic("duplicate entry\n"); 247 addino(inum, np); 248 } 249 return (np); 250 } 251 252 /* 253 * delete an entry from the symbol table 254 */ 255 freeentry(ep) 256 register struct entry *ep; 257 { 258 register struct entry *np; 259 ino_t inum; 260 261 if (ep->e_flags != REMOVED) 262 badentry(ep, "not marked REMOVED"); 263 if (ep->e_type == NODE) { 264 if (ep->e_links != NIL) 265 badentry(ep, "freeing referenced directory"); 266 if (ep->e_entries != NIL) 267 badentry(ep, "freeing non-empty directory"); 268 } 269 if (ep->e_ino != 0) { 270 np = lookupino(ep->e_ino); 271 if (np == NIL) 272 badentry(ep, "lookupino failed"); 273 if (np == ep) { 274 inum = ep->e_ino; 275 deleteino(inum); 276 if (ep->e_links != NIL) 277 addino(inum, ep->e_links); 278 } else { 279 for (; np != NIL; np = np->e_links) { 280 if (np->e_links == ep) { 281 np->e_links = ep->e_links; 282 break; 283 } 284 } 285 if (np == NIL) 286 badentry(ep, "link not found"); 287 } 288 } 289 removeentry(ep); 290 freename(ep->e_name); 291 ep->e_next = freelist; 292 freelist = ep; 293 } 294 295 /* 296 * Relocate an entry in the tree structure 297 */ 298 moveentry(ep, newname) 299 register struct entry *ep; 300 char *newname; 301 { 302 struct entry *np; 303 char *cp; 304 305 np = lookupparent(newname); 306 if (np == NIL) 307 badentry(ep, "cannot move ROOT"); 308 if (np != ep->e_parent) { 309 removeentry(ep); 310 ep->e_parent = np; 311 ep->e_sibling = np->e_entries; 312 np->e_entries = ep; 313 } 314 cp = rindex(newname, '/') + 1; 315 freename(ep->e_name); 316 ep->e_name = savename(cp); 317 ep->e_namlen = strlen(cp); 318 if (strcmp(gentempname(ep), ep->e_name) == 0) 319 ep->e_flags |= TMPNAME; 320 else 321 ep->e_flags &= ~TMPNAME; 322 } 323 324 /* 325 * Remove an entry in the tree structure 326 */ 327 removeentry(ep) 328 register struct entry *ep; 329 { 330 register struct entry *np; 331 332 np = ep->e_parent; 333 if (np->e_entries == ep) { 334 np->e_entries = ep->e_sibling; 335 } else { 336 for (np = np->e_entries; np != NIL; np = np->e_sibling) { 337 if (np->e_sibling == ep) { 338 np->e_sibling = ep->e_sibling; 339 break; 340 } 341 } 342 if (np == NIL) 343 badentry(ep, "cannot find entry in parent list"); 344 } 345 } 346 347 /* 348 * Table of unused string entries, sorted by length. 349 * 350 * Entries are allocated in STRTBLINCR sized pieces so that names 351 * of similar lengths can use the same entry. The value of STRTBLINCR 352 * is chosen so that every entry has at least enough space to hold 353 * a "struct strtbl" header. Thus every entry can be linked onto an 354 * apprpriate free list. 355 * 356 * NB. The macro "allocsize" below assumes that "struct strhdr" 357 * has a size that is a power of two. 358 */ 359 struct strhdr { 360 struct strhdr *next; 361 }; 362 363 #define STRTBLINCR (sizeof(struct strhdr)) 364 #define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1)) 365 366 static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR]; 367 368 /* 369 * Allocate space for a name. It first looks to see if it already 370 * has an appropriate sized entry, and if not allocates a new one. 371 */ 372 char * 373 savename(name) 374 char *name; 375 { 376 struct strhdr *np; 377 long len; 378 char *cp; 379 380 if (name == NULL) 381 panic("bad name\n"); 382 len = strlen(name); 383 np = strtblhdr[len / STRTBLINCR].next; 384 if (np != NULL) { 385 strtblhdr[len / STRTBLINCR].next = np->next; 386 cp = (char *)np; 387 } else { 388 cp = malloc((unsigned)allocsize(len)); 389 if (cp == NULL) 390 panic("no space for string table\n"); 391 } 392 (void) strcpy(cp, name); 393 return (cp); 394 } 395 396 /* 397 * Free space for a name. The resulting entry is linked onto the 398 * appropriate free list. 399 */ 400 freename(name) 401 char *name; 402 { 403 struct strhdr *tp, *np; 404 405 tp = &strtblhdr[strlen(name) / STRTBLINCR]; 406 np = (struct strhdr *)name; 407 np->next = tp->next; 408 tp->next = np; 409 } 410 411 /* 412 * Useful quantities placed at the end of a dumped symbol table. 413 */ 414 struct symtableheader { 415 long volno; 416 long stringsize; 417 long entrytblsize; 418 time_t dumptime; 419 time_t dumpdate; 420 ino_t maxino; 421 long ntrec; 422 }; 423 424 /* 425 * dump a snapshot of the symbol table 426 */ 427 dumpsymtable(filename, checkpt) 428 char *filename; 429 long checkpt; 430 { 431 register struct entry *ep, *tep; 432 register ino_t i; 433 struct entry temp, *tentry; 434 long mynum = 1, stroff = 0; 435 FILE *fd; 436 struct symtableheader hdr; 437 438 vprintf(stdout, "Check pointing the restore\n"); 439 if (Nflag) 440 return; 441 if ((fd = fopen(filename, "w")) == NULL) { 442 perror("fopen"); 443 panic("cannot create save file %s for symbol table\n", 444 filename); 445 } 446 clearerr(fd); 447 /* 448 * Assign indicies to each entry 449 * Write out the string entries 450 */ 451 for (i = ROOTINO; i < maxino; i++) { 452 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 453 ep->e_index = mynum++; 454 (void) fwrite(ep->e_name, sizeof(char), 455 (int)allocsize(ep->e_namlen), fd); 456 } 457 } 458 /* 459 * Convert pointers to indexes, and output 460 */ 461 tep = &temp; 462 stroff = 0; 463 for (i = ROOTINO; i < maxino; i++) { 464 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 465 bcopy((char *)ep, (char *)tep, 466 (long)sizeof(struct entry)); 467 tep->e_name = (char *)stroff; 468 stroff += allocsize(ep->e_namlen); 469 tep->e_parent = (struct entry *)ep->e_parent->e_index; 470 if (ep->e_links != NIL) 471 tep->e_links = 472 (struct entry *)ep->e_links->e_index; 473 if (ep->e_sibling != NIL) 474 tep->e_sibling = 475 (struct entry *)ep->e_sibling->e_index; 476 if (ep->e_entries != NIL) 477 tep->e_entries = 478 (struct entry *)ep->e_entries->e_index; 479 if (ep->e_next != NIL) 480 tep->e_next = 481 (struct entry *)ep->e_next->e_index; 482 (void) fwrite((char *)tep, sizeof(struct entry), 1, fd); 483 } 484 } 485 /* 486 * Convert entry pointers to indexes, and output 487 */ 488 for (i = 0; i < entrytblsize; i++) { 489 if (entry[i] == NIL) 490 tentry = NIL; 491 else 492 tentry = (struct entry *)entry[i]->e_index; 493 (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd); 494 } 495 hdr.volno = checkpt; 496 hdr.maxino = maxino; 497 hdr.entrytblsize = entrytblsize; 498 hdr.stringsize = stroff; 499 hdr.dumptime = dumptime; 500 hdr.dumpdate = dumpdate; 501 hdr.ntrec = ntrec; 502 (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd); 503 if (ferror(fd)) { 504 perror("fwrite"); 505 panic("output error to file %s writing symbol table\n", 506 filename); 507 } 508 (void) fclose(fd); 509 } 510 511 /* 512 * Initialize a symbol table from a file 513 */ 514 initsymtable(filename) 515 char *filename; 516 { 517 char *base; 518 long tblsize; 519 register struct entry *ep; 520 struct entry *baseep, *lep; 521 struct symtableheader hdr; 522 struct stat stbuf; 523 register long i; 524 int fd; 525 526 vprintf(stdout, "Initialize symbol table.\n"); 527 if (filename == NULL) { 528 entrytblsize = maxino / HASHFACTOR; 529 entry = (struct entry **) 530 calloc((unsigned)entrytblsize, sizeof(struct entry *)); 531 if (entry == (struct entry **)NIL) 532 panic("no memory for entry table\n"); 533 ep = addentry(".", ROOTINO, NODE); 534 ep->e_flags |= NEW; 535 return; 536 } 537 if ((fd = open(filename, 0)) < 0) { 538 perror("open"); 539 panic("cannot open symbol table file %s\n", filename); 540 } 541 if (fstat(fd, &stbuf) < 0) { 542 perror("stat"); 543 panic("cannot stat symbol table file %s\n", filename); 544 } 545 tblsize = stbuf.st_size - sizeof(struct symtableheader); 546 base = calloc(sizeof(char), (unsigned)tblsize); 547 if (base == NULL) 548 panic("cannot allocate space for symbol table\n"); 549 if (read(fd, base, (int)tblsize) < 0 || 550 read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) { 551 perror("read"); 552 panic("cannot read symbol table file %s\n", filename); 553 } 554 switch (command) { 555 case 'r': 556 /* 557 * For normal continuation, insure that we are using 558 * the next incremental tape 559 */ 560 if (hdr.dumpdate != dumptime) { 561 if (hdr.dumpdate < dumptime) 562 fprintf(stderr, "Incremental tape too low\n"); 563 else 564 fprintf(stderr, "Incremental tape too high\n"); 565 done(1); 566 } 567 break; 568 case 'R': 569 /* 570 * For restart, insure that we are using the same tape 571 */ 572 curfile.action = SKIP; 573 dumptime = hdr.dumptime; 574 dumpdate = hdr.dumpdate; 575 if (!bflag) 576 newtapebuf(hdr.ntrec); 577 getvol(hdr.volno); 578 break; 579 default: 580 panic("initsymtable called from command %c\n", command); 581 break; 582 } 583 maxino = hdr.maxino; 584 entrytblsize = hdr.entrytblsize; 585 entry = (struct entry **) 586 (base + tblsize - (entrytblsize * sizeof(struct entry *))); 587 baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry)); 588 lep = (struct entry *)entry; 589 for (i = 0; i < entrytblsize; i++) { 590 if (entry[i] == NIL) 591 continue; 592 entry[i] = &baseep[(long)entry[i]]; 593 } 594 for (ep = &baseep[1]; ep < lep; ep++) { 595 ep->e_name = base + (long)ep->e_name; 596 ep->e_parent = &baseep[(long)ep->e_parent]; 597 if (ep->e_sibling != NIL) 598 ep->e_sibling = &baseep[(long)ep->e_sibling]; 599 if (ep->e_links != NIL) 600 ep->e_links = &baseep[(long)ep->e_links]; 601 if (ep->e_entries != NIL) 602 ep->e_entries = &baseep[(long)ep->e_entries]; 603 if (ep->e_next != NIL) 604 ep->e_next = &baseep[(long)ep->e_next]; 605 } 606 } 607