From f6fdaf49aa3338a7a4dd47e362fb2d7deb1f2030 Mon Sep 17 00:00:00 2001 From: Kevin Lange Date: Sat, 29 Jan 2011 14:12:00 -0600 Subject: [PATCH] [ext2] Massive EXT2 compatibility commit. --- core/alloc.c | 6 -- core/fs/ext2_initrd.c | 170 +++++++++++++++++++++++++++++++++++++++++- core/system.c | 20 +++++ core/vfs.c | 38 +++++++++- include/ext2.h | 2 + include/system.h | 2 + main.c | 9 +++ 7 files changed, 238 insertions(+), 9 deletions(-) diff --git a/core/alloc.c b/core/alloc.c index 060c645d..eb56fb5d 100644 --- a/core/alloc.c +++ b/core/alloc.c @@ -119,14 +119,8 @@ * Defines for often-used integral values * related to our binning and paging strategy. */ -#if SIZE_MAX == UINT32_MAX #define NUM_BINS 11U /* Number of bins, total, under 32-bit. */ #define SMALLEST_BIN_LOG 2U /* Logarithm base two of the smallest bin: log_2(sizeof(int32)). */ -#else -#define NUM_BINS 10U /* Number of bins, total, under 64-bit. */ -#define SMALLEST_BIN_LOG 3U /* Logarithm base two of the smallest bin: log_2(sizeof(int64)). */ -#endif - #define BIG_BIN (NUM_BINS - 1) /* Index for the big bin, (NUM_BINS - 1) */ #define SMALLEST_BIN (1UL << SMALLEST_BIN_LOG) /* Size of the smallest bin. */ diff --git a/core/fs/ext2_initrd.c b/core/fs/ext2_initrd.c index f63b9258..c5bb2488 100644 --- a/core/fs/ext2_initrd.c +++ b/core/fs/ext2_initrd.c @@ -4,6 +4,10 @@ ext2_superblock_t * initrd_superblock; ext2_inodetable_t * initrd_root_node; +ext2_bgdescriptor_t * initrd_root_block; +ext2_inodetable_t * initrd_inode_table; +void * initrd_start; + fs_node_t * initrd_root; fs_node_t * initrd_dev; @@ -14,6 +18,9 @@ void open_initrd(fs_node_t *node, uint8_t read, uint8_t write); void close_initrd(fs_node_t *node); struct dirent *readdir_initrd(fs_node_t *node, uint32_t index); fs_node_t *finddir_initrd(fs_node_t *node, char *name); +ext2_dir_t * ext2_get_direntry(ext2_inodetable_t * inode, uint32_t index); +ext2_inodetable_t * ext2_get_inode(uint32_t inode); +void * ext2_get_block(uint32_t block); uint32_t read_initrd( @@ -61,15 +68,70 @@ readdir_initrd( fs_node_t *node, uint32_t index ) { - return NULL; + ext2_inodetable_t * inode = ext2_get_inode(node->inode); + ext2_dir_t * direntry = ext2_get_direntry(inode, index); + if (!direntry) { + return NULL; + } + struct dirent * dirent = malloc(sizeof(struct dirent)); + memcpy(&dirent->name, &direntry->name, direntry->name_len); + dirent->name[direntry->name_len] = '\0'; + dirent->ino = direntry->inode; + return dirent; } +/* + * find the child entry named `name` within the directory + * node `node`. The VFS has already checked that `node` is + * a valid directory, but we'll do that again just to be safe, + * and just in case someone didn't use the VFS layer to call us. + * Basically, run through the directory entries until we find + * the one requested and build an fs_node_t for it. The requester + * will have to free it when they are done with it. + */ fs_node_t * finddir_initrd( fs_node_t *node, char *name ) { - return NULL; + /* + * Find the actual inode in the ramdisk image for the requested file + */ + ext2_inodetable_t * inode = ext2_get_inode(node->inode); + void * block; + ext2_dir_t * direntry = NULL; + block = (void *)ext2_get_block(inode->block[0]); + uint32_t dir_offset; + dir_offset = 0; + /* + * Look through the requested entries until we find what we're looking for + */ + while (dir_offset < inode->size) { + ext2_dir_t * d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); + if (strlen(name) != d_ent->name_len) { + dir_offset += d_ent->rec_len; + continue; + } + char * dname = malloc(sizeof(char) * (d_ent->name_len + 1)); + memcpy(dname, &d_ent->name, d_ent->name_len); + dname[d_ent->name_len] = '\0'; + if (!strcmp(dname, name)) { + free(dname); + direntry = d_ent; + break; + } + free(dname); + dir_offset += d_ent->rec_len; + } + if (!direntry) { + /* + * We could not find the requested entry in this directory. + */ + return NULL; + } + fs_node_t * outnode = malloc(sizeof(fs_node_t)); + initrd_node_from_file(direntry->inode, direntry, outnode); + return outnode; } uint32_t @@ -93,6 +155,54 @@ initrd_node_from_file( fnode->mask = inode->mode & 0xFFF; /* File Flags */ fnode->flags = 0; + if (inode->mode & EXT2_S_IFREG) { + fnode->flags |= FS_FILE; + } + if (inode->mode & EXT2_S_IFDIR) { + fnode->flags |= FS_DIRECTORY; + } + if (inode->mode & EXT2_S_IFBLK) { + fnode->flags |= FS_BLOCKDEVICE; + } + if (inode->mode & EXT2_S_IFCHR) { + fnode->flags |= FS_CHARDEVICE; + } + if (inode->mode & EXT2_S_IFIFO) { + fnode->flags |= FS_PIPE; + } + if (inode->mode & EXT2_S_IFLNK) { + fnode->flags |= FS_SYMLINK; + } + fnode->read = read_initrd; + fnode->write = write_initrd; + fnode->open = open_initrd; + fnode->close = close_initrd; + fnode->readdir = readdir_initrd; + fnode->finddir = finddir_initrd; + return 1; +} + +uint32_t +initrd_node_from_dirent( + ext2_inodetable_t * inode, + struct dirent * direntry, + fs_node_t * fnode + ) { + if (!fnode) { + /* You didn't give me a node to write into, go *** yourself */ + return 0; + } + /* Information from the direntry */ + fnode->inode = direntry->ino; + memcpy(&fnode->name, &direntry->name, strlen(direntry->name)); + fnode->name[strlen(direntry->name)] = '\0'; + /* Information from the inode */ + fnode->uid = inode->uid; + fnode->gid = inode->gid; + fnode->length = inode->size; + fnode->mask = inode->mode & 0xFFF; + /* File Flags */ + fnode->flags = 0; if (inode->mode & EXT2_S_IFREG) { fnode->flags &= FS_FILE; } @@ -117,4 +227,60 @@ initrd_node_from_file( fnode->close = close_initrd; fnode->readdir = readdir_initrd; fnode->finddir = finddir_initrd; + return 1; +} + +ext2_inodetable_t * +ext2_get_inode( + uint32_t inode + ) { + return (ext2_inodetable_t *)((uintptr_t)initrd_inode_table + initrd_superblock->inode_size * (inode - 1)); +} + +void * +ext2_get_block( + uint32_t block + ) { + return (void *)((uintptr_t)initrd_start + (1024 << initrd_superblock->log_block_size) * block); +} + +ext2_dir_t * +ext2_get_direntry( + ext2_inodetable_t * inode, + uint32_t index + ) { + assert(inode->mode & EXT2_S_IFDIR); + void * block; + block = (void *)ext2_get_block(inode->block[0]); + uint32_t dir_offset; + dir_offset = 0; + uint32_t dir_index; + dir_index = 0; + while (dir_offset < inode->size) { + ext2_dir_t * d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); + if (dir_index == index) { + return d_ent; + } + dir_offset += d_ent->rec_len; + dir_index++; + } + return NULL; +} + +void +initrd_mount( + uint32_t mem_head, + uint32_t mem_top + ) { + initrd_start = (void *)mem_head; + initrd_superblock = (ext2_superblock_t *)((uintptr_t)initrd_start + 1024); + assert(initrd_superblock->magic == EXT2_SUPER_MAGIC); + initrd_root_block = (ext2_bgdescriptor_t *)((uintptr_t)initrd_start + 1024 + 1024); + initrd_inode_table = (ext2_inodetable_t *)((uintptr_t)initrd_start + (1024 << initrd_superblock->log_block_size) * initrd_root_block->inode_table); + // Get the second inode + ext2_inodetable_t * root_inode = ext2_get_inode(2); + ext2_dir_t * root_direntry = ext2_get_direntry(root_inode, 0); + initrd_root = (fs_node_t *)malloc(sizeof(fs_node_t)); + assert(initrd_node_from_file(root_inode, root_direntry, initrd_root)); + fs_root = initrd_root; } diff --git a/core/system.c b/core/system.c index a2ee1c2b..8cce0ca6 100644 --- a/core/system.c +++ b/core/system.c @@ -20,6 +20,26 @@ memcpy( return dest; } +int +strcmp( + const char * a, + const char * b + ) { + uint32_t i = 0; + while (1) { + if (a[i] < b[i]) { + return -1; + } else if (a[i] > b[i]) { + return 1; + } else { + if (a[i] == '\0') { + return 0; + } + ++i; + } + } +} + /* * memset * Set `count` bytes to `val`. diff --git a/core/vfs.c b/core/vfs.c index 6826f872..751a2991 100644 --- a/core/vfs.c +++ b/core/vfs.c @@ -40,19 +40,55 @@ struct dirent * readdir_fs(fs_node_t *node, uint32_t index) { } fs_node_t *finddir_fs(fs_node_t *node, char *name) { - if ((node->flags & 0x07) == FS_DIRECTORY && node->readdir != 0) { + if ((node->flags & FS_DIRECTORY) && node->readdir != 0) { return node->finddir(node, name); } else { return (fs_node_t *)NULL; } } +/* + * Retreive the node for the requested path + */ fs_node_t * kopen( const char *filename, uint32_t flags ) { /* let's do this shit */ + if (!fs_root) { + HALT_AND_CATCH_FIRE("Attempted to kopen() without a filesystem in place."); + } + if (!filename[0] == '/') { + HALT_AND_CATCH_FIRE("Attempted to kopen() a non-absolute path."); + } + uint32_t path_len = strlen(filename); + char * path = (char *)malloc(sizeof(char) * (path_len)); + memcpy(path, filename, path_len); + char * path_offset = path; + uint32_t path_depth = 0; + while (path_offset < path + path_len) { + if (*path_offset == '/') { + *path_offset = '\0'; + path_depth++; + } + path_offset++; + } + path[path_len] = '\0'; + path_offset = path + 1; + uint32_t depth; + fs_node_t * node_ptr = fs_root; + for (depth = 0; depth < path_depth; ++depth) { + node_ptr = finddir_fs(node_ptr, path_offset); + if (!node_ptr) { + free((void *)path); + return NULL; + } else if (depth == path_depth - 1) { + return node_ptr; + } + } + free((void *)path); + return NULL; } diff --git a/include/ext2.h b/include/ext2.h index 06bd5857..fe71f37b 100644 --- a/include/ext2.h +++ b/include/ext2.h @@ -149,4 +149,6 @@ struct ext2_dir { typedef struct ext2_dir ext2_dir_t; +void initrd_mount(uint32_t mem_head, uint32_t mem_top); + #endif diff --git a/include/system.h b/include/system.h index e17939e5..35cf1847 100644 --- a/include/system.h +++ b/include/system.h @@ -30,6 +30,7 @@ extern unsigned short *memsetw(unsigned short *dest, unsigned short val, int cou extern int strlen(const char *str); extern unsigned char inportb (unsigned short _port); extern void outportb (unsigned short _port, unsigned char _data); +int strcmp(const char * a, const char * b); /* Panic */ #define HALT_AND_CATCH_FIRE(mesg) halt_and_catch_fire(mesg, __FILE__, __LINE__) @@ -129,5 +130,6 @@ void heap_install(); void * __attribute__ ((malloc)) malloc(size_t size); void * __attribute__ ((malloc)) realloc(void * ptr, size_t size); void * __attribute__ ((malloc)) calloc(size_t nmemb, size_t size); +void free(void * ptr); #endif diff --git a/main.c b/main.c index 89a4b53c..17b282cd 100644 --- a/main.c +++ b/main.c @@ -92,6 +92,14 @@ main(struct multiboot *mboot_ptr) { uint32_t module_start = *((uint32_t*)mboot_ptr->mods_addr); uint32_t module_end = *(uint32_t*)(mboot_ptr->mods_addr+4); + initrd_mount(module_start, module_end); + fs_node_t * test_file = kopen("/hello.txt", NULL); + if (!test_file) { + kprintf("Couldn't find /hello.txt\n"); + } + kprintf("Found %s at inode %d\n", test_file->name, test_file->inode); + +#if 0 ext2_superblock_t * superblock = (ext2_superblock_t *)(module_start + 1024); kprintf("Magic is 0x%x\n", (int)superblock->magic); assert(superblock->magic == EXT2_SUPER_MAGIC); @@ -160,6 +168,7 @@ main(struct multiboot *mboot_ptr) { } kprintf("\n"); }; +#endif return 0; }