操作系统真象还原:创建目录

14.11创建目录

14.11.1 实现sys_mkdir创建目录

Linux用mkdir函数创建目 录,还有一个同名的 mkdir命令也用来创建目录,原理上都是一回事 ,只是一个是系统调用,另一个是利用此系统调用实现的可执行程序 。

创建目录所涉及的工作包括:

  1. 确认待创建的新目录在文件系统上不存在
  2. 为新目录创建inode
  3. 为新目录分配 1 个块存储该目录中的目录项。
  4. 在新目录中创建两个目录项“.”和“…”这是每个目录都必须存在的两个目录项 。
  5. 在新目录的父目录中添加新目录的目录项。
  6. 将以上资源的变更同步到硬盘。
//fs.c

/*创建目录pathname,成功返回0,失败返回-1*/
int32_t sys_mkdir(const char* pathname){
    uint8_t rollback_step = 0;  //用于操作失败时回滚各种资源状态
    void* io_buf = sys_malloc(SECTOR_SIZE*2);
    if(io_buf==NULL){
        printk("sys_mkdir:sys_malloc for io_buf failed\n");
        return -1;
    }

    struct path_search_record search_record;
    memset(&search_record,0,sizeof(struct path_search_record));
    int inode_no = -1;
    inode_no = search_file(pathname,&search_record);
    if(inode_no!=-1){   //如果找到了同名的目录或者是文件.失败返回
        printk("sys mkdir: file or directory %s exist!\n",pathname);
        rollback_step = 1;
        goto rollback;
    }else{  //若未找到,也要判断是在最终目录没找到,还是某个中间目录不存在
        uint32_t pathname_depth = pathr_depth_cnt((char*)pathname);
        uint32_t path_searched_depth = pathr_depth_cnt(search_record.searched_path);
        /*先判断是否把 pathname 的各层目录都访问到了,即是否在某个中间目录就失败了*/
        if(pathname_depth != path_searched_depth){  //说明并没有访问到全部的路径,某个中间目录是不存在的
            printk("sys_mkdir : cannot access %s: Not a directory, subpath %s is`t exist\n",pathname,search_record.searched_path);;
            rollback_step = 1;
            goto rollback;
        }
    }

    struct dir* parent_dir = search_record.parent_dir;
    /*目录名称后可能会有字符'/',所以最好直接用search_record.searched_path,无'/'*/
    char* dirname = strrchr(search_record.searched_path,'/')+1;
    inode_no = inode_bitmap_alloc(cur_part);
    if(inode_no == -1){
        printk("sys_mkdir: allocate inode failed\n");
        rollback_step = 1;
        goto rollback;
    }
    
    struct inode new_dir_inode;
    inode_init(inode_no,&new_dir_inode);    //初始化i节点

    uint32_t block_bitmap_idx = 0;  //用来记录block对应于block_bitmap中的索引

    int32_t block_lba = -1;
    /*为目录分配一个块,用来写入目录.和..*/
    block_lba = block_bitmap_alloc(cur_part);
    if(block_lba == -1){
        printk("sys_mkdir: block bitmap_alloc for create directory failed\n");
        rollback_step = 2;
        goto rollback;
    }

    new_dir_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);

    /*将当前目录的目录项和'.'和'..'写入目录*/
    memset(io_buf,0,SECTOR_SIZE*2); //情况io_buf
    struct dir_entry* p_de = (struct dir_entry*)io_buf;
    
    /*初始化当前目录'.'*/
    memcpy(p_de->filename,".",1);
    p_de->i_no = inode_no;
    p_de->f_type = FT_DIRECTORY;
    
    p_de++;
    /*初始化当前目录'..'*/
    memcpy(p_de->filename,"..",2);
    p_de->i_no = parent_dir->inode->i_no;
    p_de->f_type = FT_DIRECTORY;
    ide_write(cur_part->my_disk,new_dir_inode.i_sectors[0],io_buf,1);

    new_dir_inode.i_size = 2*cur_part->sb->dir_entry_size;
    
    /*在父目录中添加自己的目录项*/
    struct dir_entry new_dir_entry;
    memset(&new_dir_entry,0,sizeof(struct dir_entry));
    create_dir_entry(dirname,inode_no,FT_DIRECTORY,&new_dir_entry);
    memset(io_buf,0,SECTOR_SIZE*2);
    if(!sync_dir_entry(parent_dir,&new_dir_entry,io_buf)){  //sync_dir_entry中将block_bitmap通过bitmap_sync同步到硬盘
        printk("sys_mkdir: sync_dir_entry to disk failed! \n");
        rollback_step = 2;
        goto rollback;
    }

    /*父目录的inode同步到硬盘*/
    memset(io_buf,0,SECTOR_SIZE*2);
    inode_sync(cur_part,parent_dir->inode,io_buf);

    /*将心创建目录的inode同步到硬盘*/
    memset(io_buf,0,SECTOR_SIZE*2);
    inode_sync(cur_part,&new_dir_inode,io_buf);

    /*将inode位图同步到硬盘*/
    bitmap_sync(cur_part,inode_no,INODE_BITMAP);

    sys_free(io_buf);
    
    /*关闭所创建目录的父目录*/
    dir_close(search_record.parent_dir);
    return 0;

rollback:
    switch (rollback_step)
    {
    case 2:
        bitmap_set(&cur_part->inode_bitmap,inode_no,0);//如果新文件的inode创建失败,之前图中分配的inode_no也要恢复
        break;
    
    case 1:
        /*关闭所创建目录的父目录*/
        dir_close(search_record.parent_dir);
        break;
    }
    sys_free(io_buf);
    return -1;
}

sys_mkdir支持 1 个参数,路径名 pathname,功能是创建目录pathname,成功返回 0,失败返回-1。创建目录也是由多个步骤完成的,因此创建目录的工作是个事务,具有原子性,即要么所有步骤都完成,要么一个都不做,若其中某个步骤失败,必须将之前完成的操作回漆到之前的状态。在函数开头定义rollback_step 用于记录回滚的步骤。

核心原理:1、调用search_file来确认待创建的新目录文件在文件系统是否存在,若未找到,也要判断是在最终目录没找到还是某个中间目录不存在,如果是中间目录不存在我们则模拟Linux一样给出提示然后退出;2、调用inode_bitmap_alloc来为新目录分配inode索引,并调用inode_init来初始化这个inode;3、调用block_bitmap_alloc来分配一个块用于承载该目录的目录文件。同时设定inodei_sectors[0],并调用bitmap_sync同步块位图;4、清零缓冲区,然后写入...两个目录项,之后将缓冲区内容写入到目录文件中,这就完成了...两个目录项的创建;5、创建并设定自己的目录项,调用sync_dir_entry来将目录项同步到父目录中;6、inode_sync同步父目录的inode与自己的inodebitmap_sync同步inode位图。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值