root/kernel/sysfile.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. argfd
  2. fdalloc
  3. sys_dup
  4. sys_read
  5. sys_write
  6. sys_close
  7. sys_fstat
  8. sys_link
  9. isdirempty
  10. sys_unlink
  11. create
  12. sys_open
  13. sys_mkdir
  14. sys_mknod
  15. sys_chdir
  16. sys_exec
  17. sys_pipe

   1 //
   2 // File-system system calls.
   3 // Mostly argument checking, since we don't trust
   4 // user code, and calls into file.c and fs.c.
   5 //
   6 
   7 #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"
  18 
  19 // Fetch the nth word-sized system call argument as a file descriptor
  20 // and return both the descriptor and the corresponding struct file.
  21 static int
  22 argfd(int n, int *pfd, struct file **pf)
  23 {
  24   int fd;
  25   struct file *f;
  26 
  27   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 }
  36 
  37 // Allocate a file descriptor for the given file.
  38 // Takes over file reference from caller on success.
  39 static int
  40 fdalloc(struct file *f)
  41 {
  42   int fd;
  43   struct proc *p = myproc();
  44 
  45   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 }
  53 
  54 uint64
  55 sys_dup(void)
  56 {
  57   struct file *f;
  58   int fd;
  59 
  60   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 }
  67 
  68 uint64
  69 sys_read(void)
  70 {
  71   struct file *f;
  72   int n;
  73   uint64 p;
  74 
  75   argaddr(1, &p);
  76   argint(2, &n);
  77   if(argfd(0, 0, &f) < 0)
  78     return -1;
  79   return fileread(f, p, n);
  80 }
  81 
  82 uint64
  83 sys_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;
  93 
  94   return filewrite(f, p, n);
  95 }
  96 
  97 uint64
  98 sys_close(void)
  99 {
 100   int fd;
 101   struct file *f;
 102 
 103   if(argfd(0, &fd, &f) < 0)
 104     return -1;
 105   myproc()->ofile[fd] = 0;
 106   fileclose(f);
 107   return 0;
 108 }
 109 
 110 uint64
 111 sys_fstat(void)
 112 {
 113   struct file *f;
 114   uint64 st; // user pointer to struct stat
 115 
 116   argaddr(1, &st);
 117   if(argfd(0, 0, &f) < 0)
 118     return -1;
 119   return filestat(f, st);
 120 }
 121 
 122 // Create the path new as a link to the same inode as old.
 123 uint64
 124 sys_link(void)
 125 {
 126   char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
 127   struct inode *dp, *ip;
 128 
 129   if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
 130     return -1;
 131 
 132   begin_op();
 133   if((ip = namei(old)) == 0){
 134     end_op();
 135     return -1;
 136   }
 137 
 138   ilock(ip);
 139   if(ip->type == T_DIR){
 140     iunlockput(ip);
 141     end_op();
 142     return -1;
 143   }
 144 
 145   ip->nlink++;
 146   iupdate(ip);
 147   iunlock(ip);
 148 
 149   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);
 158 
 159   end_op();
 160 
 161   return 0;
 162 
 163 bad:
 164   ilock(ip);
 165   ip->nlink--;
 166   iupdate(ip);
 167   iunlockput(ip);
 168   end_op();
 169   return -1;
 170 }
 171 
 172 // Is the directory dp empty except for "." and ".." ?
 173 static int
 174 isdirempty(struct inode *dp)
 175 {
 176   int off;
 177   struct dirent de;
 178 
 179   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 }
 187 
 188 uint64
 189 sys_unlink(void)
 190 {
 191   struct inode *ip, *dp;
 192   struct dirent de;
 193   char name[DIRSIZ], path[MAXPATH];
 194   uint off;
 195 
 196   if(argstr(0, path, MAXPATH) < 0)
 197     return -1;
 198 
 199   begin_op();
 200   if((dp = nameiparent(path, name)) == 0){
 201     end_op();
 202     return -1;
 203   }
 204 
 205   ilock(dp);
 206 
 207   // Cannot unlink "." or "..".
 208   if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
 209     goto bad;
 210 
 211   if((ip = dirlookup(dp, name, &off)) == 0)
 212     goto bad;
 213   ilock(ip);
 214 
 215   if(ip->nlink < 1)
 216     panic("unlink: nlink < 1");
 217   if(ip->type == T_DIR && !isdirempty(ip)){
 218     iunlockput(ip);
 219     goto bad;
 220   }
 221 
 222   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);
 230 
 231   ip->nlink--;
 232   iupdate(ip);
 233   iunlockput(ip);
 234 
 235   end_op();
 236 
 237   return 0;
 238 
 239 bad:
 240   iunlockput(dp);
 241   end_op();
 242   return -1;
 243 }
 244 
 245 static struct inode*
 246 create(char *path, short type, short major, short minor)
 247 {
 248   struct inode *ip, *dp;
 249   char name[DIRSIZ];
 250 
 251   if((dp = nameiparent(path, name)) == 0)
 252     return 0;
 253 
 254   ilock(dp);
 255 
 256   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   }
 264 
 265   if((ip = ialloc(dp->dev, type)) == 0){
 266     iunlockput(dp);
 267     return 0;
 268   }
 269 
 270   ilock(ip);
 271   ip->major = major;
 272   ip->minor = minor;
 273   ip->nlink = 1;
 274   iupdate(ip);
 275 
 276   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   }
 281 
 282   if(dirlink(dp, name, ip->inum) < 0)
 283     goto fail;
 284 
 285   if(type == T_DIR){
 286     // now that success is guaranteed:
 287     dp->nlink++;  // for ".."
 288     iupdate(dp);
 289   }
 290 
 291   iunlockput(dp);
 292 
 293   return ip;
 294 
 295  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 }
 303 
 304 uint64
 305 sys_open(void)
 306 {
 307   char path[MAXPATH];
 308   int fd, omode;
 309   struct file *f;
 310   struct inode *ip;
 311   int n;
 312 
 313   argint(1, &omode);
 314   if((n = argstr(0, path, MAXPATH)) < 0)
 315     return -1;
 316 
 317   begin_op();
 318 
 319   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   }
 337 
 338   if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
 339     iunlockput(ip);
 340     end_op();
 341     return -1;
 342   }
 343 
 344   if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
 345     if(f)
 346       fileclose(f);
 347     iunlockput(ip);
 348     end_op();
 349     return -1;
 350   }
 351 
 352   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);
 362 
 363   if((omode & O_TRUNC) && ip->type == T_FILE){
 364     itrunc(ip);
 365   }
 366 
 367   iunlock(ip);
 368   end_op();
 369 
 370   return fd;
 371 }
 372 
 373 uint64
 374 sys_mkdir(void)
 375 {
 376   char path[MAXPATH];
 377   struct inode *ip;
 378 
 379   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 }
 388 
 389 uint64
 390 sys_mknod(void)
 391 {
 392   struct inode *ip;
 393   char path[MAXPATH];
 394   int major, minor;
 395 
 396   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 }
 408 
 409 uint64
 410 sys_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 }
 433 
 434 uint64
 435 sys_exec(void)
 436 {
 437   char path[MAXPATH], *argv[MAXARG];
 438   int i;
 439   uint64 uargv, uarg;
 440 
 441   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   }
 463 
 464   int ret = exec(path, argv);
 465 
 466   for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
 467     kfree(argv[i]);
 468 
 469   return ret;
 470 
 471  bad:
 472   for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
 473     kfree(argv[i]);
 474   return -1;
 475 }
 476 
 477 uint64
 478 sys_pipe(void)
 479 {
 480   uint64 fdarray; // user pointer to array of two integers
 481   struct file *rf, *wf;
 482   int fd0, fd1;
 483   struct proc *p = myproc();
 484 
 485   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 }

/* [<][>][^][v][top][bottom][index][help] */