kernel/file.c

180 lines
1//2// Support functions for system calls that involve file descriptors.3//45#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"1516struct devsw devsw[NDEV];17struct {18  struct spinlock lock;19  struct file file[NFILE];20} ftable;2122void23fileinit(void)24{25  initlock(&ftable.lock, "ftable");26}2728// Allocate a file structure.29struct file*30filealloc(void)31{32  struct file *f;3334  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}4546// Increment ref count for file f.47struct file*48filedup(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}5758// Close file f.  (Decrement ref count, close when reaches 0.)59void60fileclose(struct file *f)61{62  struct file ff;6364  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);7576  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}8485// Get metadata about file f.86// addr is a user virtual address, pointing to a struct stat.87int88filestat(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}103104// Read from file f.105// addr is a user virtual address.106int107fileread(struct file *f, uint64 addr, int n)108{109  int r = 0;110111  if(f->readable == 0)112    return -1;113114  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  }128129  return r;130}131132// Write to file f.133// addr is a user virtual address.134int135filewrite(struct file *f, uint64 addr, int n)136{137  int r, ret = 0;138139  if(f->writable == 0)140    return -1;141142  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 exceeding150    // the maximum log transaction size, including151    // i-node, indirect block, allocation blocks,152    // and 2 blocks of slop for non-aligned writes.153    int max = ((MAXOPBLOCKS-1-1-2) / 2) * BSIZE;154    int i = 0;155    while(i < n){156      int n1 = n - i;157      if(n1 > max)158        n1 = max;159160      begin_op();161      ilock(f->ip);162      if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)163        f->off += r;164      iunlock(f->ip);165      end_op();166167      if(r != n1){168        // error from writei169        break;170      }171      i += r;172    }173    ret = (i == n ? n : -1);174  } else {175    panic("filewrite");176  }177178  return ret;179}180181