home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / fsck / inode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  12.1 KB  |  532 lines

  1. /*
  2.  * Copyright (c) 1980, 1986 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[] = "@(#)inode.c    5.18 (Berkeley) 3/19/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <ufs/dinode.h>
  40. #include <ufs/fs.h>
  41. #include <ufs/dir.h>
  42. #include <pwd.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include "fsck.h"
  46.  
  47. static ino_t startinum;
  48.  
  49. ckinode(dp, idesc)
  50.     struct dinode *dp;
  51.     register struct inodesc *idesc;
  52. {
  53.     register daddr_t *ap;
  54.     long ret, n, ndb, offset;
  55.     struct dinode dino;
  56.  
  57.     if (idesc->id_fix != IGNORE)
  58.         idesc->id_fix = DONTKNOW;
  59.     idesc->id_entryno = 0;
  60.     idesc->id_filesize = dp->di_size;
  61.     if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR)
  62.         return (KEEPON);
  63.     dino = *dp;
  64.     ndb = howmany(dino.di_size, sblock.fs_bsize);
  65.     for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
  66.         if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
  67.             idesc->id_numfrags =
  68.                 numfrags(&sblock, fragroundup(&sblock, offset));
  69.         else
  70.             idesc->id_numfrags = sblock.fs_frag;
  71.         if (*ap == 0)
  72.             continue;
  73.         idesc->id_blkno = *ap;
  74.         if (idesc->id_type == ADDR)
  75.             ret = (*idesc->id_func)(idesc);
  76.         else
  77.             ret = dirscan(idesc);
  78.         if (ret & STOP)
  79.             return (ret);
  80.     }
  81.     idesc->id_numfrags = sblock.fs_frag;
  82.     for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
  83.         if (*ap) {
  84.             idesc->id_blkno = *ap;
  85.             ret = iblock(idesc, n,
  86.                 dino.di_size - sblock.fs_bsize * NDADDR);
  87.             if (ret & STOP)
  88.                 return (ret);
  89.         }
  90.     }
  91.     return (KEEPON);
  92. }
  93.  
  94. iblock(idesc, ilevel, isize)
  95.     struct inodesc *idesc;
  96.     register long ilevel;
  97.     u_long isize;
  98. {
  99.     register daddr_t *ap;
  100.     register daddr_t *aplim;
  101.     int i, n, (*func)(), nif, sizepb;
  102.     register struct bufarea *bp;
  103.     char buf[BUFSIZ];
  104.     extern int dirscan(), pass1check();
  105.  
  106.     if (idesc->id_type == ADDR) {
  107.         func = idesc->id_func;
  108.         if (((n = (*func)(idesc)) & KEEPON) == 0)
  109.             return (n);
  110.     } else
  111.         func = dirscan;
  112.     if (chkrange(idesc->id_blkno, idesc->id_numfrags))
  113.         return (SKIP);
  114.     bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
  115.     ilevel--;
  116.     for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
  117.         sizepb *= NINDIR(&sblock);
  118.     nif = isize / sizepb + 1;
  119.     if (nif > NINDIR(&sblock))
  120.         nif = NINDIR(&sblock);
  121.     if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
  122.         aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
  123.         for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
  124.             if (*ap == 0)
  125.                 continue;
  126.             (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
  127.                 idesc->id_number);
  128.             if (dofix(idesc, buf)) {
  129.                 *ap = 0;
  130.                 dirty(bp);
  131.             }
  132.         }
  133.         flush(fswritefd, bp);
  134.     }
  135.     aplim = &bp->b_un.b_indir[nif];
  136.     for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) {
  137.         if (*ap) {
  138.             idesc->id_blkno = *ap;
  139.             if (ilevel > 0)
  140.                 n = iblock(idesc, ilevel, isize - i * sizepb);
  141.             else
  142.                 n = (*func)(idesc);
  143.             if (n & STOP) {
  144.                 bp->b_flags &= ~B_INUSE;
  145.                 return (n);
  146.             }
  147.         }
  148.     }
  149.     bp->b_flags &= ~B_INUSE;
  150.     return (KEEPON);
  151. }
  152.  
  153. /*
  154.  * Check that a block in a legal block number.
  155.  * Return 0 if in range, 1 if out of range.
  156.  */
  157. chkrange(blk, cnt)
  158.     daddr_t blk;
  159.     int cnt;
  160. {
  161.     register int c;
  162.  
  163.     if ((unsigned)(blk + cnt) > maxfsblock)
  164.         return (1);
  165.     c = dtog(&sblock, blk);
  166.     if (blk < cgdmin(&sblock, c)) {
  167.         if ((blk + cnt) > cgsblock(&sblock, c)) {
  168.             if (debug) {
  169.                 printf("blk %ld < cgdmin %ld;",
  170.                     blk, cgdmin(&sblock, c));
  171.                 printf(" blk + cnt %ld > cgsbase %ld\n",
  172.                     blk + cnt, cgsblock(&sblock, c));
  173.             }
  174.             return (1);
  175.         }
  176.     } else {
  177.         if ((blk + cnt) > cgbase(&sblock, c+1)) {
  178.             if (debug)  {
  179.                 printf("blk %ld >= cgdmin %ld;",
  180.                     blk, cgdmin(&sblock, c));
  181.                 printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
  182.                     blk+cnt, sblock.fs_fpg);
  183.             }
  184.             return (1);
  185.         }
  186.     }
  187.     return (0);
  188. }
  189.  
  190. /*
  191.  * General purpose interface for reading inodes.
  192.  */
  193. struct dinode *
  194. ginode(inumber)
  195.     ino_t inumber;
  196. {
  197.     daddr_t iblk;
  198.  
  199.     if (inumber < ROOTINO || inumber > maxino)
  200.         errexit("bad inode number %d to ginode\n", inumber);
  201.     if (startinum == 0 ||
  202.         inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
  203.         iblk = itod(&sblock, inumber);
  204.         if (pbp != 0)
  205.             pbp->b_flags &= ~B_INUSE;
  206.         pbp = getdatablk(iblk, sblock.fs_bsize);
  207.         startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
  208.     }
  209.     return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
  210. }
  211.  
  212. /*
  213.  * Special purpose version of ginode used to optimize first pass
  214.  * over all the inodes in numerical order.
  215.  */
  216. ino_t nextino, lastinum;
  217. long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
  218. struct dinode *inodebuf;
  219.  
  220. struct dinode *
  221. getnextinode(inumber)
  222.     ino_t inumber;
  223. {
  224.     long size;
  225.     daddr_t dblk;
  226.     static struct dinode *dp;
  227.  
  228.     if (inumber != nextino++ || inumber > maxino)
  229.         errexit("bad inode number %d to nextinode\n", inumber);
  230.     if (inumber >= lastinum) {
  231.         readcnt++;
  232.         dblk = fsbtodb(&sblock, itod(&sblock, lastinum));
  233.         if (readcnt % readpercg == 0) {
  234.             size = partialsize;
  235.             lastinum += partialcnt;
  236.         } else {
  237.             size = inobufsize;
  238.             lastinum += fullcnt;
  239.         }
  240.         (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
  241.         dp = inodebuf;
  242.     }
  243.     return (dp++);
  244. }
  245.  
  246. resetinodebuf()
  247. {
  248.  
  249.     startinum = 0;
  250.     nextino = 0;
  251.     lastinum = 0;
  252.     readcnt = 0;
  253.     inobufsize = blkroundup(&sblock, INOBUFSIZE);
  254.     fullcnt = inobufsize / sizeof(struct dinode);
  255.     readpercg = sblock.fs_ipg / fullcnt;
  256.     partialcnt = sblock.fs_ipg % fullcnt;
  257.     partialsize = partialcnt * sizeof(struct dinode);
  258.     if (partialcnt != 0) {
  259.         readpercg++;
  260.     } else {
  261.         partialcnt = fullcnt;
  262.         partialsize = inobufsize;
  263.     }
  264.     if (inodebuf == NULL &&
  265.         (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
  266.         errexit("Cannot allocate space for inode buffer\n");
  267.     while (nextino < ROOTINO)
  268.         (void)getnextinode(nextino);
  269. }
  270.  
  271. freeinodebuf()
  272. {
  273.  
  274.     if (inodebuf != NULL)
  275.         free((char *)inodebuf);
  276.     inodebuf = NULL;
  277. }
  278.  
  279. /*
  280.  * Routines to maintain information about directory inodes.
  281.  * This is built during the first pass and used during the
  282.  * second and third passes.
  283.  *
  284.  * Enter inodes into the cache.
  285.  */
  286. cacheino(dp, inumber)
  287.     register struct dinode *dp;
  288.     ino_t inumber;
  289. {
  290.     register struct inoinfo *inp;
  291.     struct inoinfo **inpp;
  292.     unsigned int blks;
  293.  
  294.     blks = howmany(dp->di_size, sblock.fs_bsize);
  295.     if (blks > NDADDR)
  296.         blks = NDADDR + NIADDR;
  297.     inp = (struct inoinfo *)
  298.         malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
  299.     if (inp == NULL)
  300.         return;
  301.     inpp = &inphead[inumber % numdirs];
  302.     inp->i_nexthash = *inpp;
  303.     *inpp = inp;
  304.     inp->i_parent = (ino_t)0;
  305.     inp->i_dotdot = (ino_t)0;
  306.     inp->i_number = inumber;
  307.     inp->i_isize = dp->di_size;
  308.     inp->i_numblks = blks * sizeof(daddr_t);
  309.     bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
  310.         (size_t)inp->i_numblks);
  311.     if (inplast == listmax) {
  312.         listmax += 100;
  313.         inpsort = (struct inoinfo **)realloc((char *)inpsort,
  314.             (unsigned)listmax * sizeof(struct inoinfo *));
  315.         if (inpsort == NULL)
  316.             errexit("cannot increase directory list");
  317.     }
  318.     inpsort[inplast++] = inp;
  319. }
  320.  
  321. /*
  322.  * Look up an inode cache structure.
  323.  */
  324. struct inoinfo *
  325. getinoinfo(inumber)
  326.     ino_t inumber;
  327. {
  328.     register struct inoinfo *inp;
  329.  
  330.     for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
  331.         if (inp->i_number != inumber)
  332.             continue;
  333.         return (inp);
  334.     }
  335.     errexit("cannot find inode %d\n", inumber);
  336.     return ((struct inoinfo *)0);
  337. }
  338.  
  339. /*
  340.  * Clean up all the inode cache structure.
  341.  */
  342. inocleanup()
  343. {
  344.     register struct inoinfo **inpp;
  345.  
  346.     if (inphead == NULL)
  347.         return;
  348.     for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
  349.         free((char *)(*inpp));
  350.     free((char *)inphead);
  351.     free((char *)inpsort);
  352.     inphead = inpsort = NULL;
  353. }
  354.     
  355. inodirty()
  356. {
  357.     
  358.     dirty(pbp);
  359. }
  360.  
  361. clri(idesc, type, flag)
  362.     register struct inodesc *idesc;
  363.     char *type;
  364.     int flag;
  365. {
  366.     register struct dinode *dp;
  367.  
  368.     dp = ginode(idesc->id_number);
  369.     if (flag == 1) {
  370.         pwarn("%s %s", type,
  371.             (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
  372.         pinode(idesc->id_number);
  373.     }
  374.     if (preen || reply("CLEAR") == 1) {
  375.         if (preen)
  376.             printf(" (CLEARED)\n");
  377.         n_files--;
  378.         (void)ckinode(dp, idesc);
  379.         clearinode(dp);
  380.         statemap[idesc->id_number] = USTATE;
  381.         inodirty();
  382.     }
  383. }
  384.  
  385. findname(idesc)
  386.     struct inodesc *idesc;
  387. {
  388.     register struct direct *dirp = idesc->id_dirp;
  389.  
  390.     if (dirp->d_ino != idesc->id_parent)
  391.         return (KEEPON);
  392.     bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
  393.     return (STOP|FOUND);
  394. }
  395.  
  396. findino(idesc)
  397.     struct inodesc *idesc;
  398. {
  399.     register struct direct *dirp = idesc->id_dirp;
  400.  
  401.     if (dirp->d_ino == 0)
  402.         return (KEEPON);
  403.     if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
  404.         dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
  405.         idesc->id_parent = dirp->d_ino;
  406.         return (STOP|FOUND);
  407.     }
  408.     return (KEEPON);
  409. }
  410.  
  411. pinode(ino)
  412.     ino_t ino;
  413. {
  414.     register struct dinode *dp;
  415.     register char *p;
  416.     struct passwd *pw;
  417.     char *ctime();
  418.  
  419.     printf(" I=%lu ", ino);
  420.     if (ino < ROOTINO || ino > maxino)
  421.         return;
  422.     dp = ginode(ino);
  423.     printf(" OWNER=");
  424.     if ((pw = getpwuid((int)dp->di_uid)) != 0)
  425.         printf("%s ", pw->pw_name);
  426.     else
  427.         printf("%u ", (unsigned)dp->di_uid);
  428.     printf("MODE=%o\n", dp->di_mode);
  429.     if (preen)
  430.         printf("%s: ", devname);
  431.     printf("SIZE=%lu ", dp->di_size);
  432.     p = ctime(&dp->di_mtime);
  433.     printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
  434. }
  435.  
  436. blkerror(ino, type, blk)
  437.     ino_t ino;
  438.     char *type;
  439.     daddr_t blk;
  440. {
  441.  
  442.     pfatal("%ld %s I=%lu", blk, type, ino);
  443.     printf("\n");
  444.     switch (statemap[ino]) {
  445.  
  446.     case FSTATE:
  447.         statemap[ino] = FCLEAR;
  448.         return;
  449.  
  450.     case DSTATE:
  451.         statemap[ino] = DCLEAR;
  452.         return;
  453.  
  454.     case FCLEAR:
  455.     case DCLEAR:
  456.         return;
  457.  
  458.     default:
  459.         errexit("BAD STATE %d TO BLKERR", statemap[ino]);
  460.         /* NOTREACHED */
  461.     }
  462. }
  463.  
  464. /*
  465.  * allocate an unused inode
  466.  */
  467. ino_t
  468. allocino(request, type)
  469.     ino_t request;
  470.     int type;
  471. {
  472.     register ino_t ino;
  473.     register struct dinode *dp;
  474.  
  475.     if (request == 0)
  476.         request = ROOTINO;
  477.     else if (statemap[request] != USTATE)
  478.         return (0);
  479.     for (ino = request; ino < maxino; ino++)
  480.         if (statemap[ino] == USTATE)
  481.             break;
  482.     if (ino == maxino)
  483.         return (0);
  484.     switch (type & IFMT) {
  485.     case IFDIR:
  486.         statemap[ino] = DSTATE;
  487.         break;
  488.     case IFREG:
  489.     case IFLNK:
  490.         statemap[ino] = FSTATE;
  491.         break;
  492.     default:
  493.         return (0);
  494.     }
  495.     dp = ginode(ino);
  496.     dp->di_db[0] = allocblk((long)1);
  497.     if (dp->di_db[0] == 0) {
  498.         statemap[ino] = USTATE;
  499.         return (0);
  500.     }
  501.     dp->di_mode = type;
  502.     (void)time(&dp->di_atime);
  503.     dp->di_mtime = dp->di_ctime = dp->di_atime;
  504.     dp->di_size = sblock.fs_fsize;
  505.     dp->di_blocks = btodb(sblock.fs_fsize);
  506.     n_files++;
  507.     inodirty();
  508.     return (ino);
  509. }
  510.  
  511. /*
  512.  * deallocate an inode
  513.  */
  514. freeino(ino)
  515.     ino_t ino;
  516. {
  517.     struct inodesc idesc;
  518.     extern int pass4check();
  519.     struct dinode *dp;
  520.  
  521.     bzero((char *)&idesc, sizeof(struct inodesc));
  522.     idesc.id_type = ADDR;
  523.     idesc.id_func = pass4check;
  524.     idesc.id_number = ino;
  525.     dp = ginode(ino);
  526.     (void)ckinode(dp, &idesc);
  527.     clearinode(dp);
  528.     inodirty();
  529.     statemap[ino] = USTATE;
  530.     n_files--;
  531. }
  532.