- dqrele(ip->i_dquot);
- ip->i_dquot = NODQUOT;
-#endif
- ip->i_flag = 0;
- return (0);
-}
-
-/*
- * Check accessed and update flags on an inode structure.
- * If any is on, update the inode with the current time.
- * If waitfor is given, then must ensure I/O order,
- * so wait for write to complete.
- */
-iupdat(ip, ta, tm, waitfor)
- register struct inode *ip;
- struct timeval *ta, *tm;
- int waitfor;
-{
- struct buf *bp;
- struct vnode *vp = ITOV(ip);
- struct dinode *dp;
- register struct fs *fs;
-
- fs = ip->i_fs;
- if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
- return (0);
- if (vp->v_mount->m_flag & M_RDONLY)
- return (0);
- error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
- (int)fs->fs_bsize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return (error);
- }
- if (ip->i_flag&IACC)
- ip->i_atime = ta->tv_sec;
- if (ip->i_flag&IUPD)
- ip->i_mtime = tm->tv_sec;
- if (ip->i_flag&ICHG)
- ip->i_ctime = time.tv_sec;
- ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
- dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
- *dp = ip->i_din;
- if (waitfor) {
- return (bwrite(bp));
- } else {
- bdwrite(bp);
- return (0);
- }
-}
-
-#define SINGLE 0 /* index of single indirect block */
-#define DOUBLE 1 /* index of double indirect block */
-#define TRIPLE 2 /* index of triple indirect block */
-/*
- * Truncate the inode ip to at most length size. Free affected disk
- * blocks -- the blocks of the file are removed in reverse order.
- *
- * NB: triple indirect blocks are untested.
- */
-itrunc(oip, length, flags)
- register struct inode *oip;
- u_long length;
- int flags;
-{
- register daddr_t lastblock;
- daddr_t bn, lbn, lastiblock[NIADDR];
- register struct fs *fs;
- register struct inode *ip;
- struct buf *bp;
- int offset, osize, size, level;
- long count, nblocks, blocksreleased = 0;
- register int i;
- int aflags, error, allerror;
- struct inode tip;
-
- if (oip->i_size <= length) {
- oip->i_flag |= ICHG|IUPD;
- error = iupdat(oip, &time, &time, 1);
- return (error);
- }
- /*
- * Calculate index into inode's block list of
- * last direct and indirect blocks (if any)
- * which we want to keep. Lastblock is -1 when
- * the file is truncated to 0.
- */
- fs = oip->i_fs;
- lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
- lastiblock[SINGLE] = lastblock - NDADDR;
- lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
- lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
- nblocks = btodb(fs->fs_bsize);
- /*
- * Update the size of the file. If the file is not being
- * truncated to a block boundry, the contents of the
- * partial block following the end of the file must be
- * zero'ed in case it ever become accessable again because
- * of subsequent file growth.
- */
- osize = oip->i_size;
- offset = blkoff(fs, length);
- if (offset == 0) {
- oip->i_size = length;
- } else {
- lbn = lblkno(fs, length);
- aflags = B_CLRBUF;
- if (flags & IO_SYNC)
- aflags |= B_SYNC;
- if (error = balloc(oip, lbn, offset, &bp, aflags))
- return (error);
- oip->i_size = length;
- size = blksize(fs, oip, lbn);
- bn = bp->b_blkno;
- count = howmany(size, CLBYTES);
- munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
- bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
- brealloc(bp, size);
- if (flags & IO_SYNC)
- bwrite(bp);
- else
- bdwrite(bp);
- }
- /*
- * Update file and block pointers
- * on disk before we start freeing blocks.
- * If we crash before free'ing blocks below,
- * the blocks will be returned to the free list.
- * lastiblock values are also normalized to -1
- * for calls to indirtrunc below.
- */
- tip = *oip;
- tip.i_size = osize;
- for (level = TRIPLE; level >= SINGLE; level--)
- if (lastiblock[level] < 0) {
- oip->i_ib[level] = 0;
- lastiblock[level] = -1;
- }
- for (i = NDADDR - 1; i > lastblock; i--)
- oip->i_db[i] = 0;
- oip->i_flag |= ICHG|IUPD;
- vinvalbuf(ITOV(oip), (length > 0));
- allerror = iupdat(oip, &time, &time, MNT_WAIT);
-
- /*
- * Indirect blocks first.
- */
- ip = &tip;
- for (level = TRIPLE; level >= SINGLE; level--) {
- bn = ip->i_ib[level];
- if (bn != 0) {
- error = indirtrunc(ip, bn, lastiblock[level], level,
- &count);
- if (error)
- allerror = error;
- blocksreleased += count;
- if (lastiblock[level] < 0) {
- ip->i_ib[level] = 0;
- blkfree(ip, bn, (off_t)fs->fs_bsize);
- blocksreleased += nblocks;
- }
- }
- if (lastiblock[level] >= 0)
- goto done;
- }
-
- /*
- * All whole direct blocks or frags.
- */
- for (i = NDADDR - 1; i > lastblock; i--) {
- register off_t bsize;
-
- bn = ip->i_db[i];
- if (bn == 0)
- continue;
- ip->i_db[i] = 0;
- bsize = (off_t)blksize(fs, ip, i);
- blkfree(ip, bn, bsize);
- blocksreleased += btodb(bsize);
- }
- if (lastblock < 0)
- goto done;
-
- /*
- * Finally, look for a change in size of the
- * last direct block; release any frags.
- */
- bn = ip->i_db[lastblock];
- if (bn != 0) {
- off_t oldspace, newspace;
-
- /*
- * Calculate amount of space we're giving
- * back as old block size minus new block size.
- */
- oldspace = blksize(fs, ip, lastblock);
- ip->i_size = length;
- newspace = blksize(fs, ip, lastblock);
- if (newspace == 0)
- panic("itrunc: newspace");
- if (oldspace - newspace > 0) {
- /*
- * Block number of space to be free'd is
- * the old block # plus the number of frags
- * required for the storage we're keeping.
- */
- bn += numfrags(fs, newspace);
- blkfree(ip, bn, oldspace - newspace);
- blocksreleased += btodb(oldspace - newspace);