Orion
Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)diff --git a/vfs/ext2fs/block.c b/vfs/ext2fs/block.c new file mode 100644 index 0000000..28cf480 --- /dev/null +++ b/vfs/ext2fs/block.c @@ -0,0 +1,32 @@ +/* + * This file contains the Ext2 block implementation. It reads a backing file + * from the super block in the intervals specified by the superblock. It also + * contains functions for reading blocks from files. + */ + +#include <stdint.h> +#include "fs.h" + +/* Read a block of data */ +void +ext2_read_block(SuperBlock *super, uint32_t index, char *buf) +{ + Ext2Super *rsuper = super->data; + + super->back->pos = index * (1024 << rsuper->blockSize); + file_read(super->back, buf, 1024 << rsuper->blockSize); +} + +/* Get the data block address from inode block index */ +uint32_t +ext2_get_data_addr(SuperBlock *super, Ext2Inode *node, uint32_t index) +{ + uint32_t tmp; + char block[4096]; + + /* Main blocks */ + if (index < 12) + return node->directBlock[index]; + index -= 12; + return 0; +} diff --git a/vfs/ext2fs/file.c b/vfs/ext2fs/file.c new file mode 100644 index 0000000..d0caa35 --- /dev/null +++ b/vfs/ext2fs/file.c @@ -0,0 +1,86 @@ +/* + * This file controls access to Ext2FS Files. It contains the functions called + * by the VFS for any operation on a Ext2FS File struct. + */ + +#include <stddef.h> +#include <string.h> +#include <dirent.h> +#include <errno.h> +#include "fs.h" +#include "../vfs.h" + +size_t ext2fs_read(File *file, char *buf, size_t size, off_t offset); +int ext2fs_readdir(File *file, DirEnt *dent, off_t index); +int ext2fs_open(File *file); + +FileOps ext2fsFileOps = { + .read = ext2fs_read, + .readdir = ext2fs_readdir, + .open = ext2fs_open, +}; + +/* Read a file */ +size_t +ext2fs_read(File *file, char *buf, size_t size, off_t offset) +{ + Ext2Inode inode; + uint16_t min; + size_t count = 0, i = offset / 4096; + uint32_t blk; + char ebuf[4096]; + ext2_read_inode(file->inode->super, file->inode->ino, &inode); + if (offset > inode.lsize) + return 0; + if (size + offset > inode.lsize) + size = inode.lsize - offset; + while (size) { + min = (size > 0x1000) ? 0x1000 : size; + blk = ext2_get_data_addr(file->inode->super, &inode, i); + ext2_read_block(file->inode->super, blk, ebuf); + memcpy(buf + count, ebuf + (offset % 4096), min); + size -= min; + count += min; + i++; + } + if (count >= 0x1000) + return count; +} + +/* Read a directory entry */ +int +ext2fs_readdir(File *file, DirEnt *dent, off_t index) +{ + char buf[4096]; + uint32_t block, blk = 0; + Ext2DirEntry *de; + Ext2Inode inode; + ext2_read_inode(file->inode->super, file->inode->ino, &inode); + for (blk = 0; blk < 0xFFFF; blk++) { + block = ext2_get_data_addr(file->inode->super, &inode, blk); + if (!block) + return -ENOENT; + ext2_read_block(file->inode->super, block, buf); + for (de = (Ext2DirEntry *) buf; + index && de < (Ext2DirEntry *) (buf + 4096); + de = (void *) ((char *) de + de->size), index--); + if (de >= (Ext2DirEntry *) (buf + 4096)) + return -ENOENT; + if (!index) + break; + } + if (!de->ino) + return -ENOENT; + dent->ino = de->ino; + dent->type = de->type; + dent->namelen = de->nameLen + 1; + strncpy(dent->name, de->name, de->size); + return 0; +} + +/* Open a file */ +int +ext2fs_open(File *file) +{ + return 0; +} diff --git a/vfs/ext2fs/fs.h b/vfs/ext2fs/fs.h new file mode 100644 index 0000000..0e5cadb --- /dev/null +++ b/vfs/ext2fs/fs.h @@ -0,0 +1,116 @@ +#ifndef KERNEL_VFS_EXT2FS_H +#define KERNEL_VFS_EXT2FS_H + +#include "../vfs.h" + +typedef struct Ext2Super Ext2Super; +typedef struct Ext2BlockGroupDesc Ext2BlockGroupDesc; +typedef struct Ext2Inode Ext2Inode; +typedef struct Ext2DirEntry Ext2DirEntry; + +/* Structure of the Ext2 SuperBlock */ +struct Ext2Super { + uint32_t numInodes; + uint32_t numBlocks; + uint32_t reservedBlocks; + uint32_t unallocBlocks; + uint32_t unallocInodes; + uint32_t superBlock; + uint32_t blockSize; + uint32_t fragSize; + uint32_t blocksPerGroup; + uint32_t fragsPerGroup; + uint32_t inodesPerGroup; + uint32_t lastMountTime; + uint32_t lastWriteTime; + uint16_t lastCheck; + uint16_t mustCheck; + uint16_t signature; + uint16_t state; + uint16_t error; + uint16_t verMinor; + uint32_t lastCheckTime; + uint32_t checkInterval; + uint32_t creator; + uint32_t verMajor; + uint16_t uid, gid; + /* Extended fields */ + uint32_t firstAvailInode; + uint16_t inodeSize; + uint16_t blockGroup; + uint32_t optionalFeatures; + uint32_t requiredFeatures; + uint32_t writableFeatures; + char fsId[16]; + char volumeName[16]; + char lastPath[64]; + uint32_t compression; + uint8_t preallocFileBlocks; + uint8_t preallocDirBlocks; + uint16_t unused; + char journalId[16]; + uint32_t journalInode; + uint32_t journalDev; + uint32_t orphanHead; +} __attribute__((packed)); + +/* Structure of the Ext2 Block Group Descriptor */ +struct Ext2BlockGroupDesc { + uint32_t blockUsage; + uint32_t inodeUsage; + uint32_t inodeTable; + uint16_t unallocBlocks; + uint16_t unallocInodes; + uint16_t numDirs; +} __attribute__((packed)); + +/* Structure of the Ext2 Inode */ +struct Ext2Inode { + uint16_t type; + uint16_t uid; + uint32_t lsize; + uint32_t lastAccessTime; + uint32_t creationTime; + uint32_t lastWriteTime; + uint32_t deletionTime; + uint16_t gid; + uint16_t numHardLinks; + uint32_t numSectors; + uint32_t flags; + uint32_t osA; + uint32_t directBlock[12]; + uint32_t singleBlock; + uint32_t doubleBlock; + uint32_t tripleBlock; + uint32_t gen; + uint32_t attr; + union { + uint32_t usize; + uint32_t dirACL; + }; + uint32_t fragment; + uint32_t osB[3]; +} __attribute__((packed)); + +/* Structure of the Ext2 Directory Entry */ +struct Ext2DirEntry { + uint32_t ino; + uint16_t size; + uint8_t nameLen; + uint8_t type; + char name[]; +} __attribute__((packed)); + +/* Operations */ +extern SuperOps ext2fsSuperOps; +extern InodeOps ext2fsInodeOps; +extern FileOps ext2fsFileOps; + +extern FileSystemType ext2fsType; + +void ext2_read_vnode(SuperBlock *super, uint32_t index, Inode *res); +void ext2_read_inode(SuperBlock *super, uint32_t index, Ext2Inode *res); +void ext2_read_block(SuperBlock *super, uint32_t index, char *buf); +uint32_t ext2_get_data_addr(SuperBlock *super, Ext2Inode *node, uint32_t index); + +#endif diff --git a/vfs/ext2fs/inode.c b/vfs/ext2fs/inode.c new file mode 100644 index 0000000..3437220 --- /dev/null +++ b/vfs/ext2fs/inode.c @@ -0,0 +1,94 @@ +/* + * This file contains the Ext2 inode implementation. It contains the functions + * for the inode operations, as well as several internal operations relating to + * inodes required for the full Ext2 implementation. + */ + +#include <stdint.h> +#include <string.h> +#include <fcntl.h> +#include "fs.h" +#include "../vfs.h" +#include "../super.h" +#include "../../mem/heap.h" + +Inode *ext2fs_lookup(Inode *inode, const char *name); + +InodeOps ext2fsInodeOps = { + .lookup = ext2fs_lookup, +}; + +/* Read an Ext2 inode as a VFS inode */ +void +ext2_read_vnode(SuperBlock *super, uint32_t index, Inode *res) +{ + Ext2Inode inode; + ext2_read_inode(super, index, &inode); + + res->ino = index; + res->usage = 0; + res->uid = inode.uid; + res->gid = inode.gid; + res->mode = inode.type; + res->nlink = inode.numHardLinks; + res->size = inode.lsize; + res->ops = &ext2fsInodeOps; + res->fileOps = &ext2fsFileOps; + res->super = super; +} + +/* Read an Ext2 inode */ +void +ext2_read_inode(SuperBlock *super, uint32_t index, Ext2Inode *res) +{ + Ext2Super *rsuper = super->data; + + /* Find the Block Group Descriptor */ + Ext2BlockGroupDesc bgd; + uint32_t groups = rsuper->numBlocks / rsuper->blocksPerGroup; + uint32_t group = (index - 1) / rsuper->inodesPerGroup; + index = (index - 1) % rsuper->inodesPerGroup; + if (rsuper->numBlocks % rsuper->blocksPerGroup) + groups++; + super->back->pos = (rsuper->blockSize ? 1 : 2) + * (1024 << rsuper->blockSize); + super->back->pos += sizeof(Ext2BlockGroupDesc) * group; + file_read(super->back, (char *) &bgd, sizeof(Ext2BlockGroupDesc)); + /* Read Inode */ + super->back->pos = bgd.inodeTable * (1024 << rsuper->blockSize); + super->back->pos += rsuper->inodeSize * index; + file_read(super->back, (char *) res, sizeof(Ext2Inode)); +} + +/* Look up a file */ +Inode * +ext2fs_lookup(Inode *vnode, const char *name) +{ + char buf[4096]; + uint32_t block, blk = 0; + Ext2DirEntry *de; + Ext2Inode inode; + ext2_read_inode(vnode->super, vnode->ino, &inode); + for (blk = 0; blk < 0xFFFF; blk++) { + block = ext2_get_data_addr(vnode->super, &inode, blk); + if (!block) + return NULL; + ext2_read_block(vnode->super, block, buf); + for (de = (Ext2DirEntry *) buf; + strncmp(de->name, name, de->nameLen) + && de < (Ext2DirEntry *) (buf + 4096); + de = (void *) ((char *) de + de->size)); + if (de >= (Ext2DirEntry *) (buf + 4096)) + return NULL; + if (!strncmp(de->name, name, de->nameLen)) + break; + } + if (!de->ino) + return NULL; + Inode *res = super_find_inode(vnode->super, de->ino); + if (res) + return res; + res = kmalloc(sizeof(Inode)); + ext2_read_vnode(vnode->super, de->ino, res); + return res; +} diff --git a/vfs/ext2fs/super.c b/vfs/ext2fs/super.c new file mode 100644 index 0000000..98ca800 --- /dev/null +++ b/vfs/ext2fs/super.c @@ -0,0 +1,89 @@ +/* + * This file controls the superblock for Ext2FS. It supports mounting new + * Ext2FS filesystems. The VFS will use the calls here when dealing directly + * with the filesystem structure. + */ + +#include <stdint.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/mount.h> +#include "fs.h" +#include "../vfs.h" +#include "../inode.h" +#include "../super.h" +#include "../../mem/heap.h" +#include "../../task/task.h" +#include "../../screen.h" + +Inode *ext2fs_mount(FileSystemType *type, int flags, + const char *dev, void *data); +Inode *ext2fs_alloc_inode(SuperBlock *sb); + +FileSystemType ext2fsType = { + .name = "Ext2FS", + .mount = ext2fs_mount, +}; + +SuperOps ext2fsSuperOps = { + .alloc_inode = ext2fs_alloc_inode, +}; + +/* Mount a Ext2FS instance */ +Inode * +ext2fs_mount(FileSystemType *type, int flags, const char *dev, void *data) +{ + if (type != &ext2fsType) + return NULL; + + int fd = open(dev, O_RDONLY); + if (fd < 0) + return (void *) fd; + File *back = file_get(current->files->fd[fd]); + close(fd); + if (!S_ISBLK(back->mode)) { + file_put(back); + return (void *) -ENOTBLK; + } + + Ext2Super *rsuper = kmalloc(sizeof(Ext2Super)); + back->pos = 1024; + file_read(back, (char *) rsuper, sizeof(Ext2Super)); + if (rsuper->signature != 0xEF53) { + kprintf("Error while mounting %s: Not an Ext2FS drive", dev); + file_put(back); + kfree(rsuper); + return (void *) -EINVAL; + } + if (rsuper->requiredFeatures & 0x01) { + kprintf("Cannot mount %s: Compression required", dev); + file_put(back); + kfree(rsuper); + return (void *) -EINVAL; + } + if ((rsuper->writableFeatures & 0x02) && !(flags & MS_RDONLY)) { + kprintf("Cannot mount %s: 64-bit File System required", dev); + file_put(back); + kfree(rsuper); + return (void *) -EINVAL; + } + + SuperBlock *super = kmalloc(sizeof(SuperBlock)); + super->type = type; + super->ops = &ext2fsSuperOps; + init_lock(&super->lock); + super->back = back; + super->data = rsuper; + super->root = kmalloc(sizeof(Inode)); + ext2_read_vnode(super, 2, super->root); + + return super->root; +} + +/* Allocate an inode */ +Inode * +ext2fs_alloc_inode(SuperBlock *sb) +{ + return NULL; +}