- return (allerror);
-}
-
-/*
- * Release blocks associated with the inode ip and
- * stored in the indirect block bn. Blocks are free'd
- * in LIFO order up to (but not including) lastbn. If
- * level is greater than SINGLE, the block is an indirect
- * block and recursive calls to indirtrunc must be used to
- * cleanse other indirect blocks.
- *
- * NB: triple indirect blocks are untested.
- */
-indirtrunc(ip, bn, lastbn, level, countp)
- register struct inode *ip;
- daddr_t bn, lastbn;
- int level;
- long *countp;
-{
- register int i;
- struct buf *bp;
- register struct fs *fs = ip->i_fs;
- register daddr_t *bap;
- daddr_t *copy, nb, last;
- long blkcount, factor;
- int nblocks, blocksreleased = 0;
- int error, allerror = 0;
-
- /*
- * Calculate index in current block of last
- * block to be kept. -1 indicates the entire
- * block so we need not calculate the index.
- */
- factor = 1;
- for (i = SINGLE; i < level; i++)
- factor *= NINDIR(fs);
- last = lastbn;
- if (lastbn > 0)
- last /= factor;
- nblocks = btodb(fs->fs_bsize);
- /*
- * Get buffer of block pointers, zero those
- * entries corresponding to blocks to be free'd,
- * and update on disk copy first.
- */
-#ifdef SECSIZE
- bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
- fs->fs_dbsize);
-#else SECSIZE
- error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize,
- NOCRED, &bp);
- if (error) {
- brelse(bp);
- *countp = 0;
- return (error);
- }
- if ((bp->b_flags & B_CACHE) == 0)
- reassignbuf(bp, ITOV(ip));
- bap = bp->b_un.b_daddr;
- MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
- bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
- bzero((caddr_t)&bap[last + 1],
- (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
- if (last == -1)
- bp->b_flags |= B_INVAL;
- error = bwrite(bp);
- if (error)
- allerror = error;
- bap = copy;
-
- /*
- * Recursively free totally unused blocks.
- */
- for (i = NINDIR(fs) - 1; i > last; i--) {
- nb = bap[i];
- if (nb == 0)
- continue;
- if (level > SINGLE) {
- error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
- &blkcount);
- if (error)
- allerror = error;
- blocksreleased += blkcount;
- }
- blkfree(ip, nb, (off_t)fs->fs_bsize);
- blocksreleased += nblocks;
- }
-
- /*
- * Recursively free last partial block.
- */
- if (level > SINGLE && lastbn >= 0) {
- last = lastbn % factor;
- nb = bap[i];
- if (nb != 0) {
- error = indirtrunc(ip, nb, last, level - 1, &blkcount);
- if (error)
- allerror = error;
- blocksreleased += blkcount;
- }
- }
- FREE(copy, M_TEMP);
- *countp = blocksreleased;
- return (allerror);
-}
-
-/*
- * Lock an inode. If its already locked, set the WANT bit and sleep.
- */
-ilock(ip)
- register struct inode *ip;
-{
-
- while (ip->i_flag & ILOCKED) {
- ip->i_flag |= IWANT;
- if (ip->i_spare0 == u.u_procp->p_pid)
- panic("locking against myself");
- ip->i_spare1 = u.u_procp->p_pid;
- (void) sleep((caddr_t)ip, PINOD);
- }
- ip->i_spare1 = 0;
- ip->i_spare0 = u.u_procp->p_pid;
- u.u_spare[0]++;
- ip->i_flag |= ILOCKED;
-}
-
-/*
- * Unlock an inode. If WANT bit is on, wakeup.
- */
-iunlock(ip)
- register struct inode *ip;
-{
-
- if ((ip->i_flag & ILOCKED) == 0)
- vprint("iunlock: unlocked inode", ITOV(ip));
- ip->i_spare0 = 0;
- u.u_spare[0]--;
- ip->i_flag &= ~ILOCKED;
- if (ip->i_flag&IWANT) {
- ip->i_flag &= ~IWANT;
- wakeup((caddr_t)ip);
- }
-}
-
-/*
- * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
- * The mode is shifted to select the owner/group/other fields. The
- * super user is granted all permissions.
- *
- * NB: Called from vnode op table. It seems this could all be done
- * using vattr's but...
- */
-iaccess(ip, mode, cred)
- register struct inode *ip;
- register int mode;
- struct ucred *cred;
-{
- register gid_t *gp;
- int i;
-
- /*
- * If you're the super-user, you always get access.
- */
- if (cred->cr_uid == 0)
- return (0);
- /*
- * Access check is based on only one of owner, group, public.
- * If not owner, then check group. If not a member of the
- * group, then check public access.
- */
- if (cred->cr_uid != ip->i_uid) {
- mode >>= 3;
- gp = cred->cr_groups;
- for (i = 0; i < cred->cr_ngroups; i++, gp++)
- if (ip->i_gid == *gp)
- goto found;
- mode >>= 3;
-found:
- ;
- }
- if ((ip->i_mode & mode) != 0)
- return (0);
- return (EACCES);