1use core::mem::{self, MaybeUninit};
2use core::slice;
3
4use alloc::sync::Arc;
5
6use crate::console::Console;
7use crate::fs::{BSIZE, FsError, Inode, Stat};
8use crate::log::Operation;
9use crate::param::{MAXOPBLOCKS, NDEV, NFILE};
10use crate::pipe::Pipe;
11use crate::proc;
12use crate::sleeplock::SleepLock;
13use crate::spinlock::SpinLock;
14use crate::syscall::SysError;
15use crate::vm::VA;
16
17#[derive(Debug, Clone)]
18pub enum FileType {
19 None,
20 Pipe { pipe: Arc<Pipe> },
21 Inode { inode: Inode },
22 Device { inode: Inode, major: u16 },
23}
24
25#[derive(Debug, Clone)]
27pub struct FileMeta {
28 pub ref_count: usize,
29}
30
31#[derive(Debug, Clone)]
33pub struct FileInner {
34 pub readable: bool,
36 pub writeable: bool,
37 pub r#type: FileType,
38 pub offset: u32,
39}
40
41pub static FILE_TABLE: FileTable = FileTable::new();
42
43#[derive(Debug)]
45pub struct FileTable {
46 pub meta: SpinLock<[FileMeta; NFILE]>,
48 pub inner: [SleepLock<FileInner>; NFILE],
50}
51
52impl FileTable {
53 const fn new() -> Self {
54 let meta = {
55 let mut array: [MaybeUninit<FileMeta>; NFILE] =
56 unsafe { MaybeUninit::uninit().assume_init() };
57
58 let mut i = 0;
59 while i < NFILE {
60 array[i] = MaybeUninit::new(FileMeta { ref_count: 0 });
61 i += 1;
62 }
63
64 SpinLock::new(
65 unsafe {
66 mem::transmute::<[MaybeUninit<FileMeta>; NFILE], [FileMeta; NFILE]>(array)
67 },
68 "filetable",
69 )
70 };
71
72 let inner = {
73 let mut array: [MaybeUninit<SleepLock<FileInner>>; NFILE] =
74 unsafe { MaybeUninit::uninit().assume_init() };
75
76 let mut i = 0;
77 while i < NFILE {
78 array[i] = MaybeUninit::new(SleepLock::new(
79 FileInner {
80 readable: false,
81 writeable: false,
82 r#type: FileType::None,
83 offset: 0,
84 },
85 "file",
86 ));
87 i += 1;
88 }
89
90 unsafe {
91 mem::transmute::<
92 [MaybeUninit<SleepLock<FileInner>>; NFILE],
93 [SleepLock<FileInner>; NFILE],
94 >(array)
95 }
96 };
97
98 Self { meta, inner }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct File {
105 pub id: usize,
106}
107
108impl File {
109 pub fn alloc() -> Result<Self, FsError> {
111 let mut meta = FILE_TABLE.meta.lock();
112
113 for (i, meta) in meta.iter_mut().enumerate() {
114 if meta.ref_count == 0 {
115 meta.ref_count = 1;
116
117 return Ok(Self { id: i });
118 }
119 }
120
121 err!(FsError::OutOfFile);
122 }
123
124 pub fn dup(&mut self) -> Self {
126 let meta = &mut FILE_TABLE.meta.lock()[self.id];
127
128 assert!(meta.ref_count >= 1, "filedup");
129
130 meta.ref_count += 1;
131
132 self.clone()
133 }
134
135 pub fn close(&mut self) {
137 let mut meta_guard = FILE_TABLE.meta.lock();
138 let meta = &mut meta_guard[self.id];
139
140 assert!(meta.ref_count >= 1, "fileclose");
141
142 meta.ref_count -= 1;
143 if meta.ref_count > 0 {
144 return;
145 }
146
147 let inner_copy = {
148 let mut inner = FILE_TABLE.inner[self.id].lock();
149 let copy = inner.clone();
151
152 meta.ref_count = 0;
153 inner.r#type = FileType::None;
154
155 drop(meta_guard);
156 copy
157 }; match inner_copy.r#type {
160 FileType::None => {}
161 FileType::Pipe { pipe } => {
162 pipe.close(inner_copy.writeable);
163 }
164 FileType::Inode { inode } | FileType::Device { inode, .. } => {
165 let _op = Operation::begin();
166 inode.put();
167 }
168 }
169 }
170
171 pub fn stat(&self, addr: VA) -> Result<(), SysError> {
173 let file_inner = FILE_TABLE.inner[self.id].lock();
174
175 match &file_inner.r#type {
176 FileType::Inode { inode } | FileType::Device { inode, .. } => {
177 let inode_inner = inode.lock();
178 let stat = inode.stat(&inode_inner);
179 inode.unlock(inode_inner);
180
181 let src = unsafe {
182 slice::from_raw_parts(&stat as *const _ as *const u8, size_of::<Stat>())
183 };
184 if log!(proc::copy_to_user(src, addr)).is_err() {
185 err!(SysError::BadAddress);
186 }
187
188 Ok(())
189 }
190 _ => Err(SysError::BadDescriptor),
191 }
192 }
193
194 pub fn read(&self, addr: VA, n: usize) -> Result<usize, SysError> {
196 let mut file_inner = FILE_TABLE.inner[self.id].lock();
197
198 if !file_inner.readable {
199 err!(SysError::BadDescriptor);
200 }
201
202 match &mut file_inner.r#type {
203 FileType::None => panic!("fileread"),
204
205 FileType::Pipe { pipe } => pipe.read(addr, n),
206
207 FileType::Inode { inode } => {
208 let inode = inode.clone();
209 let mut inode_inner = inode.lock();
210
211 let dst = unsafe { slice::from_raw_parts_mut(addr.as_mut_ptr(), n) };
212 let read = log!(inode.read(&mut inode_inner, file_inner.offset, dst, true));
213
214 if let Ok(read) = read {
215 file_inner.offset += read;
216 }
217
218 inode.unlock(inode_inner);
219
220 if let Ok(read) = read {
221 Ok(read as usize)
222 } else {
223 err!(SysError::IoError);
224 }
225 }
226
227 FileType::Device { inode: _, major } => match &DEVICES[*major as usize] {
228 Some(dev) => (dev.read)(addr, n),
229 None => err!(SysError::NoEntry),
230 },
231 }
232 }
233
234 pub fn write(&mut self, addr: VA, n: usize) -> Result<usize, SysError> {
236 let mut file_inner = FILE_TABLE.inner[self.id].lock();
237
238 if !file_inner.writeable {
239 err!(SysError::BadDescriptor);
240 }
241
242 match &mut file_inner.r#type {
243 FileType::None => panic!("filewrite"),
244
245 FileType::Pipe { pipe } => pipe.write(addr, n),
246
247 FileType::Inode { inode } => {
248 let inode = inode.clone();
249
250 let max = ((MAXOPBLOCKS - 1 - 1 - 2) / 2) * BSIZE;
254 let mut i = 0;
255
256 while i < n {
257 let n1 = (n - i).min(max);
258
259 let _op = Operation::begin();
260 let mut inode_inner = inode.lock();
261
262 let src =
263 unsafe { slice::from_raw_parts((addr.as_usize() + i) as *const u8, n1) };
264 let write = log!(inode.write(&mut inode_inner, file_inner.offset, src, true));
265
266 if let Ok(w) = write {
267 file_inner.offset += w;
268 }
269
270 inode.unlock(inode_inner);
271 drop(_op);
272
273 if write.is_err() {
274 break;
275 }
276
277 i += write.unwrap() as usize;
278 }
279
280 if i == n {
281 Ok(n)
282 } else {
283 err!(SysError::IoError);
284 }
285 }
286
287 FileType::Device { inode: _, major } => match &DEVICES[*major as usize] {
288 Some(dev) => (dev.write)(addr, n),
289 None => err!(SysError::NoEntry),
290 },
291 }
292 }
293}
294
295pub struct OpenFlag;
297
298impl OpenFlag {
299 pub const READ_ONLY: usize = 0x000;
300 pub const WRITE_ONLY: usize = 0x001;
301 pub const READ_WRITE: usize = 0x002;
302 pub const CREATE: usize = 0x200;
303 pub const TRUNCATE: usize = 0x400;
304}
305
306#[derive(Debug, Clone, Copy)]
308pub struct Device {
309 pub read: fn(addr: VA, n: usize) -> Result<usize, SysError>,
310 pub write: fn(addr: VA, n: usize) -> Result<usize, SysError>,
311}
312
313pub const CONSOLE: usize = 1;
315
316pub static DEVICES: [Option<Device>; NDEV] = {
318 let mut devices = [None; NDEV];
319 devices[CONSOLE] = Some(Device {
320 read: Console::read,
321 write: Console::write,
322 });
323 devices
324};