Mercurial > hg > CbC > CbC_xv6
diff src/sysfile.cbc @ 52:214d21c891c7
rename to cbc
__ncode is not handled as interfaces
author | kono |
---|---|
date | Mon, 03 Jun 2019 18:12:44 +0900 |
parents | src/sysfile.c@36bd61f5c847 |
children | f38d8d39d617 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sysfile.cbc Mon Jun 03 18:12:44 2019 +0900 @@ -0,0 +1,520 @@ +// +// File-system system calls. +// Mostly argument checking, since we don't trust +// user code, and calls into file.c and fs.c. +// + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "stat.h" +#include "mmu.h" +#include "proc.h" +#include "fs.h" +#include "file.h" +#include "fcntl.h" + +#define __ncode __code + +// Fetch the nth word-sized system call argument as a file descriptor +// and return both the descriptor and the corresponding struct file. +static int argfd(int n, int *pfd, struct file **pf) +{ + int fd; + struct file *f; + + if(argint(n, &fd) < 0) { + return -1; + } + + if(fd < 0 || fd >= NOFILE || (f=proc->ofile[fd]) == 0) { + return -1; + } + + if(pfd) { + *pfd = fd; + } + + if(pf) { + *pf = f; + } + + return 0; +} + +// Allocate a file descriptor for the given file. +// Takes over file reference from caller on success. +static int fdalloc(struct file *f) +{ + int fd; + + for(fd = 0; fd < NOFILE; fd++){ + if(proc->ofile[fd] == 0){ + proc->ofile[fd] = f; + return fd; + } + } + + return -1; +} + +int sys_dup(void) +{ + struct file *f; + int fd; + + if(argfd(0, 0, &f) < 0) { + return -1; + } + + if((fd=fdalloc(f)) < 0) { + return -1; + } + + filedup(f); + + return fd; +} + +__ncode cbc_read(__code (*next)(int ret)){ + struct file *f; + int n; + char *p; + + if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) { + goto next(-1); + } + goto cbc_fileread(f, p, n, next); +} + +int sys_read(void) +{ + struct file *f; + int n; + char *p; + + if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) { + return -1; + } + + return fileread(f, p, n); +} + +int sys_write(void) +{ + struct file *f; + int n; + char *p; + + if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) { + return -1; + } + + return filewrite(f, p, n); +} + +int sys_close(void) +{ + int fd; + struct file *f; + + if(argfd(0, &fd, &f) < 0) { + return -1; + } + + proc->ofile[fd] = 0; + fileclose(f); + + return 0; +} + +int sys_fstat(void) +{ + struct file *f; + struct stat *st; + + if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0) { + return -1; + } + + return filestat(f, st); +} + +// Create the path new as a link to the same inode as old. +int sys_link(void) +{ + char name[DIRSIZ], *new, *old; + struct inode *dp, *ip; + + if(argstr(0, &old) < 0 || argstr(1, &new) < 0) { + return -1; + } + + if((ip = namei(old)) == 0) { + return -1; + } + + begin_trans(); + + ilock(ip); + + if(ip->type == T_DIR){ + iunlockput(ip); + commit_trans(); + return -1; + } + + ip->nlink++; + iupdate(ip); + iunlock(ip); + + if((dp = nameiparent(new, name)) == 0) { + goto bad; + } + + ilock(dp); + + if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ + iunlockput(dp); + goto bad; + } + + iunlockput(dp); + iput(ip); + + commit_trans(); + + return 0; + + bad: + ilock(ip); + ip->nlink--; + iupdate(ip); + iunlockput(ip); + commit_trans(); + return -1; +} + +// Is the directory dp empty except for "." and ".." ? +static int isdirempty(struct inode *dp) +{ + int off; + struct dirent de; + + for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ + if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) { + panic("isdirempty: readi"); + } + + if(de.inum != 0) { + return 0; + } + } + return 1; +} + +//PAGEBREAK! +int sys_unlink(void) +{ + struct inode *ip, *dp; + struct dirent de; + char name[DIRSIZ], *path; + uint off; + + if(argstr(0, &path) < 0) { + return -1; + } + + if((dp = nameiparent(path, name)) == 0) { + return -1; + } + + begin_trans(); + + ilock(dp); + + // Cannot unlink "." or "..". + if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0) { + goto bad; + } + + if((ip = dirlookup(dp, name, &off)) == 0) { + goto bad; + } + + ilock(ip); + + if(ip->nlink < 1) { + panic("unlink: nlink < 1"); + } + + if(ip->type == T_DIR && !isdirempty(ip)){ + iunlockput(ip); + goto bad; + } + + memset(&de, 0, sizeof(de)); + + if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) { + panic("unlink: writei"); + } + + if(ip->type == T_DIR){ + dp->nlink--; + iupdate(dp); + } + + iunlockput(dp); + + ip->nlink--; + iupdate(ip); + iunlockput(ip); + + commit_trans(); + + return 0; + + bad: + iunlockput(dp); + commit_trans(); + return -1; +} + +static struct inode* create(char *path, short type, short major, short minor) +{ + uint off; + struct inode *ip, *dp; + char name[DIRSIZ]; + + if((dp = nameiparent(path, name)) == 0) { + return 0; + } + + ilock(dp); + + if((ip = dirlookup(dp, name, &off)) != 0){ + iunlockput(dp); + ilock(ip); + + if(type == T_FILE && ip->type == T_FILE) { + return ip; + } + + iunlockput(ip); + + return 0; + } + + if((ip = ialloc(dp->dev, type)) == 0) { + panic("create: ialloc"); + } + + ilock(ip); + ip->major = major; + ip->minor = minor; + ip->nlink = 1; + iupdate(ip); + + if(type == T_DIR){ // Create . and .. entries. + dp->nlink++; // for ".." + iupdate(dp); + + // No ip->nlink++ for ".": avoid cyclic ref count. + if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) { + panic("create dots"); + } + } + + if(dirlink(dp, name, ip->inum) < 0) { + panic("create: dirlink"); + } + + iunlockput(dp); + + return ip; +} + +int sys_open(void) +{ + char *path; + int fd, omode; + struct file *f; + struct inode *ip; + + if(argstr(0, &path) < 0 || argint(1, &omode) < 0) { + return -1; + } + + if(omode & O_CREATE){ + begin_trans(); + ip = create(path, T_FILE, 0, 0); + commit_trans(); + + if(ip == 0) { + return -1; + } + + } else { + if((ip = namei(path)) == 0) { + return -1; + } + + ilock(ip); + + if(ip->type == T_DIR && omode != O_RDONLY){ + iunlockput(ip); + return -1; + } + } + + if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ + if(f) { + fileclose(f); + } + + iunlockput(ip); + return -1; + } + + iunlock(ip); + + f->type = FD_INODE; + f->ip = ip; + f->off = 0; + f->readable = !(omode & O_WRONLY); + f->writable = (omode & O_WRONLY) || (omode & O_RDWR); + + return fd; +} + +int sys_mkdir(void) +{ + char *path; + struct inode *ip; + + begin_trans(); + + if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){ + commit_trans(); + return -1; + } + + iunlockput(ip); + commit_trans(); + + return 0; +} + +int sys_mknod(void) +{ + struct inode *ip; + char *path; + int len; + int major, minor; + + begin_trans(); + + if((len=argstr(0, &path)) < 0 || + argint(1, &major) < 0 || argint(2, &minor) < 0 || + (ip = create(path, T_DEV, major, minor)) == 0){ + + commit_trans(); + return -1; + } + + iunlockput(ip); + commit_trans(); + + return 0; +} + +int sys_chdir(void) +{ + char *path; + struct inode *ip; + + if(argstr(0, &path) < 0 || (ip = namei(path)) == 0) { + return -1; + } + + ilock(ip); + + if(ip->type != T_DIR){ + iunlockput(ip); + return -1; + } + + iunlock(ip); + + iput(proc->cwd); + proc->cwd = ip; + + return 0; +} + +int sys_exec(void) +{ + char *path, *argv[MAXARG]; + int i; + uint uargv, uarg; + + if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){ + return -1; + } + + memset(argv, 0, sizeof(argv)); + + for(i=0;; i++){ + if(i >= NELEM(argv)) { + return -1; + } + + if(fetchint(uargv+4*i, (int*)&uarg) < 0) { + return -1; + } + + if(uarg == 0){ + argv[i] = 0; + break; + } + + if(fetchstr(uarg, &argv[i]) < 0) { + return -1; + } + } + + return exec(path, argv); +} + +int sys_pipe(void) +{ + int *fd; + struct file *rf, *wf; + int fd0, fd1; + + if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) { + return -1; + } + + if(pipealloc(&rf, &wf) < 0) { + return -1; + } + + fd0 = -1; + + if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ + if(fd0 >= 0) { + proc->ofile[fd0] = 0; + } + + fileclose(rf); + fileclose(wf); + + return -1; + } + + fd[0] = fd0; + fd[1] = fd1; + + return 0; +}