示例#1
0
static int
virtualblocks(struct fs *super, union dinode *dp)
{
	off_t nblk, sz;

	sz = DIP(super, dp, di_size);
#ifdef	COMPAT
	if (lblkno(super, sz) >= NDADDR) {
		nblk = blkroundup(super, sz);
		if (sz == nblk)
			nblk += super->fs_bsize;
	}

	return sz / 1024;
#else	/* COMPAT */

	if (lblkno(super, sz) >= NDADDR) {
		nblk = blkroundup(super, sz);
		sz = lblkno(super, nblk);
		sz = howmany(sz - NDADDR, NINDIR(super));
		while (sz > 0) {
			nblk += sz * super->fs_bsize;
			/* One block on this level is in the inode itself */
			sz = howmany(sz - 1, NINDIR(super));
		}
	} else
		nblk = fragroundup(super, sz);

	return nblk / DEV_BSIZE;
#endif	/* COMPAT */
}
示例#2
0
文件: quot.c 项目: Alkzndr/freebsd
static int virtualblocks(struct fs *super, union dinode *dp)
{
	off_t nblk, sz;

	sz = DIP(super, dp, di_size);
#ifdef	COMPAT
	if (lblkno(super,sz) >= NDADDR) {
		nblk = blkroundup(super,sz);
		if (sz == nblk)
			nblk += super->fs_bsize;
	}

	return sz / 1024;

#else	/* COMPAT */

	if (lblkno(super,sz) >= NDADDR) {
		nblk = blkroundup(super,sz);
		sz = lblkno(super,nblk);
		sz = (sz - NDADDR + NINDIR(super) - 1) / NINDIR(super);
		while (sz > 0) {
			nblk += sz * super->fs_bsize;
			/* sz - 1 rounded up */
			sz = (sz - 1 + NINDIR(super) - 1) / NINDIR(super);
		}
	} else
		nblk = fragroundup(super,sz);

	return nblk / 512;
#endif	/* COMPAT */
}
示例#3
0
void
ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
{
	struct inode *ip = VTOI(vp);
	struct fs *fs = ip->i_fs;
	daddr_t olbn, nlbn;

	olbn = lblkno(fs, ip->i_size);
	nlbn = lblkno(fs, size);
	if (nlbn < NDADDR && olbn <= nlbn) {
		*eobp = fragroundup(fs, size);
	} else {
		*eobp = blkroundup(fs, size);
	}
}
示例#4
0
int
ext2fs_blkatoff(struct vnode *vp, off_t offset, char **res,
#undef struct
		 struct buf **bpp)
{
	struct inode *ip;
	struct m_ext2fs *fs;
	struct buf *bp;
	daddr_t lbn;
	int error;

	ip = VTOI(vp);
	fs = ip->i_e2fs;
	lbn = lblkno(fs, offset);

	*bpp = NULL;
	if ((error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, 0, &bp)) != 0) {
		brelse(bp, 0);
		return (error);
	}
	if (res)
		*res = (char *)bp->b_data + blkoff(fs, offset);
	*bpp = bp;
	return (0);
}
示例#5
0
/*
 * get next entry in a directory.
 */
struct direct *
dreaddir(struct dirstuff *dirp)
{
	struct direct *dp;
	daddr_t lbn, d;

	for (;;) {

		if (dirp->loc >= (int)dirp->ip->di_size)
			return (NULL);
		if (blkoff(&sblock, dirp->loc) == 0) {

			lbn = lblkno(&sblock, dirp->loc);

			d = bmap(lbn);
			if (d == 0)
				return (NULL);

			bread(fsbtodb(&sblock, d), dirp->dbuf,
			    (int)dblksize(&sblock, dirp->ip, (int)lbn));

		}
		dp = (struct direct *)
		    (dirp->dbuf + blkoff(&sblock, dirp->loc));
		dirp->loc += dp->d_reclen;
		if (dp->d_ino == 0) {
			continue;
		}
		return (dp);
	}
}
/*
 * Return buffer with the contents of block "offset" from the beginning of
 * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
 * remaining space in the directory.
 */
int
cd9660_blkatoff(vnode_t vp, off_t offset, char **res, buf_t *bpp)
{
	struct iso_node *ip;
	register struct iso_mnt *imp;
	buf_t	bp;
	daddr_t lbn;
	int bsize, error;

	ip = VTOI(vp);
	imp = ip->i_mnt;
	lbn = lblkno(imp, offset);
	bsize = blksize(imp, ip, lbn);

	if ((bsize != imp->im_sector_size) &&
	    (offset & (imp->im_sector_size - 1)) == 0) {
		bsize = imp->im_sector_size;
	}

	if ( (error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), bsize, NOCRED, &bp)) ) {
		buf_brelse(bp);
		*bpp = NULL;
		return (error);
	}
	if (res)
		*res = (char *)0 + buf_dataptr(bp) + blkoff(imp, offset);
	*bpp = bp;
	
	return (0);
}
示例#7
0
文件: sys.c 项目: rohsaini/mkunity
static int
ioread(void *addr, int count, int phys)
{
	int logno, off, size;

	while (count) {
		off = blkoff(fs, poff);
		logno = lblkno(fs, poff);
		cnt = size = blksize(fs, &inode, logno);
		bnum = block_map(logno);
		if (bnum == -1)
			return(1);
		bnum = fsbtodb(fs, bnum) + boff;
		size -= off;
		if (size > count)
			size = count;
		if (disk_read(bnum, cnt, (vm_offset_t)iobuf))
			return(1);
		if (phys)
			pcpy(iobuf+off,addr,size);
		else
			bcopy(iobuf+off,addr,size);
		addr = (char *)addr + size;
		count -= size;
		poff += size;
	}
	return(0);
}
示例#8
0
/* ARGSUSED */
static int
ext2_read(struct vop_read_args *ap)
{
	struct vnode *vp;
	struct inode *ip;
	struct uio *uio;
	FS *fs;
	struct buf *bp;
	daddr_t lbn, nextlbn;
	off_t nextloffset;
	off_t bytesinfile;
	long size, xfersize, blkoffset;
	int error, orig_resid;
	int seqcount = ap->a_ioflag >> 16;

	vp = ap->a_vp;
	ip = VTOI(vp);
	uio = ap->a_uio;

#ifdef DIAGNOSTIC
	if (uio->uio_rw != UIO_READ)
		panic("ext2_read: mode");

	if (vp->v_type == VLNK) {
		if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
			panic("ext2_read: short symlink");
	} else if (vp->v_type != VREG && vp->v_type != VDIR)
		panic("ext2_read: type %d", vp->v_type);
#endif
	fs = ip->I_FS;
#if 0
	if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize)
		return (EFBIG);
