Mercurial > hg > Members > innparusu > xv6_rpi_port
diff source/sysfile.c @ 0:c450faca55f4
Init
author | Tatsuki IHA <innparusu@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 22 Oct 2017 18:25:39 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/sysfile.c Sun Oct 22 18:25:39 2017 +0900 @@ -0,0 +1,426 @@ +// +// 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" + +// 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=curr_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(curr_proc->ofile[fd] == 0){ + curr_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; +} + +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; +//cprintf("inside sys_write\n"); + return filewrite(f, p, n); +} + +int +sys_close(void) +{ + int fd; + struct file *f; + + if(argfd(0, &fd, &f) < 0) + return -1; + curr_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(curr_proc->cwd); + curr_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(char *)*MAXARG); + 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) + curr_proc->ofile[fd0] = 0; + fileclose(rf); + fileclose(wf); + return -1; + } + fd[0] = fd0; + fd[1] = fd1; + return 0; +}