-daddr_t
-bmap(ip, bn, rwflg)
-register struct inode *ip;
-daddr_t bn;
-{
- register i;
- struct buf *bp, *nbp;
- int j, sh;
- daddr_t nb, *bap;
- dev_t dev;
-
- if(bn < 0) {
- u.u_error = EFBIG;
- return((daddr_t)0);
- }
- dev = ip->i_dev;
- rablock = 0;
-
- /*
- * blocks 0..NADDR-4 are direct blocks
- */
- if(bn < NADDR-3) {
- i = bn;
- nb = ip->i_un.i_addr[i];
- if(nb == 0) {
- if(rwflg==B_READ || (bp = alloc(dev))==NULL)
- return((daddr_t)-1);
- nb = dbtofsb(bp->b_blkno);
- if ((ip->i_mode&IFMT) == IFDIR)
- /*
- * Write directory blocks synchronously
- * so they never appear with garbage in
- * them on the disk.
- */
- bwrite(bp);
- else
- bdwrite(bp);
- ip->i_un.i_addr[i] = nb;
- ip->i_flag |= IUPD|ICHG;
- }
- if(i < NADDR-4)
- rablock = ip->i_un.i_addr[i+1];
- return(nb);
- }
-
- /*
- * addresses NADDR-3, NADDR-2, and NADDR-1
- * have single, double, triple indirect blocks.
- * the first step is to determine
- * how many levels of indirection.
- */
- sh = 0;
- nb = 1;
- bn -= NADDR-3;
- for(j=3; j>0; j--) {
- sh += NSHIFT;
- nb <<= NSHIFT;
- if(bn < nb)
- break;
- bn -= nb;
- }
- if(j == 0) {
- u.u_error = EFBIG;
- return((daddr_t)0);
- }
-
- /*
- * fetch the first indirect block
- */
- nb = ip->i_un.i_addr[NADDR-j];
- if(nb == 0) {
- if(rwflg==B_READ || (bp = alloc(dev))==NULL)
- return((daddr_t)-1);
- nb = dbtofsb(bp->b_blkno);
- /*
- * Write synchronously so that indirect blocks
- * never point at garbage.
- */
- bwrite(bp);
- ip->i_un.i_addr[NADDR-j] = nb;
- ip->i_flag |= IUPD|ICHG;
- }
-
- /*
- * fetch through the indirect blocks
- */
- for(; j<=3; j++) {
- bp = bread(dev, nb);
- if(bp->b_flags & B_ERROR) {
- brelse(bp);
- return((daddr_t)0);
- }
- bap = bp->b_un.b_daddr;
- sh -= NSHIFT;
- i = (bn>>sh) & NMASK;
- nb = bap[i];
- if(nb == 0) {
- if(rwflg==B_READ || (nbp = alloc(dev))==NULL) {
- brelse(bp);
- return((daddr_t)-1);
- }
- nb = dbtofsb(nbp->b_blkno);
- if (j < 3 || (ip->i_mode&IFMT) == IFDIR)
- /*
- * Write synchronously so indirect blocks
- * never point at garbage and blocks
- * in directories never contain garbage.
- */
- bwrite(nbp);
- else
- bdwrite(nbp);
- bap[i] = nb;
- bdwrite(bp);
- } else
- brelse(bp);
- }
-
- /*
- * calculate read-ahead.
- */
- if(i < NINDIR-1)
- rablock = bap[i+1];
- return(nb);
-}