1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #ifndef lint 40 #if 0 41 static char sccsid[] = "@(#)dirs.c 8.7 (Berkeley) 5/1/95"; 42 #endif 43 static const char rcsid[] = 44 "$FreeBSD$"; 45 #endif /* not lint */ 46 47 #include <sys/param.h> 48 #include <sys/file.h> 49 #include <sys/stat.h> 50 #include <sys/time.h> 51 52 #include <ufs/ufs/dinode.h> 53 #include <ufs/ufs/dir.h> 54 #include <protocols/dumprestore.h> 55 56 #include <err.h> 57 #include <errno.h> 58 #include <paths.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 #include "restore.h" 65 #include "extern.h" 66 67 /* 68 * Symbol table of directories read from tape. 69 */ 70 #define HASHSIZE 1000 71 #define INOHASH(val) (val % HASHSIZE) 72 struct inotab { 73 struct inotab *t_next; 74 ino_t t_ino; 75 int32_t t_seekpt; 76 int32_t t_size; 77 }; 78 static struct inotab *inotab[HASHSIZE]; 79 80 /* 81 * Information retained about directories. 82 */ 83 struct modeinfo { 84 ino_t ino; 85 struct timeval timep[2]; 86 mode_t mode; 87 uid_t uid; 88 gid_t gid; 89 int flags; 90 }; 91 92 /* 93 * Definitions for library routines operating on directories. 94 */ 95 #undef DIRBLKSIZ 96 #define DIRBLKSIZ 1024 97 struct rstdirdesc { 98 int dd_fd; 99 int32_t dd_loc; 100 int32_t dd_size; 101 char dd_buf[DIRBLKSIZ]; 102 }; 103 104 /* 105 * Global variables for this file. 106 */ 107 static long seekpt; 108 static FILE *df, *mf; 109 static RST_DIR *dirp; 110 static char dirfile[MAXPATHLEN] = "#"; /* No file */ 111 static char modefile[MAXPATHLEN] = "#"; /* No file */ 112 static char dot[2] = "."; /* So it can be modified */ 113 114 /* 115 * Format of old style directories. 116 */ 117 #define ODIRSIZ 14 118 struct odirect { 119 u_short d_ino; 120 char d_name[ODIRSIZ]; 121 }; 122 123 static struct inotab *allocinotab __P((ino_t, struct dinode *, long)); 124 static void dcvt __P((struct odirect *, struct direct *)); 125 static void flushent __P((void)); 126 static struct inotab *inotablookup __P((ino_t)); 127 static RST_DIR *opendirfile __P((const char *)); 128 static void putdir __P((char *, long)); 129 static void putent __P((struct direct *)); 130 static void rst_seekdir __P((RST_DIR *, long, long)); 131 static long rst_telldir __P((RST_DIR *)); 132 static struct direct *searchdir __P((ino_t, char *)); 133 134 /* 135 * Extract directory contents, building up a directory structure 136 * on disk for extraction by name. 137 * If genmode is requested, save mode, owner, and times for all 138 * directories on the tape. 139 */ 140 void 141 extractdirs(genmode) 142 int genmode; 143 { 144 register int i; 145 register struct dinode *ip; 146 struct inotab *itp; 147 struct direct nulldir; 148 int fd; 149 const char *tmpdir; 150 151 vprintf(stdout, "Extract directories from tape\n"); 152 if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0') 153 tmpdir = _PATH_TMP; 154 (void) sprintf(dirfile, "%s/rstdir%d", tmpdir, dumpdate); 155 if (command != 'r' && command != 'R') { 156 (void *) strcat(dirfile, "-XXXXXX"); 157 fd = mkstemp(dirfile); 158 } else 159 fd = open(dirfile, O_RDWR|O_CREAT|O_EXCL, 0666); 160 if (fd == -1 || (df = fdopen(fd, "w")) == NULL) { 161 if (fd != -1) 162 close(fd); 163 warn("%s - cannot create directory temporary\nfopen", dirfile); 164 done(1); 165 } 166 if (genmode != 0) { 167 (void) sprintf(modefile, "%s/rstmode%d", tmpdir, dumpdate); 168 if (command != 'r' && command != 'R') { 169 (void *) strcat(modefile, "-XXXXXX"); 170 fd = mkstemp(modefile); 171 } else 172 fd = open(modefile, O_RDWR|O_CREAT|O_EXCL, 0666); 173 if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) { 174 if (fd != -1) 175 close(fd); 176 warn("%s - cannot create modefile\nfopen", modefile); 177 done(1); 178 } 179 } 180 nulldir.d_ino = 0; 181 nulldir.d_type = DT_DIR; 182 nulldir.d_namlen = 1; 183 (void) strcpy(nulldir.d_name, "/"); 184 nulldir.d_reclen = DIRSIZ(0, &nulldir); 185 for (;;) { 186 curfile.name = "<directory file - name unknown>"; 187 curfile.action = USING; 188 ip = curfile.dip; 189 if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 190 (void) fclose(df); 191 dirp = opendirfile(dirfile); 192 if (dirp == NULL) 193 fprintf(stderr, "opendirfile: %s\n", 194 strerror(errno)); 195 if (mf != NULL) 196 (void) fclose(mf); 197 i = dirlookup(dot); 198 if (i == 0) 199 panic("Root directory is not on tape\n"); 200 return; 201 } 202 itp = allocinotab(curfile.ino, ip, seekpt); 203 getfile(putdir, xtrnull); 204 putent(&nulldir); 205 flushent(); 206 itp->t_size = seekpt - itp->t_seekpt; 207 } 208 } 209 210 /* 211 * skip over all the directories on the tape 212 */ 213 void 214 skipdirs() 215 { 216 217 while (curfile.dip && (curfile.dip->di_mode & IFMT) == IFDIR) { 218 skipfile(); 219 } 220 } 221 222 /* 223 * Recursively find names and inumbers of all files in subtree 224 * pname and pass them off to be processed. 225 */ 226 void 227 treescan(pname, ino, todo) 228 char *pname; 229 ino_t ino; 230 long (*todo) __P((char *, ino_t, int)); 231 { 232 register struct inotab *itp; 233 register struct direct *dp; 234 int namelen; 235 long bpt; 236 char locname[MAXPATHLEN + 1]; 237 238 itp = inotablookup(ino); 239 if (itp == NULL) { 240 /* 241 * Pname is name of a simple file or an unchanged directory. 242 */ 243 (void) (*todo)(pname, ino, LEAF); 244 return; 245 } 246 /* 247 * Pname is a dumped directory name. 248 */ 249 if ((*todo)(pname, ino, NODE) == FAIL) 250 return; 251 /* 252 * begin search through the directory 253 * skipping over "." and ".." 254 */ 255 (void) strncpy(locname, pname, sizeof(locname) - 1); 256 locname[sizeof(locname) - 1] = '\0'; 257 (void) strncat(locname, "/", sizeof(locname) - strlen(locname)); 258 namelen = strlen(locname); 259 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 260 dp = rst_readdir(dirp); /* "." */ 261 if (dp != NULL && strcmp(dp->d_name, ".") == 0) 262 dp = rst_readdir(dirp); /* ".." */ 263 else 264 fprintf(stderr, "Warning: `.' missing from directory %s\n", 265 pname); 266 if (dp != NULL && strcmp(dp->d_name, "..") == 0) 267 dp = rst_readdir(dirp); /* first real entry */ 268 else 269 fprintf(stderr, "Warning: `..' missing from directory %s\n", 270 pname); 271 bpt = rst_telldir(dirp); 272 /* 273 * a zero inode signals end of directory 274 */ 275 while (dp != NULL) { 276 locname[namelen] = '\0'; 277 if (namelen + dp->d_namlen >= sizeof(locname)) { 278 fprintf(stderr, "%s%s: name exceeds %d char\n", 279 locname, dp->d_name, sizeof(locname) - 1); 280 } else { 281 (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 282 treescan(locname, dp->d_ino, todo); 283 rst_seekdir(dirp, bpt, itp->t_seekpt); 284 } 285 dp = rst_readdir(dirp); 286 bpt = rst_telldir(dirp); 287 } 288 } 289 290 /* 291 * Lookup a pathname which is always assumed to start from the ROOTINO. 292 */ 293 struct direct * 294 pathsearch(pathname) 295 const char *pathname; 296 { 297 ino_t ino; 298 struct direct *dp; 299 char *path, *name, buffer[MAXPATHLEN]; 300 301 strcpy(buffer, pathname); 302 path = buffer; 303 ino = ROOTINO; 304 while (*path == '/') 305 path++; 306 dp = NULL; 307 while ((name = strsep(&path, "/")) != NULL && *name != '\0') { 308 if ((dp = searchdir(ino, name)) == NULL) 309 return (NULL); 310 ino = dp->d_ino; 311 } 312 return (dp); 313 } 314 315 /* 316 * Lookup the requested name in directory inum. 317 * Return its inode number if found, zero if it does not exist. 318 */ 319 static struct direct * 320 searchdir(inum, name) 321 ino_t inum; 322 char *name; 323 { 324 register struct direct *dp; 325 register struct inotab *itp; 326 int len; 327 328 itp = inotablookup(inum); 329 if (itp == NULL) 330 return (NULL); 331 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 332 len = strlen(name); 333 do { 334 dp = rst_readdir(dirp); 335 if (dp == NULL) 336 return (NULL); 337 } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); 338 return (dp); 339 } 340 341 /* 342 * Put the directory entries in the directory file 343 */ 344 static void 345 putdir(buf, size) 346 char *buf; 347 long size; 348 { 349 struct direct cvtbuf; 350 register struct odirect *odp; 351 struct odirect *eodp; 352 register struct direct *dp; 353 long loc, i; 354 355 if (cvtflag) { 356 eodp = (struct odirect *)&buf[size]; 357 for (odp = (struct odirect *)buf; odp < eodp; odp++) 358 if (odp->d_ino != 0) { 359 dcvt(odp, &cvtbuf); 360 putent(&cvtbuf); 361 } 362 } else { 363 for (loc = 0; loc < size; ) { 364 dp = (struct direct *)(buf + loc); 365 if (Bcvt) 366 swabst((u_char *)"ls", (u_char *) dp); 367 if (oldinofmt && dp->d_ino != 0) { 368 # if BYTE_ORDER == BIG_ENDIAN 369 if (Bcvt) 370 dp->d_namlen = dp->d_type; 371 # else 372 if (!Bcvt) 373 dp->d_namlen = dp->d_type; 374 # endif 375 dp->d_type = DT_UNKNOWN; 376 } 377 i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 378 if ((dp->d_reclen & 0x3) != 0 || 379 dp->d_reclen > i || 380 dp->d_reclen < DIRSIZ(0, dp) || 381 dp->d_namlen > NAME_MAX) { 382 vprintf(stdout, "Mangled directory: "); 383 if ((dp->d_reclen & 0x3) != 0) 384 vprintf(stdout, 385 "reclen not multiple of 4 "); 386 if (dp->d_reclen < DIRSIZ(0, dp)) 387 vprintf(stdout, 388 "reclen less than DIRSIZ (%d < %d) ", 389 dp->d_reclen, DIRSIZ(0, dp)); 390 if (dp->d_namlen > NAME_MAX) 391 vprintf(stdout, 392 "reclen name too big (%d > %d) ", 393 dp->d_namlen, NAME_MAX); 394 vprintf(stdout, "\n"); 395 loc += i; 396 continue; 397 } 398 loc += dp->d_reclen; 399 if (dp->d_ino != 0) { 400 putent(dp); 401 } 402 } 403 } 404 } 405 406 /* 407 * These variables are "local" to the following two functions. 408 */ 409 char dirbuf[DIRBLKSIZ]; 410 long dirloc = 0; 411 long prev = 0; 412 413 /* 414 * add a new directory entry to a file. 415 */ 416 static void 417 putent(dp) 418 struct direct *dp; 419 { 420 dp->d_reclen = DIRSIZ(0, dp); 421 if (dirloc + dp->d_reclen > DIRBLKSIZ) { 422 ((struct direct *)(dirbuf + prev))->d_reclen = 423 DIRBLKSIZ - prev; 424 (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 425 dirloc = 0; 426 } 427 memmove(dirbuf + dirloc, dp, (long)dp->d_reclen); 428 prev = dirloc; 429 dirloc += dp->d_reclen; 430 } 431 432 /* 433 * flush out a directory that is finished. 434 */ 435 static void 436 flushent() 437 { 438 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 439 (void) fwrite(dirbuf, (int)dirloc, 1, df); 440 seekpt = ftell(df); 441 dirloc = 0; 442 } 443 444 static void 445 dcvt(odp, ndp) 446 register struct odirect *odp; 447 register struct direct *ndp; 448 { 449 450 memset(ndp, 0, (long)(sizeof *ndp)); 451 ndp->d_ino = odp->d_ino; 452 ndp->d_type = DT_UNKNOWN; 453 (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 454 ndp->d_namlen = strlen(ndp->d_name); 455 ndp->d_reclen = DIRSIZ(0, ndp); 456 } 457 458 /* 459 * Seek to an entry in a directory. 460 * Only values returned by rst_telldir should be passed to rst_seekdir. 461 * This routine handles many directories in a single file. 462 * It takes the base of the directory in the file, plus 463 * the desired seek offset into it. 464 */ 465 static void 466 rst_seekdir(dirp, loc, base) 467 register RST_DIR *dirp; 468 long loc, base; 469 { 470 471 if (loc == rst_telldir(dirp)) 472 return; 473 loc -= base; 474 if (loc < 0) 475 fprintf(stderr, "bad seek pointer to rst_seekdir %ld\n", loc); 476 (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); 477 dirp->dd_loc = loc & (DIRBLKSIZ - 1); 478 if (dirp->dd_loc != 0) 479 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 480 } 481 482 /* 483 * get next entry in a directory. 484 */ 485 struct direct * 486 rst_readdir(dirp) 487 register RST_DIR *dirp; 488 { 489 register struct direct *dp; 490 491 for (;;) { 492 if (dirp->dd_loc == 0) { 493 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 494 DIRBLKSIZ); 495 if (dirp->dd_size <= 0) { 496 dprintf(stderr, "error reading directory\n"); 497 return (NULL); 498 } 499 } 500 if (dirp->dd_loc >= dirp->dd_size) { 501 dirp->dd_loc = 0; 502 continue; 503 } 504 dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 505 if (dp->d_reclen == 0 || 506 dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 507 dprintf(stderr, "corrupted directory: bad reclen %d\n", 508 dp->d_reclen); 509 return (NULL); 510 } 511 dirp->dd_loc += dp->d_reclen; 512 if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) 513 return (NULL); 514 if (dp->d_ino >= maxino) { 515 dprintf(stderr, "corrupted directory: bad inum %d\n", 516 dp->d_ino); 517 continue; 518 } 519 return (dp); 520 } 521 } 522 523 /* 524 * Simulate the opening of a directory 525 */ 526 RST_DIR * 527 rst_opendir(name) 528 const char *name; 529 { 530 struct inotab *itp; 531 RST_DIR *dirp; 532 ino_t ino; 533 534 if ((ino = dirlookup(name)) > 0 && 535 (itp = inotablookup(ino)) != NULL) { 536 dirp = opendirfile(dirfile); 537 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 538 return (dirp); 539 } 540 return (NULL); 541 } 542 543 /* 544 * In our case, there is nothing to do when closing a directory. 545 */ 546 void 547 rst_closedir(dirp) 548 RST_DIR *dirp; 549 { 550 551 (void)close(dirp->dd_fd); 552 free(dirp); 553 return; 554 } 555 556 /* 557 * Simulate finding the current offset in the directory. 558 */ 559 static long 560 rst_telldir(dirp) 561 RST_DIR *dirp; 562 { 563 return ((long)lseek(dirp->dd_fd, 564 (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc); 565 } 566 567 /* 568 * Open a directory file. 569 */ 570 static RST_DIR * 571 opendirfile(name) 572 const char *name; 573 { 574 register RST_DIR *dirp; 575 register int fd; 576 577 if ((fd = open(name, O_RDONLY)) == -1) 578 return (NULL); 579 if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { 580 (void)close(fd); 581 return (NULL); 582 } 583 dirp->dd_fd = fd; 584 dirp->dd_loc = 0; 585 return (dirp); 586 } 587 588 /* 589 * Set the mode, owner, and times for all new or changed directories 590 */ 591 void 592 setdirmodes(flags) 593 int flags; 594 { 595 FILE *mf; 596 struct modeinfo node; 597 struct entry *ep; 598 char *cp; 599 const char *tmpdir; 600 601 vprintf(stdout, "Set directory mode, owner, and times.\n"); 602 if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0') 603 tmpdir = _PATH_TMP; 604 if (command == 'r' || command == 'R') 605 (void) sprintf(modefile, "%s/rstmode%d", tmpdir, dumpdate); 606 if (modefile[0] == '#') { 607 panic("modefile not defined\n"); 608 fprintf(stderr, "directory mode, owner, and times not set\n"); 609 return; 610 } 611 mf = fopen(modefile, "r"); 612 if (mf == NULL) { 613 fprintf(stderr, "fopen: %s\n", strerror(errno)); 614 fprintf(stderr, "cannot open mode file %s\n", modefile); 615 fprintf(stderr, "directory mode, owner, and times not set\n"); 616 return; 617 } 618 clearerr(mf); 619 for (;;) { 620 (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 621 if (feof(mf)) 622 break; 623 ep = lookupino(node.ino); 624 if (command == 'i' || command == 'x') { 625 if (ep == NULL) 626 continue; 627 if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { 628 ep->e_flags &= ~NEW; 629 continue; 630 } 631 if (node.ino == ROOTINO && 632 reply("set owner/mode for '.'") == FAIL) 633 continue; 634 } 635 if (ep == NULL) { 636 panic("cannot find directory inode %d\n", node.ino); 637 } else { 638 cp = myname(ep); 639 if (!Nflag) { 640 (void) chown(cp, node.uid, node.gid); 641 (void) chmod(cp, node.mode); 642 utimes(cp, node.timep); 643 (void) chflags(cp, node.flags); 644 } 645 ep->e_flags &= ~NEW; 646 } 647 } 648 if (ferror(mf)) 649 panic("error setting directory modes\n"); 650 (void) fclose(mf); 651 } 652 653 /* 654 * Generate a literal copy of a directory. 655 */ 656 int 657 genliteraldir(name, ino) 658 char *name; 659 ino_t ino; 660 { 661 register struct inotab *itp; 662 int ofile, dp, i, size; 663 char buf[BUFSIZ]; 664 665 itp = inotablookup(ino); 666 if (itp == NULL) 667 panic("Cannot find directory inode %d named %s\n", ino, name); 668 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { 669 fprintf(stderr, "%s: ", name); 670 (void) fflush(stderr); 671 fprintf(stderr, "cannot create file: %s\n", strerror(errno)); 672 return (FAIL); 673 } 674 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 675 dp = dup(dirp->dd_fd); 676 for (i = itp->t_size; i > 0; i -= BUFSIZ) { 677 size = i < BUFSIZ ? i : BUFSIZ; 678 if (read(dp, buf, (int) size) == -1) { 679 fprintf(stderr, 680 "write error extracting inode %d, name %s\n", 681 curfile.ino, curfile.name); 682 fprintf(stderr, "read: %s\n", strerror(errno)); 683 done(1); 684 } 685 if (!Nflag && write(ofile, buf, (int) size) == -1) { 686 fprintf(stderr, 687 "write error extracting inode %d, name %s\n", 688 curfile.ino, curfile.name); 689 fprintf(stderr, "write: %s\n", strerror(errno)); 690 done(1); 691 } 692 } 693 (void) close(dp); 694 (void) close(ofile); 695 return (GOOD); 696 } 697 698 /* 699 * Determine the type of an inode 700 */ 701 int 702 inodetype(ino) 703 ino_t ino; 704 { 705 struct inotab *itp; 706 707 itp = inotablookup(ino); 708 if (itp == NULL) 709 return (LEAF); 710 return (NODE); 711 } 712 713 /* 714 * Allocate and initialize a directory inode entry. 715 * If requested, save its pertinent mode, owner, and time info. 716 */ 717 static struct inotab * 718 allocinotab(ino, dip, seekpt) 719 ino_t ino; 720 struct dinode *dip; 721 long seekpt; 722 { 723 register struct inotab *itp; 724 struct modeinfo node; 725 726 itp = calloc(1, sizeof(struct inotab)); 727 if (itp == NULL) 728 panic("no memory directory table\n"); 729 itp->t_next = inotab[INOHASH(ino)]; 730 inotab[INOHASH(ino)] = itp; 731 itp->t_ino = ino; 732 itp->t_seekpt = seekpt; 733 if (mf == NULL) 734 return (itp); 735 node.ino = ino; 736 node.timep[0].tv_sec = dip->di_atime; 737 node.timep[0].tv_usec = dip->di_atimensec / 1000; 738 node.timep[1].tv_sec = dip->di_mtime; 739 node.timep[1].tv_usec = dip->di_mtimensec / 1000; 740 node.mode = dip->di_mode; 741 node.flags = dip->di_flags; 742 node.uid = dip->di_uid; 743 node.gid = dip->di_gid; 744 (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 745 return (itp); 746 } 747 748 /* 749 * Look up an inode in the table of directories 750 */ 751 static struct inotab * 752 inotablookup(ino) 753 ino_t ino; 754 { 755 register struct inotab *itp; 756 757 for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 758 if (itp->t_ino == ino) 759 return (itp); 760 return (NULL); 761 } 762 763 /* 764 * Clean up and exit 765 */ 766 void 767 done(exitcode) 768 int exitcode; 769 { 770 771 closemt(); 772 if (modefile[0] != '#') 773 (void) unlink(modefile); 774 if (dirfile[0] != '#') 775 (void) unlink(dirfile); 776 exit(exitcode); 777 } 778