root/kernel/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. fileinit
  2. filealloc
  3. filedup
  4. fileclose
  5. filestat
  6. fileread
  7. filewrite

   1 //
   2 // Support functions for system calls that involve file descriptors.
   3 //
   4 
   5 #include "types.h"
   6 #include "riscv.h"
   7 #include "defs.h"
   8 #include "param.h"
   9 #include "fs.h"
  10 #include "spinlock.h"
  11 #include "sleeplock.h"
  12 #include "file.h"
  13 #include "stat.h"
  14 #include "proc.h"
  15 
  16 struct devsw devsw[NDEV];
  17 struct {
  18   struct spinlock lock;
  19   struct file file[NFILE];
  20 } ftable;
  21 
  22 void
  23 fileinit(void)
  24 {
  25   initlock(&ftable.lock, "ftable");
  26 }
  27 
  28 // Allocate a file structure.
  29 struct file*
  30 filealloc(void)
  31 {
  32   struct file *f;
  33 
  34   acquire(&ftable.lock);
  35   for(f = ftable.file; f < ftable.file + NFILE; f++){
  36     if(f->ref == 0){
  37       f->ref = 1;
  38       release(&ftable.lock);
  39       return f;
  40     }
  41   }
  42   release(&ftable.lock);
  43   return 0;
  44 }
  45 
  46 // Increment ref count for file f.
  47 struct file*
  48 filedup(struct file *f)
  49 {
  50   acquire(&ftable.lock);
  51   if(f->ref < 1)
  52     panic("filedup");
  53   f->ref++;
  54   release(&ftable.lock);
  55   return f;
  56 }
  57 
  58 // Close file f.  (Decrement ref count, close when reaches 0.)
  59 void
  60 fileclose(struct file *f)
  61 {
  62   struct file ff;
  63 
  64   acquire(&ftable.lock);
  65   if(f->ref < 1)
  66     panic("fileclose");
  67   if(--f->ref > 0){
  68     release(&ftable.lock);
  69     return;
  70   }
  71   ff = *f;
  72   f->ref = 0;
  73   f->type = FD_NONE;
  74   release(&ftable.lock);
  75 
  76   if(ff.type == FD_PIPE){
  77     pipeclose(ff.pipe, ff.writable);
  78   } else if(ff.type == FD_INODE || ff.type == FD_DEVICE){
  79     begin_op();
  80     iput(ff.ip);
  81     end_op();
  82   }
  83 }
  84 
  85 // Get metadata about file f.
  86 // addr is a user virtual address, pointing to a struct stat.
  87 int
  88 filestat(struct file *f, uint64 addr)
  89 {
  90   struct proc *p = myproc();
  91   struct stat st;
  92   
  93   if(f->type == FD_INODE || f->type == FD_DEVICE){
  94     ilock(f->ip);
  95     stati(f->ip, &st);
  96     iunlock(f->ip);
  97     if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
  98       return -1;
  99     return 0;
 100   }
 101   return -1;
 102 }
 103 
 104 // Read from file f.
 105 // addr is a user virtual address.
 106 int
 107 fileread(struct file *f, uint64 addr, int n)
 108 {
 109   int r = 0;
 110 
 111   if(f->readable == 0)
 112     return -1;
 113 
 114   if(f->type == FD_PIPE){
 115     r = piperead(f->pipe, addr, n);
 116   } else if(f->type == FD_DEVICE){
 117     if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
 118       return -1;
 119     r = devsw[f->major].read(1, addr, n);
 120   } else if(f->type == FD_INODE){
 121     ilock(f->ip);
 122     if((r = readi(f->ip, 1, addr, f->off, n)) > 0)
 123       f->off += r;
 124     iunlock(f->ip);
 125   } else {
 126     panic("fileread");
 127   }
 128 
 129   return r;
 130 }
 131 
 132 // Write to file f.
 133 // addr is a user virtual address.
 134 int
 135 filewrite(struct file *f, uint64 addr, int n)
 136 {
 137   int r, ret = 0;
 138 
 139   if(f->writable == 0)
 140     return -1;
 141 
 142   if(f->type == FD_PIPE){
 143     ret = pipewrite(f->pipe, addr, n);
 144   } else if(f->type == FD_DEVICE){
 145     if(f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
 146       return -1;
 147     ret = devsw[f->major].write(1, addr, n);
 148   } else if(f->type == FD_INODE){
 149     // write a few blocks at a time to avoid exceeding
 150     // the maximum log transaction size, including
 151     // i-node, indirect block, allocation blocks,
 152     // and 2 blocks of slop for non-aligned writes.
 153     // this really belongs lower down, since writei()
 154     // might be writing a device like the console.
 155     int max = ((MAXOPBLOCKS-1-1-2) / 2) * BSIZE;
 156     int i = 0;
 157     while(i < n){
 158       int n1 = n - i;
 159       if(n1 > max)
 160         n1 = max;
 161 
 162       begin_op();
 163       ilock(f->ip);
 164       if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)
 165         f->off += r;
 166       iunlock(f->ip);
 167       end_op();
 168 
 169       if(r != n1){
 170         // error from writei
 171         break;
 172       }
 173       i += r;
 174     }
 175     ret = (i == n ? n : -1);
 176   } else {
 177     panic("filewrite");
 178   }
 179 
 180   return ret;
 181 }
 182 

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