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
23static 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
44pub struct VirtualFileSystem {
48 file_systems: RwLock<CriticalSectionRawMutex, FileSystemsArray>,
50 character_device: RwLock<CriticalSectionRawMutex, CharacterDevicesMap>,
52 block_device: RwLock<CriticalSectionRawMutex, BlockDevicesMap>,
54 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 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)?; 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; 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)?; 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; 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)?; 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)?; 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; let (parent_file_system, relative_path, _) =
399 Self::get_mutable_file_system_from_path(&mut file_systems, &path)?; 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; let (file_system, relative_path, _) =
586 Self::get_file_system_from_path(&file_systems, &path)?; 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; let (file_system, relative_path, _) = Self::get_file_system_from_path(&file_systems, path)?; let (time, user, group) = self.get_time_user_group(task).await?;
627
628 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; let (old_file_system, old_relative_path, _) =
672 Self::get_file_system_from_path(&file_systems, old_path)?; let (new_file_system, new_relative_path, _) =
675 Self::get_file_system_from_path(&file_systems, new_path)?; 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)?; 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; let (file_system, relative_path, _) =
804 Self::get_file_system_from_path(&file_systems, &path)?; 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; let (file_system, relative_path, _) =
828 Self::get_file_system_from_path(&file_systems, &path)?; 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}