1use crate::{
2 error::Error,
3 runtime::types::{FdFlags, FdStat, Whence},
4 storage::{
5 Storage,
6 types::{FileSize, FileType, Node},
7 },
8};
9
10#[derive(Clone, Debug)]
11pub struct File {
12 pub node: Node,
13 pub cursor: FileSize,
14 pub stat: FdStat,
15}
16
17impl File {
18 pub fn new(node: Node, stat: FdStat, storage: &dyn Storage) -> Result<Self, Error> {
20 let metadata = storage.get_metadata(node)?;
21 let file_type = metadata.file_type;
22 match file_type {
23 FileType::RegularFile => {}
24 FileType::Directory => {
25 unreachable!("Unexpected file type, expected a regular file.");
26 }
27 FileType::SymbolicLink => unimplemented!("Symbolic links are not implemented yet"),
28 };
29 let cursor = if stat.flags.contains(FdFlags::APPEND) {
30 metadata.size
31 } else {
32 0
33 };
34 Ok(Self { node, cursor, stat })
35 }
36
37 pub fn seek(
39 &mut self,
40 delta: i64,
41 whence: Whence,
42 storage: &dyn Storage,
43 ) -> Result<FileSize, Error> {
44 let size = storage.get_metadata(self.node)?.size;
45 let position = match whence {
46 Whence::SET => {
47 if delta < 0 {
48 return Err(Error::InvalidArgument);
49 }
50 delta as FileSize
51 }
52 Whence::CUR => {
53 let back = if delta < 0 {
54 (-delta).try_into().map_err(|_| Error::InvalidArgument)?
55 } else {
56 0
57 };
58 let fwd = if delta >= 0 { delta as FileSize } else { 0 };
59
60 if self.cursor < back {
61 return Err(Error::InvalidArgument);
63 }
64 self.cursor + fwd - back
65 }
66 Whence::END => {
67 let back: FileSize = (-delta).try_into().map_err(|_| Error::InvalidSeek)?;
68 if back > size {
69 return Err(Error::InvalidSeek);
70 }
71 size - back
72 }
73 };
74 self.cursor = position;
75 Ok(self.cursor)
76 }
77
78 pub fn tell(&self) -> FileSize {
80 self.cursor
81 }
82
83 pub fn read_with_cursor(
85 &mut self,
86 buf: &mut [u8],
87 storage: &mut dyn Storage,
88 ) -> Result<FileSize, Error> {
89 let read_size = self.read_with_offset(self.cursor, buf, storage)?;
90 self.cursor += read_size;
91 Ok(read_size)
92 }
93
94 pub fn read_with_offset(
96 &self,
97 offset: FileSize,
98 buf: &mut [u8],
99 storage: &mut dyn Storage,
100 ) -> Result<FileSize, Error> {
101 if buf.is_empty() {
102 return Ok(0 as FileSize);
103 }
104
105 let read_size = storage.read(self.node, offset, buf)?;
106
107 Ok(read_size as FileSize)
108 }
109
110 pub fn write_with_offset(
112 &self,
113 offset: FileSize,
114 buf: &[u8],
115 storage: &mut dyn Storage,
116 ) -> Result<FileSize, Error> {
117 storage.write(self.node, offset, buf)
118 }
119
120 pub fn truncate(&self, storage: &mut dyn Storage) -> Result<(), Error> {
122 let mut metadata = storage.get_metadata(self.node)?;
123 metadata.size = 0;
124 storage.put_metadata(self.node, &metadata)?;
125 Ok(())
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use crate::{
132 fs::OpenFlags,
133 test_utils::{test_fs_setups, test_stable_fs_v2},
134 };
135
136 use super::*;
137
138 #[test]
139 fn seek_and_tell() {
140 let mut fs = test_stable_fs_v2();
141 let fd = fs
142 .create_open_file(fs.root_fd(), "test", FdStat::default(), 0)
143 .unwrap();
144
145 let mut file = fs.get_test_file(fd);
146 let storage = fs.get_test_storage();
147
148 file.write_with_offset(0, &[0; 1000], storage).unwrap();
149
150 assert_eq!(file.tell(), 0);
151 let pos = file.seek(10, Whence::CUR, storage).unwrap();
152 assert_eq!(pos, 10);
153 assert_eq!(file.tell(), 10);
154
155 let pos = file.seek(-9, Whence::CUR, storage).unwrap();
156 assert_eq!(pos, 1);
157 assert_eq!(file.tell(), 1);
158
159 let err = file.seek(-2, Whence::CUR, storage).unwrap_err();
160 assert_eq!(err, Error::InvalidArgument);
161 assert_eq!(file.tell(), 1);
162
163 let pos = file.seek(0, Whence::END, storage).unwrap();
164 assert_eq!(pos, 1000);
165 assert_eq!(file.tell(), 1000);
166
167 let pos = file.seek(500, Whence::SET, storage).unwrap();
168 assert_eq!(pos, 500);
169 assert_eq!(file.tell(), 500);
170
171 let err = file.seek(-1, Whence::SET, storage).unwrap_err();
172 assert_eq!(err, Error::InvalidArgument);
173 assert_eq!(file.tell(), 500);
174
175 let pos = file.seek(1001, Whence::SET, storage).unwrap();
176 assert_eq!(pos, 1001);
177 assert_eq!(file.tell(), 1001);
178 }
179
180 #[test]
181 fn read_and_write_offset() {
182 let mut fs = test_stable_fs_v2();
183 let fd = fs
184 .create_open_file(fs.root_fd(), "test", FdStat::default(), 0)
185 .unwrap();
186
187 let mut file = fs.get_test_file(fd);
188 let storage = fs.get_test_storage();
189
190 for i in 0..1000 {
191 let buf = [(i % 256) as u8; 16];
192 file.write_with_offset(i * 16, &buf, storage).unwrap();
193 }
194
195 file.seek(-1000 * 16, Whence::END, storage).unwrap();
196 for i in 0..1000 {
197 let mut buf = [0; 16];
198 file.read_with_offset(i * 16, &mut buf, storage).unwrap();
199 let expected = [(i % 256) as u8; 16];
200 assert_eq!(buf, expected);
201 }
202 }
203
204 #[test]
205 fn read_and_write_small_and_big_buffer() {
206 let mut fs = test_stable_fs_v2();
207 let fd = fs
208 .create_open_file(fs.root_fd(), "test", FdStat::default(), 0)
209 .unwrap();
210
211 let file = fs.get_test_file(fd);
212 let storage = fs.get_test_storage();
213
214 for i in 0..1000 {
215 let buf = [(i % 256) as u8; 10];
216 file.write_with_offset(i * 16, &buf, storage).unwrap();
217 }
218
219 for i in 0..1000 {
220 let mut buf1 = [0; 13];
221 let mut buf2 = [0; 5000];
222 let mut buf3 = [0; 15000];
223
224 let r1 = file.read_with_offset(i * 17, &mut buf1, storage).unwrap() as usize;
225 let r2 = file.read_with_offset(i * 17, &mut buf2, storage).unwrap() as usize;
226 let _r3 = file.read_with_offset(i * 17, &mut buf3, storage).unwrap() as usize;
227
228 assert_eq!(buf1[..r1], buf2[..r1]);
229 assert_eq!(buf2[..r2], buf3[..r2]);
230 }
231 }
232
233 #[test]
234 fn read_and_write_offset_chunk() {
235 for mut fs in [test_stable_fs_v2()] {
236 let fd = fs
238 .open(
239 fs.root_fd(),
240 "test",
241 FdStat::default(),
242 OpenFlags::CREATE,
243 0,
244 )
245 .unwrap();
246
247 let mut file = fs.get_test_file(fd);
248 let storage = fs.get_test_storage();
249
250 for i in 0..1000 {
251 let buf = [(i % 256) as u8; 16];
252 file.write_with_offset(i * 16, &buf, storage).unwrap();
253 }
254
255 file.seek(-1000 * 16, Whence::END, storage).unwrap();
256
257 for i in 0..1000 {
258 let mut buf = [0; 16];
259 file.read_with_offset(i * 16, &mut buf, storage).unwrap();
260
261 let expected = [(i % 256) as u8; 16];
262 assert_eq!(buf, expected);
263 }
264 }
265 }
266
267 #[test]
268 fn read_and_write_offset_vs_range() {
269 for mut fs in test_fs_setups("test") {
270 let fd = fs
271 .open(
272 fs.root_fd(),
273 "test",
274 FdStat::default(),
275 OpenFlags::CREATE,
276 0,
277 )
278 .unwrap();
279
280 let file = fs.get_test_file(fd);
281 let storage = fs.get_test_storage();
282
283 for i in 0..1000 {
284 let buf = [(i % 256) as u8; 16];
285 file.write_with_offset(i * 16, &buf, storage).unwrap();
286 }
287
288 for i in 0..1000 {
289 let mut buf1 = [0; 13];
290 let len1 = file.read_with_offset(i * 16, &mut buf1, storage).unwrap();
291
292 let mut buf2 = [0; 13];
293 let len2 = file.read_with_offset(i * 16, &mut buf2, storage).unwrap();
294
295 assert_eq!(buf1, buf2);
296 assert_eq!(len1, len2);
297 }
298
299 for i in 0..2050 {
300 let mut buf1 = [0; 5003];
301 let len1 = file.read_with_offset(i * 13, &mut buf1, storage).unwrap();
302
303 let mut buf2 = [0; 5003];
304 let len2 = file.read_with_offset(i * 13, &mut buf2, storage).unwrap();
305
306 assert_eq!(buf1, buf2);
307 assert_eq!(len1, len2);
308 }
309 }
310 }
311}