1 /* $NetBSD: dirs.c,v 1.40 2003/11/05 22:27:16 fvdl 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.40 2003/11/05 22:27:16 fvdl 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 __P((FILE *, struct context *, long)); 127 static void dcvt __P((struct odirect *, struct direct *)); 128 static void flushent __P((void)); 129 static struct inotab *inotablookup __P((ino_t)); 130 static RST_DIR *opendirfile __P((const char *)); 131 static void putdir __P((char *, long)); 132 static void putent __P((struct direct *)); 133 static void rst_seekdir __P((RST_DIR *, long, long)); 134 static long rst_telldir __P((RST_DIR *)); 135 static struct direct *searchdir __P((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(genmode) 145 int genmode; 146 { 147 FILE *mf; 148 int i, dfd, mfd; 149 struct inotab *itp; 150 struct direct nulldir; 151 152 mf = NULL; 153 vprintf(stdout, "Extract directories from tape\n"); 154 (void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%d", 155 tmpdir, (int)dumpdate); 156 if (command != 'r' && command != 'R') { 157 (void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%d-XXXXXX", 158 tmpdir, (int)dumpdate); 159 if ((dfd = mkstemp(dirfile)) == -1) 160 err(1, "cannot mkstemp temporary file %s", dirfile); 161 df = fdopen(dfd, "w"); 162 } 163 else 164 df = fopen(dirfile, "w"); 165 if (df == NULL) 166 err(1, "cannot open temporary file %s", dirfile); 167 168 if (genmode != 0) { 169 (void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d", 170 tmpdir, (int)dumpdate); 171 if (command != 'r' && command != 'R') { 172 (void) snprintf(modefile, sizeof(modefile), 173 "%s/rstmode%d-XXXXXX", tmpdir, (int)dumpdate); 174 if ((mfd = mkstemp(modefile)) == -1) 175 err(1, "cannot mkstemp temporary file %s", 176 modefile); 177 mf = fdopen(mfd, "w"); 178 } 179 else 180 mf = fopen(modefile, "w"); 181 if (mf == NULL) 182 err(1, "cannot open temporary file %s", modefile); 183 } 184 nulldir.d_ino = 0; 185 nulldir.d_type = DT_DIR; 186 nulldir.d_namlen = 1; 187 (void) strcpy(nulldir.d_name, "/"); 188 nulldir.d_reclen = DIRSIZ(0, &nulldir, 0); 189 for (;;) { 190 curfile.name = "<directory file - name unknown>"; 191 curfile.action = USING; 192 if (curfile.mode == 0 || (curfile.mode & IFMT) != IFDIR) { 193 (void) fclose(df); 194 dirp = opendirfile(dirfile); 195 if (dirp == NULL) 196 fprintf(stderr, "opendirfile: %s\n", 197 strerror(errno)); 198 if (mf != NULL) 199 (void) fclose(mf); 200 i = dirlookup(dot); 201 if (i == 0) 202 panic("Root directory is not on tape\n"); 203 return; 204 } 205 itp = allocinotab(mf, &curfile, seekpt); 206 getfile(putdir, xtrnull); 207 putent(&nulldir); 208 flushent(); 209 itp->t_size = seekpt - itp->t_seekpt; 210 } 211 } 212 213 /* 214 * skip over all the directories on the tape 215 */ 216 void 217 skipdirs() 218 { 219 220 while (curfile.ino && (curfile.mode & IFMT) == IFDIR) { 221 skipfile(); 222 } 223 } 224 225 /* 226 * Recursively find names and inumbers of all files in subtree 227 * pname and pass them off to be processed. 228 */ 229 void 230 treescan(pname, ino, todo) 231 char *pname; 232 ino_t ino; 233 long (*todo) __P((char *, ino_t, int)); 234 { 235 struct inotab *itp; 236 struct direct *dp; 237 int namelen; 238 long bpt; 239 char locname[MAXPATHLEN + 1]; 240 241 itp = inotablookup(ino); 242 if (itp == NULL) { 243 /* 244 * Pname is name of a simple file or an unchanged directory. 245 */ 246 (void) (*todo)(pname, ino, LEAF); 247 return; 248 } 249 /* 250 * Pname is a dumped directory name. 251 */ 252 if ((*todo)(pname, ino, NODE) == FAIL) 253 return; 254 /* 255 * begin search through the directory 256 * skipping over "." and ".." 257 */ 258 (void) snprintf(locname, sizeof(locname), "%s/", pname); 259 namelen = strlen(locname); 260 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 261 dp = rst_readdir(dirp); /* "." */ 262 if (dp != NULL && strcmp(dp->d_name, ".") == 0) 263 dp = rst_readdir(dirp); /* ".." */ 264 else 265 fprintf(stderr, "Warning: `.' missing from directory %s\n", 266 pname); 267 if (dp != NULL && strcmp(dp->d_name, "..") == 0) 268 dp = rst_readdir(dirp); /* first real entry */ 269 else 270 fprintf(stderr, "Warning: `..' missing from directory %s\n", 271 pname); 272 bpt = rst_telldir(dirp); 273 /* 274 * a zero inode signals end of directory 275 */ 276 while (dp != NULL) { 277 locname[namelen] = '\0'; 278 if (namelen + dp->d_namlen >= sizeof(locname)) { 279 fprintf(stderr, "%s%s: name exceeds %lu char\n", 280 locname, dp->d_name, (u_long)(sizeof(locname) - 1)); 281 } else { 282 (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 283 locname[namelen + dp->d_namlen] = '\0'; 284 treescan(locname, dp->d_ino, todo); 285 rst_seekdir(dirp, bpt, itp->t_seekpt); 286 } 287 dp = rst_readdir(dirp); 288 bpt = rst_telldir(dirp); 289 } 290 } 291 292 /* 293 * Lookup a pathname which is always assumed to start from the ROOTINO. 294 */ 295 struct direct * 296 pathsearch(pathname) 297 const char *pathname; 298 { 299 ino_t ino; 300 struct direct *dp; 301 char *path, *name, buffer[MAXPATHLEN]; 302 303 strcpy(buffer, pathname); 304 path = buffer; 305 ino = ROOTINO; 306 while (*path == '/') 307 path++; 308 dp = NULL; 309 while ((name = strsep(&path, "/")) != NULL && *name != '\0') { 310 if ((dp = searchdir(ino, name)) == NULL) 311 return (NULL); 312 ino = dp->d_ino; 313 } 314 return (dp); 315 } 316 317 /* 318 * Lookup the requested name in directory inum. 319 * Return its inode number if found, zero if it does not exist. 320 */ 321 static struct direct * 322 searchdir(inum, name) 323 ino_t inum; 324 char *name; 325 { 326 struct direct *dp; 327 struct inotab *itp; 328 int len; 329 330 itp = inotablookup(inum); 331 if (itp == NULL) 332 return (NULL); 333 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 334 len = strlen(name); 335 do { 336 dp = rst_readdir(dirp); 337 if (dp == NULL) 338 return (NULL); 339 } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); 340 return (dp); 341 } 342 343 /* 344 * Put the directory entries in the directory file 345 */ 346 static void 347 putdir(buf, size) 348 char *buf; 349 long size; 350 { 351 struct direct cvtbuf; 352 struct odirect *odp; 353 struct odirect *eodp; 354 struct direct *dp; 355 long loc, i; 356 357 if (cvtflag) { 358 eodp = (struct odirect *)&buf[size]; 359 for (odp = (struct odirect *)buf; odp < eodp; odp++) 360 if (odp->d_ino != 0) { 361 dcvt(odp, &cvtbuf); 362 putent(&cvtbuf); 363 } 364 } else { 365 for (loc = 0; loc < size; ) { 366 dp = (struct direct *)(buf + loc); 367 if (Bcvt) { 368 dp->d_ino = bswap32(dp->d_ino); 369 dp->d_reclen = bswap16(dp->d_reclen); 370 } 371 if (oldinofmt && dp->d_ino != 0) { 372 # if BYTE_ORDER == BIG_ENDIAN 373 if (Bcvt) 374 dp->d_namlen = dp->d_type; 375 # else 376 if (!Bcvt) 377 dp->d_namlen = dp->d_type; 378 # endif 379 dp->d_type = DT_UNKNOWN; 380 } 381 i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 382 if ((dp->d_reclen & 0x3) != 0 || 383 dp->d_reclen > i || 384 dp->d_reclen < DIRSIZ(0, dp, 0) /* || 385 dp->d_namlen > NAME_MAX */) { 386 vprintf(stdout, "Mangled directory: "); 387 if ((dp->d_reclen & 0x3) != 0) 388 vprintf(stdout, 389 "reclen not multiple of 4 "); 390 if (dp->d_reclen < DIRSIZ(0, dp, 0)) 391 vprintf(stdout, 392 "reclen less than DIRSIZ (%d < %lu) ", 393 dp->d_reclen, (u_long)DIRSIZ(0, dp, 0)); 394 #if 0 /* dp->d_namlen is a uint8_t, always < NAME_MAX */ 395 if (dp->d_namlen > NAME_MAX) 396 vprintf(stdout, 397 "reclen name too big (%d > %d) ", 398 dp->d_namlen, NAME_MAX); 399 #endif 400 vprintf(stdout, "\n"); 401 loc += i; 402 continue; 403 } 404 loc += dp->d_reclen; 405 if (dp->d_ino != 0) { 406 putent(dp); 407 } 408 } 409 } 410 } 411 412 /* 413 * These variables are "local" to the following two functions. 414 */ 415 char dirbuf[DIRBLKSIZ]; 416 long dirloc = 0; 417 long prev = 0; 418 419 /* 420 * add a new directory entry to a file. 421 */ 422 static void 423 putent(dp) 424 struct direct *dp; 425 { 426 dp->d_reclen = DIRSIZ(0, dp, 0); 427 if (dirloc + dp->d_reclen > DIRBLKSIZ) { 428 ((struct direct *)(dirbuf + prev))->d_reclen = 429 DIRBLKSIZ - prev; 430 (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 431 dirloc = 0; 432 } 433 memmove(dirbuf + dirloc, dp, (long)dp->d_reclen); 434 prev = dirloc; 435 dirloc += dp->d_reclen; 436 } 437 438 /* 439 * flush out a directory that is finished. 440 */ 441 static void 442 flushent() 443 { 444 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 445 (void) fwrite(dirbuf, (int)dirloc, 1, df); 446 seekpt = ftell(df); 447 dirloc = 0; 448 } 449 450 static void 451 dcvt(odp, ndp) 452 struct odirect *odp; 453 struct direct *ndp; 454 { 455 456 memset(ndp, 0, (size_t)(sizeof *ndp)); 457 if (Bcvt) 458 ndp->d_ino = bswap16(odp->d_ino); 459 else 460 ndp->d_ino = odp->d_ino; 461 ndp->d_type = DT_UNKNOWN; 462 (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 463 ndp->d_namlen = strlen(ndp->d_name); 464 ndp->d_reclen = DIRSIZ(0, ndp, 0); 465 } 466 467 /* 468 * Seek to an entry in a directory. 469 * Only values returned by rst_telldir should be passed to rst_seekdir. 470 * This routine handles many directories in a single file. 471 * It takes the base of the directory in the file, plus 472 * the desired seek offset into it. 473 */ 474 static void 475 rst_seekdir(rdirp, loc, base) 476 RST_DIR *rdirp; 477 long loc, base; 478 { 479 480 if (loc == rst_telldir(rdirp)) 481 return; 482 loc -= base; 483 if (loc < 0) 484 fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", 485 (int)loc); 486 (void) lseek(rdirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); 487 rdirp->dd_loc = loc & (DIRBLKSIZ - 1); 488 if (rdirp->dd_loc != 0) 489 rdirp->dd_size = read(rdirp->dd_fd, rdirp->dd_buf, DIRBLKSIZ); 490 } 491 492 /* 493 * get next entry in a directory. 494 */ 495 struct direct * 496 rst_readdir(rdirp) 497 RST_DIR *rdirp; 498 { 499 struct direct *dp; 500 501 for (;;) { 502 if (rdirp->dd_loc == 0) { 503 rdirp->dd_size = read(rdirp->dd_fd, rdirp->dd_buf, 504 DIRBLKSIZ); 505 if (rdirp->dd_size <= 0) { 506 dprintf(stderr, "error reading directory\n"); 507 return (NULL); 508 } 509 } 510 if (rdirp->dd_loc >= rdirp->dd_size) { 511 rdirp->dd_loc = 0; 512 continue; 513 } 514 dp = (struct direct *)(rdirp->dd_buf + rdirp->dd_loc); 515 if (dp->d_reclen == 0 || 516 dp->d_reclen > DIRBLKSIZ + 1 - rdirp->dd_loc) { 517 dprintf(stderr, "corrupted directory: bad reclen %d\n", 518 dp->d_reclen); 519 return (NULL); 520 } 521 rdirp->dd_loc += dp->d_reclen; 522 if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) 523 return (NULL); 524 if (dp->d_ino >= maxino) { 525 dprintf(stderr, "corrupted directory: bad inum %d\n", 526 dp->d_ino); 527 continue; 528 } 529 return (dp); 530 } 531 } 532 533 /* 534 * Simulate the opening of a directory 535 */ 536 RST_DIR * 537 rst_opendir(name) 538 const char *name; 539 { 540 struct inotab *itp; 541 RST_DIR *rdirp; 542 ino_t ino; 543 544 if ((ino = dirlookup(name)) > 0 && 545 (itp = inotablookup(ino)) != NULL) { 546 rdirp = opendirfile(dirfile); 547 rst_seekdir(rdirp, itp->t_seekpt, itp->t_seekpt); 548 return (rdirp); 549 } 550 return (NULL); 551 } 552 553 /* 554 * In our case, there is nothing to do when closing a directory. 555 */ 556 void 557 rst_closedir(rdirp) 558 RST_DIR *rdirp; 559 { 560 561 (void)close(rdirp->dd_fd); 562 free(rdirp); 563 return; 564 } 565 566 /* 567 * Simulate finding the current offset in the directory. 568 */ 569 static long 570 rst_telldir(rdirp) 571 RST_DIR *rdirp; 572 { 573 return ((long)lseek(rdirp->dd_fd, 574 (off_t)0, SEEK_CUR) - rdirp->dd_size + rdirp->dd_loc); 575 } 576 577 /* 578 * Open a directory file. 579 */ 580 static RST_DIR * 581 opendirfile(name) 582 const char *name; 583 { 584 RST_DIR *rdirp; 585 int fd; 586 587 if ((fd = open(name, O_RDONLY)) == -1) 588 return (NULL); 589 if ((rdirp = malloc(sizeof(RST_DIR))) == NULL) { 590 (void)close(fd); 591 return (NULL); 592 } 593 rdirp->dd_fd = fd; 594 rdirp->dd_loc = 0; 595 return (rdirp); 596 } 597 598 /* 599 * Set the mode, owner, and times for all new or changed directories 600 */ 601 void 602 setdirmodes(flags) 603 int flags; 604 { 605 FILE *mf; 606 struct modeinfo node; 607 struct entry *ep; 608 char *cp; 609 610 vprintf(stdout, "Set directory mode, owner, and times.\n"); 611 if (command == 'r' || command == 'R') 612 (void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d", 613 tmpdir, (int)dumpdate); 614 if (modefile[0] == '#') { 615 panic("modefile not defined\n"); 616 fprintf(stderr, "directory mode, owner, and times not set\n"); 617 return; 618 } 619 mf = fopen(modefile, "r"); 620 if (mf == NULL) { 621 fprintf(stderr, "fopen: %s\n", strerror(errno)); 622 fprintf(stderr, "cannot open mode file %s\n", modefile); 623 fprintf(stderr, "directory mode, owner, and times not set\n"); 624 return; 625 } 626 clearerr(mf); 627 for (;;) { 628 (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 629 if (feof(mf)) 630 break; 631 ep = lookupino(node.ino); 632 if (command == 'i' || command == 'x') { 633 if (ep == NULL) 634 continue; 635 if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { 636 ep->e_flags &= ~NEW; 637 continue; 638 } 639 if (node.ino == ROOTINO && 640 reply("set owner/mode for '.'") == FAIL) 641 continue; 642 } 643 if (ep == NULL) { 644 panic("cannot find directory inode %d\n", node.ino); 645 } else { 646 if (!Nflag) { 647 cp = myname(ep); 648 (void) utimes(cp, node.ctimep); 649 (void) utimes(cp, node.mtimep); 650 (void) chown(cp, node.uid, node.gid); 651 (void) chmod(cp, node.mode); 652 (void) chflags(cp, node.flags); 653 } 654 ep->e_flags &= ~NEW; 655 } 656 } 657 if (ferror(mf)) 658 panic("error setting directory modes\n"); 659 (void) fclose(mf); 660 } 661 662 /* 663 * Generate a literal copy of a directory. 664 */ 665 int 666 genliteraldir(name, ino) 667 char *name; 668 ino_t ino; 669 { 670 struct inotab *itp; 671 int ofile, dp, i, size; 672 char buf[BUFSIZ]; 673 674 itp = inotablookup(ino); 675 if (itp == NULL) 676 panic("Cannot find directory inode %d named %s\n", ino, name); 677 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { 678 fprintf(stderr, "%s: ", name); 679 (void) fflush(stderr); 680 fprintf(stderr, "cannot create file: %s\n", strerror(errno)); 681 return (FAIL); 682 } 683 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 684 dp = dup(dirp->dd_fd); 685 for (i = itp->t_size; i > 0; i -= BUFSIZ) { 686 size = i < BUFSIZ ? i : BUFSIZ; 687 if (read(dp, buf, (int) size) == -1) { 688 fprintf(stderr, 689 "write error extracting inode %d, name %s\n", 690 curfile.ino, curfile.name); 691 fprintf(stderr, "read: %s\n", strerror(errno)); 692 exit(1); 693 } 694 if (!Nflag && write(ofile, buf, (int) size) == -1) { 695 fprintf(stderr, 696 "write error extracting inode %d, name %s\n", 697 curfile.ino, curfile.name); 698 fprintf(stderr, "write: %s\n", strerror(errno)); 699 exit(1); 700 } 701 } 702 (void) close(dp); 703 (void) close(ofile); 704 return (GOOD); 705 } 706 707 /* 708 * Determine the type of an inode 709 */ 710 int 711 inodetype(ino) 712 ino_t ino; 713 { 714 struct inotab *itp; 715 716 itp = inotablookup(ino); 717 if (itp == NULL) 718 return (LEAF); 719 return (NODE); 720 } 721 722 /* 723 * Allocate and initialize a directory inode entry. 724 * If requested, save its pertinent mode, owner, and time info. 725 */ 726 static struct inotab * 727 allocinotab(mf, ctxp, aseekpt) 728 FILE *mf; 729 struct context *ctxp; 730 long aseekpt; 731 { 732 struct inotab *itp; 733 struct modeinfo node; 734 735 itp = calloc(1, sizeof(struct inotab)); 736 if (itp == NULL) 737 panic("no memory directory table\n"); 738 itp->t_next = inotab[INOHASH(ctxp->ino)]; 739 inotab[INOHASH(ctxp->ino)] = itp; 740 itp->t_ino = ctxp->ino; 741 itp->t_seekpt = aseekpt; 742 if (mf == NULL) 743 return (itp); 744 node.ino = ctxp->ino; 745 node.mtimep[0].tv_sec = ctxp->atime_sec; 746 node.mtimep[0].tv_usec = ctxp->atime_nsec / 1000; 747 node.mtimep[1].tv_sec = ctxp->mtime_sec; 748 node.mtimep[1].tv_usec = ctxp->mtime_nsec / 1000; 749 node.ctimep[0].tv_sec = ctxp->atime_sec; 750 node.ctimep[0].tv_usec = ctxp->atime_nsec / 1000; 751 node.ctimep[1].tv_sec = ctxp->birthtime_sec; 752 node.ctimep[1].tv_usec = ctxp->birthtime_nsec / 1000; 753 node.mode = ctxp->mode; 754 node.flags = ctxp->file_flags; 755 node.uid = ctxp->uid; 756 node.gid = ctxp->gid; 757 (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 758 return (itp); 759 } 760 761 /* 762 * Look up an inode in the table of directories 763 */ 764 static struct inotab * 765 inotablookup(ino) 766 ino_t ino; 767 { 768 struct inotab *itp; 769 770 for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 771 if (itp->t_ino == ino) 772 return (itp); 773 return (NULL); 774 } 775 776 /* 777 * Clean up and exit 778 */ 779 void 780 cleanup() 781 { 782 783 closemt(); 784 if (modefile[0] != '#') 785 (void) unlink(modefile); 786 if (dirfile[0] != '#') 787 (void) unlink(dirfile); 788 } 789