[ext2] Massive EXT2 compatibility commit.

This commit is contained in:
Kevin Lange 2011-01-29 14:12:00 -06:00
parent 73e15ede2f
commit f6fdaf49aa
7 changed files with 238 additions and 9 deletions

View File

@ -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. */

View File

@ -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,16 +68,71 @@ readdir_initrd(
fs_node_t *node,
uint32_t index
) {
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
) {
/*
* 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
initrd_node_from_file(
@ -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;
}

View File

@ -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`.

View File

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

View File

@ -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

View File

@ -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

9
main.c
View File

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