0
|
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"
|
32
|
11 #include "proc.h"
|
0
|
12
|
52
|
13 #define __ncode __code
|
113
|
14 #
|
0
|
15 struct devsw devsw[NDEV];
|
27
|
16 struct cbc_devsw cbc_devsw[NDEV];
|
|
17
|
0
|
18 struct {
|
|
19 struct spinlock lock;
|
|
20 struct file file[NFILE];
|
|
21 } ftable;
|
|
22
|
|
23 void fileinit (void)
|
|
24 {
|
|
25 initlock(&ftable.lock, "ftable");
|
|
26 }
|
|
27
|
|
28 // Allocate a file structure.
|
|
29 struct file* filealloc (void)
|
|
30 {
|
|
31 struct file *f;
|
|
32
|
|
33 acquire(&ftable.lock);
|
|
34
|
|
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
|
|
43 release(&ftable.lock);
|
|
44 return 0;
|
|
45 }
|
|
46
|
|
47 // Increment ref count for file f.
|
|
48 struct file* filedup (struct file *f)
|
|
49 {
|
|
50 acquire(&ftable.lock);
|
|
51
|
|
52 if (f->ref < 1) {
|
|
53 panic("filedup");
|
|
54 }
|
|
55
|
|
56 f->ref++;
|
|
57 release(&ftable.lock);
|
|
58 return f;
|
|
59 }
|
|
60
|
|
61 // Close file f. (Decrement ref count, close when reaches 0.)
|
|
62 void fileclose (struct file *f)
|
|
63 {
|
|
64 struct file ff;
|
|
65
|
|
66 acquire(&ftable.lock);
|
|
67
|
|
68 if (f->ref < 1) {
|
|
69 panic("fileclose");
|
|
70 }
|
|
71
|
|
72 if (--f->ref > 0) {
|
|
73 release(&ftable.lock);
|
|
74 return;
|
|
75 }
|
|
76
|
|
77 ff = *f;
|
|
78 f->ref = 0;
|
|
79 f->type = FD_NONE;
|
|
80 release(&ftable.lock);
|
|
81
|
|
82 if (ff.type == FD_PIPE) {
|
|
83 pipeclose(ff.pipe, ff.writable);
|
|
84
|
|
85 } else if (ff.type == FD_INODE) {
|
|
86 begin_trans();
|
|
87 iput(ff.ip);
|
|
88 commit_trans();
|
|
89 }
|
|
90 }
|
|
91
|
|
92 // Get metadata about file f.
|
|
93 int filestat (struct file *f, struct stat *st)
|
|
94 {
|
|
95 if (f->type == FD_INODE) {
|
|
96 ilock(f->ip);
|
|
97 stati(f->ip, st);
|
|
98 iunlock(f->ip);
|
|
99
|
|
100 return 0;
|
|
101 }
|
|
102
|
|
103 return -1;
|
|
104 }
|
|
105
|
52
|
106 __ncode cbc_fileread1 (int r)
|
24
|
107 {
|
33
|
108 struct file *f = proc->cbc_arg.cbc_console_arg.f;
|
|
109 __code (*next)(int ret) = cbc_ret;
|
24
|
110 if (r > 0)
|
|
111 f->off += r;
|
|
112 iunlock(f->ip);
|
|
113 goto next(r);
|
|
114 }
|
|
115
|
113
|
116 __ncode cbc_fileread (struct file *f, char *addr, int n, __code (*next)(int ret))
|
24
|
117 {
|
|
118 if (f->readable == 0) {
|
|
119 goto next(-1);
|
|
120 }
|
|
121
|
|
122 if (f->type == FD_PIPE) {
|
113
|
123 goto cbc_piperead(f->pipe, addr, n, next);
|
30
|
124 goto next(-1);
|
24
|
125 }
|
|
126
|
|
127 if (f->type == FD_INODE) {
|
|
128 ilock(f->ip);
|
33
|
129 proc->cbc_arg.cbc_console_arg.f = f;
|
|
130 goto cbc_readi(f->ip, addr, f->off, n, cbc_fileread1);
|
24
|
131 }
|
|
132
|
|
133 goto cbc_panic("fileread");
|
|
134 }
|
|
135
|
0
|
136 // Read from file f.
|
|
137 int fileread (struct file *f, char *addr, int n)
|
|
138 {
|
|
139 int r;
|
|
140
|
|
141 if (f->readable == 0) {
|
|
142 return -1;
|
|
143 }
|
|
144
|
|
145 if (f->type == FD_PIPE) {
|
|
146 return piperead(f->pipe, addr, n);
|
|
147 }
|
|
148
|
|
149 if (f->type == FD_INODE) {
|
|
150 ilock(f->ip);
|
|
151
|
|
152 if ((r = readi(f->ip, addr, f->off, n)) > 0) {
|
|
153 f->off += r;
|
|
154 }
|
|
155
|
|
156 iunlock(f->ip);
|
|
157
|
|
158 return r;
|
|
159 }
|
|
160
|
|
161 panic("fileread");
|
|
162 }
|
|
163
|
|
164 //PAGEBREAK!
|
|
165 // Write to file f.
|
|
166 int filewrite (struct file *f, char *addr, int n)
|
|
167 {
|
|
168 int r;
|
|
169 int i;
|
|
170 int max;
|
|
171 int n1;
|
|
172
|
|
173 if (f->writable == 0) {
|
|
174 return -1;
|
|
175 }
|
|
176
|
|
177 if (f->type == FD_PIPE) {
|
|
178 return pipewrite(f->pipe, addr, n);
|
|
179 }
|
|
180
|
|
181 if (f->type == FD_INODE) {
|
|
182 // write a few blocks at a time to avoid exceeding
|
|
183 // the maximum log transaction size, including
|
|
184 // i-node, indirect block, allocation blocks,
|
|
185 // and 2 blocks of slop for non-aligned writes.
|
|
186 // this really belongs lower down, since writei()
|
|
187 // might be writing a device like the console.
|
|
188 max = ((LOGSIZE - 1 - 1 - 2) / 2) * 512;
|
|
189 i = 0;
|
|
190
|
|
191 while (i < n) {
|
|
192 n1 = n - i;
|
|
193
|
|
194 if (n1 > max) {
|
|
195 n1 = max;
|
|
196 }
|
|
197
|
|
198 begin_trans();
|
|
199 ilock(f->ip);
|
|
200
|
|
201 if ((r = writei(f->ip, addr + i, f->off, n1)) > 0) {
|
|
202 f->off += r;
|
|
203 }
|
|
204
|
|
205 iunlock(f->ip);
|
|
206 commit_trans();
|
|
207
|
|
208 if (r < 0) {
|
|
209 break;
|
|
210 }
|
|
211
|
|
212 if (r != n1) {
|
|
213 panic("short filewrite");
|
|
214 }
|
|
215
|
|
216 i += r;
|
|
217 }
|
|
218
|
|
219 return i == n ? n : -1;
|
|
220 }
|
|
221
|
|
222 panic("filewrite");
|
109
|
223 }
|
|
224
|