diff --git a/kernel/sysfile.c b/kernel/sysfile.c index 3fd28fa3c43ee88e4c9408e52b3c9079c7cdec47..26b39629517e2222247fdb60f8936ad79415b839 100644 --- a/kernel/sysfile.c +++ b/kernel/sysfile.c @@ -1,9 +1,3 @@ -// -// File-system system calls. -// Mostly argument checking, since we don't trust -// user code, and calls into file.c and fs.c. -// - #include "include/types.h" #include "include/riscv.h" @@ -72,6 +66,37 @@ sys_dup(void) return fd; } +uint64 +sys_dup3(void) +{ + struct file *f1; + struct file *f2; + int oldfd; + int newfd; + + if(argfd(0, &oldfd, &f1) < 0) + return -1; + if(argint(1, &newfd) < 0) + return -1; + + if(newfd == oldfd) + return newfd; + + if(newfd < 0 || newfd >= NOFILE) + return -1; + + if(myproc()->ofile[newfd]){ + f2 = myproc()->ofile[newfd]; + myproc()->ofile[newfd] = 0; + fileclose(f2); + } + + myproc()->ofile[newfd] = f1; + filedup(f1); + + return newfd; +} + uint64 sys_read(void) { @@ -110,6 +135,33 @@ sys_close(void) return 0; } + +static void +getkstat(struct dirent *de, struct kstat *kst){ + kst->st_dev = de->dev; + kst->st_ino = de->first_clus; + kst->st_mode = (de->attribute & ATTR_DIRECTORY) ? S_IFDIR : S_IFREG; + kst->st_nlink = 1; + kst->st_uid = 0; + kst->st_gid = 0; + kst->st_rdev = 0; + kst->__pad = 0; + kst->__pad2 = 0; + kst->st_size = de->file_size; + kst->st_blksize = get_byts_per_clus(); + kst->st_blocks = (kst->st_size / kst->st_blksize); + if (kst->st_blocks * kst->st_blksize < kst->st_size) + kst->st_blocks++; + kst->st_atime_nsec = 0; + kst->st_atime_sec = 0; + kst->st_ctime_nsec = 0; + kst->st_ctime_sec = 0; + kst->st_mtime_nsec = 0; + kst->st_mtime_sec = 0; + kst->__unused[0] = 0; + kst->__unused[1] = 0; +} + uint64 sys_fstat(void) { @@ -119,6 +171,25 @@ sys_fstat(void) if(argfd(0, 0, &f) < 0 || argaddr(1, &st) < 0) return -1; return filestat(f, st); + + +} + +uint64 +sys_fstatat(void) +{ + struct file *f; + struct kstat kst; + uint64 kst_addr; + if(argfd(0, 0, &f) < 0 || argaddr(1, &kst_addr) < 0) + return -1; + + getkstat(f->ep, &kst); + if(copyout2(kst_addr, (char*)&kst, sizeof(kst)) < 0){ + printf("sys_fstat:copyout2 failed\n"); + return -1; + } + return 0; } static struct dirent* @@ -160,6 +231,48 @@ create(char *path, short type, int mode) return ep; } + +//在f指定的目录项下创建目录,否则在当前工作目录下创建目录 +static struct dirent* +create2(char *path, short type, int mode, struct file *f) +{ + struct dirent *ep, *dp; + char name[FAT32_MAX_FILENAME + 1]; + + if((dp = enameparent2(path, name, f)) == NULL){ + printf("can't find dir\n"); + return NULL; + } + if (type == T_DIR) { + mode = ATTR_DIRECTORY; + } else if (mode & O_RDONLY) { + mode = ATTR_READ_ONLY; + } else { + mode = 0; + } + + elock(dp); + if ((ep = ealloc(dp, name, mode)) == NULL) { + eunlock(dp); + eput(dp); + return NULL; + } + + if ((type == T_DIR && !(ep->attribute & ATTR_DIRECTORY)) || + (type == T_FILE && (ep->attribute & ATTR_DIRECTORY))) { + eunlock(dp); + eput(ep); + eput(dp); + return NULL; + } + + eunlock(dp); + eput(dp); + + elock(ep); + return ep; +} + uint64 sys_open(void) { @@ -208,10 +321,98 @@ sys_open(void) f->writable = (omode & O_WRONLY) || (omode & O_RDWR); eunlock(ep); + + return fd; +} + + +uint64 +sys_openat(void) +{ + char path[FAT32_MAX_PATH]; + int fd, flags, mode; + struct file *f; + struct file *f2; + struct dirent *ep; + f2 = NULL; + + if(argint(0, &fd) < 0 || argstr(1, path, FAT32_MAX_PATH) < 0 || argint(2, &flags) < 0 || argint(3, &mode) < 0){ + printf("can't read registers\n"); + return -1; + } + + //不是绝对路径 + if(*path != '/' && fd >= 0 && fd < NOFILE){ + f2 = myproc()->ofile[fd]; + } + + + if(flags & O_CREATE){ + if(S_ISDIR(mode)){ + ep = create2(path, T_DIR, flags, f2); + if(ep == NULL){ + printf("create a dir failed\n"); + return -1; + } + } else{ + ep = create2(path, T_FILE, flags, f2); + if(ep == NULL){ + printf("create a file failed\n"); + return -1; + } + } + } else{//打开已有文件 + + if((ep = ename2(path, f2)) == NULL){ + return -1;//从这退出了 + } + + elock(ep); + + if((ep->attribute & ATTR_DIRECTORY) && ((flags & O_RDWR) || (flags & O_WRONLY))){ + printf("dir can't write\n"); + eunlock(ep); + eput(ep); + return -1; + } + + if((flags & O_DIRECTORY) && !(ep->attribute & ATTR_DIRECTORY)){ + printf("it is not dir\n"); + eunlock(ep); + eput(ep); + return -1; + } + + } + + if((f = filealloc()) == NULL || (fd = fdalloc(f)) < 0){ + printf("no free filetable or fd\n"); + if (f) { + fileclose(f); + } + eunlock(ep); + eput(ep); + return -1; + } + + if(!(ep->attribute & ATTR_DIRECTORY) && (flags & O_TRUNC)){ + etrunc(ep); + } + + f->type = FD_ENTRY; + f->off = (flags & O_APPEND) ? ep->file_size : 0; + f->ep = ep; + f->readable = !(flags & O_WRONLY); + f->writable = (flags & O_WRONLY) || (flags & O_RDWR); + + eunlock(ep); + return fd; } + +//接收路径作为参数,在当前工作目录下创建目录 uint64 sys_mkdir(void) { @@ -226,6 +427,56 @@ sys_mkdir(void) return 0; } + +//在 dirfd 指定的目录下创建新目录,否则与 sys_mkdir() 等效 +uint64 +sys_mkdirat(void) +{ + int dirfd; + char path[FAT32_MAX_PATH]; + char absolute_path[FAT32_MAX_PATH]; + int mode; + int len; + char *s; + struct dirent *ep; + struct dirent *de; + + if(argint(0, &dirfd) < 0 || argstr(1, path, FAT32_MAX_PATH) < 0 || argint(2, &mode) < 0){ + return -1; + } + if(path[0] == '/'){ // absolute path + if((ep = create(path, T_DIR, mode)) == 0) + return -1; + eunlock(ep); + eput(ep); + return 0; + } + else if(dirfd == -100) // AT_CWDFD = -100 + de = myproc()->cwd; + else + de = myproc()->ofile[dirfd]->ep; + + s = absolute_path + FAT32_MAX_PATH - 1; + *s = '\0'; + len = strlen(path); + s -= len; + strncpy(s, path, len); + while (de->parent) { + len = strlen(de->filename); + s -= len; + if (s <= absolute_path) // can't reach root "/" + return 0; + strncpy(s, de->filename, len); + *--s = '/'; + de = de->parent; + } + if((ep = create(s, T_DIR, mode)) == 0) + return -1; + eunlock(ep); + eput(ep); + return 0; +} + uint64 sys_chdir(void) { @@ -233,18 +484,24 @@ sys_chdir(void) struct dirent *ep; struct proc *p = myproc(); + // 获取参数 path if(argstr(0, path, FAT32_MAX_PATH) < 0 || (ep = ename(path)) == NULL){ return -1; } + elock(ep); + // 判断是否为目录 if(!(ep->attribute & ATTR_DIRECTORY)){ eunlock(ep); eput(ep); return -1; } eunlock(ep); + + // 释放原来的 cwd eput(p->cwd); p->cwd = ep; + return 0; } @@ -281,6 +538,46 @@ sys_pipe(void) return 0; } +uint64 +sys_pipe2(void) +{ + uint64 fdarray; // user pointer to array of two integers + struct file *rf, *wf; + int fd0, fd1; + struct proc *p = myproc(); + if(argaddr(0, &fdarray) < 0){ + printf("can't read registers\n"); + return -1; + } + if(pipealloc(&rf, &wf) < 0){ + printf("create pipe failed\n"); + return -1; + } + + fd0 = -1; + if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ + printf("no free fd\n"); + if(fd0 >= 0) + p->ofile[fd0] = 0; + fileclose(rf); + fileclose(wf); + return -1; + } + // if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 || + // copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){ + if(copyout2(fdarray, (char*)&fd0, sizeof(fd0)) < 0 || + copyout2(fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){ + printf("copy failed\n"); + p->ofile[fd0] = 0; + p->ofile[fd1] = 0; + fileclose(rf); + fileclose(wf); + return -1; + } + // printf("fd[0] = %d, fd[1] = %d\n", (*((int*)fdarray)), (*((int*)(fdarray + sizeof(fd0))))); + return 0; +} + // To open console device. uint64 sys_dev(void) @@ -333,8 +630,9 @@ uint64 sys_getcwd(void) { uint64 addr; - if (argaddr(0, &addr) < 0) - return -1; + int size; + if (argaddr(0, &addr) < 0 || argint(1, &size) < 0) + return NULL; struct dirent *de = myproc()->cwd; char path[FAT32_MAX_PATH]; @@ -356,12 +654,16 @@ sys_getcwd(void) de = de->parent; } } - + if (size < strlen(s) + 1){ + if (copyout2(addr, s, strlen(s) + 1) < 0) + return NULL; + } // if (copyout(myproc()->pagetable, addr, s, strlen(s) + 1) < 0) - if (copyout2(addr, s, strlen(s) + 1) < 0) - return -1; - - return 0; + else{ + if (copyout2(addr, s, strlen(s) + 1) < 0) + return NULL; + } + return addr; } @@ -494,3 +796,196 @@ fail: eput(src); return -1; } + +void getdstat(struct dirent *de, struct dstat *st) +{ + strncpy(st->d_name, de->filename, STAT_MAX_NAME); + st->d_type = (de->attribute & ATTR_DIRECTORY) ? S_IFDIR : S_IFREG; + st->d_ino = de->first_clus; + st->d_off = 0; + st->d_reclen = de->file_size; +} + +uint64 +sys_getdents64(void){ + int len; + struct file *f; + uint64 buf; + struct dstat ds; + if(argaddr(1, &buf) < 0 || argfd(0, 0, &f) < 0 || argint(1, &len) < 0){ + printf("can't read registers\n"); + return -1; + } + + // (&ds)->d_ino = f->ep->first_clus; + // (&ds)->d_off = 0; + // (&ds)->d_reclen = f->ep->file_size; + // (&ds)->d_type = (f->ep->attribute & ATTR_DIRECTORY) ? S_IFDIR : S_IFREG; + // strncpy((&ds)->d_name, f->ep->filename, STAT_MAX_NAME); + getdstat(f->ep, &ds); + if(copyout2(buf, (char*)&ds, sizeof(ds)) < 0){ + printf("copy wrong\n"); + return -1; + } + + return sizeof(ds); + // return 0; +} + +uint64 +sys_mount(void) +{ + char mount_path[FAT32_MAX_PATH]; + char dev_path[FAT32_MAX_PATH]; + char fstype[10]; + int flags; + struct dirent *ep,*dev_ep; + + if(argstr(0,dev_path,FAT32_MAX_PATH)<0||argstr(1,mount_path,FAT32_MAX_PATH)<0) + { + return -1; + } + + if(argstr(2,fstype,10)<0|| argint(3, (int*)&flags) <0) + { + return -1; + } + //mountpoint not allowed the root + if(strncmp("/",mount_path,2)==0) + { + printf("not allowed\n"); + return -1; + } + if((dev_ep=ename(dev_path))==NULL) + { + printf("dev not found file"); + return -1; + } + + if((ep=ename(mount_path))==NULL) + { + printf("mount not found file"); + return -1; + } + + if(!(ep->attribute & ATTR_DIRECTORY)) + { + printf("mountpoint is not a dir"); + return -1; + } + if (strncmp("vfat", fstype, 5) != 0 && + strncmp("fat32", fstype, 6) != 0) + { + printf("the fstype is not fat32"); + return -1; + } + int ret= do_mount(ep,dev_ep); + return ret; + + // char special[FAT32_MAX_PATH],dir[FAT32_MAX_PATH],fstype[FAT32_MAX_PATH]; + // int flags; + // uint64 data; + + // if(argstr(0, special, FAT32_MAX_PATH) < 0||argstr(1, dir, FAT32_MAX_PATH) < 0||argstr(2, fstype, FAT32_MAX_PATH) < 0||argint(3, &flags) < 0||argaddr(4, &data) < 0) + // return -1; + + // struct dirent *mydir; + // if((mydir = ename(dir)) == 0){ + // return -1; + // } + // elock(mydir); + // mydir->attribute |= 0x40; + // if(emount(dir, NULL) == -1){ + // mydir->attribute &= ~0x40; + // return -1; + // } + // eunlock(mydir); + // return 0; +} + +uint64 +sys_umount2(void) +{ + char dev_path[FAT32_MAX_PATH]; + argstr(0,dev_path,FAT32_MAX_PATH); + struct dirent*ep; + if(strncmp("/",dev_path,2)==0) + { + printf("path error"); + return -1; + } + + if((ep=ename(dev_path))==NULL) + { + printf("not found file\n"); + return -1; + } + int ret=do_umount(ep); + return ret; + + // eumount(NULL); + // return 0; + +} + + +uint64 +sys_mmap(void) +{ + uint64 start, len, prot, flags, fd, off; + if (argaddr(0, &start) < 0||argaddr(1, &len) < 0||argaddr(2, &prot)||argaddr(3, &flags)||argaddr(4, &fd)||argaddr(5, &off)){ + return -1; + } + + return do_mmap(start, len, prot, flags, fd, off); +} + +uint64 sys_munmap(void){ + uint64 start, len; + if (argaddr(0, &start) < 0||argaddr(1, &len) < 0){ + return -1; + } + return do_munmap(start,(long)len); +} + +uint64 +sys_linkat(void){ + int olddirfd, newdirfd; + char oldpath[FAT32_MAX_PATH], newpath[FAT32_MAX_PATH]; + int flags; + struct file *f1, *f2; + f1 = NULL;f2 = NULL; + if(argint(0, &olddirfd) < 0 || argstr(1, oldpath, FAT32_MAX_PATH) < 0){ + printf("can't read register\n"); + return -1; + } + if(argint(2, &newdirfd) < 0 || argstr(3, newpath, FAT32_MAX_PATH) < 0 || argint(4, &flags) < 0){ + printf("can't read register\n"); + return -1; + } + if(*oldpath != '/' && olddirfd >= 0 && olddirfd < NOFILE){ + f1 = myproc()->ofile[olddirfd]; + } + if(*newpath != '/' && newdirfd >= 0 && newdirfd < NOFILE){ + f2 = myproc()->ofile[newdirfd]; + } + return link(oldpath, f1, newpath, f2); +} + +uint64 +sys_unlinkat(void){ + int dirfd; + char path[FAT32_MAX_PATH]; + int flags; + struct file *f; + f = NULL; + if(argint(0, &dirfd) < 0 || argstr(1, path, FAT32_MAX_PATH) < 0 || argint(2, &flags) < 0){ + printf("can't read register\n"); + return -1; + } + if(*path != '/' && dirfd >= 0 && dirfd < NOFILE){ + f = myproc()->ofile[dirfd]; + } + return unlink(path, f); +} +