Skip to main content

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