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
35pub struct VirtualFileSystem {
38 task_manager: &'static task::Manager,
39 users_manager: &'static users::Manager,
40 time_manager: &'static time::Manager<'static>,
41 file_systems: RwLock<CriticalSectionRawMutex, FileSystemsArray>,
43 character_device: RwLock<CriticalSectionRawMutex, CharacterDevicesMap>,
45 block_device: RwLock<CriticalSectionRawMutex, BlockDevicesMap>,
47 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 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)?; 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; 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)?; 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; 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)?; 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)?; 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; let (parent_file_system, relative_path, _) =
414 Self::get_mutable_file_system_from_path(&mut file_systems, &path)?; 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; let (file_system, relative_path, _) =
603 Self::get_file_system_from_path(&file_systems, &path)?; 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; 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?;
644
645 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; let (old_file_system, old_relative_path, _) =
689 Self::get_file_system_from_path(&file_systems, old_path)?; let (new_file_system, new_relative_path, _) =
692 Self::get_file_system_from_path(&file_systems, new_path)?; 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)?; 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; let (file_system, relative_path, _) =
829 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 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; let (file_system, relative_path, _) =
853 Self::get_file_system_from_path(&file_systems, &path)?; 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}