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