12685309fSrsc #include "types.h" 2558ab49fSrsc #include "defs.h" 32685309fSrsc #include "param.h" 4558ab49fSrsc #include "stat.h" 52685309fSrsc #include "mmu.h" 62685309fSrsc #include "proc.h" 72685309fSrsc #include "fs.h" 89936bffaSrsc #include "file.h" 92685309fSrsc #include "fcntl.h" 102685309fSrsc 11224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor 12224f6598Srsc // and return both the descriptor and the corresponding struct file. 13224f6598Srsc static int 1464c47374Srsc argfd(int n, int *pfd, struct file **pf) 15224f6598Srsc { 16224f6598Srsc int fd; 17224f6598Srsc struct file *f; 18224f6598Srsc 193a2310f7Srsc if(argint(n, &fd) < 0) 20224f6598Srsc return -1; 2148755214SRuss Cox if(fd < 0 || fd >= NOFILE || (f=proc->ofile[fd]) == 0) 22224f6598Srsc return -1; 23224f6598Srsc if(pfd) 24224f6598Srsc *pfd = fd; 25224f6598Srsc if(pf) 26224f6598Srsc *pf = f; 27224f6598Srsc return 0; 28224f6598Srsc } 29224f6598Srsc 30224f6598Srsc // Allocate a file descriptor for the given file. 31224f6598Srsc // Takes over file reference from caller on success. 32224f6598Srsc static int 33224f6598Srsc fdalloc(struct file *f) 34224f6598Srsc { 35224f6598Srsc int fd; 369583b476Srsc 37224f6598Srsc for(fd = 0; fd < NOFILE; fd++){ 3848755214SRuss Cox if(proc->ofile[fd] == 0){ 3948755214SRuss Cox proc->ofile[fd] = f; 40224f6598Srsc return fd; 41224f6598Srsc } 42224f6598Srsc } 43224f6598Srsc return -1; 44224f6598Srsc } 45224f6598Srsc 462685309fSrsc int 47f9a06440SRuss Cox sys_dup(void) 48f9a06440SRuss Cox { 49f9a06440SRuss Cox struct file *f; 50f9a06440SRuss Cox int fd; 51f9a06440SRuss Cox 52f9a06440SRuss Cox if(argfd(0, 0, &f) < 0) 53f9a06440SRuss Cox return -1; 54f9a06440SRuss Cox if((fd=fdalloc(f)) < 0) 55f9a06440SRuss Cox return -1; 56f9a06440SRuss Cox filedup(f); 57f9a06440SRuss Cox return fd; 58f9a06440SRuss Cox } 59f9a06440SRuss Cox 60f9a06440SRuss Cox int 61eaea18cbSrsc sys_read(void) 622685309fSrsc { 63eaea18cbSrsc struct file *f; 64eaea18cbSrsc int n; 65666f58c7Srsc char *p; 662685309fSrsc 67666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) 682685309fSrsc return -1; 69666f58c7Srsc return fileread(f, p, n); 702685309fSrsc } 712685309fSrsc 722685309fSrsc int 732685309fSrsc sys_write(void) 742685309fSrsc { 75224f6598Srsc struct file *f; 76224f6598Srsc int n; 77666f58c7Srsc char *p; 782685309fSrsc 79666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) 802685309fSrsc return -1; 81666f58c7Srsc return filewrite(f, p, n); 822685309fSrsc } 832685309fSrsc 842685309fSrsc int 852685309fSrsc sys_close(void) 862685309fSrsc { 872685309fSrsc int fd; 88224f6598Srsc struct file *f; 892685309fSrsc 90224f6598Srsc if(argfd(0, &fd, &f) < 0) 912685309fSrsc return -1; 9248755214SRuss Cox proc->ofile[fd] = 0; 93224f6598Srsc fileclose(f); 942685309fSrsc return 0; 952685309fSrsc } 962685309fSrsc 978d2e9a48Srsc int 988d2e9a48Srsc sys_fstat(void) 998d2e9a48Srsc { 1008d2e9a48Srsc struct file *f; 1018d2e9a48Srsc struct stat *st; 1028d2e9a48Srsc 1038d2e9a48Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0) 1048d2e9a48Srsc return -1; 1058d2e9a48Srsc return filestat(f, st); 1068d2e9a48Srsc } 1078d2e9a48Srsc 108eaea18cbSrsc // Create the path new as a link to the same inode as old. 109eaea18cbSrsc int 110eaea18cbSrsc sys_link(void) 111eaea18cbSrsc { 112eaea18cbSrsc char name[DIRSIZ], *new, *old; 113eaea18cbSrsc struct inode *dp, *ip; 114eaea18cbSrsc 115eaea18cbSrsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 116eaea18cbSrsc return -1; 11707090dd7Srsc if((ip = namei(old)) == 0) 118eaea18cbSrsc return -1; 119*5053dd6aSRobert Morris 120*5053dd6aSRobert Morris begin_trans(); 121*5053dd6aSRobert Morris 12207090dd7Srsc ilock(ip); 123eaea18cbSrsc if(ip->type == T_DIR){ 12407090dd7Srsc iunlockput(ip); 125*5053dd6aSRobert Morris commit_trans(); 126eaea18cbSrsc return -1; 127eaea18cbSrsc } 1282e590463SRobert Morris 129eaea18cbSrsc ip->nlink++; 130eaea18cbSrsc iupdate(ip); 13107090dd7Srsc iunlock(ip); 132eaea18cbSrsc 13307090dd7Srsc if((dp = nameiparent(new, name)) == 0) 13407090dd7Srsc goto bad; 13507090dd7Srsc ilock(dp); 136f3685aa3Srsc if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ 137f3685aa3Srsc iunlockput(dp); 13807090dd7Srsc goto bad; 139f3685aa3Srsc } 14007090dd7Srsc iunlockput(dp); 14107090dd7Srsc iput(ip); 1422e590463SRobert Morris 1432e590463SRobert Morris commit_trans(); 1442e590463SRobert Morris 14507090dd7Srsc return 0; 14607090dd7Srsc 14707090dd7Srsc bad: 14807090dd7Srsc ilock(ip); 149eaea18cbSrsc ip->nlink--; 150eaea18cbSrsc iupdate(ip); 15107090dd7Srsc iunlockput(ip); 1522e590463SRobert Morris commit_trans(); 153eaea18cbSrsc return -1; 154eaea18cbSrsc } 155eaea18cbSrsc 156eaea18cbSrsc // Is the directory dp empty except for "." and ".." ? 157eaea18cbSrsc static int 158eaea18cbSrsc isdirempty(struct inode *dp) 159eaea18cbSrsc { 160eaea18cbSrsc int off; 161eaea18cbSrsc struct dirent de; 162eaea18cbSrsc 163eaea18cbSrsc for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ 164eaea18cbSrsc if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 165eaea18cbSrsc panic("isdirempty: readi"); 166eaea18cbSrsc if(de.inum != 0) 167eaea18cbSrsc return 0; 168eaea18cbSrsc } 169eaea18cbSrsc return 1; 170eaea18cbSrsc } 171eaea18cbSrsc 1728d2e9a48Srsc //PAGEBREAK! 173eaea18cbSrsc int 174eaea18cbSrsc sys_unlink(void) 175eaea18cbSrsc { 176eaea18cbSrsc struct inode *ip, *dp; 177eaea18cbSrsc struct dirent de; 178eaea18cbSrsc char name[DIRSIZ], *path; 179eaea18cbSrsc uint off; 180eaea18cbSrsc 181eaea18cbSrsc if(argstr(0, &path) < 0) 182eaea18cbSrsc return -1; 18307090dd7Srsc if((dp = nameiparent(path, name)) == 0) 184eaea18cbSrsc return -1; 185*5053dd6aSRobert Morris 186*5053dd6aSRobert Morris begin_trans(); 187*5053dd6aSRobert Morris 18807090dd7Srsc ilock(dp); 189eaea18cbSrsc 190eaea18cbSrsc // Cannot unlink "." or "..". 191eaea18cbSrsc if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ 19207090dd7Srsc iunlockput(dp); 193*5053dd6aSRobert Morris commit_trans(); 194eaea18cbSrsc return -1; 195eaea18cbSrsc } 196eaea18cbSrsc 19707090dd7Srsc if((ip = dirlookup(dp, name, &off)) == 0){ 19807090dd7Srsc iunlockput(dp); 199*5053dd6aSRobert Morris commit_trans(); 200eaea18cbSrsc return -1; 201eaea18cbSrsc } 20207090dd7Srsc ilock(ip); 203eaea18cbSrsc 204eaea18cbSrsc if(ip->nlink < 1) 205eaea18cbSrsc panic("unlink: nlink < 1"); 206eaea18cbSrsc if(ip->type == T_DIR && !isdirempty(ip)){ 20707090dd7Srsc iunlockput(ip); 20807090dd7Srsc iunlockput(dp); 209*5053dd6aSRobert Morris commit_trans(); 210eaea18cbSrsc return -1; 211eaea18cbSrsc } 212eaea18cbSrsc 213eaea18cbSrsc memset(&de, 0, sizeof(de)); 214eaea18cbSrsc if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 215eaea18cbSrsc panic("unlink: writei"); 21615a26936Skolya if(ip->type == T_DIR){ 21715a26936Skolya dp->nlink--; 21815a26936Skolya iupdate(dp); 21915a26936Skolya } 22007090dd7Srsc iunlockput(dp); 221eaea18cbSrsc 222eaea18cbSrsc ip->nlink--; 223eaea18cbSrsc iupdate(ip); 22407090dd7Srsc iunlockput(ip); 2252e590463SRobert Morris 2262e590463SRobert Morris commit_trans(); 2272e590463SRobert Morris 228eaea18cbSrsc return 0; 229eaea18cbSrsc } 230eaea18cbSrsc 231eaea18cbSrsc static struct inode* 232f3685aa3Srsc create(char *path, short type, short major, short minor) 233eaea18cbSrsc { 234eaea18cbSrsc uint off; 235eaea18cbSrsc struct inode *ip, *dp; 236eaea18cbSrsc char name[DIRSIZ]; 237eaea18cbSrsc 23807090dd7Srsc if((dp = nameiparent(path, name)) == 0) 239eaea18cbSrsc return 0; 24007090dd7Srsc ilock(dp); 241eaea18cbSrsc 242f3685aa3Srsc if((ip = dirlookup(dp, name, &off)) != 0){ 24307090dd7Srsc iunlockput(dp); 24407090dd7Srsc ilock(ip); 245f9a06440SRuss Cox if(type == T_FILE && ip->type == T_FILE) 246f9a06440SRuss Cox return ip; 24707090dd7Srsc iunlockput(ip); 248eaea18cbSrsc return 0; 249eaea18cbSrsc } 250eaea18cbSrsc 251f9a06440SRuss Cox if((ip = ialloc(dp->dev, type)) == 0) 252f9a06440SRuss Cox panic("create: ialloc"); 253f9a06440SRuss Cox 25407090dd7Srsc ilock(ip); 255eaea18cbSrsc ip->major = major; 256eaea18cbSrsc ip->minor = minor; 257603deefcSrsc ip->nlink = 1; 258eaea18cbSrsc iupdate(ip); 259eaea18cbSrsc 260eaea18cbSrsc if(type == T_DIR){ // Create . and .. entries. 261eaea18cbSrsc dp->nlink++; // for ".." 262eaea18cbSrsc iupdate(dp); 263eaea18cbSrsc // No ip->nlink++ for ".": avoid cyclic ref count. 264eaea18cbSrsc if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) 265e79b1659Srsc panic("create dots"); 266eaea18cbSrsc } 267f3e87bc8Skolya 268f3685aa3Srsc if(dirlink(dp, name, ip->inum) < 0) 269f3685aa3Srsc panic("create: dirlink"); 270f3e87bc8Skolya 27107090dd7Srsc iunlockput(dp); 2722e590463SRobert Morris 273eaea18cbSrsc return ip; 274eaea18cbSrsc } 275eaea18cbSrsc 2762685309fSrsc int 2772685309fSrsc sys_open(void) 2782685309fSrsc { 279f32f3638Srsc char *path; 280f32f3638Srsc int fd, omode; 281224f6598Srsc struct file *f; 282f32f3638Srsc struct inode *ip; 2832685309fSrsc 284224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 2852685309fSrsc return -1; 286eaea18cbSrsc if(omode & O_CREATE){ 2872e590463SRobert Morris begin_trans(); 2882e590463SRobert Morris ip = create(path, T_FILE, 0, 0); 2892e590463SRobert Morris commit_trans(); 2902e590463SRobert Morris if(ip == 0) 291e2a620daSrsc return -1; 292eaea18cbSrsc } else { 29307090dd7Srsc if((ip = namei(path)) == 0) 294eaea18cbSrsc return -1; 29507090dd7Srsc ilock(ip); 296f3685aa3Srsc if(ip->type == T_DIR && omode != O_RDONLY){ 29707090dd7Srsc iunlockput(ip); 2982685309fSrsc return -1; 2992685309fSrsc } 300eaea18cbSrsc } 3012685309fSrsc 302eaea18cbSrsc if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ 303eaea18cbSrsc if(f) 304224f6598Srsc fileclose(f); 30507090dd7Srsc iunlockput(ip); 3062685309fSrsc return -1; 3072685309fSrsc } 30807090dd7Srsc iunlock(ip); 3092685309fSrsc 310eaea18cbSrsc f->type = FD_INODE; 31107090dd7Srsc f->ip = ip; 312eaea18cbSrsc f->off = 0; 313e79b1659Srsc f->readable = !(omode & O_WRONLY); 314e79b1659Srsc f->writable = (omode & O_WRONLY) || (omode & O_RDWR); 315224f6598Srsc return fd; 3162685309fSrsc } 3172685309fSrsc 3182685309fSrsc int 319f9a06440SRuss Cox sys_mkdir(void) 320f9a06440SRuss Cox { 321f9a06440SRuss Cox char *path; 322f9a06440SRuss Cox struct inode *ip; 323f9a06440SRuss Cox 3242e590463SRobert Morris begin_trans(); 3252e590463SRobert Morris if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){ 3262e590463SRobert Morris commit_trans(); 327f9a06440SRuss Cox return -1; 3282e590463SRobert Morris } 329f9a06440SRuss Cox iunlockput(ip); 3302e590463SRobert Morris commit_trans(); 331f9a06440SRuss Cox return 0; 332f9a06440SRuss Cox } 333f9a06440SRuss Cox 334f9a06440SRuss Cox int 3352685309fSrsc sys_mknod(void) 3362685309fSrsc { 337eaea18cbSrsc struct inode *ip; 338224f6598Srsc char *path; 339224f6598Srsc int len; 340aa6824abSrsc int major, minor; 3412685309fSrsc 3422e590463SRobert Morris begin_trans(); 34307090dd7Srsc if((len=argstr(0, &path)) < 0 || 34407090dd7Srsc argint(1, &major) < 0 || 34507090dd7Srsc argint(2, &minor) < 0 || 3462e590463SRobert Morris (ip = create(path, T_DEV, major, minor)) == 0){ 3472e590463SRobert Morris commit_trans(); 3482685309fSrsc return -1; 3492e590463SRobert Morris } 35007090dd7Srsc iunlockput(ip); 3512e590463SRobert Morris commit_trans(); 352224f6598Srsc return 0; 3532685309fSrsc } 3542685309fSrsc 3552685309fSrsc int 3562685309fSrsc sys_chdir(void) 3572685309fSrsc { 358eaea18cbSrsc char *path; 3592685309fSrsc struct inode *ip; 3602685309fSrsc 36107090dd7Srsc if(argstr(0, &path) < 0 || (ip = namei(path)) == 0) 3622685309fSrsc return -1; 36307090dd7Srsc ilock(ip); 3642685309fSrsc if(ip->type != T_DIR){ 36507090dd7Srsc iunlockput(ip); 3662685309fSrsc return -1; 3672685309fSrsc } 36807090dd7Srsc iunlock(ip); 36948755214SRuss Cox iput(proc->cwd); 37048755214SRuss Cox proc->cwd = ip; 3712685309fSrsc return 0; 3722685309fSrsc } 3732685309fSrsc 3742685309fSrsc int 3752685309fSrsc sys_exec(void) 3762685309fSrsc { 3774655d42eSRobert Morris char *path, *argv[MAXARG]; 378f32f3638Srsc int i; 379f32f3638Srsc uint uargv, uarg; 3802685309fSrsc 38140889627SFrans Kaashoek if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){ 3822685309fSrsc return -1; 38340889627SFrans Kaashoek } 384eaea18cbSrsc memset(argv, 0, sizeof(argv)); 3852685309fSrsc for(i=0;; i++){ 386eaea18cbSrsc if(i >= NELEM(argv)) 3872685309fSrsc return -1; 38848755214SRuss Cox if(fetchint(proc, uargv+4*i, (int*)&uarg) < 0) 389f32f3638Srsc return -1; 390f32f3638Srsc if(uarg == 0){ 391f32f3638Srsc argv[i] = 0; 392f32f3638Srsc break; 3932685309fSrsc } 39448755214SRuss Cox if(fetchstr(proc, uarg, &argv[i]) < 0) 395f32f3638Srsc return -1; 396f32f3638Srsc } 397f32f3638Srsc return exec(path, argv); 398f32f3638Srsc } 399f32f3638Srsc 400eaea18cbSrsc int 401eaea18cbSrsc sys_pipe(void) 402eaea18cbSrsc { 403eaea18cbSrsc int *fd; 404eaea18cbSrsc struct file *rf, *wf; 405eaea18cbSrsc int fd0, fd1; 406eaea18cbSrsc 407eaea18cbSrsc if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) 408eaea18cbSrsc return -1; 4097834cca6Srsc if(pipealloc(&rf, &wf) < 0) 410eaea18cbSrsc return -1; 411eaea18cbSrsc fd0 = -1; 412eaea18cbSrsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 413eaea18cbSrsc if(fd0 >= 0) 41448755214SRuss Cox proc->ofile[fd0] = 0; 415eaea18cbSrsc fileclose(rf); 416eaea18cbSrsc fileclose(wf); 417eaea18cbSrsc return -1; 418eaea18cbSrsc } 419eaea18cbSrsc fd[0] = fd0; 420eaea18cbSrsc fd[1] = fd1; 421eaea18cbSrsc return 0; 422eaea18cbSrsc } 423