112abb1a5SRobert Morris //
212abb1a5SRobert Morris // File descriptors
312abb1a5SRobert Morris //
412abb1a5SRobert Morris
59936bffaSrsc #include "types.h"
69936bffaSrsc #include "defs.h"
7558ab49fSrsc #include "param.h"
80aef8914SRuss Cox #include "fs.h"
91ddfbbb1SFrans Kaashoek #include "spinlock.h"
10dec637bcSFrans Kaashoek #include "sleeplock.h"
11dec637bcSFrans Kaashoek #include "file.h"
129936bffaSrsc
139936bffaSrsc struct devsw devsw[NDEV];
147f399ccaSrsc struct {
157f399ccaSrsc struct spinlock lock;
169936bffaSrsc struct file file[NFILE];
177f399ccaSrsc } ftable;
189936bffaSrsc
199936bffaSrsc void
fileinit(void)2050e514beSrsc fileinit(void)
219936bffaSrsc {
2234295f46Srsc initlock(&ftable.lock, "ftable");
239936bffaSrsc }
249936bffaSrsc
25eaea18cbSrsc // Allocate a file structure.
269936bffaSrsc struct file*
filealloc(void)2750e514beSrsc filealloc(void)
289936bffaSrsc {
297f399ccaSrsc struct file *f;
309936bffaSrsc
317f399ccaSrsc acquire(&ftable.lock);
327f399ccaSrsc for(f = ftable.file; f < ftable.file + NFILE; f++){
337f399ccaSrsc if(f->ref == 0){
347f399ccaSrsc f->ref = 1;
357f399ccaSrsc release(&ftable.lock);
367f399ccaSrsc return f;
379936bffaSrsc }
389936bffaSrsc }
397f399ccaSrsc release(&ftable.lock);
409936bffaSrsc return 0;
419936bffaSrsc }
429936bffaSrsc
432186f88cSrsc // Increment ref count for file f.
441ccff18bSrsc struct file*
filedup(struct file * f)451ccff18bSrsc filedup(struct file *f)
469936bffaSrsc {
477f399ccaSrsc acquire(&ftable.lock);
487f399ccaSrsc if(f->ref < 1)
491ccff18bSrsc panic("filedup");
502186f88cSrsc f->ref++;
517f399ccaSrsc release(&ftable.lock);
521ccff18bSrsc return f;
539936bffaSrsc }
549936bffaSrsc
5513491bf3Srsc // Close file f. (Decrement ref count, close when reaches 0.)
5613491bf3Srsc void
fileclose(struct file * f)5713491bf3Srsc fileclose(struct file *f)
5813491bf3Srsc {
5913491bf3Srsc struct file ff;
6013491bf3Srsc
617f399ccaSrsc acquire(&ftable.lock);
627f399ccaSrsc if(f->ref < 1)
6313491bf3Srsc panic("fileclose");
6413491bf3Srsc if(--f->ref > 0){
657f399ccaSrsc release(&ftable.lock);
6613491bf3Srsc return;
6713491bf3Srsc }
6813491bf3Srsc ff = *f;
6913491bf3Srsc f->ref = 0;
707f399ccaSrsc f->type = FD_NONE;
717f399ccaSrsc release(&ftable.lock);
7213491bf3Srsc
7313491bf3Srsc if(ff.type == FD_PIPE)
747834cca6Srsc pipeclose(ff.pipe, ff.writable);
752e590463SRobert Morris else if(ff.type == FD_INODE){
7671453f72SRobert Morris begin_op();
7713491bf3Srsc iput(ff.ip);
7871453f72SRobert Morris end_op();
792e590463SRobert Morris }
8013491bf3Srsc }
8113491bf3Srsc
8213491bf3Srsc // Get metadata about file f.
8313491bf3Srsc int
filestat(struct file * f,struct stat * st)8413491bf3Srsc filestat(struct file *f, struct stat *st)
8513491bf3Srsc {
8613491bf3Srsc if(f->type == FD_INODE){
8713491bf3Srsc ilock(f->ip);
8813491bf3Srsc stati(f->ip, st);
8913491bf3Srsc iunlock(f->ip);
9013491bf3Srsc return 0;
9113491bf3Srsc }
9213491bf3Srsc return -1;
9313491bf3Srsc }
9413491bf3Srsc
9512abb1a5SRobert Morris // Read from file f.
969936bffaSrsc int
fileread(struct file * f,char * addr,int n)972cbb4b18Srsc fileread(struct file *f, char *addr, int n)
989936bffaSrsc {
992186f88cSrsc int r;
1002186f88cSrsc
1012cbb4b18Srsc if(f->readable == 0)
1029936bffaSrsc return -1;
1032186f88cSrsc if(f->type == FD_PIPE)
1047834cca6Srsc return piperead(f->pipe, addr, n);
105eaea18cbSrsc if(f->type == FD_INODE){
10607090dd7Srsc ilock(f->ip);
10707090dd7Srsc if((r = readi(f->ip, addr, f->off, n)) > 0)
1082186f88cSrsc f->off += r;
10907090dd7Srsc iunlock(f->ip);
1102186f88cSrsc return r;
1112186f88cSrsc }
11250e514beSrsc panic("fileread");
1139936bffaSrsc }
1149936bffaSrsc
115e76dab4fSAustin Clements //PAGEBREAK!
11612abb1a5SRobert Morris // Write to file f.
1172186f88cSrsc int
filewrite(struct file * f,char * addr,int n)1182186f88cSrsc filewrite(struct file *f, char *addr, int n)
1199936bffaSrsc {
1202186f88cSrsc int r;
1219936bffaSrsc
1222186f88cSrsc if(f->writable == 0)
1232186f88cSrsc return -1;
1242186f88cSrsc if(f->type == FD_PIPE)
1257834cca6Srsc return pipewrite(f->pipe, addr, n);
126eaea18cbSrsc if(f->type == FD_INODE){
1272e590463SRobert Morris // write a few blocks at a time to avoid exceeding
1282e590463SRobert Morris // the maximum log transaction size, including
1292e590463SRobert Morris // i-node, indirect block, allocation blocks,
1302e590463SRobert Morris // and 2 blocks of slop for non-aligned writes.
1312e590463SRobert Morris // this really belongs lower down, since writei()
1322e590463SRobert Morris // might be writing a device like the console.
133*0754d21cSRobert Morris int max = ((MAXOPBLOCKS-1-1-2) / 2) * 512;
1342e590463SRobert Morris int i = 0;
1352e590463SRobert Morris while(i < n){
1362e590463SRobert Morris int n1 = n - i;
1372e590463SRobert Morris if(n1 > max)
1382e590463SRobert Morris n1 = max;
1395053dd6aSRobert Morris
14071453f72SRobert Morris begin_op();
1415053dd6aSRobert Morris ilock(f->ip);
1423a5fa7edSFrans Kaashoek if ((r = writei(f->ip, addr + i, f->off, n1)) > 0)
1433a5fa7edSFrans Kaashoek f->off += r;
1445053dd6aSRobert Morris iunlock(f->ip);
14571453f72SRobert Morris end_op();
1465053dd6aSRobert Morris
1472e590463SRobert Morris if(r < 0)
1482e590463SRobert Morris break;
1492e590463SRobert Morris if(r != n1)
1502e590463SRobert Morris panic("short filewrite");
1512e590463SRobert Morris i += r;
1522e590463SRobert Morris }
1532e590463SRobert Morris return i == n ? n : -1;
1549936bffaSrsc }
1552186f88cSrsc panic("filewrite");
1569936bffaSrsc }
1579936bffaSrsc
158