十八. 文件系统四(文件的读写与删除)

写入文件

文件的数据都是记录在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
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值