持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情
接着上篇文章,在每一个系统中,文件操作都是必不可少的一部分,每一个操作都需要复杂的步骤,这篇文章争对文件操作进行了一部分的总结是,实验与笔记 注:内容相对枯燥,就是我个人学习过程中的技术笔记与总结思考
文件操作
在fs/fs.c 中我们已经提供了很多函数去实现解释和管理File结构体的基本要素,扫描和管理目录文件的条目以及从根目录遍历文件系统以解析绝对路径。请阅读fs/fs.c中的代码,保证你了解代码中的每一处细节。
在这里我提供了fs.c中文件系统的主要函数的功能:
| Function Name | Function |
|---|---|
| fs_init() | 初始化文件系统(寻找要使用的硬盘) |
| file_block_walk() | 寻找File结构体f中第fileno个块指向的磁盘块编号放入ppdiskbno中。如果filebno<NDIRECT,则返回f.direct[NDIRECT]中的对应项,否则返回f_inderect中查找到的块。如果设置alloc为true则会在必要时分配一个磁盘块 |
| file_get_block() | 设置blk到f结构体中的第filebno块映射在内存的地址 |
| dir_lookup() | 在dir中寻找文件名为name的文件,如果查找到就把f指向那个位置 |
| dir_alloc_file() | 将file指针设置到dir中的一个空闲File结构体,调用方负责填写文件的各个字段 |
| skip_slash() | 处理路径字符串,跳过一个’/’ |
| walk_path() | 如果找到path绝对路径的文件,则把其文件结构体赋给pf,其所在的目录结构体赋给pdir。lastelm是失败时检测到的最后一个文件名 |
| file_read()/write() | 从文件中读count字节到buf/从buf中写count字节到文件 |
| file_truncate_blocks() | 将文件截断为指定大小,如果新的块数<NDIRECT,则要把f->indirect清零,但是不要改变f->f_size |
Exercise 4. Implement file_block_walk() and file_get_block(). file_block_walk() maps from a block offset within a file to the pointer for that block in the struct File or the indirect block, very much like what pgdir_walk() did for page tables. file_get_block() goes one step further and maps to the actual disk block, allocating a new one if necessary.
static int
file_block_walk(struct File *f, uint32_t filebno, uint32_t **ppdiskbno, bool alloc)
{
// LAB 5: Your code here.
if (filebno > NDIRECT + NINDIRECT) return -E_INVAL;
if (filebno < NDIRECT) {
*ppdiskbno = &(f->f_direct[filebno]);
} else {
uint32_t blockno, *indirects;
if (f->f_indirect) {
indirects = diskaddr(f->f_indirect);
*ppdiskbno = &(indirects[filebno - NDIRECT]);
} else {
if (!alloc)
return -E_NOT_FOUND;
if ((blockno = alloc_block()) < 0)
return blockno;
f->f_indirect = blockno;
flush_block(diskaddr(blockno));
indirects = diskaddr(blockno);
*ppdiskbno = &(indirects[filebno - NDIRECT]);
}
}
return 0;
}
这个函数是我们实现文件系统的主要函数,功能实现:
- 如果filebno位于直接块中,则将其对应的磁盘编号存入ppdiskbno中
- 否则返回在f_indirects中查找到的对应块的磁盘编号,存入ppdiskbno中
- 如果不在f_indirects的项,alloc为true时分配一个磁盘块并存入ppdiskno
- 否则抛出错误E_NOT_FOUND
int
file_get_block(struct File *f, uint32_t filebno, char **blk)
{
// LAB 5: Your code here.
int r;
uint32_t *ppdiskbno;
if ((r = file_block_walk(f, filebno, &ppdiskbno, 1)) < 0) {
return r;
}
int blockno;
if (*ppdiskbno == 0) {
if ((blockno = alloc_block()) < 0) {
return blockno;
}
*ppdiskbno = blockno;
flush_block(diskaddr(blockno));
}
*blk = diskaddr(*ppdiskbno);
return 0;
}
通过调用file_block_walk()找到filebno所在的目标块,然后将该块的地址复制给blk。
file_block_walk() 和file_get_block() 是实现文件系统的主力。例如file_read() 和file_write()只不过是在file_get_block()记录的散列的块和顺序缓冲区之间必要地拷贝一些字节。