#endif

	orig_resid = uio->uio_resid;
	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
		if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
			break;
		lbn = lblkno(fs, uio->uio_offset);
		nextlbn = lbn + 1;
		nextloffset = lblktodoff(fs, nextlbn);
		size = BLKSIZE(fs, ip, lbn);
		blkoffset = blkoff(fs, uio->uio_offset);

		xfersize = fs->s_frag_size - blkoffset;
		if (uio->uio_resid < xfersize)
			xfersize = uio->uio_resid;
		if (bytesinfile < xfersize)
			xfersize = bytesinfile;

		if (nextloffset >= ip->i_size) {
			error = bread(vp, lblktodoff(fs, lbn), size, &bp);
		} else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
			error = cluster_read(vp, (off_t)ip->i_size,
					     lblktodoff(fs, lbn), size,
					     uio->uio_resid,
					     (ap->a_ioflag >> 16) * BKVASIZE,
					     &bp);
		} else if (seqcount > 1) {
示例#9
0
int
readit(char *buffer, int count)
{
    int logno, off, size;
    int cnt2, bnum2;
    struct fs *fs_copy;
    int n = 0;

    if (poff + count > inode.i_size)
	count = inode.i_size - poff;
    while (count > 0 && poff < inode.i_size) {
	fs_copy = fs;
	off = blkoff(fs_copy, poff);
	logno = lblkno(fs_copy, poff);
	cnt2 = size = blksize(fs_copy, &inode, logno);
	bnum2 = fsbtodb(fs_copy, block_map(logno)) + boff;
	if (	(!off)  && (size <= count)) {
	    devread(buffer, bnum2, cnt2);
	} else {
	    size -= off;
	    if (size > count)
		size = count;
	    devread(iobuf, bnum2, cnt2);
	    bcopy(iobuf+off, buffer, size);
	}
	buffer += size;
	count -= size;
	poff += size;
	n += size;
    }
    return n;
}
示例#10
0
/*
 * Return buffer with the contents of block "offset" from the beginning of
 * vnode "vp".  If "res" is non-zero, fill it in with a pointer to the
 * remaining space in the vnode.
 */
int
ffs_blkatoff(struct vnode *vp, off_t uoffset, char **res, struct buf **bpp)
{
	struct inode *ip;
	struct fs *fs;
	struct buf *bp;
	ufs_daddr_t lbn;
	int bsize, error;

	ip = VTOI(vp);
	fs = ip->i_fs;
	lbn = lblkno(fs, uoffset);
	bsize = blksize(fs, ip, lbn);

	*bpp = NULL;
	error = bread(vp, lblktodoff(fs, lbn), bsize, &bp);
	if (error) {
		brelse(bp);
		return (error);
	}
	if (res)
		*res = (char *)bp->b_data + blkoff(fs, uoffset);
	*bpp = bp;
	return (0);
}
示例#11
0
static int
udf_read(struct vop_read_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct uio *uio = ap->a_uio;
	struct udf_node *node = VTON(vp);
	struct udf_mnt *udfmp;
	struct file_entry *fentry;
	struct buf *bp;
	uint8_t *data;
	daddr_t lbn, rablock;
	off_t diff, fsize;
	ssize_t n;
	int error = 0;
	long size, on;

	if (uio->uio_resid == 0)
		return (0);
	if (uio->uio_offset < 0)
		return (EINVAL);

	if (is_data_in_fentry(node)) {
		fentry = node->fentry;
		data = &fentry->data[le32toh(fentry->l_ea)];
		fsize = le32toh(fentry->l_ad);

		n = uio->uio_resid;
		diff = fsize - uio->uio_offset;
		if (diff <= 0)
			return (0);
		if (diff < n)
			n = diff;
		error = uiomove(data + uio->uio_offset, (int)n, uio);
		return (error);
	}

	fsize = le64toh(node->fentry->inf_len);
	udfmp = node->udfmp;
	do {
		lbn = lblkno(udfmp, uio->uio_offset);
		on = blkoff(udfmp, uio->uio_offset);
		n = min((u_int)(udfmp->bsize - on),
			uio->uio_resid);
		diff = fsize - uio->uio_offset;
		if (diff <= 0)
			return (0);
		if (diff < n)
			n = diff;
		size = udfmp->bsize;
		rablock = lbn + 1;
		if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
			if (lblktosize(udfmp, rablock) < fsize) {
				error = cluster_read(vp, fsize, lbn, size,
				    NOCRED, uio->uio_resid,
				    (ap->a_ioflag >> 16), 0, &bp);
			} else {
				error = bread(vp, lbn, size, NOCRED, &bp);
			}
		} else {
示例#12
0
文件: dir.c 项目: AgamAgarwal/minix
/*
 * Attempt to expand the size of a directory
 */
static int
expanddir(struct ext2fs_dinode *dp, char *name)
{
	daddr_t lastbn, newblk;
	struct bufarea *bp;
	char *firstblk;

	lastbn = lblkno(&sblock, inosize(dp));
	if (lastbn >= NDADDR - 1 || fs2h32(dp->e2di_blocks[lastbn]) == 0 ||
		inosize(dp) == 0) {
		return (0);
	}
	if ((newblk = allocblk()) == 0) {
		return (0);
	}
	dp->e2di_blocks[lastbn + 1] = dp->e2di_blocks[lastbn];
	dp->e2di_blocks[lastbn] = h2fs32(newblk);
	inossize(dp, inosize(dp) + sblock.e2fs_bsize);
	dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) + 1);
	bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]),
		sblock.e2fs_bsize);
	if (bp->b_errs)
		goto bad;
	if ((firstblk = malloc(sblock.e2fs_bsize)) == NULL)
		err(8, "cannot allocate first block");
	memcpy(firstblk, bp->b_un.b_buf, sblock.e2fs_bsize);
	bp = getdirblk(newblk, sblock.e2fs_bsize);
	if (bp->b_errs) {
		free(firstblk);
		goto bad;
	}
	memcpy(bp->b_un.b_buf, firstblk, sblock.e2fs_bsize);
	free(firstblk);
	dirty(bp);
	bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]),
		sblock.e2fs_bsize);
	if (bp->b_errs)
		goto bad;
	emptydir.dot_reclen = h2fs16(sblock.e2fs_bsize);
	memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir);
	pwarn("NO SPACE LEFT IN %s", name);
	if (preen)
		printf(" (EXPANDED)\n");
	else if (reply("EXPAND") == 0)
		goto bad;
	dirty(bp);
	inodirty();
	return (1);
