diff options
Diffstat (limited to 'kernel/file.c')
-rw-r--r-- | kernel/file.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/kernel/file.c b/kernel/file.c new file mode 100644 index 0000000..6f27f22 --- /dev/null +++ b/kernel/file.c @@ -0,0 +1,175 @@ +// +// Support functions for system calls that involve file descriptors. +// + +#include "types.h" +#include "riscv.h" +#include "defs.h" +#include "param.h" +#include "fs.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "file.h" +#include "stat.h" +#include "proc.h" + +struct devsw devsw[NDEV]; +struct { + struct spinlock lock; + struct file file[NFILE]; +} ftable; + +void +fileinit(void) +{ + initlock(&ftable.lock, "ftable"); +} + +// Allocate a file structure. +struct file* +filealloc(void) +{ + struct file *f; + + acquire(&ftable.lock); + for(f = ftable.file; f < ftable.file + NFILE; f++){ + if(f->ref == 0){ + f->ref = 1; + release(&ftable.lock); + return f; + } + } + release(&ftable.lock); + return 0; +} + +// Increment ref count for file f. +struct file* +filedup(struct file *f) +{ + acquire(&ftable.lock); + if(f->ref < 1) + panic("filedup"); + f->ref++; + release(&ftable.lock); + return f; +} + +// Close file f. (Decrement ref count, close when reaches 0.) +void +fileclose(struct file *f) +{ + struct file ff; + + acquire(&ftable.lock); + if(f->ref < 1) + panic("fileclose"); + if(--f->ref > 0){ + release(&ftable.lock); + return; + } + ff = *f; + f->ref = 0; + f->type = FD_NONE; + release(&ftable.lock); + + if(ff.type == FD_PIPE) + pipeclose(ff.pipe, ff.writable); + else if(ff.type == FD_INODE){ + begin_op(); + iput(ff.ip); + end_op(); + } +} + +// Get metadata about file f. +// addr is a user virtual address, pointing to a struct stat. +int +filestat(struct file *f, uint64 addr) +{ + struct proc *p = myproc(); + struct stat st; + + if(f->type == FD_INODE){ + ilock(f->ip); + stati(f->ip, &st); + iunlock(f->ip); + if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0) + return -1; + return 0; + } + return -1; +} + +// Read from file f. +// addr is a user virtual address. +int +fileread(struct file *f, uint64 addr, int n) +{ + int r = 0; + + if(f->readable == 0) + return -1; + + if(f->type == FD_PIPE){ + r = piperead(f->pipe, addr, n); + } else if(f->type == FD_INODE){ + ilock(f->ip); + if((r = readi(f->ip, 1, addr, f->off, n)) > 0) + f->off += r; + iunlock(f->ip); + } else { + panic("fileread"); + } + + return r; +} + +//PAGEBREAK! +// Write to file f. +// addr is a user virtual address. +int +filewrite(struct file *f, uint64 addr, int n) +{ + int r, ret = 0; + + if(f->writable == 0) + return -1; + + if(f->type == FD_PIPE){ + ret = pipewrite(f->pipe, addr, n); + } else if(f->type == FD_INODE){ + // write a few blocks at a time to avoid exceeding + // the maximum log transaction size, including + // i-node, indirect block, allocation blocks, + // and 2 blocks of slop for non-aligned writes. + // this really belongs lower down, since writei() + // might be writing a device like the console. + int max = ((MAXOPBLOCKS-1-1-2) / 2) * 512; + int i = 0; + while(i < n){ + int n1 = n - i; + if(n1 > max) + n1 = max; + + begin_op(); + ilock(f->ip); + if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0) + f->off += r; + iunlock(f->ip); + end_op(); + + if(r < 0) + break; + if(r != n1) + panic("short filewrite"); + i += r; + } + ret = (i == n ? n : -1); + } else { + panic("filewrite"); + } + + return ret; +} + |