首页 > 其他分享 >【MIT-OS6.S081作业1.4】Lab1-utilities find

【MIT-OS6.S081作业1.4】Lab1-utilities find

时间:2024-12-08 19:33:04浏览次数:6  
标签:1.4 de utilities st ls path buf find

本文记录MIT-OS6.S081 Lab1 utilities 的find函数的实现过程

文章目录

1. 作业要求

find (moderate)

Write a simple version of the UNIX find program: find all the files in a directory tree with a specific name. Your solution should be in the file user/find.c.

Some hints:

  • Look at user/ls.c to see how to read directories.
  • Use recursion to allow find to descend into sub-directories.
  • Don’t recurse into “.” and “…”.
  • Changes to the file system persist across runs of qemu; to get a clean file system run make clean and then make qemu.
  • You’ll need to use C strings. Have a look at K&R (the C book), for example Section 5.5.
  • Note that == does not compare strings like in Python. Use strcmp() instead.
  • Add the program to UPROGS in Makefile.
  • Your solution is correct if produces the following output (when the file system contains the files b and a/b):

$ make qemu

init: starting sh
$ echo > b
$ mkdir a
$ echo > a/b
$ find . b
./b
./a/b
$

2. 实现过程

2.1 代码实现

提示中说到要重点关注user/ls.c的实现,我们来看一下ls.c

#include "user/user.h"
#include "kernel/fs.h"

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

  // Find first character after last slash.
  for(p=path+strlen(path); p >= path && *p != '/'; p--)
    ;
  p++;

  // Return blank-padded name.
  if(strlen(p) >= DIRSIZ)
    return p;
  memmove(buf, p, strlen(p));
  memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
  return buf;
}

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

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

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

  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){
      printf("ls: 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;
      memmove(p, de.name, DIRSIZ);
      p[DIRSIZ] = 0;
      if(stat(buf, &st) < 0){
        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);
}

main函数很好懂,如果输入参数小于2(只有一个ls),那么对当前目录(.)进行ls,否则对ls后面所有的参数视为目录进行ls。我们看下ls函数,下面进行了注释:

void
ls(char *path)
{
  char buf[512], *p;
  int fd;
  struct dirent de;
  struct stat st;
  // 打开path路径
  if((fd = open(path, 0)) < 0){
    fprintf(2, "ls: cannot open %s\n", path);
    return;
  }
  // 获取路径的信息
  if(fstat(fd, &st) < 0){
    fprintf(2, "ls: cannot stat %s\n", path);
    close(fd);
    return;
  }
  // 查看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: // 文件夹
    // 因为路径下还有文件要继续向下查找文件并在路径后面加上文件的名字,DIRSIZ表示当前文件夹下文件/文件夹名的最大长度,+1表示末尾的'\0',strlen不记录'\0',如果strlen(path) + 1 + DIRSIZ + 1 > sizeof buf那么路径太长了buf会越界,退出
    if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
      printf("ls: path too long\n");
      break;
    }
    // 路径拷贝到buf
    strcpy(buf, path);
    // p指向'\0'并替换为'/',然后自增
    p = buf+strlen(buf);
    *p++ = '/';
    // 读取dirent 类型的de结构体
    while(read(fd, &de, sizeof(de)) == sizeof(de)){
      if(de.inum == 0)
        continue;
      // de.name搬动到p,移动长度为DIRSIZ,末尾设置为0
      memmove(p, de.name, DIRSIZ);
      p[DIRSIZ] = 0;
      // 读取buf文件的状态
      if(stat(buf, &st) < 0){
        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);
}

这里使用了fmtname,我们在qemu模拟使用ls,我们会发现打印的就是文件的名字:

在这里插入图片描述
那么我们看一下fmtname的实现,其实就是找到倒数第一个’/‘,然后p移动到’/'后面表示文件名的开头,设置了一个buf来复制文件名:

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

  // Find first character after last slash.
  for(p=path+strlen(path); p >= path && *p != '/'; p--)
    ;
  p++;

  // Return blank-padded name.
  if(strlen(p) >= DIRSIZ)
    return p;
  //移动长度是strlen,DIRSIZ没有填满在后面填充' ',这样的好处是shell打印出来是对齐的,比如打印为下面,文件名和后面的数字中间的间隔是对齐的
  /*
  $ ./a/b          1 1 2 
  $ ./b            1 1 5
  */
  memmove(buf, p, strlen(p));
  memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
  return buf;
}

我们可以编写我们的find函数了,其实就是把上面的ls拿来改一改,要注意的是进行递归搜索,如果发现是文件夹,那么向下递归的path参数是文件+文件名,如果发现是文件,判断是否是要找的文件名,如果是那么打印,递归停止。

为了不匹配’.‘和’…',我们需要在遍历到文件夹时进行判断来跳过:

if (de.inum == 0 || strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)

完整代码:

#include "kernel/types.h"
#include "user/user.h"
#include "kernel/stat.h"
#include "kernel/fs.h"

char* getFileName(char *path)
{
  char *p;

  // Find first character after last slash.
  for(p=path+strlen(path); p >= path && *p != '/'; p--)
    ;
  p++;

  return p;
}