bad:
	dp->e2di_blocks[lastbn] = dp->e2di_blocks[lastbn + 1];
	dp->e2di_blocks[lastbn + 1] = 0;
	inossize(dp, inosize(dp) - sblock.e2fs_bsize);
	dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) - 1);
	freeblk(newblk);
	return (0);
}
示例#13
0
文件: ufs.c 项目: DragonQuan/minix3
/*
 * Read a portion of a file into an internal buffer.
 * Return the location in the buffer and the amount in the buffer.
 */
static int
buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
{
	struct file *fp = (struct file *)f->f_fsdata;
	struct fs *fs = fp->f_fs;
	long off;
	indp_t file_block;
	indp_t disk_block;
	size_t block_size;
	int rc;

	off = blkoff(fs, fp->f_seekp);
	file_block = lblkno(fs, fp->f_seekp);
#ifdef LIBSA_LFS
	block_size = dblksize(fs, &fp->f_di, file_block);
#else
	block_size = sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
#endif

	if (file_block != fp->f_buf_blkno) {
		rc = block_map(f, file_block, &disk_block);
		if (rc)
			return rc;

		if (disk_block == 0) {
			memset(fp->f_buf, 0, block_size);
			fp->f_buf_size = block_size;
		} else {
			twiddle();
			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
				FSBTODB(fs, disk_block),
				block_size, fp->f_buf, &fp->f_buf_size);
			if (rc)
				return rc;
		}

		fp->f_buf_blkno = file_block;
	}

	/*
	 * Return address of byte in buffer corresponding to
	 * offset, and size of remainder of buffer after that
	 * byte.
	 */
	*buf_p = fp->f_buf + off;
	*size_p = block_size - off;

	/*
	 * But truncate buffer at end of file.
	 */
	if (*size_p > fp->f_di.di_size - fp->f_seekp)
		*size_p = fp->f_di.di_size - fp->f_seekp;

	return 0;
}
示例#14
0
/*
 * Read a portion of a file into an internal buffer.  Return
 * the location in the buffer and the amount in the buffer.
 *
 * Parameters:
 *	buf_p:	out
 *	size_p:	out
 */
static int
buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
{
	struct file *fp = (struct file *)f->f_fsdata;
	struct fs *fs = fp->f_fs;
	long off;
	daddr_t file_block;
	daddr_t	disk_block;
	size_t block_size;
	int rc;

	off = blkoff(fs, fp->f_seekp);
	file_block = lblkno(fs, fp->f_seekp);
	block_size = dblksize(fs, &fp->f_di, file_block);

	if (file_block != fp->f_buf_blkno) {
		rc = block_map(f, file_block, &disk_block);
		if (rc)
			return (rc);

		if (fp->f_buf == NULL)
			fp->f_buf = malloc(fs->fs_bsize);

		if (disk_block == 0) {
			bzero(fp->f_buf, block_size);
			fp->f_buf_size = block_size;
		} else {
			twiddle();
			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
				fsbtodb(fs, disk_block),
				block_size, fp->f_buf, &fp->f_buf_size);
			if (rc)
				return (rc);
		}

		fp->f_buf_blkno = file_block;
	}

	/*
	 * Return address of byte in buffer corresponding to
	 * offset, and size of remainder of buffer after that
	 * byte.
	 */
	*buf_p = fp->f_buf + off;
	*size_p = block_size - off;

	/*
	 * But truncate buffer at end of file.
	 */
	if (*size_p > fp->f_di.di_size - fp->f_seekp)
		*size_p = fp->f_di.di_size - fp->f_seekp;

	return (0);
}
示例#15
0
/*
 * Attempt to expand the size of a directory
 */
static int
expanddir(union dinode *dp, char *name)
{
	ufs2_daddr_t lastbn, newblk;
	struct bufarea *bp;
	char *cp, firstblk[DIRBLKSIZ];

	lastbn = lblkno(&sblock, DIP(dp, di_size));
	if (lastbn >= NDADDR - 1 || DIP(dp, di_db[lastbn]) == 0 ||
	    DIP(dp, di_size) == 0)
		return (0);
	if ((newblk = allocblk(sblock.fs_frag)) == 0)
		return (0);
	DIP_SET(dp, di_db[lastbn + 1], DIP(dp, di_db[lastbn]));
	DIP_SET(dp, di_db[lastbn], newblk);
	DIP_SET(dp, di_size, DIP(dp, di_size) + sblock.fs_bsize);
	DIP_SET(dp, di_blocks, DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
	bp = getdirblk(DIP(dp, di_db[lastbn + 1]),
		sblksize(&sblock, DIP(dp, di_size), lastbn + 1));
	if (bp->b_errs)
		goto bad;
	memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
	bp = getdirblk(newblk, sblock.fs_bsize);
	if (bp->b_errs)
		goto bad;
	memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
	     cp < &bp->b_un.b_buf[sblock.fs_bsize];
	     cp += DIRBLKSIZ)
		memmove(cp, &emptydir, sizeof emptydir);
	dirty(bp);
	bp = getdirblk(DIP(dp, di_db[lastbn + 1]),
		sblksize(&sblock, DIP(dp, di_size), lastbn + 1));
	if (bp->b_errs)
		goto bad;
	memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir);
	pwarn("NO SPACE LEFT IN %s", name);
	if (preen)
		printf(" (EXPANDED)\n");
	else if (reply("EXPAND") == 0)
		goto bad;
	dirty(bp);
	inodirty();
	return (1);
bad:
	DIP_SET(dp, di_db[lastbn], DIP(dp, di_db[lastbn + 1]));
	DIP_SET(dp, di_db[lastbn + 1], 0);
	DIP_SET(dp, di_size, DIP(dp, di_size) - sblock.fs_bsize);
	DIP_SET(dp, di_blocks, DIP(dp, di_blocks) - btodb(sblock.fs_bsize));
	freeblk(newblk, sblock.fs_frag);
	return (0);
}
示例#16
0
/*
 * Read a portion of a file into an internal buffer.
 * Return the location in the buffer and the amount in the buffer.
 */
