root/sysfile.c

/* [previous][next][first][last][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 "defs.h"
   9 #include "param.h"
  10 #include "stat.h"
  11 #include "mmu.h"
  12 #include "proc.h"
  13 #include "fs.h"
  14 #include "spinlock.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)
     /* [previous][next][first][last][top][bottom][index][help]  */
  23 {
  24   int fd;
  25   struct file *f;
  26 
  27   if(argint(n, &fd) < 0)
  28     return -1;
  29   if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
  30     return -1;
  31   if(pfd)
  32     *pfd = fd;
  33   if(pf)
  34     *pf = f;
  35   return 0;
  36 }
  37 
  38 // Allocate a file descriptor for the given file.
  39 // Takes over file reference from caller on success.
  40 static int
  41 fdalloc(struct file *f)
     /* [previous][next][first][last][top][bottom][index][help]  */
  42 {
  43   int fd;
  44   struct proc *curproc = myproc();
  45 
  46   for(fd = 0; fd < NOFILE; fd++){
  47     if(curproc->ofile[fd] == 0){
  48       curproc->ofile[fd] = f;
  49       return fd;
  50     }
  51   }
  52   return -1;
  53 }
  54 
  55 int
  56 sys_dup(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  57 {
  58   struct file *f;
  59   int fd;
  60 
  61   if(argfd(0, 0, &f) < 0)
  62     return -1;
  63   if((fd=fdalloc(f)) < 0)
  64     return -1;
  65   filedup(f);
  66   return fd;
  67 }
  68 
  69 int
  70 sys_read(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  71 {
  72   struct file *f;
  73   int n;
  74   char *p;
  75 
  76   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
  77     return -1;
  78   return fileread(f, p, n);
  79 }
  80 
  81 int
  82 sys_write(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  83 {
  84   struct file *f;
  85   int n;
  86   char *p;
  87 
  88   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
  89     return -1;
  90   return filewrite(f, p, n);
  91 }
  92 
  93 int
  94 sys_close(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  95 {
  96   int fd;
  97   struct file *f;
  98 
  99   if(argfd(0, &fd, &f) < 0)
 100     return -1;
 101   myproc()->ofile[fd] = 0;
 102   fileclose(f);
 103   return 0;
 104 }
 105 
 106 int
 107 sys_fstat(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 108 {
 109   struct file *f;
 110   struct stat *st;
 111 
 112   if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
 113     return -1;
 114   return filestat(f, st);
 115 }
 116 
 117 // Create the path new as a link to the same inode as old.
 118 int
 119 sys_link(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 120 {
 121   char name[DIRSIZ], *new, *old;
 122   struct inode *dp, *ip;
 123 
 124   if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
 125     return -1;
 126 
 127   begin_op();
 128   if((ip = namei(old)) == 0){
 129     end_op();
 130     return -1;
 131   }
 132 
 133   ilock(ip);
 134   if(ip->type == T_DIR){
 135     iunlockput(ip);
 136     end_op();
 137     return -1;
 138   }
 139 
 140   ip->nlink++;
 141   iupdate(ip);
 142   iunlock(ip);
 143 
 144   if((dp = nameiparent(new, name)) == 0)
 145     goto bad;
 146   ilock(dp);
 147   if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
 148     iunlockput(dp);
 149     goto bad;
 150   }
 151   iunlockput(dp);
 152   iput(ip);
 153 
 154   end_op();
 155 
 156   return 0;
 157 
 158 bad:
 159   ilock(ip);
 160   ip->nlink--;
 161   iupdate(ip);
 162   iunlockput(ip);
 163   end_op();
 164   return -1;
 165 }
 166 
 167 // Is the directory dp empty except for "." and ".." ?
 168 static int
 169 isdirempty(struct inode *dp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 170 {
 171   int off;
 172   struct dirent de;
 173 
 174   for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
 175     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
 176       panic("isdirempty: readi");
 177     if(de.inum != 0)
 178       return 0;
 179   }
 180   return 1;
 181 }
 182 
 183 //PAGEBREAK!
 184 int
 185 sys_unlink(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 186 {
 187   struct inode *ip, *dp;
 188   struct dirent de;
 189   char name[DIRSIZ], *path;
 190   uint off;
 191 
 192   if(argstr(0, &path) < 0)
 193     return -1;
 194 
 195   begin_op();
 196   if((dp = nameiparent(path, name)) == 0){
 197     end_op();
 198     return -1;
 199   }
 200 
 201   ilock(dp);
 202 
 203   // Cannot unlink "." or "..".
 204   if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
 205     goto bad;
 206 
 207   if((ip = dirlookup(dp, name, &off)) == 0)
 208     goto bad;
 209   ilock(ip);
 210 
 211   if(ip->nlink < 1)
 212     panic("unlink: nlink < 1");
 213   if(ip->type == T_DIR && !isdirempty(ip)){
 214     iunlockput(ip);
 215     goto bad;
 216   }
 217 
 218   memset(&de, 0, sizeof(de));
 219   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
 220     panic("unlink: writei");
 221   if(ip->type == T_DIR){
 222     dp->nlink--;
 223     iupdate(dp);
 224   }
 225   iunlockput(dp);
 226 
 227   ip->nlink--;
 228   iupdate(ip);
 229   iunlockput(ip);
 230 
 231   end_op();
 232 
 233   return 0;
 234 
 235 bad:
 236   iunlockput(dp);
 237   end_op();
 238   return -1;
 239 }
 240 
 241 static struct inode*
 242 create(char *path, short type, short major, short minor)
     /* [previous][next][first][last][top][bottom][index][help]  */
 243 {
 244   struct inode *ip, *dp;
 245   char name[DIRSIZ];
 246 
 247   if((dp = nameiparent(path, name)) == 0)
 248     return 0;
 249   ilock(dp);
 250 
 251   if((ip = dirlookup(dp, name, 0)) != 0){
 252     iunlockput(dp);
 253     ilock(ip);
 254     if(type == T_FILE && ip->type == T_FILE)
 255       return ip;
 256     iunlockput(ip);
 257     return 0;
 258   }
 259 
 260   if((ip = ialloc(dp->dev, type)) == 0)
 261     panic("create: ialloc");
 262 
 263   ilock(ip);
 264   ip->major = major;
 265   ip->minor = minor;
 266   ip->nlink = 1;
 267   iupdate(ip);
 268 
 269   if(type == T_DIR){  // Create . and .. entries.
 270     dp->nlink++;  // for ".."
 271     iupdate(dp);
 272     // No ip->nlink++ for ".": avoid cyclic ref count.
 273     if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
 274       panic("create dots");
 275   }
 276 
 277   if(dirlink(dp, name, ip->inum) < 0)
 278     panic("create: dirlink");
 279 
 280   iunlockput(dp);
 281 
 282   return ip;
 283 }
 284 
 285 int
 286 sys_open(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 287 {
 288   char *path;
 289   int fd, omode;
 290   struct file *f;
 291   struct inode *ip;
 292 
 293   if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
 294     return -1;
 295 
 296   begin_op();
 297 
 298   if(omode & O_CREATE){
 299     ip = create(path, T_FILE, 0, 0);
 300     if(ip == 0){
 301       end_op();
 302       return -1;
 303     }
 304   } else {
 305     if((ip = namei(path)) == 0){
 306       end_op();
 307       return -1;
 308     }
 309     ilock(ip);
 310     if(ip->type == T_DIR && omode != O_RDONLY){
 311       iunlockput(ip);
 312       end_op();
 313       return -1;
 314     }
 315   }
 316 
 317   if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
 318     if(f)
 319       fileclose(f);
 320     iunlockput(ip);
 321     end_op();
 322     return -1;
 323   }
 324   iunlock(ip);
 325   end_op();
 326 
 327   f->type = FD_INODE;
 328   f->ip = ip;
 329   f->off = 0;
 330   f->readable = !(omode & O_WRONLY);
 331   f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
 332   return fd;
 333 }
 334 
 335 int
 336 sys_mkdir(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 337 {
 338   char *path;
 339   struct inode *ip;
 340 
 341   begin_op();
 342   if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
 343     end_op();
 344     return -1;
 345   }
 346   iunlockput(ip);
 347   end_op();
 348   return 0;
 349 }
 350 
 351 int
 352 sys_mknod(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 353 {
 354   struct inode *ip;
 355   char *path;
 356   int major, minor;
 357 
 358   begin_op();
 359   if((argstr(0, &path)) < 0 ||
 360      argint(1, &major) < 0 ||
 361      argint(2, &minor) < 0 ||
 362      (ip = create(path, T_DEV, major, minor)) == 0){
 363     end_op();
 364     return -1;
 365   }
 366   iunlockput(ip);
 367   end_op();
 368   return 0;
 369 }
 370 
 371 int
 372 sys_chdir(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 373 {
 374   char *path;
 375   struct inode *ip;
 376   struct proc *curproc = myproc();
 377   
 378   begin_op();
 379   if(argstr(0, &path) < 0 || (ip = namei(path)) == 0){
 380     end_op();
 381     return -1;
 382   }
 383   ilock(ip);
 384   if(ip->type != T_DIR){
 385     iunlockput(ip);
 386     end_op();
 387     return -1;
 388   }
 389   iunlock(ip);
 390   iput(curproc->cwd);
 391   end_op();
 392   curproc->cwd = ip;
 393   return 0;
 394 }
 395 
 396 int
 397 sys_exec(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 398 {
 399   char *path, *argv[MAXARG];
 400   int i;
 401   uint uargv, uarg;
 402 
 403   if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){
 404     return -1;
 405   }
 406   memset(argv, 0, sizeof(argv));
 407   for(i=0;; i++){
 408     if(i >= NELEM(argv))
 409       return -1;
 410     if(fetchint(uargv+4*i, (int*)&uarg) < 0)
 411       return -1;
 412     if(uarg == 0){
 413       argv[i] = 0;
 414       break;
 415     }
 416     if(fetchstr(uarg, &argv[i]) < 0)
 417       return -1;
 418   }
 419   return exec(path, argv);
 420 }
 421 
 422 int
 423 sys_pipe(void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 424 {
 425   int *fd;
 426   struct file *rf, *wf;
 427   int fd0, fd1;
 428 
 429   if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
 430     return -1;
 431   if(pipealloc(&rf, &wf) < 0)
 432     return -1;
 433   fd0 = -1;
 434   if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
 435     if(fd0 >= 0)
 436       myproc()->ofile[fd0] = 0;
 437     fileclose(rf);
 438     fileclose(wf);
 439     return -1;
 440   }
 441   fd[0] = fd0;
 442   fd[1] = fd1;
 443   return 0;
 444 }

/* [previous][next][first][last][top][bottom][index][help]  */