stable_fs/
fs.rs

1use ic_stable_structures::Memory;
2
3use crate::{
4    error::Error,
5    filename_cache::FilenameCache,
6    runtime::{
7        dir::Dir,
8        fd::{FdEntry, FdTable, STDERR_FD},
9        file::File,
10        structure_helpers::{create_hard_link, find_node, rm_dir_entry},
11        types::{RIGHTS_FD_READ, RIGHTS_FD_WRITE},
12    },
13    storage::{
14        Storage,
15        types::{DirEntry, DirEntryIndex, FileType, Metadata, MountedFileSizePolicy, Node},
16    },
17};
18
19pub use crate::runtime::types::{
20    Advice, ChunkSize, ChunkType, DstBuf, DstIoVec, Fd, FdFlags, FdStat, OpenFlags, SrcBuf,
21    SrcIoVec, Whence,
22};
23pub use crate::storage::types::FileSize;
24
25/// The main class implementing the API to work with the file system.
26pub struct FileSystem {
27    pub(crate) root_fd: Fd,
28    pub(crate) fd_table: FdTable,
29    pub(crate) names_cache: FilenameCache,
30    pub storage: Box<dyn Storage>,
31}
32
33impl FileSystem {
34    // Create a new file system hosted on a given storage implementation.
35    pub fn new(storage: Box<dyn Storage>) -> Result<Self, Error> {
36        let mut fd_table = FdTable::new();
37
38        if storage.get_version() == 0 {
39            return Ok(Self {
40                root_fd: 0,
41                fd_table,
42                names_cache: FilenameCache::new(),
43                storage,
44            });
45        }
46
47        let root_node = storage.root_node();
48        let root_entry = Dir::new(root_node, FdStat::default(), &*storage)?;
49        let root_fd = fd_table.open_root(FdEntry::Dir(root_entry));
50        let names_cache = FilenameCache::new();
51
52        Ok(Self {
53            root_fd,
54            fd_table,
55            names_cache,
56            storage,
57        })
58    }
59
60    // Get version of the file system
61    pub fn get_storage_version(&self) -> u32 {
62        self.storage.get_version()
63    }
64
65    // Get the file descriptor of the root folder.
66    // This file descriptor is always open and cannot be closed or renumbered.
67    pub fn root_fd(&self) -> Fd {
68        self.root_fd
69    }
70
71    // Get the path of the root folder.
72    pub fn root_path(&self) -> &str {
73        "/"
74    }
75
76    // advice on the usage of the file system,
77    // this implementation doesn't take any special action, only checks that the Fd is valid.
78    pub fn advice(
79        &mut self,
80        fd: Fd,
81        _offset: FileSize,
82        _len: FileSize,
83        _advice: Advice,
84    ) -> Result<(), Error> {
85        let meta = self.metadata(fd)?;
86
87        // this method only works for regular files
88        if meta.file_type != FileType::RegularFile {
89            return Err(Error::BadFileDescriptor);
90        }
91
92        Ok(())
93    }
94
95    // The method tries to reserve enough memory for the file.
96    // If the file is hosting a mounted memory, the memory will actually grow and take more space,
97    // the regular file will only change its size (no additional memory is consumed by its chunks).
98    // This method might fail if the resulting file size is above the maximum allowed file size.
99    pub fn allocate(
100        &mut self,
101        fd: Fd,
102        _offset: FileSize,
103        _additional_size: FileSize,
104    ) -> Result<(), Error> {
105        let meta = self.metadata(fd)?;
106
107        if meta.file_type != FileType::RegularFile {
108            return Err(Error::BadFileDescriptor);
109        }
110
111        // TODO: do make file bigger by the given file size
112        Ok(())
113    }
114
115    // Close the opened file and release the corresponding file descriptor.
116    pub fn close(&mut self, fd: Fd) -> Result<(), Error> {
117        if fd == crate::runtime::fd::ROOT_FD {
118            // we do not close the root fd,
119            // and there is no error in trying to close it
120            return Ok(());
121        }
122
123        // flush if regular file
124        match self.fd_table.get(fd) {
125            Some(FdEntry::File(file)) => {
126                self.storage.flush(file.node);
127            }
128            Some(FdEntry::Dir(_dir)) => {
129                // directories do not need flush
130            }
131            None => Err(Error::BadFileDescriptor)?,
132        };
133
134        self.fd_table.close(fd).ok_or(Error::BadFileDescriptor)?;
135
136        Ok(())
137    }
138
139    // Flush any cached changes to the disk.
140    pub fn flush(&mut self, fd: Fd) -> Result<(), Error> {
141        let file = self.get_file(fd)?;
142
143        self.storage.flush(file.node);
144
145        Ok(())
146    }
147
148    // Reassign a file descriptor to a new number, the source descriptor is closed in the process.
149    // If the destination descriptor is busy, it is closed in the process.
150    pub fn renumber(&mut self, from: Fd, to: Fd) -> Result<(), Error> {
151        self.fd_table.renumber(from, to)
152    }
153
154    pub(crate) fn get_node(&self, fd: Fd) -> Result<Node, Error> {
155        match self.fd_table.get(fd) {
156            Some(FdEntry::File(file)) => Ok(file.node),
157            Some(FdEntry::Dir(dir)) => Ok(dir.node),
158            None => Err(Error::BadFileDescriptor),
159        }
160    }
161
162    pub(crate) fn get_file(&self, fd: Fd) -> Result<File, Error> {
163        match self.fd_table.get(fd) {
164            Some(FdEntry::Dir(_)) => Err(Error::BadFileDescriptor),
165            Some(FdEntry::File(file)) => Ok(file.clone()),
166            None => Err(Error::BadFileDescriptor),
167        }
168    }
169
170    pub(crate) fn put_file(&mut self, fd: Fd, file: File) {
171        self.fd_table.update(fd, FdEntry::File(file))
172    }
173
174    pub(crate) fn get_dir(&self, fd: Fd) -> Result<Dir, Error> {
175        match self.fd_table.get(fd) {
176            Some(FdEntry::Dir(dir)) => Ok(dir.clone()),
177            Some(FdEntry::File(_)) => Err(Error::NotADirectoryOrSymbolicLink),
178            None => Err(Error::BadFileDescriptor),
179        }
180    }
181
182    // mount memory on the top of the given host file name, if the file does not exist, it will be created.
183    // The method fails if the file system could not open or create the file.
184    pub fn mount_memory_file(
185        &mut self,
186        filename: &str,
187        memory: Box<dyn Memory>,
188        policy: MountedFileSizePolicy,
189    ) -> Result<(), Error> {
190        let filename = filename.strip_prefix('/').unwrap_or(filename);
191
192        // create a file for the mount
193        let fd = self.open(
194            self.root_fd,
195            filename,
196            FdStat::default(),
197            OpenFlags::CREATE,
198            0,
199        )?;
200
201        let result = (|| {
202            let file = self.get_file(fd)?;
203            self.storage.mount_node(file.node, memory, policy)
204        })();
205
206        let _ = self.close(fd);
207
208        result
209    }
210
211    // initialize mounted memory with the data stored in the host file
212    pub fn init_memory_file(&mut self, filename: &str) -> Result<(), Error> {
213        let filename = filename.strip_prefix('/').unwrap_or(filename);
214
215        // create a file for the mount
216        let fd = self.open(
217            self.root_fd,
218            filename,
219            FdStat::default(),
220            OpenFlags::empty(),
221            0,
222        )?;
223
224        let result = (|| {
225            let file = self.get_file(fd)?;
226            self.storage.init_mounted_memory(file.node)
227        })();
228
229        let _ = self.close(fd);
230
231        result
232    }
233
234    // store content of the currently active memory file to the file system
235    pub fn store_memory_file(&mut self, filename: &str) -> Result<(), Error> {
236        let filename = filename.strip_prefix('/').unwrap_or(filename);
237
238        // create a file for the mount
239        let fd = self.open(
240            self.root_fd,
241            filename,
242            FdStat::default(),
243            OpenFlags::empty(),
244            0,
245        )?;
246
247        let result = (|| {
248            let file = self.get_file(fd)?;
249            self.storage.store_mounted_memory(file.node)
250        })();
251
252        let _ = self.close(fd);
253
254        result
255    }
256
257    // Unmount memory, the system will continue to work with the file in normal mode.
258    pub fn unmount_memory_file(&mut self, filename: &str) -> Result<Box<dyn Memory>, Error> {
259        let filename = filename.strip_prefix('/').unwrap_or(filename);
260
261        // create a file for the mount
262        let fd = self.open(
263            self.root_fd,
264            filename,
265            FdStat::default(),
266            OpenFlags::empty(),
267            0,
268        )?;
269
270        let result = (|| {
271            let file = self.get_file(fd)?;
272
273            let memory = self.storage.unmount_node(file.node)?;
274
275            Ok(memory)
276        })();
277
278        let _ = self.close(fd);
279
280        result
281    }
282
283    // Get directory entry for a given directory file descriptor and the entry index.
284    pub fn get_direntry(&self, fd: Fd, index: DirEntryIndex) -> Result<DirEntry, Error> {
285        self.get_dir(fd)?.get_entry(index, self.storage.as_ref())
286    }
287
288    // Iterate all directory entries for a given directory file descriptor.
289    // if the initial_index is None, the entries "." and ".." are also added in the beginning of the list
290    // To get dir entries without "." and ".." pass initial_index as Some(0)
291    pub fn with_direntries(
292        &self,
293        fd: Fd,
294        initial_index: Option<DirEntryIndex>,
295        f: &mut dyn FnMut(&DirEntryIndex, &DirEntry) -> bool,
296    ) -> Result<(), Error> {
297        let dir = self.get_dir(fd)?;
298
299        self.storage.with_direntries(dir.node, initial_index, f);
300
301        Ok(())
302    }
303
304    fn put_dir(&mut self, fd: Fd, dir: Dir) {
305        self.fd_table.update(fd, FdEntry::Dir(dir))
306    }
307
308    // Read file's `fd` contents into `dst`.
309    pub fn read(&mut self, fd: Fd, dst: &mut [u8]) -> Result<FileSize, Error> {
310        let mut file = self.get_file(fd)?;
311
312        if file.stat.rights_base & RIGHTS_FD_READ == 0 {
313            return Err(Error::OperationNotPermitted);
314        }
315
316        let read_size = file.read_with_cursor(dst, self.storage.as_mut())?;
317        self.put_file(fd, file);
318        Ok(read_size)
319    }
320
321    // Read file into a vector of buffers.
322    pub fn read_vec(&mut self, fd: Fd, dst: DstIoVec) -> Result<FileSize, Error> {
323        let mut file = self.get_file(fd)?;
324
325        if file.stat.rights_base & RIGHTS_FD_READ == 0 {
326            return Err(Error::OperationNotPermitted);
327        }
328
329        let mut read_size = 0;
330        for buf in dst {
331            let buf = unsafe { std::slice::from_raw_parts_mut(buf.buf, buf.len) };
332            let size = file.read_with_cursor(buf, self.storage.as_mut())?;
333            read_size += size;
334        }
335        self.put_file(fd, file);
336        Ok(read_size)
337    }
338
339    // Read file into a vector of buffers at a given offset, the file cursor is NOT updated.
340    pub fn read_vec_with_offset(
341        &mut self,
342        fd: Fd,
343        dst: DstIoVec,
344        offset: FileSize,
345    ) -> Result<FileSize, Error> {
346        let file = self.get_file(fd)?;
347
348        if file.stat.rights_base & RIGHTS_FD_READ == 0 {
349            return Err(Error::OperationNotPermitted);
350        }
351
352        let mut read_size = 0;
353
354        for buf in dst {
355            let rbuf = unsafe { std::slice::from_raw_parts_mut(buf.buf, buf.len) };
356
357            let size = file.read_with_offset(read_size + offset, rbuf, self.storage.as_mut())?;
358
359            read_size += size;
360        }
361        self.put_file(fd, file);
362        Ok(read_size)
363    }
364
365    // Write `src` contents into a file.
366    pub fn write(&mut self, fd: Fd, src: &[u8]) -> Result<FileSize, Error> {
367        let buf = SrcBuf {
368            buf: src.as_ptr(),
369            len: src.len(),
370        };
371
372        self.write_vec(fd, &[buf])
373    }
374
375    // Write a vector of buffers into a file at a given offset, the file cursor is updated.
376    pub fn write_vec(&mut self, fd: Fd, src: SrcIoVec) -> Result<FileSize, Error> {
377        let mut file = self.get_file(fd)?;
378
379        if file.stat.rights_base & RIGHTS_FD_WRITE == 0 {
380            return Err(Error::OperationNotPermitted);
381        }
382
383        let is_append = file.stat.flags.contains(FdFlags::APPEND);
384
385        // in the append mode, we always write to the end of file
386        let offset = if is_append {
387            let meta = self.metadata_from_node(file.node)?;
388            meta.size
389        } else {
390            file.cursor
391        };
392
393        let mut written_size = 0;
394        for buf in src {
395            let buf = unsafe { std::slice::from_raw_parts(buf.buf, buf.len) };
396
397            let size = file.write_with_offset(written_size + offset, buf, self.storage.as_mut())?;
398            written_size += size;
399        }
400
401        // always update cursor position after write
402        file.cursor = written_size + offset;
403
404        self.put_file(fd, file);
405        Ok(written_size)
406    }
407
408    // Write a vector of buffers into a file at a given offset, the file cursor is NOT updated.
409    pub fn write_vec_with_offset(
410        &mut self,
411        fd: Fd,
412        src: SrcIoVec,
413        offset: FileSize,
414    ) -> Result<FileSize, Error> {
415        let file = self.get_file(fd)?;
416
417        if file.stat.rights_base & RIGHTS_FD_WRITE == 0 {
418            return Err(Error::OperationNotPermitted);
419        }
420
421        let is_append = file.stat.flags.contains(FdFlags::APPEND);
422
423        // in the append mode, we always write to the end of file
424        let offset = if is_append {
425            let meta = self.metadata_from_node(file.node)?;
426            meta.size
427        } else {
428            offset
429        };
430
431        let mut written_size = 0;
432        for buf in src {
433            let buf = unsafe { std::slice::from_raw_parts(buf.buf, buf.len) };
434
435            let size = file.write_with_offset(written_size + offset, buf, self.storage.as_mut())?;
436
437            written_size += size;
438        }
439
440        self.put_file(fd, file);
441        Ok(written_size)
442    }
443
444    // Position file cursor to a given position.
445    pub fn seek(&mut self, fd: Fd, delta: i64, whence: Whence) -> Result<FileSize, Error> {
446        let mut file = self.get_file(fd)?;
447
448        let pos = file.seek(delta, whence, self.storage.as_mut())?;
449        self.put_file(fd, file);
450        Ok(pos)
451    }
452
453    // Get the current file cursor position.
454    pub fn tell(&mut self, fd: Fd) -> Result<FileSize, Error> {
455        let file = self.get_file(fd)?;
456
457        let pos = file.tell();
458        Ok(pos)
459    }
460
461    // Get the metadata for a given node
462    pub fn metadata_from_node(&self, node: Node) -> Result<Metadata, Error> {
463        self.storage.get_metadata(node)
464    }
465
466    // Get the metadata for a given file descriptor
467    pub fn metadata(&self, fd: Fd) -> Result<Metadata, Error> {
468        // return fake metadata for the std channels, it is read-only
469        if fd <= STDERR_FD {
470            return Ok(Metadata {
471                node: u64::MAX, // return fake, unusable node here
472                file_type: FileType::RegularFile,
473                link_count: 0,
474                size: 0,
475                times: crate::storage::types::Times::default(),
476                chunk_type: None,
477                maximum_size_allowed: None,
478                first_dir_entry: None,
479                last_dir_entry: None,
480            });
481        }
482
483        let node = self.get_node(fd)?;
484        self.storage.get_metadata(node)
485    }
486
487    // Update metadata of a given file descriptor
488    pub fn set_metadata(&mut self, fd: Fd, metadata: Metadata) -> Result<(), Error> {
489        let node = self.get_node(fd)?;
490        self.storage.put_metadata(node, &metadata)?;
491
492        Ok(())
493    }
494
495    pub fn set_file_size(&mut self, fd: Fd, new_size: FileSize) -> Result<(), Error> {
496        let file = self.get_file(fd)?;
497
498        if file.stat.rights_base & RIGHTS_FD_WRITE == 0 {
499            // in this case setting size without write permission
500            // is the invalid argument error
501            return Err(Error::InvalidArgument);
502        }
503
504        let mut metadata = self.storage.get_metadata(file.node)?;
505
506        metadata.size = new_size;
507
508        self.storage.put_metadata(file.node, &metadata)?;
509
510        Ok(())
511    }
512
513    // Set maxmum file size limit in bytes. Reading, writing, and setting the cursor above the limit will result in error.
514    // Use this feature to limit how much memory can be consumed by the mounted memory files.
515    pub fn set_file_size_limit(&mut self, fd: Fd, max_size: FileSize) -> Result<(), Error> {
516        let file = self.get_file(fd)?;
517
518        let mut metadata = self.storage.get_metadata(file.node)?;
519
520        metadata.maximum_size_allowed = Some(max_size);
521
522        self.storage.put_metadata(file.node, &metadata)?;
523
524        Ok(())
525    }
526
527    // Update access time.
528    pub fn set_accessed_time(&mut self, fd: Fd, time: u64) -> Result<(), Error> {
529        let node = self.get_node(fd)?;
530        let mut metadata = self.storage.get_metadata(node)?;
531
532        metadata.times.accessed = time;
533
534        self.storage.put_metadata(node, &metadata)?;
535
536        Ok(())
537    }
538
539    // Update modification time.
540    pub fn set_modified_time(&mut self, fd: Fd, time: u64) -> Result<(), Error> {
541        let node = self.get_node(fd)?;
542        let mut metadata = self.storage.get_metadata(node)?;
543
544        metadata.times.modified = time;
545
546        self.storage.put_metadata(node, &metadata)?;
547
548        Ok(())
549    }
550
551    // Get file or directory stats.
552    pub fn get_stat(&self, fd: Fd) -> Result<(FileType, FdStat), Error> {
553        match self.fd_table.get(fd) {
554            None => Err(Error::BadFileDescriptor),
555            Some(FdEntry::File(file)) => Ok((FileType::RegularFile, file.stat)),
556            Some(FdEntry::Dir(dir)) => Ok((FileType::Directory, dir.stat)),
557        }
558    }
559
560    // Update stats of a given file.
561    pub fn set_stat(&mut self, fd: Fd, stat: FdStat) -> Result<(), Error> {
562        match self.fd_table.get(fd) {
563            Some(FdEntry::File(file)) => {
564                let mut file = file.clone();
565                file.stat = stat;
566                self.put_file(fd, file);
567                Ok(())
568            }
569            Some(FdEntry::Dir(dir)) => {
570                // file-only stats cause badfd error
571                if stat.flags.contains(FdFlags::APPEND) || stat.flags.contains(FdFlags::NONBLOCK) {
572                    return Err(Error::BadFileDescriptor);
573                }
574
575                let mut dir = dir.clone();
576                dir.stat = stat;
577                self.put_dir(fd, dir);
578                Ok(())
579            }
580            None => Err(Error::BadFileDescriptor),
581        }
582    }
583
584    // Get metadata of a file with name `path` in a given folder.
585    pub fn open_metadata(&mut self, parent: Fd, path: &str) -> Result<Metadata, Error> {
586        let dir = self.get_dir(parent)?;
587        let node = find_node(dir.node, path, &mut self.names_cache, self.storage.as_ref())?;
588        self.storage.get_metadata(node)
589    }
590
591    // Opens a directory or file or creates a new file (depending on the flags provided).
592    pub fn open(
593        &mut self,
594        parent_fd: Fd,
595        path: &str,
596        stat: FdStat,
597        flags: OpenFlags,
598        ctime: u64,
599    ) -> Result<Fd, Error> {
600        let dir = self.get_dir(parent_fd)?;
601
602        let res = find_node(dir.node, path, &mut self.names_cache, self.storage.as_ref());
603
604        match res {
605            Ok(node) => {
606                // exclusive create is an error, if the file exists already
607                if flags.contains(OpenFlags::CREATE) && flags.contains(OpenFlags::EXCLUSIVE) {
608                    return Err(Error::FileExists);
609                }
610
611                self.open_internal(node, stat, flags)
612            }
613
614            Err(Error::NoSuchFileOrDirectory) => {
615                if !flags.contains(OpenFlags::CREATE) {
616                    return Err(Error::NoSuchFileOrDirectory);
617                }
618
619                if flags.contains(OpenFlags::DIRECTORY) {
620                    self.create_open_directory(parent_fd, path, stat, ctime)
621                } else {
622                    self.create_open_file(parent_fd, path, stat, ctime)
623                }
624            }
625            Err(err) => Err(err),
626        }
627    }
628
629    // Opens an existing file or directory by node and return its new file descriptor.
630    fn open_internal(&mut self, node: Node, stat: FdStat, flags: OpenFlags) -> Result<Fd, Error> {
631        let metadata = self.storage.get_metadata(node)?;
632
633        match metadata.file_type {
634            FileType::Directory => {
635                let dir = Dir::new(node, stat, self.storage.as_mut())?;
636                let fd = self.fd_table.open(FdEntry::Dir(dir));
637                Ok(fd)
638            }
639            FileType::RegularFile => {
640                if flags.contains(OpenFlags::DIRECTORY) {
641                    return Err(Error::OperationNotPermitted);
642                }
643
644                let file = File::new(node, stat, self.storage.as_mut())?;
645
646                if flags.contains(OpenFlags::TRUNCATE) {
647                    file.truncate(self.storage.as_mut())?;
648                }
649
650                let fd = self.fd_table.open(FdEntry::File(file));
651                Ok(fd)
652            }
653            FileType::SymbolicLink => unimplemented!("Symbolic links are not supported"),
654        }
655    }
656
657    // Create a new file and open it. Function fails if the file exists already.
658    pub(crate) fn create_open_file(
659        &mut self,
660        parent: Fd,
661        path: &str,
662        stat: FdStat,
663        ctime: u64,
664    ) -> Result<Fd, Error> {
665        let dir = self.get_dir(parent)?;
666
667        let child = dir.create_file(
668            path,
669            stat,
670            &mut self.names_cache,
671            self.storage.as_mut(),
672            ctime,
673        )?;
674
675        let child_fd = self.fd_table.open(FdEntry::File(child));
676        self.put_dir(parent, dir);
677
678        Ok(child_fd)
679    }
680
681    // Delete a file by name `path` in the given file folder.
682    pub fn remove_file(&mut self, parent: Fd, path: &str) -> Result<(), Error> {
683        let dir = self.get_dir(parent)?;
684        dir.remove_file(
685            path,
686            self.fd_table.node_refcount(),
687            &mut self.names_cache,
688            self.storage.as_mut(),
689        )?;
690
691        self.put_dir(parent, dir);
692
693        Ok(())
694    }
695
696    // Convenience method, create a new directory without opening it
697    pub fn mkdir(&mut self, parent: Fd, path: &str, stat: FdStat, ctime: u64) -> Result<(), Error> {
698        let dir = self.get_dir(parent)?;
699
700        dir.create_dir(
701            path,
702            stat,
703            &mut self.names_cache,
704            self.storage.as_mut(),
705            ctime,
706        )?;
707
708        self.put_dir(parent, dir);
709
710        Ok(())
711    }
712
713    // create a directory and return an opened file descriptor of it
714    pub fn create_open_directory(
715        &mut self,
716        parent: Fd,
717        path: &str,
718        stat: FdStat,
719        ctime: u64,
720    ) -> Result<Fd, Error> {
721        let dir = self.get_dir(parent)?;
722
723        let child = dir.create_dir(
724            path,
725            stat,
726            &mut self.names_cache,
727            self.storage.as_mut(),
728            ctime,
729        )?;
730
731        let child_fd = self.fd_table.open(FdEntry::Dir(child));
732        self.put_dir(parent, dir);
733
734        Ok(child_fd)
735    }
736
737    // Delete a directory by name `path` in the given file folder.
738    pub fn remove_dir(&mut self, parent: Fd, path: &str) -> Result<(), Error> {
739        let dir = self.get_dir(parent)?;
740        dir.remove_dir(
741            path,
742            self.fd_table.node_refcount(),
743            &mut self.names_cache,
744            self.storage.as_mut(),
745        )?;
746
747        self.put_dir(parent, dir);
748
749        Ok(())
750    }
751
752    pub(crate) fn list_dir_internal(
753        &mut self,
754        dir_fd: Fd,
755        file_type: Option<FileType>,
756    ) -> Result<Vec<(Node, String)>, Error> {
757        let mut res = vec![];
758
759        self.with_direntries(dir_fd, Some(0), &mut |_index, entry| -> bool {
760            // here we assume the entry value name is correct UTF-8
761            let filename = unsafe {
762                std::str::from_utf8_unchecked(&entry.name.bytes[..(entry.name.length as usize)])
763            }
764            .to_string();
765
766            if let Some(file_type) = file_type {
767                let meta = self
768                    .metadata_from_node(entry.node)
769                    .expect("Metadata not found!");
770
771                if meta.file_type == file_type {
772                    res.push((entry.node, filename));
773                }
774            } else {
775                res.push((entry.node, filename));
776            }
777
778            true
779        })?;
780
781        Ok(res)
782    }
783
784    /// A convenience method to recursively remove a directory (and all subdirectories/files within) or delete a file, if the entry is a file.
785    pub fn remove_recursive(&mut self, parent: Fd, path: &str) -> Result<(), Error> {
786        let meta = self.open_metadata(parent, path)?;
787
788        if meta.file_type == FileType::RegularFile {
789            return self.remove_file(parent, path);
790        }
791
792        // Open the target directory. We use `OpenFlags::DIRECTORY` to ensure
793        //    the path is interpreted as a directory (or fail if it doesn't exist).
794        let dir_fd = self.open(parent, path, FdStat::default(), OpenFlags::DIRECTORY, 0)?;
795
796        let result = (|| {
797            // Find all directory children
798            let children = self.list_dir_internal(dir_fd, None)?;
799
800            // For each child, figure out if it's a subdirectory or file and remove accordingly.
801            for (child_node, child_name) in children {
802                let child_meta = self.storage.get_metadata(child_node)?;
803
804                match child_meta.file_type {
805                    FileType::Directory => {
806                        // Recurse into the subdirectory.
807                        self.remove_recursive(dir_fd, &child_name)?;
808                    }
809                    FileType::RegularFile => {
810                        // Remove the file.
811                        self.remove_file(dir_fd, &child_name)?;
812                    }
813                    FileType::SymbolicLink => {
814                        unimplemented!("Symbolic links are not supported yet");
815                    }
816                }
817            }
818
819            Ok(())
820        })();
821
822        // close the folder itself before its deletion
823        self.close(dir_fd)?;
824
825        // Now that it is empty, remove the directory entry from its parent.
826        self.remove_dir(parent, path)?;
827
828        result
829    }
830
831    // Create a hard link to an existing file.
832    pub fn create_hard_link(
833        &mut self,
834        old_fd: Fd,
835        old_path: &str,
836        new_fd: Fd,
837        new_path: &str,
838    ) -> Result<Fd, Error> {
839        let src_dir = self.get_dir(old_fd)?;
840        let dst_dir = self.get_dir(new_fd)?;
841
842        create_hard_link(
843            dst_dir.node,
844            new_path,
845            src_dir.node,
846            old_path,
847            false,
848            self.fd_table.node_refcount(),
849            &mut self.names_cache,
850            self.storage.as_mut(),
851        )?;
852
853        let node = find_node(
854            dst_dir.node,
855            new_path,
856            &mut self.names_cache,
857            self.storage.as_ref(),
858        )?;
859
860        self.open_internal(node, FdStat::default(), OpenFlags::empty())
861    }
862
863    // Rename a file or a directory.
864    pub fn rename(
865        &mut self,
866        old_fd: Fd,
867        old_path: &str,
868        new_fd: Fd,
869        new_path: &str,
870    ) -> Result<Fd, Error> {
871        let src_dir = self.get_dir(old_fd)?;
872        let dst_dir = self.get_dir(new_fd)?;
873
874        // create a new link
875        create_hard_link(
876            dst_dir.node,
877            new_path,
878            src_dir.node,
879            old_path,
880            true,
881            self.fd_table.node_refcount(),
882            &mut self.names_cache,
883            self.storage.as_mut(),
884        )?;
885
886        // now unlink the older entry
887        let (node, _metadata) = rm_dir_entry(
888            src_dir.node,
889            old_path,
890            None,
891            true,
892            self.fd_table.node_refcount(),
893            &mut self.names_cache,
894            self.storage.as_mut(),
895        )?;
896
897        self.open_internal(node, FdStat::default(), OpenFlags::empty())
898    }
899
900    #[cfg(test)]
901    pub(crate) fn get_test_storage(&mut self) -> &mut dyn Storage {
902        self.storage.as_mut()
903    }
904
905    #[cfg(test)]
906    pub(crate) fn get_test_file(&self, fd: Fd) -> File {
907        self.get_file(fd).unwrap()
908    }
909}