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