aboutsummaryrefslogtreecommitdiff
path: root/src/features/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/fs.c')
-rw-r--r--src/features/fs.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/features/fs.c b/src/features/fs.c
new file mode 100644
index 0000000..ba66033
--- /dev/null
+++ b/src/features/fs.c
@@ -0,0 +1,150 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+// EXT2 based filesystem
+
+#include <def.h>
+#include <fs.h>
+#include <ide.h>
+#include <mem.h>
+#include <print.h>
+#include <str.h>
+
+void *buffer_read(int block)
+{
+ return ide_read(malloc(BLOCK_SIZE), block);
+}
+
+struct superblock *get_superblock()
+{
+ struct superblock *sb = buffer_read(EXT2_SUPER);
+ if (sb->magic != EXT2_MAGIC)
+ return NULL;
+ return sb;
+}
+
+struct bgd *get_bgd()
+{
+ return buffer_read(EXT2_SUPER + 1);
+}
+
+struct inode *get_inode(int i)
+{
+ struct superblock *s = get_superblock();
+ struct bgd *b = get_bgd();
+
+ int block_group = (i - 1) / s->inodes_per_group;
+ int index = (i - 1) % s->inodes_per_group;
+ int block = (index * INODE_SIZE) / BLOCK_SIZE;
+ b += block_group;
+
+ u32 *data = buffer_read(b->inode_table + block);
+ struct inode *in =
+ (struct inode *)((u32)data + (index % (BLOCK_SIZE / INODE_SIZE)) * INODE_SIZE);
+ return in;
+}
+
+u32 read_indirect(u32 indirect, u32 block_num)
+{
+ char *data = buffer_read(indirect);
+ return *(u32 *)((u32)data + block_num * 4);
+}
+
+void *read_file(struct inode *in)
+{
+ //assert(in);
+ if (!in)
+ return NULL;
+
+ int num_blocks = in->blocks / (BLOCK_SIZE / SECTOR_SIZE);
+
+ // assert(num_blocks != 0);
+ if (!num_blocks)
+ return NULL;
+
+ u32 sz = BLOCK_SIZE * num_blocks;
+ void *buf = malloc(sz);
+ //assert(buf != NULL);
+
+ int indirect = 0;
+
+ // Single indirect pointer
+ if (num_blocks > 12) {
+ indirect = in->block[13];
+ }
+
+ int blocknum = 0;
+ char *data;
+ for (int i = 0; i < num_blocks; i++) {
+ if (i < 12) {
+ blocknum = in->block[i];
+ data = buffer_read(blocknum);
+ memcpy((void *)((u32)buf + (i * BLOCK_SIZE)), data, BLOCK_SIZE);
+ }
+ if (i > 12) {
+ blocknum = read_indirect(indirect, i - 13);
+ data = buffer_read(blocknum);
+ memcpy((void *)((u32)buf + ((i - 1) * BLOCK_SIZE)), data, BLOCK_SIZE);
+ }
+ }
+ return buf;
+}
+
+int find_inode(const char *name, int dir_inode)
+{
+ if (!dir_inode)
+ return -1;
+
+ struct inode *i = get_inode(dir_inode);
+
+ char *buf = malloc(BLOCK_SIZE * i->blocks / 2);
+ memset(buf, 0, BLOCK_SIZE * i->blocks / 2);
+
+ for (u32 q = 0; q < i->blocks / 2; q++) {
+ char *data = buffer_read(i->block[q]);
+ memcpy((void *)((u32)buf + (q * BLOCK_SIZE)), data, BLOCK_SIZE);
+ }
+
+ struct dirent *d = (struct dirent *)buf;
+
+ u32 sum = 0;
+ do {
+ // Calculate the 4byte aligned size of each entry
+ sum += d->total_len;
+ //printf("%2d %10s\t%2d %3d\n", (int)d->inode, d->name, d->name_len, d->rec_len);
+ if (strncmp((void *)d->name, name, d->name_len) == 0) {
+ free(buf);
+ return d->inode_num;
+ }
+ d = (struct dirent *)((u32)d + d->total_len);
+
+ } while (sum < (1024 * i->blocks / 2));
+ free(buf);
+ return -1;
+}
+
+void ls_root()
+{
+ struct inode *i = get_inode(2);
+
+ char *buf = malloc(BLOCK_SIZE * i->blocks / 2);
+
+ for (u32 q = 0; q < i->blocks / 2; q++) {
+ char *data = buffer_read(i->block[q]);
+ memcpy((void *)((u32)buf + (q * BLOCK_SIZE)), data, BLOCK_SIZE);
+ }
+
+ struct dirent *d = (struct dirent *)buf;
+
+ int sum = 0;
+ int calc = 0;
+ printf("Root directory:\n");
+ do {
+ calc = (sizeof(struct dirent) + d->name_len + 4) & ~0x3;
+ sum += d->total_len;
+ printf("/%s\n", d->name);
+ if (d->total_len != calc && sum == 1024)
+ d->total_len = calc;
+
+ d = (struct dirent *)((u32)d + d->total_len);
+
+ } while (sum < 1024);
+}