写入文件
文件的数据都是记录在inode中的文件块中,在该文件系统的设计中,只用了12个直接块和一个间接块来存储文件,所以一个文件最大可以存放 140 * 512字节的数据。
写文件的过程对文件块和扇区的分配过程,根据当前要写入的数据量大小,来判断是否需要分配新的数据块。如果12个直接块不够存储该数据,就分配间接块来存储,当所需的数据块分配好了之后,就会逐块的往硬盘上写入数据,知道所有的数据被写入硬盘,最后返回写入的字节数。
1 | /* 把buf中的count个字节写入file,成功则返回写入的字节数,失败则返回-1 */ |
最后将write添加到系统调用中, 根据其文件描述符来判断数据是写入磁盘还是标准输出中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26int32_t sys_write(int32_t fd, const void *buf, uint32_t count)
{
if (fd < 0)
{
return -1;
}
if (fd == stdout_no)
{
char tmp_buf[1024] = {0};
memcpy(tmp_buf, buf, count);
console_put_str(tmp_buf);
return count;
}
uint32_t _fd = fd_local2global(fd);
struct file *wr_file = &file_table[_fd];
if (wr_file->fd_flag & O_WRONLY || wr_file->fd_flag & O_RDWR)
{
uint32_t bytes_written = file_write(wr_file, buf, count);
return bytes_written;
}
else
{
console_put_str("sys_write: not allowed to write file without flag O_RDWR or O_WRONLY\n");
return -1;
}
}
上图是向文件file1中写入数据hello,world之后,磁盘上数据的表现。
写入的位置是第0xa6c个扇区,将其*512转换成地址之后查看该地址的数,可以看到数据确实写入到磁盘上了。
读取文件
1 | /* 从文件file中读取count个字节写入buf, 返回读出的字节数,若到文件尾则返回-1 */ |
设置文件的读写偏移量
想象一下这种情况,在文件读取到文件尾的时候,再想去读取文件前面的部分。在目前的实现下,只能将该文件关闭之后,再重新打开,才能读取到之前的数据,这样做的话显然是不合理的。所以需要实现文件读写定位的功能。也就是lseek的实现。
文件的读写偏移量的设置有三个基准数,文件头,文件当前位置,文件尾。
1 | // 文件读写位置偏移量 |
1 | /* 重置用于文件读写操作的偏移指针,成功时返回新的偏移量,出错时返回-1 */ |
删除文件
删除文件主要是对资源的回收。主要有以下几部分的数据
- inode
- inode bitmap
- inode table
- inode中的12个直接块和一个间接块
- 存储间接块的扇区
- 目录项
- 该文件对应的目录项数据需要清0
- 该文件删除之后,目录中不存在目录项,需要回收目录项对应的块
- 目录inode中的size需要减去该文件目录项大小
- 将目录inode同步到硬盘
上面两部分资源的回收主要通过inode_release和delete_dir_entry这两个函数实现,这里只贴出删除文件的整体调用过程。
1 | /* 删除文件(非目录),成功返回0,失败返回-1 */ |