当前位置: 首页 > article >正文

10.Lab Nine —— file system-下

 Symbolic links

添加符号链接

1.添加有关symlink系统调用的定义声明,包括kernel/syscall.h, kernel/syscall.c, user/usys.pluser/user.h.

2.添加新的文件类型T_SYMLINK到kernel/stat.h中,添加新的文件标识位O_NOFOLLOW到kernel/fcntl.h中

3.在kenel/sysfile.c中实现sys_symlink()函数

该函数用于生成符号链接,该符号链接相当于一个特殊的独立文件,里面存储的是目标文件的路径

4.修改kernel/sysfile中的sys_open()函数

该函数可以用来打开文件,对于符号链接一般情况下需要打开的是其目标文件,因此需要额外处理

(此处需要注意避免成环问题的出现)

/* 系统调用open的实现 */
uint64
sys_open(void)
{
  /* 路径名缓冲区 */
  char path[MAXPATH];
  /* 文件描述符和打开模式 */
  int fd, omode;
  /* 文件结构指针 */
  struct file *f;
  /* i节点指针 */
  struct inode *ip;
  /* 临时变量,用于存储函数调用返回值 */
  int n;

  /* 获取路径名和打开模式,如果出错则返回-1 */
  if((n = argstr(0, path, MAXPATH)) < 0 || argint(1, &omode) < 0)
    return -1;

  /* 开始一个文件操作 */
  begin_op();

  /* 如果需要创建文件 */
  if(omode & O_CREATE){
    /* 调用create函数创建文件,如果失败则返回-1 */
    ip = create(path, T_FILE, 0, 0);
    if(ip == 0){
      end_op();
      return -1;
    }
  } else {
    int symlink_depth = 0;
    /* 查找已存在的文件,如果失败则返回-1 */
    while(1){
      if((ip = namei(path)) == 0){
        end_op();
        return -1;
      }
      /* 加锁i节点 */
      ilock(ip);

      if(ip->type == T_SYMLINK && (omode & O_NOFOLLOW) == 0){
        //在跟踪符号链接时需要额外考虑到符号链接的目标可能还是符号链接, 此时需要递归的去跟踪目标链接直至得到真正的文件. 而这其中需要解决两个问题: 一是符号链接可能成环, 这样会一直递归地跟踪下去, 因此需要进行成环的检测; 另一方面是需要对链接的深度进行限制, 以减轻系统负担,这里把最大深度设成10
        if(++symlink_depth > 10){
          // too many layer of symlinks, might be a loop
          iunlockput(ip);
          end_op();
          return -1;
        }
        if(readi(ip, 0, (uint64)path, 0, MAXPATH) < 0){
          iunlockput(ip);
          end_op();
          return -1;
        }
        iunlockput(ip);
        
      }else{
        break;
      }
    }

    /* 如果是目录文件且不是只读打开,返回-1 */
    if(ip->type == T_DIR && omode != O_RDONLY){
      // // 如果是目录,并且打开模式不是 O_RDONLY(只读),则不能打开
      iunlockput(ip);
      end_op();
      return -1;
    }
  }

  /* 如果是设备文件,检查设备号是否有效,否则返回-1 */
  if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
    iunlockput(ip);
    end_op();
    return -1;
  }

  /* 分配文件结构,如果失败则返回-1 */
  if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
    if(f)
      fileclose(f);
    iunlockput(ip);
    end_op();
    return -1;
  }

  // //处理符号链接,即软连接,如果
  // if(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)){ //如果不是不可追踪
  //   //若符号链接指向的仍旧是符号链接,则递归跟随它,直到找到真正的指向文件
  //   //深度不能超过MAX_SYMLINK_DEPTH
  //   for(int i = 0; i < MAX_SYMLINK_DEPTH; i++){
  //     //读出符号链接指的路径
  //   }
  // }

  /* 根据文件类型设置文件结构的类型和主要设备号 */
  if(ip->type == T_DEVICE){
    f->type = FD_DEVICE;
    f->major = ip->major;
  } else {
    f->type = FD_INODE;
    f->off = 0;
  }
  /* 设置文件结构的i节点指针和读写权限 */
  f->ip = ip;
  f->readable = !(omode & O_WRONLY);
  f->writable = (omode & O_WRONLY) || (omode & O_RDWR);

  /* 如果要求截断文件,且文件类型是普通文件,则截断文件 */
  if((omode & O_TRUNC) && ip->type == T_FILE){
    itrunc(ip);
  }

  /* 解锁i节点 */
  iunlock(ip);
  /* 结束文件操作 */
  end_op();

  /* 返回文件描述符 */
  return fd;
}