void find(char* path, char* name)
{
    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;
    }

    if (st.type == T_FILE)
    {
        char* fileName = getFileName(path);
        if (strcmp(fileName, name) == 0)
	        printf("%s\n", path);
	    close(fd);
    }
    else if (st.type == T_DIR)
    {
        if (strlen(path) + 1 + DIRSIZ + 1 > sizeof(buf))
		{
            printf("find: path too long\n");
		}
		else
		{
            strcpy(buf, path);
            p = buf + strlen(buf);
		    *p++ = '/';
		    while (read(fd, &de, sizeof(de)) == sizeof(de))
		    {
                if (de.inum == 0 || 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;
				}
                find(buf, name);
		
	    	}
	    
		}
       	close(fd);
    }

    
}

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
	printf("error: find <?> <?>\n");
        exit(1);
    }
    find(argv[1], argv[2]);
    exit(0);
}

UPROGS=\
	$U/_cat\
	$U/_echo\
	$U/_forktest\
	$U/_grep\
	$U/_init\
	$U/_kill\
	$U/_ln\
	$U/_ls\
	$U/_mkdir\
	$U/_rm\
	$U/_sh\
	$U/_stressfs\
	$U/_usertests\
	$U/_grind\
	$U/_wc\
	$U/_zombie\
	$U/_sleep\ 
	$U/_pingpong\ 
	$U/_primes\ 
	$U/_find\ 

重新编译通过,测试find,如题所述正确打印:

在这里插入图片描述

确实过了一会然后可以继续输入命令,然后我们再使用作业所说的测试命令:

./grade-lab-util find

在这里插入图片描述

完活!

文件夹和文件的递归还是比较好想的。

标签:1.4,de,utilities,st,ls,path,buf,find
From: https://blog.csdn.net/subtitle_/article/details/144329058

相关文章

  • NocoBase 1.4.0 正式版发布
    主要新特性简化插件的添加和更新流程插件列表直接读取本地目录合并插件添加和更新流程界面支持批量激活插件简化商业插件下载和升级流程参考文档:插件的安装与升级发布日志/简化插件的添加和更新流程通知站内信:支持用户在NocoBase应用内实时接收消息通知;电子......
  • FIND_IN_SET() 和 POSITION () 灵活使用
    需求A字段中去B字段找是否存在,B字段为,隔开,不存在找第一个赋值SELECTws.sample_id,ws.ex_warehouse_user_id,wss.test_user_id,if(POSITION(','INwss.test_user_id)=0,wss.test_user_id,LEFT(wss.test_user_id,POSITION(','INwss.test_user_id)-1))fromwt_samp......
  • Linux: Centos7 Cannot find a valid baseurl for repo: base/7/x86_64 解决方案
    问题背景执行yumupdate出现如下报错排查虚拟机是否联网ping-c4www.baidu.com可以看到网络链接没有问题解决方案原因是国外的镜像源有问题,换成国内的即可。备份原有的镜像源sudomv/etc/yum.repos.d/CentOS-Base.repo/etc/yum.repos.d/CentOS-Base.repo.backup......
  • HS6621Cx/OM6621Px国产低功耗蓝牙芯片支持Find My寻物
    什么是“FindMy“?“FindMy”是苹果公司于19年前推出的针对失物追踪,FindMyiPhone(查找我的iPhone)和FindMyFriends(查找朋友)的结合体应用。为第三方配件制造商设计的FindMy网络配件计划,允许设备制造商将FindMyright集成到他们的产品中。该应用基于低功耗蓝牙技术,利用苹......
  • Cannot find a valid baseurl for repo: base/7/x86_64
     001、yum报错(base)[root@PC1yum.repos.d]#yuminstallhttpd##yum安装应用报错 。 002、解决方法(base)[root@PC1home]#cd/etc/yum.repos.d(base)[root@PC1yum.repos.d]#lsCentOS-Base.repoCentOS-CR.repoCentOS-Debuginfo.repoCentOS-f......
  • Problem Set Main Findings of AHXZ
    ProblemSet3Thisisthefinalhomeworkassignment,whichaccountsfor60%ofyourfinalgrade.Unlike thepreviousproblemsets,youarerequiredtocollectthedataonyour ownand conductdataanalysisbasedon yourcollecteddata.Youmayworkwitho......
  • windows下配置hadoop3.1.4环境
    文章目录说明目前情况检查Java环境配置Hadoop环境下载解压hadoop3.1.4下载插件设置环境变量报错修改Hadoop配置文件修改core-site.xml文件修改hdfs-site.xml文件修改yarn-site.xml文件修改mapred-site.xml文件修改hadoop-env.sh文件修改hadoop-env.cmd文件格式化启动集......
  • 1.1.4 逆元
    1.1.4逆元主要内容:扩欧求逆元,快速幂求逆元,线性(递归)求逆元,同余模公式(补充),反复平方法求幂(补充)一、逆元首先给出逆元的定义:$$\begin{aligned}假设a\cdotp&\equiv1\quad(mod\quadb)\\且(a,b)&=1\quad即\quada,b互素\\则称p为a的逆元&,记作p=a^{-1}\end{aligned}$......
  • find
    #include<bits/stdc++.h>usingnamespacestd;intn,k,j,i,b,_min;vector<string>a;structp{intid;stringname;vector<int>gx;};vector<p>list;pl;boold(intz,stringc){for(inti=0;i<list[z].gx.size();i......
  • [gym 100917F] Find the Length
    算法转化题意:给出一个无向正权无自环图要求对于每个点经过它的最短"简单环"的长度有一种错误的思路,对于每次询问我们以该点\(s\)作为起点先处理出到其余每点的最短路,从一条边走回来即可这个思路容易找到反例,具体的,我们显然可以发现如果\(s\)分别到\(u\)和......