summaryrefslogtreecommitdiff
path: root/sysfile.c
diff options
context:
space:
mode:
authorrsc <rsc>2007-08-22 06:01:32 +0000
committerrsc <rsc>2007-08-22 06:01:32 +0000
commiteaea18cb9cbb86018dae8f1decfa217ecbe85fa5 (patch)
tree98c4a9b852ad9b6aaf16016417cf5eeee0b3857e /sysfile.c
parent3dcf889c1b5c2c5ddf5b4756f2a731c344f6f08e (diff)
downloadxv6-labs-eaea18cb9cbb86018dae8f1decfa217ecbe85fa5.tar.gz
xv6-labs-eaea18cb9cbb86018dae8f1decfa217ecbe85fa5.tar.bz2
xv6-labs-eaea18cb9cbb86018dae8f1decfa217ecbe85fa5.zip
PDF at http://am.lcs.mit.edu/~rsc/xv6.pdf
Various changes made while offline. + bwrite sector argument is redundant; use b->sector. + reformatting of files for nicer PDF page breaks + distinguish between locked, unlocked inodes in type signatures + change FD_FILE to FD_INODE + move userinit (nee proc0init) to proc.c + move ROOTDEV to param.h + always parenthesize sizeof argument
Diffstat (limited to 'sysfile.c')
-rw-r--r--sysfile.c314
1 files changed, 211 insertions, 103 deletions
diff --git a/sysfile.c b/sysfile.c
index 87d163c..625d466 100644
--- a/sysfile.c
+++ b/sysfile.c
@@ -11,7 +11,6 @@
#include "buf.h"
#include "fs.h"
#include "fsvar.h"
-#include "elf.h"
#include "file.h"
#include "fcntl.h"
@@ -51,27 +50,15 @@ fdalloc(struct file *f)
}
int
-sys_pipe(void)
+sys_read(void)
{
- int *fd;
- struct file *rf, *wf;
- int fd0, fd1;
+ struct file *f;
+ int n;
+ char *cp;
- if(argptr(0, (void*)&fd, 2*sizeof fd[0]) < 0)
- return -1;
- if(pipe_alloc(&rf, &wf) < 0)
- return -1;
- fd0 = -1;
- if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
- if(fd0 >= 0)
- cp->ofile[fd0] = 0;
- fileclose(rf);
- fileclose(wf);
+ if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
return -1;
- }
- fd[0] = fd0;
- fd[1] = fd1;
- return 0;
+ return fileread(f, cp, n);
}
int
@@ -87,15 +74,14 @@ sys_write(void)
}
int
-sys_read(void)
+sys_fstat(void)
{
struct file *f;
- int n;
- char *cp;
-
- if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
+ struct stat *st;
+
+ if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
return -1;
- return fileread(f, cp, n);
+ return filestat(f, st);
}
int
@@ -111,6 +97,150 @@ sys_close(void)
return 0;
}
+// 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;
+ struct uinode *ipu;
+
+ if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
+ return -1;
+ if((ip = ilock(namei(old))) == 0)
+ return -1;
+ if(ip->type == T_DIR){
+ iput(iunlock(ip));
+ return -1;
+ }
+ ip->nlink++;
+ iupdate(ip);
+ ipu = iunlock(ip); ip = 0;
+
+ if((dp = ilock(nameiparent(new, name))) == 0 ||
+ dp->dev != ipu->dev || dirlink(dp, name, ipu->inum) < 0){
+ if(dp)
+ iput(iunlock(dp));
+ ip = ilock(ipu);
+ ip->nlink--;
+ iupdate(ip);
+ iput(iunlock(ip));
+ return -1;
+ }
+ iput(iunlock(dp));
+ iput(ipu);
+ return 0;
+}
+
+// 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;
+}
+
+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 = ilock(nameiparent(path, name))) == 0)
+ return -1;
+
+ // Cannot unlink "." or "..".
+ if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
+ iput(iunlock(dp));
+ return -1;
+ }
+
+ if((ip = ilock(dirlookup(dp, name, &off))) == 0){
+ iput(iunlock(dp));
+ return -1;
+ }
+
+ if(ip->nlink < 1)
+ panic("unlink: nlink < 1");
+ if(ip->type == T_DIR && !isdirempty(ip)){
+ iput(iunlock(ip));
+ iput(iunlock(dp));
+ return -1;
+ }
+
+ memset(&de, 0, sizeof(de));
+ if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
+ panic("unlink: writei");
+ iput(iunlock(dp));
+
+ ip->nlink--;
+ iupdate(ip);
+ iput(iunlock(ip));
+ return 0;
+}
+
+// Create the path and return its unlocked inode structure.
+static struct inode*
+mkpath(char *path, int canexist, short type, short major, short minor)
+{
+ uint off;
+ struct inode *ip, *dp;
+ struct uinode *ipu;
+ char name[DIRSIZ];
+
+ if((dp = ilock(nameiparent(path, name))) == 0)
+ return 0;
+
+ if(canexist && (ipu = dirlookup(dp, name, &off)) != 0){
+ iput(iunlock(dp));
+ ip = ilock(ipu);
+ if(ip->type != type || ip->major != major || ip->minor != minor){
+ iput(iunlock(ip));
+ return 0;
+ }
+ return ip;
+ }
+
+ if((ip = ilock(ialloc(dp->dev, type))) == 0){
+ iput(iunlock(dp));
+ return 0;
+ }
+ ip->major = major;
+ ip->minor = minor;
+ ip->size = 0;
+ ip->nlink = 1;
+ iupdate(ip);
+
+ if(dirlink(dp, name, ip->inum) < 0){
+ ip->nlink = 0;
+ iput(iunlock(ip));
+ iput(iunlock(dp));
+ return 0;
+ }
+
+ 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("mkpath dots");
+ }
+ iput(iunlock(dp));
+ return ip;
+}
+
int
sys_open(void)
{
@@ -122,30 +252,28 @@ sys_open(void)
if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
return -1;
- if(omode & O_CREATE)
- ip = create(path);
- else
- ip = namei(path);
- if(ip == 0)
- return -1;
-
- if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){
- iput(ip);
- return -1;
+ if(omode & O_CREATE){
+ if((ip = mkpath(path, 1, T_FILE, 0, 0)) == 0)
+ return -1;
+ }else{
+ if((ip = ilock(namei(path))) == 0)
+ return -1;
+ if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){
+ iput(iunlock(ip));
+ return -1;
+ }
}
- if((f = filealloc()) == 0){
- iput(ip);
- return -1;
- }
- if((fd = fdalloc(f)) < 0){
- iput(ip);
- fileclose(f);
+ if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
+ if(f)
+ fileclose(f);
+ iput(iunlock(ip));
return -1;
}
- iunlock(ip);
- f->type = FD_FILE;
+ f->type = FD_INODE;
+ f->ip = iunlock(ip);
+ f->off = 0;
if(omode & O_RDWR) {
f->readable = 1;
f->writable = 1;
@@ -156,8 +284,6 @@ sys_open(void)
f->readable = 1;
f->writable = 0;
}
- f->ip = ip;
- f->off = 0;
return fd;
}
@@ -165,7 +291,7 @@ sys_open(void)
int
sys_mknod(void)
{
- struct inode *nip;
+ struct inode *ip;
char *path;
int len;
int type, major, minor;
@@ -173,14 +299,10 @@ sys_mknod(void)
if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 ||
argint(2, &major) < 0 || argint(3, &minor) < 0)
return -1;
-
- // XXX why this check?
- if(len >= DIRSIZ)
+ // XXX check that type == T_DEV or eliminate type arg?
+ if((ip = mkpath(path, 0, type, major, minor)) == 0)
return -1;
-
- if((nip = mknod(path, type, major, minor)) == 0)
- return -1;
- iput(nip);
+ iput(iunlock(ip));
return 0;
}
@@ -188,57 +310,32 @@ int
sys_mkdir(void)
{
char *path;
+ struct inode *ip;
- if(argstr(0, &path) < 0)
+ if(argstr(0, &path) < 0 || (ip = mkpath(path, 0, T_DIR, 0, 0)) == 0)
return -1;
- return mkdir(path);
+ iput(iunlock(ip));
+ return 0;
}
int
sys_chdir(void)
{
- struct inode *ip;
char *path;
+ struct inode *ip;
- if(argstr(0, &path) < 0)
- return -1;
-
- if((ip = namei(path)) == 0)
+ if(argstr(0, &path) < 0 || (ip = ilock(namei(path))) == 0)
return -1;
-
if(ip->type != T_DIR) {
- iput(ip);
+ iput(iunlock(ip));
return -1;
}
-
- iunlock(ip);
- idecref(cp->cwd);
- cp->cwd = ip;
+ iput(cp->cwd);
+ cp->cwd = iunlock(ip);
return 0;
}
int
-sys_unlink(void)
-{
- char *path;
-
- if(argstr(0, &path) < 0)
- return -1;
- return unlink(path);
-}
-
-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);
-}
-
-int
sys_dup(void)
{
struct file *f;
@@ -253,29 +350,17 @@ sys_dup(void)
}
int
-sys_link(void)
-{
- char *old, *new;
-
- if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
- return -1;
- return link(old, new);
-}
-
-#define MAXARGS 20
-
-int
sys_exec(void)
{
- char *path, *argv[MAXARGS];
+ char *path, *argv[20];
int i;
uint uargv, uarg;
if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0)
return -1;
- memset(argv, 0, sizeof argv);
+ memset(argv, 0, sizeof(argv));
for(i=0;; i++){
- if(i >= MAXARGS)
+ if(i >= NELEM(argv))
return -1;
if(fetchint(cp, uargv+4*i, (int*)&uarg) < 0)
return -1;
@@ -289,3 +374,26 @@ sys_exec(void)
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(pipe_alloc(&rf, &wf) < 0)
+ return -1;
+ fd0 = -1;
+ if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
+ if(fd0 >= 0)
+ cp->ofile[fd0] = 0;
+ fileclose(rf);
+ fileclose(wf);
+ return -1;
+ }
+ fd[0] = fd0;
+ fd[1] = fd1;
+ return 0;
+}