Orion
Barry Importing existing Orion kernel d41a53c (3 years, 3 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;
+}