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