写入文件
文件的数据都是记录在inode中的文件块中,在该文件系统的设计中,只用了12个直接块和一个间接块来存储文件,所以一个文件最大可以存放 140 * 512字节的数据。
写文件的过程对文件块和扇区的分配过程,根据当前要写入的数据量大小,来判断是否需要分配新的数据块。如果12个直接块不够存储该数据,就分配间接块来存储,当所需的数据块分配好了之后,就会逐块的往硬盘上写入数据,知道所有的数据被写入硬盘,最后返回写入的字节数。
/* 把buf中的count个字节写入file,成功则返回写入的字节数,失败则返回-1 */
int32_t file_write(struct file *file, const void *buf, uint32_t count)
{
if ((file->fd_inode->i_size + count) > (BLOCK_SIZE * 140))
{
// 文件目前最大只支持512*140=71680字节
return -1;
}
uint8_t *io_buf = sys_malloc(BLOCK_SIZE);
if (io_buf == NULL)
{
return -1;
}
uint32_t *all_blocks = (uint32_t *)sys_malloc(BLOCK_SIZE + 48); // 用来记录文件所有的块地址
if (all_blocks == NULL)
{
printk("file_write: sys_malloc for all_blocks failed\n");
return -1;
}
const uint8_t *src = buf; // 用src指向buf中待写入的数据
uint32_t bytes_written = 0; // 用来记录已写入数据大小
uint32_t size_left = count; // 用来记录未写入数据大小
int32_t block_lba = -1; // 块地址
uint32_t block_bitmap_idx = 0; // 用来记录block对应于block_bitmap中的索引,做为参数传给bitmap_sync
uint32_t sec_idx; // 用来索引扇区
uint32_t sec_lba; // 扇区地址
uint32_t sec_off_bytes; // 扇区内字节偏移量
uint32_t sec_left_bytes; // 扇区内剩余字节量
uint32_t chunk_size; // 每次写入硬盘的数据块大小
int32_t indirect_block_table; // 用来获取一级间接表地址
uint32_t block_idx; // 块索引
/* 判断文件是否是第一次写,如果是,先为其分配一个块 */
if (file->fd_inode->i_sectors[0] == 0)
{
block_lba = block_bitmap_alloc(cur_part);
if (block_lba == -1)
{
return -1;
}
file->fd_inode->i_sectors[0] = block_lba;
/* 每分配一个块就将位图同步到硬盘 */
block_bitmap_idx = block_lba - cur_part->sb->data_start_lba;
ASSERT(block_bitmap_idx != 0);
bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);
}
/* 写入count个字节前,该文件已经占用的块数 */
uint32_t file_has_used_blocks = file->fd_inode->i_size / BLOCK_SIZE + 1;
/* 存储count字节后该文件将占用的块数 */
uint32_t file_will_use_blocks = (file->fd_inode->i_size + count) / BLOCK_SIZE + 1;
ASSERT(file_will_use_blocks <= 140);
/* 通过此增量判断是否需要分配扇区,如增量为0,表示原扇区够用 */
uint32_t add_blocks = file_will_use_blocks - file_has_used_blocks;
/* 开始将文件所有块地址收集到all_blocks,(系统中块大小等于扇区大小)
* 后面都统一在all_blocks中获取写入扇区地址 */
if (add_blocks == 0)
{
/* 在同一扇区内写入数据,不涉及到分配新扇区 */
if (file_has_used_blocks <= 12)
{ // 文件数据量将在12块之内
block_idx = file_has_used_blocks - 1; // 指向最后一个已有数据的扇区
all_blocks[block_idx] = file->fd_inode->i_sectors[block_idx];
}
else
{
/* 未写入新数据之前已经占用了间接块,需要将间接块地址读进来 */
ASSERT(file->fd_inode->i_sectors[12] != 0);
indirect_block_table = file->fd_inode->i_sectors[12];
ide_read(cur_part->my_disk, indirect_block_table, all_blocks + 12, 1);
}
}
else
{
/* 若有增量,便涉及到分配新扇区及是否分配一级间接块表,下面要分三种情况处理 */
/* 第一种情况:12个直接块够用*/
if (file_will_use_blocks <= 12)
{
/* 先将有剩余空间的可继续用的扇区地址写入al