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

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