这里也可以看一下硬链接的实现方式(kernel/sysfile)

// Create the path new as a link to the same inode as old.
//xv6硬链接实现方式
uint64 sys_link(void) {
  char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
  struct inode *dp, *ip;

  // 从用户态获取参数 old 和 new,分别表示旧路径和新路径
  if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
    return -1;

  // 开始文件系统操作事务
  begin_op();

  // 根据旧路径名找到 inode
  if((ip = namei(old)) == 0){
    end_op();
    return -1;
  }

  // 对 inode 进行加锁
  ilock(ip);

  // 检查旧路径对应的 inode 是否为目录,如果是目录则不能创建硬链接
  if(ip->type == T_DIR){
    iunlockput(ip); // 解锁 inode 并释放引用
    end_op();
    return -1;
  }

  // 增加 inode 的链接数,因为即将创建一个新的硬链接指向该 inode
  ip->nlink++;
  iupdate(ip); // 更新 inode 的磁盘信息
  iunlock(ip); // 解锁 inode

  // 解析新路径中的目录名和文件名
  if((dp = nameiparent(new, name)) == 0)
    goto bad;

  // 对目录的 inode 进行加锁
  ilock(dp);

  // 检查新路径所在的目录的设备号与旧路径所在的设备号是否相同
  // 如果不相同,或者在新路径所在的目录中无法创建新的目录项,说明创建硬链接失败
  if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
    iunlockput(dp); // 解锁目录的 inode 并释放引用
    goto bad;
  }

  // 解锁目录的 inode 并释放引用
  iunlockput(dp);

  // 释放旧路径对应的 inode 的引用
  iput(ip);

  // 结束文件系统操作事务
  end_op();

  return 0;

bad:
  // 创建硬链接失败时,需要回滚之前对旧路径 inode 的修改,即减少链接数
  ilock(ip);
  ip->nlink--;
  iupdate(ip);
  iunlockput(ip);
  end_op();
  return -1;
}

5.最后在Makefile中添加对测试文件symlinktest.c 的编译.

测试


http://www.kler.cn/a/320099.html

相关文章:

  • 年后找工作需要注意的事项
  • C 语言标准库函数——strtol函数
  • o3模型重大突破:引领推理语言模型新纪元,展望2025年AI发展新格局
  • Ubuntu把应用程序放到桌面
  • Qt之http客户端类
  • Redis复制(replica)
  • CorePress Pro 网站加载慢 WordPress
  • 计算机毕业设计 基于 Hadoop平台的岗位推荐系统 SpringBoot+Vue 前后端分离 附源码 讲解 文档
  • JavaScript window的open和close用法
  • LeetCode 面试经典150题 137.只出现一次的数字II
  • 深入探索 RUM 与全链路追踪:优化数字体验的利器
  • Python有常用库学习整理(一)
  • ThreadPoolExecutor的原理?
  • 【大数据】元数据是解锁数据价值的关键
  • JPA+Thymeleaf增删改查
  • WPF 绑定 DataGrid 里面 Button点击事件 TextBlock 双击事件
  • 免杀笔记 ---> 无痕Hook?硬件断点 Syscall!
  • Git 的安装和配置
  • Ubuntu下TexMaker发生CTeX fontset `fandol‘ is unavailable问题
  • SpringSecurity-用户认证
  • JAVA基础语法 day07
  • 全能通人工智能的能力评估框架-Levels of AGI: Operationalizing Progress on the Path to AGI
  • 欺诈文本分类检测(十六):支持分类原因评测改造
  • 面经 | 手写
  • 口语笔记——被动语态
  • spring boot 项目中redis的使用,key=value值 如何用命令行来查询并设置值。