Lab1 : Xv6 and Unix utilities

1.xv6 system call interface

2.task

i. primes

注意管道pipe的使用:
int pipe(int p[]) Create a pipe, put read/write file descriptors in p[0] and p[1], 成功:0;失败:-1,设置errno;

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

void myprimes(int *p){
    int p_id;
    if((p_id = fork()) < 0){
        fprintf(2, "primes: fork failed\n");
        exit(1);
    }
    if(p_id == 0){
        char buff[1];
        int child_p[2];
        int len;
        int num = -1;

        close(p[1]);
        while((len = read(p[0], buff, 1)) > 0){
            int n = (int)buff[0];
            // printf("%d:recv %d\n", getpid(), n);
            if(num == -1){
                num = n;
                printf("prime %d\n", num);
                if(pipe(child_p) < 0){
                    fprintf(2, "primes: pipe failed\n");
                    exit(1);
                }
                myprimes(child_p); // 注意,先创建新的子进程,再关闭文件描述符
                close(child_p[0]); // 否则会导致子进程对应的文件描述符也关闭(复制过去的)
            }
            else if(n % num){
                write(child_p[1], buff, 1);
            }
        }
        close(child_p[1]);
        close(p[0]);
        wait(0);
        exit(0);
    }
}

int
main(int argc, char const *argv[]){
    int p[2];
    if(pipe(p) < 0){
        fprintf(2, "prime: pipe failed\n");
        exit(1);
    }
    myprimes(p);     
    close(p[0]);
    char buff[1];
    for(int i=2;i<=35;++i){
        buff[0] = (char)i;
        // printf("%d: emit %d\n",getpid(), i);
        write(p[1], buff, 1);
    }
    close(p[1]);
    wait(0);
    exit(0);
}

ii. find

实现思路:修改ls即可,ls只遍历当前目录,find修改为遍历当前目录及其所有子目录,通过递归实现即可,需要注意的是不要遍历"."和"..",会导致死循环。
此外,需要注意对于目录的读取:
read(fd, &de, sizeof(de)) == sizeof(de)
和文件的读取方式相同,每次读取目录中的一个元素,读取的结果存储在dirent结构体中。

struct dirent {
    ushort inum;
    char name[DIRSIZ];
};
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"

char*
filename(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++;

    memmove(buf, p, strlen(p));
    buf[strlen(p)] = 0;
    return buf;
}

void find(char *src, char *dst){
    char buf[512], *p;
    int fd;
    struct dirent de;
    struct stat st;
    // printf("find in : %s\n", src);
    if((fd = open(src, 0)) < 0){
        fprintf(2, "find: cannot open %s\n", src);
        return;
    }

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

    switch (st.type)
    {
    case T_FILE:
        // printf("name:%s\n", filename(src));
        if(strcmp(filename(src), dst) == 0){
            printf("%s\n", src);
        }
        break;
    case T_DIR:
        if(strlen(src) + 1 + DIRSIZ + 1 > sizeof buf){
            printf("find: path too long\n");
            break;
        }
        strcpy(buf, src);
        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(strcmp(".", p) == 0 || strcmp("..", p)==0)
                continue;
            if(stat(buf, &st) < 0){
                printf("ls: cannot stat %s\n", buf);
                continue;
            }
            find(buf, dst);
        }
        break;
    }
    close(fd);
}

int 
main(int argc, char *argv[]){
    if(argc != 3){
        fprintf(2, "Usage: find src dst\n");
        exit(1);
    }
    find(argv[1], argv[2]);
    exit(0);
}
posted @ 2022-03-17 18:16  fwx  阅读(109)  评论(0)    收藏  举报