keramics_vfs/
file_system.rs

1/* Copyright 2024-2025 Joachim Metz <joachim.metz@gmail.com>
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may
5 * obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 * License for the specific language governing permissions and limitations
11 * under the License.
12 */
13
14use std::path::Path;
15use std::sync::Arc;
16
17use keramics_core::{DataStreamReference, ErrorTrace};
18use keramics_formats::ext::{ExtFileEntry, ExtFileSystem};
19use keramics_formats::ntfs::{NtfsFileEntry, NtfsFileSystem};
20
21use super::apm::{ApmFileEntry, ApmFileSystem};
22use super::enums::VfsType;
23use super::ewf::{EwfFileEntry, EwfFileSystem};
24use super::fake::{FakeFileEntry, FakeFileSystem};
25use super::file_entry::VfsFileEntry;
26use super::gpt::{GptFileEntry, GptFileSystem};
27use super::location::VfsLocation;
28use super::mbr::{MbrFileEntry, MbrFileSystem};
29use super::os::OsFileEntry;
30use super::path::VfsPath;
31use super::qcow::{QcowFileEntry, QcowFileSystem};
32use super::sparseimage::{SparseImageFileEntry, SparseImageFileSystem};
33use super::types::VfsFileSystemReference;
34use super::udif::{UdifFileEntry, UdifFileSystem};
35use super::vhd::{VhdFileEntry, VhdFileSystem};
36use super::vhdx::{VhdxFileEntry, VhdxFileSystem};
37
38/// Virtual File System (VFS) file system.
39pub enum VfsFileSystem {
40    Apm(ApmFileSystem),
41    Ext(ExtFileSystem),
42    Ewf(EwfFileSystem),
43    Fake(FakeFileSystem),
44    Gpt(GptFileSystem),
45    Mbr(MbrFileSystem),
46    Ntfs(NtfsFileSystem),
47    Os,
48    Qcow(QcowFileSystem),
49    SparseImage(SparseImageFileSystem),
50    Udif(UdifFileSystem),
51    Vhd(VhdFileSystem),
52    Vhdx(VhdxFileSystem),
53}
54
55impl VfsFileSystem {
56    /// Creates a new file system.
57    pub fn new(location_type: &VfsType) -> Self {
58        match location_type {
59            VfsType::Apm => VfsFileSystem::Apm(ApmFileSystem::new()),
60            VfsType::Ext => VfsFileSystem::Ext(ExtFileSystem::new()),
61            VfsType::Ewf => VfsFileSystem::Ewf(EwfFileSystem::new()),
62            VfsType::Fake => VfsFileSystem::Fake(FakeFileSystem::new()),
63            VfsType::Gpt => VfsFileSystem::Gpt(GptFileSystem::new()),
64            VfsType::Mbr => VfsFileSystem::Mbr(MbrFileSystem::new()),
65            VfsType::Ntfs => VfsFileSystem::Ntfs(NtfsFileSystem::new()),
66            VfsType::Os => VfsFileSystem::Os,
67            VfsType::Qcow => VfsFileSystem::Qcow(QcowFileSystem::new()),
68            VfsType::SparseImage => VfsFileSystem::SparseImage(SparseImageFileSystem::new()),
69            VfsType::Udif => VfsFileSystem::Udif(UdifFileSystem::new()),
70            VfsType::Vhd => VfsFileSystem::Vhd(VhdFileSystem::new()),
71            VfsType::Vhdx => VfsFileSystem::Vhdx(VhdxFileSystem::new()),
72        }
73    }
74
75    /// Determines if the file entry with the specified path exists.
76    pub fn file_entry_exists(&self, vfs_path: &VfsPath) -> Result<bool, ErrorTrace> {
77        match self {
78            VfsFileSystem::Apm(apm_file_system) => {
79                match apm_file_system.file_entry_exists(vfs_path) {
80                    Ok(result) => Ok(result),
81                    Err(mut error) => {
82                        keramics_core::error_trace_add_frame!(
83                            error,
84                            "Unable to determine if APM file entry exists"
85                        );
86                        return Err(error);
87                    }
88                }
89            }
90            VfsFileSystem::Ext(ext_file_system) => match vfs_path {
91                VfsPath::Ext(ext_path) => {
92                    let result: Option<ExtFileEntry> =
93                        match ext_file_system.get_file_entry_by_path(&ext_path) {
94                            Ok(result) => result,
95                            Err(mut error) => {
96                                keramics_core::error_trace_add_frame!(
97                                    error,
98                                    "Unable to retrieve ext file entry"
99                                );
100                                return Err(error);
101                            }
102                        };
103                    match result {
104                        Some(_) => Ok(true),
105                        None => Ok(false),
106                    }
107                }
108                _ => Err(keramics_core::error_trace_new!(
109                    "Unsupported ext VFS path type"
110                )),
111            },
112            VfsFileSystem::Ewf(ewf_file_system) => {
113                match ewf_file_system.file_entry_exists(vfs_path) {
114                    Ok(result) => Ok(result),
115                    Err(mut error) => {
116                        keramics_core::error_trace_add_frame!(
117                            error,
118                            "Unable to determine if EWF file entry exists"
119                        );
120                        return Err(error);
121                    }
122                }
123            }
124            VfsFileSystem::Fake(fake_file_system) => {
125                match fake_file_system.file_entry_exists(vfs_path) {
126                    Ok(result) => Ok(result),
127                    Err(mut error) => {
128                        keramics_core::error_trace_add_frame!(
129                            error,
130                            "Unable to determine if fake file entry exists"
131                        );
132                        return Err(error);
133                    }
134                }
135            }
136            VfsFileSystem::Gpt(gpt_file_system) => {
137                match gpt_file_system.file_entry_exists(vfs_path) {
138                    Ok(result) => Ok(result),
139                    Err(mut error) => {
140                        keramics_core::error_trace_add_frame!(
141                            error,
142                            "Unable to determine if GPT file entry exists"
143                        );
144                        return Err(error);
145                    }
146                }
147            }
148            VfsFileSystem::Mbr(mbr_file_system) => {
149                match mbr_file_system.file_entry_exists(vfs_path) {
150                    Ok(result) => Ok(result),
151                    Err(mut error) => {
152                        keramics_core::error_trace_add_frame!(
153                            error,
154                            "Unable to determine if MBR file entry exists"
155                        );
156                        return Err(error);
157                    }
158                }
159            }
160            VfsFileSystem::Ntfs(ntfs_file_system) => match vfs_path {
161                VfsPath::Ntfs(ntfs_path) => {
162                    let result: Option<NtfsFileEntry> =
163                        match ntfs_file_system.get_file_entry_by_path(&ntfs_path) {
164                            Ok(result) => result,
165                            Err(mut error) => {
166                                keramics_core::error_trace_add_frame!(
167                                    error,
168                                    "Unable to retrieve NTFS file entry"
169                                );
170                                return Err(error);
171                            }
172                        };
173                    match result {
174                        Some(_) => Ok(true),
175                        None => Ok(false),
176                    }
177                }
178                _ => Err(keramics_core::error_trace_new!(
179                    "Unsupported NTFS VFS path type"
180                )),
181            },
182            VfsFileSystem::Os => match vfs_path {
183                VfsPath::Os(string_path) => {
184                    let os_path: &Path = Path::new(&string_path);
185
186                    match os_path.try_exists() {
187                        Ok(result) => Ok(result),
188                        Err(error) => {
189                            return Err(keramics_core::error_trace_new_with_error!(
190                                "Unable to determine if OS file entry exists",
191                                error
192                            ));
193                        }
194                    }
195                }
196                _ => Err(keramics_core::error_trace_new!(
197                    "Unsupported OS VFS path type"
198                )),
199            },
200            VfsFileSystem::Qcow(qcow_file_system) => {
201                match qcow_file_system.file_entry_exists(vfs_path) {
202                    Ok(result) => Ok(result),
203                    Err(mut error) => {
204                        keramics_core::error_trace_add_frame!(
205                            error,
206                            "Unable to determine if QCOW file entry exists"
207                        );
208                        return Err(error);
209                    }
210                }
211            }
212            VfsFileSystem::SparseImage(sparseimage_file_system) => {
213                match sparseimage_file_system.file_entry_exists(vfs_path) {
214                    Ok(result) => Ok(result),
215                    Err(mut error) => {
216                        keramics_core::error_trace_add_frame!(
217                            error,
218                            "Unable to determine if sparseimage file entry exists"
219                        );
220                        return Err(error);
221                    }
222                }
223            }
224            VfsFileSystem::Udif(udif_file_system) => {
225                match udif_file_system.file_entry_exists(vfs_path) {
226                    Ok(result) => Ok(result),
227                    Err(mut error) => {
228                        keramics_core::error_trace_add_frame!(
229                            error,
230                            "Unable to determine if UDIF file entry exists"
231                        );
232                        return Err(error);
233                    }
234                }
235            }
236            VfsFileSystem::Vhd(vhd_file_system) => {
237                match vhd_file_system.file_entry_exists(vfs_path) {
238                    Ok(result) => Ok(result),
239                    Err(mut error) => {
240                        keramics_core::error_trace_add_frame!(
241                            error,
242                            "Unable to determine if VHD file entry exists"
243                        );
244                        return Err(error);
245                    }
246                }
247            }
248            VfsFileSystem::Vhdx(vhdx_file_system) => {
249                match vhdx_file_system.file_entry_exists(vfs_path) {
250                    Ok(result) => Ok(result),
251                    Err(mut error) => {
252                        keramics_core::error_trace_add_frame!(
253                            error,
254                            "Unable to determine if VHDX file entry exists"
255                        );
256                        return Err(error);
257                    }
258                }
259            }
260        }
261    }
262
263    /// Retrieves a data stream with the specified path and name.
264    #[inline(always)]
265    pub fn get_data_stream_by_path_and_name(
266        &self,
267        vfs_path: &VfsPath,
268        name: Option<&str>,
269    ) -> Result<Option<DataStreamReference>, ErrorTrace> {
270        match self.get_file_entry_by_path(vfs_path)? {
271            // TODO: replace by get_data_fork_by_name
272            Some(file_entry) => file_entry.get_data_stream_by_name(name),
273            None => Ok(None),
274        }
275    }
276
277    /// Retrieves a file entry with the specified path.
278    pub fn get_file_entry_by_path(
279        &self,
280        vfs_path: &VfsPath,
281    ) -> Result<Option<VfsFileEntry>, ErrorTrace> {
282        match self {
283            VfsFileSystem::Apm(apm_file_system) => {
284                let result: Option<ApmFileEntry> =
285                    match apm_file_system.get_file_entry_by_path(vfs_path) {
286                        Ok(result) => result,
287                        Err(mut error) => {
288                            keramics_core::error_trace_add_frame!(
289                                error,
290                                "Unable to retrieve APM file entry"
291                            );
292                            return Err(error);
293                        }
294                    };
295                match result {
296                    Some(apm_file_entry) => Ok(Some(VfsFileEntry::Apm(apm_file_entry))),
297                    None => Ok(None),
298                }
299            }
300            VfsFileSystem::Ext(ext_file_system) => match vfs_path {
301                VfsPath::Ext(ext_path) => {
302                    let result: Option<ExtFileEntry> =
303                        match ext_file_system.get_file_entry_by_path(&ext_path) {
304                            Ok(result) => result,
305                            Err(mut error) => {
306                                keramics_core::error_trace_add_frame!(
307                                    error,
308                                    "Unable to retrieve ext file entry"
309                                );
310                                return Err(error);
311                            }
312                        };
313                    match result {
314                        Some(file_entry) => Ok(Some(VfsFileEntry::Ext(file_entry))),
315                        None => Ok(None),
316                    }
317                }
318                _ => Err(keramics_core::error_trace_new!(
319                    "Unsupported ext VFS path type"
320                )),
321            },
322            VfsFileSystem::Ewf(ewf_file_system) => {
323                let result: Option<EwfFileEntry> =
324                    match ewf_file_system.get_file_entry_by_path(vfs_path) {
325                        Ok(result) => result,
326                        Err(mut error) => {
327                            keramics_core::error_trace_add_frame!(
328                                error,
329                                "Unable to retrieve EWF file entry"
330                            );
331                            return Err(error);
332                        }
333                    };
334                match result {
335                    Some(ewf_file_entry) => Ok(Some(VfsFileEntry::Ewf(ewf_file_entry))),
336                    None => Ok(None),
337                }
338            }
339            VfsFileSystem::Fake(fake_file_system) => {
340                let result: Option<Arc<FakeFileEntry>> =
341                    match fake_file_system.get_file_entry_by_path(vfs_path) {
342                        Ok(result) => result,
343                        Err(mut error) => {
344                            keramics_core::error_trace_add_frame!(
345                                error,
346                                "Unable to retrieve fake file entry"
347                            );
348                            return Err(error);
349                        }
350                    };
351                match result {
352                    Some(file_entry) => Ok(Some(VfsFileEntry::Fake(file_entry.clone()))),
353                    None => Ok(None),
354                }
355            }
356            VfsFileSystem::Gpt(gpt_file_system) => {
357                let result: Option<GptFileEntry> =
358                    match gpt_file_system.get_file_entry_by_path(vfs_path) {
359                        Ok(result) => result,
360                        Err(mut error) => {
361                            keramics_core::error_trace_add_frame!(
362                                error,
363                                "Unable to retrieve GPT file entry"
364                            );
365                            return Err(error);
366                        }
367                    };
368                match result {
369                    Some(gpt_file_entry) => Ok(Some(VfsFileEntry::Gpt(gpt_file_entry))),
370                    None => Ok(None),
371                }
372            }
373            VfsFileSystem::Mbr(mbr_file_system) => {
374                let result: Option<MbrFileEntry> =
375                    match mbr_file_system.get_file_entry_by_path(vfs_path) {
376                        Ok(result) => result,
377                        Err(mut error) => {
378                            keramics_core::error_trace_add_frame!(
379                                error,
380                                "Unable to retrieve MBR file entry"
381                            );
382                            return Err(error);
383                        }
384                    };
385                match result {
386                    Some(mbr_file_entry) => Ok(Some(VfsFileEntry::Mbr(mbr_file_entry))),
387                    None => Ok(None),
388                }
389            }
390            VfsFileSystem::Ntfs(ntfs_file_system) => match vfs_path {
391                VfsPath::Ntfs(ntfs_path) => {
392                    let result: Option<NtfsFileEntry> =
393                        match ntfs_file_system.get_file_entry_by_path(&ntfs_path) {
394                            Ok(result) => result,
395                            Err(mut error) => {
396                                keramics_core::error_trace_add_frame!(
397                                    error,
398                                    "Unable to retrieve NTFS file entry"
399                                );
400                                return Err(error);
401                            }
402                        };
403                    match result {
404                        Some(file_entry) => Ok(Some(VfsFileEntry::Ntfs(file_entry))),
405                        None => Ok(None),
406                    }
407                }
408                _ => Err(keramics_core::error_trace_new!(
409                    "Unsupported NTFS VFS path type"
410                )),
411            },
412            VfsFileSystem::Os => match vfs_path {
413                VfsPath::Os(string_path) => {
414                    let os_path: &Path = Path::new(&string_path);
415
416                    let result: bool = match os_path.try_exists() {
417                        Ok(result) => result,
418                        Err(error) => {
419                            return Err(keramics_core::error_trace_new_with_error!(
420                                "Unable to determine if OS file entry exists",
421                                error
422                            ));
423                        }
424                    };
425                    match result {
426                        false => Ok(None),
427                        true => {
428                            let mut os_file_entry: OsFileEntry = OsFileEntry::new();
429
430                            match os_file_entry.open(string_path.as_os_str()) {
431                                Ok(_) => {}
432                                Err(error) => {
433                                    return Err(keramics_core::error_trace_new_with_error!(
434                                        "Unable to open OS file entry",
435                                        error
436                                    ));
437                                }
438                            }
439                            Ok(Some(VfsFileEntry::Os(os_file_entry)))
440                        }
441                    }
442                }
443                _ => Err(keramics_core::error_trace_new!(
444                    "Unsupported OS VFS path type"
445                )),
446            },
447            VfsFileSystem::Qcow(qcow_file_system) => {
448                let result: Option<QcowFileEntry> =
449                    match qcow_file_system.get_file_entry_by_path(vfs_path) {
450                        Ok(result) => result,
451                        Err(mut error) => {
452                            keramics_core::error_trace_add_frame!(
453                                error,
454                                "Unable to retrieve QCOW file entry"
455                            );
456                            return Err(error);
457                        }
458                    };
459                match result {
460                    Some(qcow_file_entry) => Ok(Some(VfsFileEntry::Qcow(qcow_file_entry))),
461                    None => Ok(None),
462                }
463            }
464            VfsFileSystem::SparseImage(sparseimage_file_system) => {
465                let result: Option<SparseImageFileEntry> =
466                    match sparseimage_file_system.get_file_entry_by_path(vfs_path) {
467                        Ok(result) => result,
468                        Err(mut error) => {
469                            keramics_core::error_trace_add_frame!(
470                                error,
471                                "Unable to retrieve sparseimage file entry"
472                            );
473                            return Err(error);
474                        }
475                    };
476                match result {
477                    Some(sparseimage_file_entry) => {
478                        Ok(Some(VfsFileEntry::SparseImage(sparseimage_file_entry)))
479                    }
480                    None => Ok(None),
481                }
482            }
483            VfsFileSystem::Udif(udif_file_system) => {
484                let result: Option<UdifFileEntry> =
485                    match udif_file_system.get_file_entry_by_path(vfs_path) {
486                        Ok(result) => result,
487                        Err(mut error) => {
488                            keramics_core::error_trace_add_frame!(
489                                error,
490                                "Unable to retrieve UDIF file entry"
491                            );
492                            return Err(error);
493                        }
494                    };
495                match result {
496                    Some(udif_file_entry) => Ok(Some(VfsFileEntry::Udif(udif_file_entry))),
497                    None => Ok(None),
498                }
499            }
500            VfsFileSystem::Vhd(vhd_file_system) => {
501                let result: Option<VhdFileEntry> =
502                    match vhd_file_system.get_file_entry_by_path(vfs_path) {
503                        Ok(result) => result,
504                        Err(mut error) => {
505                            keramics_core::error_trace_add_frame!(
506                                error,
507                                "Unable to retrieve VHD file entry"
508                            );
509                            return Err(error);
510                        }
511                    };
512                match result {
513                    Some(vhd_file_entry) => Ok(Some(VfsFileEntry::Vhd(vhd_file_entry))),
514                    None => Ok(None),
515                }
516            }
517            VfsFileSystem::Vhdx(vhdx_file_system) => {
518                let result: Option<VhdxFileEntry> =
519                    match vhdx_file_system.get_file_entry_by_path(vfs_path) {
520                        Ok(result) => result,
521                        Err(mut error) => {
522                            keramics_core::error_trace_add_frame!(
523                                error,
524                                "Unable to retrieve VHDX file entry"
525                            );
526                            return Err(error);
527                        }
528                    };
529                match result {
530                    Some(vhdx_file_entry) => Ok(Some(VfsFileEntry::Vhdx(vhdx_file_entry))),
531                    None => Ok(None),
532                }
533            }
534        }
535    }
536
537    /// Retrieves the root file entry.
538    pub fn get_root_file_entry(&self) -> Result<Option<VfsFileEntry>, ErrorTrace> {
539        match self {
540            VfsFileSystem::Apm(apm_file_system) => {
541                let apm_file_entry: ApmFileEntry = match apm_file_system.get_root_file_entry() {
542                    Ok(file_entry) => file_entry,
543                    Err(mut error) => {
544                        keramics_core::error_trace_add_frame!(
545                            error,
546                            "Unable to retrieve APM root file entry"
547                        );
548                        return Err(error);
549                    }
550                };
551                Ok(Some(VfsFileEntry::Apm(apm_file_entry)))
552            }
553            VfsFileSystem::Ext(ext_file_system) => match ext_file_system.get_root_directory() {
554                Ok(result) => match result {
555                    Some(ext_file_entry) => Ok(Some(VfsFileEntry::Ext(ext_file_entry))),
556                    None => Ok(None),
557                },
558                Err(mut error) => {
559                    keramics_core::error_trace_add_frame!(
560                        error,
561                        "Unable to retrieve ext root directory"
562                    );
563                    return Err(error);
564                }
565            },
566            VfsFileSystem::Ewf(ewf_file_system) => {
567                let ewf_file_entry: EwfFileEntry = match ewf_file_system.get_root_file_entry() {
568                    Ok(file_entry) => file_entry,
569                    Err(mut error) => {
570                        keramics_core::error_trace_add_frame!(
571                            error,
572                            "Unable to retrieve EWF root file entry"
573                        );
574                        return Err(error);
575                    }
576                };
577                Ok(Some(VfsFileEntry::Ewf(ewf_file_entry)))
578            }
579            VfsFileSystem::Fake(_) => todo!(),
580            VfsFileSystem::Gpt(gpt_file_system) => {
581                let gpt_file_entry: GptFileEntry = match gpt_file_system.get_root_file_entry() {
582                    Ok(file_entry) => file_entry,
583                    Err(mut error) => {
584                        keramics_core::error_trace_add_frame!(
585                            error,
586                            "Unable to retrieve GPT root file entry"
587                        );
588                        return Err(error);
589                    }
590                };
591                Ok(Some(VfsFileEntry::Gpt(gpt_file_entry)))
592            }
593            VfsFileSystem::Mbr(mbr_file_system) => {
594                let mbr_file_entry: MbrFileEntry = match mbr_file_system.get_root_file_entry() {
595                    Ok(file_entry) => file_entry,
596                    Err(mut error) => {
597                        keramics_core::error_trace_add_frame!(
598                            error,
599                            "Unable to retrieve MBR root file entry"
600                        );
601                        return Err(error);
602                    }
603                };
604                Ok(Some(VfsFileEntry::Mbr(mbr_file_entry)))
605            }
606            VfsFileSystem::Ntfs(ntfs_file_system) => {
607                let ntfs_file_entry: NtfsFileEntry = match ntfs_file_system.get_root_directory() {
608                    Ok(file_entry) => file_entry,
609                    Err(mut error) => {
610                        keramics_core::error_trace_add_frame!(
611                            error,
612                            "Unable to retrieve NTFS root directory"
613                        );
614                        return Err(error);
615                    }
616                };
617                Ok(Some(VfsFileEntry::Ntfs(ntfs_file_entry)))
618            }
619            VfsFileSystem::Os => todo!(),
620            VfsFileSystem::Qcow(qcow_file_system) => {
621                let qcow_file_entry: QcowFileEntry = match qcow_file_system.get_root_file_entry() {
622                    Ok(file_entry) => file_entry,
623                    Err(mut error) => {
624                        keramics_core::error_trace_add_frame!(
625                            error,
626                            "Unable to retrieve QCOW root file entry"
627                        );
628                        return Err(error);
629                    }
630                };
631                Ok(Some(VfsFileEntry::Qcow(qcow_file_entry)))
632            }
633            VfsFileSystem::SparseImage(sparseimage_file_system) => {
634                let sparseimage_file_entry: SparseImageFileEntry =
635                    match sparseimage_file_system.get_root_file_entry() {
636                        Ok(file_entry) => file_entry,
637                        Err(mut error) => {
638                            keramics_core::error_trace_add_frame!(
639                                error,
640                                "Unable to retrieve sparseimage root file entry"
641                            );
642                            return Err(error);
643                        }
644                    };
645                Ok(Some(VfsFileEntry::SparseImage(sparseimage_file_entry)))
646            }
647            VfsFileSystem::Udif(udif_file_system) => {
648                let udif_file_entry: UdifFileEntry = match udif_file_system.get_root_file_entry() {
649                    Ok(file_entry) => file_entry,
650                    Err(mut error) => {
651                        keramics_core::error_trace_add_frame!(
652                            error,
653                            "Unable to retrieve UDIF root file entry"
654                        );
655                        return Err(error);
656                    }
657                };
658                Ok(Some(VfsFileEntry::Udif(udif_file_entry)))
659            }
660            VfsFileSystem::Vhd(vhd_file_system) => {
661                let vhd_file_entry: VhdFileEntry = match vhd_file_system.get_root_file_entry() {
662                    Ok(file_entry) => file_entry,
663                    Err(mut error) => {
664                        keramics_core::error_trace_add_frame!(
665                            error,
666                            "Unable to retrieve VHD root file entry"
667                        );
668                        return Err(error);
669                    }
670                };
671                Ok(Some(VfsFileEntry::Vhd(vhd_file_entry)))
672            }
673            VfsFileSystem::Vhdx(vhdx_file_system) => {
674                let vhdx_file_entry: VhdxFileEntry = match vhdx_file_system.get_root_file_entry() {
675                    Ok(file_entry) => file_entry,
676                    Err(mut error) => {
677                        keramics_core::error_trace_add_frame!(
678                            error,
679                            "Unable to retrieve VHDX root file entry"
680                        );
681                        return Err(error);
682                    }
683                };
684                Ok(Some(VfsFileEntry::Vhdx(vhdx_file_entry)))
685            }
686        }
687    }
688
689    /// Opens the file system.
690    pub(super) fn open(
691        &mut self,
692        parent_file_system: Option<&VfsFileSystemReference>,
693        vfs_location: &VfsLocation,
694    ) -> Result<(), ErrorTrace> {
695        match self {
696            VfsFileSystem::Apm(apm_file_system) => {
697                match apm_file_system.open(parent_file_system, vfs_location) {
698                    Ok(_) => {}
699                    Err(mut error) => {
700                        keramics_core::error_trace_add_frame!(
701                            error,
702                            "Unable to open APM file system"
703                        );
704                        return Err(error);
705                    }
706                }
707            }
708            VfsFileSystem::Ext(ext_file_system) => {
709                let file_system: &VfsFileSystemReference = match parent_file_system {
710                    Some(file_system) => file_system,
711                    None => {
712                        return Err(keramics_core::error_trace_new!(
713                            "Missing parent file system"
714                        ));
715                    }
716                };
717                let vfs_path: &VfsPath = vfs_location.get_path();
718
719                let result: Option<DataStreamReference> =
720                    match file_system.get_data_stream_by_path_and_name(vfs_path, None) {
721                        Ok(result) => result,
722                        Err(mut error) => {
723                            keramics_core::error_trace_add_frame!(
724                                error,
725                                "Unable to retrieve data stream"
726                            );
727                            return Err(error);
728                        }
729                    };
730                let data_stream: DataStreamReference = match result {
731                    Some(data_stream) => data_stream,
732                    None => {
733                        return Err(keramics_core::error_trace_new!(format!(
734                            "No such file: {}",
735                            vfs_location.to_string()
736                        )));
737                    }
738                };
739                match ext_file_system.read_data_stream(&data_stream) {
740                    Ok(result) => result,
741                    Err(mut error) => {
742                        keramics_core::error_trace_add_frame!(
743                            error,
744                            "Unable to read ext file system from data stream"
745                        );
746                        return Err(error);
747                    }
748                }
749            }
750            VfsFileSystem::Ewf(ewf_file_system) => {
751                match ewf_file_system.open(parent_file_system, vfs_location) {
752                    Ok(_) => {}
753                    Err(mut error) => {
754                        keramics_core::error_trace_add_frame!(
755                            error,
756                            "Unable to open EWF file system"
757                        );
758                        return Err(error);
759                    }
760                }
761            }
762            VfsFileSystem::Fake(_) | VfsFileSystem::Os => {
763                if parent_file_system.is_some() {
764                    return Err(keramics_core::error_trace_new!(
765                        "Unsupported parent file system"
766                    ));
767                }
768            }
769            VfsFileSystem::Gpt(gpt_file_system) => {
770                match gpt_file_system.open(parent_file_system, vfs_location) {
771                    Ok(_) => {}
772                    Err(mut error) => {
773                        keramics_core::error_trace_add_frame!(
774                            error,
775                            "Unable to open GPT file system"
776                        );
777                        return Err(error);
778                    }
779                }
780            }
781            VfsFileSystem::Mbr(mbr_file_system) => {
782                match mbr_file_system.open(parent_file_system, vfs_location) {
783                    Ok(_) => {}
784                    Err(mut error) => {
785                        keramics_core::error_trace_add_frame!(
786                            error,
787                            "Unable to open MBR file system"
788                        );
789                        return Err(error);
790                    }
791                }
792            }
793            VfsFileSystem::Ntfs(ntfs_file_system) => {
794                let file_system: &VfsFileSystemReference = match parent_file_system {
795                    Some(file_system) => file_system,
796                    None => {
797                        return Err(keramics_core::error_trace_new!(
798                            "Missing parent file system"
799                        ));
800                    }
801                };
802                let vfs_path: &VfsPath = vfs_location.get_path();
803
804                let result: Option<DataStreamReference> =
805                    match file_system.get_data_stream_by_path_and_name(vfs_path, None) {
806                        Ok(result) => result,
807                        Err(mut error) => {
808                            keramics_core::error_trace_add_frame!(
809                                error,
810                                "Unable to retrieve data stream"
811                            );
812                            return Err(error);
813                        }
814                    };
815                let data_stream: DataStreamReference = match result {
816                    Some(data_stream) => data_stream,
817                    None => {
818                        return Err(keramics_core::error_trace_new!(format!(
819                            "No such file: {}",
820                            vfs_location.to_string()
821                        )));
822                    }
823                };
824                match ntfs_file_system.read_data_stream(&data_stream) {
825                    Ok(result) => result,
826                    Err(mut error) => {
827                        keramics_core::error_trace_add_frame!(
828                            error,
829                            "Unable to read NTFS file system from data stream"
830                        );
831                        return Err(error);
832                    }
833                }
834            }
835            VfsFileSystem::Qcow(qcow_file_system) => {
836                match qcow_file_system.open(parent_file_system, vfs_location) {
837                    Ok(_) => {}
838                    Err(mut error) => {
839                        keramics_core::error_trace_add_frame!(
840                            error,
841                            "Unable to open QCOW file system"
842                        );
843                        return Err(error);
844                    }
845                }
846            }
847            VfsFileSystem::SparseImage(sparseimage_file_system) => {
848                match sparseimage_file_system.open(parent_file_system, vfs_location) {
849                    Ok(_) => {}
850                    Err(mut error) => {
851                        keramics_core::error_trace_add_frame!(
852                            error,
853                            "Unable to open sparseimage file system"
854                        );
855                        return Err(error);
856                    }
857                }
858            }
859            VfsFileSystem::Udif(udif_file_system) => {
860                match udif_file_system.open(parent_file_system, vfs_location) {
861                    Ok(_) => {}
862                    Err(mut error) => {
863                        keramics_core::error_trace_add_frame!(
864                            error,
865                            "Unable to open UDIF file system"
866                        );
867                        return Err(error);
868                    }
869                }
870            }
871            VfsFileSystem::Vhd(vhd_file_system) => {
872                match vhd_file_system.open(parent_file_system, vfs_location) {
873                    Ok(_) => {}
874                    Err(mut error) => {
875                        keramics_core::error_trace_add_frame!(
876                            error,
877                            "Unable to open VHD file system"
878                        );
879                        return Err(error);
880                    }
881                }
882            }
883            VfsFileSystem::Vhdx(vhdx_file_system) => {
884                match vhdx_file_system.open(parent_file_system, vfs_location) {
885                    Ok(_) => {}
886                    Err(mut error) => {
887                        keramics_core::error_trace_add_frame!(
888                            error,
889                            "Unable to open VHDX file system"
890                        );
891                        return Err(error);
892                    }
893                }
894            }
895        }
896        Ok(())
897    }
898}
899
900#[cfg(test)]
901mod tests {
902    use super::*;
903
904    use crate::enums::VfsFileType;
905    use crate::fake::FakeFileEntry;
906    use crate::location::new_os_vfs_location;
907
908    fn get_apm_file_system() -> Result<VfsFileSystem, ErrorTrace> {
909        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Apm);
910
911        let parent_file_system: VfsFileSystemReference =
912            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
913        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/apm/apm.dmg");
914        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
915
916        Ok(vfs_file_system)
917    }
918
919    fn get_ext_file_system() -> Result<VfsFileSystem, ErrorTrace> {
920        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Ext);
921
922        let parent_file_system: VfsFileSystemReference =
923            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
924        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/ext/ext2.raw");
925        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
926
927        Ok(vfs_file_system)
928    }
929
930    fn get_ewf_file_system() -> Result<VfsFileSystem, ErrorTrace> {
931        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Ewf);
932
933        let parent_file_system: VfsFileSystemReference =
934            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
935        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/ewf/ext2.E01");
936        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
937
938        Ok(vfs_file_system)
939    }
940
941    fn get_fake_file_system() -> Result<VfsFileSystem, ErrorTrace> {
942        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Fake);
943        if let VfsFileSystem::Fake(fake_file_system) = &mut vfs_file_system {
944            let data: [u8; 4] = [1, 2, 3, 4];
945            let fake_file_entry: FakeFileEntry = FakeFileEntry::new_file(&data);
946            _ = fake_file_system.add_file_entry("/fake1", fake_file_entry);
947
948            let data: [u8; 4] = [5, 6, 7, 8];
949            let fake_file_entry: FakeFileEntry = FakeFileEntry::new_file(&data);
950            _ = fake_file_system.add_file_entry("/fake2", fake_file_entry);
951        }
952        Ok(vfs_file_system)
953    }
954
955    fn get_gpt_file_system() -> Result<VfsFileSystem, ErrorTrace> {
956        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Gpt);
957
958        let parent_file_system: VfsFileSystemReference =
959            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
960        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/gpt/gpt.raw");
961        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
962
963        Ok(vfs_file_system)
964    }
965
966    fn get_mbr_file_system() -> Result<VfsFileSystem, ErrorTrace> {
967        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Mbr);
968
969        let parent_file_system: VfsFileSystemReference =
970            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
971        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/mbr/mbr.raw");
972        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
973
974        Ok(vfs_file_system)
975    }
976
977    // TODO: add get_ntfs_file_system
978
979    fn get_qcow_file_system() -> Result<VfsFileSystem, ErrorTrace> {
980        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Qcow);
981
982        let parent_file_system: VfsFileSystemReference =
983            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
984        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/qcow/ext2.qcow2");
985        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
986
987        Ok(vfs_file_system)
988    }
989
990    fn get_sparseimage_file_system() -> Result<VfsFileSystem, ErrorTrace> {
991        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::SparseImage);
992
993        let parent_file_system: VfsFileSystemReference =
994            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
995        let vfs_location: VfsLocation =
996            new_os_vfs_location("../test_data/sparseimage/hfsplus.sparseimage");
997        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
998
999        Ok(vfs_file_system)
1000    }
1001
1002    fn get_udif_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1003        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Udif);
1004
1005        let parent_file_system: VfsFileSystemReference =
1006            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
1007        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/udif/hfsplus_zlib.dmg");
1008        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1009
1010        Ok(vfs_file_system)
1011    }
1012
1013    fn get_vhd_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1014        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Vhd);
1015
1016        let parent_file_system: VfsFileSystemReference =
1017            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
1018        let vfs_location: VfsLocation =
1019            new_os_vfs_location("../test_data/vhd/ntfs-differential.vhd");
1020        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1021
1022        Ok(vfs_file_system)
1023    }
1024
1025    fn get_vhdx_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1026        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Vhdx);
1027
1028        let parent_file_system: VfsFileSystemReference =
1029            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
1030        let vfs_location: VfsLocation =
1031            new_os_vfs_location("../test_data/vhdx/ntfs-differential.vhdx");
1032        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1033
1034        Ok(vfs_file_system)
1035    }
1036
1037    #[test]
1038    fn test_file_entry_exists_with_apm() -> Result<(), ErrorTrace> {
1039        let vfs_file_system: VfsFileSystem = get_apm_file_system()?;
1040
1041        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/apm2");
1042        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1043
1044        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/bogus2");
1045        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1046
1047        Ok(())
1048    }
1049
1050    #[test]
1051    fn test_file_entry_exists_with_ext() -> Result<(), ErrorTrace> {
1052        let vfs_file_system: VfsFileSystem = get_ext_file_system()?;
1053
1054        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/testdir1/testfile1");
1055        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1056
1057        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/bogus");
1058        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1059
1060        Ok(())
1061    }
1062
1063    #[test]
1064    fn test_file_entry_exists_with_ewf() -> Result<(), ErrorTrace> {
1065        let vfs_file_system: VfsFileSystem = get_ewf_file_system()?;
1066
1067        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/ewf1");
1068        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1069
1070        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/bogus");
1071        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1072
1073        Ok(())
1074    }
1075
1076    #[test]
1077    fn test_file_entry_exists_with_fake() -> Result<(), ErrorTrace> {
1078        let vfs_file_system: VfsFileSystem = get_fake_file_system()?;
1079
1080        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Fake, "/fake2");
1081        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1082
1083        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Fake, "/bogus");
1084        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1085
1086        Ok(())
1087    }
1088
1089    #[test]
1090    fn test_file_entry_exists_with_gpt() -> Result<(), ErrorTrace> {
1091        let vfs_file_system: VfsFileSystem = get_gpt_file_system()?;
1092
1093        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/gpt2");
1094        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1095
1096        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/bogus2");
1097        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1098
1099        Ok(())
1100    }
1101
1102    #[test]
1103    fn test_file_entry_exists_with_mbr() -> Result<(), ErrorTrace> {
1104        let vfs_file_system: VfsFileSystem = get_mbr_file_system()?;
1105
1106        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/mbr2");
1107        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1108
1109        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/bogus2");
1110        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1111
1112        Ok(())
1113    }
1114
1115    // TODO: add test_file_entry_exists_with_ntfs
1116
1117    #[test]
1118    fn test_file_entry_exists_with_os() -> Result<(), ErrorTrace> {
1119        let vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Os);
1120
1121        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Os, "../test_data/file.txt");
1122        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1123
1124        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Os, "../test_data/bogus.txt");
1125        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1126
1127        Ok(())
1128    }
1129
1130    #[test]
1131    fn test_file_entry_exists_with_qcow() -> Result<(), ErrorTrace> {
1132        let vfs_file_system: VfsFileSystem = get_qcow_file_system()?;
1133
1134        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/qcow1");
1135        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1136
1137        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/bogus1");
1138        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1139
1140        Ok(())
1141    }
1142
1143    #[test]
1144    fn test_file_entry_exists_with_sparseimage() -> Result<(), ErrorTrace> {
1145        let vfs_file_system: VfsFileSystem = get_sparseimage_file_system()?;
1146
1147        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/sparseimage1");
1148        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1149
1150        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/bogus1");
1151        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1152
1153        Ok(())
1154    }
1155
1156    #[test]
1157    fn test_file_entry_exists_with_udif() -> Result<(), ErrorTrace> {
1158        let vfs_file_system: VfsFileSystem = get_udif_file_system()?;
1159
1160        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/udif1");
1161        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1162
1163        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/bogus1");
1164        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1165
1166        Ok(())
1167    }
1168
1169    #[test]
1170    fn test_file_entry_exists_with_vhd() -> Result<(), ErrorTrace> {
1171        let vfs_file_system: VfsFileSystem = get_vhd_file_system()?;
1172
1173        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/vhd2");
1174        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1175
1176        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/bogus2");
1177        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1178
1179        Ok(())
1180    }
1181
1182    #[test]
1183    fn test_file_entry_exists_with_vhdx() -> Result<(), ErrorTrace> {
1184        let vfs_file_system: VfsFileSystem = get_vhdx_file_system()?;
1185
1186        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/vhdx2");
1187        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, true);
1188
1189        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/bogus2");
1190        assert_eq!(vfs_file_system.file_entry_exists(&vfs_path)?, false);
1191
1192        Ok(())
1193    }
1194
1195    // TODO: add test for get_data_stream_by_path_and_name
1196
1197    #[test]
1198    fn test_get_file_entry_by_path_with_apm_non_existing() -> Result<(), ErrorTrace> {
1199        let vfs_file_system: VfsFileSystem = get_apm_file_system()?;
1200
1201        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/bogus2");
1202        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1203
1204        assert!(result.is_none());
1205
1206        Ok(())
1207    }
1208
1209    #[test]
1210    fn test_get_file_entry_by_path_with_apm_partition() -> Result<(), ErrorTrace> {
1211        let vfs_file_system: VfsFileSystem = get_apm_file_system()?;
1212
1213        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/apm2");
1214        let vfs_file_entry: VfsFileEntry =
1215            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1216
1217        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1218
1219        Ok(())
1220    }
1221
1222    #[test]
1223    fn test_get_file_entry_by_path_with_apm_root() -> Result<(), ErrorTrace> {
1224        let vfs_file_system: VfsFileSystem = get_apm_file_system()?;
1225
1226        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/");
1227        let vfs_file_entry: VfsFileEntry =
1228            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1229
1230        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1231
1232        Ok(())
1233    }
1234
1235    #[test]
1236    fn test_get_file_entry_by_path_with_ext_non_existing() -> Result<(), ErrorTrace> {
1237        let vfs_file_system: VfsFileSystem = get_ext_file_system()?;
1238
1239        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/bogus");
1240        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1241
1242        assert!(result.is_none());
1243
1244        Ok(())
1245    }
1246
1247    #[test]
1248    fn test_get_file_entry_by_path_with_ext_partition() -> Result<(), ErrorTrace> {
1249        let vfs_file_system: VfsFileSystem = get_ext_file_system()?;
1250
1251        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/testdir1/testfile1");
1252        let vfs_file_entry: VfsFileEntry =
1253            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1254
1255        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1256
1257        Ok(())
1258    }
1259
1260    #[test]
1261    fn test_get_file_entry_by_path_with_ext_root() -> Result<(), ErrorTrace> {
1262        let vfs_file_system: VfsFileSystem = get_ext_file_system()?;
1263
1264        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/");
1265        let vfs_file_entry: VfsFileEntry =
1266            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1267
1268        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1269
1270        Ok(())
1271    }
1272
1273    #[test]
1274    fn test_get_file_entry_by_path_with_ewf_non_existing() -> Result<(), ErrorTrace> {
1275        let vfs_file_system: VfsFileSystem = get_ewf_file_system()?;
1276
1277        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/bogus");
1278        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1279
1280        assert!(result.is_none());
1281
1282        Ok(())
1283    }
1284
1285    #[test]
1286    fn test_get_file_entry_by_path_with_ewf_layer() -> Result<(), ErrorTrace> {
1287        let vfs_file_system: VfsFileSystem = get_ewf_file_system()?;
1288
1289        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/ewf1");
1290        let vfs_file_entry: VfsFileEntry =
1291            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1292
1293        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1294
1295        Ok(())
1296    }
1297
1298    #[test]
1299    fn test_get_file_entry_by_path_with_ewf_root() -> Result<(), ErrorTrace> {
1300        let vfs_file_system: VfsFileSystem = get_ewf_file_system()?;
1301
1302        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/");
1303        let vfs_file_entry: VfsFileEntry =
1304            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1305
1306        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1307
1308        Ok(())
1309    }
1310
1311    #[test]
1312    fn test_get_file_entry_by_path_with_fake_file() -> Result<(), ErrorTrace> {
1313        let vfs_file_system: VfsFileSystem = get_fake_file_system()?;
1314
1315        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Fake, "/fake2");
1316        let vfs_file_entry: VfsFileEntry =
1317            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1318
1319        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1320
1321        Ok(())
1322    }
1323
1324    #[test]
1325    fn test_get_file_entry_by_path_with_fake_non_existing() -> Result<(), ErrorTrace> {
1326        let vfs_file_system: VfsFileSystem = get_fake_file_system()?;
1327
1328        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Fake, "/bogus");
1329        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1330
1331        assert!(result.is_none());
1332
1333        Ok(())
1334    }
1335
1336    // TODO: add tests fir get_file_entry of fake root
1337
1338    #[test]
1339    fn test_get_file_entry_by_path_with_gpt_non_existing() -> Result<(), ErrorTrace> {
1340        let vfs_file_system: VfsFileSystem = get_gpt_file_system()?;
1341
1342        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/bogus2");
1343        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1344
1345        assert!(result.is_none());
1346
1347        Ok(())
1348    }
1349
1350    #[test]
1351    fn test_get_file_entry_by_path_with_gpt_partition() -> Result<(), ErrorTrace> {
1352        let vfs_file_system: VfsFileSystem = get_gpt_file_system()?;
1353
1354        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/gpt2");
1355        let vfs_file_entry: VfsFileEntry =
1356            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1357
1358        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1359
1360        Ok(())
1361    }
1362
1363    #[test]
1364    fn test_get_file_entry_by_path_with_gpt_root() -> Result<(), ErrorTrace> {
1365        let vfs_file_system: VfsFileSystem = get_gpt_file_system()?;
1366
1367        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/");
1368        let vfs_file_entry: VfsFileEntry =
1369            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1370
1371        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1372
1373        Ok(())
1374    }
1375
1376    #[test]
1377    fn test_get_file_entry_by_path_with_mbr_non_existing() -> Result<(), ErrorTrace> {
1378        let vfs_file_system: VfsFileSystem = get_mbr_file_system()?;
1379
1380        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/bogus2");
1381        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1382
1383        assert!(result.is_none());
1384
1385        Ok(())
1386    }
1387
1388    #[test]
1389    fn test_get_file_entry_by_path_with_mbr_partition() -> Result<(), ErrorTrace> {
1390        let vfs_file_system: VfsFileSystem = get_mbr_file_system()?;
1391
1392        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/mbr2");
1393        let vfs_file_entry: VfsFileEntry =
1394            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1395
1396        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1397
1398        Ok(())
1399    }
1400
1401    #[test]
1402    fn test_get_file_entry_by_path_with_mbr_root() -> Result<(), ErrorTrace> {
1403        let vfs_file_system: VfsFileSystem = get_mbr_file_system()?;
1404
1405        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/");
1406        let vfs_file_entry: VfsFileEntry =
1407            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1408
1409        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1410
1411        Ok(())
1412    }
1413
1414    // TODO: add test_get_file_entry_by_path_with_ntfs_non_existing
1415    // TODO: add test_get_file_entry_by_path_with_ntfs_partition
1416    // TODO: add test_get_file_entry_by_path_with_ntfs_root
1417
1418    #[test]
1419    fn test_get_file_entry_by_path_with_qcow_non_existing() -> Result<(), ErrorTrace> {
1420        let vfs_file_system: VfsFileSystem = get_qcow_file_system()?;
1421
1422        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/bogus1");
1423        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1424
1425        assert!(result.is_none());
1426
1427        Ok(())
1428    }
1429
1430    #[test]
1431    fn test_get_file_entry_by_path_with_qcow_layer() -> Result<(), ErrorTrace> {
1432        let vfs_file_system: VfsFileSystem = get_qcow_file_system()?;
1433
1434        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/qcow1");
1435        let vfs_file_entry: VfsFileEntry =
1436            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1437
1438        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1439
1440        Ok(())
1441    }
1442
1443    #[test]
1444    fn test_get_file_entry_by_path_with_qcow_root() -> Result<(), ErrorTrace> {
1445        let vfs_file_system: VfsFileSystem = get_qcow_file_system()?;
1446
1447        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/");
1448        let vfs_file_entry: VfsFileEntry =
1449            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1450
1451        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1452
1453        Ok(())
1454    }
1455
1456    #[test]
1457    fn test_get_file_entry_by_path_with_sparseimage_non_existing() -> Result<(), ErrorTrace> {
1458        let vfs_file_system: VfsFileSystem = get_sparseimage_file_system()?;
1459
1460        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/bogus1");
1461        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1462
1463        assert!(result.is_none());
1464
1465        Ok(())
1466    }
1467
1468    #[test]
1469    fn test_get_file_entry_by_path_with_sparseimage_layer() -> Result<(), ErrorTrace> {
1470        let vfs_file_system: VfsFileSystem = get_sparseimage_file_system()?;
1471
1472        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/sparseimage1");
1473        let vfs_file_entry: VfsFileEntry =
1474            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1475
1476        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1477
1478        Ok(())
1479    }
1480
1481    #[test]
1482    fn test_get_file_entry_by_path_with_sparseimage_root() -> Result<(), ErrorTrace> {
1483        let vfs_file_system: VfsFileSystem = get_sparseimage_file_system()?;
1484
1485        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/");
1486        let vfs_file_entry: VfsFileEntry =
1487            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1488
1489        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1490
1491        Ok(())
1492    }
1493
1494    #[test]
1495    fn test_get_file_entry_by_path_with_udif_non_existing() -> Result<(), ErrorTrace> {
1496        let vfs_file_system: VfsFileSystem = get_udif_file_system()?;
1497
1498        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/bogus1");
1499        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1500
1501        assert!(result.is_none());
1502
1503        Ok(())
1504    }
1505
1506    #[test]
1507    fn test_get_file_entry_by_path_with_udif_layer() -> Result<(), ErrorTrace> {
1508        let vfs_file_system: VfsFileSystem = get_udif_file_system()?;
1509
1510        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/udif1");
1511        let vfs_file_entry: VfsFileEntry =
1512            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1513
1514        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1515
1516        Ok(())
1517    }
1518
1519    #[test]
1520    fn test_get_file_entry_by_path_with_udif_root() -> Result<(), ErrorTrace> {
1521        let vfs_file_system: VfsFileSystem = get_udif_file_system()?;
1522
1523        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/");
1524        let vfs_file_entry: VfsFileEntry =
1525            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1526
1527        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1528
1529        Ok(())
1530    }
1531
1532    #[test]
1533    fn test_get_file_entry_by_path_with_vhd_non_existing() -> Result<(), ErrorTrace> {
1534        let vfs_file_system: VfsFileSystem = get_vhd_file_system()?;
1535
1536        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/bogus2");
1537        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1538
1539        assert!(result.is_none());
1540
1541        Ok(())
1542    }
1543
1544    #[test]
1545    fn test_get_file_entry_by_path_with_vhd_layer() -> Result<(), ErrorTrace> {
1546        let vfs_file_system: VfsFileSystem = get_vhd_file_system()?;
1547
1548        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/vhd2");
1549        let vfs_file_entry: VfsFileEntry =
1550            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1551
1552        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1553
1554        Ok(())
1555    }
1556
1557    #[test]
1558    fn test_get_file_entry_by_path_with_vhd_root() -> Result<(), ErrorTrace> {
1559        let vfs_file_system: VfsFileSystem = get_vhd_file_system()?;
1560
1561        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/");
1562        let vfs_file_entry: VfsFileEntry =
1563            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1564
1565        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1566
1567        Ok(())
1568    }
1569
1570    #[test]
1571    fn test_get_file_entry_by_path_with_vhdx_non_existing() -> Result<(), ErrorTrace> {
1572        let vfs_file_system: VfsFileSystem = get_vhdx_file_system()?;
1573
1574        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/bogus2");
1575        let result: Option<VfsFileEntry> = vfs_file_system.get_file_entry_by_path(&vfs_path)?;
1576
1577        assert!(result.is_none());
1578
1579        Ok(())
1580    }
1581
1582    #[test]
1583    fn test_get_file_entry_by_path_with_vhdx_layer() -> Result<(), ErrorTrace> {
1584        let vfs_file_system: VfsFileSystem = get_vhdx_file_system()?;
1585
1586        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/vhdx2");
1587        let vfs_file_entry: VfsFileEntry =
1588            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1589
1590        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1591
1592        Ok(())
1593    }
1594
1595    #[test]
1596    fn test_get_file_entry_by_path_with_vhdx_root() -> Result<(), ErrorTrace> {
1597        let vfs_file_system: VfsFileSystem = get_vhdx_file_system()?;
1598
1599        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/");
1600        let vfs_file_entry: VfsFileEntry =
1601            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1602
1603        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1604
1605        Ok(())
1606    }
1607
1608    #[test]
1609    fn test_get_file_entry_by_path_with_unsupported_location_type() -> Result<(), ErrorTrace> {
1610        let vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Os);
1611
1612        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/");
1613        let result = vfs_file_system.get_file_entry_by_path(&vfs_path);
1614        assert!(result.is_err());
1615
1616        Ok(())
1617    }
1618
1619    // TODO: add tests for get_root_file_entry
1620}