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   if (ip->nlink >= NLINK_MAX) {
 146     iunlockput(ip);
 147     end_op();
 148     return -1;
 149   }
 150 
 151   ip->nlink++;
 152   iupdate(ip);
 153   iunlock(ip);
 154 
 155   if ((dp = nameiparent(new, name)) == 0)
 156     goto bad;
 157   ilock(dp);
 158   // dp may have been unlinked while we resolved it; linking into an
 159   // orphaned directory leaks ip (itrunc discards the record without
 160   // dropping ip->nlink).  create() has the same guard.
 161   if (dp->nlink == 0) {
 162     iunlockput(dp);
 163     goto bad;
 164   }
 165   if (dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0) {
 166     iunlockput(dp);
 167     goto bad;
 168   }
 169   iunlockput(dp);
 170   iput(ip);
 171 
 172   end_op();
 173 
 174   return 0;
 175 
 176 bad:
 177   ilock(ip);
 178   ip->nlink--;
 179   iupdate(ip);
 180   iunlockput(ip);
 181   end_op();
 182   return -1;
 183 }
 184 
 185 // Is the directory dp empty except for "." and ".." ?
 186 static int
 187 isdirempty(struct inode *dp)
 188 {
 189   int off;
 190   struct dirent de;
 191 
 192   for (off = 2 * sizeof(de); off < dp->size; off += sizeof(de)) {
 193     if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
 194       panic("isdirempty: readi");
 195     if (de.inum != 0)
 196       return 0;
 197   }
 198   return 1;
 199 }
 200 
 201 uint64
 202 sys_unlink(void)
 203 {
 204   struct inode *ip, *dp;
 205   struct dirent de;
 206   char name[DIRSIZ], path[MAXPATH];
 207   uint off;
 208 
 209   if (argstr(0, path, MAXPATH) < 0)
 210     return -1;
 211 
 212   begin_op();
 213   if ((dp = nameiparent(path, name)) == 0) {
 214     end_op();
 215     return -1;
 216   }
 217 
 218   ilock(dp);
 219 
 220   // Cannot unlink "." or "..".
 221   if (namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
 222     goto bad;
 223 
 224   if ((ip = dirlookup(dp, name, &off)) == 0)
 225     goto bad;
 226   ilock(ip);
 227 
 228   if (ip->nlink < 1)
 229     panic("unlink: nlink < 1");
 230   if (ip->type == T_DIR && !isdirempty(ip)) {
 231     iunlockput(ip);
 232     goto bad;
 233   }
 234 
 235   memset(&de, 0, sizeof(de));
 236   if (writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
 237     panic("unlink: writei");
 238   if (ip->type == T_DIR) {
 239     dp->nlink--;
 240     iupdate(dp);
 241   }
 242   iunlockput(dp);
 243 
 244   ip->nlink--;
 245   iupdate(ip);
 246   iunlockput(ip);
 247 
 248   end_op();
 249 
 250   return 0;
 251 
 252 bad:
 253   iunlockput(dp);
 254   end_op();
 255   return -1;
 256 }
 257 
 258 static struct inode *
 259 create(char *path, short type, short major, short minor)
 260 {
 261   struct inode *ip, *dp;
 262   char name[DIRSIZ];
 263 
 264   if ((dp = nameiparent(path, name)) == 0)
 265     return 0;
 266 
 267   ilock(dp);
 268 
 269   if (dp->nlink == 0) {
 270     iunlockput(dp);
 271     return 0;
 272   }
 273 
 274   // a new directory's ".." would push dp->nlink past its maximum
 275   if (type == T_DIR && dp->nlink >= NLINK_MAX) {
 276     iunlockput(dp);
 277     return 0;
 278   }
 279 
 280   if ((ip = dirlookup(dp, name, 0)) != 0) {
 281     iunlockput(dp);
 282     ilock(ip);
 283     if (type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
 284       return ip;
 285     iunlockput(ip);
 286     return 0;
 287   }
 288 
 289   if ((ip = ialloc(dp->dev, type)) == 0) {
 290     iunlockput(dp);
 291     return 0;
 292   }
 293 
 294   ilock(ip);
 295   ip->major = major;
 296   ip->minor = minor;
 297   ip->nlink = 1;
 298   iupdate(ip);
 299 
 300   if (type == T_DIR) { // Create . and .. entries.
 301     // No ip->nlink++ for ".": avoid cyclic ref count.
 302     if (dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
 303       goto fail;
 304   }
 305 
 306   if (dirlink(dp, name, ip->inum) < 0)
 307     goto fail;
 308 
 309   if (type == T_DIR) {
 310     // now that success is guaranteed:
 311     dp->nlink++; // for ".."
 312     iupdate(dp);
 313   }
 314 
 315   iunlockput(dp);
 316 
 317   return ip;
 318 
 319 fail:
 320   // something went wrong. de-allocate ip.
 321   ip->nlink = 0;
 322   iupdate(ip);
 323   iunlockput(ip);
 324   iunlockput(dp);
 325   return 0;
 326 }
 327 
 328 uint64
 329 sys_open(void)
 330 {
 331   char path[MAXPATH];
 332   int fd, omode;
 333   struct file *f;
 334   struct inode *ip;
 335   int n;
 336 
 337   argint(1, &omode);
 338   if ((n = argstr(0, path, MAXPATH)) < 0)
 339     return -1;
 340 
 341   begin_op();
 342 
 343   if (omode & O_CREATE) {
 344     ip = create(path, T_FILE, 0, 0);
 345     if (ip == 0) {
 346       end_op();
 347       return -1;
 348     }
 349   } else {
 350     if ((ip = namei(path)) == 0) {
 351       end_op();
 352       return -1;
 353     }
 354     ilock(ip);
 355     if (ip->type == T_DIR && omode != O_RDONLY) {
 356       iunlockput(ip);
 357       end_op();
 358       return -1;
 359     }
 360   }
 361 
 362   if (ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)) {
 363     iunlockput(ip);
 364     end_op();
 365     return -1;
 366   }
 367 
 368   if ((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0) {
 369     if (f)
 370       fileclose(f);
 371     iunlockput(ip);
 372     end_op();
 373     return -1;
 374   }
 375 
 376   if (ip->type == T_DEVICE) {
 377     f->type = FD_DEVICE;
 378     f->major = ip->major;
 379   } else {
 380     f->type = FD_INODE;
 381     f->off = 0;
 382   }
 383   f->ip = ip;
 384   f->readable = !(omode & O_WRONLY);
 385   f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
 386 
 387   if ((omode & O_TRUNC) && ip->type == T_FILE) {
 388     itrunc(ip);
 389   }
 390 
 391   iunlock(ip);
 392   end_op();
 393 
 394   return fd;
 395 }
 396 
 397 uint64
 398 sys_mkdir(void)
 399 {
 400   char path[MAXPATH];
 401   struct inode *ip;
 402 
 403   begin_op();
 404   if (argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0) {
 405     end_op();
 406     return -1;
 407   }
 408   iunlockput(ip);
 409   end_op();
 410   return 0;
 411 }
 412 
 413 uint64
 414 sys_mknod(void)
 415 {
 416   struct inode *ip;
 417   char path[MAXPATH];
 418   int major, minor;
 419 
 420   begin_op();
 421   argint(1, &major);
 422   argint(2, &minor);
 423   if ((argstr(0, path, MAXPATH)) < 0 ||
 424       (ip = create(path, T_DEVICE, major, minor)) == 0) {
 425     end_op();
 426     return -1;
 427   }
 428   iunlockput(ip);
 429   end_op();
 430   return 0;
 431 }
 432 
 433 uint64
 434 sys_chdir(void)
 435 {
 436   char path[MAXPATH];
 437   struct inode *ip;
 438   struct proc *p = myproc();
 439 
 440   begin_op();
 441   if (argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0) {
 442     end_op();
 443     return -1;
 444   }
 445   ilock(ip);
 446   if (ip->type != T_DIR) {
 447     iunlockput(ip);
 448     end_op();
 449     return -1;
 450   }
 451   iunlock(ip);
 452   iput(p->cwd);
 453   end_op();
 454   p->cwd = ip;
 455   return 0;
 456 }
 457 
 458 uint64
 459 sys_exec(void)
 460 {
 461   char path[MAXPATH], *argv[MAXARG];
 462   int i;
 463   uint64 uargv, uarg;
 464 
 465   argaddr(1, &uargv);
 466   if (argstr(0, path, MAXPATH) < 0) {
 467     return -1;
 468   }
 469   memset(argv, 0, sizeof(argv));
 470   for (i = 0;; i++) {
 471     if (i >= NELEM(argv)) {
 472       goto bad;
 473     }
 474     if (fetchaddr(uargv + sizeof(uint64) * i, (uint64 *)&uarg) < 0) {
 475       goto bad;
 476     }
 477     if (uarg == 0) {
 478       argv[i] = 0;
 479       break;
 480     }
 481     argv[i] = kalloc();
 482     if (argv[i] == 0)
 483       goto bad;
 484     if (fetchstr(uarg, argv[i], PGSIZE) < 0)
 485       goto bad;
 486   }
 487 
 488   int ret = kexec(path, argv);
 489 
 490   for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
 491     kfree(argv[i]);
 492 
 493   return ret;
 494 
 495 bad:
 496   for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
 497     kfree(argv[i]);
 498   return -1;
 499 }
 500 
 501 uint64
 502 sys_pipe(void)
 503 {
 504   uint64 fdarray; // user pointer to array of two integers
 505   struct file *rf, *wf;
 506   int fd0, fd1;
 507   struct proc *p = myproc();
 508 
 509   argaddr(0, &fdarray);
 510   if (pipealloc(&rf, &wf) < 0)
 511     return -1;
 512   fd0 = -1;
 513   if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) {
 514     if (fd0 >= 0)
 515       p->ofile[fd0] = 0;
 516     fileclose(rf);
 517     fileclose(wf);
 518     return -1;
 519   }
 520   if (copyout(p->pagetable, p->sz, fdarray, (char *)&fd0, sizeof(fd0)) < 0 ||
 521       copyout(p->pagetable, p->sz, fdarray + sizeof(fd0), (char *)&fd1,
 522               sizeof(fd1)) < 0) {
 523     p->ofile[fd0] = 0;
 524     p->ofile[fd1] = 0;
 525     fileclose(rf);
 526     fileclose(wf);
 527     return -1;
 528   }
 529   return 0;
 530 }

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