static int
buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
{
	struct file *fp = (struct file *)f->f_fsdata;
	struct m_ext2fs *fs = fp->f_fs;
	long off;
	indp_t file_block;
	indp_t disk_block;
	size_t block_size;
	int rc;

	off = blkoff(fs, fp->f_seekp);
	file_block = lblkno(fs, fp->f_seekp);
	block_size = fs->e2fs_bsize;	/* no fragment */

	if (file_block != fp->f_buf_blkno) {
		rc = block_map(f, file_block, &disk_block);
		if (rc)
			return rc;

		if (disk_block == 0) {
			memset(fp->f_buf, 0, block_size);
			fp->f_buf_size = block_size;
		} else {
			twiddle();
			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
				FSBTODB(fs, disk_block),
				block_size, fp->f_buf, &fp->f_buf_size);
			if (rc)
				return rc;
		}

		fp->f_buf_blkno = file_block;
	}

	/*
	 * Return address of byte in buffer corresponding to
	 * offset, and size of remainder of buffer after that
	 * byte.
	 */
	*buf_p = fp->f_buf + off;
	*size_p = block_size - off;

	/*
	 * But truncate buffer at end of file.
	 */
	/* XXX should handle LARGEFILE */
	if (*size_p > fp->f_di.e2di_size - fp->f_seekp)
		*size_p = fp->f_di.e2di_size - fp->f_seekp;

	return 0;
}
示例#17
0
/*
 * Attempt to expand the size of a directory
 */
static int
expanddir(struct ufs1_dinode *dp, char *name)
{
	ufs_daddr_t lastbn, newblk;
	struct bufarea *bp;
	char *cp, firstblk[DIRBLKSIZ];

	lastbn = lblkno(&sblock, dp->di_size);
	if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)
		return (0);
	if ((newblk = allocblk(sblock.fs_frag)) == 0)
		return (0);
	dp->di_db[lastbn + 1] = dp->di_db[lastbn];
	dp->di_db[lastbn] = newblk;
	dp->di_size += sblock.fs_bsize;
	dp->di_blocks += btodb(sblock.fs_bsize);
	bp = getdirblk(dp->di_db[lastbn + 1],
		(long)dblksize(&sblock, dp, lastbn + 1));
	if (bp->b_errs)
		goto bad;
	memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
	bp = getdirblk(newblk, sblock.fs_bsize);
	if (bp->b_errs)
		goto bad;
	memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
	     cp < &bp->b_un.b_buf[sblock.fs_bsize];
	     cp += DIRBLKSIZ)
		memmove(cp, &emptydir, sizeof emptydir);
	dirty(bp);
	bp = getdirblk(dp->di_db[lastbn + 1],
		(long)dblksize(&sblock, dp, lastbn + 1));
	if (bp->b_errs)
		goto bad;
	memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir);
	pwarn("NO SPACE LEFT IN %s", name);
	if (preen)
		printf(" (EXPANDED)\n");
	else if (reply("EXPAND") == 0)
		goto bad;
	dirty(bp);
	inodirty();
	return (1);
bad:
	dp->di_db[lastbn] = dp->di_db[lastbn + 1];
	dp->di_db[lastbn + 1] = 0;
	dp->di_size -= sblock.fs_bsize;
	dp->di_blocks -= btodb(sblock.fs_bsize);
	freeblk(newblk, sblock.fs_frag);
	return (0);
}
示例#18
0
static int
find(char *path)
{
    char *rest, ch;
    int block, off, loc, ino = ROOTINO;
    struct dirent *dp;
    char list_only;

    list_only = (path[0] == '?' && path[1] == '\0');
 loop:
    devread(iobuf, fsbtodb(fs, ino_to_fsba(fs, ino)) + boff, fs->fs_bsize);
    bcopy((void *)&((struct dinode *)iobuf)[ino % fs->fs_inopb],
	  (void *)&inode.i_din,
	  sizeof (struct dinode));
    if (!*path)
	return 1;
    while (*path == '/')
	path++;
    if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
	return 0;
    for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
    *rest = 0;
    loc = 0;
    do {
	if (loc >= inode.i_size) {
	    if (list_only) {
		putchar('\n');
		return -1;
	    } else {
		return 0;
	    }
	}
	if (!(off = blkoff(fs, loc))) {
	    block = lblkno(fs, loc);
	    devread(iobuf, fsbtodb(fs, block_map(block)) + boff,
		    blksize(fs, &inode, block));
	}
	dp = (struct dirent *)(iobuf + off);
	loc += dp->d_reclen;
	if (dp->d_fileno && list_only) {
	    puts(dp->d_name);
	    putchar(' ');
	}
    } while (!dp->d_fileno || strcmp(path, dp->d_name));
    ino = dp->d_fileno;
    *(path = rest) = ch;
    goto loop;
}
示例#19
0
文件: sys.c 项目: aosm/boot
static int getch(int fdesc)
{
	register struct iob *io;
	struct fs *fs;
	char *p;
	int c, lbn, off, size, diff;

	if ((io = iob_from_fdesc(fdesc)) == 0) {
		return (-1);
	}
	p = io->i_ma;
	if (io->i_cc <= 0) {
		if ((io->i_flgs & F_FILE) != 0) {
			diff = io->i_ino.i_size - io->i_offset;
			if (diff <= 0)
				return (-1);
			fs = io->i_fs;
			lbn = lblkno(fs, io->i_offset);
			io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff;
			off = blkoff(fs, io->i_offset);
			size = blksize(fs, &io->i_ino, lbn);
		} else {
			diff = 0;
#ifndef	SMALL
			io->i_bn = io->i_offset / DEV_BSIZE;
			off = 0;
			size = DEV_BSIZE;
#endif	SMALL
		}
		io->i_ma = io->i_buf;
		io->i_cc = size;
		if (devread(io) < 0) {
			return (-1);
		}
		if ((io->i_flgs & F_FILE) != 0) {
			if (io->i_offset - off + size >= io->i_ino.i_size)
				io->i_cc = diff + off;
			io->i_cc -= off;
		}
		p = &io->i_buf[off];
	}
	io->i_cc--;
	io->i_offset++;
	c = (unsigned)*p++;
	io->i_ma = p;
	return (c);
}
示例#20
0
文件: sys.c 项目: rohsaini/mkunity
int
find(const char *path)
{
	const char *rest;
	int ch;
	int block, off, loc, ino = ROOTINO;
	struct dirent *dp;

	for (;;) {
		cnt = fs->fs_bsize;
		bnum = fsbtodb(fs,itod(fs,ino)) + boff;
		if (disk_read(bnum, cnt, (vm_offset_t)iobuf))
			return 0;
		bcopy((char *)&((struct dinode *)iobuf)[ino % fs->fs_inopb],
		      (char *)&inode.i_di,
		      sizeof (struct dinode));
		if (!*path)
			return 1;
		while (*path == '/')
			path++;
		if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
			return 0;
		for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
		loc = 0;
		for (;;) {
			if (loc >= inode.i_size)
				return 0;
			if (!(off = blkoff(fs, loc))) {
				block = lblkno(fs, loc);
				cnt = blksize(fs, &inode, block);
				bnum = fsbtodb(fs, block_map(block)) + boff;
				if (disk_read(bnum, cnt, (vm_offset_t)iobuf))
					return 0;
			}
			dp = (struct dirent *)(iobuf + off);
			loc += dp->d_reclen;
			if (dp->d_ino == 0)
				continue;
			if (strncmp(path, dp->d_name, rest - path) == 0 &&
			    dp->d_name[rest - path] == 0)
				break;
		}
		ino = dp->d_ino;
		path = rest;
	}
}
示例#21
0
unsigned long
ufs2_read (char *buf, unsigned long len, unsigned long write)
{
  unsigned long logno, off, size, ret = 0;
  grub_int64_t map;

  while (len && !errnum)
    {
      off = blkoff (SUPERBLOCK, filepos);
      logno = lblkno (SUPERBLOCK, filepos);
      size = blksize (SUPERBLOCK, INODE_UFS2, logno);

      if ((map = block_map (logno)) < 0)
	  break; 

      size -= off;

      if (size > len)
	  size = len;

      disk_read_func = disk_read_hook;

      devread (fsbtodb (SUPERBLOCK, map), off, size, buf, write);

      disk_read_func = NULL;

      if (buf)
	buf += size;
      len -= size;	/* len always >= 0 */
      filepos += size;
      ret += size;
    }

  if (errnum)
    ret = 0;

  return ret;
}
示例#22
0
int
ufs2_read (char *buf, int len)
{
  int logno, off, size, ret = 0;
  grub_int64_t map;

  while (len && !errnum)
    {
      off = blkoff (SUPERBLOCK, filepos);
      logno = lblkno (SUPERBLOCK, filepos);
      size = blksize (SUPERBLOCK, INODE_UFS2, logno);

      if ((map = block_map (logno)) < 0)
	break; 

      size -= off;

      if (size > len)
	size = len;

      disk_read_func = disk_read_hook;

      devread (fsbtodb (SUPERBLOCK, map), off, size, buf);

      disk_read_func = NULL;

      buf += size;
      len -= size;
      filepos += size;
      ret += size;
    }

  if (errnum)
    ret = 0;

  return ret;
}
示例#23
0
/*
 * Return buffer with the contents of block "offset" from the beginning of
 * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
 * remaining space in the directory.
 */
