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