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