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" 149936bffaSrsc #include "file.h" 152685309fSrsc #include "fcntl.h" 162685309fSrsc 17224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor 18224f6598Srsc // and return both the descriptor and the corresponding struct file. 19224f6598Srsc static int 2064c47374Srsc argfd(int n, int *pfd, struct file **pf) 21224f6598Srsc { 22224f6598Srsc int fd; 23224f6598Srsc struct file *f; 24224f6598Srsc 253a2310f7Srsc if(argint(n, &fd) < 0) 26224f6598Srsc return -1; 2748755214SRuss Cox if(fd < 0 || fd >= NOFILE || (f=proc->ofile[fd]) == 0) 28224f6598Srsc return -1; 29224f6598Srsc if(pfd) 30224f6598Srsc *pfd = fd; 31224f6598Srsc if(pf) 32224f6598Srsc *pf = f; 33224f6598Srsc return 0; 34224f6598Srsc } 35224f6598Srsc 36224f6598Srsc // Allocate a file descriptor for the given file. 37224f6598Srsc // Takes over file reference from caller on success. 38224f6598Srsc static int 39224f6598Srsc fdalloc(struct file *f) 40224f6598Srsc { 41224f6598Srsc int fd; 429583b476Srsc 43224f6598Srsc for(fd = 0; fd < NOFILE; fd++){ 4448755214SRuss Cox if(proc->ofile[fd] == 0){ 4548755214SRuss Cox proc->ofile[fd] = f; 46224f6598Srsc return fd; 47224f6598Srsc } 48224f6598Srsc } 49224f6598Srsc return -1; 50224f6598Srsc } 51224f6598Srsc 522685309fSrsc int 53f9a06440SRuss Cox sys_dup(void) 54f9a06440SRuss Cox { 55f9a06440SRuss Cox struct file *f; 56f9a06440SRuss Cox int fd; 57f9a06440SRuss Cox 58f9a06440SRuss Cox if(argfd(0, 0, &f) < 0) 59f9a06440SRuss Cox return -1; 60f9a06440SRuss Cox if((fd=fdalloc(f)) < 0) 61f9a06440SRuss Cox return -1; 62f9a06440SRuss Cox filedup(f); 63f9a06440SRuss Cox return fd; 64f9a06440SRuss Cox } 65f9a06440SRuss Cox 66f9a06440SRuss Cox int 67eaea18cbSrsc sys_read(void) 682685309fSrsc { 69eaea18cbSrsc struct file *f; 70eaea18cbSrsc int n; 71666f58c7Srsc char *p; 722685309fSrsc 73666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) 742685309fSrsc return -1; 75666f58c7Srsc return fileread(f, p, n); 762685309fSrsc } 772685309fSrsc 782685309fSrsc int 792685309fSrsc sys_write(void) 802685309fSrsc { 81224f6598Srsc struct file *f; 82224f6598Srsc int n; 83666f58c7Srsc char *p; 842685309fSrsc 85666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) 862685309fSrsc return -1; 87666f58c7Srsc return filewrite(f, p, n); 882685309fSrsc } 892685309fSrsc 902685309fSrsc int 912685309fSrsc sys_close(void) 922685309fSrsc { 932685309fSrsc int fd; 94224f6598Srsc struct file *f; 952685309fSrsc 96224f6598Srsc if(argfd(0, &fd, &f) < 0) 972685309fSrsc return -1; 9848755214SRuss Cox proc->ofile[fd] = 0; 99224f6598Srsc fileclose(f); 1002685309fSrsc return 0; 1012685309fSrsc } 1022685309fSrsc 1038d2e9a48Srsc int 1048d2e9a48Srsc sys_fstat(void) 1058d2e9a48Srsc { 1068d2e9a48Srsc struct file *f; 1078d2e9a48Srsc struct stat *st; 1088d2e9a48Srsc 1098d2e9a48Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0) 1108d2e9a48Srsc return -1; 1118d2e9a48Srsc return filestat(f, st); 1128d2e9a48Srsc } 1138d2e9a48Srsc 114eaea18cbSrsc // Create the path new as a link to the same inode as old. 115eaea18cbSrsc int 116eaea18cbSrsc sys_link(void) 117eaea18cbSrsc { 118eaea18cbSrsc char name[DIRSIZ], *new, *old; 119eaea18cbSrsc struct inode *dp, *ip; 120eaea18cbSrsc 121eaea18cbSrsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 122eaea18cbSrsc return -1; 1235053dd6aSRobert Morris 1245053dd6aSRobert Morris begin_trans(); 125*2c565472SRobert Morris if((ip = namei(old)) == 0){ 126*2c565472SRobert Morris commit_trans(); 127*2c565472SRobert Morris return -1; 128*2c565472SRobert Morris } 1295053dd6aSRobert Morris 13007090dd7Srsc ilock(ip); 131eaea18cbSrsc if(ip->type == T_DIR){ 13207090dd7Srsc iunlockput(ip); 1335053dd6aSRobert Morris commit_trans(); 134eaea18cbSrsc return -1; 135eaea18cbSrsc } 1362e590463SRobert Morris 137eaea18cbSrsc ip->nlink++; 138eaea18cbSrsc iupdate(ip); 13907090dd7Srsc iunlock(ip); 140eaea18cbSrsc 14107090dd7Srsc if((dp = nameiparent(new, name)) == 0) 14207090dd7Srsc goto bad; 14307090dd7Srsc ilock(dp); 144f3685aa3Srsc if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ 145f3685aa3Srsc iunlockput(dp); 14607090dd7Srsc goto bad; 147f3685aa3Srsc } 14807090dd7Srsc iunlockput(dp); 14907090dd7Srsc iput(ip); 1502e590463SRobert Morris 1512e590463SRobert Morris commit_trans(); 1522e590463SRobert Morris 15307090dd7Srsc return 0; 15407090dd7Srsc 15507090dd7Srsc bad: 15607090dd7Srsc ilock(ip); 157eaea18cbSrsc ip->nlink--; 158eaea18cbSrsc iupdate(ip); 15907090dd7Srsc iunlockput(ip); 1602e590463SRobert Morris commit_trans(); 161eaea18cbSrsc return -1; 162eaea18cbSrsc } 163eaea18cbSrsc 164eaea18cbSrsc // Is the directory dp empty except for "." and ".." ? 165eaea18cbSrsc static int 166eaea18cbSrsc isdirempty(struct inode *dp) 167eaea18cbSrsc { 168eaea18cbSrsc int off; 169eaea18cbSrsc struct dirent de; 170eaea18cbSrsc 171eaea18cbSrsc for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ 172eaea18cbSrsc if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 173eaea18cbSrsc panic("isdirempty: readi"); 174eaea18cbSrsc if(de.inum != 0) 175eaea18cbSrsc return 0; 176eaea18cbSrsc } 177eaea18cbSrsc return 1; 178eaea18cbSrsc } 179eaea18cbSrsc 1808d2e9a48Srsc //PAGEBREAK! 181eaea18cbSrsc int 182eaea18cbSrsc sys_unlink(void) 183eaea18cbSrsc { 184eaea18cbSrsc struct inode *ip, *dp; 185eaea18cbSrsc struct dirent de; 186eaea18cbSrsc char name[DIRSIZ], *path; 187eaea18cbSrsc uint off; 188eaea18cbSrsc 189eaea18cbSrsc if(argstr(0, &path) < 0) 190eaea18cbSrsc return -1; 1915053dd6aSRobert Morris 1925053dd6aSRobert Morris begin_trans(); 193*2c565472SRobert Morris if((dp = nameiparent(path, name)) == 0){ 194*2c565472SRobert Morris commit_trans(); 195*2c565472SRobert Morris return -1; 196*2c565472SRobert Morris } 1975053dd6aSRobert Morris 19807090dd7Srsc ilock(dp); 199eaea18cbSrsc 200eaea18cbSrsc // Cannot unlink "." or "..". 2014e015d81SAustin Clements if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0) 2024e015d81SAustin Clements goto bad; 203eaea18cbSrsc 2044e015d81SAustin Clements if((ip = dirlookup(dp, name, &off)) == 0) 2054e015d81SAustin Clements goto bad; 20607090dd7Srsc ilock(ip); 207eaea18cbSrsc 208eaea18cbSrsc if(ip->nlink < 1) 209eaea18cbSrsc panic("unlink: nlink < 1"); 210eaea18cbSrsc if(ip->type == T_DIR && !isdirempty(ip)){ 21107090dd7Srsc iunlockput(ip); 2124e015d81SAustin Clements goto bad; 213eaea18cbSrsc } 214eaea18cbSrsc 215eaea18cbSrsc memset(&de, 0, sizeof(de)); 216eaea18cbSrsc if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 217eaea18cbSrsc panic("unlink: writei"); 21815a26936Skolya if(ip->type == T_DIR){ 21915a26936Skolya dp->nlink--; 22015a26936Skolya iupdate(dp); 22115a26936Skolya } 22207090dd7Srsc iunlockput(dp); 223eaea18cbSrsc 224eaea18cbSrsc ip->nlink--; 225eaea18cbSrsc iupdate(ip); 22607090dd7Srsc iunlockput(ip); 2272e590463SRobert Morris 2282e590463SRobert Morris commit_trans(); 2292e590463SRobert Morris 230eaea18cbSrsc return 0; 2314e015d81SAustin Clements 2324e015d81SAustin Clements bad: 2334e015d81SAustin Clements iunlockput(dp); 2344e015d81SAustin Clements commit_trans(); 2354e015d81SAustin Clements return -1; 236eaea18cbSrsc } 237eaea18cbSrsc 238eaea18cbSrsc static struct inode* 239f3685aa3Srsc create(char *path, short type, short major, short minor) 240eaea18cbSrsc { 241eaea18cbSrsc uint off; 242eaea18cbSrsc struct inode *ip, *dp; 243eaea18cbSrsc char name[DIRSIZ]; 244eaea18cbSrsc 24507090dd7Srsc if((dp = nameiparent(path, name)) == 0) 246eaea18cbSrsc return 0; 24707090dd7Srsc ilock(dp); 248eaea18cbSrsc 249f3685aa3Srsc if((ip = dirlookup(dp, name, &off)) != 0){ 25007090dd7Srsc iunlockput(dp); 25107090dd7Srsc ilock(ip); 252f9a06440SRuss Cox if(type == T_FILE && ip->type == T_FILE) 253f9a06440SRuss Cox return ip; 25407090dd7Srsc iunlockput(ip); 255eaea18cbSrsc return 0; 256eaea18cbSrsc } 257eaea18cbSrsc 258f9a06440SRuss Cox if((ip = ialloc(dp->dev, type)) == 0) 259f9a06440SRuss Cox panic("create: ialloc"); 260f9a06440SRuss Cox 26107090dd7Srsc ilock(ip); 262eaea18cbSrsc ip->major = major; 263eaea18cbSrsc ip->minor = minor; 264603deefcSrsc ip->nlink = 1; 265eaea18cbSrsc iupdate(ip); 266eaea18cbSrsc 267eaea18cbSrsc if(type == T_DIR){ // Create . and .. entries. 268eaea18cbSrsc dp->nlink++; // for ".." 269eaea18cbSrsc iupdate(dp); 270eaea18cbSrsc // No ip->nlink++ for ".": avoid cyclic ref count. 271eaea18cbSrsc if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) 272e79b1659Srsc panic("create dots"); 273eaea18cbSrsc } 274f3e87bc8Skolya 275f3685aa3Srsc if(dirlink(dp, name, ip->inum) < 0) 276f3685aa3Srsc panic("create: dirlink"); 277f3e87bc8Skolya 27807090dd7Srsc iunlockput(dp); 2792e590463SRobert Morris 280eaea18cbSrsc return ip; 281eaea18cbSrsc } 282eaea18cbSrsc 2832685309fSrsc int 2842685309fSrsc sys_open(void) 2852685309fSrsc { 286f32f3638Srsc char *path; 287f32f3638Srsc int fd, omode; 288224f6598Srsc struct file *f; 289f32f3638Srsc struct inode *ip; 2902685309fSrsc 291224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 2922685309fSrsc return -1; 293*2c565472SRobert Morris 2942e590463SRobert Morris begin_trans(); 295*2c565472SRobert Morris 296*2c565472SRobert Morris if(omode & O_CREATE){ 2972e590463SRobert Morris ip = create(path, T_FILE, 0, 0); 298*2c565472SRobert Morris if(ip == 0){ 2992e590463SRobert Morris commit_trans(); 300e2a620daSrsc return -1; 301*2c565472SRobert Morris } 302eaea18cbSrsc } else { 303*2c565472SRobert Morris if((ip = namei(path)) == 0){ 304*2c565472SRobert Morris commit_trans(); 305eaea18cbSrsc return -1; 306*2c565472SRobert Morris } 30707090dd7Srsc ilock(ip); 308f3685aa3Srsc if(ip->type == T_DIR && omode != O_RDONLY){ 30907090dd7Srsc iunlockput(ip); 310*2c565472SRobert Morris commit_trans(); 3112685309fSrsc return -1; 3122685309fSrsc } 313eaea18cbSrsc } 3142685309fSrsc 315eaea18cbSrsc if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ 316eaea18cbSrsc if(f) 317224f6598Srsc fileclose(f); 31807090dd7Srsc iunlockput(ip); 319*2c565472SRobert Morris commit_trans(); 3202685309fSrsc return -1; 3212685309fSrsc } 32207090dd7Srsc iunlock(ip); 323*2c565472SRobert Morris commit_trans(); 3242685309fSrsc 325eaea18cbSrsc f->type = FD_INODE; 32607090dd7Srsc f->ip = ip; 327eaea18cbSrsc f->off = 0; 328e79b1659Srsc f->readable = !(omode & O_WRONLY); 329e79b1659Srsc f->writable = (omode & O_WRONLY) || (omode & O_RDWR); 330224f6598Srsc return fd; 3312685309fSrsc } 3322685309fSrsc 3332685309fSrsc int 334f9a06440SRuss Cox sys_mkdir(void) 335f9a06440SRuss Cox { 336f9a06440SRuss Cox char *path; 337f9a06440SRuss Cox struct inode *ip; 338f9a06440SRuss Cox 3392e590463SRobert Morris begin_trans(); 3402e590463SRobert Morris if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){ 3412e590463SRobert Morris commit_trans(); 342f9a06440SRuss Cox return -1; 3432e590463SRobert Morris } 344f9a06440SRuss Cox iunlockput(ip); 3452e590463SRobert Morris commit_trans(); 346f9a06440SRuss Cox return 0; 347f9a06440SRuss Cox } 348f9a06440SRuss Cox 349f9a06440SRuss Cox int 3502685309fSrsc sys_mknod(void) 3512685309fSrsc { 352eaea18cbSrsc struct inode *ip; 353224f6598Srsc char *path; 354224f6598Srsc int len; 355aa6824abSrsc int major, minor; 3562685309fSrsc 3572e590463SRobert Morris begin_trans(); 35807090dd7Srsc if((len=argstr(0, &path)) < 0 || 35907090dd7Srsc argint(1, &major) < 0 || 36007090dd7Srsc argint(2, &minor) < 0 || 3612e590463SRobert Morris (ip = create(path, T_DEV, major, minor)) == 0){ 3622e590463SRobert Morris commit_trans(); 3632685309fSrsc return -1; 3642e590463SRobert Morris } 36507090dd7Srsc iunlockput(ip); 3662e590463SRobert Morris commit_trans(); 367224f6598Srsc return 0; 3682685309fSrsc } 3692685309fSrsc 3702685309fSrsc int 3712685309fSrsc sys_chdir(void) 3722685309fSrsc { 373eaea18cbSrsc char *path; 3742685309fSrsc struct inode *ip; 3752685309fSrsc 376*2c565472SRobert Morris begin_trans(); 377*2c565472SRobert Morris if(argstr(0, &path) < 0 || (ip = namei(path)) == 0){ 378*2c565472SRobert Morris commit_trans(); 3792685309fSrsc return -1; 380*2c565472SRobert Morris } 38107090dd7Srsc ilock(ip); 3822685309fSrsc if(ip->type != T_DIR){ 38307090dd7Srsc iunlockput(ip); 384*2c565472SRobert Morris commit_trans(); 3852685309fSrsc return -1; 3862685309fSrsc } 38707090dd7Srsc iunlock(ip); 38848755214SRuss Cox iput(proc->cwd); 389*2c565472SRobert Morris commit_trans(); 39048755214SRuss Cox proc->cwd = ip; 3912685309fSrsc return 0; 3922685309fSrsc } 3932685309fSrsc 3942685309fSrsc int 3952685309fSrsc sys_exec(void) 3962685309fSrsc { 3974655d42eSRobert Morris char *path, *argv[MAXARG]; 398f32f3638Srsc int i; 399f32f3638Srsc uint uargv, uarg; 4002685309fSrsc 40140889627SFrans Kaashoek if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){ 4022685309fSrsc return -1; 40340889627SFrans Kaashoek } 404eaea18cbSrsc memset(argv, 0, sizeof(argv)); 4052685309fSrsc for(i=0;; i++){ 406eaea18cbSrsc if(i >= NELEM(argv)) 4072685309fSrsc return -1; 4089d59eb01SAustin Clements if(fetchint(uargv+4*i, (int*)&uarg) < 0) 409f32f3638Srsc return -1; 410f32f3638Srsc if(uarg == 0){ 411f32f3638Srsc argv[i] = 0; 412f32f3638Srsc break; 4132685309fSrsc } 4149d59eb01SAustin Clements if(fetchstr(uarg, &argv[i]) < 0) 415f32f3638Srsc return -1; 416f32f3638Srsc } 417f32f3638Srsc return exec(path, argv); 418f32f3638Srsc } 419f32f3638Srsc 420eaea18cbSrsc int 421eaea18cbSrsc sys_pipe(void) 422eaea18cbSrsc { 423eaea18cbSrsc int *fd; 424eaea18cbSrsc struct file *rf, *wf; 425eaea18cbSrsc int fd0, fd1; 426eaea18cbSrsc 427eaea18cbSrsc if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) 428eaea18cbSrsc return -1; 4297834cca6Srsc if(pipealloc(&rf, &wf) < 0) 430eaea18cbSrsc return -1; 431eaea18cbSrsc fd0 = -1; 432eaea18cbSrsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 433eaea18cbSrsc if(fd0 >= 0) 43448755214SRuss Cox proc->ofile[fd0] = 0; 435eaea18cbSrsc fileclose(rf); 436eaea18cbSrsc fileclose(wf); 437eaea18cbSrsc return -1; 438eaea18cbSrsc } 439eaea18cbSrsc fd[0] = fd0; 440eaea18cbSrsc fd[1] = fd1; 441eaea18cbSrsc return 0; 442eaea18cbSrsc } 443