1use core::{
3 cmp::min,
4 ffi::{CStr, c_char},
5 num::NonZeroU32,
6 ptr::copy_nonoverlapping,
7};
8use file_system::{
9 AccessFlags, CreateFlags, Flags, Kind, Permissions, StateFlags, Statistics, Time,
10 character_device,
11};
12use task::block_on;
13use users::{GroupIdentifier, UserIdentifier};
14use virtual_file_system::{
15 Error, SynchronousDirectory, SynchronousFile, get_instance as get_file_system_instance,
16};
17
18use crate::{XilaFileSystemPollEvent, XilaFileSystemState, XilaTime, file_system::into_position};
19
20use super::{
21 XilaFileIdentifier, XilaFileSystemMode, XilaFileSystemOpen, XilaFileSystemResult,
22 XilaFileSystemSize, XilaFileSystemStatistics, XilaFileSystemWhence,
23};
24
25use abi_context::{self as context, FileIdentifier};
26
27pub fn into_u32<F>(function: F) -> XilaFileSystemResult
29where
30 F: FnOnce() -> Result<(), virtual_file_system::Error>,
31{
32 match function() {
33 Ok(()) => 0,
34 Err(error) => {
35 let non_zero: NonZeroU32 = error.into();
36
37 if matches!(
38 error,
39 Error::RessourceBusy | Error::FileSystem(file_system::Error::RessourceBusy)
40 ) {
41 log::debug!(
42 "File system busy (expected while polling): {:?} ({})",
43 error,
44 non_zero
45 );
46 } else {
47 log::error!("File system error: {:?} ({})", error, non_zero);
48 log::error!("Context debug info: {:?}", context::get_instance());
49 }
50
51 non_zero.get()
54 }
55 }
56}
57
58#[unsafe(no_mangle)]
68pub unsafe extern "C" fn xila_file_system_get_statistics(
69 file: XilaFileIdentifier,
70 statistics: *mut XilaFileSystemStatistics,
71) -> XilaFileSystemResult {
72 unsafe {
73 into_u32(move || {
74 let statistics = XilaFileSystemStatistics::from_mutable_pointer(statistics)
75 .ok_or(Error::InvalidParameter)?;
76
77 let context = context::get_instance();
78
79 let s = if let Some(result) = context.perform_operation_on_directory(
80 file.try_into()?,
81 SynchronousDirectory::get_statistics,
82 ) {
83 log::information!(
84 "File identifier {:?} is a directory, getting statistics",
85 file
86 );
87 result.inspect_err(|&e| {
88 log::error!(
89 "Performing operation on directory to get statistics: {:?}",
90 e
91 );
92 })?
93 } else {
94 log::information!(
95 "File identifier {:?} is not a directory, trying as a file",
96 file
97 );
98 match context
99 .perform_operation_on_file(file.try_into()?, SynchronousFile::get_statistics)
100 .ok_or(Error::InvalidParameter)
101 .inspect_err(|&e| {
102 log::error!("Performing operation on file to get statistics: {:?}", e);
103 })? {
104 Ok(statistics) => statistics,
105 Err(Error::UnsupportedOperation)
109 | Err(Error::FileSystem(file_system::Error::UnsupportedOperation)) => {
110 Statistics::new(
111 0,
112 1,
113 0,
114 Time::new(0),
115 Time::new(0),
116 Time::new(0),
117 Time::new(0),
118 Kind::CharacterDevice,
119 Permissions::DEVICE_DEFAULT,
120 UserIdentifier::ROOT,
121 GroupIdentifier::ROOT,
122 )
123 }
124 Err(error) => return Err(error),
125 }
126 };
127
128 *statistics = XilaFileSystemStatistics::from_statistics(s);
129
130 Ok(())
131 })
132 }
133}
134
135#[unsafe(no_mangle)]
141pub unsafe extern "C" fn xila_file_system_get_statistics_from_path_at(
142 directory: XilaFileIdentifier,
143 path: *const c_char,
144 statistics: *mut XilaFileSystemStatistics,
145 _: bool,
146) -> XilaFileSystemResult {
147 unsafe {
148 into_u32(move || {
149 let path = CStr::from_ptr(path)
150 .to_str()
151 .map_err(|_| Error::InvalidParameter)?;
152
153 let context = context::get_instance();
154
155 let task = context.get_current_task_identifier();
156
157 let path = context::get_instance()
158 .resolve_path(task, directory.try_into()?, path)
159 .ok_or(Error::InvalidParameter)?;
160
161 let statistics = XilaFileSystemStatistics::from_mutable_pointer(statistics)
162 .ok_or(Error::InvalidParameter)?;
163
164 *statistics = XilaFileSystemStatistics::from_statistics(block_on(
165 get_file_system_instance().get_statistics(&path),
166 )?);
167
168 Ok(())
169 })
170 }
171}
172
173#[unsafe(no_mangle)]
183pub unsafe extern "C" fn xila_file_system_get_access_flags(
184 file: XilaFileIdentifier,
185 mode: *mut XilaFileSystemMode,
186) -> XilaFileSystemResult {
187 unsafe {
188 into_u32(move || {
191 if mode.is_null() {
192 Err(Error::InvalidParameter)?;
193 }
194
195 let m = context::get_instance()
196 .perform_operation_on_file_or_directory(
197 file.try_into()?,
198 |f| SynchronousFile::get_access(f),
199 |d| SynchronousDirectory::get_access(d),
200 )
201 .ok_or(Error::InvalidIdentifier)??;
202
203 mode.write(m.bits());
204
205 Ok(())
206 })
207 }
208}
209
210#[unsafe(no_mangle)]
217pub extern "C" fn xila_file_system_close(file: XilaFileIdentifier) -> XilaFileSystemResult {
218 into_u32(move || {
219 let file: FileIdentifier = file.try_into()?;
220
221 if !file.is_directory() {
222 context::get_instance()
223 .remove_file(file)
224 .ok_or(Error::InvalidIdentifier)?
225 .close(get_file_system_instance())?;
226 } else {
227 log::warning!("Attempted to close a directory with identifier: {:?}", file);
228 }
229
230 Ok(())
231 })
232}
233
234#[unsafe(no_mangle)]
246pub unsafe extern "C" fn xila_file_system_write_vectored(
247 file: XilaFileIdentifier,
248 buffers: *const *const u8,
249 buffers_length: *const usize,
250 buffer_count: usize,
251 written: *mut usize,
252) -> XilaFileSystemResult {
253 unsafe {
254 into_u32(move || {
255 let buffers = core::slice::from_raw_parts(buffers, buffer_count);
256 let buffers_length = core::slice::from_raw_parts(buffers_length, buffer_count);
257
258 let size = context::get_instance()
259 .perform_operation_on_file(file.try_into()?, |file| {
260 let mut current_written = 0;
261
262 for (buffer, length) in buffers.iter().zip(buffers_length.iter()) {
263 let buffer_slice = core::slice::from_raw_parts(*buffer, *length);
264
265 current_written += file.write(buffer_slice)?;
266 }
267
268 Ok::<_, virtual_file_system::Error>(current_written)
269 })
270 .ok_or(Error::InvalidIdentifier)??;
271
272 if !written.is_null() {
273 *written = size;
274 }
275
276 Ok(())
277 })
278 }
279}
280
281#[unsafe(no_mangle)]
291pub unsafe extern "C" fn xila_file_system_read_vectored(
292 file: XilaFileIdentifier,
293 buffers: *mut *mut u8,
294 buffers_length: *mut usize,
295 buffer_count: usize,
296 read: *mut usize,
297) -> XilaFileSystemResult {
298 unsafe {
299 into_u32(move || {
300 let buffers = core::slice::from_raw_parts_mut(buffers, buffer_count);
301 let buffers_length = core::slice::from_raw_parts_mut(buffers_length, buffer_count);
302
303 let current_read = context::get_instance()
304 .perform_operation_on_file(file.try_into()?, |file| {
305 let mut current_read = 0;
306
307 for (buffer_pointer, buffer_length) in
308 buffers.iter_mut().zip(buffers_length.iter_mut())
309 {
310 let buffer =
311 core::slice::from_raw_parts_mut(*buffer_pointer, *buffer_length);
312
313 let read_count = file.read(buffer)?;
314
315 current_read += read_count;
316 }
317
318 Ok::<_, virtual_file_system::Error>(current_read)
319 })
320 .ok_or(Error::InvalidIdentifier)??;
321
322 if !read.is_null() {
323 *read = current_read;
324 }
325
326 Ok(())
327 })
328 }
329}
330
331#[unsafe(no_mangle)]
337pub unsafe extern "C" fn xila_file_system_read_at_position_vectored(
338 file: XilaFileIdentifier,
339 buffers: *mut *mut u8,
340 buffers_length: *mut usize,
341 buffer_count: usize,
342 position: u64,
343 read: *mut usize,
344) -> XilaFileSystemResult {
345 unsafe {
346 into_u32(move || {
347 let buffers = core::slice::from_raw_parts_mut(buffers, buffer_count);
348 let buffers_length = core::slice::from_raw_parts_mut(buffers_length, buffer_count);
349
350 let current_read = context::get_instance()
351 .perform_operation_on_file(file.try_into()?, |file| {
352 file.set_position(&file_system::Position::Start(position))?;
353
354 let mut current_read = 0;
355
356 for (buffer_pointer, buffer_length) in
357 buffers.iter_mut().zip(buffers_length.iter_mut())
358 {
359 let buffer =
360 core::slice::from_raw_parts_mut(*buffer_pointer, *buffer_length);
361
362 let read_count = file.read(buffer)?;
363
364 current_read += read_count;
365 }
366
367 Ok::<_, virtual_file_system::Error>(current_read)
368 })
369 .ok_or(Error::InvalidIdentifier)??;
370
371 if !read.is_null() {
372 *read = current_read;
373 }
374
375 Ok(())
376 })
377 }
378}
379
380#[unsafe(no_mangle)]
386pub unsafe extern "C" fn xila_file_system_write_at_position_vectored(
387 file: XilaFileIdentifier,
388 buffers: *const *const u8,
389 buffers_length: *const usize,
390 buffer_count: usize,
391 position: u64,
392 written: *mut usize,
393) -> XilaFileSystemResult {
394 unsafe {
395 into_u32(move || {
396 let buffers = core::slice::from_raw_parts(buffers, buffer_count);
397 let buffers_length = core::slice::from_raw_parts(buffers_length, buffer_count);
398
399 let current_written = context::get_instance()
400 .perform_operation_on_file(file.try_into()?, |file| {
401 file.set_position(&file_system::Position::Start(position))?;
402
403 let mut current_written = 0;
404
405 for (buffer, length) in buffers.iter().zip(buffers_length.iter()) {
406 let buffer_slice = core::slice::from_raw_parts(*buffer, *length);
407
408 current_written += file.write(buffer_slice)?;
409 }
410
411 Ok::<_, virtual_file_system::Error>(current_written)
412 })
413 .ok_or(Error::InvalidIdentifier)??;
414
415 if !written.is_null() {
416 *written = current_written;
417 }
418
419 Ok(())
420 })
421 }
422}
423
424#[unsafe(no_mangle)]
434pub unsafe extern "C" fn xila_file_system_is_a_terminal(
435 file: XilaFileIdentifier,
436 is_a_terminal: *mut bool,
437) -> XilaFileSystemResult {
438 into_u32(move || {
439 if is_a_terminal.is_null() {
440 Err(Error::InvalidParameter)?;
441 }
442
443 unsafe {
444 *is_a_terminal = context::get_instance()
445 .perform_operation_on_file(file.try_into()?, |file| {
446 file.control(character_device::IS_A_TERMINAL, &())
447 })
448 .ok_or(Error::InvalidIdentifier)??;
449 }
450
451 Ok(())
452 })
453}
454
455#[unsafe(no_mangle)]
456pub extern "C" fn xila_file_system_is_stdin(file: XilaFileIdentifier) -> bool {
457 if let Ok(file) = file.try_into() {
458 FileIdentifier::STANDARD_IN == file
460 } else {
461 false
462 }
463}
464
465#[unsafe(no_mangle)]
466pub extern "C" fn xila_file_system_is_stderr(file: XilaFileIdentifier) -> bool {
467 if let Ok(file) = file.try_into() {
468 FileIdentifier::STANDARD_ERROR == file
469 } else {
470 false
471 }
472}
473
474#[unsafe(no_mangle)]
475pub extern "C" fn xila_file_system_is_stdout(file: XilaFileIdentifier) -> bool {
476 if let Ok(file) = file.try_into() {
477 FileIdentifier::STANDARD_OUT == file
478 } else {
479 false
480 }
481}
482
483#[unsafe(no_mangle)]
489pub unsafe extern "C" fn xila_file_system_open(
490 path: *const c_char,
491 mode: XilaFileSystemMode,
492 open: XilaFileSystemOpen,
493 status: XilaFileSystemState,
494 file: *mut XilaFileIdentifier,
495) -> XilaFileSystemResult {
496 unsafe {
497 into_u32(move || {
498 let path = core::ffi::CStr::from_ptr(path)
499 .to_str()
500 .map_err(|_| Error::InvalidParameter)?;
501
502 let mode = AccessFlags::from_bits_truncate(mode);
503 let open = CreateFlags::from_bits_truncate(open);
504 let status = StateFlags::from_bits_truncate(status);
505
506 let flags = Flags::new(mode, Some(open), Some(status));
507
508 let task = context::get_instance().get_current_task_identifier();
511
512 let f = SynchronousFile::open(get_file_system_instance(), task, path, flags)?;
513
514 *file = context::get_instance()
515 .insert_file(task, f, None)
516 .ok_or(Error::InvalidIdentifier)?
517 .into();
518
519 Ok(())
520 })
521 }
522}
523
524#[unsafe(no_mangle)]
525pub extern "C" fn xila_file_system_set_flags(
526 _file: XilaFileIdentifier,
527 _status: XilaFileSystemState,
528) -> XilaFileSystemResult {
529 todo!()
530}
531
532#[unsafe(no_mangle)]
538pub unsafe extern "C" fn xila_file_system_get_state_flags(
539 _file: XilaFileIdentifier,
540 _status: *mut XilaFileSystemState,
541) -> XilaFileSystemResult {
542 unsafe {
543 into_u32(move || {
544 if _status.is_null() {
545 Err(Error::InvalidParameter)?;
546 }
547
548 let state = context::get_instance()
549 .perform_operation_on_file_or_directory(
550 _file.try_into()?,
551 |f| SynchronousFile::get_state(f),
552 |d| SynchronousDirectory::get_state(d),
553 )
554 .ok_or(Error::InvalidIdentifier)??;
555
556 _status.write(state.bits());
557
558 Ok(())
559 })
560 }
561}
562
563#[unsafe(no_mangle)]
569pub unsafe extern "C" fn xila_file_system_resolve_path(
570 path: *const i8,
571 resolved_path: *mut u8,
572 resolved_path_size: usize,
573) -> XilaFileSystemResult {
574 unsafe {
575 into_u32(move || {
576 let path = core::ffi::CStr::from_ptr(path)
577 .to_str()
578 .map_err(|_| Error::InvalidParameter)?;
579
580 copy_nonoverlapping(
584 path.as_ptr(),
585 resolved_path,
586 min(resolved_path_size, path.len()),
587 );
588
589 Ok(())
590 })
591 }
592}
593
594#[unsafe(no_mangle)]
595pub extern "C" fn xila_file_system_flush(
596 file: XilaFileIdentifier,
597 _: bool,
598) -> XilaFileSystemResult {
599 into_u32(move || {
600 context::get_instance()
601 .perform_operation_on_file(file.try_into()?, |file| file.flush())
602 .ok_or(Error::InvalidIdentifier)??;
603
604 Ok(())
605 })
606}
607
608#[unsafe(no_mangle)]
609pub extern "C" fn xila_file_system_create_symbolic_link_at(
610 _: XilaFileIdentifier,
611 _: *const c_char,
612 _: *const c_char,
613) -> XilaFileSystemResult {
614 todo!()
615}
616
617#[unsafe(no_mangle)]
618pub extern "C" fn xila_file_system_read_link_at(
619 _directory: XilaFileIdentifier,
620 _path: *mut i8,
621 _size: usize,
622 _used: *mut usize,
623) -> XilaFileSystemResult {
624 todo!()
625}
626
627#[unsafe(no_mangle)]
633pub unsafe extern "C" fn xila_file_system_set_position(
634 file: XilaFileIdentifier,
635 offset: i64,
636 whence: XilaFileSystemWhence,
637 position: *mut XilaFileSystemSize,
638) -> XilaFileSystemResult {
639 unsafe {
640 into_u32(move || {
641 let current_position = into_position(whence, offset);
642
643 let result = context::get_instance()
646 .perform_operation_on_file(file.try_into()?, |file| {
647 file.set_position(¤t_position)
648 })
649 .ok_or(Error::InvalidIdentifier)??;
650
651 *position = result;
652
653 Ok(())
654 })
655 }
656}
657
658#[unsafe(no_mangle)]
664pub unsafe extern "C" fn xila_file_system_create_directory_at(
665 directory: XilaFileIdentifier,
666 path: *const c_char,
667) -> XilaFileSystemResult {
668 unsafe {
669 into_u32(move || {
670 let path = CStr::from_ptr(path)
671 .to_str()
672 .map_err(|_| Error::InvalidParameter)?;
673
674 let context = context::get_instance();
675
676 let task = context.get_current_task_identifier();
677
678 let path = context
679 .resolve_path(task, directory.try_into()?, path)
680 .ok_or(Error::InvalidParameter)?;
681
682 let task = context::get_instance().get_current_task_identifier();
683 block_on(get_file_system_instance().create_directory(task, &path))?;
684
685 Ok(())
686 })
687 }
688}
689
690#[unsafe(no_mangle)]
696pub unsafe extern "C" fn xila_file_system_rename(
697 old_path: *const c_char,
698 new_path: *const c_char,
699) -> XilaFileSystemResult {
700 unsafe {
701 into_u32(move || {
702 let old_path = CStr::from_ptr(old_path)
703 .to_str()
704 .map_err(|_| Error::InvalidParameter)?;
705
706 let new_path = CStr::from_ptr(new_path)
707 .to_str()
708 .map_err(|_| Error::InvalidParameter)?;
709
710 block_on(get_file_system_instance().rename(&old_path, &new_path))?;
713
714 Ok(())
715 })
716 }
717}
718
719#[unsafe(no_mangle)]
720pub extern "C" fn xila_file_system_set_times(
721 _: XilaFileIdentifier,
722 _: XilaTime,
723 _: XilaTime,
724 _: u8,
725) -> XilaFileSystemResult {
726 todo!()
727}
728
729#[unsafe(no_mangle)]
735pub unsafe extern "C" fn xila_file_system_set_times_from_path(
736 _path: *const c_char,
737 _access: XilaTime,
738 _modification: XilaTime,
739 _flags: u8,
740 _follow: bool,
741) -> XilaFileSystemResult {
742 todo!()
743}
744
745#[unsafe(no_mangle)]
751pub unsafe extern "C" fn xila_file_system_remove(_path: *const c_char) -> XilaFileSystemResult {
752 unsafe {
753 into_u32(|| {
754 let path = CStr::from_ptr(_path)
755 .to_str()
756 .map_err(|_| Error::InvalidParameter)?;
757
758 let task = context::get_instance().get_current_task_identifier();
759
760 block_on(get_file_system_instance().remove(task, path))?;
761
762 Ok(())
763 })
764 }
765}
766
767#[unsafe(no_mangle)]
769pub extern "C" fn xila_file_system_truncate(
770 _file: XilaFileIdentifier,
771 _length: XilaFileSystemSize,
772) -> XilaFileSystemResult {
773 into_u32(move || {
774 let _task = context::get_instance().get_current_task_identifier();
775
776 let _file: FileIdentifier = _file.try_into()?;
777
778 todo!();
779 })
780}
781
782#[unsafe(no_mangle)]
788pub unsafe extern "C" fn xila_file_system_link(
789 _path: *const c_char,
790 _link: *const c_char,
791) -> XilaFileSystemResult {
792 todo!()
793}
794
795#[unsafe(no_mangle)]
797pub extern "C" fn xila_file_system_advise(
798 _file: XilaFileIdentifier,
799 _offset: XilaFileSystemSize,
800 _length: XilaFileSystemSize,
801 _advice: u8,
802) -> XilaFileSystemResult {
803 todo!()
804}
805
806#[unsafe(no_mangle)]
807pub extern "C" fn xila_file_system_allocate(
808 _file: XilaFileIdentifier,
809 _offset: XilaFileSystemSize,
810 _length: XilaFileSystemSize,
811) -> XilaFileSystemResult {
812 todo!()
813}
814
815#[unsafe(no_mangle)]
816pub extern "C" fn xila_file_system_dummy(_: XilaFileSystemPollEvent) -> XilaFileSystemResult {
817 into_u32(move || Ok(()))
818}