BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / vfs / ext2fs

// Related

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;
+}