keramics_vfs/
file_entry.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::sync::Arc;
15
16use keramics_core::{DataStreamReference, ErrorTrace};
17use keramics_datetime::DateTime;
18use keramics_formats::ext::constants::*;
19use keramics_formats::ext::{ExtFileEntry, ExtPath};
20use keramics_formats::ntfs::{NtfsDataFork, NtfsFileEntry, NtfsPath};
21use keramics_types::{ByteString, Ucs2String};
22
23use super::apm::ApmFileEntry;
24use super::data_fork::VfsDataFork;
25use super::enums::VfsFileType;
26use super::ewf::EwfFileEntry;
27use super::fake::FakeFileEntry;
28use super::gpt::GptFileEntry;
29use super::iterators::VfsFileEntriesIterator;
30use super::mbr::MbrFileEntry;
31use super::os::OsFileEntry;
32use super::path::VfsPath;
33use super::qcow::QcowFileEntry;
34use super::sparseimage::SparseImageFileEntry;
35use super::string::VfsString;
36use super::udif::UdifFileEntry;
37use super::vhd::VhdFileEntry;
38use super::vhdx::VhdxFileEntry;
39
40/// Virtual File System (VFS) file entry.
41pub enum VfsFileEntry {
42    Apm(ApmFileEntry),
43    Ext(ExtFileEntry),
44    Ewf(EwfFileEntry),
45    Fake(Arc<FakeFileEntry>),
46    Gpt(GptFileEntry),
47    Mbr(MbrFileEntry),
48    Ntfs(NtfsFileEntry),
49    Os(OsFileEntry),
50    Qcow(QcowFileEntry),
51    SparseImage(SparseImageFileEntry),
52    Udif(UdifFileEntry),
53    Vhd(VhdFileEntry),
54    Vhdx(VhdxFileEntry),
55}
56
57impl VfsFileEntry {
58    /// Retrieves the access time.
59    pub fn get_access_time(&self) -> Option<&DateTime> {
60        match self {
61            VfsFileEntry::Apm(_)
62            | VfsFileEntry::Ewf(_)
63            | VfsFileEntry::Gpt(_)
64            | VfsFileEntry::Mbr(_)
65            | VfsFileEntry::Qcow(_)
66            | VfsFileEntry::SparseImage(_)
67            | VfsFileEntry::Udif(_)
68            | VfsFileEntry::Vhd(_)
69            | VfsFileEntry::Vhdx(_) => None,
70            VfsFileEntry::Ext(ext_file_entry) => ext_file_entry.get_access_time(),
71            VfsFileEntry::Fake(fake_file_entry) => fake_file_entry.get_access_time(),
72            VfsFileEntry::Ntfs(ntfs_file_entry) => ntfs_file_entry.get_access_time(),
73            VfsFileEntry::Os(os_file_entry) => os_file_entry.get_access_time(),
74        }
75    }
76
77    /// Retrieves the change time.
78    pub fn get_change_time(&self) -> Option<&DateTime> {
79        match self {
80            VfsFileEntry::Apm(_)
81            | VfsFileEntry::Ewf(_)
82            | VfsFileEntry::Gpt(_)
83            | VfsFileEntry::Mbr(_)
84            | VfsFileEntry::Qcow(_)
85            | VfsFileEntry::SparseImage(_)
86            | VfsFileEntry::Udif(_)
87            | VfsFileEntry::Vhd(_)
88            | VfsFileEntry::Vhdx(_) => None,
89            VfsFileEntry::Ext(ext_file_entry) => ext_file_entry.get_change_time(),
90            VfsFileEntry::Fake(fake_file_entry) => fake_file_entry.get_change_time(),
91            VfsFileEntry::Ntfs(ntfs_file_entry) => ntfs_file_entry.get_change_time(),
92            VfsFileEntry::Os(os_file_entry) => os_file_entry.get_change_time(),
93        }
94    }
95
96    /// Retrieves the creation time.
97    pub fn get_creation_time(&self) -> Option<&DateTime> {
98        match self {
99            VfsFileEntry::Apm(_)
100            | VfsFileEntry::Ewf(_)
101            | VfsFileEntry::Gpt(_)
102            | VfsFileEntry::Mbr(_)
103            | VfsFileEntry::Qcow(_)
104            | VfsFileEntry::SparseImage(_)
105            | VfsFileEntry::Udif(_)
106            | VfsFileEntry::Vhd(_)
107            | VfsFileEntry::Vhdx(_) => None,
108            VfsFileEntry::Ext(ext_file_entry) => ext_file_entry.get_creation_time(),
109            VfsFileEntry::Fake(fake_file_entry) => fake_file_entry.get_creation_time(),
110            VfsFileEntry::Ntfs(ntfs_file_entry) => ntfs_file_entry.get_creation_time(),
111            VfsFileEntry::Os(os_file_entry) => os_file_entry.get_creation_time(),
112        }
113    }
114
115    /// Retrieves the file type.
116    pub fn get_file_type(&self) -> VfsFileType {
117        match self {
118            VfsFileEntry::Apm(apm_file_entry) => apm_file_entry.get_file_type(),
119            VfsFileEntry::Ext(ext_file_entry) => {
120                let file_mode: u16 = ext_file_entry.get_file_mode();
121                let file_type: u16 = file_mode & 0xf000;
122                match file_type {
123                    EXT_FILE_MODE_TYPE_FIFO => VfsFileType::NamedPipe,
124                    EXT_FILE_MODE_TYPE_CHARACTER_DEVICE => VfsFileType::CharacterDevice,
125                    EXT_FILE_MODE_TYPE_DIRECTORY => VfsFileType::Directory,
126                    EXT_FILE_MODE_TYPE_BLOCK_DEVICE => VfsFileType::BlockDevice,
127                    EXT_FILE_MODE_TYPE_REGULAR_FILE => VfsFileType::File,
128                    EXT_FILE_MODE_TYPE_SYMBOLIC_LINK => VfsFileType::SymbolicLink,
129                    EXT_FILE_MODE_TYPE_SOCKET => VfsFileType::Socket,
130                    _ => VfsFileType::Unknown(file_type),
131                }
132            }
133            VfsFileEntry::Ewf(ewf_file_entry) => ewf_file_entry.get_file_type(),
134            VfsFileEntry::Fake(fake_file_entry) => fake_file_entry.get_file_type(),
135            VfsFileEntry::Gpt(gpt_file_entry) => gpt_file_entry.get_file_type(),
136            VfsFileEntry::Mbr(mbr_file_entry) => mbr_file_entry.get_file_type(),
137            VfsFileEntry::Ntfs(ntfs_file_entry) => {
138                // FILE_ATTRIBUTE_DEVICE is not used by NTFS.
139                if ntfs_file_entry.is_symbolic_link() {
140                    VfsFileType::SymbolicLink
141                }
142                // FILE_ATTRIBUTE_DIRECTORY is not used by NTFS.
143                else if ntfs_file_entry.has_directory_entries() {
144                    VfsFileType::Directory
145                } else {
146                    VfsFileType::File
147                }
148            }
149            VfsFileEntry::Os(os_file_entry) => os_file_entry.get_file_type(),
150            VfsFileEntry::Qcow(qcow_file_entry) => qcow_file_entry.get_file_type(),
151            VfsFileEntry::SparseImage(sparseimage_file_entry) => {
152                sparseimage_file_entry.get_file_type()
153            }
154            VfsFileEntry::Udif(udif_file_entry) => udif_file_entry.get_file_type(),
155            VfsFileEntry::Vhd(vhd_file_entry) => vhd_file_entry.get_file_type(),
156            VfsFileEntry::Vhdx(vhdx_file_entry) => vhdx_file_entry.get_file_type(),
157        }
158    }
159
160    /// Retrieves the modification time.
161    pub fn get_modification_time(&self) -> Option<&DateTime> {
162        match self {
163            VfsFileEntry::Apm(_)
164            | VfsFileEntry::Ewf(_)
165            | VfsFileEntry::Gpt(_)
166            | VfsFileEntry::Mbr(_)
167            | VfsFileEntry::Qcow(_)
168            | VfsFileEntry::SparseImage(_)
169            | VfsFileEntry::Udif(_)
170            | VfsFileEntry::Vhd(_)
171            | VfsFileEntry::Vhdx(_) => None,
172            VfsFileEntry::Ext(ext_file_entry) => ext_file_entry.get_modification_time(),
173            VfsFileEntry::Fake(fake_file_entry) => fake_file_entry.get_modification_time(),
174            VfsFileEntry::Ntfs(ntfs_file_entry) => ntfs_file_entry.get_modification_time(),
175            VfsFileEntry::Os(os_file_entry) => os_file_entry.get_modification_time(),
176        }
177    }
178
179    /// Retrieves the name.
180    pub fn get_name(&self) -> Option<VfsString> {
181        match self {
182            VfsFileEntry::Apm(apm_file_entry) => match apm_file_entry.get_name() {
183                Some(name) => Some(VfsString::String(name)),
184                None => None,
185            },
186            VfsFileEntry::Ext(ext_file_entry) => match ext_file_entry.get_name() {
187                Some(name) => Some(VfsString::Byte(name.clone())),
188                None => None,
189            },
190            VfsFileEntry::Ewf(ewf_file_entry) => match ewf_file_entry.get_name() {
191                Some(name) => Some(VfsString::String(name)),
192                None => None,
193            },
194            VfsFileEntry::Fake(_) => todo!(),
195            VfsFileEntry::Gpt(gpt_file_entry) => match gpt_file_entry.get_name() {
196                Some(name) => Some(VfsString::String(name)),
197                None => None,
198            },
199            VfsFileEntry::Mbr(mbr_file_entry) => match mbr_file_entry.get_name() {
200                Some(name) => Some(VfsString::String(name)),
201                None => None,
202            },
203            VfsFileEntry::Ntfs(ntfs_file_entry) => match ntfs_file_entry.get_name() {
204                Some(name) => Some(VfsString::Ucs2(name.clone())),
205                None => None,
206            },
207            VfsFileEntry::Os(os_file_entry) => match os_file_entry.get_name() {
208                Some(name) => Some(VfsString::OsString(name.to_os_string())),
209                None => None,
210            },
211            VfsFileEntry::Qcow(qcow_file_entry) => match qcow_file_entry.get_name() {
212                Some(name) => Some(VfsString::String(name)),
213                None => None,
214            },
215            VfsFileEntry::SparseImage(sparseimage_file_entry) => {
216                match sparseimage_file_entry.get_name() {
217                    Some(name) => Some(VfsString::String(name)),
218                    None => None,
219                }
220            }
221            VfsFileEntry::Udif(udif_file_entry) => match udif_file_entry.get_name() {
222                Some(name) => Some(VfsString::String(name)),
223                None => None,
224            },
225            VfsFileEntry::Vhd(vhd_file_entry) => match vhd_file_entry.get_name() {
226                Some(name) => Some(VfsString::String(name)),
227                None => None,
228            },
229            VfsFileEntry::Vhdx(vhdx_file_entry) => match vhdx_file_entry.get_name() {
230                Some(name) => Some(VfsString::String(name)),
231                None => None,
232            },
233        }
234    }
235
236    /// Retrieves the size.
237    pub fn get_size(&self) -> u64 {
238        match self {
239            VfsFileEntry::Apm(_)
240            | VfsFileEntry::Ewf(_)
241            | VfsFileEntry::Fake(_)
242            | VfsFileEntry::Gpt(_)
243            | VfsFileEntry::Mbr(_)
244            | VfsFileEntry::Qcow(_)
245            | VfsFileEntry::SparseImage(_)
246            | VfsFileEntry::Udif(_)
247            | VfsFileEntry::Vhd(_)
248            | VfsFileEntry::Vhdx(_) => 1,
249            VfsFileEntry::Ext(ext_file_entry) => ext_file_entry.get_size(),
250            VfsFileEntry::Ntfs(ntfs_file_entry) => ntfs_file_entry.get_size(),
251            VfsFileEntry::Os(_) => todo!(),
252        }
253    }
254
255    /// Retrieves the symbolic link target.
256    pub fn get_symbolic_link_target(&mut self) -> Result<Option<VfsPath>, ErrorTrace> {
257        match self {
258            VfsFileEntry::Apm(_)
259            | VfsFileEntry::Ewf(_)
260            | VfsFileEntry::Fake(_)
261            | VfsFileEntry::Gpt(_)
262            | VfsFileEntry::Mbr(_)
263            | VfsFileEntry::Qcow(_)
264            | VfsFileEntry::SparseImage(_)
265            | VfsFileEntry::Udif(_)
266            | VfsFileEntry::Vhd(_)
267            | VfsFileEntry::Vhdx(_) => Ok(None),
268            VfsFileEntry::Ext(ext_file_entry) => match ext_file_entry.get_symbolic_link_target() {
269                Ok(result) => match result {
270                    Some(name) => {
271                        let path_components: Vec<ByteString> = name
272                            .elements
273                            .split(|value| *value == 0x2f)
274                            .map(|component| ByteString::from(component))
275                            .collect::<Vec<ByteString>>();
276                        Ok(Some(VfsPath::Ext(ExtPath {
277                            components: path_components,
278                        })))
279                    }
280                    None => Ok(None),
281                },
282                Err(mut error) => {
283                    keramics_core::error_trace_add_frame!(
284                        error,
285                        "Unable to retrieve ext symbolic link target"
286                    );
287                    Err(error)
288                }
289            },
290            VfsFileEntry::Ntfs(ntfs_file_entry) => match ntfs_file_entry.get_symbolic_link_target()
291            {
292                Ok(result) => match result {
293                    Some(name) => {
294                        let path_components: Vec<Ucs2String> = name
295                            .elements
296                            .split(|value| *value == 0x005c)
297                            .skip(2) // Strip leading "\\??\\".
298                            .map(|component| Ucs2String::from(component))
299                            .collect::<Vec<Ucs2String>>();
300                        Ok(Some(VfsPath::Ntfs(NtfsPath {
301                            components: path_components,
302                        })))
303                    }
304                    None => Ok(None),
305                },
306                Err(mut error) => {
307                    keramics_core::error_trace_add_frame!(
308                        error,
309                        "Unable to retrieve NTFS symbolic link target"
310                    );
311                    Err(error)
312                }
313            },
314            VfsFileEntry::Os(_) => todo!(),
315        }
316    }
317
318    /// Retrieves the number of data forks.
319    pub fn get_number_of_data_forks(&self) -> Result<usize, ErrorTrace> {
320        let result: usize = match self {
321            VfsFileEntry::Apm(apm_file_entry) => match apm_file_entry {
322                ApmFileEntry::Partition { .. } => 1,
323                ApmFileEntry::Root { .. } => 0,
324            },
325            VfsFileEntry::Ext(ext_file_entry) => {
326                let file_mode: u16 = ext_file_entry.get_file_mode();
327                if file_mode & 0xf000 != EXT_FILE_MODE_TYPE_REGULAR_FILE {
328                    0
329                } else {
330                    1
331                }
332            }
333            VfsFileEntry::Ewf(ewf_file_entry) => match ewf_file_entry {
334                EwfFileEntry::Layer { .. } => 1,
335                EwfFileEntry::Root { .. } => 0,
336            },
337            VfsFileEntry::Fake(fake_file_entry) => match fake_file_entry.get_file_type() {
338                VfsFileType::File => 1,
339                _ => 0,
340            },
341            VfsFileEntry::Gpt(gpt_file_entry) => match gpt_file_entry {
342                GptFileEntry::Partition { .. } => 1,
343                GptFileEntry::Root { .. } => 0,
344            },
345            VfsFileEntry::Mbr(mbr_file_entry) => match mbr_file_entry {
346                MbrFileEntry::Partition { .. } => 1,
347                MbrFileEntry::Root { .. } => 0,
348            },
349            VfsFileEntry::Ntfs(ntfs_file_entry) => {
350                match ntfs_file_entry.get_number_of_data_forks() {
351                    Ok(number_of_data_forks) => number_of_data_forks,
352                    Err(mut error) => {
353                        keramics_core::error_trace_add_frame!(
354                            error,
355                            "Unable to retrieve number of data forks"
356                        );
357                        return Err(error);
358                    }
359                }
360            }
361            VfsFileEntry::Os(os_file_entry) => match os_file_entry.get_file_type() {
362                VfsFileType::File => 1,
363                _ => 0,
364            },
365            VfsFileEntry::Qcow(qcow_file_entry) => match qcow_file_entry {
366                QcowFileEntry::Layer { .. } => 1,
367                QcowFileEntry::Root { .. } => 0,
368            },
369            VfsFileEntry::SparseImage(sparseimage_file_entry) => match sparseimage_file_entry {
370                SparseImageFileEntry::Layer { .. } => 1,
371                SparseImageFileEntry::Root { .. } => 0,
372            },
373            VfsFileEntry::Udif(udif_file_entry) => match udif_file_entry {
374                UdifFileEntry::Layer { .. } => 1,
375                UdifFileEntry::Root { .. } => 0,
376            },
377            VfsFileEntry::Vhd(vhd_file_entry) => match vhd_file_entry {
378                VhdFileEntry::Layer { .. } => 1,
379                VhdFileEntry::Root { .. } => 0,
380            },
381            VfsFileEntry::Vhdx(vhdx_file_entry) => match vhdx_file_entry {
382                VhdxFileEntry::Layer { .. } => 1,
383                VhdxFileEntry::Root { .. } => 0,
384            },
385        };
386        Ok(result)
387    }
388
389    /// Retrieves a specific data fork.
390    pub fn get_data_fork_by_index(
391        &self,
392        data_fork_index: usize,
393    ) -> Result<VfsDataFork<'_>, ErrorTrace> {
394        let data_fork: VfsDataFork = match self {
395            VfsFileEntry::Apm(_) => todo!(),
396            VfsFileEntry::Ext(ext_file_entry) => {
397                if data_fork_index != 0 {
398                    return Err(keramics_core::error_trace_new!(format!(
399                        "Invalid data fork index: {}",
400                        data_fork_index
401                    )));
402                }
403                let result: Option<DataStreamReference> = match ext_file_entry.get_data_stream() {
404                    Ok(result) => result,
405                    Err(mut error) => {
406                        keramics_core::error_trace_add_frame!(
407                            error,
408                            "Unable to retrieve ext data stream"
409                        );
410                        return Err(error);
411                    }
412                };
413                match result {
414                    Some(data_stream) => VfsDataFork::Ext(data_stream),
415                    None => {
416                        return Err(keramics_core::error_trace_new!("Missing ext data stream"));
417                    }
418                }
419            }
420            VfsFileEntry::Ewf(_) => todo!(),
421            VfsFileEntry::Fake(_) => todo!(),
422            VfsFileEntry::Gpt(_) => todo!(),
423            VfsFileEntry::Mbr(_) => todo!(),
424            VfsFileEntry::Ntfs(ntfs_file_entry) => {
425                let ntfs_data_fork: NtfsDataFork =
426                    match ntfs_file_entry.get_data_fork_by_index(data_fork_index) {
427                        Ok(result) => result,
428                        Err(mut error) => {
429                            keramics_core::error_trace_add_frame!(
430                                error,
431                                "Unable to retrieve NTFS data stream"
432                            );
433                            return Err(error);
434                        }
435                    };
436                VfsDataFork::Ntfs(ntfs_data_fork)
437            }
438            VfsFileEntry::Os(_) => todo!(),
439            VfsFileEntry::Qcow(_) => todo!(),
440            VfsFileEntry::SparseImage(_) => todo!(),
441            VfsFileEntry::Udif(_) => todo!(),
442            VfsFileEntry::Vhd(_) => todo!(),
443            VfsFileEntry::Vhdx(_) => todo!(),
444        };
445        Ok(data_fork)
446    }
447
448    /// Retrieves the default data stream.
449    pub fn get_data_stream(&self) -> Result<Option<DataStreamReference>, ErrorTrace> {
450        let result: Option<DataStreamReference> = match self {
451            VfsFileEntry::Apm(apm_file_entry) => match apm_file_entry.get_data_stream() {
452                Ok(result) => result,
453                Err(mut error) => {
454                    keramics_core::error_trace_add_frame!(
455                        error,
456                        "Unable to retrieve APM data stream"
457                    );
458                    return Err(error);
459                }
460            },
461            VfsFileEntry::Ext(ext_file_entry) => match ext_file_entry.get_data_stream() {
462                Ok(result) => result,
463                Err(mut error) => {
464                    keramics_core::error_trace_add_frame!(
465                        error,
466                        "Unable to retrieve ext data stream"
467                    );
468                    return Err(error);
469                }
470            },
471            VfsFileEntry::Ewf(ewf_file_entry) => match ewf_file_entry.get_data_stream() {
472                Ok(result) => result,
473                Err(mut error) => {
474                    keramics_core::error_trace_add_frame!(
475                        error,
476                        "Unable to retrieve EWF data stream"
477                    );
478                    return Err(error);
479                }
480            },
481            VfsFileEntry::Fake(fake_file_entry) => match fake_file_entry.get_data_stream() {
482                Ok(result) => result,
483                Err(mut error) => {
484                    keramics_core::error_trace_add_frame!(
485                        error,
486                        "Unable to retrieve fake data stream"
487                    );
488                    return Err(error);
489                }
490            },
491            VfsFileEntry::Gpt(gpt_file_entry) => match gpt_file_entry.get_data_stream() {
492                Ok(result) => result,
493                Err(mut error) => {
494                    keramics_core::error_trace_add_frame!(
495                        error,
496                        "Unable to retrieve GPT data stream"
497                    );
498                    return Err(error);
499                }
500            },
501            VfsFileEntry::Mbr(mbr_file_entry) => match mbr_file_entry.get_data_stream() {
502                Ok(result) => result,
503                Err(mut error) => {
504                    keramics_core::error_trace_add_frame!(
505                        error,
506                        "Unable to retrieve MBR data stream"
507                    );
508                    return Err(error);
509                }
510            },
511            VfsFileEntry::Ntfs(ntfs_file_entry) => match ntfs_file_entry.get_data_stream() {
512                Ok(result) => result,
513                Err(mut error) => {
514                    keramics_core::error_trace_add_frame!(
515                        error,
516                        "Unable to retrieve NTFS data stream"
517                    );
518                    return Err(error);
519                }
520            },
521            VfsFileEntry::Os(os_file_entry) => match os_file_entry.get_data_stream() {
522                Ok(result) => result,
523                Err(mut error) => {
524                    keramics_core::error_trace_add_frame!(
525                        error,
526                        "Unable to retrieve OS data stream"
527                    );
528                    return Err(error);
529                }
530            },
531            VfsFileEntry::Qcow(qcow_file_entry) => match qcow_file_entry.get_data_stream() {
532                Ok(result) => result,
533                Err(mut error) => {
534                    keramics_core::error_trace_add_frame!(
535                        error,
536                        "Unable to retrieve QCOW data stream"
537                    );
538                    return Err(error);
539                }
540            },
541            VfsFileEntry::SparseImage(sparseimage_file_entry) => {
542                match sparseimage_file_entry.get_data_stream() {
543                    Ok(result) => result,
544                    Err(mut error) => {
545                        keramics_core::error_trace_add_frame!(
546                            error,
547                            "Unable to retrieve sparseimage data stream"
548                        );
549                        return Err(error);
550                    }
551                }
552            }
553            VfsFileEntry::Udif(udif_file_entry) => match udif_file_entry.get_data_stream() {
554                Ok(result) => result,
555                Err(mut error) => {
556                    keramics_core::error_trace_add_frame!(
557                        error,
558                        "Unable to retrieve UDIF data stream"
559                    );
560                    return Err(error);
561                }
562            },
563            VfsFileEntry::Vhd(vhd_file_entry) => match vhd_file_entry.get_data_stream() {
564                Ok(result) => result,
565                Err(mut error) => {
566                    keramics_core::error_trace_add_frame!(
567                        error,
568                        "Unable to retrieve VHD data stream"
569                    );
570                    return Err(error);
571                }
572            },
573            VfsFileEntry::Vhdx(vhdx_file_entry) => match vhdx_file_entry.get_data_stream() {
574                Ok(result) => result,
575                Err(mut error) => {
576                    keramics_core::error_trace_add_frame!(
577                        error,
578                        "Unable to retrieve VHDX data stream"
579                    );
580                    return Err(error);
581                }
582            },
583        };
584        Ok(result)
585    }
586
587    /// Retrieves a data stream with the specified name.
588    pub fn get_data_stream_by_name(
589        &self,
590        name: Option<&str>,
591    ) -> Result<Option<DataStreamReference>, ErrorTrace> {
592        let result: Option<DataStreamReference> = match self {
593            VfsFileEntry::Apm(_)
594            | VfsFileEntry::Ext(_)
595            | VfsFileEntry::Ewf(_)
596            | VfsFileEntry::Fake(_)
597            | VfsFileEntry::Gpt(_)
598            | VfsFileEntry::Mbr(_)
599            | VfsFileEntry::Os(_)
600            | VfsFileEntry::Qcow(_)
601            | VfsFileEntry::SparseImage(_)
602            | VfsFileEntry::Udif(_)
603            | VfsFileEntry::Vhd(_)
604            | VfsFileEntry::Vhdx(_) => match name {
605                Some(_) => None,
606                None => match self.get_data_stream() {
607                    Ok(result) => result,
608                    Err(mut error) => {
609                        keramics_core::error_trace_add_frame!(
610                            error,
611                            "Unable to retrieve data stream"
612                        );
613                        return Err(error);
614                    }
615                },
616            },
617            VfsFileEntry::Ntfs(ntfs_file_entry) => {
618                let ntfs_name: Option<Ucs2String> = match name {
619                    Some(string) => Some(Ucs2String::from(string)),
620                    None => None,
621                };
622                match ntfs_file_entry.get_data_stream_by_name(&ntfs_name) {
623                    Ok(result) => result,
624                    Err(mut error) => {
625                        keramics_core::error_trace_add_frame!(
626                            error,
627                            "Unable to retrieve NTFS data stream"
628                        );
629                        return Err(error);
630                    }
631                }
632            }
633        };
634        Ok(result)
635    }
636
637    /// Retrieves the number of sub file entries.
638    pub fn get_number_of_sub_file_entries(&mut self) -> Result<usize, ErrorTrace> {
639        let number_of_sub_file_entries: usize = match self {
640            VfsFileEntry::Apm(apm_file_entry) => {
641                match apm_file_entry.get_number_of_sub_file_entries() {
642                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
643                    Err(mut error) => {
644                        keramics_core::error_trace_add_frame!(
645                            error,
646                            "Unable to retrieve number of APM sub file entries"
647                        );
648                        return Err(error);
649                    }
650                }
651            }
652            VfsFileEntry::Ext(ext_file_entry) => {
653                match ext_file_entry.get_number_of_sub_file_entries() {
654                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
655                    Err(mut error) => {
656                        keramics_core::error_trace_add_frame!(
657                            error,
658                            "Unable to retrieve number of ext sub file entries"
659                        );
660                        return Err(error);
661                    }
662                }
663            }
664            VfsFileEntry::Ewf(ewf_file_entry) => {
665                match ewf_file_entry.get_number_of_sub_file_entries() {
666                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
667                    Err(mut error) => {
668                        keramics_core::error_trace_add_frame!(
669                            error,
670                            "Unable to retrieve number of EWF sub file entries"
671                        );
672                        return Err(error);
673                    }
674                }
675            }
676            VfsFileEntry::Fake(_) => todo!(),
677            VfsFileEntry::Gpt(gpt_file_entry) => {
678                match gpt_file_entry.get_number_of_sub_file_entries() {
679                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
680                    Err(mut error) => {
681                        keramics_core::error_trace_add_frame!(
682                            error,
683                            "Unable to retrieve number of GPT sub file entries"
684                        );
685                        return Err(error);
686                    }
687                }
688            }
689            VfsFileEntry::Mbr(mbr_file_entry) => {
690                match mbr_file_entry.get_number_of_sub_file_entries() {
691                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
692                    Err(mut error) => {
693                        keramics_core::error_trace_add_frame!(
694                            error,
695                            "Unable to retrieve number of MBR sub file entries"
696                        );
697                        return Err(error);
698                    }
699                }
700            }
701            VfsFileEntry::Ntfs(ntfs_file_entry) => {
702                match ntfs_file_entry.get_number_of_sub_file_entries() {
703                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
704                    Err(mut error) => {
705                        keramics_core::error_trace_add_frame!(
706                            error,
707                            "Unable to retrieve number of NTFS sub file entries"
708                        );
709                        return Err(error);
710                    }
711                }
712            }
713            VfsFileEntry::Os(_) => todo!(),
714            VfsFileEntry::Qcow(qcow_file_entry) => {
715                match qcow_file_entry.get_number_of_sub_file_entries() {
716                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
717                    Err(mut error) => {
718                        keramics_core::error_trace_add_frame!(
719                            error,
720                            "Unable to retrieve number of QCOW sub file entries"
721                        );
722                        return Err(error);
723                    }
724                }
725            }
726            VfsFileEntry::SparseImage(sparseimage_file_entry) => {
727                match sparseimage_file_entry.get_number_of_sub_file_entries() {
728                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
729                    Err(mut error) => {
730                        keramics_core::error_trace_add_frame!(
731                            error,
732                            "Unable to retrieve number of sparseimage sub file entries"
733                        );
734                        return Err(error);
735                    }
736                }
737            }
738            VfsFileEntry::Udif(udif_file_entry) => {
739                match udif_file_entry.get_number_of_sub_file_entries() {
740                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
741                    Err(mut error) => {
742                        keramics_core::error_trace_add_frame!(
743                            error,
744                            "Unable to retrieve number of UDIF sub file entries"
745                        );
746                        return Err(error);
747                    }
748                }
749            }
750            VfsFileEntry::Vhd(vhd_file_entry) => {
751                match vhd_file_entry.get_number_of_sub_file_entries() {
752                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
753                    Err(mut error) => {
754                        keramics_core::error_trace_add_frame!(
755                            error,
756                            "Unable to retrieve number of VHD sub file entries"
757                        );
758                        return Err(error);
759                    }
760                }
761            }
762            VfsFileEntry::Vhdx(vhdx_file_entry) => {
763                match vhdx_file_entry.get_number_of_sub_file_entries() {
764                    Ok(number_of_sub_file_entries) => number_of_sub_file_entries,
765                    Err(mut error) => {
766                        keramics_core::error_trace_add_frame!(
767                            error,
768                            "Unable to retrieve number of VHDX sub file entries"
769                        );
770                        return Err(error);
771                    }
772                }
773            }
774        };
775        Ok(number_of_sub_file_entries)
776    }
777
778    /// Retrieves a specific sub file entry.
779    pub fn get_sub_file_entry_by_index(
780        &mut self,
781        sub_file_entry_index: usize,
782    ) -> Result<VfsFileEntry, ErrorTrace> {
783        let sub_file_entry: VfsFileEntry = match self {
784            VfsFileEntry::Apm(apm_file_entry) => {
785                match apm_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
786                    Ok(sub_file_entry) => VfsFileEntry::Apm(sub_file_entry),
787                    Err(mut error) => {
788                        keramics_core::error_trace_add_frame!(
789                            error,
790                            format!(
791                                "Unable to retrieve APM sub file entry: {}",
792                                sub_file_entry_index
793                            )
794                        );
795                        return Err(error);
796                    }
797                }
798            }
799            VfsFileEntry::Ext(ext_file_entry) => {
800                match ext_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
801                    Ok(sub_file_entry) => VfsFileEntry::Ext(sub_file_entry),
802                    Err(mut error) => {
803                        keramics_core::error_trace_add_frame!(
804                            error,
805                            format!(
806                                "Unable to retrieve ext sub file entry: {}",
807                                sub_file_entry_index
808                            )
809                        );
810                        return Err(error);
811                    }
812                }
813            }
814            VfsFileEntry::Ewf(ewf_file_entry) => {
815                match ewf_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
816                    Ok(sub_file_entry) => VfsFileEntry::Ewf(sub_file_entry),
817                    Err(mut error) => {
818                        keramics_core::error_trace_add_frame!(
819                            error,
820                            format!(
821                                "Unable to retrieve EWF sub file entry: {}",
822                                sub_file_entry_index
823                            )
824                        );
825                        return Err(error);
826                    }
827                }
828            }
829            VfsFileEntry::Fake(_) => todo!(),
830            VfsFileEntry::Gpt(gpt_file_entry) => {
831                match gpt_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
832                    Ok(sub_file_entry) => VfsFileEntry::Gpt(sub_file_entry),
833                    Err(mut error) => {
834                        keramics_core::error_trace_add_frame!(
835                            error,
836                            format!(
837                                "Unable to retrieve GPT sub file entry: {}",
838                                sub_file_entry_index
839                            )
840                        );
841                        return Err(error);
842                    }
843                }
844            }
845            VfsFileEntry::Mbr(mbr_file_entry) => {
846                match mbr_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
847                    Ok(sub_file_entry) => VfsFileEntry::Mbr(sub_file_entry),
848                    Err(mut error) => {
849                        keramics_core::error_trace_add_frame!(
850                            error,
851                            format!(
852                                "Unable to retrieve MBR sub file entry: {}",
853                                sub_file_entry_index
854                            )
855                        );
856                        return Err(error);
857                    }
858                }
859            }
860            VfsFileEntry::Ntfs(ntfs_file_entry) => {
861                match ntfs_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
862                    Ok(sub_file_entry) => VfsFileEntry::Ntfs(sub_file_entry),
863                    Err(mut error) => {
864                        keramics_core::error_trace_add_frame!(
865                            error,
866                            format!(
867                                "Unable to retrieve NTFS sub file entry: {}",
868                                sub_file_entry_index
869                            )
870                        );
871                        return Err(error);
872                    }
873                }
874            }
875            VfsFileEntry::Os(_) => todo!(),
876            VfsFileEntry::Qcow(qcow_file_entry) => {
877                match qcow_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
878                    Ok(sub_file_entry) => VfsFileEntry::Qcow(sub_file_entry),
879                    Err(mut error) => {
880                        keramics_core::error_trace_add_frame!(
881                            error,
882                            format!(
883                                "Unable to retrieve QCOW sub file entry: {}",
884                                sub_file_entry_index
885                            )
886                        );
887                        return Err(error);
888                    }
889                }
890            }
891            VfsFileEntry::SparseImage(sparseimage_file_entry) => {
892                match sparseimage_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
893                    Ok(sub_file_entry) => VfsFileEntry::SparseImage(sub_file_entry),
894                    Err(mut error) => {
895                        keramics_core::error_trace_add_frame!(
896                            error,
897                            format!(
898                                "Unable to retrieve sparseimage sub file entry: {}",
899                                sub_file_entry_index
900                            )
901                        );
902                        return Err(error);
903                    }
904                }
905            }
906            VfsFileEntry::Udif(udif_file_entry) => {
907                match udif_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
908                    Ok(sub_file_entry) => VfsFileEntry::Udif(sub_file_entry),
909                    Err(mut error) => {
910                        keramics_core::error_trace_add_frame!(
911                            error,
912                            format!(
913                                "Unable to retrieve UDIF sub file entry: {}",
914                                sub_file_entry_index
915                            )
916                        );
917                        return Err(error);
918                    }
919                }
920            }
921            VfsFileEntry::Vhd(vhd_file_entry) => {
922                match vhd_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
923                    Ok(sub_file_entry) => VfsFileEntry::Vhd(sub_file_entry),
924                    Err(mut error) => {
925                        keramics_core::error_trace_add_frame!(
926                            error,
927                            format!(
928                                "Unable to retrieve VHD sub file entry: {}",
929                                sub_file_entry_index
930                            )
931                        );
932                        return Err(error);
933                    }
934                }
935            }
936            VfsFileEntry::Vhdx(vhdx_file_entry) => {
937                match vhdx_file_entry.get_sub_file_entry_by_index(sub_file_entry_index) {
938                    Ok(sub_file_entry) => VfsFileEntry::Vhdx(sub_file_entry),
939                    Err(mut error) => {
940                        keramics_core::error_trace_add_frame!(
941                            error,
942                            format!(
943                                "Unable to retrieve VHDX sub file entry: {}",
944                                sub_file_entry_index
945                            )
946                        );
947                        return Err(error);
948                    }
949                }
950            }
951        };
952        Ok(sub_file_entry)
953    }
954
955    /// Retrieves a sub file entries iterator.
956    pub fn sub_file_entries(&mut self) -> Result<VfsFileEntriesIterator<'_>, ErrorTrace> {
957        let number_of_sub_file_entries: usize = self.get_number_of_sub_file_entries()?;
958        Ok(VfsFileEntriesIterator::new(
959            self,
960            number_of_sub_file_entries,
961        ))
962    }
963
964    /// Determines if the file entry is the root directory.
965    pub fn is_root_directory(&self) -> bool {
966        match self {
967            VfsFileEntry::Apm(apm_file_entry) => todo!(),
968            VfsFileEntry::Ext(ext_file_entry) => ext_file_entry.is_root_directory(),
969            VfsFileEntry::Ewf(ewf_file_entry) => todo!(),
970            VfsFileEntry::Fake(_) => todo!(),
971            VfsFileEntry::Gpt(gpt_file_entry) => todo!(),
972            VfsFileEntry::Mbr(mbr_file_entry) => todo!(),
973            VfsFileEntry::Ntfs(ntfs_file_entry) => ntfs_file_entry.is_root_directory(),
974            VfsFileEntry::Os(_) => todo!(),
975            VfsFileEntry::Qcow(qcow_file_entry) => todo!(),
976            VfsFileEntry::SparseImage(sparseimage_file_entry) => todo!(),
977            VfsFileEntry::Udif(udif_file_entry) => todo!(),
978            VfsFileEntry::Vhd(vhd_file_entry) => todo!(),
979            VfsFileEntry::Vhdx(vhdx_file_entry) => todo!(),
980        }
981    }
982}
983
984#[cfg(test)]
985mod tests {
986    use super::*;
987
988    use keramics_datetime::PosixTime32;
989
990    use crate::enums::{VfsFileType, VfsType};
991    use crate::file_system::VfsFileSystem;
992    use crate::location::{VfsLocation, new_os_vfs_location};
993    use crate::path::VfsPath;
994    use crate::types::VfsFileSystemReference;
995
996    fn get_parent_file_system() -> VfsFileSystemReference {
997        VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os))
998    }
999
1000    fn get_apm_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1001        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Apm);
1002
1003        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1004        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/apm/apm.dmg");
1005        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1006
1007        Ok(vfs_file_system)
1008    }
1009
1010    fn get_apm_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1011        let vfs_file_system: VfsFileSystem = get_apm_file_system()?;
1012
1013        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, path);
1014        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1015            Some(file_entry) => Ok(file_entry),
1016            None => Err(keramics_core::error_trace_new!(format!(
1017                "No such file entry: {}",
1018                path
1019            ))),
1020        }
1021    }
1022
1023    fn get_ext_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1024        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Ext);
1025
1026        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1027        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/ext/ext2.raw");
1028        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1029
1030        Ok(vfs_file_system)
1031    }
1032
1033    fn get_ext_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1034        let vfs_file_system: VfsFileSystem = get_ext_file_system()?;
1035
1036        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, path);
1037        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1038            Some(file_entry) => Ok(file_entry),
1039            None => Err(keramics_core::error_trace_new!(format!(
1040                "No such file entry: {}",
1041                path
1042            ))),
1043        }
1044    }
1045
1046    fn get_ewf_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1047        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Ewf);
1048
1049        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1050        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/ewf/ext2.E01");
1051        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1052
1053        Ok(vfs_file_system)
1054    }
1055
1056    fn get_ewf_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1057        let vfs_file_system: VfsFileSystem = get_ewf_file_system()?;
1058
1059        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, path);
1060        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1061            Some(file_entry) => Ok(file_entry),
1062            None => Err(keramics_core::error_trace_new!(format!(
1063                "No such file entry: {}",
1064                path
1065            ))),
1066        }
1067    }
1068
1069    fn get_gpt_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1070        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Gpt);
1071
1072        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1073        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/gpt/gpt.raw");
1074        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1075
1076        Ok(vfs_file_system)
1077    }
1078
1079    fn get_gpt_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1080        let vfs_file_system: VfsFileSystem = get_gpt_file_system()?;
1081
1082        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, path);
1083        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1084            Some(file_entry) => Ok(file_entry),
1085            None => Err(keramics_core::error_trace_new!(format!(
1086                "No such file entry: {}",
1087                path
1088            ))),
1089        }
1090    }
1091
1092    fn get_mbr_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1093        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Mbr);
1094
1095        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1096        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/mbr/mbr.raw");
1097        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1098
1099        Ok(vfs_file_system)
1100    }
1101
1102    fn get_mbr_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1103        let vfs_file_system: VfsFileSystem = get_mbr_file_system()?;
1104
1105        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, path);
1106        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1107            Some(file_entry) => Ok(file_entry),
1108            None => Err(keramics_core::error_trace_new!(format!(
1109                "No such file entry: {}",
1110                path
1111            ))),
1112        }
1113    }
1114
1115    fn get_os_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1116        let vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Os);
1117
1118        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Os, path);
1119        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1120            Some(file_entry) => Ok(file_entry),
1121            None => Err(keramics_core::error_trace_new!(format!(
1122                "No such file entry: {}",
1123                path
1124            ))),
1125        }
1126    }
1127
1128    fn get_qcow_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1129        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Qcow);
1130
1131        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1132        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/qcow/ext2.qcow2");
1133        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1134
1135        Ok(vfs_file_system)
1136    }
1137
1138    fn get_qcow_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1139        let vfs_file_system: VfsFileSystem = get_qcow_file_system()?;
1140
1141        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, path);
1142        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1143            Some(file_entry) => Ok(file_entry),
1144            None => Err(keramics_core::error_trace_new!(format!(
1145                "No such file entry: {}",
1146                path
1147            ))),
1148        }
1149    }
1150
1151    fn get_sparseimage_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1152        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::SparseImage);
1153
1154        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1155        let vfs_location: VfsLocation =
1156            new_os_vfs_location("../test_data/sparseimage/hfsplus.sparseimage");
1157        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1158
1159        Ok(vfs_file_system)
1160    }
1161
1162    fn get_sparseimage_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1163        let vfs_file_system: VfsFileSystem = get_sparseimage_file_system()?;
1164
1165        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, path);
1166        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1167            Some(file_entry) => Ok(file_entry),
1168            None => Err(keramics_core::error_trace_new!(format!(
1169                "No such file entry: {}",
1170                path
1171            ))),
1172        }
1173    }
1174
1175    fn get_udif_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1176        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Udif);
1177
1178        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1179        let vfs_location: VfsLocation = new_os_vfs_location("../test_data/udif/hfsplus_zlib.dmg");
1180        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1181
1182        Ok(vfs_file_system)
1183    }
1184
1185    fn get_udif_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1186        let vfs_file_system: VfsFileSystem = get_udif_file_system()?;
1187
1188        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, path);
1189        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1190            Some(file_entry) => Ok(file_entry),
1191            None => Err(keramics_core::error_trace_new!(format!(
1192                "No such file entry: {}",
1193                path
1194            ))),
1195        }
1196    }
1197
1198    fn get_vhd_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1199        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Vhd);
1200
1201        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1202        let vfs_location: VfsLocation =
1203            new_os_vfs_location("../test_data/vhd/ntfs-differential.vhd");
1204        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1205
1206        Ok(vfs_file_system)
1207    }
1208
1209    fn get_vhd_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1210        let vfs_file_system: VfsFileSystem = get_vhd_file_system()?;
1211
1212        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, path);
1213        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1214            Some(file_entry) => Ok(file_entry),
1215            None => Err(keramics_core::error_trace_new!(format!(
1216                "No such file entry: {}",
1217                path
1218            ))),
1219        }
1220    }
1221
1222    fn get_vhdx_file_system() -> Result<VfsFileSystem, ErrorTrace> {
1223        let mut vfs_file_system: VfsFileSystem = VfsFileSystem::new(&VfsType::Vhdx);
1224
1225        let parent_file_system: VfsFileSystemReference = get_parent_file_system();
1226        let vfs_location: VfsLocation =
1227            new_os_vfs_location("../test_data/vhdx/ntfs-differential.vhdx");
1228        vfs_file_system.open(Some(&parent_file_system), &vfs_location)?;
1229
1230        Ok(vfs_file_system)
1231    }
1232
1233    fn get_vhdx_file_entry(path: &str) -> Result<VfsFileEntry, ErrorTrace> {
1234        let vfs_file_system: VfsFileSystem = get_vhdx_file_system()?;
1235
1236        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, path);
1237        match vfs_file_system.get_file_entry_by_path(&vfs_path)? {
1238            Some(file_entry) => Ok(file_entry),
1239            None => Err(keramics_core::error_trace_new!(format!(
1240                "No such file entry: {}",
1241                path
1242            ))),
1243        }
1244    }
1245
1246    #[test]
1247    fn test_get_access_time_with_apm() -> Result<(), ErrorTrace> {
1248        let vfs_file_entry: VfsFileEntry = get_apm_file_entry("/apm2")?;
1249
1250        assert_eq!(vfs_file_entry.get_access_time(), None);
1251
1252        Ok(())
1253    }
1254
1255    #[test]
1256    fn test_get_access_time_with_ext() -> Result<(), ErrorTrace> {
1257        let vfs_file_entry: VfsFileEntry = get_ext_file_entry("/testdir1/testfile1")?;
1258
1259        assert_eq!(
1260            vfs_file_entry.get_access_time(),
1261            Some(&DateTime::PosixTime32(PosixTime32 {
1262                timestamp: 1735977482
1263            }))
1264        );
1265
1266        Ok(())
1267    }
1268
1269    #[test]
1270    fn test_get_access_time_with_ewf() -> Result<(), ErrorTrace> {
1271        let vfs_file_entry: VfsFileEntry = get_ewf_file_entry("/ewf1")?;
1272
1273        assert_eq!(vfs_file_entry.get_access_time(), None);
1274
1275        Ok(())
1276    }
1277
1278    // TODO: add test_get_access_time_with_fake
1279
1280    #[test]
1281    fn test_get_access_time_with_gpt() -> Result<(), ErrorTrace> {
1282        let vfs_file_entry: VfsFileEntry = get_gpt_file_entry("/gpt2")?;
1283
1284        assert_eq!(vfs_file_entry.get_access_time(), None);
1285
1286        Ok(())
1287    }
1288
1289    // TODO: add test_get_access_time_with_ntfs
1290
1291    #[test]
1292    fn test_get_access_time_with_mbr() -> Result<(), ErrorTrace> {
1293        let vfs_file_entry: VfsFileEntry = get_mbr_file_entry("/mbr2")?;
1294
1295        assert_eq!(vfs_file_entry.get_access_time(), None);
1296
1297        Ok(())
1298    }
1299
1300    #[test]
1301    fn test_get_access_time_with_os() -> Result<(), ErrorTrace> {
1302        let vfs_file_entry: VfsFileEntry = get_os_file_entry("../test_data/file.txt")?;
1303
1304        assert_ne!(vfs_file_entry.get_access_time(), None);
1305
1306        Ok(())
1307    }
1308
1309    #[test]
1310    fn test_get_access_time_with_qcow() -> Result<(), ErrorTrace> {
1311        let vfs_file_entry: VfsFileEntry = get_qcow_file_entry("/qcow1")?;
1312
1313        assert_eq!(vfs_file_entry.get_access_time(), None);
1314
1315        Ok(())
1316    }
1317
1318    #[test]
1319    fn test_get_access_time_with_sparseimage() -> Result<(), ErrorTrace> {
1320        let vfs_file_entry: VfsFileEntry = get_sparseimage_file_entry("/sparseimage1")?;
1321
1322        assert_eq!(vfs_file_entry.get_access_time(), None);
1323
1324        Ok(())
1325    }
1326
1327    #[test]
1328    fn test_get_access_time_with_udif() -> Result<(), ErrorTrace> {
1329        let vfs_file_entry: VfsFileEntry = get_udif_file_entry("/udif1")?;
1330
1331        assert_eq!(vfs_file_entry.get_access_time(), None);
1332
1333        Ok(())
1334    }
1335
1336    #[test]
1337    fn test_get_access_time_with_vhd() -> Result<(), ErrorTrace> {
1338        let vfs_file_entry: VfsFileEntry = get_vhd_file_entry("/vhd1")?;
1339
1340        assert_eq!(vfs_file_entry.get_access_time(), None);
1341
1342        Ok(())
1343    }
1344
1345    #[test]
1346    fn test_get_access_time_with_vhdx() -> Result<(), ErrorTrace> {
1347        let vfs_file_entry: VfsFileEntry = get_vhdx_file_entry("/vhdx1")?;
1348
1349        assert_eq!(vfs_file_entry.get_access_time(), None);
1350
1351        Ok(())
1352    }
1353
1354    #[test]
1355    fn test_get_change_time_with_apm() -> Result<(), ErrorTrace> {
1356        let vfs_file_entry: VfsFileEntry = get_apm_file_entry("/apm2")?;
1357
1358        assert_eq!(vfs_file_entry.get_change_time(), None);
1359
1360        Ok(())
1361    }
1362
1363    #[test]
1364    fn test_get_change_time_with_ext() -> Result<(), ErrorTrace> {
1365        let vfs_file_entry: VfsFileEntry = get_ext_file_entry("/testdir1/testfile1")?;
1366
1367        assert_eq!(
1368            vfs_file_entry.get_change_time(),
1369            Some(&DateTime::PosixTime32(PosixTime32 {
1370                timestamp: 1735977481
1371            }))
1372        );
1373
1374        Ok(())
1375    }
1376
1377    #[test]
1378    fn test_get_change_time_with_ewf() -> Result<(), ErrorTrace> {
1379        let vfs_file_entry: VfsFileEntry = get_ewf_file_entry("/ewf1")?;
1380
1381        assert_eq!(vfs_file_entry.get_change_time(), None);
1382
1383        Ok(())
1384    }
1385
1386    // TODO: add test_get_change_time_with_fake
1387
1388    #[test]
1389    fn test_get_change_time_with_gpt() -> Result<(), ErrorTrace> {
1390        let vfs_file_entry: VfsFileEntry = get_gpt_file_entry("/gpt2")?;
1391
1392        assert_eq!(vfs_file_entry.get_change_time(), None);
1393
1394        Ok(())
1395    }
1396
1397    // TODO: add test_get_change_time_with_ntfs
1398
1399    #[test]
1400    fn test_get_change_time_with_mbr() -> Result<(), ErrorTrace> {
1401        let vfs_file_entry: VfsFileEntry = get_mbr_file_entry("/mbr2")?;
1402
1403        assert_eq!(vfs_file_entry.get_change_time(), None);
1404
1405        Ok(())
1406    }
1407
1408    // TODO: add test_get_change_time_with_os
1409
1410    #[test]
1411    fn test_get_change_time_with_qcow() -> Result<(), ErrorTrace> {
1412        let vfs_file_entry: VfsFileEntry = get_qcow_file_entry("/qcow1")?;
1413
1414        assert_eq!(vfs_file_entry.get_change_time(), None);
1415
1416        Ok(())
1417    }
1418
1419    #[test]
1420    fn test_get_change_time_with_sparseimage() -> Result<(), ErrorTrace> {
1421        let vfs_file_entry: VfsFileEntry = get_sparseimage_file_entry("/sparseimage1")?;
1422
1423        assert_eq!(vfs_file_entry.get_change_time(), None);
1424
1425        Ok(())
1426    }
1427
1428    #[test]
1429    fn test_get_change_time_with_udif() -> Result<(), ErrorTrace> {
1430        let vfs_file_entry: VfsFileEntry = get_udif_file_entry("/udif1")?;
1431
1432        assert_eq!(vfs_file_entry.get_change_time(), None);
1433
1434        Ok(())
1435    }
1436
1437    #[test]
1438    fn test_get_change_time_with_vhd() -> Result<(), ErrorTrace> {
1439        let vfs_file_entry: VfsFileEntry = get_vhd_file_entry("/vhd2")?;
1440
1441        assert_eq!(vfs_file_entry.get_change_time(), None);
1442
1443        Ok(())
1444    }
1445
1446    #[test]
1447    fn test_get_change_time_with_vhdx() -> Result<(), ErrorTrace> {
1448        let vfs_file_entry: VfsFileEntry = get_vhdx_file_entry("/vhdx2")?;
1449
1450        assert_eq!(vfs_file_entry.get_change_time(), None);
1451
1452        Ok(())
1453    }
1454
1455    #[test]
1456    fn test_get_creation_time_with_apm() -> Result<(), ErrorTrace> {
1457        let vfs_file_entry: VfsFileEntry = get_apm_file_entry("/apm2")?;
1458
1459        assert_eq!(vfs_file_entry.get_creation_time(), None);
1460
1461        Ok(())
1462    }
1463
1464    #[test]
1465    fn test_get_creation_time_with_ext() -> Result<(), ErrorTrace> {
1466        let vfs_file_entry: VfsFileEntry = get_ext_file_entry("/testdir1/testfile1")?;
1467
1468        assert_eq!(vfs_file_entry.get_creation_time(), None);
1469
1470        Ok(())
1471    }
1472
1473    #[test]
1474    fn test_get_creation_time_with_ewf() -> Result<(), ErrorTrace> {
1475        let vfs_file_entry: VfsFileEntry = get_ewf_file_entry("/ewf1")?;
1476
1477        assert_eq!(vfs_file_entry.get_creation_time(), None);
1478
1479        Ok(())
1480    }
1481
1482    // TODO: add test_get_creation_time_with_fake
1483
1484    #[test]
1485    fn test_get_creation_time_with_gpt() -> Result<(), ErrorTrace> {
1486        let vfs_file_entry: VfsFileEntry = get_gpt_file_entry("/gpt2")?;
1487
1488        assert_eq!(vfs_file_entry.get_creation_time(), None);
1489
1490        Ok(())
1491    }
1492
1493    // TODO: add test_get_creation_time_with_ntfs
1494
1495    #[test]
1496    fn test_get_creation_time_with_mbr() -> Result<(), ErrorTrace> {
1497        let vfs_file_entry: VfsFileEntry = get_mbr_file_entry("/mbr2")?;
1498
1499        assert_eq!(vfs_file_entry.get_creation_time(), None);
1500
1501        Ok(())
1502    }
1503
1504    // TODO: add test_get_creation_time_with_os
1505
1506    #[test]
1507    fn test_get_creation_time_with_qcow() -> Result<(), ErrorTrace> {
1508        let vfs_file_entry: VfsFileEntry = get_qcow_file_entry("/qcow1")?;
1509
1510        assert_eq!(vfs_file_entry.get_creation_time(), None);
1511
1512        Ok(())
1513    }
1514
1515    #[test]
1516    fn test_get_creation_time_with_sparseimage() -> Result<(), ErrorTrace> {
1517        let vfs_file_entry: VfsFileEntry = get_sparseimage_file_entry("/sparseimage1")?;
1518
1519        assert_eq!(vfs_file_entry.get_creation_time(), None);
1520
1521        Ok(())
1522    }
1523
1524    #[test]
1525    fn test_get_creation_time_with_udif() -> Result<(), ErrorTrace> {
1526        let vfs_file_entry: VfsFileEntry = get_udif_file_entry("/udif1")?;
1527
1528        assert_eq!(vfs_file_entry.get_creation_time(), None);
1529
1530        Ok(())
1531    }
1532
1533    #[test]
1534    fn test_get_creation_time_with_vhd() -> Result<(), ErrorTrace> {
1535        let vfs_file_entry: VfsFileEntry = get_vhd_file_entry("/vhd2")?;
1536
1537        assert_eq!(vfs_file_entry.get_creation_time(), None);
1538
1539        Ok(())
1540    }
1541
1542    #[test]
1543    fn test_get_creation_time_with_vhdx() -> Result<(), ErrorTrace> {
1544        let vfs_file_entry: VfsFileEntry = get_vhdx_file_entry("/vhdx2")?;
1545
1546        assert_eq!(vfs_file_entry.get_creation_time(), None);
1547
1548        Ok(())
1549    }
1550
1551    #[test]
1552    fn test_get_file_type_with_apm() -> Result<(), ErrorTrace> {
1553        let vfs_file_system: VfsFileSystem = get_apm_file_system()?;
1554
1555        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/");
1556        let vfs_file_entry: VfsFileEntry =
1557            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1558
1559        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1560
1561        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/apm2");
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::File);
1566
1567        Ok(())
1568    }
1569
1570    #[test]
1571    fn test_get_file_type_with_ext() -> Result<(), ErrorTrace> {
1572        let vfs_file_system: VfsFileSystem = get_ext_file_system()?;
1573
1574        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/testdir1");
1575        let vfs_file_entry: VfsFileEntry =
1576            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1577
1578        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1579
1580        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/testdir1/testfile1");
1581        let vfs_file_entry: VfsFileEntry =
1582            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1583
1584        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1585
1586        Ok(())
1587    }
1588
1589    #[test]
1590    fn test_get_file_type_with_ewf() -> Result<(), ErrorTrace> {
1591        let vfs_file_system: VfsFileSystem = get_ewf_file_system()?;
1592
1593        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/");
1594        let vfs_file_entry: VfsFileEntry =
1595            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1596
1597        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1598
1599        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/ewf1");
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::File);
1604
1605        Ok(())
1606    }
1607
1608    // TODO: add test_get_file_type_with_fake
1609
1610    #[test]
1611    fn test_get_file_type_with_gpt() -> Result<(), ErrorTrace> {
1612        let vfs_file_system: VfsFileSystem = get_gpt_file_system()?;
1613
1614        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/");
1615        let vfs_file_entry: VfsFileEntry =
1616            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1617
1618        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1619
1620        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/gpt2");
1621        let vfs_file_entry: VfsFileEntry =
1622            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1623
1624        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1625
1626        Ok(())
1627    }
1628
1629    // TODO: add test_get_file_type_with_ntfs
1630
1631    #[test]
1632    fn test_get_file_type_with_mbr() -> Result<(), ErrorTrace> {
1633        let vfs_file_system: VfsFileSystem = get_mbr_file_system()?;
1634
1635        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/");
1636        let vfs_file_entry: VfsFileEntry =
1637            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1638
1639        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1640
1641        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/mbr2");
1642        let vfs_file_entry: VfsFileEntry =
1643            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1644
1645        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1646
1647        Ok(())
1648    }
1649
1650    // TODO: add test_get_file_type_with_os
1651
1652    #[test]
1653    fn test_get_file_type_with_qcow() -> Result<(), ErrorTrace> {
1654        let vfs_file_system: VfsFileSystem = get_qcow_file_system()?;
1655
1656        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/");
1657        let vfs_file_entry: VfsFileEntry =
1658            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1659
1660        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1661
1662        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/qcow1");
1663        let vfs_file_entry: VfsFileEntry =
1664            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1665
1666        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1667
1668        Ok(())
1669    }
1670
1671    #[test]
1672    fn test_get_file_type_with_sparseimage() -> Result<(), ErrorTrace> {
1673        let vfs_file_system: VfsFileSystem = get_sparseimage_file_system()?;
1674
1675        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/");
1676        let vfs_file_entry: VfsFileEntry =
1677            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1678
1679        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1680
1681        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/sparseimage1");
1682        let vfs_file_entry: VfsFileEntry =
1683            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1684
1685        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1686
1687        Ok(())
1688    }
1689
1690    #[test]
1691    fn test_get_file_type_with_udif() -> Result<(), ErrorTrace> {
1692        let vfs_file_system: VfsFileSystem = get_udif_file_system()?;
1693
1694        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/");
1695        let vfs_file_entry: VfsFileEntry =
1696            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1697
1698        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1699
1700        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/udif1");
1701        let vfs_file_entry: VfsFileEntry =
1702            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1703
1704        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1705
1706        Ok(())
1707    }
1708
1709    #[test]
1710    fn test_get_file_type_with_vhd() -> Result<(), ErrorTrace> {
1711        let vfs_file_system: VfsFileSystem = get_vhd_file_system()?;
1712
1713        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/");
1714        let vfs_file_entry: VfsFileEntry =
1715            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1716
1717        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1718
1719        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/vhd2");
1720        let vfs_file_entry: VfsFileEntry =
1721            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1722
1723        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1724
1725        Ok(())
1726    }
1727
1728    #[test]
1729    fn test_get_file_type_with_vhdx() -> Result<(), ErrorTrace> {
1730        let vfs_file_system: VfsFileSystem = get_vhdx_file_system()?;
1731
1732        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/");
1733        let vfs_file_entry: VfsFileEntry =
1734            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1735
1736        assert!(vfs_file_entry.get_file_type() == VfsFileType::Directory);
1737
1738        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/vhdx2");
1739        let vfs_file_entry: VfsFileEntry =
1740            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1741
1742        assert!(vfs_file_entry.get_file_type() == VfsFileType::File);
1743
1744        Ok(())
1745    }
1746
1747    // TODO: add tests for get_group_identifier
1748
1749    #[test]
1750    fn test_get_modification_time_with_apm() -> Result<(), ErrorTrace> {
1751        let vfs_file_entry: VfsFileEntry = get_apm_file_entry("/apm2")?;
1752
1753        assert_eq!(vfs_file_entry.get_modification_time(), None);
1754
1755        Ok(())
1756    }
1757
1758    #[test]
1759    fn test_get_modification_time_with_ext() -> Result<(), ErrorTrace> {
1760        let vfs_file_entry: VfsFileEntry = get_ext_file_entry("/testdir1/testfile1")?;
1761
1762        assert_eq!(
1763            vfs_file_entry.get_modification_time(),
1764            Some(&DateTime::PosixTime32(PosixTime32 {
1765                timestamp: 1735977481
1766            }))
1767        );
1768
1769        Ok(())
1770    }
1771
1772    #[test]
1773    fn test_get_modification_time_with_ewf() -> Result<(), ErrorTrace> {
1774        let vfs_file_entry: VfsFileEntry = get_ewf_file_entry("/ewf1")?;
1775
1776        assert_eq!(vfs_file_entry.get_modification_time(), None);
1777
1778        Ok(())
1779    }
1780
1781    // TODO: add test_get_modification_time_with_fake
1782
1783    #[test]
1784    fn test_get_modification_time_with_gpt() -> Result<(), ErrorTrace> {
1785        let vfs_file_entry: VfsFileEntry = get_gpt_file_entry("/gpt2")?;
1786
1787        assert_eq!(vfs_file_entry.get_modification_time(), None);
1788
1789        Ok(())
1790    }
1791
1792    // TODO: add test_get_modification_time_with_ntfs
1793
1794    #[test]
1795    fn test_get_modification_time_with_mbr() -> Result<(), ErrorTrace> {
1796        let vfs_file_entry: VfsFileEntry = get_mbr_file_entry("/mbr2")?;
1797
1798        assert_eq!(vfs_file_entry.get_modification_time(), None);
1799
1800        Ok(())
1801    }
1802
1803    // TODO: add test_get_modification_time_with_os
1804
1805    #[test]
1806    fn test_get_modification_time_with_qcow() -> Result<(), ErrorTrace> {
1807        let vfs_file_entry: VfsFileEntry = get_qcow_file_entry("/qcow1")?;
1808
1809        assert_eq!(vfs_file_entry.get_modification_time(), None);
1810
1811        Ok(())
1812    }
1813
1814    #[test]
1815    fn test_get_modification_time_with_sparseimage() -> Result<(), ErrorTrace> {
1816        let vfs_file_entry: VfsFileEntry = get_sparseimage_file_entry("/sparseimage1")?;
1817
1818        assert_eq!(vfs_file_entry.get_modification_time(), None);
1819
1820        Ok(())
1821    }
1822
1823    #[test]
1824    fn test_get_modification_time_with_udif() -> Result<(), ErrorTrace> {
1825        let vfs_file_entry: VfsFileEntry = get_udif_file_entry("/udif1")?;
1826
1827        assert_eq!(vfs_file_entry.get_modification_time(), None);
1828
1829        Ok(())
1830    }
1831
1832    #[test]
1833    fn test_get_modification_time_with_vhd() -> Result<(), ErrorTrace> {
1834        let vfs_file_entry: VfsFileEntry = get_vhd_file_entry("/vhd2")?;
1835
1836        assert_eq!(vfs_file_entry.get_modification_time(), None);
1837
1838        Ok(())
1839    }
1840
1841    #[test]
1842    fn test_get_modification_time_with_vhdx() -> Result<(), ErrorTrace> {
1843        let vfs_file_entry: VfsFileEntry = get_vhdx_file_entry("/vhdx2")?;
1844
1845        assert_eq!(vfs_file_entry.get_modification_time(), None);
1846
1847        Ok(())
1848    }
1849
1850    // TODO: add tests for get_name
1851    // TODO: add tests for get_number_of_links
1852    // TODO: add tests for get_size
1853    // TODO: add tests for get_symbolic_link_target
1854    // TODO: add tests for get_number_of_data_forks
1855
1856    #[test]
1857    fn test_get_data_stream_with_apm() -> Result<(), ErrorTrace> {
1858        let vfs_file_system: VfsFileSystem = get_apm_file_system()?;
1859
1860        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/");
1861        let vfs_file_entry: VfsFileEntry =
1862            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1863
1864        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1865        assert!(result.is_none());
1866
1867        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Apm, "/apm2");
1868        let vfs_file_entry: VfsFileEntry =
1869            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1870
1871        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1872        assert!(result.is_some());
1873
1874        Ok(())
1875    }
1876
1877    #[test]
1878    fn test_get_data_stream_with_ext() -> Result<(), ErrorTrace> {
1879        let vfs_file_system: VfsFileSystem = get_ext_file_system()?;
1880
1881        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/testdir1");
1882        let vfs_file_entry: VfsFileEntry =
1883            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1884
1885        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1886        assert!(result.is_none());
1887
1888        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ext, "/testdir1/testfile1");
1889        let vfs_file_entry: VfsFileEntry =
1890            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1891
1892        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1893        assert!(result.is_some());
1894
1895        Ok(())
1896    }
1897
1898    #[test]
1899    fn test_get_data_stream_with_ewf() -> Result<(), ErrorTrace> {
1900        let vfs_file_system: VfsFileSystem = get_ewf_file_system()?;
1901
1902        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/");
1903        let vfs_file_entry: VfsFileEntry =
1904            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1905
1906        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1907        assert!(result.is_none());
1908
1909        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Ewf, "/ewf1");
1910        let vfs_file_entry: VfsFileEntry =
1911            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1912
1913        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1914        assert!(result.is_some());
1915
1916        Ok(())
1917    }
1918
1919    // TODO: add test_get_data_stream_with_fake
1920
1921    #[test]
1922    fn test_get_data_stream_with_gpt() -> Result<(), ErrorTrace> {
1923        let vfs_file_system: VfsFileSystem = get_gpt_file_system()?;
1924
1925        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/");
1926        let vfs_file_entry: VfsFileEntry =
1927            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1928
1929        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1930        assert!(result.is_none());
1931
1932        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Gpt, "/gpt2");
1933        let vfs_file_entry: VfsFileEntry =
1934            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1935
1936        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1937        assert!(result.is_some());
1938
1939        Ok(())
1940    }
1941
1942    // TODO: add test_get_data_stream_with_ntfs
1943
1944    #[test]
1945    fn test_get_data_stream_with_mbr() -> Result<(), ErrorTrace> {
1946        let vfs_file_system: VfsFileSystem = get_mbr_file_system()?;
1947
1948        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/");
1949        let vfs_file_entry: VfsFileEntry =
1950            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1951
1952        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1953        assert!(result.is_none());
1954
1955        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Mbr, "/mbr2");
1956        let vfs_file_entry: VfsFileEntry =
1957            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1958
1959        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1960        assert!(result.is_some());
1961
1962        Ok(())
1963    }
1964
1965    // TODO: add test_get_data_stream_with_os
1966
1967    #[test]
1968    fn test_get_data_stream_with_qcow() -> Result<(), ErrorTrace> {
1969        let vfs_file_system: VfsFileSystem = get_qcow_file_system()?;
1970
1971        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/");
1972        let vfs_file_entry: VfsFileEntry =
1973            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1974
1975        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1976        assert!(result.is_none());
1977
1978        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Qcow, "/qcow1");
1979        let vfs_file_entry: VfsFileEntry =
1980            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1981
1982        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1983        assert!(result.is_some());
1984
1985        Ok(())
1986    }
1987
1988    #[test]
1989    fn test_get_data_stream_with_sparseimage() -> Result<(), ErrorTrace> {
1990        let vfs_file_system: VfsFileSystem = get_sparseimage_file_system()?;
1991
1992        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/");
1993        let vfs_file_entry: VfsFileEntry =
1994            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
1995
1996        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
1997        assert!(result.is_none());
1998
1999        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::SparseImage, "/sparseimage1");
2000        let vfs_file_entry: VfsFileEntry =
2001            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
2002
2003        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
2004        assert!(result.is_some());
2005
2006        Ok(())
2007    }
2008
2009    #[test]
2010    fn test_get_data_stream_with_udif() -> Result<(), ErrorTrace> {
2011        let vfs_file_system: VfsFileSystem = get_udif_file_system()?;
2012
2013        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/");
2014        let vfs_file_entry: VfsFileEntry =
2015            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
2016
2017        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
2018        assert!(result.is_none());
2019
2020        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Udif, "/udif1");
2021        let vfs_file_entry: VfsFileEntry =
2022            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
2023
2024        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
2025        assert!(result.is_some());
2026
2027        Ok(())
2028    }
2029
2030    #[test]
2031    fn test_get_data_stream_with_vhd() -> Result<(), ErrorTrace> {
2032        let vfs_file_system: VfsFileSystem = get_vhd_file_system()?;
2033
2034        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/");
2035        let vfs_file_entry: VfsFileEntry =
2036            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
2037
2038        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
2039        assert!(result.is_none());
2040
2041        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhd, "/vhd2");
2042        let vfs_file_entry: VfsFileEntry =
2043            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
2044
2045        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
2046        assert!(result.is_some());
2047
2048        Ok(())
2049    }
2050
2051    #[test]
2052    fn test_get_data_stream_with_vhdx() -> Result<(), ErrorTrace> {
2053        let vfs_file_system: VfsFileSystem = get_vhdx_file_system()?;
2054
2055        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/");
2056        let vfs_file_entry: VfsFileEntry =
2057            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
2058
2059        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
2060        assert!(result.is_none());
2061
2062        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Vhdx, "/vhdx2");
2063        let vfs_file_entry: VfsFileEntry =
2064            vfs_file_system.get_file_entry_by_path(&vfs_path)?.unwrap();
2065
2066        let result: Option<DataStreamReference> = vfs_file_entry.get_data_stream()?;
2067        assert!(result.is_some());
2068
2069        Ok(())
2070    }
2071
2072    // TODO: add tests for get_number_of_sub_file_entries
2073    // TODO: add tests for get_sub_file_entry_by_index
2074    // TODO: add tests for sub_file_entries
2075}