int
cd9660_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
{
	struct iso_node *ip;
	struct iso_mnt *imp;
	struct buf *bp;
	daddr_t lbn;
	int bsize, error;

	ip = VTOI(vp);
	imp = ip->i_mnt;
	lbn = lblkno(imp, offset);
	bsize = blksize(imp, ip, lbn);

	if ((error = bread(vp, lbn, bsize, NOCRED, 0, &bp)) != 0) {
		brelse(bp, 0);
		*bpp = NULL;
		return (error);
	}
	if (res)
		*res = (char *)bp->b_data + blkoff(imp, offset);
	*bpp = bp;
	return (0);
}
示例#24
0
/*
 * Return buffer with the contents of block "offset" from the beginning of
 * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
 * remaining space in the directory.
 */
int
ext2_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
{
	struct inode *ip;
	struct ext2_sb_info *fs;
	struct buf *bp;
	daddr_t lbn;
	int bsize, error;

	ip = VTOI(vp);
	fs = ip->i_e2fs;
	lbn = lblkno(fs, offset);
	bsize = blksize(fs, ip, lbn);

	*bpp = NULL;
	if ((error = bread(vp, lblktodoff(fs, lbn), bsize, &bp)) != 0) {
		brelse(bp);
		return (error);
	}
	if (res)
		*res = (char *)bp->b_data + blkoff(fs, offset);
	*bpp = bp;
	return (0);
}
示例#25
0
文件: sys.c 项目: aosm/boot
int
read(int fdesc, char *buf, int count)
{
	int i, size;
	register struct iob *file;
	struct fs *fs;
	int lbn, off;

	if ((file = iob_from_fdesc(fdesc)) == 0) {
		return (-1);
	}
	if ((file->i_flgs&F_READ) == 0) {
		return (-1);
	}
#ifndef	SMALL
	if ((file->i_flgs & F_FILE) == 0) {
		file->i_cc = count;
		file->i_ma = buf;
		file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE);
		i = devread(file);
		file->i_offset += count;
		return (i);
	}
#endif	SMALL
	if (file->i_offset+count > file->i_ino.i_size)
		count = file->i_ino.i_size - file->i_offset;
	if ((i = count) <= 0)
		return (0);
	/*
	 * While reading full blocks, do I/O into user buffer.
	 * Anything else uses getc().
	 */
	fs = file->i_fs;
	while (i) {
		off = blkoff(fs, file->i_offset);
		lbn = lblkno(fs, file->i_offset);
		size = blksize(fs, &file->i_ino, lbn);
		if (off == 0 && size <= i) {
			file->i_bn = fsbtodb(fs, sbmap(file, lbn)) +
			    file->i_boff;
			file->i_cc = size;
			file->i_ma = buf;
			if (devread(file) < 0) {
				return (-1);
			}
			file->i_offset += size;
			file->i_cc = 0;
			buf += size;
			i -= size;
		} else {
			size -= off;
			if (size > i)
				size = i;
			i -= size;
			do {
				*buf++ = getch(fdesc);
			} while (--size);
		}
	}
	return (count);
}
示例#26
0
文件: sys.c 项目: aosm/boot
/*
 * get next entry in a directory.
 */
