1use alloc::string::{String, ToString};
2use core::fmt::Display;
3use crc::{Crc, CRC_32_CKSUM};
4use spacepackets::cfdp::ChecksumType;
5use spacepackets::ByteConversionError;
6#[cfg(feature = "std")]
7use std::error::Error;
8use std::path::Path;
9#[cfg(feature = "std")]
10pub use stdmod::*;
11
12pub const CRC_32: Crc<u32> = Crc::<u32>::new(&CRC_32_CKSUM);
13
14#[derive(Debug, Clone)]
15pub enum FilestoreError {
16 FileDoesNotExist,
17 FileAlreadyExists,
18 DirDoesNotExist,
19 Permission,
20 IsNotFile,
21 IsNotDirectory,
22 ByteConversion(ByteConversionError),
23 Io {
24 raw_errno: Option<i32>,
25 string: String,
26 },
27 ChecksumTypeNotImplemented(ChecksumType),
28}
29
30impl From<ByteConversionError> for FilestoreError {
31 fn from(value: ByteConversionError) -> Self {
32 Self::ByteConversion(value)
33 }
34}
35
36impl Display for FilestoreError {
37 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38 match self {
39 FilestoreError::FileDoesNotExist => {
40 write!(f, "file does not exist")
41 }
42 FilestoreError::FileAlreadyExists => {
43 write!(f, "file already exists")
44 }
45 FilestoreError::DirDoesNotExist => {
46 write!(f, "directory does not exist")
47 }
48 FilestoreError::Permission => {
49 write!(f, "permission error")
50 }
51 FilestoreError::IsNotFile => {
52 write!(f, "is not a file")
53 }
54 FilestoreError::IsNotDirectory => {
55 write!(f, "is not a directory")
56 }
57 FilestoreError::ByteConversion(e) => {
58 write!(f, "filestore error: {e}")
59 }
60 FilestoreError::Io { raw_errno, string } => {
61 write!(
62 f,
63 "filestore generic IO error with raw errno {:?}: {}",
64 raw_errno, string
65 )
66 }
67 FilestoreError::ChecksumTypeNotImplemented(checksum_type) => {
68 write!(f, "checksum {:?} not implemented", checksum_type)
69 }
70 }
71 }
72}
73
74impl Error for FilestoreError {
75 fn source(&self) -> Option<&(dyn Error + 'static)> {
76 match self {
77 FilestoreError::ByteConversion(e) => Some(e),
78 _ => None,
79 }
80 }
81}
82
83#[cfg(feature = "std")]
84impl From<std::io::Error> for FilestoreError {
85 fn from(value: std::io::Error) -> Self {
86 Self::Io {
87 raw_errno: value.raw_os_error(),
88 string: value.to_string(),
89 }
90 }
91}
92
93pub trait VirtualFilestore {
94 fn create_file(&self, file_path: &str) -> Result<(), FilestoreError>;
95
96 fn remove_file(&self, file_path: &str) -> Result<(), FilestoreError>;
97
98 fn truncate_file(&self, file_path: &str) -> Result<(), FilestoreError>;
101
102 fn remove_dir(&self, dir_path: &str, all: bool) -> Result<(), FilestoreError>;
103 fn create_dir(&self, dir_path: &str) -> Result<(), FilestoreError>;
104
105 fn read_data(
106 &self,
107 file_path: &str,
108 offset: u64,
109 read_len: u64,
110 buf: &mut [u8],
111 ) -> Result<(), FilestoreError>;
112
113 fn write_data(&self, file: &str, offset: u64, buf: &[u8]) -> Result<(), FilestoreError>;
114
115 fn filename_from_full_path(path: &str) -> Option<&str>
116 where
117 Self: Sized,
118 {
119 let path = Path::new(path);
121
122 path.file_name().and_then(|name| name.to_str())
124 }
125
126 fn is_file(&self, path: &str) -> bool;
127
128 fn is_dir(&self, path: &str) -> bool {
129 !self.is_file(path)
130 }
131
132 fn exists(&self, path: &str) -> bool;
133
134 fn checksum_verify(
142 &self,
143 file_path: &str,
144 checksum_type: ChecksumType,
145 expected_checksum: u32,
146 verification_buf: &mut [u8],
147 ) -> Result<bool, FilestoreError>;
148}
149
150#[cfg(feature = "std")]
151pub mod stdmod {
152 use super::*;
153 use std::{
154 fs::{self, File, OpenOptions},
155 io::{BufReader, Read, Seek, SeekFrom, Write},
156 path::Path,
157 };
158
159 #[derive(Default)]
160 pub struct NativeFilestore {}
161
162 impl VirtualFilestore for NativeFilestore {
163 fn create_file(&self, file_path: &str) -> Result<(), FilestoreError> {
164 if self.exists(file_path) {
165 return Err(FilestoreError::FileAlreadyExists);
166 }
167 File::create(file_path)?;
168 Ok(())
169 }
170
171 fn remove_file(&self, file_path: &str) -> Result<(), FilestoreError> {
172 if !self.exists(file_path) {
173 return Err(FilestoreError::FileDoesNotExist);
174 }
175 if !self.is_file(file_path) {
176 return Err(FilestoreError::IsNotFile);
177 }
178 fs::remove_file(file_path)?;
179 Ok(())
180 }
181
182 fn truncate_file(&self, file_path: &str) -> Result<(), FilestoreError> {
183 if !self.exists(file_path) {
184 return Err(FilestoreError::FileDoesNotExist);
185 }
186 if !self.is_file(file_path) {
187 return Err(FilestoreError::IsNotFile);
188 }
189 OpenOptions::new()
190 .write(true)
191 .truncate(true)
192 .open(file_path)?;
193 Ok(())
194 }
195
196 fn create_dir(&self, dir_path: &str) -> Result<(), FilestoreError> {
197 fs::create_dir(dir_path).map_err(|e| FilestoreError::Io {
198 raw_errno: e.raw_os_error(),
199 string: e.to_string(),
200 })?;
201 Ok(())
202 }
203
204 fn remove_dir(&self, dir_path: &str, all: bool) -> Result<(), FilestoreError> {
205 if !self.exists(dir_path) {
206 return Err(FilestoreError::DirDoesNotExist);
207 }
208 if !self.is_dir(dir_path) {
209 return Err(FilestoreError::IsNotDirectory);
210 }
211 if !all {
212 fs::remove_dir(dir_path)?;
213 return Ok(());
214 }
215 fs::remove_dir_all(dir_path)?;
216 Ok(())
217 }
218
219 fn read_data(
220 &self,
221 file_name: &str,
222 offset: u64,
223 read_len: u64,
224 buf: &mut [u8],
225 ) -> Result<(), FilestoreError> {
226 if buf.len() < read_len as usize {
227 return Err(ByteConversionError::ToSliceTooSmall {
228 found: buf.len(),
229 expected: read_len as usize,
230 }
231 .into());
232 }
233 if !self.exists(file_name) {
234 return Err(FilestoreError::FileDoesNotExist);
235 }
236 if !self.is_file(file_name) {
237 return Err(FilestoreError::IsNotFile);
238 }
239 let mut file = File::open(file_name)?;
240 file.seek(SeekFrom::Start(offset))?;
241 file.read_exact(&mut buf[0..read_len as usize])?;
242 Ok(())
243 }
244
245 fn write_data(&self, file: &str, offset: u64, buf: &[u8]) -> Result<(), FilestoreError> {
246 if !self.exists(file) {
247 return Err(FilestoreError::FileDoesNotExist);
248 }
249 if !self.is_file(file) {
250 return Err(FilestoreError::IsNotFile);
251 }
252 let mut file = OpenOptions::new().write(true).open(file)?;
253 file.seek(SeekFrom::Start(offset))?;
254 file.write_all(buf)?;
255 Ok(())
256 }
257
258 fn is_file(&self, path: &str) -> bool {
259 let path = Path::new(path);
260 path.is_file()
261 }
262
263 fn exists(&self, path: &str) -> bool {
264 let path = Path::new(path);
265 if !path.exists() {
266 return false;
267 }
268 true
269 }
270
271 fn checksum_verify(
272 &self,
273 file_path: &str,
274 checksum_type: ChecksumType,
275 expected_checksum: u32,
276 verification_buf: &mut [u8],
277 ) -> Result<bool, FilestoreError> {
278 match checksum_type {
279 ChecksumType::Modular => {
280 if self.calc_modular_checksum(file_path)? == expected_checksum {
281 return Ok(true);
282 }
283 Ok(false)
284 }
285 ChecksumType::Crc32 => {
286 let mut digest = CRC_32.digest();
287 let file_to_check = File::open(file_path)?;
288 let mut buf_reader = BufReader::new(file_to_check);
289 loop {
290 let bytes_read = buf_reader.read(verification_buf)?;
291 if bytes_read == 0 {
292 break;
293 }
294 digest.update(&verification_buf[0..bytes_read]);
295 }
296 if digest.finalize() == expected_checksum {
297 return Ok(true);
298 }
299 Ok(false)
300 }
301 ChecksumType::NullChecksum => Ok(true),
302 _ => Err(FilestoreError::ChecksumTypeNotImplemented(checksum_type)),
303 }
304 }
305 }
306
307 impl NativeFilestore {
308 pub fn calc_modular_checksum(&self, file_path: &str) -> Result<u32, FilestoreError> {
309 let mut checksum: u32 = 0;
310 let file = File::open(file_path)?;
311 let mut buf_reader = BufReader::new(file);
312 let mut buffer = [0; 4];
313
314 loop {
315 let bytes_read = buf_reader.read(&mut buffer)?;
316 if bytes_read == 0 {
317 break;
318 }
319 (bytes_read..4).for_each(|i| {
321 buffer[i] = 0;
322 });
323
324 checksum = checksum.wrapping_add(u32::from_be_bytes(buffer));
325 }
326 Ok(checksum)
327 }
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use std::{fs, path::Path, println};
334
335 use super::*;
336 use alloc::format;
337 use tempfile::tempdir;
338
339 const EXAMPLE_DATA_CFDP: [u8; 15] = [
340 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
341 ];
342
343 const NATIVE_FS: NativeFilestore = NativeFilestore {};
344
345 #[test]
346 fn test_basic_native_filestore_create() {
347 let tmpdir = tempdir().expect("creating tmpdir failed");
348 let file_path = tmpdir.path().join("test.txt");
349 let result =
350 NATIVE_FS.create_file(file_path.to_str().expect("getting str for file failed"));
351 assert!(result.is_ok());
352 let path = Path::new(&file_path);
353 assert!(path.exists());
354 assert!(NATIVE_FS.exists(file_path.to_str().unwrap()));
355 assert!(NATIVE_FS.is_file(file_path.to_str().unwrap()));
356 }
357
358 #[test]
359 fn test_basic_native_fs_file_exists() {
360 let tmpdir = tempdir().expect("creating tmpdir failed");
361 let file_path = tmpdir.path().join("test.txt");
362 assert!(!NATIVE_FS.exists(file_path.to_str().unwrap()));
363 NATIVE_FS
364 .create_file(file_path.to_str().expect("getting str for file failed"))
365 .unwrap();
366 assert!(NATIVE_FS.exists(file_path.to_str().unwrap()));
367 assert!(NATIVE_FS.is_file(file_path.to_str().unwrap()));
368 }
369
370 #[test]
371 fn test_basic_native_fs_dir_exists() {
372 let tmpdir = tempdir().expect("creating tmpdir failed");
373 let dir_path = tmpdir.path().join("testdir");
374 assert!(!NATIVE_FS.exists(dir_path.to_str().unwrap()));
375 NATIVE_FS
376 .create_dir(dir_path.to_str().expect("getting str for file failed"))
377 .unwrap();
378 assert!(NATIVE_FS.exists(dir_path.to_str().unwrap()));
379 assert!(NATIVE_FS.is_dir(dir_path.as_path().to_str().unwrap()));
380 }
381
382 #[test]
383 fn test_basic_native_fs_remove_file() {
384 let tmpdir = tempdir().expect("creating tmpdir failed");
385 let file_path = tmpdir.path().join("test.txt");
386 NATIVE_FS
387 .create_file(file_path.to_str().expect("getting str for file failed"))
388 .expect("creating file failed");
389 assert!(NATIVE_FS.exists(file_path.to_str().unwrap()));
390 NATIVE_FS
391 .remove_file(file_path.to_str().unwrap())
392 .expect("removing file failed");
393 assert!(!NATIVE_FS.exists(file_path.to_str().unwrap()));
394 }
395
396 #[test]
397 fn test_basic_native_fs_write() {
398 let tmpdir = tempdir().expect("creating tmpdir failed");
399 let file_path = tmpdir.path().join("test.txt");
400 assert!(!NATIVE_FS.exists(file_path.to_str().unwrap()));
401 NATIVE_FS
402 .create_file(file_path.to_str().expect("getting str for file failed"))
403 .unwrap();
404 assert!(NATIVE_FS.exists(file_path.to_str().unwrap()));
405 assert!(NATIVE_FS.is_file(file_path.to_str().unwrap()));
406 println!("{}", file_path.to_str().unwrap());
407 let write_data = "hello world\n";
408 NATIVE_FS
409 .write_data(file_path.to_str().unwrap(), 0, write_data.as_bytes())
410 .expect("writing to file failed");
411 let read_back = fs::read_to_string(file_path).expect("reading back data failed");
412 assert_eq!(read_back, write_data);
413 }
414
415 #[test]
416 fn test_basic_native_fs_read() {
417 let tmpdir = tempdir().expect("creating tmpdir failed");
418 let file_path = tmpdir.path().join("test.txt");
419 assert!(!NATIVE_FS.exists(file_path.to_str().unwrap()));
420 NATIVE_FS
421 .create_file(file_path.to_str().expect("getting str for file failed"))
422 .unwrap();
423 assert!(NATIVE_FS.exists(file_path.to_str().unwrap()));
424 assert!(NATIVE_FS.is_file(file_path.to_str().unwrap()));
425 println!("{}", file_path.to_str().unwrap());
426 let write_data = "hello world\n";
427 NATIVE_FS
428 .write_data(file_path.to_str().unwrap(), 0, write_data.as_bytes())
429 .expect("writing to file failed");
430 let read_back = fs::read_to_string(file_path).expect("reading back data failed");
431 assert_eq!(read_back, write_data);
432 }
433
434 #[test]
435 fn test_truncate_file() {
436 let tmpdir = tempdir().expect("creating tmpdir failed");
437 let file_path = tmpdir.path().join("test.txt");
438 NATIVE_FS
439 .create_file(file_path.to_str().expect("getting str for file failed"))
440 .expect("creating file failed");
441 fs::write(file_path.clone(), [1, 2, 3, 4]).unwrap();
442 assert_eq!(fs::read(file_path.clone()).unwrap(), [1, 2, 3, 4]);
443 NATIVE_FS
444 .truncate_file(file_path.to_str().unwrap())
445 .unwrap();
446 assert_eq!(fs::read(file_path.clone()).unwrap(), []);
447 }
448
449 #[test]
450 fn test_remove_dir() {
451 let tmpdir = tempdir().expect("creating tmpdir failed");
452 let dir_path = tmpdir.path().join("testdir");
453 assert!(!NATIVE_FS.exists(dir_path.to_str().unwrap()));
454 NATIVE_FS
455 .create_dir(dir_path.to_str().expect("getting str for file failed"))
456 .unwrap();
457 assert!(NATIVE_FS.exists(dir_path.to_str().unwrap()));
458 NATIVE_FS
459 .remove_dir(dir_path.to_str().unwrap(), false)
460 .unwrap();
461 assert!(!NATIVE_FS.exists(dir_path.to_str().unwrap()));
462 }
463
464 #[test]
465 fn test_read_file() {
466 let tmpdir = tempdir().expect("creating tmpdir failed");
467 let file_path = tmpdir.path().join("test.txt");
468 NATIVE_FS
469 .create_file(file_path.to_str().expect("getting str for file failed"))
470 .expect("creating file failed");
471 fs::write(file_path.clone(), [1, 2, 3, 4]).unwrap();
472 let read_buf: &mut [u8] = &mut [0; 4];
473 NATIVE_FS
474 .read_data(file_path.to_str().unwrap(), 0, 4, read_buf)
475 .unwrap();
476 assert_eq!([1, 2, 3, 4], read_buf);
477 NATIVE_FS
478 .write_data(file_path.to_str().unwrap(), 4, &[5, 6, 7, 8])
479 .expect("writing to file failed");
480 NATIVE_FS
481 .read_data(file_path.to_str().unwrap(), 2, 4, read_buf)
482 .unwrap();
483 assert_eq!([3, 4, 5, 6], read_buf);
484 }
485
486 #[test]
487 fn test_remove_which_does_not_exist() {
488 let tmpdir = tempdir().expect("creating tmpdir failed");
489 let file_path = tmpdir.path().join("test.txt");
490 let result = NATIVE_FS.read_data(file_path.to_str().unwrap(), 0, 4, &mut [0; 4]);
491 assert!(result.is_err());
492 let error = result.unwrap_err();
493 if let FilestoreError::FileDoesNotExist = error {
494 assert_eq!(error.to_string(), "file does not exist");
495 } else {
496 panic!("unexpected error");
497 }
498 }
499
500 #[test]
501 fn test_file_already_exists() {
502 let tmpdir = tempdir().expect("creating tmpdir failed");
503 let file_path = tmpdir.path().join("test.txt");
504 let result =
505 NATIVE_FS.create_file(file_path.to_str().expect("getting str for file failed"));
506 assert!(result.is_ok());
507 let result =
508 NATIVE_FS.create_file(file_path.to_str().expect("getting str for file failed"));
509 assert!(result.is_err());
510 let error = result.unwrap_err();
511 if let FilestoreError::FileAlreadyExists = error {
512 assert_eq!(error.to_string(), "file already exists");
513 } else {
514 panic!("unexpected error");
515 }
516 }
517
518 #[test]
519 fn test_remove_file_with_dir_api() {
520 let tmpdir = tempdir().expect("creating tmpdir failed");
521 let file_path = tmpdir.path().join("test.txt");
522 NATIVE_FS
523 .create_file(file_path.to_str().expect("getting str for file failed"))
524 .unwrap();
525 let result = NATIVE_FS.remove_dir(file_path.to_str().unwrap(), true);
526 assert!(result.is_err());
527 let error = result.unwrap_err();
528 if let FilestoreError::IsNotDirectory = error {
529 assert_eq!(error.to_string(), "is not a directory");
530 } else {
531 panic!("unexpected error");
532 }
533 }
534
535 #[test]
536 fn test_remove_dir_remove_all() {
537 let tmpdir = tempdir().expect("creating tmpdir failed");
538 let dir_path = tmpdir.path().join("test");
539 NATIVE_FS
540 .create_dir(dir_path.to_str().expect("getting str for file failed"))
541 .unwrap();
542 let file_path = dir_path.as_path().join("test.txt");
543 NATIVE_FS
544 .create_file(file_path.to_str().expect("getting str for file failed"))
545 .unwrap();
546 let result = NATIVE_FS.remove_dir(dir_path.to_str().unwrap(), true);
547 assert!(result.is_ok());
548 assert!(!NATIVE_FS.exists(dir_path.to_str().unwrap()));
549 }
550
551 #[test]
552 fn test_remove_dir_with_file_api() {
553 let tmpdir = tempdir().expect("creating tmpdir failed");
554 let file_path = tmpdir.path().join("test");
555 NATIVE_FS
556 .create_dir(file_path.to_str().expect("getting str for file failed"))
557 .unwrap();
558 let result = NATIVE_FS.remove_file(file_path.to_str().unwrap());
559 assert!(result.is_err());
560 let error = result.unwrap_err();
561 if let FilestoreError::IsNotFile = error {
562 assert_eq!(error.to_string(), "is not a file");
563 } else {
564 panic!("unexpected error");
565 }
566 }
567
568 #[test]
569 fn test_remove_dir_which_does_not_exist() {
570 let tmpdir = tempdir().expect("creating tmpdir failed");
571 let file_path = tmpdir.path().join("test");
572 let result = NATIVE_FS.remove_dir(file_path.to_str().unwrap(), true);
573 assert!(result.is_err());
574 let error = result.unwrap_err();
575 if let FilestoreError::DirDoesNotExist = error {
576 assert_eq!(error.to_string(), "directory does not exist");
577 } else {
578 panic!("unexpected error");
579 }
580 }
581
582 #[test]
583 fn test_remove_file_which_does_not_exist() {
584 let tmpdir = tempdir().expect("creating tmpdir failed");
585 let file_path = tmpdir.path().join("test.txt");
586 let result = NATIVE_FS.remove_file(file_path.to_str().unwrap());
587 assert!(result.is_err());
588 let error = result.unwrap_err();
589 if let FilestoreError::FileDoesNotExist = error {
590 assert_eq!(error.to_string(), "file does not exist");
591 } else {
592 panic!("unexpected error");
593 }
594 }
595
596 #[test]
597 fn test_truncate_file_which_does_not_exist() {
598 let tmpdir = tempdir().expect("creating tmpdir failed");
599 let file_path = tmpdir.path().join("test.txt");
600 let result = NATIVE_FS.truncate_file(file_path.to_str().unwrap());
601 assert!(result.is_err());
602 let error = result.unwrap_err();
603 if let FilestoreError::FileDoesNotExist = error {
604 assert_eq!(error.to_string(), "file does not exist");
605 } else {
606 panic!("unexpected error");
607 }
608 }
609
610 #[test]
611 fn test_truncate_file_on_directory() {
612 let tmpdir = tempdir().expect("creating tmpdir failed");
613 let file_path = tmpdir.path().join("test");
614 NATIVE_FS.create_dir(file_path.to_str().unwrap()).unwrap();
615 let result = NATIVE_FS.truncate_file(file_path.to_str().unwrap());
616 assert!(result.is_err());
617 let error = result.unwrap_err();
618 if let FilestoreError::IsNotFile = error {
619 assert_eq!(error.to_string(), "is not a file");
620 } else {
621 panic!("unexpected error");
622 }
623 }
624
625 #[test]
626 fn test_byte_conversion_error_when_reading() {
627 let tmpdir = tempdir().expect("creating tmpdir failed");
628 let file_path = tmpdir.path().join("test.txt");
629 NATIVE_FS
630 .create_file(file_path.to_str().expect("getting str for file failed"))
631 .unwrap();
632 let result = NATIVE_FS.read_data(file_path.to_str().unwrap(), 0, 2, &mut []);
633 assert!(result.is_err());
634 let error = result.unwrap_err();
635 if let FilestoreError::ByteConversion(byte_conv_error) = error {
636 if let ByteConversionError::ToSliceTooSmall { found, expected } = byte_conv_error {
637 assert_eq!(found, 0);
638 assert_eq!(expected, 2);
639 } else {
640 panic!("unexpected error");
641 }
642 assert_eq!(
643 error.to_string(),
644 format!("filestore error: {}", byte_conv_error)
645 );
646 } else {
647 panic!("unexpected error");
648 }
649 }
650
651 #[test]
652 fn test_read_file_on_dir() {
653 let tmpdir = tempdir().expect("creating tmpdir failed");
654 let dir_path = tmpdir.path().join("test");
655 NATIVE_FS
656 .create_dir(dir_path.to_str().expect("getting str for file failed"))
657 .unwrap();
658 let result = NATIVE_FS.read_data(dir_path.to_str().unwrap(), 0, 4, &mut [0; 4]);
659 assert!(result.is_err());
660 let error = result.unwrap_err();
661 if let FilestoreError::IsNotFile = error {
662 assert_eq!(error.to_string(), "is not a file");
663 } else {
664 panic!("unexpected error");
665 }
666 }
667
668 #[test]
669 fn test_write_file_non_existing() {
670 let tmpdir = tempdir().expect("creating tmpdir failed");
671 let file_path = tmpdir.path().join("test.txt");
672 let result = NATIVE_FS.write_data(file_path.to_str().unwrap(), 0, &[]);
673 assert!(result.is_err());
674 let error = result.unwrap_err();
675 if let FilestoreError::FileDoesNotExist = error {
676 } else {
677 panic!("unexpected error");
678 }
679 }
680
681 #[test]
682 fn test_write_file_on_dir() {
683 let tmpdir = tempdir().expect("creating tmpdir failed");
684 let file_path = tmpdir.path().join("test");
685 NATIVE_FS.create_dir(file_path.to_str().unwrap()).unwrap();
686 let result = NATIVE_FS.write_data(file_path.to_str().unwrap(), 0, &[]);
687 assert!(result.is_err());
688 let error = result.unwrap_err();
689 if let FilestoreError::IsNotFile = error {
690 } else {
691 panic!("unexpected error");
692 }
693 }
694
695 #[test]
696 fn test_filename_extraction() {
697 let tmpdir = tempdir().expect("creating tmpdir failed");
698 let file_path = tmpdir.path().join("test.txt");
699 NATIVE_FS
700 .create_file(file_path.to_str().expect("getting str for file failed"))
701 .unwrap();
702 NativeFilestore::filename_from_full_path(file_path.to_str().unwrap());
703 }
704
705 #[test]
706 fn test_modular_checksum() {
707 let tmpdir = tempdir().expect("creating tmpdir failed");
708 let file_path = tmpdir.path().join("mod-crc.bin");
709 fs::write(file_path.as_path(), EXAMPLE_DATA_CFDP).expect("writing test file failed");
710 let mut checksum: u32 = 0;
713 let mut buffer: [u8; 4] = [0; 4];
714 for i in 0..3 {
715 buffer = EXAMPLE_DATA_CFDP[i * 4..(i + 1) * 4].try_into().unwrap();
716 checksum = checksum.wrapping_add(u32::from_be_bytes(buffer));
717 }
718 buffer[0..3].copy_from_slice(&EXAMPLE_DATA_CFDP[12..15]);
719 buffer[3] = 0;
720 checksum = checksum.wrapping_add(u32::from_be_bytes(buffer));
721 let mut verif_buf: [u8; 32] = [0; 32];
722 let result = NATIVE_FS.checksum_verify(
723 file_path.to_str().unwrap(),
724 ChecksumType::Modular,
725 checksum,
726 &mut verif_buf,
727 );
728 assert!(result.is_ok());
729 }
730
731 #[test]
732 fn test_null_checksum_impl() {
733 let tmpdir = tempdir().expect("creating tmpdir failed");
734 let file_path = tmpdir.path().join("mod-crc.bin");
735 let result = NATIVE_FS.checksum_verify(
738 file_path.to_str().unwrap(),
739 ChecksumType::NullChecksum,
740 0,
741 &mut [],
742 );
743 assert!(result.is_ok());
744 assert!(result.unwrap());
745 }
746
747 #[test]
748 fn test_checksum_not_implemented() {
749 let tmpdir = tempdir().expect("creating tmpdir failed");
750 let file_path = tmpdir.path().join("mod-crc.bin");
751 let result = NATIVE_FS.checksum_verify(
754 file_path.to_str().unwrap(),
755 ChecksumType::Crc32Proximity1,
756 0,
757 &mut [],
758 );
759 assert!(result.is_err());
760 let error = result.unwrap_err();
761 if let FilestoreError::ChecksumTypeNotImplemented(cksum_type) = error {
762 assert_eq!(
763 error.to_string(),
764 format!("checksum {:?} not implemented", cksum_type)
765 );
766 } else {
767 panic!("unexpected error");
768 }
769 }
770}