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