1use super::bitmap_block::BitmapBlock;
2use super::block::LinkedBlock;
3use super::dir::Dir;
4use super::dir_entry::DirEntry;
5use super::{dirname, filename, realpath, FileIO, IO};
6
7use alloc::boxed::Box;
8use alloc::string::{String, ToString};
9use alloc::vec;
10
11pub enum SeekFrom {
12 Start(u32),
13 Current(i32),
14 End(i32),
15}
16
17#[derive(Debug, Clone)]
18pub struct File {
19 parent: Option<Box<Dir>>,
20 name: String,
21 addr: u32,
22 size: u32,
23 offset: u32,
24}
25
26impl From<DirEntry> for File {
27 fn from(entry: DirEntry) -> Self {
28 Self {
29 parent: Some(Box::new(entry.dir())),
30 name: entry.name(),
31 addr: entry.addr(),
32 size: entry.size(),
33 offset: 0,
34 }
35 }
36}
37
38impl File {
39 pub fn new() -> Self {
40 Self {
41 parent: None,
42 name: String::new(),
43 addr: 0,
44 size: 0,
45 offset: 0,
46 }
47 }
48
49 pub fn create(pathname: &str) -> Option<Self> {
50 let pathname = realpath(pathname);
51 let dirname = dirname(&pathname);
52 let filename = filename(&pathname);
53 if let Some(mut dir) = Dir::open(dirname) {
54 if let Some(dir_entry) = dir.create_file(filename) {
55 return Some(dir_entry.into());
56 }
57 }
58 None
59 }
60
61 pub fn open(pathname: &str) -> Option<Self> {
62 let pathname = realpath(pathname);
63 let dirname = dirname(&pathname);
64 let filename = filename(&pathname);
65 if let Some(dir) = Dir::open(dirname) {
66 if let Some(dir_entry) = dir.find(filename) {
67 if dir_entry.is_file() {
68 return Some(dir_entry.into());
69 }
70 }
71 }
72 None
73 }
74
75 pub fn name(&self) -> String {
76 self.name.clone()
77 }
78
79 pub fn size(&self) -> usize {
80 self.size as usize
81 }
82
83 pub fn seek(&mut self, pos: SeekFrom) -> Result<u32, ()> {
84 let offset = match pos {
85 SeekFrom::Start(i) => i as i32,
86 SeekFrom::Current(i) => i + self.offset as i32,
87 SeekFrom::End(i) => i + self.size as i32,
88 };
89 if offset < 0 || offset > self.size as i32 { return Err(());
91 }
92 self.offset = offset as u32;
93
94 Ok(self.offset)
95 }
96 pub fn read_to_string(&mut self) -> String {
100 let mut buf = vec![0; self.size()];
101 if let Ok(bytes) = self.read(&mut buf) {
102 buf.resize(bytes, 0);
103 }
104 String::from_utf8_lossy(&buf).to_string()
105 }
106
107 pub fn addr(&self) -> u32 {
108 self.addr
109 }
110
111 pub fn delete(pathname: &str) -> Result<(), ()> {
112 let pathname = realpath(pathname);
113 let dirname = dirname(&pathname);
114 let filename = filename(&pathname);
115 if let Some(mut dir) = Dir::open(dirname) {
116 dir.delete_entry(filename)
117 } else {
118 Err(())
119 }
120 }
121}
122
123impl FileIO for File {
124 fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
125 let buf_len = buf.len();
126 let mut addr = self.addr;
127 let mut bytes = 0; let mut pos = 0; loop {
130 let block = LinkedBlock::read(addr);
131 let data = block.data();
132 let data_len = data.len();
133 for i in 0..data_len {
134 if pos == self.offset {
135 if bytes == buf_len || pos as usize == self.size() {
136 return Ok(bytes);
137 }
138 buf[bytes] = data[i];
139 bytes += 1;
140 self.offset += 1;
141 }
142 pos += 1;
143 }
144 match block.next() {
145 Some(next_block) => addr = next_block.addr(),
146 None => return Ok(bytes),
147 }
148 }
149 }
150
151 fn write(&mut self, buf: &[u8]) -> Result<usize, ()> {
152 let buf_len = buf.len();
153 let mut addr = self.addr;
154 let mut bytes = 0; let mut pos = 0; if self.offset == self.size && self.size > 0 {
159 let mut block = LinkedBlock::read(addr);
160 while let Some(next_block) = block.next() {
161 addr = next_block.addr();
162 block = LinkedBlock::read(addr);
163 }
164 let block_data_len = block.len() as u32;
166 if self.size % block_data_len == 0 {
167 match LinkedBlock::alloc() {
168 Some(new_block) => {
169 let mut last_block = LinkedBlock::read(addr);
170 last_block.set_next_addr(new_block.addr());
171 last_block.write();
172 addr = new_block.addr();
173 pos = self.size;
174 }
175 None => return Err(()),
176 }
177 } else {
178 pos = self.size - (self.size % block_data_len);
179 }
180 }
181
182 while bytes < buf_len {
183 let mut block = LinkedBlock::read(addr);
184 let data = block.data_mut();
185 let data_len = data.len();
186 for i in 0..data_len {
187 if pos == self.offset {
188 if bytes == buf_len {
189 break;
190 }
191 data[i] = buf[bytes];
192 bytes += 1;
193 self.offset += 1;
194 }
195 pos += 1;
196 }
197
198 addr = match block.next() {
199 Some(next_block) => {
200 if bytes < buf_len {
201 next_block.addr()
202 } else {
203 let mut free_block = next_block;
205 loop {
206 BitmapBlock::free(free_block.addr());
207 match free_block.next() { Some(next_block) => free_block = next_block,
209 None => break,
210 }
211 }
212 0
213 }
214 }
215 None => {
216 if bytes < buf_len {
217 match LinkedBlock::alloc() {
218 Some(next_block) => next_block.addr(),
219 None => return Err(()),
220 }
221 } else {
222 0
223 }
224 }
225 };
226
227 block.set_next_addr(addr);
228 block.write();
229 }
230 self.size = self.offset;
231 if let Some(dir) = self.parent.clone() {
232 dir.update_entry(&self.name, self.size);
233 }
234 Ok(bytes)
235 }
236
237 fn close(&mut self) {}
238
239 fn poll(&mut self, event: IO) -> bool {
240 match event {
241 IO::Read => self.offset < self.size,
242 IO::Write => true,
243 }
244 }
245}
246
247#[test_case]
248fn test_file_create() {
249 super::mount_mem();
250 super::format_mem();
251 assert!(File::create("/test").is_some());
252 assert_eq!(File::create("/hello").unwrap().name(), "hello");
253 super::dismount();
254}
255
256#[test_case]
257fn test_file_write() {
258 super::mount_mem();
259 super::format_mem();
260 let mut file = File::create("/test").unwrap();
261 let buf = "Hello, World!".as_bytes();
262 assert_eq!(file.write(&buf), Ok(buf.len()));
263 super::dismount();
264}
265
266#[test_case]
267fn test_file_open() {
268 super::mount_mem();
269 super::format_mem();
270 assert!(File::open("/test").is_none());
271 let mut file = File::create("/test").unwrap();
272 let buf = "Hello, World!".as_bytes();
273 file.write(&buf).unwrap();
274 assert!(File::open("/test").is_some());
275 super::dismount();
276}
277
278#[test_case]
279fn test_file_read() {
280 super::mount_mem();
281 super::format_mem();
282 let mut file = File::create("/test").unwrap();
283 let input = "Hello, World!".as_bytes();
284 file.write(&input).unwrap();
285
286 let mut file = File::open("/test").unwrap();
287 let mut output = [0u8; 13];
288 assert_eq!(file.read(&mut output), Ok(input.len()));
289 assert_eq!(input, output);
290 super::dismount();
291}
292
293#[test_case]
294fn test_file_delete() {
295 super::mount_mem();
296 super::format_mem();
297 assert!(File::open("/test").is_none());
298 assert!(File::create("/test").is_some());
299 assert!(File::open("/test").is_some());
300 assert!(File::delete("/test").is_ok());
301 assert!(File::open("/test").is_none());
302 super::dismount();
303}