VFS
因为在一个操作系统中不单只有一种文件系统,要使操作系统能够支持不同的文件系统,让他们能够友好共存,这就是VFS(Virtaul Filesystem Switch)的使命。VFS将对各种不同文件系统的管理和操作纳入到一个统一的框架中,使得用户程序可以通过同一个文件系统调用,对各种不同的文件系统和文件进行操作,而无需关心文件属于什么文件系统。
接下来看看具体实现:
//定义指向函数的指针,对应不同的文件系统,有不同的函数,使用这种方式可以
//统一接口
typedef unsigned int (*read_type_t)(struct fs_node*,unsigned int,unsigned int,unsigned char*);//读文件
typedef unsigned int (*write_type_t)(struct fs_node*,unsigned int,unsigned int,unsigned char*);//写文件
typedef void (*open_type_t)(struct fs_node*);//打开文件,然后可以接下其他动作
typedef void (*close_type_t)(struct fs_node*);//关闭文件
typedef struct dirent * (*readdir_type_t)(struct fs_node*,unsigned int);
//获取目录文件信息,返回目录项指针,因为有很多的目录项(每个文件对应一个)
typedef struct fs_node * (*finddir_type_t)(struct fs_node*,char *name);
//找到文件
上面是函数指针,实际上就是函数跳转表,每个函数指针指向具体文件系统用来实现文件操作的入口函数。
typedef 指令用来简化指针函数的写法,这样就可以在接下的结构体定义中,写出清晰的代码。
在看下界面的主体结构体:
typedef struct fs_node
{
char name[128]; // 文件名
unsigned int mask; // 权限掩码,读写和执行
unsigned int uid; // 用户id,user id
unsigned int gid; // 组id,group id
unsigned int flags; // 文件类型
unsigned int inode; //文件id,唯一,用来表示不同的文件
unsigned int length; // 文件大小(byte)
unsigned int impl; // An implementation-defined number.
read_type_t read;
write_type_t write;
open_type_t open;
close_type_t close;
readdir_type_t readdir;
finddir_type_t finddir;
struct fs_node *ptr; // 有符号链接时存在
} fs_node_t;
可以这样初始化一个文件的函数指针:
root_nodes[i].read = &initrd_read;
root_nodes[i].write = &initrd_write;
统一的函数实现如下,比如读文件:
unsigned int read_fs(fs_node_t *node, unsigned int offset, unsigned int size, unsigned char *buffer)
//读取索引节点node的文件数据,读取从offset位置开始,大小为size的数据
//将他们写到buffer中
{
if (node->read != 0)
//有读函数
return node->read(node, offset, size, buffer);
else
return 0;
}
initrd
initrd 的英文含义是 boot loader initialized RAM disk,就是由 boot loader 初始化的内存盘。在 linux内核启动前, boot loader 会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的 initrd 文件系统。
通过一下两个结构管理initrd中的文件。
unsigned int num_files; // ramdisk中的文件数
typedef struct
//文件格式信息
{
unsigned char name[64]; // 文件名
unsigned int address; // 文件在内存中的偏离起始位置的
//的大小,就是文件的地
unsigned int length; // 文件的长度
} initrd_file;
通过address和length,就可以找到文件,完成读写等操作。写操作如下:
static unsigned int write(fs_node_t *node,unsigned int offset,unsigned int size,unsigned char *buffer)
{
initrd_file header = file_headers[node->inode];
if(offset>header.length)
return 0;
if(size>strlen(buffer))
size=strlen(buffer);
file_headers[node->inode].length=offset+strlen(buffer);
root_nodes[node->inode].length=offset+strlen(buffer);
memcpy((unsigned char*)(header.offset+offset),buffer,size);
return size;
}