1use alloc::boxed::Box;
2use alloc::vec;
3use alloc::vec::Vec;
4use core::ffi::c_void;
5use core::mem::MaybeUninit;
6
7use littlefs_rust_core::{LfsFile, LfsFileConfig};
8
9use crate::error::{from_lfs_result, from_lfs_size, Error};
10use crate::filesystem::Filesystem;
11use crate::metadata::{OpenFlags, SeekFrom};
12use crate::storage::Storage;
13
14pub(crate) struct FileAllocation {
15 pub(crate) file: MaybeUninit<LfsFile>,
16 _cache: Vec<u8>,
17 pub(crate) file_config: LfsFileConfig,
18}
19
20impl FileAllocation {
21 pub(crate) fn new(cache_size: u32) -> Self {
22 let mut cache = vec![0u8; cache_size as usize];
23 let file_config = LfsFileConfig {
24 buffer: cache.as_mut_ptr() as *mut c_void,
25 attrs: core::ptr::null_mut(),
26 attr_count: 0,
27 };
28 Self {
29 file: MaybeUninit::zeroed(),
30 _cache: cache,
31 file_config,
32 }
33 }
34}
35
36pub struct File<'a, S: Storage> {
41 fs: &'a Filesystem<S>,
42 alloc: Box<FileAllocation>,
43 closed: bool,
44}
45
46impl<'a, S: Storage> File<'a, S> {
47 pub(crate) fn open(fs: &'a Filesystem<S>, path: &str, flags: OpenFlags) -> Result<Self, Error> {
48 let mut alloc = Box::new(FileAllocation::new(fs.cache_size()));
49 let path_bytes = null_terminate(path);
50 {
51 let mut inner = fs.inner.borrow_mut();
52 let rc = littlefs_rust_core::lfs_file_opencfg(
53 inner.lfs.as_mut_ptr(),
54 alloc.file.as_mut_ptr(),
55 path_bytes.as_ptr(),
56 flags.bits() as i32,
57 &alloc.file_config as *const LfsFileConfig,
58 );
59 from_lfs_result(rc)?;
60 }
61 Ok(File {
62 fs,
63 alloc,
64 closed: false,
65 })
66 }
67
68 pub fn read(&self, buf: &mut [u8]) -> Result<u32, Error> {
71 let mut inner = self.fs.inner.borrow_mut();
72 let rc = littlefs_rust_core::lfs_file_read(
73 inner.lfs.as_mut_ptr(),
74 self.alloc.file.as_ptr() as *mut LfsFile,
75 buf.as_mut_ptr() as *mut c_void,
76 buf.len() as u32,
77 );
78 drop(inner);
79 from_lfs_size(rc)
80 }
81
82 pub fn write(&self, data: &[u8]) -> Result<u32, Error> {
84 let mut inner = self.fs.inner.borrow_mut();
85 let rc = littlefs_rust_core::lfs_file_write(
86 inner.lfs.as_mut_ptr(),
87 self.alloc.file.as_ptr() as *mut LfsFile,
88 data.as_ptr() as *const c_void,
89 data.len() as u32,
90 );
91 drop(inner);
92 from_lfs_size(rc)
93 }
94
95 pub fn seek(&self, pos: SeekFrom) -> Result<u32, Error> {
97 let (off, whence) = match pos {
98 SeekFrom::Start(n) => (
99 n as i32,
100 littlefs_rust_core::lfs_type::lfs_whence_flags::LFS_SEEK_SET,
101 ),
102 SeekFrom::Current(n) => (
103 n,
104 littlefs_rust_core::lfs_type::lfs_whence_flags::LFS_SEEK_CUR,
105 ),
106 SeekFrom::End(n) => (
107 n,
108 littlefs_rust_core::lfs_type::lfs_whence_flags::LFS_SEEK_END,
109 ),
110 };
111 let mut inner = self.fs.inner.borrow_mut();
112 let rc = littlefs_rust_core::lfs_file_seek(
113 inner.lfs.as_mut_ptr(),
114 self.alloc.file.as_ptr() as *mut LfsFile,
115 off,
116 whence,
117 );
118 drop(inner);
119 from_lfs_size(rc)
120 }
121
122 pub fn tell(&self) -> u32 {
124 let mut inner = self.fs.inner.borrow_mut();
125 let rc = littlefs_rust_core::lfs_file_tell(
126 inner.lfs.as_mut_ptr(),
127 self.alloc.file.as_ptr() as *mut LfsFile,
128 );
129 drop(inner);
130 rc as u32
131 }
132
133 pub fn size(&self) -> u32 {
135 let mut inner = self.fs.inner.borrow_mut();
136 let rc = littlefs_rust_core::lfs_file_size(
137 inner.lfs.as_mut_ptr(),
138 self.alloc.file.as_ptr() as *mut LfsFile,
139 );
140 drop(inner);
141 rc as u32
142 }
143
144 pub fn sync(&self) -> Result<(), Error> {
146 let mut inner = self.fs.inner.borrow_mut();
147 let rc = littlefs_rust_core::lfs_file_sync(
148 inner.lfs.as_mut_ptr(),
149 self.alloc.file.as_ptr() as *mut LfsFile,
150 );
151 drop(inner);
152 from_lfs_result(rc)
153 }
154
155 pub fn truncate(&self, size: u32) -> Result<(), Error> {
157 let mut inner = self.fs.inner.borrow_mut();
158 let rc = littlefs_rust_core::lfs_file_truncate(
159 inner.lfs.as_mut_ptr(),
160 self.alloc.file.as_ptr() as *mut LfsFile,
161 size,
162 );
163 drop(inner);
164 from_lfs_result(rc)
165 }
166
167 pub fn close(mut self) -> Result<(), Error> {
171 self.closed = true;
172 let mut inner = self.fs.inner.borrow_mut();
173 let rc = littlefs_rust_core::lfs_file_close(
174 inner.lfs.as_mut_ptr(),
175 self.alloc.file.as_ptr() as *mut LfsFile,
176 );
177 from_lfs_result(rc)
178 }
179}
180
181impl<S: Storage> Drop for File<'_, S> {
182 fn drop(&mut self) {
183 if !self.closed {
184 if let Ok(mut inner) = self.fs.inner.try_borrow_mut() {
185 let _ = littlefs_rust_core::lfs_file_close(
186 inner.lfs.as_mut_ptr(),
187 self.alloc.file.as_ptr() as *mut LfsFile,
188 );
189 }
190 }
191 }
192}
193
194fn null_terminate(s: &str) -> Vec<u8> {
195 let mut v: Vec<u8> = s.bytes().collect();
196 v.push(0);
197 v
198}