/* * 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; }
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); }