xv6

port of xv6 to x86-64
git clone http://frotz.net/git/xv6.git
Log | Files | Refs | README | LICENSE

sysfile.c (7183B)


      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   if((ip = namei(old)) == 0)
    124     return -1;
    125 
    126   begin_trans();
    127 
    128   ilock(ip);
    129   if(ip->type == T_DIR){
    130     iunlockput(ip);
    131     commit_trans();
    132     return -1;
    133   }
    134 
    135   ip->nlink++;
    136   iupdate(ip);
    137   iunlock(ip);
    138 
    139   if((dp = nameiparent(new, name)) == 0)
    140     goto bad;
    141   ilock(dp);
    142   if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
    143     iunlockput(dp);
    144     goto bad;
    145   }
    146   iunlockput(dp);
    147   iput(ip);
    148 
    149   commit_trans();
    150 
    151   return 0;
    152 
    153 bad:
    154   ilock(ip);
    155   ip->nlink--;
    156   iupdate(ip);
    157   iunlockput(ip);
    158   commit_trans();
    159   return -1;
    160 }
    161 
    162 // Is the directory dp empty except for "." and ".." ?
    163 static int
    164 isdirempty(struct inode *dp)
    165 {
    166   int off;
    167   struct dirent de;
    168 
    169   for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
    170     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
    171       panic("isdirempty: readi");
    172     if(de.inum != 0)
    173       return 0;
    174   }
    175   return 1;
    176 }
    177 
    178 //PAGEBREAK!
    179 int
    180 sys_unlink(void)
    181 {
    182   struct inode *ip, *dp;
    183   struct dirent de;
    184   char name[DIRSIZ], *path;
    185   uint off;
    186 
    187   if(argstr(0, &path) < 0)
    188     return -1;
    189   if((dp = nameiparent(path, name)) == 0)
    190     return -1;
    191 
    192   begin_trans();
    193 
    194   ilock(dp);
    195 
    196   // Cannot unlink "." or "..".
    197   if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
    198     goto bad;
    199 
    200   if((ip = dirlookup(dp, name, &off)) == 0)
    201     goto bad;
    202   ilock(ip);
    203 
    204   if(ip->nlink < 1)
    205     panic("unlink: nlink < 1");
    206   if(ip->type == T_DIR && !isdirempty(ip)){
    207     iunlockput(ip);
    208     goto bad;
    209   }
    210 
    211   memset(&de, 0, sizeof(de));
    212   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
    213     panic("unlink: writei");
    214   if(ip->type == T_DIR){
    215     dp->nlink--;
    216     iupdate(dp);
    217   }
    218   iunlockput(dp);
    219 
    220   ip->nlink--;
    221   iupdate(ip);
    222   iunlockput(ip);
    223 
    224   commit_trans();
    225 
    226   return 0;
    227 
    228 bad:
    229   iunlockput(dp);
    230   commit_trans();
    231   return -1;
    232 }
    233 
    234 static struct inode*
    235 create(char *path, short type, short major, short minor)
    236 {
    237   uint off;
    238   struct inode *ip, *dp;
    239   char name[DIRSIZ];
    240 
    241   if((dp = nameiparent(path, name)) == 0)
    242     return 0;
    243   ilock(dp);
    244 
    245   if((ip = dirlookup(dp, name, &off)) != 0){
    246     iunlockput(dp);
    247     ilock(ip);
    248     if(type == T_FILE && ip->type == T_FILE)
    249       return ip;
    250     iunlockput(ip);
    251     return 0;
    252   }
    253 
    254   if((ip = ialloc(dp->dev, type)) == 0)
    255     panic("create: ialloc");
    256 
    257   ilock(ip);
    258   ip->major = major;
    259   ip->minor = minor;
    260   ip->nlink = 1;
    261   iupdate(ip);
    262 
    263   if(type == T_DIR){  // Create . and .. entries.
    264     dp->nlink++;  // for ".."
    265     iupdate(dp);
    266     // No ip->nlink++ for ".": avoid cyclic ref count.
    267     if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
    268       panic("create dots");
    269   }
    270 
    271   if(dirlink(dp, name, ip->inum) < 0)
    272     panic("create: dirlink");
    273 
    274   iunlockput(dp);
    275 
    276   return ip;
    277 }
    278 
    279 int
    280 sys_open(void)
    281 {
    282   char *path;
    283   int fd, omode;
    284   struct file *f;
    285   struct inode *ip;
    286 
    287   if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
    288     return -1;
    289   if(omode & O_CREATE){
    290     begin_trans();
    291     ip = create(path, T_FILE, 0, 0);
    292     commit_trans();
    293     if(ip == 0)
    294       return -1;
    295   } else {
    296     if((ip = namei(path)) == 0)
    297       return -1;
    298     ilock(ip);
    299     if(ip->type == T_DIR && omode != O_RDONLY){
    300       iunlockput(ip);
    301       return -1;
    302     }
    303   }
    304 
    305   if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
    306     if(f)
    307       fileclose(f);
    308     iunlockput(ip);
    309     return -1;
    310   }
    311   iunlock(ip);
    312 
    313   f->type = FD_INODE;
    314   f->ip = ip;
    315   f->off = 0;
    316   f->readable = !(omode & O_WRONLY);
    317   f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
    318   return fd;
    319 }
    320 
    321 int
    322 sys_mkdir(void)
    323 {
    324   char *path;
    325   struct inode *ip;
    326 
    327   begin_trans();
    328   if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
    329     commit_trans();
    330     return -1;
    331   }
    332   iunlockput(ip);
    333   commit_trans();
    334   return 0;
    335 }
    336 
    337 int
    338 sys_mknod(void)
    339 {
    340   struct inode *ip;
    341   char *path;
    342   int len;
    343   int major, minor;
    344   
    345   begin_trans();
    346   if((len=argstr(0, &path)) < 0 ||
    347      argint(1, &major) < 0 ||
    348      argint(2, &minor) < 0 ||
    349      (ip = create(path, T_DEV, major, minor)) == 0){
    350     commit_trans();
    351     return -1;
    352   }
    353   iunlockput(ip);
    354   commit_trans();
    355   return 0;
    356 }
    357 
    358 int
    359 sys_chdir(void)
    360 {
    361   char *path;
    362   struct inode *ip;
    363 
    364   if(argstr(0, &path) < 0 || (ip = namei(path)) == 0)
    365     return -1;
    366   ilock(ip);
    367   if(ip->type != T_DIR){
    368     iunlockput(ip);
    369     return -1;
    370   }
    371   iunlock(ip);
    372   iput(proc->cwd);
    373   proc->cwd = ip;
    374   return 0;
    375 }
    376 
    377 int
    378 sys_exec(void)
    379 {
    380   char *path, *argv[MAXARG];
    381   int i;
    382   uintp uargv, uarg;
    383 
    384   if(argstr(0, &path) < 0 || arguintp(1, &uargv) < 0){
    385     return -1;
    386   }
    387   memset(argv, 0, sizeof(argv));
    388   for(i=0;; i++){
    389     if(i >= NELEM(argv))
    390       return -1;
    391     if(fetchuintp(uargv+sizeof(uintp)*i, &uarg) < 0)
    392       return -1;
    393     if(uarg == 0){
    394       argv[i] = 0;
    395       break;
    396     }
    397     if(fetchstr(uarg, &argv[i]) < 0)
    398       return -1;
    399   }
    400   return exec(path, argv);
    401 }
    402 
    403 int
    404 sys_pipe(void)
    405 {
    406   int *fd;
    407   struct file *rf, *wf;
    408   int fd0, fd1;
    409 
    410   if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
    411     return -1;
    412   if(pipealloc(&rf, &wf) < 0)
    413     return -1;
    414   fd0 = -1;
    415   if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
    416     if(fd0 >= 0)
    417       proc->ofile[fd0] = 0;
    418     fileclose(rf);
    419     fileclose(wf);
    420     return -1;
    421   }
    422   fd[0] = fd0;
    423   fd[1] = fd1;
    424   return 0;
    425 }