kernel/sysfile.c
505 lines
1//2// File-system system calls.3// Mostly argument checking, since we don't trust4// user code, and calls into file.c and fs.c.5//67#include "types.h"8#include "riscv.h"9#include "defs.h"10#include "param.h"11#include "stat.h"12#include "spinlock.h"13#include "proc.h"14#include "fs.h"15#include "sleeplock.h"16#include "file.h"17#include "fcntl.h"1819// Fetch the nth word-sized system call argument as a file descriptor20// and return both the descriptor and the corresponding struct file.21static int22argfd(int n, int *pfd, struct file **pf)23{24 int fd;25 struct file *f;2627 argint(n, &fd);28 if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)29 return -1;30 if(pfd)31 *pfd = fd;32 if(pf)33 *pf = f;34 return 0;35}3637// Allocate a file descriptor for the given file.38// Takes over file reference from caller on success.39static int40fdalloc(struct file *f)41{42 int fd;43 struct proc *p = myproc();4445 for(fd = 0; fd < NOFILE; fd++){46 if(p->ofile[fd] == 0){47 p->ofile[fd] = f;48 return fd;49 }50 }51 return -1;52}5354uint6455sys_dup(void)56{57 struct file *f;58 int fd;5960 if(argfd(0, 0, &f) < 0)61 return -1;62 if((fd=fdalloc(f)) < 0)63 return -1;64 filedup(f);65 return fd;66}6768uint6469sys_read(void)70{71 struct file *f;72 int n;73 uint64 p;7475 argaddr(1, &p);76 argint(2, &n);77 if(argfd(0, 0, &f) < 0)78 return -1;79 return fileread(f, p, n);80}8182uint6483sys_write(void)84{85 struct file *f;86 int n;87 uint64 p;88 89 argaddr(1, &p);90 argint(2, &n);91 if(argfd(0, 0, &f) < 0)92 return -1;9394 return filewrite(f, p, n);95}9697uint6498sys_close(void)99{100 int fd;101 struct file *f;102103 if(argfd(0, &fd, &f) < 0)104 return -1;105 myproc()->ofile[fd] = 0;106 fileclose(f);107 return 0;108}109110uint64111sys_fstat(void)112{113 struct file *f;114 uint64 st; // user pointer to struct stat115116 argaddr(1, &st);117 if(argfd(0, 0, &f) < 0)118 return -1;119 return filestat(f, st);120}121122// Create the path new as a link to the same inode as old.123uint64124sys_link(void)125{126 char name[DIRSIZ], new[MAXPATH], old[MAXPATH];127 struct inode *dp, *ip;128129 if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)130 return -1;131132 begin_op();133 if((ip = namei(old)) == 0){134 end_op();135 return -1;136 }137138 ilock(ip);139 if(ip->type == T_DIR){140 iunlockput(ip);141 end_op();142 return -1;143 }144145 ip->nlink++;146 iupdate(ip);147 iunlock(ip);148149 if((dp = nameiparent(new, name)) == 0)150 goto bad;151 ilock(dp);152 if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){153 iunlockput(dp);154 goto bad;155 }156 iunlockput(dp);157 iput(ip);158159 end_op();160161 return 0;162163bad:164 ilock(ip);165 ip->nlink--;166 iupdate(ip);167 iunlockput(ip);168 end_op();169 return -1;170}171172// Is the directory dp empty except for "." and ".." ?173static int174isdirempty(struct inode *dp)175{176 int off;177 struct dirent de;178179 for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){180 if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))181 panic("isdirempty: readi");182 if(de.inum != 0)183 return 0;184 }185 return 1;186}187188uint64189sys_unlink(void)190{191 struct inode *ip, *dp;192 struct dirent de;193 char name[DIRSIZ], path[MAXPATH];194 uint off;195196 if(argstr(0, path, MAXPATH) < 0)197 return -1;198199 begin_op();200 if((dp = nameiparent(path, name)) == 0){201 end_op();202 return -1;203 }204205 ilock(dp);206207 // Cannot unlink "." or "..".208 if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)209 goto bad;210211 if((ip = dirlookup(dp, name, &off)) == 0)212 goto bad;213 ilock(ip);214215 if(ip->nlink < 1)216 panic("unlink: nlink < 1");217 if(ip->type == T_DIR && !isdirempty(ip)){218 iunlockput(ip);219 goto bad;220 }221222 memset(&de, 0, sizeof(de));223 if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))224 panic("unlink: writei");225 if(ip->type == T_DIR){226 dp->nlink--;227 iupdate(dp);228 }229 iunlockput(dp);230231 ip->nlink--;232 iupdate(ip);233 iunlockput(ip);234235 end_op();236237 return 0;238239bad:240 iunlockput(dp);241 end_op();242 return -1;243}244245static struct inode*246create(char *path, short type, short major, short minor)247{248 struct inode *ip, *dp;249 char name[DIRSIZ];250251 if((dp = nameiparent(path, name)) == 0)252 return 0;253254 ilock(dp);255256 if((ip = dirlookup(dp, name, 0)) != 0){257 iunlockput(dp);258 ilock(ip);259 if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))260 return ip;261 iunlockput(ip);262 return 0;263 }264265 if((ip = ialloc(dp->dev, type)) == 0){266 iunlockput(dp);267 return 0;268 }269270 ilock(ip);271 ip->major = major;272 ip->minor = minor;273 ip->nlink = 1;274 iupdate(ip);275276 if(type == T_DIR){ // Create . and .. entries.277 // No ip->nlink++ for ".": avoid cyclic ref count.278 if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)279 goto fail;280 }281282 if(dirlink(dp, name, ip->inum) < 0)283 goto fail;284285 if(type == T_DIR){286 // now that success is guaranteed:287 dp->nlink++; // for ".."288 iupdate(dp);289 }290291 iunlockput(dp);292293 return ip;294295 fail:296 // something went wrong. de-allocate ip.297 ip->nlink = 0;298 iupdate(ip);299 iunlockput(ip);300 iunlockput(dp);301 return 0;302}303304uint64305sys_open(void)306{307 char path[MAXPATH];308 int fd, omode;309 struct file *f;310 struct inode *ip;311 int n;312313 argint(1, &omode);314 if((n = argstr(0, path, MAXPATH)) < 0)315 return -1;316317 begin_op();318319 if(omode & O_CREATE){320 ip = create(path, T_FILE, 0, 0);321 if(ip == 0){322 end_op();323 return -1;324 }325 } else {326 if((ip = namei(path)) == 0){327 end_op();328 return -1;329 }330 ilock(ip);331 if(ip->type == T_DIR && omode != O_RDONLY){332 iunlockput(ip);333 end_op();334 return -1;335 }336 }337338 if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){339 iunlockput(ip);340 end_op();341 return -1;342 }343344 if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){345 if(f)346 fileclose(f);347 iunlockput(ip);348 end_op();349 return -1;350 }351352 if(ip->type == T_DEVICE){353 f->type = FD_DEVICE;354 f->major = ip->major;355 } else {356 f->type = FD_INODE;357 f->off = 0;358 }359 f->ip = ip;360 f->readable = !(omode & O_WRONLY);361 f->writable = (omode & O_WRONLY) || (omode & O_RDWR);362363 if((omode & O_TRUNC) && ip->type == T_FILE){364 itrunc(ip);365 }366367 iunlock(ip);368 end_op();369370 return fd;371}372373uint64374sys_mkdir(void)375{376 char path[MAXPATH];377 struct inode *ip;378379 begin_op();380 if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){381 end_op();382 return -1;383 }384 iunlockput(ip);385 end_op();386 return 0;387}388389uint64390sys_mknod(void)391{392 struct inode *ip;393 char path[MAXPATH];394 int major, minor;395396 begin_op();397 argint(1, &major);398 argint(2, &minor);399 if((argstr(0, path, MAXPATH)) < 0 ||400 (ip = create(path, T_DEVICE, major, minor)) == 0){401 end_op();402 return -1;403 }404 iunlockput(ip);405 end_op();406 return 0;407}408409uint64410sys_chdir(void)411{412 char path[MAXPATH];413 struct inode *ip;414 struct proc *p = myproc();415 416 begin_op();417 if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){418 end_op();419 return -1;420 }421 ilock(ip);422 if(ip->type != T_DIR){423 iunlockput(ip);424 end_op();425 return -1;426 }427 iunlock(ip);428 iput(p->cwd);429 end_op();430 p->cwd = ip;431 return 0;432}433434uint64435sys_exec(void)436{437 char path[MAXPATH], *argv[MAXARG];438 int i;439 uint64 uargv, uarg;440441 argaddr(1, &uargv);442 if(argstr(0, path, MAXPATH) < 0) {443 return -1;444 }445 memset(argv, 0, sizeof(argv));446 for(i=0;; i++){447 if(i >= NELEM(argv)){448 goto bad;449 }450 if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){451 goto bad;452 }453 if(uarg == 0){454 argv[i] = 0;455 break;456 }457 argv[i] = kalloc();458 if(argv[i] == 0)459 goto bad;460 if(fetchstr(uarg, argv[i], PGSIZE) < 0)461 goto bad;462 }463464 int ret = kexec(path, argv);465466 for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)467 kfree(argv[i]);468469 return ret;470471 bad:472 for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)473 kfree(argv[i]);474 return -1;475}476477uint64478sys_pipe(void)479{480 uint64 fdarray; // user pointer to array of two integers481 struct file *rf, *wf;482 int fd0, fd1;483 struct proc *p = myproc();484485 argaddr(0, &fdarray);486 if(pipealloc(&rf, &wf) < 0)487 return -1;488 fd0 = -1;489 if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){490 if(fd0 >= 0)491 p->ofile[fd0] = 0;492 fileclose(rf);493 fileclose(wf);494 return -1;495 }496 if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||497 copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){498 p->ofile[fd0] = 0;499 p->ofile[fd1] = 0;500 fileclose(rf);501 fileclose(wf);502 return -1;503 }504 return 0;505}506