6.s081 lab1.4--find【全注释小白向,个人探索】

MIT 6.s081 lab1.4–find

No.1 写在前面的话

这是我自sleep以来做的第二个最顺利的实验(大声)!实际上,根据提示看懂ls后,写起来真的会很顺利,关键就在于看懂,以及思考提示的内容在哪里可以利用。我根据我的理解对代码进行了全部注释,方便思考。(真的太不容易了)

No.2 学习ls.c的读取目录

一定要先从main看起,这样一层一层才知道架构。

char*
fmtname(char *path)
{
  static char buf[DIRSIZ+1];
  char *p;

  for(p=path+strlen(path); p >= path && *p != '/'; p--)
    ;// if path_name = ./file1/a/b/file_c  then p-> "file_c"
  p++;//然后开始一点点读取

  if(strlen(p) >= DIRSIZ)
    return p;//return file name
    //下面两步其实不太理解,只是参考他人注释暂时写入
  memmove(buf, p, strlen(p));//如果 len(p)<DIRSIZ,将 *p 内容移动到 buf,
  memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));//对buf[len(p)]开始的部分进行初始化为空,就是占满buf的空间

  return buf;
}

void
ls(char *path)
{
  char buf[512], *p;
  int fd;
  struct dirent de;//包含目录结构顺序的文件
  struct stat st;//文件状态

  if((fd = open(path, 0)) < 0){//打开path,标志为只读
    fprintf(2, "ls: cannot open %s\n", path);
    return;
  }

  if(fstat(fd, &st) < 0){//文件状态无,将fd指向的文件状态复制到st的结构体中
    fprintf(2, "ls: cannot stat %s\n", path);
    close(fd);
    return;
  }
  //上面两步判断已经将path打开,且将path文件状态写入st。
  //接下来就是一个个读取。

  switch(st.type){
  case T_FILE:
    printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
    break;

  case T_DIR:
    if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){//为什么要这样计算
    //似乎为【路径长度+空字符+目录的最大长度】,+1又是什么?
      printf("ls: path too long\n");
      break;
    }
    strcpy(buf, path);//将path指向的字符串复制到buf
    p = buf+strlen(buf);//没看懂,size是512还是path?
    //p->buf[0]前进strlen(buf)--> p->buf[strlen(buf)],这里size是path,也就是移动到了path末尾

    *p++ = '/';//原来如此,这就分割为【xx//】了,以路径名访问目录
    *p++ = '/';

    while(read(fd, &de, sizeof(de)) == sizeof(de)){
      //此处读取目录
      //每次read只是read一个de的大小(也就是一个目录项),
      //只有read到最后一个目录项的下一次read才会返回0,也就不满足while循环条件退出循环

      if(de.inum == 0)//inum指占用了几个inode,此处代表此文件夹无文件
        continue;
      memmove(p, de.name, DIRSIZ);//将name移动到p,这里也即直接复写
      p[DIRSIZ] = 0;//这里我不懂,p最后是什么样子?是在重置吗?p似乎只是一个暂存区。
      if(stat(buf, &st) < 0){//如果buf中的数据没有复制到st
        printf("ls: cannot stat %s\n", buf);
        continue;
      }
      printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
    }
    break;
  }
  close(fd);
}

int
main(int argc, char *argv[])
{
  int i;

  if(argc < 2){
    ls(".");
    exit(0);
  }
  for(i=1; i<argc; i++)
    ls(argv[i]);
  exit(0);
}

No.3 开始find

看懂ls后find就清晰起来。ls是单一参数,只显示当前目录下的内容;但是find要显示目录的目录下的内容,也就是稍稍作以嵌套的ls。

提示进行递归调用,那么一定是得要在目录读取后进行;并且还提醒了利用strcmp()进行比较,比较什么,根据提示自然而然就能想到:比较是否当前目录是“.”和“..”,如果是,就跳过。代码如下:

char* GetFileName(char *path){
    //看了别人的文章这里只需要p,不用buf
    //现在才清楚,当递归使用时,文件路径已经填充好,只需得到当前路径下的当前文件名就可【1】
    char *p;

    for(p = path + strlen(path); p >= path && *p != '/'; p--)
        ;
    p++;
    return p;

    
}

void find(char *path, char* target){
    char buf[512], *p;
    int fd;
    struct dirent de;
    struct stat st;

    if((fd = open(path, 0)) < 0){
        fprintf(2, "find: cannot open %s\n", path);
        return;
    }

    if(fstat(fd, &st) < 0){
        fprintf(2, "find: cannot stat %s\n", path);
        close(fd);
        return;
    }

    switch (st.type)
    {
    case T_FILE:
        //这里我一开始直接printf,以为只要到文件就一定是它【意图通过用例的偷懒法】
        //其实是错的,需要比较才行
        if(strcmp(GetFileName(path), target) == 0){
            printf("%s\n", path);
            //当递归调用时,path已经变为拼接好'/'的buf【1】
        }
        break;
    
    case T_DIR:
        if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
            printf("find: path too long\n");
            break;
        }
    
        strcpy(buf, path);
        p = buf + strlen(buf);
        *p++ = '/';

        while (read(fd, &de, sizeof(de)) == sizeof(de))
        {
            if(de.inum == 0)
                continue;
            if(strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0){
                continue;
            }
            memmove(p, de.name, DIRSIZ);
            p[DIRSIZ] = 0;
            if(stat(buf, &st) < 0){
                printf("find: cannot stat %s\n", buf);
                continue;
            }
            //这里对比ls不需要printf,似乎是因为ls只是返回了一层目录名。
            find(buf, target);
        }
        break;
    }
    close(fd);
}



int main(int argc, char *argv[]){
    if(argc < 3){
        printf("need 2 dirctory's name.\n");
        exit(1);
    }
    for(int i = 1; i < argc; i++){
        find(argv[i], argv[i+1]);
    }
    exit(0);
}

轻松通过。【用时多半天】

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值