virtual_file_system/file_system/
mod.rs

1mod utilities;
2
3use crate::pipe::Pipe;
4use crate::{Directory, Error, File, ItemStatic, Result, poll};
5use alloc::borrow::ToOwned;
6use alloc::vec;
7use alloc::{boxed::Box, collections::BTreeMap};
8use core::ptr;
9use exported_file_system::{
10    BaseOperations, BlockDevice, CharacterDevice, CreateFlags, Permission, Permissions,
11};
12use file_system::{
13    AccessFlags, AttributeFlags, Attributes, Context, FileSystemOperations, Flags, Kind, Path,
14    StateFlags, Statistics,
15};
16use synchronization::{
17    blocking_mutex::raw::CriticalSectionRawMutex, once_lock::OnceLock, rwlock::RwLock,
18};
19use task::TaskIdentifier;
20use users::{GroupIdentifier, UserIdentifier};
21use utilities::*;
22
23/// Instance of the virtual file system.
24static VIRTUAL_FILE_SYSTEM_INSTANCE: OnceLock<VirtualFileSystem> = OnceLock::new();
25
26pub fn initialize(
27    task_manager: &'static task::Manager,
28    users_manager: &'static users::Manager,
29    time_manager: &'static time::Manager,
30    root_file_system: impl FileSystemOperations + 'static,
31) -> Result<&'static VirtualFileSystem> {
32    let virtual_file_system =
33        VirtualFileSystem::new(task_manager, users_manager, time_manager, root_file_system);
34
35    Ok(VIRTUAL_FILE_SYSTEM_INSTANCE.get_or_init(|| virtual_file_system))
36}
37
38pub fn get_instance() -> &'static VirtualFileSystem {
39    VIRTUAL_FILE_SYSTEM_INSTANCE
40        .try_get()
41        .expect("Virtual file system is not initialized")
42}
43
44/// The virtual file system.
45///
46/// It is a singleton.
47pub struct VirtualFileSystem {
48    /// Mounted file systems.
49    file_systems: RwLock<CriticalSectionRawMutex, FileSystemsArray>,
50    /// Character devices.
51    character_device: RwLock<CriticalSectionRawMutex, CharacterDevicesMap>,
52    /// Block devices.
53    block_device: RwLock<CriticalSectionRawMutex, BlockDevicesMap>,
54    /// Pipes.
55    pipes: RwLock<CriticalSectionRawMutex, PipeMap>,
56}
57
58impl VirtualFileSystem {
59    pub fn new(
60        _: &'static task::Manager,
61        _: &'static users::Manager,
62        _: &'static time::Manager,
63        root_file_system: impl FileSystemOperations + 'static,
64    ) -> Self {
65        let file_systems = vec![InternalFileSystem {
66            reference_count: 1,
67            mount_point: Path::ROOT.to_owned(),
68            file_system: Box::leak(Box::new(root_file_system)),
69        }];
70
71        Self {
72            file_systems: RwLock::new(file_systems),
73            character_device: RwLock::new(BTreeMap::new()),
74            block_device: RwLock::new(BTreeMap::new()),
75            pipes: RwLock::new(BTreeMap::new()),
76        }
77    }
78
79    pub async fn uninitialize(&self) {
80        let mut file_systems = self.file_systems.write().await;
81
82        for internal_file_system in file_systems.drain(..) {
83            let _: Box<dyn FileSystemOperations> =
84                unsafe { Box::from_raw(internal_file_system.file_system as *const _ as *mut _) };
85        }
86    }
87
88    /// Mount a file system at a given mount point.
89    pub async fn mount_file_system(
90        &'static self,
91        file_system: impl FileSystemOperations + 'static,
92        path: impl AsRef<Path>,
93        task: TaskIdentifier,
94    ) -> Result<()> {
95        self.mount_static(
96            task,
97            path,
98            ItemStatic::FileSystem(Box::leak(Box::new(file_system))),
99        )
100        .await
101    }
102
103    pub async fn unmount(&self, path: impl AsRef<Path>, force: bool) -> Result<()> {
104        let path = path.as_ref();
105
106        if !path.is_valid() || !path.is_absolute() || path.is_root() {
107            return Err(Error::InvalidPath);
108        }
109
110        let file_systems = self.file_systems.write().await;
111
112        let parent_path = path.go_parent().ok_or(Error::InvalidPath)?;
113
114        let (underlying_file_system, relative_path, _) =
115            Self::get_file_system_from_path(&file_systems, &parent_path)?; // Get the file system identifier and the relative path
116
117        let mut attributes =
118            Attributes::new().set_mask(AttributeFlags::Kind | AttributeFlags::Inode);
119        Self::get_attributes(underlying_file_system.file_system, path, &mut attributes).await?;
120
121        let kind = attributes.get_kind().ok_or(Error::MissingAttribute)?;
122        let inode = *attributes.get_inode().ok_or(Error::MissingAttribute)?;
123
124        match kind {
125            Kind::Directory => {
126                let (file_system, _, _) = Self::get_file_system_from_path(&file_systems, &path)?;
127
128                if file_system.reference_count > 1 && !force {
129                    return Err(Error::RessourceBusy);
130                }
131
132                underlying_file_system.file_system.remove(relative_path)?;
133                file_system.file_system.unmount()?;
134            }
135            Kind::BlockDevice => {
136                let mut block_devices = self.block_device.write().await;
137                let device = block_devices.get_mut(&inode).ok_or(Error::InvalidInode)?;
138
139                if device.reference_count > 1 && !force {
140                    return Err(Error::RessourceBusy);
141                }
142
143                underlying_file_system.file_system.remove(relative_path)?;
144                device.device.unmount()?;
145            }
146            Kind::CharacterDevice => {
147                let mut character_devices = self.character_device.write().await;
148                let device = character_devices
149                    .get_mut(&inode)
150                    .ok_or(Error::InvalidInode)?;
151
152                if device.reference_count > 1 && !force {
153                    return Err(Error::RessourceBusy);
154                }
155
156                underlying_file_system.file_system.remove(relative_path)?;
157                device.device.unmount()?;
158            }
159            _ => {
160                return Err(Error::UnsupportedOperation);
161            }
162        }
163
164        Ok(())
165    }
166
167    pub async fn unmount_all(&self) -> Result<()> {
168        let mut file_systems = self.file_systems.write().await;
169        let mut block_devices = self.block_device.write().await;
170        let mut character_devices = self.character_device.write().await;
171
172        for file_system in file_systems.drain(..) {
173            file_system.file_system.unmount()?;
174            let _: Box<dyn FileSystemOperations> =
175                unsafe { Box::from_raw(file_system.file_system as *const _ as *mut _) };
176        }
177
178        for (_, block_device) in block_devices.iter_mut() {
179            block_device.device.unmount()?;
180            let _: Box<dyn BlockDevice> =
181                unsafe { Box::from_raw(block_device.device as *const _ as *mut _) };
182        }
183        block_devices.clear();
184
185        for (_, character_device) in character_devices.iter_mut() {
186            character_device.device.unmount()?;
187            let _: Box<dyn CharacterDevice> =
188                unsafe { Box::from_raw(character_device.device as *const _ as *mut _) };
189        }
190        character_devices.clear();
191
192        Ok(())
193    }
194
195    pub async fn open_directory(
196        &self,
197        task: TaskIdentifier,
198        path: &impl AsRef<Path>,
199    ) -> Result<Directory> {
200        let path = path.as_ref();
201
202        let mut file_systems = self.file_systems.write().await; // Get the file systems
203
204        let (time, user, _) = self.get_time_user_group(task).await?;
205
206        Self::check_permissions_with_parent(
207            &file_systems,
208            path,
209            Permission::Read,
210            Permission::Execute,
211            user,
212        )
213        .await?;
214
215        let (file_system, relative_path, _) =
216            Self::get_mutable_file_system_from_path(&mut file_systems, &path)?; // Get the file system identifier and the relative path
217
218        let mut attributes = Attributes::new().set_mask(
219            AttributeFlags::Kind
220                | AttributeFlags::User
221                | AttributeFlags::Group
222                | AttributeFlags::Permissions,
223        );
224        Self::get_attributes(file_system.file_system, relative_path, &mut attributes).await?;
225        let kind = attributes.get_kind().ok_or(Error::MissingAttribute)?;
226
227        if *kind != Kind::Directory {
228            return Err(Error::NotADirectory);
229        }
230
231        let attributes = Attributes::new().set_access(time);
232        Self::set_attributes(file_system.file_system, relative_path, &attributes).await?;
233
234        let mut context = Context::new_empty();
235
236        poll(|| {
237            Ok(file_system
238                .file_system
239                .lookup_directory(&mut context, relative_path)?)
240        })
241        .await?;
242
243        file_system.reference_count += 1;
244
245        Ok(Directory::new(
246            file_system.file_system,
247            Flags::new(AccessFlags::Read, None, None),
248            context,
249        ))
250    }
251
252    pub async fn open(
253        &self,
254        path: &impl AsRef<Path>,
255        flags: Flags,
256        task: TaskIdentifier,
257    ) -> Result<File> {
258        let path = path.as_ref();
259
260        let mut file_systems = self.file_systems.write().await; // Get the file systems
261
262        let (time, user, group) = self.get_time_user_group(task).await?;
263        let (mode, open, _) = flags.split();
264
265        if open.contains(CreateFlags::Create) {
266            let (file_system, relative_path, _) =
267                Self::get_mutable_file_system_from_path(&mut file_systems, &path)?; // Get the file system identifier and the relative path
268
269            let result = poll(|| Ok(file_system.file_system.create_file(relative_path)?)).await;
270
271            match result {
272                Ok(()) => {
273                    Self::check_permissions(
274                        file_system.file_system,
275                        path.go_parent().ok_or_else(|| {
276                            log::error!("Error getting parent path for {:?}", path);
277                            Error::InvalidPath
278                        })?,
279                        Permission::Write | Permission::Execute,
280                        user,
281                    )
282                    .await?;
283
284                    let attributes = Attributes::new()
285                        .set_user(user)
286                        .set_group(group)
287                        .set_creation(time)
288                        .set_modification(time)
289                        .set_status(time)
290                        .set_access(time)
291                        .set_permissions(Permissions::FILE_DEFAULT)
292                        .set_kind(Kind::File);
293                    Self::set_attributes(file_system.file_system, relative_path, &attributes)
294                        .await?;
295                }
296                Err(Error::FileSystem(file_system::Error::AlreadyExists)) => {
297                    if open.contains(CreateFlags::Exclusive) {
298                        return Err(Error::AlreadyExists);
299                    }
300                }
301                Err(e) => {
302                    return Err(e);
303                }
304            }
305        } else {
306            Self::check_permissions_with_parent(
307                &file_systems,
308                path,
309                mode.into_permission(),
310                Permission::Execute,
311                user,
312            )
313            .await?;
314        }
315
316        let (file_system, relative_path, _) =
317            Self::get_mutable_file_system_from_path(&mut file_systems, &path)?; // Get the file system identifier and the relative path
318
319        let attributes = if mode.contains(AccessFlags::Write) {
320            Attributes::new().set_modification(time).set_access(time)
321        } else {
322            Attributes::new().set_access(time)
323        };
324        Self::set_attributes(file_system.file_system, relative_path, &attributes).await?;
325
326        let mut attributes =
327            Attributes::new().set_mask(AttributeFlags::Inode | AttributeFlags::Kind);
328        Self::get_attributes(file_system.file_system, path, &mut attributes).await?;
329
330        let kind = attributes.get_kind().ok_or(Error::MissingAttribute)?;
331        let inode = *attributes.get_inode().ok_or(Error::MissingAttribute)?;
332
333        let mut context = Context::new_empty();
334
335        let file = match kind {
336            Kind::CharacterDevice => {
337                let mut devices = self.character_device.write().await;
338
339                let device = devices.get_mut(&inode).ok_or(Error::InvalidInode)?;
340
341                poll(|| Ok(device.device.open(&mut context)?)).await?;
342                device.reference_count += 1;
343
344                File::new(ItemStatic::CharacterDevice(device.device), flags, context)
345            }
346            Kind::BlockDevice => {
347                let mut devices = self.block_device.write().await;
348
349                let device = devices.get_mut(&inode).ok_or(Error::InvalidInode)?;
350
351                poll(|| Ok(device.device.open(&mut context)?)).await?;
352                device.reference_count += 1;
353
354                File::new(ItemStatic::BlockDevice(device.device), flags, context)
355            }
356            Kind::Pipe => {
357                let mut pipes = self.pipes.write().await;
358                let pipe = pipes.get_mut(&inode).ok_or(Error::InvalidInode)?;
359
360                poll(|| Ok(pipe.pipe.open(&mut context)?)).await?;
361                pipe.reference_count += 1;
362
363                File::new(ItemStatic::Pipe(pipe.pipe), flags, context)
364            }
365            Kind::File => {
366                poll(|| {
367                    Ok(file_system.file_system.lookup_file(
368                        &mut context,
369                        relative_path,
370                        Flags::new(flags.get_access(), None, None),
371                    )?)
372                })
373                .await?;
374
375                file_system.reference_count += 1;
376
377                File::new(ItemStatic::File(file_system.file_system), flags, context)
378            }
379            _ => Err(Error::UnsupportedOperation)?,
380        };
381
382        Ok(file)
383    }
384
385    pub async fn mount_static(
386        &self,
387        task: TaskIdentifier,
388        path: impl AsRef<Path>,
389        item: ItemStatic,
390    ) -> Result<()> {
391        let path: &Path = path.as_ref();
392        if !path.is_valid() || !path.is_absolute() || path.is_root() {
393            return Err(Error::InvalidPath);
394        }
395
396        let mut file_systems = self.file_systems.write().await; // Get the file systems
397
398        let (parent_file_system, relative_path, _) =
399            Self::get_mutable_file_system_from_path(&mut file_systems, &path)?; // Get the file system identifier and the relative path
400
401        let (_, user, _) = self.get_time_user_group(task).await?;
402
403        let parent_path = path.go_parent().ok_or(Error::InvalidPath)?;
404
405        Self::check_permissions(
406            parent_file_system.file_system,
407            parent_path,
408            Permission::Write,
409            user,
410        )
411        .await?;
412
413        if let ItemStatic::FileSystem(_) = item {
414            parent_file_system
415                .file_system
416                .create_directory(relative_path)?;
417        } else {
418            parent_file_system.file_system.create_file(relative_path)?;
419        }
420
421        let inode = match item {
422            ItemStatic::BlockDevice(device) => {
423                let mut block_devices = self.block_device.write().await;
424                let inode = Self::get_new_inode(&*block_devices).ok_or(Error::TooManyInodes)?;
425                block_devices.insert(
426                    inode,
427                    InternalBlockDevice {
428                        reference_count: 1,
429                        device,
430                    },
431                );
432                inode
433            }
434            ItemStatic::CharacterDevice(device) => {
435                let mut character_devices = self.character_device.write().await;
436                let inode = Self::get_new_inode(&*character_devices).ok_or(Error::TooManyInodes)?;
437                character_devices.insert(
438                    inode,
439                    InternalCharacterDevice {
440                        reference_count: 1,
441                        device,
442                    },
443                );
444                inode
445            }
446            ItemStatic::FileSystem(_) => 0,
447            ItemStatic::Pipe(pipe) => {
448                let mut pipes = self.pipes.write().await;
449                let inode = Self::get_new_inode(&*pipes).ok_or(Error::TooManyInodes)?;
450                pipes.insert(
451                    inode,
452                    InternalPipe {
453                        reference_count: 1,
454                        pipe,
455                    },
456                );
457                inode
458            }
459            _ => {
460                return Err(Error::InvalidIdentifier);
461            }
462        };
463
464        let (time, user, group) = self.get_time_user_group(task).await?;
465        let underlying_kind = match &item {
466            ItemStatic::FileSystem(_) => Kind::Directory,
467            ItemStatic::BlockDevice(_) => Kind::BlockDevice,
468            ItemStatic::CharacterDevice(_) => Kind::CharacterDevice,
469            ItemStatic::Pipe(_) => Kind::Pipe,
470            _ => {
471                return Err(Error::InvalidIdentifier);
472            }
473        };
474
475        let attributes = Attributes::new()
476            .set_user(user)
477            .set_group(group)
478            .set_creation(time)
479            .set_modification(time)
480            .set_access(time)
481            .set_status(time)
482            .set_kind(underlying_kind)
483            .set_permissions(Permissions::DEVICE_DEFAULT)
484            .set_inode(inode);
485        Self::set_attributes(parent_file_system.file_system, relative_path, &attributes).await?;
486
487        if let ItemStatic::FileSystem(file_system) = item {
488            file_systems.push(InternalFileSystem {
489                reference_count: 1,
490                mount_point: path.to_owned(),
491                file_system,
492            });
493        }
494
495        poll(|| {
496            Ok(item
497                .as_mount_operations()
498                .ok_or(Error::UnsupportedOperation)?
499                .mount()?)
500        })
501        .await?;
502
503        Ok(())
504    }
505
506    pub async fn mount_block_device(
507        &self,
508        task: TaskIdentifier,
509        path: impl AsRef<Path>,
510        device: impl BlockDevice + 'static,
511    ) -> Result<()> {
512        self.mount_static(
513            task,
514            path,
515            ItemStatic::BlockDevice(Box::leak(Box::new(device))),
516        )
517        .await
518    }
519
520    pub async fn mount_character_device(
521        &self,
522        task: TaskIdentifier,
523        path: impl AsRef<Path>,
524        device: impl CharacterDevice + 'static,
525    ) -> Result<()> {
526        self.mount_static(
527            task,
528            path,
529            ItemStatic::CharacterDevice(Box::leak(Box::new(device))),
530        )
531        .await
532    }
533
534    pub async fn create_named_pipe(
535        &self,
536        path: &impl AsRef<Path>,
537        size: usize,
538        task: TaskIdentifier,
539    ) -> Result<()> {
540        self.mount_static(
541            task,
542            path,
543            ItemStatic::Pipe(Box::leak(Box::new(Pipe::new(size)))),
544        )
545        .await
546    }
547
548    pub async fn create_unnamed_pipe(
549        &self,
550        size: usize,
551        status: StateFlags,
552    ) -> Result<(File, File)> {
553        let mut pipes = self.pipes.write().await;
554
555        let inode = Self::get_new_inode(&*pipes).ok_or(Error::TooManyInodes)?;
556
557        let pipe = Box::leak(Box::new(Pipe::new(size)));
558
559        pipes.insert(
560            inode,
561            InternalPipe {
562                reference_count: 3,
563                pipe,
564            },
565        );
566
567        let writer = File::new(
568            ItemStatic::Pipe(pipe),
569            Flags::new(AccessFlags::Write, None, Some(status)),
570            Context::new_empty(),
571        );
572
573        let reader = File::new(
574            ItemStatic::Pipe(pipe),
575            Flags::new(AccessFlags::Read, None, Some(status)),
576            Context::new_empty(),
577        );
578
579        Ok((reader, writer))
580    }
581
582    pub async fn remove(&self, task: TaskIdentifier, path: impl AsRef<Path>) -> Result<()> {
583        let file_systems = self.file_systems.read().await; // Get the file systems
584
585        let (file_system, relative_path, _) =
586            Self::get_file_system_from_path(&file_systems, &path)?; // Get the file system identifier and the relative path
587
588        let (_, user, _) = self.get_time_user_group(task).await?;
589
590        Self::check_permissions(
591            file_system.file_system,
592            path.as_ref().go_parent().ok_or(Error::InvalidPath)?,
593            Permission::Write,
594            user,
595        )
596        .await?;
597
598        let mut attributes =
599            Attributes::new().set_mask(AttributeFlags::Kind | AttributeFlags::Inode);
600
601        Self::get_attributes(file_system.file_system, path.as_ref(), &mut attributes).await?;
602
603        let inode = *attributes.get_inode().ok_or(Error::MissingAttribute)?;
604        let kind = attributes.get_kind().ok_or(Error::MissingAttribute)?;
605
606        if kind == &Kind::Pipe {
607            let mut named_pipes = self.pipes.write().await;
608
609            named_pipes.remove(&inode);
610        }
611
612        poll(|| Ok(file_system.file_system.remove(relative_path)?)).await?;
613
614        Ok(())
615    }
616
617    pub async fn create_directory(
618        &self,
619        task: TaskIdentifier,
620        path: &impl AsRef<Path>,
621    ) -> Result<()> {
622        let file_systems = self.file_systems.read().await; // Get the file systems
623
624        let (file_system, relative_path, _) = Self::get_file_system_from_path(&file_systems, path)?; // Get the file system identifier and the relative path
625
626        let (time, user, group) = self.get_time_user_group(task).await?;
627
628        // Get the parent directory attributes
629        Self::check_permissions(
630            file_system.file_system,
631            path.as_ref().go_parent().ok_or(Error::InvalidPath)?,
632            Permission::Write,
633            user,
634        )
635        .await?;
636
637        match poll(|| Ok(file_system.file_system.create_directory(relative_path)?)).await {
638            Ok(()) => {}
639            Err(Error::FileSystem(file_system::Error::AlreadyExists)) => {
640                return Err(Error::AlreadyExists);
641            }
642            Err(e) => {
643                return Err(e);
644            }
645        }
646
647        let attributes = Attributes::new()
648            .set_inode(0)
649            .set_links(1)
650            .set_user(user)
651            .set_group(group)
652            .set_creation(time)
653            .set_modification(time)
654            .set_access(time)
655            .set_status(time)
656            .set_kind(Kind::Directory)
657            .set_permissions(Permissions::DIRECTORY_DEFAULT);
658
659        Self::set_attributes(file_system.file_system, path.as_ref(), &attributes).await?;
660
661        Ok(())
662    }
663
664    pub async fn rename(
665        &self,
666        old_path: &impl AsRef<Path>,
667        new_path: &impl AsRef<Path>,
668    ) -> Result<()> {
669        let file_systems = self.file_systems.read().await; // Get the file systems
670
671        let (old_file_system, old_relative_path, _) =
672            Self::get_file_system_from_path(&file_systems, old_path)?; // Get the file system identifier and the relative path
673
674        let (new_file_system, new_relative_path, _) =
675            Self::get_file_system_from_path(&file_systems, new_path)?; // Get the file system identifier and the relative path
676
677        if !ptr::eq(old_file_system, new_file_system) {
678            return Err(Error::InvalidPath);
679        }
680
681        poll(|| {
682            Ok(old_file_system
683                .file_system
684                .rename(old_relative_path, new_relative_path)?)
685        })
686        .await?;
687
688        Ok(())
689    }
690
691    pub async fn get_statistics(&self, path: &impl AsRef<Path>) -> Result<Statistics> {
692        let file_systems = self.file_systems.read().await;
693
694        let (file_system, relative_path, _) = Self::get_file_system_from_path(&file_systems, path)?; // Get the file system identifier and the relative path
695
696        let mut attributes = Attributes::new().set_mask(AttributeFlags::All);
697
698        Self::get_attributes(file_system.file_system, relative_path, &mut attributes).await?;
699
700        Statistics::from_attributes(&attributes).ok_or(Error::MissingAttribute)
701    }
702
703    pub async fn close(&self, item: &ItemStatic, context: &mut Context) -> Result<()> {
704        match item {
705            ItemStatic::File(file_system) | ItemStatic::Directory(file_system) => {
706                self.file_systems
707                    .write()
708                    .await
709                    .iter_mut()
710                    .find_map(|fs| {
711                        if ptr::eq(fs.file_system, *file_system) {
712                            fs.reference_count -= 1;
713                            Some(())
714                        } else {
715                            None
716                        }
717                    })
718                    .ok_or(Error::InvalidIdentifier)?;
719            }
720            ItemStatic::Pipe(pipe) => {
721                let pipes = &mut self.pipes.write().await;
722
723                let key = pipes
724                    .iter_mut()
725                    .find_map(|(key, p)| {
726                        if ptr::eq(p.pipe, *pipe) {
727                            p.reference_count -= 1;
728                            if p.reference_count == 1 {
729                                Some(Some(*key))
730                            } else {
731                                Some(None)
732                            }
733                        } else {
734                            None
735                        }
736                    })
737                    .ok_or(Error::InvalidIdentifier)?;
738
739                if let Some(key) = key {
740                    pipes.remove(&key);
741                }
742            }
743            ItemStatic::BlockDevice(device) => {
744                self.block_device
745                    .write()
746                    .await
747                    .iter_mut()
748                    .find_map(|(_, d)| {
749                        if ptr::eq(d.device, *device) {
750                            d.reference_count -= 1;
751                            Some(())
752                        } else {
753                            None
754                        }
755                    })
756                    .ok_or(Error::InvalidIdentifier)?;
757            }
758            ItemStatic::CharacterDevice(device) => {
759                self.character_device
760                    .write()
761                    .await
762                    .iter_mut()
763                    .find_map(|(_, d)| {
764                        if ptr::eq(d.device, *device) {
765                            d.reference_count -= 1;
766                            Some(())
767                        } else {
768                            None
769                        }
770                    })
771                    .ok_or(Error::InvalidIdentifier)?;
772            }
773            _ => {
774                return Err(Error::InvalidIdentifier);
775            }
776        }
777
778        if let Some(operations) = item.as_directory_operations() {
779            poll(|| Ok(operations.close(context)?)).await?;
780        } else {
781            poll(|| {
782                Ok(item
783                    .as_base_operations()
784                    .ok_or(Error::UnsupportedOperation)?
785                    .close(context)?)
786            })
787            .await?;
788        }
789
790        Ok(())
791    }
792
793    pub async fn set_ownership(
794        &self,
795        task: TaskIdentifier,
796        path: impl AsRef<Path>,
797        user: Option<UserIdentifier>,
798        group: Option<GroupIdentifier>,
799    ) -> Result<()> {
800        let path = path.as_ref();
801        let file_systems = self.file_systems.read().await; // Get the file systems 
802
803        let (file_system, relative_path, _) =
804            Self::get_file_system_from_path(&file_systems, &path)?; // Get the file system identifier and the relative path
805        let (_, current_user, _) = self.get_time_user_group(task).await?;
806        Self::check_owner(file_system.file_system, relative_path, current_user).await?;
807
808        let mut attributes = Attributes::new();
809        if let Some(user) = user {
810            attributes = attributes.set_user(user);
811        }
812        if let Some(group) = group {
813            attributes = attributes.set_group(group);
814        }
815        Self::set_attributes(file_system.file_system, relative_path, &attributes).await
816    }
817
818    pub async fn set_permissions(
819        &self,
820        task: TaskIdentifier,
821        path: impl AsRef<Path>,
822        permissions: Permissions,
823    ) -> Result<()> {
824        let path = path.as_ref();
825        let file_systems = self.file_systems.read().await; // Get the file systems
826
827        let (file_system, relative_path, _) =
828            Self::get_file_system_from_path(&file_systems, &path)?; // Get the file system identifier and the relative path
829
830        let (_, current_user, _) = self.get_time_user_group(task).await?;
831        Self::check_owner(file_system.file_system, relative_path, current_user).await?;
832
833        let attributes = Attributes::new().set_permissions(permissions);
834        Self::set_attributes(file_system.file_system, relative_path, &attributes).await
835    }
836}