112abb1a5SRobert Morris // 212abb1a5SRobert Morris // File-system system calls. 312abb1a5SRobert Morris // Mostly argument checking, since we don't trust 412abb1a5SRobert Morris // user code, and calls into file.c and fs.c. 512abb1a5SRobert Morris // 612abb1a5SRobert Morris 72685309fSrsc #include "types.h" 8558ab49fSrsc #include "defs.h" 92685309fSrsc #include "param.h" 10558ab49fSrsc #include "stat.h" 112685309fSrsc #include "mmu.h" 122685309fSrsc #include "proc.h" 132685309fSrsc #include "fs.h" 14dec637bcSFrans Kaashoek #include "spinlock.h" 15dec637bcSFrans Kaashoek #include "sleeplock.h" 169936bffaSrsc #include "file.h" 172685309fSrsc #include "fcntl.h" 182685309fSrsc 19224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor 20224f6598Srsc // and return both the descriptor and the corresponding struct file. 21224f6598Srsc static int 2264c47374Srsc argfd(int n, int *pfd, struct file **pf) 23224f6598Srsc { 24224f6598Srsc int fd; 25224f6598Srsc struct file *f; 26224f6598Srsc 273a2310f7Srsc if(argint(n, &fd) < 0) 28224f6598Srsc return -1; 29*abf847a0SFrans Kaashoek if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0) 30224f6598Srsc return -1; 31224f6598Srsc if(pfd) 32224f6598Srsc *pfd = fd; 33224f6598Srsc if(pf) 34224f6598Srsc *pf = f; 35224f6598Srsc return 0; 36224f6598Srsc } 37224f6598Srsc 38224f6598Srsc // Allocate a file descriptor for the given file. 39224f6598Srsc // Takes over file reference from caller on success. 40224f6598Srsc static int 41224f6598Srsc fdalloc(struct file *f) 42224f6598Srsc { 43224f6598Srsc int fd; 449583b476Srsc 45224f6598Srsc for(fd = 0; fd < NOFILE; fd++){ 46*abf847a0SFrans Kaashoek if(myproc()->ofile[fd] == 0){ 47*abf847a0SFrans Kaashoek myproc()->ofile[fd] = f; 48224f6598Srsc return fd; 49224f6598Srsc } 50224f6598Srsc } 51224f6598Srsc return -1; 52224f6598Srsc } 53224f6598Srsc 542685309fSrsc int 55f9a06440SRuss Cox sys_dup(void) 56f9a06440SRuss Cox { 57f9a06440SRuss Cox struct file *f; 58f9a06440SRuss Cox int fd; 59f9a06440SRuss Cox 60f9a06440SRuss Cox if(argfd(0, 0, &f) < 0) 61f9a06440SRuss Cox return -1; 62f9a06440SRuss Cox if((fd=fdalloc(f)) < 0) 63f9a06440SRuss Cox return -1; 64f9a06440SRuss Cox filedup(f); 65f9a06440SRuss Cox return fd; 66f9a06440SRuss Cox } 67f9a06440SRuss Cox 68f9a06440SRuss Cox int 69eaea18cbSrsc sys_read(void) 702685309fSrsc { 71eaea18cbSrsc struct file *f; 72eaea18cbSrsc int n; 73666f58c7Srsc char *p; 742685309fSrsc 75666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) 762685309fSrsc return -1; 77666f58c7Srsc return fileread(f, p, n); 782685309fSrsc } 792685309fSrsc 802685309fSrsc int 812685309fSrsc sys_write(void) 822685309fSrsc { 83224f6598Srsc struct file *f; 84224f6598Srsc int n; 85666f58c7Srsc char *p; 862685309fSrsc 87666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) 882685309fSrsc return -1; 89666f58c7Srsc return filewrite(f, p, n); 902685309fSrsc } 912685309fSrsc 922685309fSrsc int 932685309fSrsc sys_close(void) 942685309fSrsc { 952685309fSrsc int fd; 96224f6598Srsc struct file *f; 972685309fSrsc 98224f6598Srsc if(argfd(0, &fd, &f) < 0) 992685309fSrsc return -1; 100*abf847a0SFrans Kaashoek myproc()->ofile[fd] = 0; 101224f6598Srsc fileclose(f); 1022685309fSrsc return 0; 1032685309fSrsc } 1042685309fSrsc 1058d2e9a48Srsc int 1068d2e9a48Srsc sys_fstat(void) 1078d2e9a48Srsc { 1088d2e9a48Srsc struct file *f; 1098d2e9a48Srsc struct stat *st; 1108d2e9a48Srsc 1118d2e9a48Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0) 1128d2e9a48Srsc return -1; 1138d2e9a48Srsc return filestat(f, st); 1148d2e9a48Srsc } 1158d2e9a48Srsc 116eaea18cbSrsc // Create the path new as a link to the same inode as old. 117eaea18cbSrsc int 118eaea18cbSrsc sys_link(void) 119eaea18cbSrsc { 120eaea18cbSrsc char name[DIRSIZ], *new, *old; 121eaea18cbSrsc struct inode *dp, *ip; 122eaea18cbSrsc 123eaea18cbSrsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 124eaea18cbSrsc return -1; 1255053dd6aSRobert Morris 12671453f72SRobert Morris begin_op(); 1272c565472SRobert Morris if((ip = namei(old)) == 0){ 12871453f72SRobert Morris end_op(); 1292c565472SRobert Morris return -1; 1302c565472SRobert Morris } 1315053dd6aSRobert Morris 13207090dd7Srsc ilock(ip); 133eaea18cbSrsc if(ip->type == T_DIR){ 13407090dd7Srsc iunlockput(ip); 13571453f72SRobert Morris end_op(); 136eaea18cbSrsc return -1; 137eaea18cbSrsc } 1382e590463SRobert Morris 139eaea18cbSrsc ip->nlink++; 140eaea18cbSrsc iupdate(ip); 14107090dd7Srsc iunlock(ip); 142eaea18cbSrsc 14307090dd7Srsc if((dp = nameiparent(new, name)) == 0) 14407090dd7Srsc goto bad; 14507090dd7Srsc ilock(dp); 146f3685aa3Srsc if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ 147f3685aa3Srsc iunlockput(dp); 14807090dd7Srsc goto bad; 149f3685aa3Srsc } 15007090dd7Srsc iunlockput(dp); 15107090dd7Srsc iput(ip); 1522e590463SRobert Morris 15371453f72SRobert Morris end_op(); 1542e590463SRobert Morris 15507090dd7Srsc return 0; 15607090dd7Srsc 15707090dd7Srsc bad: 15807090dd7Srsc ilock(ip); 159eaea18cbSrsc ip->nlink--; 160eaea18cbSrsc iupdate(ip); 16107090dd7Srsc iunlockput(ip); 16271453f72SRobert Morris end_op(); 163eaea18cbSrsc return -1; 164eaea18cbSrsc } 165eaea18cbSrsc 166eaea18cbSrsc // Is the directory dp empty except for "." and ".." ? 167eaea18cbSrsc static int 168eaea18cbSrsc isdirempty(struct inode *dp) 169eaea18cbSrsc { 170eaea18cbSrsc int off; 171eaea18cbSrsc struct dirent de; 172eaea18cbSrsc 173eaea18cbSrsc for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ 174eaea18cbSrsc if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 175eaea18cbSrsc panic("isdirempty: readi"); 176eaea18cbSrsc if(de.inum != 0) 177eaea18cbSrsc return 0; 178eaea18cbSrsc } 179eaea18cbSrsc return 1; 180eaea18cbSrsc } 181eaea18cbSrsc 1828d2e9a48Srsc //PAGEBREAK! 183eaea18cbSrsc int 184eaea18cbSrsc sys_unlink(void) 185eaea18cbSrsc { 186eaea18cbSrsc struct inode *ip, *dp; 187eaea18cbSrsc struct dirent de; 188eaea18cbSrsc char name[DIRSIZ], *path; 189eaea18cbSrsc uint off; 190eaea18cbSrsc 191eaea18cbSrsc if(argstr(0, &path) < 0) 192eaea18cbSrsc return -1; 1935053dd6aSRobert Morris 19471453f72SRobert Morris begin_op(); 1952c565472SRobert Morris if((dp = nameiparent(path, name)) == 0){ 19671453f72SRobert Morris end_op(); 1972c565472SRobert Morris return -1; 1982c565472SRobert Morris } 1995053dd6aSRobert Morris 20007090dd7Srsc ilock(dp); 201eaea18cbSrsc 202eaea18cbSrsc // Cannot unlink "." or "..". 2034e015d81SAustin Clements if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0) 2044e015d81SAustin Clements goto bad; 205eaea18cbSrsc 2064e015d81SAustin Clements if((ip = dirlookup(dp, name, &off)) == 0) 2074e015d81SAustin Clements goto bad; 20807090dd7Srsc ilock(ip); 209eaea18cbSrsc 210eaea18cbSrsc if(ip->nlink < 1) 211eaea18cbSrsc panic("unlink: nlink < 1"); 212eaea18cbSrsc if(ip->type == T_DIR && !isdirempty(ip)){ 21307090dd7Srsc iunlockput(ip); 2144e015d81SAustin Clements goto bad; 215eaea18cbSrsc } 216eaea18cbSrsc 217eaea18cbSrsc memset(&de, 0, sizeof(de)); 218eaea18cbSrsc if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 219eaea18cbSrsc panic("unlink: writei"); 22015a26936Skolya if(ip->type == T_DIR){ 22115a26936Skolya dp->nlink--; 22215a26936Skolya iupdate(dp); 22315a26936Skolya } 22407090dd7Srsc iunlockput(dp); 225eaea18cbSrsc 226eaea18cbSrsc ip->nlink--; 227eaea18cbSrsc iupdate(ip); 22807090dd7Srsc iunlockput(ip); 2292e590463SRobert Morris 23071453f72SRobert Morris end_op(); 2312e590463SRobert Morris 232eaea18cbSrsc return 0; 2334e015d81SAustin Clements 2344e015d81SAustin Clements bad: 2354e015d81SAustin Clements iunlockput(dp); 23671453f72SRobert Morris end_op(); 2374e015d81SAustin Clements return -1; 238eaea18cbSrsc } 239eaea18cbSrsc 240eaea18cbSrsc static struct inode* 241f3685aa3Srsc create(char *path, short type, short major, short minor) 242eaea18cbSrsc { 243eaea18cbSrsc uint off; 244eaea18cbSrsc struct inode *ip, *dp; 245eaea18cbSrsc char name[DIRSIZ]; 246eaea18cbSrsc 24707090dd7Srsc if((dp = nameiparent(path, name)) == 0) 248eaea18cbSrsc return 0; 24907090dd7Srsc ilock(dp); 250eaea18cbSrsc 251f3685aa3Srsc if((ip = dirlookup(dp, name, &off)) != 0){ 25207090dd7Srsc iunlockput(dp); 25307090dd7Srsc ilock(ip); 254f9a06440SRuss Cox if(type == T_FILE && ip->type == T_FILE) 255f9a06440SRuss Cox return ip; 25607090dd7Srsc iunlockput(ip); 257eaea18cbSrsc return 0; 258eaea18cbSrsc } 259eaea18cbSrsc 260f9a06440SRuss Cox if((ip = ialloc(dp->dev, type)) == 0) 261f9a06440SRuss Cox panic("create: ialloc"); 262f9a06440SRuss Cox 26307090dd7Srsc ilock(ip); 264eaea18cbSrsc ip->major = major; 265eaea18cbSrsc ip->minor = minor; 266603deefcSrsc ip->nlink = 1; 267eaea18cbSrsc iupdate(ip); 268eaea18cbSrsc 269eaea18cbSrsc if(type == T_DIR){ // Create . and .. entries. 270eaea18cbSrsc dp->nlink++; // for ".." 271eaea18cbSrsc iupdate(dp); 272eaea18cbSrsc // No ip->nlink++ for ".": avoid cyclic ref count. 273eaea18cbSrsc if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) 274e79b1659Srsc panic("create dots"); 275eaea18cbSrsc } 276f3e87bc8Skolya 277f3685aa3Srsc if(dirlink(dp, name, ip->inum) < 0) 278f3685aa3Srsc panic("create: dirlink"); 279f3e87bc8Skolya 28007090dd7Srsc iunlockput(dp); 2812e590463SRobert Morris 282eaea18cbSrsc return ip; 283eaea18cbSrsc } 284eaea18cbSrsc 2852685309fSrsc int 2862685309fSrsc sys_open(void) 2872685309fSrsc { 288f32f3638Srsc char *path; 289f32f3638Srsc int fd, omode; 290224f6598Srsc struct file *f; 291f32f3638Srsc struct inode *ip; 2922685309fSrsc 293224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 2942685309fSrsc return -1; 2952c565472SRobert Morris 29671453f72SRobert Morris begin_op(); 2972c565472SRobert Morris 2982c565472SRobert Morris if(omode & O_CREATE){ 2992e590463SRobert Morris ip = create(path, T_FILE, 0, 0); 3002c565472SRobert Morris if(ip == 0){ 30171453f72SRobert Morris end_op(); 302e2a620daSrsc return -1; 3032c565472SRobert Morris } 304eaea18cbSrsc } else { 3052c565472SRobert Morris if((ip = namei(path)) == 0){ 30671453f72SRobert Morris end_op(); 307eaea18cbSrsc return -1; 3082c565472SRobert Morris } 30907090dd7Srsc ilock(ip); 310f3685aa3Srsc if(ip->type == T_DIR && omode != O_RDONLY){ 31107090dd7Srsc iunlockput(ip); 31271453f72SRobert Morris end_op(); 3132685309fSrsc return -1; 3142685309fSrsc } 315eaea18cbSrsc } 3162685309fSrsc 317eaea18cbSrsc if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ 318eaea18cbSrsc if(f) 319224f6598Srsc fileclose(f); 32007090dd7Srsc iunlockput(ip); 32171453f72SRobert Morris end_op(); 3222685309fSrsc return -1; 3232685309fSrsc } 32407090dd7Srsc iunlock(ip); 32571453f72SRobert Morris end_op(); 3262685309fSrsc 327eaea18cbSrsc f->type = FD_INODE; 32807090dd7Srsc f->ip = ip; 329eaea18cbSrsc f->off = 0; 330e79b1659Srsc f->readable = !(omode & O_WRONLY); 331e79b1659Srsc f->writable = (omode & O_WRONLY) || (omode & O_RDWR); 332224f6598Srsc return fd; 3332685309fSrsc } 3342685309fSrsc 3352685309fSrsc int 336f9a06440SRuss Cox sys_mkdir(void) 337f9a06440SRuss Cox { 338f9a06440SRuss Cox char *path; 339f9a06440SRuss Cox struct inode *ip; 340f9a06440SRuss Cox 34171453f72SRobert Morris begin_op(); 3422e590463SRobert Morris if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){ 34371453f72SRobert Morris end_op(); 344f9a06440SRuss Cox return -1; 3452e590463SRobert Morris } 346f9a06440SRuss Cox iunlockput(ip); 34771453f72SRobert Morris end_op(); 348f9a06440SRuss Cox return 0; 349f9a06440SRuss Cox } 350f9a06440SRuss Cox 351f9a06440SRuss Cox int 3522685309fSrsc sys_mknod(void) 3532685309fSrsc { 354eaea18cbSrsc struct inode *ip; 355224f6598Srsc char *path; 356aa6824abSrsc int major, minor; 3572685309fSrsc 35871453f72SRobert Morris begin_op(); 3591ccb5a6fSPeter H. Froehlich if((argstr(0, &path)) < 0 || 36007090dd7Srsc argint(1, &major) < 0 || 36107090dd7Srsc argint(2, &minor) < 0 || 3622e590463SRobert Morris (ip = create(path, T_DEV, major, minor)) == 0){ 36371453f72SRobert Morris end_op(); 3642685309fSrsc return -1; 3652e590463SRobert Morris } 36607090dd7Srsc iunlockput(ip); 36771453f72SRobert Morris end_op(); 368224f6598Srsc return 0; 3692685309fSrsc } 3702685309fSrsc 3712685309fSrsc int 3722685309fSrsc sys_chdir(void) 3732685309fSrsc { 374eaea18cbSrsc char *path; 3752685309fSrsc struct inode *ip; 3762685309fSrsc 37771453f72SRobert Morris begin_op(); 3782c565472SRobert Morris if(argstr(0, &path) < 0 || (ip = namei(path)) == 0){ 37971453f72SRobert Morris end_op(); 3802685309fSrsc return -1; 3812c565472SRobert Morris } 38207090dd7Srsc ilock(ip); 3832685309fSrsc if(ip->type != T_DIR){ 38407090dd7Srsc iunlockput(ip); 38571453f72SRobert Morris end_op(); 3862685309fSrsc return -1; 3872685309fSrsc } 38807090dd7Srsc iunlock(ip); 389*abf847a0SFrans Kaashoek iput(myproc()->cwd); 39071453f72SRobert Morris end_op(); 391*abf847a0SFrans Kaashoek myproc()->cwd = ip; 3922685309fSrsc return 0; 3932685309fSrsc } 3942685309fSrsc 3952685309fSrsc int 3962685309fSrsc sys_exec(void) 3972685309fSrsc { 3984655d42eSRobert Morris char *path, *argv[MAXARG]; 399f32f3638Srsc int i; 400f32f3638Srsc uint uargv, uarg; 4012685309fSrsc 40240889627SFrans Kaashoek if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){ 4032685309fSrsc return -1; 40440889627SFrans Kaashoek } 405eaea18cbSrsc memset(argv, 0, sizeof(argv)); 4062685309fSrsc for(i=0;; i++){ 407eaea18cbSrsc if(i >= NELEM(argv)) 4082685309fSrsc return -1; 4099d59eb01SAustin Clements if(fetchint(uargv+4*i, (int*)&uarg) < 0) 410f32f3638Srsc return -1; 411f32f3638Srsc if(uarg == 0){ 412f32f3638Srsc argv[i] = 0; 413f32f3638Srsc break; 4142685309fSrsc } 4159d59eb01SAustin Clements if(fetchstr(uarg, &argv[i]) < 0) 416f32f3638Srsc return -1; 417f32f3638Srsc } 418f32f3638Srsc return exec(path, argv); 419f32f3638Srsc } 420f32f3638Srsc 421eaea18cbSrsc int 422eaea18cbSrsc sys_pipe(void) 423eaea18cbSrsc { 424eaea18cbSrsc int *fd; 425eaea18cbSrsc struct file *rf, *wf; 426eaea18cbSrsc int fd0, fd1; 427eaea18cbSrsc 428eaea18cbSrsc if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) 429eaea18cbSrsc return -1; 4307834cca6Srsc if(pipealloc(&rf, &wf) < 0) 431eaea18cbSrsc return -1; 432eaea18cbSrsc fd0 = -1; 433eaea18cbSrsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 434eaea18cbSrsc if(fd0 >= 0) 435*abf847a0SFrans Kaashoek myproc()->ofile[fd0] = 0; 436eaea18cbSrsc fileclose(rf); 437eaea18cbSrsc fileclose(wf); 438eaea18cbSrsc return -1; 439eaea18cbSrsc } 440eaea18cbSrsc fd[0] = fd0; 441eaea18cbSrsc fd[1] = fd1; 442eaea18cbSrsc return 0; 443eaea18cbSrsc } 444