struct direct *
readdir(struct dirstuff *dirp)
{
	struct direct *dp;
	register struct iob *io;
	daddr_t lbn, d;
	int off;
#if DCACHE
	char *bp;
	int dirblkno;

	if (dcache == 0)
		dcache = cacheInit(DCACHE_SIZE, DIRBLKSIZ);
#endif DCACHE
	io = dirp->io;
	for(;;)
	{
		if (dirp->loc >= io->i_ino.i_size)
			return (NULL);
		off = blkoff(io->i_fs, dirp->loc);
		lbn = lblkno(io->i_fs, dirp->loc);

#if DCACHE
		dirblkno = dirp->loc / DIRBLKSIZ;
		if (cacheFind(dcache, io->i_ino.i_number, dirblkno, &bp)) {
		    dp = (struct direct *)(bp + (dirp->loc % DIRBLKSIZ));
		} else
#else DCACHE
		if (io->dirbuf_blkno != lbn)
#endif DCACHE
		{
		    if((d = sbmap(io, lbn)) == 0)
			    return NULL;
		    io->i_bn = fsbtodb(io->i_fs, d) + io->i_boff;
		    io->i_ma = io->i_buf;
		    io->i_cc = blksize(io->i_fs, &io->i_ino, lbn);
		
		    if (devread(io) < 0)
		    {
#if	SYS_MESSAGES
			    error("bn %d: directory read error\n",
				    io->i_bn);
#endif
			    return (NULL);
		    }
#if	BIG_ENDIAN_FS
		    byte_swap_dir_block_in(io->i_buf, io->i_cc);
#endif	BIG_ENDIAN_FS
#if DCACHE
		    bcopy(io->i_buf + dirblkno * DIRBLKSIZ, bp, DIRBLKSIZ);
		    dp = (struct direct *)(io->i_buf + off);
#endif
		}
#if !DCACHE
		dp = (struct direct *)(io->i_buf + off);
#endif
		dirp->loc += dp->d_reclen;

		if (dp->d_ino != 0) return (dp);
	}
}
示例#27
0
/*
 * Load the appropriate indirect block, and change the appropriate pointer.
 * Mark the block dirty.  Do segment and avail accounting.
 */
static int
update_meta(struct lfs *fs, ino_t ino, int vers, daddr_t lbn,
	    daddr_t ndaddr, size_t size, struct lwp *l)
{
	int error;
	struct vnode *vp;
	struct inode *ip;
#ifdef DEBUG
	daddr_t odaddr;
	struct indir a[NIADDR];
	int num;
	int i;
#endif /* DEBUG */
	struct buf *bp;
	SEGUSE *sup;

	KASSERT(lbn >= 0);	/* no indirect blocks */

	if ((error = lfs_rf_valloc(fs, ino, vers, l, &vp)) != 0) {
		DLOG((DLOG_RF, "update_meta: ino %d: lfs_rf_valloc"
		      " returned %d\n", ino, error));
		return error;
	}

	if ((error = lfs_balloc(vp, (lbn << fs->lfs_bshift), size,
				NOCRED, 0, &bp)) != 0) {
		vput(vp);
		return (error);
	}
	/* No need to write, the block is already on disk */
	if (bp->b_oflags & BO_DELWRI) {
		LFS_UNLOCK_BUF(bp);
		fs->lfs_avail += btofsb(fs, bp->b_bcount);
	}
	brelse(bp, BC_INVAL);

	/*
	 * Extend the file, if it is not large enough already.
	 * XXX this is not exactly right, we don't know how much of the
	 * XXX last block is actually used.  We hope that an inode will
	 * XXX appear later to give the correct size.
	 */
	ip = VTOI(vp);
	if (ip->i_size <= (lbn << fs->lfs_bshift)) {
		u_int64_t newsize;

		if (lbn < NDADDR)
			newsize = ip->i_ffs1_size = (lbn << fs->lfs_bshift) +
				(size - fs->lfs_fsize) + 1;
		else
			newsize = ip->i_ffs1_size = (lbn << fs->lfs_bshift) + 1;

		if (ip->i_size < newsize) {
			ip->i_size = newsize;
			/*
			 * tell vm our new size for the case the inode won't
			 * appear later.
			 */
			uvm_vnp_setsize(vp, newsize);
		}
	}

	lfs_update_single(fs, NULL, vp, lbn, ndaddr, size);

	LFS_SEGENTRY(sup, fs, dtosn(fs, ndaddr), bp);
	sup->su_nbytes += size;
	LFS_WRITESEGENTRY(sup, fs, dtosn(fs, ndaddr), bp);

	/* differences here should be due to UNWRITTEN indirect blocks. */
	KASSERT((lblkno(fs, ip->i_size) > NDADDR &&
	    ip->i_lfs_effnblks == ip->i_ffs1_blocks) ||
	    ip->i_lfs_effnblks >= ip->i_ffs1_blocks);

#ifdef DEBUG
	/* Now look again to make sure it worked */
	ufs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL);
	for (i = num; i > 0; i--) {
		if (!a[i].in_exists)
			panic("update_meta: absent %d lv indirect block", i);
	}
	if (dbtofsb(fs, odaddr) != ndaddr)
		DLOG((DLOG_RF, "update_meta: failed setting ino %d lbn %"
		      PRId64 " to %" PRId64 "\n", ino, lbn, ndaddr));
#endif /* DEBUG */
	vput(vp);
	return 0;
}
示例#28
0
/*
 * Vnode op for writing.
 */
