home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / restore / dirs.c next >
Encoding:
C/C++ Source or Header  |  1992-12-01  |  17.0 KB  |  742 lines

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