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