static int
ext2_write(struct vop_write_args *ap)
{
	struct vnode *vp;
	struct uio *uio;
	struct inode *ip;
	struct m_ext2fs *fs;
	struct buf *bp;
	daddr_t lbn;
	off_t osize;
	int blkoffset, error, flags, ioflag, resid, size, seqcount, xfersize;

	ioflag = ap->a_ioflag;
	uio = ap->a_uio;
	vp = ap->a_vp;

	seqcount = ioflag >> IO_SEQSHIFT;
	ip = VTOI(vp);

#ifdef INVARIANTS
	if (uio->uio_rw != UIO_WRITE)
		panic("%s: mode", "ext2_write");
#endif

	switch (vp->v_type) {
	case VREG:
		if (ioflag & IO_APPEND)
			uio->uio_offset = ip->i_size;
		if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
			return (EPERM);
		/* FALLTHROUGH */
	case VLNK:
		break;
	case VDIR:
		/* XXX differs from ffs -- this is called from ext2_mkdir(). */
		if ((ioflag & IO_SYNC) == 0)
		panic("ext2_write: nonsync dir write");
		break;
	default:
		panic("ext2_write: type %p %d (%jd,%jd)", (void *)vp,
		    vp->v_type, (intmax_t)uio->uio_offset,
		    (intmax_t)uio->uio_resid);
	}

	KASSERT(uio->uio_resid >= 0, ("ext2_write: uio->uio_resid < 0"));
	KASSERT(uio->uio_offset >= 0, ("ext2_write: uio->uio_offset < 0"));
	fs = ip->i_e2fs;
	if ((uoff_t)uio->uio_offset + uio->uio_resid > fs->e2fs_maxfilesize)
		return (EFBIG);
	/*
	 * Maybe this should be above the vnode op call, but so long as
	 * file servers have no limits, I don't think it matters.
	 */
	if (vn_rlimit_fsize(vp, uio, uio->uio_td))
		return (EFBIG);

	resid = uio->uio_resid;
	osize = ip->i_size;
	if (seqcount > BA_SEQMAX)
		flags = BA_SEQMAX << BA_SEQSHIFT;
	else
		flags = seqcount << BA_SEQSHIFT;
	if ((ioflag & IO_SYNC) && !DOINGASYNC(vp))
		flags |= IO_SYNC;

	for (error = 0; uio->uio_resid > 0;) {
		lbn = lblkno(fs, uio->uio_offset);
		blkoffset = blkoff(fs, uio->uio_offset);
		xfersize = fs->e2fs_fsize - blkoffset;
		if (uio->uio_resid < xfersize)
			xfersize = uio->uio_resid;
		if (uio->uio_offset + xfersize > ip->i_size)
			vnode_pager_setsize(vp, uio->uio_offset + xfersize);

                /*
		 * We must perform a read-before-write if the transfer size
		 * does not cover the entire buffer.
                 */
		if (fs->e2fs_bsize > xfersize)
			flags |= BA_CLRBUF;
		else
			flags &= ~BA_CLRBUF;
		error = ext2_balloc(ip, lbn, blkoffset + xfersize,
		    ap->a_cred, &bp, flags);
		if (error != 0)
			break;

		/*
		 * If the buffer is not valid and we did not clear garbage
		 * out above, we have to do so here even though the write
		 * covers the entire buffer in order to avoid a mmap()/write
		 * race where another process may see the garbage prior to
		 * the uiomove() for a write replacing it.
		 */
		if ((bp->b_flags & B_CACHE) == 0 && fs->e2fs_bsize <= xfersize)
			vfs_bio_clrbuf(bp);
		if ((ioflag & (IO_SYNC|IO_INVAL)) == (IO_SYNC|IO_INVAL))
			bp->b_flags |= B_NOCACHE;
		if (uio->uio_offset + xfersize > ip->i_size)
			ip->i_size = uio->uio_offset + xfersize;
		size = blksize(fs, ip, lbn) - bp->b_resid;
		if (size < xfersize)
			xfersize = size;

		error =
		    uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
		if (ioflag & (IO_VMIO|IO_DIRECT)) {
			bp->b_flags |= B_RELBUF;
		}

		/*
		 * If IO_SYNC each buffer is written synchronously.  Otherwise
		 * if we have a severe page deficiency write the buffer
		 * asynchronously.  Otherwise try to cluster, and if that
		 * doesn't do it then either do an async write (if O_DIRECT),
		 * or a delayed write (if not).
		 */
		if (ioflag & IO_SYNC) {
			(void)bwrite(bp);
		} else if (vm_page_count_severe() ||
		    buf_dirty_count_severe() ||
		    (ioflag & IO_ASYNC)) {
			bp->b_flags |= B_CLUSTEROK;
			bawrite(bp);
		} else if (xfersize + blkoffset == fs->e2fs_fsize) {
			if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) {
				bp->b_flags |= B_CLUSTEROK;
				cluster_write(vp, bp, ip->i_size, seqcount, 0);
			} else {
				bawrite(bp);
			}
		} else if (ioflag & IO_DIRECT) {
			bp->b_flags |= B_CLUSTEROK;
			bawrite(bp);
		} else {
			bp->b_flags |= B_CLUSTEROK;
			bdwrite(bp);
		}
		if (error || xfersize == 0)
			break;
	}
	/*
	 * If we successfully wrote any data, and we are not the superuser
	 * we clear the setuid and setgid bits as a precaution against
	 * tampering.
	 */
	if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid &&
	    ap->a_cred) {
		if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID, 0))
			ip->i_mode &= ~(ISUID | ISGID);
	}
	if (error) {
		if (ioflag & IO_UNIT) {
			(void)ext2_truncate(vp, osize,
			    ioflag & IO_SYNC, ap->a_cred, uio->uio_td);
			uio->uio_offset -= resid - uio->uio_resid;
			uio->uio_resid = resid;
		}
	}
	if (uio->uio_resid != resid) {
               ip->i_flag |= IN_CHANGE | IN_UPDATE;
               if (ioflag & IO_SYNC)
                       error = ext2_update(vp, 1);
       }
	return (error);
}
示例#29
0
/*
 * Vnode op for reading.
 */
