Ejemplo n.º 1
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 = 0;	/* XXX: gcc */
	size_t block_size;
	int rc;

	off = ext2_blkoff(fs, fp->f_seekp);
	file_block = ext2_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;
}
Ejemplo n.º 2
0
int
ext2fs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
    kauth_cred_t cred)
{
	struct inode *ip = VTOI(vp);
	struct m_ext2fs *fs = ip->i_e2fs;
	int error, delta, bshift, bsize;
	UVMHIST_FUNC("ext2fs_gop_alloc"); UVMHIST_CALLED(ubchist);

	bshift = fs->e2fs_bshift;
	bsize = 1 << bshift;

	delta = off & (bsize - 1);
	off -= delta;
	len += delta;

	while (len > 0) {
		bsize = min(bsize, len);
		UVMHIST_LOG(ubchist, "off 0x%x len 0x%x bsize 0x%x",
			    off, len, bsize, 0);

		error = ext2fs_balloc(ip, ext2_lblkno(fs, off), bsize, cred,
		    NULL, flags);
		if (error) {
			UVMHIST_LOG(ubchist, "error %d", error, 0,0,0);
			return error;
		}

		/*
		 * increase file size now, ext2fs_balloc() requires that
		 * EOF be up-to-date before each call.
		 */

		if (ext2fs_size(ip) < off + bsize) {
			UVMHIST_LOG(ubchist, "old 0x%lx%8lx new 0x%lx%8lx",
			    /* Note that arguments are always cast to u_long. */
				    ext2fs_size(ip) >> 32,
				    ext2fs_size(ip) & 0xffffffff,
				    (off + bsize) >> 32,
				    (off + bsize) & 0xffffffff);
			error = ext2fs_setsize(ip, off + bsize);
			if (error) {
				UVMHIST_LOG(ubchist, "error %d", error, 0,0,0);
				return error;
			}
		}

		off += bsize;
		len -= bsize;
	}
/*
 * 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
ext2fs_blkatoff(struct vnode *vp, off_t offset, char **res, 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 = ext2_lblkno(fs, offset);

	*bpp = NULL;
	if ((error = bread(vp, lbn, fs->e2fs_bsize, 0, &bp)) != 0) {
		return (error);
	}
	if (res)
		*res = (char *)bp->b_data + ext2_blkoff(fs, offset);
	*bpp = bp;
	return (0);
}