1use core::mem::MaybeUninit;
2
3use alloc::{boxed::Box, collections::btree_map::BTreeMap, ffi::CString, vec::Vec};
4use file_system::{
5 Device, Entry, FileIdentifier, FileIdentifierInner, FileSystemIdentifier, FileSystemTraits,
6 Flags, Inode, Kind, LocalFileIdentifier, Metadata, Mode, Path, Permissions, Position, Size,
7 Statistics_type, Time, get_new_file_identifier,
8};
9use futures::block_on;
10use synchronization::{blocking_mutex::raw::CriticalSectionRawMutex, rwlock::RwLock};
11use users::{GroupIdentifier, UserIdentifier};
12
13use super::{Configuration, Directory, File, convert_result, littlefs};
14
15use file_system::{Error, Result};
16
17struct Inner {
18 file_system: littlefs::lfs_t,
19 open_files: BTreeMap<LocalFileIdentifier, File>,
20 open_directories: BTreeMap<LocalFileIdentifier, Directory>,
21}
22
23pub struct FileSystem {
24 inner: RwLock<CriticalSectionRawMutex, Inner>,
25 cache_size: usize,
26}
27
28impl Drop for FileSystem {
29 fn drop(&mut self) {
30 let mut inner = self.write_inner();
32
33 let keys = inner.open_files.keys().cloned().collect::<Vec<_>>();
34
35 for key in keys {
36 if let Some(file) = inner.open_files.remove(&key) {
37 let _ = file.close(&mut inner.file_system);
38 }
39 }
40
41 let configuration =
42 unsafe { Box::from_raw(inner.file_system.cfg as *mut littlefs::lfs_config) };
43
44 let _read_buffer = unsafe {
45 Vec::from_raw_parts(
46 configuration.read_buffer as *mut u8,
47 0,
48 configuration.cache_size as usize,
49 )
50 };
51 let _write_buffer = unsafe {
52 Vec::from_raw_parts(
53 configuration.prog_buffer as *mut u8,
54 0,
55 configuration.cache_size as usize,
56 )
57 };
58 let _look_ahead_buffer = unsafe {
59 Vec::from_raw_parts(
60 configuration.lookahead_buffer as *mut u8,
61 0,
62 configuration.lookahead_size as usize,
63 )
64 };
65
66 let _device = unsafe { Box::from_raw(inner.file_system.cfg.read().context as *mut Device) };
68
69 unsafe {
71 littlefs::lfs_unmount(&mut inner.file_system as *mut _);
72 }
73
74 }
76}
77
78impl FileSystem {
79 pub fn new(device: Device, cache_size: usize) -> Result<Self> {
80 let block_size = device.get_block_size().map_err(|_| Error::InputOutput)?;
81 let size = device.get_size().map_err(|_| Error::InputOutput)?;
82
83 let configuration: littlefs::lfs_config = Configuration::new(
84 device,
85 block_size,
86 usize::from(size),
87 cache_size,
88 cache_size,
89 )
90 .ok_or(Error::InvalidParameter)?
91 .try_into()
92 .map_err(|_| Error::InvalidParameter)?;
93
94 let configuration = Box::new(configuration);
95
96 let mut file_system = MaybeUninit::<littlefs::lfs_t>::uninit();
97
98 convert_result(unsafe {
99 littlefs::lfs_mount(
100 file_system.as_mut_ptr() as *mut _,
101 Box::into_raw(configuration),
102 )
103 })?;
104
105 let inner = Inner {
106 file_system: unsafe { file_system.assume_init() },
107 open_files: BTreeMap::new(),
108 open_directories: BTreeMap::new(),
109 };
110
111 Ok(Self {
112 inner: RwLock::new(inner),
113 cache_size,
114 })
115 }
116
117 pub fn format(device: Device, cache_size: usize) -> Result<()> {
118 let block_size = device.get_block_size().map_err(|_| Error::InputOutput)?;
119 let size = device.get_size().map_err(|_| Error::InputOutput)?;
120
121 let configuration: littlefs::lfs_config = Configuration::new(
122 device,
123 block_size,
124 usize::from(size),
125 cache_size,
126 cache_size,
127 )
128 .ok_or(Error::InvalidParameter)?
129 .try_into()
130 .map_err(|_| Error::InvalidParameter)?;
131
132 let configuration = Box::new(configuration);
133
134 let mut file_system = MaybeUninit::<littlefs::lfs_t>::uninit();
135
136 convert_result(unsafe {
137 littlefs::lfs_format(file_system.as_mut_ptr(), Box::into_raw(configuration))
138 })?;
139
140 Ok(())
141 }
142
143 fn borrow_mutable_inner_2_splitted(
144 inner_2: &mut Inner,
145 ) -> (
146 &mut littlefs::lfs_t,
147 &mut BTreeMap<LocalFileIdentifier, File>,
148 &mut BTreeMap<LocalFileIdentifier, Directory>,
149 ) {
150 (
151 &mut inner_2.file_system,
152 &mut inner_2.open_files,
153 &mut inner_2.open_directories,
154 )
155 }
156
157 #[cfg(target_pointer_width = "64")]
158 const DIRECTORY_FLAG: FileIdentifierInner = 1 << 31;
159 #[cfg(target_pointer_width = "32")]
160 const Directory_flag: FileIdentifierInner = 1 << 15;
161
162 const DIRECTORY_MINIMUM: FileIdentifier = FileIdentifier::new(Self::DIRECTORY_FLAG);
163
164 pub fn is_file(file: LocalFileIdentifier) -> bool {
165 file.split().1 < Self::DIRECTORY_MINIMUM
166 }
167
168 fn read_inner(
169 &self,
170 ) -> synchronization::rwlock::RwLockReadGuard<'_, CriticalSectionRawMutex, Inner> {
171 block_on(self.inner.read())
172 }
173
174 fn write_inner(
175 &self,
176 ) -> synchronization::rwlock::RwLockWriteGuard<'_, CriticalSectionRawMutex, Inner> {
177 block_on(self.inner.write())
178 }
179}
180
181unsafe impl Send for FileSystem {}
182
183unsafe impl Sync for FileSystem {}
184
185impl FileSystemTraits for FileSystem {
186 fn open(
187 &self,
188 task: task::TaskIdentifier,
189 path: &Path,
190 flags: Flags,
191 time: Time,
192 user: UserIdentifier,
193 group: GroupIdentifier,
194 ) -> Result<LocalFileIdentifier> {
195 let mut inner = self.write_inner();
196
197 let file = File::open(
198 &mut inner.file_system,
199 path,
200 flags,
201 self.cache_size,
202 time,
203 user,
204 group,
205 )?;
206
207 let file_identifier = get_new_file_identifier(
208 task,
209 Some(FileIdentifier::MINIMUM),
210 Some(Self::DIRECTORY_MINIMUM),
211 &inner.open_files,
212 )?;
213
214 if inner.open_files.insert(file_identifier, file).is_some() {
215 return Err(Error::InternalError);
216 }
217
218 Ok(file_identifier)
219 }
220
221 fn close(&self, file: LocalFileIdentifier) -> Result<()> {
222 let mut inner = self.write_inner();
223
224 let file = inner
225 .open_files
226 .remove(&file)
227 .ok_or(Error::InvalidIdentifier)?;
228
229 file.close(&mut inner.file_system)?;
230
231 Ok(())
232 }
233
234 fn close_all(&self, task: task::TaskIdentifier) -> Result<()> {
235 let mut inner = self.write_inner();
236
237 let keys = inner
239 .open_files
240 .keys()
241 .filter(|key| key.split().0 == task)
242 .cloned()
243 .collect::<Vec<_>>();
244
245 for key in keys {
247 if let Some(file) = inner.open_files.remove(&key) {
248 file.close(&mut inner.file_system)?;
249 }
250 }
251
252 Ok(())
253 }
254
255 fn duplicate(&self, file: LocalFileIdentifier) -> Result<LocalFileIdentifier> {
256 let (task, _) = file.split();
257
258 let mut inner = self.write_inner();
259
260 let file = inner
261 .open_files
262 .get(&file)
263 .ok_or(Error::InvalidIdentifier)?;
264
265 let file = file.clone();
266
267 let file_identifier = get_new_file_identifier(
268 task,
269 Some(Self::DIRECTORY_MINIMUM),
270 Some(FileIdentifier::MAXIMUM),
271 &inner.open_files,
272 )?;
273
274 if inner.open_files.insert(file_identifier, file).is_some() {
275 return Err(Error::InternalError);
276 }
277
278 Ok(file_identifier)
279 }
280
281 fn transfert(
282 &self,
283 new_task: task::TaskIdentifier,
284 file_identifier: LocalFileIdentifier,
285 new_file: Option<FileIdentifier>,
286 ) -> Result<LocalFileIdentifier> {
287 let mut inner = self.write_inner();
288
289 let file = inner
290 .open_files
291 .remove(&file_identifier)
292 .ok_or(Error::InvalidIdentifier)?;
293
294 let file_identifier = if let Some(new_file) = new_file {
295 let file = LocalFileIdentifier::new(new_task, new_file);
296
297 if inner.open_files.contains_key(&file) {
298 return Err(Error::InvalidIdentifier);
299 }
300
301 file
302 } else if Self::is_file(file_identifier) {
303 get_new_file_identifier(
304 new_task,
305 Some(FileIdentifier::MINIMUM),
306 Some(Self::DIRECTORY_MINIMUM),
307 &inner.open_files,
308 )?
309 } else {
310 get_new_file_identifier(
311 new_task,
312 Some(Self::DIRECTORY_MINIMUM),
313 Some(FileIdentifier::MAXIMUM),
314 &inner.open_directories,
315 )?
316 };
317
318 if inner.open_files.insert(file_identifier, file).is_some() {
319 return Err(Error::InternalError); }
321
322 Ok(file_identifier)
323 }
324
325 fn remove(&self, path: &Path) -> Result<()> {
326 let path = CString::new(path.as_str()).map_err(|_| Error::InvalidParameter)?;
327
328 let mut inner = self.write_inner();
329
330 convert_result(unsafe {
331 littlefs::lfs_remove(&mut inner.file_system as *mut _, path.as_ptr())
332 })?;
333
334 Ok(())
335 }
336
337 fn read(&self, file: LocalFileIdentifier, buffer: &mut [u8], _: Time) -> Result<Size> {
338 let mut inner = self.write_inner();
339
340 let (file_system, open_files, _) = Self::borrow_mutable_inner_2_splitted(&mut inner);
341
342 let file = open_files.get_mut(&file).ok_or(Error::InvalidIdentifier)?;
343
344 file.read(file_system, buffer)
345 }
346
347 fn write(&self, file: LocalFileIdentifier, buffer: &[u8], _: Time) -> Result<Size> {
348 let mut inner = self.write_inner();
349
350 let (file_system, open_files, _) = Self::borrow_mutable_inner_2_splitted(&mut inner);
351
352 let file = open_files.get_mut(&file).ok_or(Error::InvalidIdentifier)?;
353
354 file.write(file_system, buffer)
355 }
356
357 fn rename(&self, source: &Path, destination: &Path) -> Result<()> {
358 let source = CString::new(source.as_str()).map_err(|_| Error::InvalidParameter)?;
359
360 let destination =
361 CString::new(destination.as_str()).map_err(|_| Error::InvalidParameter)?;
362
363 let mut inner = self.write_inner();
364
365 convert_result(unsafe {
366 littlefs::lfs_rename(
367 &mut inner.file_system as *mut _,
368 source.as_ptr(),
369 destination.as_ptr(),
370 )
371 })?;
372
373 Ok(())
374 }
375
376 fn set_position(&self, file: LocalFileIdentifier, position: &Position) -> Result<Size> {
377 let mut inner = self.write_inner();
378
379 let (file_system, open_files, _) = Self::borrow_mutable_inner_2_splitted(&mut inner);
380
381 let file = open_files.get_mut(&file).ok_or(Error::InvalidIdentifier)?;
382
383 file.set_position(file_system, position)
384 }
385
386 fn flush(&self, file: LocalFileIdentifier) -> Result<()> {
387 let mut inner = self.write_inner();
388
389 let (file_system, open_files, _) = Self::borrow_mutable_inner_2_splitted(&mut inner);
390
391 let file = open_files.get_mut(&file).ok_or(Error::InvalidIdentifier)?;
392
393 file.flush(file_system)
394 }
395
396 fn get_statistics(&self, file: LocalFileIdentifier) -> Result<Statistics_type> {
397 let mut inner = self.write_inner();
398
399 let (file_system, open_files, open_directories) =
400 Self::borrow_mutable_inner_2_splitted(&mut inner);
401
402 if open_directories.get_mut(&file).is_some() {
404 let current_time: Time = time::get_instance().get_current_time().unwrap().into();
405
406 Ok(Statistics_type::new(
407 FileSystemIdentifier::new(0),
408 Inode::new(0),
409 1,
410 Size::new(0),
411 current_time,
412 current_time,
413 current_time,
414 Kind::Directory,
415 Permissions::new_default(Kind::Directory),
416 UserIdentifier::new(0),
417 GroupIdentifier::new(0),
418 ))
419 } else if let Some(file) = open_files.get_mut(&file) {
420 Ok(file.get_statistics(file_system)?)
421 } else {
422 Err(Error::InvalidIdentifier)
423 }
424 }
425
426 fn get_mode(&self, file: LocalFileIdentifier) -> Result<Mode> {
427 let inner = self.read_inner();
428
429 let result = if Self::is_file(file) {
430 inner
431 .open_files
432 .get(&file)
433 .ok_or(Error::InvalidIdentifier)?
434 .get_mode()
435 } else {
436 inner
437 .open_directories
438 .get(&file)
439 .ok_or(Error::InvalidIdentifier)?;
440
441 Mode::READ_ONLY
442 };
443
444 Ok(result)
445 }
446
447 fn open_directory(
448 &self,
449 path: &Path,
450 task: task::TaskIdentifier,
451 ) -> Result<LocalFileIdentifier> {
452 let mut inner = self.write_inner();
453
454 let directory = Directory::open(&mut inner.file_system, path)?;
455
456 let file_identifier = get_new_file_identifier(
457 task,
458 Some(Self::DIRECTORY_MINIMUM),
459 Some(FileIdentifier::MAXIMUM),
460 &inner.open_directories,
461 )?;
462
463 if inner
464 .open_directories
465 .insert(file_identifier, directory)
466 .is_some()
467 {
468 return Err(Error::InternalError);
469 }
470
471 Ok(file_identifier)
472 }
473
474 fn read_directory(&self, file: LocalFileIdentifier) -> Result<Option<Entry>> {
475 let mut inner = self.write_inner();
476
477 let (file_system, _, open_directories) = Self::borrow_mutable_inner_2_splitted(&mut inner);
478
479 let directory = open_directories
480 .get_mut(&file)
481 .ok_or(Error::InvalidIdentifier)?;
482
483 directory.read(file_system)
484 }
485
486 fn set_position_directory(&self, file: LocalFileIdentifier, position: Size) -> Result<()> {
487 let mut inner = self.write_inner();
488
489 let (file_system, _, open_directories) = Self::borrow_mutable_inner_2_splitted(&mut inner);
490
491 let directory = open_directories
492 .get_mut(&file)
493 .ok_or(Error::InvalidIdentifier)?;
494
495 directory.set_position(file_system, position)
496 }
497
498 fn rewind_directory(&self, file: LocalFileIdentifier) -> Result<()> {
499 let mut inner = self.write_inner();
500
501 let (file_system, _, open_directories) = Self::borrow_mutable_inner_2_splitted(&mut inner);
502
503 let directory = open_directories
504 .get_mut(&file)
505 .ok_or(Error::InvalidIdentifier)?;
506
507 directory.rewind(file_system)?;
508
509 Ok(())
510 }
511
512 fn close_directory(&self, file: LocalFileIdentifier) -> Result<()> {
513 let mut inner = self.write_inner();
514
515 let (file_system, _, open_directories) = Self::borrow_mutable_inner_2_splitted(&mut inner);
516
517 let mut directory = open_directories
518 .remove(&file)
519 .ok_or(Error::InvalidIdentifier)?;
520
521 directory.close(file_system)?;
522
523 Ok(())
524 }
525
526 fn create_directory(
527 &self,
528 path: &Path,
529
530 time: Time,
531 user: UserIdentifier,
532 group: GroupIdentifier,
533 ) -> Result<()> {
534 let mut inner = self.write_inner();
535
536 Directory::create_directory(&mut inner.file_system, path)?;
537
538 let metadata = Metadata::get_default(Kind::Directory, time, user, group)
539 .ok_or(Error::InvalidParameter)?;
540
541 File::set_metadata_from_path(&mut inner.file_system, path, &metadata)?;
542
543 Ok(())
544 }
545
546 fn get_position_directory(&self, file: LocalFileIdentifier) -> Result<Size> {
547 let mut inner = self.write_inner();
548
549 let (file_system, _, open_directories) = Self::borrow_mutable_inner_2_splitted(&mut inner);
550
551 let directory = open_directories
552 .get_mut(&file)
553 .ok_or(Error::InvalidIdentifier)?;
554
555 directory.get_position(file_system)
556 }
557
558 fn set_metadata_from_path(&self, path: &Path, metadata: &Metadata) -> Result<()> {
559 let mut inner = self.write_inner();
560
561 File::set_metadata_from_path(&mut inner.file_system, path, metadata)?;
562
563 Ok(())
564 }
565
566 fn get_metadata_from_path(&self, path: &Path) -> Result<Metadata> {
567 let mut inner = self.write_inner();
568
569 File::get_metadata_from_path(&mut inner.file_system, path)
570 }
571
572 fn get_metadata(&self, file: LocalFileIdentifier) -> Result<Metadata> {
573 let mut inner = self.write_inner();
574
575 let (_, open_files, _) = Self::borrow_mutable_inner_2_splitted(&mut inner);
576
577 let file = open_files.get_mut(&file).ok_or(Error::InvalidIdentifier)?;
578
579 Ok(file.get_metadata()?.clone())
580 }
581}
582
583#[cfg(test)]
584mod tests {
585 extern crate std;
586
587 use alloc::sync::Arc;
588 use file_system::{MemoryDevice, create_device};
589 use task::test;
590
591 use super::*;
592
593 const CACHE_SIZE: usize = 256;
594
595 fn initialize() -> FileSystem {
596 let _ = users::initialize();
597
598 task::initialize();
599
600 let _ = time::initialize(create_device!(drivers::native::TimeDriver::new()));
601
602 let mock_device = MemoryDevice::<512>::new(2048 * 512);
603
604 let device = Device::new(Arc::new(mock_device));
605
606 FileSystem::format(device.clone(), CACHE_SIZE).unwrap();
607
608 FileSystem::new(device, CACHE_SIZE).unwrap()
609 }
610
611 #[test]
612 async fn test_open_close_delete() {
613 file_system::tests::test_open_close_delete(initialize()).await;
614 }
615
616 #[test]
617 async fn test_read_write() {
618 file_system::tests::test_read_write(initialize()).await;
619 }
620
621 #[test]
622 async fn test_move() {
623 file_system::tests::test_move(initialize()).await;
624 }
625
626 #[test]
627 async fn test_set_position() {
628 file_system::tests::test_set_position(initialize()).await;
629 }
630
631 #[test]
632 async fn test_flush() {
633 file_system::tests::test_flush(initialize()).await;
634 }
635
636 #[test]
637 async fn test_set_get_metadata() {
638 file_system::tests::test_set_get_metadata(initialize()).await;
639 }
640
641 #[test]
642 async fn test_read_directory() {
643 file_system::tests::test_read_directory(initialize()).await;
644 }
645
646 #[test]
647 async fn test_set_position_directory() {
648 file_system::tests::test_set_position_directory(initialize()).await;
649 }
650
651 #[test]
652 async fn test_rewind_directory() {
653 file_system::tests::test_rewind_directory(initialize()).await;
654 }
655
656 #[test]
657 async fn test_create_remove_directory() {
658 file_system::tests::test_create_remove_directory(initialize()).await;
659 }
660
661 #[cfg(feature = "std")]
662 #[test]
663 async fn test_loader() {
664 file_system::tests::test_loader(initialize());
665 }
666}