diff --git a/fs/ext2/block.c b/fs/ext2/block.c index c98e711..95b67fb 100644 --- a/fs/ext2/block.c +++ b/fs/ext2/block.c @@ -126,21 +126,40 @@ uint32_t ext2_inode_get_index(struct fs *ext2, struct ext2_inode *inode, uint32_ _assert(data); uint32_t p = data->block_size / sizeof(uint32_t); - uint32_t a, b, c, d, e, f, g; uint32_t ptrs[p]; if (index < EXT2_DIRECT_BLOCKS) { return inode->direct_blocks[index]; - } else if (index < EXT2_DIRECT_BLOCKS + p) { + } + + // Fits in L1? + index -= EXT2_DIRECT_BLOCKS; + if (index < p) { if (!inode->indirect_block_l1) { - panic("Read beyond end of file\n"); + panic("Read beyond end of file (L1.1)\n"); } _assert(ext2_read_block(ext2, ptrs, inode->indirect_block_l1) == 0); - return ptrs[index - EXT2_DIRECT_BLOCKS]; - } else { - panic("TODO L2+\n"); + return ptrs[index]; } + + // Fits in L2? + index -= p; + if (index < p * p) { + uint32_t index_l1 = index / p; + uint32_t index_l0 = index % p; + if (!inode->indirect_block_l2) { + panic("Read beyond end of the file (L2.2)\n"); + } + _assert(ext2_read_block(ext2, ptrs, inode->indirect_block_l2) == 0); + if (!ptrs[index_l1]) { + panic("Read beyond end of the file (L2.1)\n"); + } + _assert(ext2_read_block(ext2, ptrs, ptrs[index_l1]) == 0); + return ptrs[index_l0]; + } + + panic("TODO: L3 support\n"); } int ext2_inode_set_index(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index, uint32_t value) { diff --git a/fs/ext2/node.c b/fs/ext2/node.c index 4e1a221..5a16d9c 100644 --- a/fs/ext2/node.c +++ b/fs/ext2/node.c @@ -18,6 +18,7 @@ static int ext2_vnode_find(struct vnode *at, const char *name, struct vnode **res); static ssize_t ext2_vnode_read(struct ofile *fd, void *buf, size_t count); static ssize_t ext2_vnode_write(struct ofile *fd, const void *buf, size_t count); +static off_t ext2_vnode_lseek(struct ofile *fd, off_t pos, int whence); static int ext2_vnode_open(struct ofile *fd, int opt); static int ext2_vnode_opendir(struct ofile *fd); static int ext2_vnode_chmod(struct vnode *vn, mode_t new_mode); @@ -48,7 +49,8 @@ struct vnode_operations g_ext2_vnode_ops = { .open = ext2_vnode_open, .read = ext2_vnode_read, .write = ext2_vnode_write, - .truncate = ext2_vnode_truncate + .truncate = ext2_vnode_truncate, + .lseek = ext2_vnode_lseek, }; //// @@ -168,6 +170,33 @@ static ssize_t ext2_vnode_read(struct ofile *fd, void *buf, size_t count) { return bread; } +static off_t ext2_vnode_lseek(struct ofile *fd, off_t pos, int whence) { + off_t calc; + struct vnode *node = fd->file.vnode; + _assert(node); + struct ext2_inode *inode = node->fs_data; + _assert(inode); + + switch (whence) { + case SEEK_SET: + calc = pos; + break; + case SEEK_CUR: + calc = pos + fd->file.pos; + break; + default: + panic("Invalid seek whence: %d\n", whence); + } + + if (calc < 0 || calc >= inode->size_lower) { + return (off_t) -ESPIPE; + } + + fd->file.pos = calc; + + return fd->file.pos; +} + static int ext2_vnode_opendir(struct ofile *fd) { _assert(fd && fd->file.vnode); _assert(fd->file.vnode->type == VN_DIR);