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