188 lines
6.5 KiB
C
188 lines
6.5 KiB
C
// ext2.c
|
|
// Author: Josh Holtrop
|
|
// Date: 08/22/04
|
|
// Modified: 08/22/04
|
|
|
|
#include "hos_defines.h"
|
|
#include "fs/devices.h"
|
|
#include "kout.h"
|
|
#include "ext2.h"
|
|
#include "mm/vmm.h"
|
|
#include "fs/vfs.h"
|
|
#include "lang/asmfuncs.h"
|
|
|
|
/* Turning an inode number into a (group, inode_index) pair:
|
|
* group = (inode - 1) / s_inodes_per_group
|
|
* index = (inode - 1) % s_inodes_per_group
|
|
*/
|
|
|
|
|
|
int ext2_init(int fsID)
|
|
{
|
|
vfs_fs_t *fs;
|
|
if (( fs = New(vfs_fs_t) ))
|
|
{
|
|
fs->mount_super = ext2_mount_super;
|
|
fs->umount_super = ext2_umount_super;
|
|
fs->mkfs = ext2_mkfs;
|
|
vfs_register_fs(fsID, fs);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int ext2_mkfs(major_t major, minor_t minor)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
// read the superblock of the filesystem and return a pointer to it
|
|
void *ext2_mount_super(major_t major, minor_t minor)
|
|
{
|
|
ext2_super_block_t *super = kmalloc(1024);
|
|
block_read(major, minor, 2, 2, super);
|
|
if (super->s_magic != EXT2_MAGIC) // not an ext2 filesystem
|
|
{
|
|
kfree(super);
|
|
return NULL;
|
|
}
|
|
return super;
|
|
}
|
|
|
|
void ext2_dump_root(vfs_mount_t *mount)
|
|
{
|
|
ext2_inode_t inode_root = ext2_get_inode(mount, 2);
|
|
kprintf("root dir i_mode: 0x%x, i_size: %d, i_links_count: %d, i_blocks: %d, i_uid: %d, i_gid: %d, i_flags: 0x%x\n", inode_root.i_mode, inode_root.i_size, inode_root.i_links_count, inode_root.i_blocks, inode_root.i_uid, inode_root.i_gid, inode_root.i_flags);
|
|
ext2_super_block_t *super = mount->super;
|
|
kprintf("s_def_resuid: %d, s_def_resgid: %d\n", super->s_def_resuid, super->s_def_resgid);
|
|
}
|
|
|
|
int ext2_stat(vfs_mount_t *mount, char *file, vfs_stat_t *stat)
|
|
{
|
|
if (file[0] != '/')
|
|
return -1;
|
|
char *fil = kmalloc(strlen(file) + 1);
|
|
strcpy(fil, file);
|
|
// TODO: stat the file :)
|
|
kfree(fil);
|
|
return 0;
|
|
}
|
|
|
|
ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number)
|
|
{
|
|
ext2_inode_t inode = ext2_get_inode(mount, inode_number);
|
|
ext2_open_inode_t *open_inode = New(ext2_open_inode_t);
|
|
open_inode->inode = inode;
|
|
open_inode->block = 0;
|
|
open_inode->block_pointers = NULL;
|
|
open_inode->block_pointers_start = 0;
|
|
return open_inode;
|
|
}
|
|
|
|
int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block)
|
|
{
|
|
ext2_super_block_t *super = mount->super;
|
|
// TODO: get the block number, read it to block
|
|
}
|
|
|
|
// transform open_inode->block (a relative block number) to an absolute block number for the filesystem
|
|
u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode)
|
|
{
|
|
// TODO: convert block_index to block number using open_inode fields
|
|
if (open_inode->block < 12)
|
|
return open_inode->inode.i_block[open_inode->block];
|
|
ext2_super_block_t *super = mount->super;
|
|
int pointersPerBlock = 256 << super->s_log_block_size;
|
|
if (open_inode->block_pointers && // there is a block pointers cache block allocated
|
|
(open_inode->block >= open_inode->block_pointers_start) && // and the block number is in it
|
|
(open_inode->block < (open_inode->block_pointers_start + pointersPerBlock)))
|
|
return open_inode->block_pointers[open_inode->block - open_inode->block_pointers_start];
|
|
u32_t rel_block = open_inode->block - 12;
|
|
if (!open_inode->block_pointers)
|
|
open_inode->block_pointers = kmalloc(pointersPerBlock << 2);
|
|
if (rel_block < pointersPerBlock) // indirect block in i_block[12]
|
|
{
|
|
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[12], super),
|
|
1 << super->s_log_block_size, open_inode->block_pointers);
|
|
open_inode->block_pointers_start = 12;
|
|
return open_inode->block_pointers[rel_block];
|
|
}
|
|
rel_block -= pointersPerBlock;
|
|
if (rel_block < (pointersPerBlock * pointersPerBlock)) // double-indirect block in i_block[13]
|
|
{
|
|
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[13], super),
|
|
1 << super->s_log_block_size, open_inode->block_pointers);
|
|
u32_t real_block = open_inode->block_pointers[rel_block / pointersPerBlock];
|
|
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(real_block, super),
|
|
1 << super->s_log_block_size, open_inode->block_pointers);
|
|
open_inode->block_pointers_start = 12 + pointersPerBlock + rel_block - (rel_block % pointersPerBlock);
|
|
return open_inode->block_pointers[rel_block % pointersPerBlock];
|
|
}
|
|
rel_block -= pointersPerBlock * pointersPerBlock;
|
|
// TODO: triple-indirect block in i_block[14]
|
|
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[14], super),
|
|
1 << super->s_log_block_size, open_inode->block_pointers);
|
|
u32_t block_1 = open_inode->block_pointers[rel_block / (pointersPerBlock * pointersPerBlock)];
|
|
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_1, super),
|
|
1 << super->s_log_block_size, open_inode->block_pointers);
|
|
u32_t block_2 = open_inode->block_pointers[rel_block / (pointersPerBlock * pointersPerBlock)];
|
|
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_1, super),
|
|
1 << super->s_log_block_size, open_inode->block_pointers);
|
|
open_inode->block_pointers_start = 12 + pointersPerBlock + rel_block - (rel_block % pointersPerBlock);
|
|
return open_inode->block_pointers[rel_block % pointersPerBlock];
|
|
}
|
|
|
|
int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode)
|
|
{
|
|
if (open_inode->block_pointers)
|
|
kfree(open_inode->block_pointers);
|
|
kfree(open_inode);
|
|
return 0;
|
|
}
|
|
|
|
inline u32_t ext2_diskToFSBlock(u32_t block, ext2_super_block_t *super)
|
|
{
|
|
// convert # of disk blocks to # of filesystem blocks
|
|
return block >> (super->s_log_block_size + 1);
|
|
}
|
|
|
|
inline u32_t ext2_FSToDiskBlock(u32_t block, ext2_super_block_t *super)
|
|
{
|
|
// convert # of filesystem blocks to # of disk blocks
|
|
return block << (super->s_log_block_size + 1);
|
|
}
|
|
|
|
ext2_inode_t ext2_get_inode(vfs_mount_t *mount, u32_t inode)
|
|
{
|
|
ext2_super_block_t *super = mount->super;
|
|
inode--; // turn inode into a 0-based index
|
|
u32_t group = inode / super->s_inodes_per_group;
|
|
u32_t index = inode % super->s_inodes_per_group;
|
|
u32_t inodeAddr = (ext2_get_group_desc(mount, group).bg_inode_table <<
|
|
(10 + super->s_log_block_size)) + (index << 7);
|
|
void *block = kmalloc(512);
|
|
block_read(mount->major, mount->minor, inodeAddr >> 9, 1, block);
|
|
ext2_inode_t in = *(ext2_inode_t *)(block + (inodeAddr & 0x1FF));
|
|
kfree(block);
|
|
return in;
|
|
}
|
|
|
|
ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group)
|
|
{
|
|
ext2_super_block_t *super = mount->super;
|
|
u32_t groupDescAddr = ((1 + super->s_first_data_block) << (10 + super->s_log_block_size)) + (group << 5);
|
|
void *block = kmalloc(512);
|
|
block_read(mount->major, mount->minor, groupDescAddr >> 9, 1, block);
|
|
ext2_group_desc_t gd = *(ext2_group_desc_t *)(block + (groupDescAddr & 0x1FF));
|
|
kfree(block);
|
|
return gd;
|
|
}
|
|
|
|
int ext2_umount_super(vfs_mount_t *mount)
|
|
{
|
|
return kfree(mount->super);
|
|
}
|
|
|