static int
ext2_read(struct vop_read_args *ap)
{
	struct vnode *vp;
	struct inode *ip;
	struct uio *uio;
	struct m_ext2fs *fs;
	struct buf *bp;
	daddr_t lbn, nextlbn;
	off_t bytesinfile;
	long size, xfersize, blkoffset;
	int error, orig_resid, seqcount;
	int ioflag;

	vp = ap->a_vp;
	uio = ap->a_uio;
	ioflag = ap->a_ioflag;

	seqcount = ap->a_ioflag >> IO_SEQSHIFT;
	ip = VTOI(vp);

#ifdef INVARIANTS
	if (uio->uio_rw != UIO_READ)
		panic("%s: mode", "ext2_read");

	if (vp->v_type == VLNK) {
		if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
			panic("%s: short symlink", "ext2_read");
	} else if (vp->v_type != VREG && vp->v_type != VDIR)
		panic("%s: type %d", "ext2_read", vp->v_type);
#endif
	orig_resid = uio->uio_resid;
	KASSERT(orig_resid >= 0, ("ext2_read: uio->uio_resid < 0"));
	if (orig_resid == 0)
		return (0);
	KASSERT(uio->uio_offset >= 0, ("ext2_read: uio->uio_offset < 0"));
	fs = ip->i_e2fs;
	if (uio->uio_offset < ip->i_size &&
	    uio->uio_offset >= fs->e2fs_maxfilesize)
	    	return (EOVERFLOW);

	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
		if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
			break;
		lbn = lblkno(fs, uio->uio_offset);
		nextlbn = lbn + 1;
		size = blksize(fs, ip, lbn);
		blkoffset = blkoff(fs, uio->uio_offset);

		xfersize = fs->e2fs_fsize - blkoffset;
		if (uio->uio_resid < xfersize)
			xfersize = uio->uio_resid;
		if (bytesinfile < xfersize)
			xfersize = bytesinfile;

		if (lblktosize(fs, nextlbn) >= ip->i_size)
			error = bread(vp, lbn, size, NOCRED, &bp);
		else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
			error = cluster_read(vp, ip->i_size, lbn, size,
			    NOCRED, blkoffset + uio->uio_resid, seqcount,
			    0, &bp);
		} else if (seqcount > 1) {
			int nextsize = blksize(fs, ip, nextlbn);
			error = breadn(vp, lbn,
			    size, &nextlbn, &nextsize, 1, NOCRED, &bp);
		} else
			error = bread(vp, lbn, size, NOCRED, &bp);
		if (error) {
			brelse(bp);
			bp = NULL;
			break;
		}

		/*
		 * If IO_DIRECT then set B_DIRECT for the buffer.  This
		 * will cause us to attempt to release the buffer later on
		 * and will cause the buffer cache to attempt to free the
		 * underlying pages.
		 */
		if (ioflag & IO_DIRECT)
			bp->b_flags |= B_DIRECT;

		/*
		 * We should only get non-zero b_resid when an I/O error
		 * has occurred, which should cause us to break above.
		 * However, if the short read did not cause an error,
		 * then we want to ensure that we do not uiomove bad
		 * or uninitialized data.
		 */
		size -= bp->b_resid;
		if (size < xfersize) {
			if (size == 0)
				break;
			xfersize = size;
		}
		error = uiomove((char *)bp->b_data + blkoffset,
  			(int)xfersize, uio);
		if (error)
			break;

		if (ioflag & (IO_VMIO|IO_DIRECT)) {
			/*
			 * If it's VMIO or direct I/O, then we don't
			 * need the buf, mark it available for
			 * freeing. If it's non-direct VMIO, the VM has
			 * the data.
			 */
			bp->b_flags |= B_RELBUF;
			brelse(bp);
		} else {
			/*
			 * Otherwise let whoever
			 * made the request take care of
			 * freeing it. We just queue
			 * it onto another list.
			 */
			bqrelse(bp);
		}
	}

	/* 
	 * This can only happen in the case of an error
	 * because the loop above resets bp to NULL on each iteration
	 * and on normal completion has not set a new value into it.
	 * so it must have come from a 'break' statement
	 */
	if (bp != NULL) {
		if (ioflag & (IO_VMIO|IO_DIRECT)) {
			bp->b_flags |= B_RELBUF;
			brelse(bp);
		} else {
			bqrelse(bp);
		}
	}

	if ((error == 0 || uio->uio_resid != orig_resid) &&
	    (vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
		ip->i_flag |= IN_ACCESS;
	return (error);
}
示例#30
0
// ffs文件系统的写入操作
int
ffs_write(void *v)
{
	struct vop_write_args *ap = v;
	struct vnode *vp;
	struct uio *uio;
	struct inode *ip;
	struct fs *fs;
	struct buf *bp;
	daddr_t lbn;
	off_t osize;
	int blkoffset, error, extended, flags, ioflag, size, xfersize;
	ssize_t resid, overrun;

	extended = 0;
	ioflag = ap->a_ioflag;
	uio = ap->a_uio;
	vp = ap->a_vp;
	ip = VTOI(vp);

#ifdef DIAGNOSTIC
	if (uio->uio_rw != UIO_WRITE)
		panic("ffs_write: mode");
#endif

	/*
	 * If writing 0 bytes, succeed and do not change
	 * update time or file offset (standards compliance)
	 */
	if (uio->uio_resid == 0)
		return (0);

	switch (vp->v_type) {
	case VREG:
		if (ioflag & IO_APPEND)
			uio->uio_offset = DIP(ip, size);
		if ((DIP(ip, flags) & APPEND) && uio->uio_offset != DIP(ip, size))
			return (EPERM);
		/* FALLTHROUGH */
	case VLNK:
		break;
	case VDIR:
		if ((ioflag & IO_SYNC) == 0)
			panic("ffs_write: nonsync dir write");
		break;
	default:
		panic("ffs_write: type");
	}

	fs = ip->i_fs;
	if (uio->uio_offset < 0 ||
	    (u_int64_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
		return (EFBIG);

	/* do the filesize rlimit check */
	if ((error = vn_fsizechk(vp, uio, ioflag, &overrun)))
		return (error);

	resid = uio->uio_resid;
	osize = DIP(ip, size);
	flags = ioflag & IO_SYNC ? B_SYNC : 0;

	for (error = 0; uio->uio_resid > 0;) {
		lbn = lblkno(fs, uio->uio_offset);
		blkoffset = blkoff(fs, uio->uio_offset);
		xfersize = fs->fs_bsize - blkoffset;
		if (uio->uio_resid < xfersize)
			xfersize = uio->uio_resid;
		if (fs->fs_bsize > xfersize)
			flags |= B_CLRBUF;
		else
			flags &= ~B_CLRBUF;

		if ((error = UFS_BUF_ALLOC(ip, uio->uio_offset, xfersize,
			 ap->a_cred, flags, &bp)) != 0)
			break;
		if (uio->uio_offset + xfersize > DIP(ip, size)) {
			DIP_ASSIGN(ip, size, uio->uio_offset + xfersize);
			uvm_vnp_setsize(vp, DIP(ip, size));
			extended = 1;
		}
		(void)uvm_vnp_uncache(vp);

		size = blksize(fs, ip, lbn) - bp->b_resid;
		if (size < xfersize)
			xfersize = size;

		error =
		    uiomovei(bp->b_data + blkoffset, xfersize, uio);

		if (error != 0)
			memset(bp->b_data + blkoffset, 0, xfersize);

#if 0
		if (ioflag & IO_NOCACHE)
			bp->b_flags |= B_NOCACHE;
#endif
		if (ioflag & IO_SYNC)
			(void)bwrite(bp);
		else if (xfersize + blkoffset == fs->fs_bsize) {
			if (doclusterwrite)
				cluster_write(bp, &ip->i_ci, DIP(ip, size));
			else
				bawrite(bp);
		} else
			bdwrite(bp);

		if (error || xfersize == 0)
			break;
		ip->i_flag |= IN_CHANGE | IN_UPDATE;
	}
	/*
	 * If we successfully wrote any data, and we are not the superuser
	 * we clear the setuid and setgid bits as a precaution against
	 * tampering.
	 */
	if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
		DIP_ASSIGN(ip, mode, DIP(ip, mode) & ~(ISUID | ISGID));
	if (resid > uio->uio_resid)
		VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
	if (error) {
		if (ioflag & IO_UNIT) {
			(void)UFS_TRUNCATE(ip, osize,
			    ioflag & IO_SYNC, ap->a_cred);
			uio->uio_offset -= resid - uio->uio_resid;
			uio->uio_resid = resid;
		}
	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
		error = UFS_UPDATE(ip, 1);
	}
	/* correct the result for writes clamped by vn_fsizechk() */
	uio->uio_resid += overrun;
	return (error);
}