1use alloc::{boxed::Box, sync::Arc};
18use core::cell::OnceCell;
19
20use ax_fs_vfs::{
21 VfsDirEntry, VfsError, VfsNodeAttr, VfsNodeOps, VfsNodePerm, VfsNodeRef, VfsNodeType, VfsOps,
22 VfsResult,
23};
24use axfatfs::{Dir, File, LossyOemCpConverter, NullTimeProvider, Read, Seek, SeekFrom, Write};
25use spin::Mutex;
26
27use crate::dev::{Disk, Partition};
28
29const BLOCK_SIZE: usize = 512;
30
31pub struct FatFileSystem {
33 inner: axfatfs::FileSystem<PartitionWrapper, NullTimeProvider, LossyOemCpConverter>,
34 root_dir: OnceCell<VfsNodeRef>,
35}
36
37pub struct PartitionWrapper {
39 partition: Partition,
40}
41
42impl PartitionWrapper {
43 pub fn new(partition: Partition) -> Self {
45 Self { partition }
46 }
47}
48
49impl axfatfs::IoBase for PartitionWrapper {
50 type Error = ();
51}
52
53impl axfatfs::Read for PartitionWrapper {
54 fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Self::Error> {
55 let mut read_len = 0;
56 while !buf.is_empty() {
57 match self.partition.read_one(buf) {
58 Ok(0) => break,
59 Ok(n) => {
60 let tmp = buf;
61 buf = &mut tmp[n..];
62 read_len += n;
63 }
64 Err(_) => return Err(()),
65 }
66 }
67 Ok(read_len)
68 }
69}
70
71impl axfatfs::Write for PartitionWrapper {
72 fn write(&mut self, mut buf: &[u8]) -> Result<usize, Self::Error> {
73 let mut write_len = 0;
74 while !buf.is_empty() {
75 match self.partition.write_one(buf) {
76 Ok(0) => break,
77 Ok(n) => {
78 buf = &buf[n..];
79 write_len += n;
80 }
81 Err(_) => return Err(()),
82 }
83 }
84 Ok(write_len)
85 }
86
87 fn flush(&mut self) -> Result<(), Self::Error> {
88 Ok(())
89 }
90}
91
92impl axfatfs::Seek for PartitionWrapper {
93 fn seek(&mut self, pos: axfatfs::SeekFrom) -> Result<u64, Self::Error> {
94 let size = self.partition.size();
95 let new_pos = match pos {
96 axfatfs::SeekFrom::Start(pos) => Some(pos),
97 axfatfs::SeekFrom::Current(off) => self.partition.position().checked_add_signed(off),
98 axfatfs::SeekFrom::End(off) => size.checked_add_signed(off),
99 }
100 .ok_or(())?;
101 if new_pos > size {
102 warn!("Seek beyond the end of the partition");
103 }
104 self.partition.set_position(new_pos);
105 Ok(new_pos)
106 }
107}
108
109pub struct FileWrapper<'a>(
111 Mutex<File<'a, PartitionWrapper, NullTimeProvider, LossyOemCpConverter>>,
112);
113pub struct DirWrapper<'a>(Dir<'a, PartitionWrapper, NullTimeProvider, LossyOemCpConverter>);
115
116unsafe impl Sync for FatFileSystem {}
117unsafe impl Send for FatFileSystem {}
118unsafe impl Send for FileWrapper<'_> {}
119unsafe impl Sync for FileWrapper<'_> {}
120unsafe impl Send for DirWrapper<'_> {}
121unsafe impl Sync for DirWrapper<'_> {}
122
123impl FatFileSystem {
124 #[allow(dead_code)]
126 pub fn new(disk: Disk) -> Self {
127 let disk_size = disk.size();
128 let wrapper = PartitionWrapper::new(crate::dev::Partition::new(disk, 0, disk_size / 512));
129 let inner = axfatfs::FileSystem::new(wrapper, axfatfs::FsOptions::new())
130 .expect("failed to initialize FAT filesystem");
131 Self {
132 inner,
133 root_dir: OnceCell::new(),
134 }
135 }
136
137 pub fn from_partition(partition: Partition) -> Self {
139 let wrapper = PartitionWrapper::new(partition);
140 let inner = axfatfs::FileSystem::new(wrapper, axfatfs::FsOptions::new())
141 .expect("failed to initialize FAT filesystem on partition");
142 Self {
143 inner,
144 root_dir: OnceCell::new(),
145 }
146 }
147
148 #[allow(dead_code)]
150 pub fn init(&'static self) {
151 }
153
154 fn new_file(
155 file: File<'_, PartitionWrapper, NullTimeProvider, LossyOemCpConverter>,
156 ) -> VfsNodeRef {
157 let file_box = Box::new(file);
159 let file_static = unsafe {
160 core::mem::transmute::<
161 Box<File<'_, PartitionWrapper, NullTimeProvider, LossyOemCpConverter>>,
162 Box<File<'static, PartitionWrapper, NullTimeProvider, LossyOemCpConverter>>,
163 >(file_box)
164 };
165 let file_wrapper = FileWrapper(Mutex::new(*file_static));
166 Arc::new(file_wrapper) as VfsNodeRef
167 }
168
169 fn new_dir(
170 dir: Dir<'_, PartitionWrapper, NullTimeProvider, LossyOemCpConverter>,
171 ) -> VfsNodeRef {
172 let dir_box = Box::new(dir);
174 let dir_static = unsafe {
175 core::mem::transmute::<
176 Box<Dir<'_, PartitionWrapper, NullTimeProvider, LossyOemCpConverter>>,
177 Box<Dir<'static, PartitionWrapper, NullTimeProvider, LossyOemCpConverter>>,
178 >(dir_box)
179 };
180 let dir_wrapper = DirWrapper(*dir_static);
181 Arc::new(dir_wrapper) as VfsNodeRef
182 }
183}
184
185impl VfsNodeOps for FileWrapper<'static> {
186 ax_fs_vfs::impl_vfs_non_dir_default! {}
187
188 fn get_attr(&self) -> VfsResult<VfsNodeAttr> {
189 let size = self.0.lock().seek(SeekFrom::End(0)).map_err(as_vfs_err)?;
190 let blocks = size.div_ceil(BLOCK_SIZE as u64);
191 let perm = VfsNodePerm::from_bits_truncate(0o755);
193 Ok(VfsNodeAttr::new(perm, VfsNodeType::File, size, blocks))
194 }
195
196 fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize> {
197 let mut file = self.0.lock();
198 file.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; file.read(buf).map_err(as_vfs_err)
200 }
201
202 fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult<usize> {
203 let mut file = self.0.lock();
204 file.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; file.write(buf).map_err(as_vfs_err)
206 }
207
208 fn truncate(&self, size: u64) -> VfsResult {
209 let mut file = self.0.lock();
210 let current_size = file.seek(SeekFrom::End(0)).map_err(as_vfs_err)?;
211
212 if size <= current_size {
213 file.seek(SeekFrom::Start(size)).map_err(as_vfs_err)?; file.truncate().map_err(as_vfs_err)
217 } else {
218 let mut zeros_needed = size - current_size;
220 let zeros = [0u8; 4096];
222 while zeros_needed > 0 {
223 let to_write = core::cmp::min(zeros_needed, zeros.len() as u64);
224 let write_buf = &zeros[..to_write as usize];
225 file.write(write_buf).map_err(as_vfs_err)?;
226 zeros_needed -= to_write;
227 }
228 Ok(())
229 }
230 }
231}
232
233impl VfsNodeOps for DirWrapper<'static> {
234 ax_fs_vfs::impl_vfs_dir_default! {}
235
236 fn get_attr(&self) -> VfsResult<VfsNodeAttr> {
237 Ok(VfsNodeAttr::new(
239 VfsNodePerm::from_bits_truncate(0o755),
240 VfsNodeType::Dir,
241 BLOCK_SIZE as u64,
242 1,
243 ))
244 }
245
246 fn parent(&self) -> Option<VfsNodeRef> {
247 self.0
248 .open_dir("..")
249 .map_or(None, |dir| Some(FatFileSystem::new_dir(dir)))
250 }
251
252 fn lookup(self: Arc<Self>, path: &str) -> VfsResult<VfsNodeRef> {
253 debug!("lookup at axfatfs: {}", path);
254 let path = path.trim_matches('/');
255 if path.is_empty() || path == "." {
256 return Ok(self.clone());
257 }
258 if let Some(rest) = path.strip_prefix("./") {
259 return self.lookup(rest);
260 }
261
262 if let Ok(file) = self.0.open_file(path) {
264 Ok(FatFileSystem::new_file(file))
265 } else if let Ok(dir) = self.0.open_dir(path) {
266 Ok(FatFileSystem::new_dir(dir))
267 } else {
268 Err(VfsError::NotFound)
269 }
270 }
271
272 fn create(&self, path: &str, ty: VfsNodeType) -> VfsResult {
273 debug!("create {:?} at axfatfs: {}", ty, path);
274 let path = path.trim_matches('/');
275 if path.is_empty() || path == "." {
276 return Ok(());
277 }
278 if let Some(rest) = path.strip_prefix("./") {
279 return self.create(rest, ty);
280 }
281
282 match ty {
283 VfsNodeType::File => {
284 self.0.create_file(path).map_err(as_vfs_err)?;
285 Ok(())
286 }
287 VfsNodeType::Dir => {
288 self.0.create_dir(path).map_err(as_vfs_err)?;
289 Ok(())
290 }
291 _ => Err(VfsError::Unsupported),
292 }
293 }
294
295 fn remove(&self, path: &str) -> VfsResult {
296 debug!("remove at axfatfs: {}", path);
297 let path = path.trim_matches('/');
298 assert!(!path.is_empty()); if let Some(rest) = path.strip_prefix("./") {
300 return self.remove(rest);
301 }
302 self.0.remove(path).map_err(as_vfs_err)
303 }
304
305 fn read_dir(&self, start_idx: usize, dirents: &mut [VfsDirEntry]) -> VfsResult<usize> {
306 let mut iter = self.0.iter().skip(start_idx);
307 for (i, out_entry) in dirents.iter_mut().enumerate() {
308 let x = iter.next();
309 match x {
310 Some(Ok(entry)) => {
311 let ty = if entry.is_dir() {
312 VfsNodeType::Dir
313 } else if entry.is_file() {
314 VfsNodeType::File
315 } else {
316 unreachable!()
317 };
318 *out_entry = VfsDirEntry::new(&entry.file_name(), ty);
319 }
320 _ => return Ok(i),
321 }
322 }
323 Ok(dirents.len())
324 }
325
326 fn rename(&self, src_path: &str, dst_path: &str) -> VfsResult {
327 debug!(
329 "rename at axfatfs, src_path: {}, dst_path: {}",
330 src_path, dst_path
331 );
332
333 self.0
334 .rename(src_path, &self.0, dst_path)
335 .map_err(as_vfs_err)
336 }
337}
338
339impl VfsOps for FatFileSystem {
340 fn root_dir(&self) -> VfsNodeRef {
341 self.root_dir
342 .get_or_init(|| {
343 debug!("Creating root directory for FAT filesystem");
344 let root_dir = self.inner.root_dir();
345 debug!("Successfully got root directory from FAT filesystem");
346 Self::new_dir(root_dir)
347 })
348 .clone()
349 }
350}
351
352impl axfatfs::IoBase for Disk {
353 type Error = ();
354}
355
356impl Read for Disk {
357 fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Self::Error> {
358 let mut read_len = 0;
359 while !buf.is_empty() {
360 match self.read_one(buf) {
361 Ok(0) => break,
362 Ok(n) => {
363 let tmp = buf;
364 buf = &mut tmp[n..];
365 read_len += n;
366 }
367 Err(_) => return Err(()),
368 }
369 }
370 Ok(read_len)
371 }
372}
373
374impl Write for Disk {
375 fn write(&mut self, mut buf: &[u8]) -> Result<usize, Self::Error> {
376 let mut write_len = 0;
377 while !buf.is_empty() {
378 match self.write_one(buf) {
379 Ok(0) => break,
380 Ok(n) => {
381 buf = &buf[n..];
382 write_len += n;
383 }
384 Err(_) => return Err(()),
385 }
386 }
387 Ok(write_len)
388 }
389 fn flush(&mut self) -> Result<(), Self::Error> {
390 Ok(())
391 }
392}
393
394impl Seek for Disk {
395 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
396 let size = self.size();
397 let new_pos = match pos {
398 SeekFrom::Start(pos) => Some(pos),
399 SeekFrom::Current(off) => self.position().checked_add_signed(off),
400 SeekFrom::End(off) => size.checked_add_signed(off),
401 }
402 .ok_or(())?;
403 if new_pos > size {
404 warn!("Seek beyond the end of the block device");
405 }
406 self.set_position(new_pos);
407 Ok(new_pos)
408 }
409}
410
411const fn as_vfs_err(err: axfatfs::Error<()>) -> VfsError {
412 use axfatfs::Error::*;
413 match err {
414 AlreadyExists => VfsError::AlreadyExists,
415 CorruptedFileSystem => VfsError::InvalidData,
416 DirectoryIsNotEmpty => VfsError::DirectoryNotEmpty,
417 InvalidInput | InvalidFileNameLength | UnsupportedFileNameCharacter => {
418 VfsError::InvalidInput
419 }
420 NotEnoughSpace => VfsError::StorageFull,
421 NotFound => VfsError::NotFound,
422 UnexpectedEof => VfsError::UnexpectedEof,
423 WriteZero => VfsError::WriteZero,
424 Io(_) => VfsError::Io,
425 _ => VfsError::Io,
426 }
427}