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" 82685309fSrsc #include "fsvar.h" 99936bffaSrsc #include "file.h" 102685309fSrsc #include "fcntl.h" 112685309fSrsc 12224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor 13224f6598Srsc // and return both the descriptor and the corresponding struct file. 14224f6598Srsc static int 1564c47374Srsc argfd(int n, int *pfd, struct file **pf) 16224f6598Srsc { 17224f6598Srsc int fd; 18224f6598Srsc struct file *f; 19224f6598Srsc 203a2310f7Srsc if(argint(n, &fd) < 0) 21224f6598Srsc return -1; 229583b476Srsc if(fd < 0 || fd >= NOFILE || (f=cp->ofile[fd]) == 0) 23224f6598Srsc return -1; 24224f6598Srsc if(pfd) 25224f6598Srsc *pfd = fd; 26224f6598Srsc if(pf) 27224f6598Srsc *pf = f; 28224f6598Srsc return 0; 29224f6598Srsc } 30224f6598Srsc 31224f6598Srsc // Allocate a file descriptor for the given file. 32224f6598Srsc // Takes over file reference from caller on success. 33224f6598Srsc static int 34224f6598Srsc fdalloc(struct file *f) 35224f6598Srsc { 36224f6598Srsc int fd; 379583b476Srsc 38224f6598Srsc for(fd = 0; fd < NOFILE; fd++){ 399583b476Srsc if(cp->ofile[fd] == 0){ 409583b476Srsc cp->ofile[fd] = f; 41224f6598Srsc return fd; 42224f6598Srsc } 43224f6598Srsc } 44224f6598Srsc return -1; 45224f6598Srsc } 46224f6598Srsc 472685309fSrsc int 48*f9a06440SRuss Cox sys_dup(void) 49*f9a06440SRuss Cox { 50*f9a06440SRuss Cox struct file *f; 51*f9a06440SRuss Cox int fd; 52*f9a06440SRuss Cox 53*f9a06440SRuss Cox if(argfd(0, 0, &f) < 0) 54*f9a06440SRuss Cox return -1; 55*f9a06440SRuss Cox if((fd=fdalloc(f)) < 0) 56*f9a06440SRuss Cox return -1; 57*f9a06440SRuss Cox filedup(f); 58*f9a06440SRuss Cox return fd; 59*f9a06440SRuss Cox } 60*f9a06440SRuss Cox 61*f9a06440SRuss Cox int 62eaea18cbSrsc sys_read(void) 632685309fSrsc { 64eaea18cbSrsc struct file *f; 65eaea18cbSrsc int n; 66666f58c7Srsc char *p; 672685309fSrsc 68666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) 692685309fSrsc return -1; 70666f58c7Srsc return fileread(f, p, n); 712685309fSrsc } 722685309fSrsc 732685309fSrsc int 742685309fSrsc sys_write(void) 752685309fSrsc { 76224f6598Srsc struct file *f; 77224f6598Srsc int n; 78666f58c7Srsc char *p; 792685309fSrsc 80666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) 812685309fSrsc return -1; 82666f58c7Srsc return filewrite(f, p, n); 832685309fSrsc } 842685309fSrsc 852685309fSrsc int 862685309fSrsc sys_close(void) 872685309fSrsc { 882685309fSrsc int fd; 89224f6598Srsc struct file *f; 902685309fSrsc 91224f6598Srsc if(argfd(0, &fd, &f) < 0) 922685309fSrsc return -1; 93b6095304Srsc cp->ofile[fd] = 0; 94224f6598Srsc fileclose(f); 952685309fSrsc return 0; 962685309fSrsc } 972685309fSrsc 988d2e9a48Srsc int 998d2e9a48Srsc sys_fstat(void) 1008d2e9a48Srsc { 1018d2e9a48Srsc struct file *f; 1028d2e9a48Srsc struct stat *st; 1038d2e9a48Srsc 1048d2e9a48Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0) 1058d2e9a48Srsc return -1; 1068d2e9a48Srsc return filestat(f, st); 1078d2e9a48Srsc } 1088d2e9a48Srsc 109eaea18cbSrsc // Create the path new as a link to the same inode as old. 110eaea18cbSrsc int 111eaea18cbSrsc sys_link(void) 112eaea18cbSrsc { 113eaea18cbSrsc char name[DIRSIZ], *new, *old; 114eaea18cbSrsc struct inode *dp, *ip; 115eaea18cbSrsc 116eaea18cbSrsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 117eaea18cbSrsc return -1; 11807090dd7Srsc if((ip = namei(old)) == 0) 119eaea18cbSrsc return -1; 12007090dd7Srsc ilock(ip); 121eaea18cbSrsc if(ip->type == T_DIR){ 12207090dd7Srsc iunlockput(ip); 123eaea18cbSrsc return -1; 124eaea18cbSrsc } 125eaea18cbSrsc ip->nlink++; 126eaea18cbSrsc iupdate(ip); 12707090dd7Srsc iunlock(ip); 128eaea18cbSrsc 12907090dd7Srsc if((dp = nameiparent(new, name)) == 0) 13007090dd7Srsc goto bad; 13107090dd7Srsc ilock(dp); 132f3685aa3Srsc if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ 133f3685aa3Srsc iunlockput(dp); 13407090dd7Srsc goto bad; 135f3685aa3Srsc } 13607090dd7Srsc iunlockput(dp); 13707090dd7Srsc iput(ip); 13807090dd7Srsc return 0; 13907090dd7Srsc 14007090dd7Srsc bad: 14107090dd7Srsc ilock(ip); 142eaea18cbSrsc ip->nlink--; 143eaea18cbSrsc iupdate(ip); 14407090dd7Srsc iunlockput(ip); 145eaea18cbSrsc return -1; 146eaea18cbSrsc } 147eaea18cbSrsc 148eaea18cbSrsc // Is the directory dp empty except for "." and ".." ? 149eaea18cbSrsc static int 150eaea18cbSrsc isdirempty(struct inode *dp) 151eaea18cbSrsc { 152eaea18cbSrsc int off; 153eaea18cbSrsc struct dirent de; 154eaea18cbSrsc 155eaea18cbSrsc for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ 156eaea18cbSrsc if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 157eaea18cbSrsc panic("isdirempty: readi"); 158eaea18cbSrsc if(de.inum != 0) 159eaea18cbSrsc return 0; 160eaea18cbSrsc } 161eaea18cbSrsc return 1; 162eaea18cbSrsc } 163eaea18cbSrsc 1648d2e9a48Srsc //PAGEBREAK! 165eaea18cbSrsc int 166eaea18cbSrsc sys_unlink(void) 167eaea18cbSrsc { 168eaea18cbSrsc struct inode *ip, *dp; 169eaea18cbSrsc struct dirent de; 170eaea18cbSrsc char name[DIRSIZ], *path; 171eaea18cbSrsc uint off; 172eaea18cbSrsc 173eaea18cbSrsc if(argstr(0, &path) < 0) 174eaea18cbSrsc return -1; 17507090dd7Srsc if((dp = nameiparent(path, name)) == 0) 176eaea18cbSrsc return -1; 17707090dd7Srsc ilock(dp); 178eaea18cbSrsc 179eaea18cbSrsc // Cannot unlink "." or "..". 180eaea18cbSrsc if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ 18107090dd7Srsc iunlockput(dp); 182eaea18cbSrsc return -1; 183eaea18cbSrsc } 184eaea18cbSrsc 18507090dd7Srsc if((ip = dirlookup(dp, name, &off)) == 0){ 18607090dd7Srsc iunlockput(dp); 187eaea18cbSrsc return -1; 188eaea18cbSrsc } 18907090dd7Srsc ilock(ip); 190eaea18cbSrsc 191eaea18cbSrsc if(ip->nlink < 1) 192eaea18cbSrsc panic("unlink: nlink < 1"); 193eaea18cbSrsc if(ip->type == T_DIR && !isdirempty(ip)){ 19407090dd7Srsc iunlockput(ip); 19507090dd7Srsc iunlockput(dp); 196eaea18cbSrsc return -1; 197eaea18cbSrsc } 198eaea18cbSrsc 199eaea18cbSrsc memset(&de, 0, sizeof(de)); 200eaea18cbSrsc if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 201eaea18cbSrsc panic("unlink: writei"); 20215a26936Skolya if(ip->type == T_DIR){ 20315a26936Skolya dp->nlink--; 20415a26936Skolya iupdate(dp); 20515a26936Skolya } 20607090dd7Srsc iunlockput(dp); 207eaea18cbSrsc 208eaea18cbSrsc ip->nlink--; 209eaea18cbSrsc iupdate(ip); 21007090dd7Srsc iunlockput(ip); 211eaea18cbSrsc return 0; 212eaea18cbSrsc } 213eaea18cbSrsc 214eaea18cbSrsc static struct inode* 215f3685aa3Srsc create(char *path, short type, short major, short minor) 216eaea18cbSrsc { 217eaea18cbSrsc uint off; 218eaea18cbSrsc struct inode *ip, *dp; 219eaea18cbSrsc char name[DIRSIZ]; 220eaea18cbSrsc 22107090dd7Srsc if((dp = nameiparent(path, name)) == 0) 222eaea18cbSrsc return 0; 22307090dd7Srsc ilock(dp); 224eaea18cbSrsc 225f3685aa3Srsc if((ip = dirlookup(dp, name, &off)) != 0){ 22607090dd7Srsc iunlockput(dp); 22707090dd7Srsc ilock(ip); 228*f9a06440SRuss Cox if(type == T_FILE && ip->type == T_FILE) 229*f9a06440SRuss Cox return ip; 23007090dd7Srsc iunlockput(ip); 231eaea18cbSrsc return 0; 232eaea18cbSrsc } 233eaea18cbSrsc 234*f9a06440SRuss Cox if((ip = ialloc(dp->dev, type)) == 0) 235*f9a06440SRuss Cox panic("create: ialloc"); 236*f9a06440SRuss Cox 23707090dd7Srsc ilock(ip); 238eaea18cbSrsc ip->major = major; 239eaea18cbSrsc ip->minor = minor; 240603deefcSrsc ip->nlink = 1; 241eaea18cbSrsc iupdate(ip); 242eaea18cbSrsc 243eaea18cbSrsc if(type == T_DIR){ // Create . and .. entries. 244eaea18cbSrsc dp->nlink++; // for ".." 245eaea18cbSrsc iupdate(dp); 246eaea18cbSrsc // No ip->nlink++ for ".": avoid cyclic ref count. 247eaea18cbSrsc if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) 248e79b1659Srsc panic("create dots"); 249eaea18cbSrsc } 250f3e87bc8Skolya 251f3685aa3Srsc if(dirlink(dp, name, ip->inum) < 0) 252f3685aa3Srsc panic("create: dirlink"); 253f3e87bc8Skolya 25407090dd7Srsc iunlockput(dp); 255eaea18cbSrsc return ip; 256eaea18cbSrsc } 257eaea18cbSrsc 2582685309fSrsc int 2592685309fSrsc sys_open(void) 2602685309fSrsc { 261f32f3638Srsc char *path; 262f32f3638Srsc int fd, omode; 263224f6598Srsc struct file *f; 264f32f3638Srsc struct inode *ip; 2652685309fSrsc 266224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 2672685309fSrsc return -1; 2682685309fSrsc 269eaea18cbSrsc if(omode & O_CREATE){ 270f3685aa3Srsc if((ip = create(path, T_FILE, 0, 0)) == 0) 271e2a620daSrsc return -1; 272eaea18cbSrsc } else { 27307090dd7Srsc if((ip = namei(path)) == 0) 274eaea18cbSrsc return -1; 27507090dd7Srsc ilock(ip); 276f3685aa3Srsc if(ip->type == T_DIR && omode != O_RDONLY){ 27707090dd7Srsc iunlockput(ip); 2782685309fSrsc return -1; 2792685309fSrsc } 280eaea18cbSrsc } 2812685309fSrsc 282eaea18cbSrsc if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ 283eaea18cbSrsc if(f) 284224f6598Srsc fileclose(f); 28507090dd7Srsc iunlockput(ip); 2862685309fSrsc return -1; 2872685309fSrsc } 28807090dd7Srsc iunlock(ip); 2892685309fSrsc 290eaea18cbSrsc f->type = FD_INODE; 29107090dd7Srsc f->ip = ip; 292eaea18cbSrsc f->off = 0; 293e79b1659Srsc f->readable = !(omode & O_WRONLY); 294e79b1659Srsc f->writable = (omode & O_WRONLY) || (omode & O_RDWR); 2952685309fSrsc 296224f6598Srsc return fd; 2972685309fSrsc } 2982685309fSrsc 2992685309fSrsc int 300*f9a06440SRuss Cox sys_mkdir(void) 301*f9a06440SRuss Cox { 302*f9a06440SRuss Cox char *path; 303*f9a06440SRuss Cox struct inode *ip; 304*f9a06440SRuss Cox 305*f9a06440SRuss Cox if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0) 306*f9a06440SRuss Cox return -1; 307*f9a06440SRuss Cox iunlockput(ip); 308*f9a06440SRuss Cox return 0; 309*f9a06440SRuss Cox } 310*f9a06440SRuss Cox 311*f9a06440SRuss Cox int 3122685309fSrsc sys_mknod(void) 3132685309fSrsc { 314eaea18cbSrsc struct inode *ip; 315224f6598Srsc char *path; 316224f6598Srsc int len; 317aa6824abSrsc int major, minor; 3182685309fSrsc 31907090dd7Srsc if((len=argstr(0, &path)) < 0 || 32007090dd7Srsc argint(1, &major) < 0 || 32107090dd7Srsc argint(2, &minor) < 0 || 322f3685aa3Srsc (ip = create(path, T_DEV, major, minor)) == 0) 3232685309fSrsc return -1; 32407090dd7Srsc iunlockput(ip); 325224f6598Srsc return 0; 3262685309fSrsc } 3272685309fSrsc 3282685309fSrsc int 3292685309fSrsc sys_chdir(void) 3302685309fSrsc { 331eaea18cbSrsc char *path; 3322685309fSrsc struct inode *ip; 3332685309fSrsc 33407090dd7Srsc if(argstr(0, &path) < 0 || (ip = namei(path)) == 0) 3352685309fSrsc return -1; 33607090dd7Srsc ilock(ip); 3372685309fSrsc if(ip->type != T_DIR){ 33807090dd7Srsc iunlockput(ip); 3392685309fSrsc return -1; 3402685309fSrsc } 34107090dd7Srsc iunlock(ip); 342eaea18cbSrsc iput(cp->cwd); 34307090dd7Srsc cp->cwd = ip; 3442685309fSrsc return 0; 3452685309fSrsc } 3462685309fSrsc 3472685309fSrsc int 3482685309fSrsc sys_exec(void) 3492685309fSrsc { 350eaea18cbSrsc char *path, *argv[20]; 351f32f3638Srsc int i; 352f32f3638Srsc uint uargv, uarg; 3532685309fSrsc 354f32f3638Srsc if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0) 3552685309fSrsc return -1; 356eaea18cbSrsc memset(argv, 0, sizeof(argv)); 3572685309fSrsc for(i=0;; i++){ 358eaea18cbSrsc if(i >= NELEM(argv)) 3592685309fSrsc return -1; 360f32f3638Srsc if(fetchint(cp, uargv+4*i, (int*)&uarg) < 0) 361f32f3638Srsc return -1; 362f32f3638Srsc if(uarg == 0){ 363f32f3638Srsc argv[i] = 0; 364f32f3638Srsc break; 3652685309fSrsc } 366f32f3638Srsc if(fetchstr(cp, uarg, &argv[i]) < 0) 367f32f3638Srsc return -1; 368f32f3638Srsc } 369f32f3638Srsc return exec(path, argv); 370f32f3638Srsc } 371f32f3638Srsc 372eaea18cbSrsc int 373eaea18cbSrsc sys_pipe(void) 374eaea18cbSrsc { 375eaea18cbSrsc int *fd; 376eaea18cbSrsc struct file *rf, *wf; 377eaea18cbSrsc int fd0, fd1; 378eaea18cbSrsc 379eaea18cbSrsc if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) 380eaea18cbSrsc return -1; 3817834cca6Srsc if(pipealloc(&rf, &wf) < 0) 382eaea18cbSrsc return -1; 383eaea18cbSrsc fd0 = -1; 384eaea18cbSrsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 385eaea18cbSrsc if(fd0 >= 0) 386eaea18cbSrsc cp->ofile[fd0] = 0; 387eaea18cbSrsc fileclose(rf); 388eaea18cbSrsc fileclose(wf); 389eaea18cbSrsc return -1; 390eaea18cbSrsc } 391eaea18cbSrsc fd[0] = fd0; 392eaea18cbSrsc fd[1] = fd1; 393eaea18cbSrsc return 0; 394eaea18cbSrsc } 395