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