1use core::{
3 cmp::min,
4 ffi::{CStr, c_char},
5 num::NonZeroU32,
6 ptr::copy_nonoverlapping,
7};
8use file_system::{AccessFlags, CreateFlags, Flags, StateFlags, character_device};
9use task::block_on;
10use virtual_file_system::{
11 Error, SynchronousDirectory, SynchronousFile, get_instance as get_file_system_instance,
12};
13
14use crate::{XilaFileSystemPollEvent, XilaFileSystemState, XilaTime, file_system::into_position};
15
16use super::{
17 XilaFileIdentifier, XilaFileSystemMode, XilaFileSystemOpen, XilaFileSystemResult,
18 XilaFileSystemSize, XilaFileSystemStatistics, XilaFileSystemWhence,
19};
20
21use abi_context::{self as context, FileIdentifier};
22
23pub fn into_u32<F>(function: F) -> XilaFileSystemResult
25where
26 F: FnOnce() -> Result<(), virtual_file_system::Error>,
27{
28 match function() {
29 Ok(()) => 0,
30 Err(error) => {
31 let non_zero: NonZeroU32 = error.into();
32
33 log::error!("File system error: {:?} ({})", error, non_zero);
34 log::error!("Context debug info: {:?}", context::get_instance());
35
36 non_zero.get()
37 }
38 }
39}
40
41#[unsafe(no_mangle)]
51pub unsafe extern "C" fn xila_file_system_get_statistics(
52 file: XilaFileIdentifier,
53 statistics: *mut XilaFileSystemStatistics,
54) -> XilaFileSystemResult {
55 unsafe {
56 into_u32(move || {
57 let statistics = XilaFileSystemStatistics::from_mutable_pointer(statistics)
58 .ok_or(Error::InvalidParameter)?;
59
60 let context = context::get_instance();
61
62 let s = if let Some(result) = context.perform_operation_on_directory(
63 file.try_into()?,
64 SynchronousDirectory::get_statistics,
65 ) {
66 result.inspect_err(|&e| {
67 log::error!(
68 "Performing operation on directory to get statistics: {:?}",
69 e
70 );
71 })?
72 } else {
73 context
74 .perform_operation_on_file(file.try_into()?, SynchronousFile::get_statistics)
75 .ok_or(Error::InvalidParameter)
76 .inspect_err(|&e| {
77 log::error!("Performing operation on file to get statistics: {:?}", e);
78 })??
79 };
80
81 *statistics = XilaFileSystemStatistics::from_statistics(s);
82
83 Ok(())
84 })
85 }
86}
87
88#[unsafe(no_mangle)]
94pub unsafe extern "C" fn xila_file_system_get_statistics_from_path_at(
95 directory: XilaFileIdentifier,
96 path: *const c_char,
97 statistics: *mut XilaFileSystemStatistics,
98 _: bool,
99) -> XilaFileSystemResult {
100 unsafe {
101 into_u32(move || {
102 let path = CStr::from_ptr(path)
103 .to_str()
104 .map_err(|_| Error::InvalidParameter)?;
105
106 let context = context::get_instance();
107
108 let task = context.get_current_task_identifier();
109
110 let path = context::get_instance()
111 .resolve_path(task, directory.try_into()?, path)
112 .ok_or(Error::InvalidParameter)?;
113
114 let statistics = XilaFileSystemStatistics::from_mutable_pointer(statistics)
115 .ok_or(Error::InvalidParameter)?;
116
117 *statistics = XilaFileSystemStatistics::from_statistics(block_on(
118 get_file_system_instance().get_statistics(&path),
119 )?);
120
121 Ok(())
122 })
123 }
124}
125
126#[unsafe(no_mangle)]
136pub unsafe extern "C" fn xila_file_system_get_access_flags(
137 file: XilaFileIdentifier,
138 mode: *mut XilaFileSystemMode,
139) -> XilaFileSystemResult {
140 unsafe {
141 into_u32(move || {
144 if mode.is_null() {
145 Err(Error::InvalidParameter)?;
146 }
147
148 let m = context::get_instance()
149 .perform_operation_on_file_or_directory(
150 file.try_into()?,
151 |f| SynchronousFile::get_access(f),
152 |d| SynchronousDirectory::get_access(d),
153 )
154 .ok_or(Error::InvalidIdentifier)??;
155
156 mode.write(m.bits());
157
158 Ok(())
159 })
160 }
161}
162
163#[unsafe(no_mangle)]
170pub extern "C" fn xila_file_system_close(file: XilaFileIdentifier) -> XilaFileSystemResult {
171 into_u32(move || {
172 let file: FileIdentifier = file.try_into()?;
173
174 if !file.is_directory() {
175 context::get_instance()
176 .remove_file(file)
177 .ok_or(Error::InvalidIdentifier)?
178 .close(get_file_system_instance())?;
179 } else {
180 log::warning!("Attempted to close a directory with identifier: {:?}", file);
181 }
182
183 Ok(())
184 })
185}
186
187#[unsafe(no_mangle)]
199pub unsafe extern "C" fn xila_file_system_write_vectored(
200 file: XilaFileIdentifier,
201 buffers: *const *const u8,
202 buffers_length: *const usize,
203 buffer_count: usize,
204 written: *mut usize,
205) -> XilaFileSystemResult {
206 unsafe {
207 into_u32(move || {
208 let buffers = core::slice::from_raw_parts(buffers, buffer_count);
209 let buffers_length = core::slice::from_raw_parts(buffers_length, buffer_count);
210
211 let size = context::get_instance()
212 .perform_operation_on_file(file.try_into()?, |file| {
213 let mut current_written = 0;
214
215 for (buffer, length) in buffers.iter().zip(buffers_length.iter()) {
216 let buffer_slice = core::slice::from_raw_parts(*buffer, *length);
217
218 current_written += file.write(buffer_slice)?;
219 }
220
221 Ok::<_, virtual_file_system::Error>(current_written)
222 })
223 .ok_or(Error::InvalidIdentifier)??;
224
225 if !written.is_null() {
226 *written = size;
227 }
228
229 Ok(())
230 })
231 }
232}
233
234#[unsafe(no_mangle)]
244pub unsafe extern "C" fn xila_file_system_read_vectored(
245 file: XilaFileIdentifier,
246 buffers: *mut *mut u8,
247 buffers_length: *mut usize,
248 buffer_count: usize,
249 read: *mut usize,
250) -> XilaFileSystemResult {
251 unsafe {
252 into_u32(move || {
253 let buffers = core::slice::from_raw_parts_mut(buffers, buffer_count);
254 let buffers_length = core::slice::from_raw_parts_mut(buffers_length, buffer_count);
255
256 let current_read = context::get_instance()
257 .perform_operation_on_file(file.try_into()?, |file| {
258 let mut current_read = 0;
259
260 for (buffer_pointer, buffer_length) in
261 buffers.iter_mut().zip(buffers_length.iter_mut())
262 {
263 let buffer =
264 core::slice::from_raw_parts_mut(*buffer_pointer, *buffer_length);
265
266 let read_count = file.read(buffer)?;
267
268 current_read += read_count;
269 }
270
271 Ok::<_, virtual_file_system::Error>(current_read)
272 })
273 .ok_or(Error::InvalidIdentifier)??;
274
275 if !read.is_null() {
276 *read = current_read;
277 }
278
279 Ok(())
280 })
281 }
282}
283
284#[unsafe(no_mangle)]
290pub unsafe extern "C" fn xila_file_system_read_at_position_vectored(
291 file: XilaFileIdentifier,
292 buffers: *mut *mut u8,
293 buffers_length: *mut usize,
294 buffer_count: usize,
295 position: u64,
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 file.set_position(&file_system::Position::Start(position))?;
306
307 let mut current_read = 0;
308
309 for (buffer_pointer, buffer_length) in
310 buffers.iter_mut().zip(buffers_length.iter_mut())
311 {
312 let buffer =
313 core::slice::from_raw_parts_mut(*buffer_pointer, *buffer_length);
314
315 let read_count = file.read(buffer)?;
316
317 current_read += read_count;
318 }
319
320 Ok::<_, virtual_file_system::Error>(current_read)
321 })
322 .ok_or(Error::InvalidIdentifier)??;
323
324 if !read.is_null() {
325 *read = current_read;
326 }
327
328 Ok(())
329 })
330 }
331}
332
333#[unsafe(no_mangle)]
339pub unsafe extern "C" fn xila_file_system_write_at_position_vectored(
340 file: XilaFileIdentifier,
341 buffers: *const *const u8,
342 buffers_length: *const usize,
343 buffer_count: usize,
344 position: u64,
345 written: *mut usize,
346) -> XilaFileSystemResult {
347 unsafe {
348 into_u32(move || {
349 let buffers = core::slice::from_raw_parts(buffers, buffer_count);
350 let buffers_length = core::slice::from_raw_parts(buffers_length, buffer_count);
351
352 let current_written = context::get_instance()
353 .perform_operation_on_file(file.try_into()?, |file| {
354 file.set_position(&file_system::Position::Start(position))?;
355
356 let mut current_written = 0;
357
358 for (buffer, length) in buffers.iter().zip(buffers_length.iter()) {
359 let buffer_slice = core::slice::from_raw_parts(*buffer, *length);
360
361 current_written += file.write(buffer_slice)?;
362 }
363
364 Ok::<_, virtual_file_system::Error>(current_written)
365 })
366 .ok_or(Error::InvalidIdentifier)??;
367
368 if !written.is_null() {
369 *written = current_written;
370 }
371
372 Ok(())
373 })
374 }
375}
376
377#[unsafe(no_mangle)]
387pub unsafe extern "C" fn xila_file_system_is_a_terminal(
388 file: XilaFileIdentifier,
389 is_a_terminal: *mut bool,
390) -> XilaFileSystemResult {
391 into_u32(move || {
392 if is_a_terminal.is_null() {
393 Err(Error::InvalidParameter)?;
394 }
395
396 unsafe {
397 *is_a_terminal = context::get_instance()
398 .perform_operation_on_file(file.try_into()?, |file| {
399 file.control(character_device::IS_A_TERMINAL, &())
400 })
401 .ok_or(Error::InvalidIdentifier)??;
402 }
403
404 Ok(())
405 })
406}
407
408#[unsafe(no_mangle)]
409pub extern "C" fn xila_file_system_is_stdin(file: XilaFileIdentifier) -> bool {
410 if let Ok(file) = file.try_into() {
411 FileIdentifier::STANDARD_IN == file
413 } else {
414 false
415 }
416}
417
418#[unsafe(no_mangle)]
419pub extern "C" fn xila_file_system_is_stderr(file: XilaFileIdentifier) -> bool {
420 if let Ok(file) = file.try_into() {
421 FileIdentifier::STANDARD_ERROR == file
422 } else {
423 false
424 }
425}
426
427#[unsafe(no_mangle)]
428pub extern "C" fn xila_file_system_is_stdout(file: XilaFileIdentifier) -> bool {
429 if let Ok(file) = file.try_into() {
430 FileIdentifier::STANDARD_OUT == file
431 } else {
432 false
433 }
434}
435
436#[unsafe(no_mangle)]
442pub unsafe extern "C" fn xila_file_system_open(
443 path: *const c_char,
444 mode: XilaFileSystemMode,
445 open: XilaFileSystemOpen,
446 status: XilaFileSystemState,
447 file: *mut XilaFileIdentifier,
448) -> XilaFileSystemResult {
449 unsafe {
450 into_u32(move || {
451 let path = core::ffi::CStr::from_ptr(path)
452 .to_str()
453 .map_err(|_| Error::InvalidParameter)?;
454
455 let mode = AccessFlags::from_bits_truncate(mode);
456 let open = CreateFlags::from_bits_truncate(open);
457 let status = StateFlags::from_bits_truncate(status);
458
459 let flags = Flags::new(mode, Some(open), Some(status));
460
461 let task = context::get_instance().get_current_task_identifier();
464
465 let f = SynchronousFile::open(get_file_system_instance(), task, path, flags)?;
466
467 *file = context::get_instance()
468 .insert_file(task, f, None)
469 .ok_or(Error::InvalidIdentifier)?
470 .into();
471
472 Ok(())
473 })
474 }
475}
476
477#[unsafe(no_mangle)]
478pub extern "C" fn xila_file_system_set_flags(
479 _file: XilaFileIdentifier,
480 _status: XilaFileSystemState,
481) -> XilaFileSystemResult {
482 todo!()
483}
484
485#[unsafe(no_mangle)]
491pub unsafe extern "C" fn xila_file_system_get_state_flags(
492 _file: XilaFileIdentifier,
493 _status: *mut XilaFileSystemState,
494) -> XilaFileSystemResult {
495 unsafe {
496 into_u32(move || {
497 if _status.is_null() {
498 Err(Error::InvalidParameter)?;
499 }
500
501 let state = context::get_instance()
502 .perform_operation_on_file_or_directory(
503 _file.try_into()?,
504 |f| SynchronousFile::get_state(f),
505 |d| SynchronousDirectory::get_state(d),
506 )
507 .ok_or(Error::InvalidIdentifier)??;
508
509 _status.write(state.bits());
510
511 Ok(())
512 })
513 }
514}
515
516#[unsafe(no_mangle)]
522pub unsafe extern "C" fn xila_file_system_resolve_path(
523 path: *const i8,
524 resolved_path: *mut u8,
525 resolved_path_size: usize,
526) -> XilaFileSystemResult {
527 unsafe {
528 into_u32(move || {
529 let path = core::ffi::CStr::from_ptr(path)
530 .to_str()
531 .map_err(|_| Error::InvalidParameter)?;
532
533 copy_nonoverlapping(
537 path.as_ptr(),
538 resolved_path,
539 min(resolved_path_size, path.len()),
540 );
541
542 Ok(())
543 })
544 }
545}
546
547#[unsafe(no_mangle)]
548pub extern "C" fn xila_file_system_flush(
549 file: XilaFileIdentifier,
550 _: bool,
551) -> XilaFileSystemResult {
552 into_u32(move || {
553 context::get_instance()
554 .perform_operation_on_file(file.try_into()?, |file| file.flush())
555 .ok_or(Error::InvalidIdentifier)??;
556
557 Ok(())
558 })
559}
560
561#[unsafe(no_mangle)]
562pub extern "C" fn xila_file_system_create_symbolic_link_at(
563 _: XilaFileIdentifier,
564 _: *const c_char,
565 _: *const c_char,
566) -> XilaFileSystemResult {
567 todo!()
568}
569
570#[unsafe(no_mangle)]
571pub extern "C" fn xila_file_system_read_link_at(
572 _directory: XilaFileIdentifier,
573 _path: *mut i8,
574 _size: usize,
575 _used: *mut usize,
576) -> XilaFileSystemResult {
577 todo!()
578}
579
580#[unsafe(no_mangle)]
586pub unsafe extern "C" fn xila_file_system_set_position(
587 file: XilaFileIdentifier,
588 offset: i64,
589 whence: XilaFileSystemWhence,
590 position: *mut XilaFileSystemSize,
591) -> XilaFileSystemResult {
592 unsafe {
593 into_u32(move || {
594 let current_position = into_position(whence, offset);
595
596 let result = context::get_instance()
599 .perform_operation_on_file(file.try_into()?, |file| {
600 file.set_position(¤t_position)
601 })
602 .ok_or(Error::InvalidIdentifier)??;
603
604 *position = result;
605
606 Ok(())
607 })
608 }
609}
610
611#[unsafe(no_mangle)]
617pub unsafe extern "C" fn xila_file_system_create_directory_at(
618 directory: XilaFileIdentifier,
619 path: *const c_char,
620) -> XilaFileSystemResult {
621 unsafe {
622 into_u32(move || {
623 let path = CStr::from_ptr(path)
624 .to_str()
625 .map_err(|_| Error::InvalidParameter)?;
626
627 let context = context::get_instance();
628
629 let task = context.get_current_task_identifier();
630
631 let path = context
632 .resolve_path(task, directory.try_into()?, path)
633 .ok_or(Error::InvalidParameter)?;
634
635 let task = context::get_instance().get_current_task_identifier();
636 block_on(get_file_system_instance().create_directory(task, &path))?;
637
638 Ok(())
639 })
640 }
641}
642
643#[unsafe(no_mangle)]
649pub unsafe extern "C" fn xila_file_system_rename(
650 old_path: *const c_char,
651 new_path: *const c_char,
652) -> XilaFileSystemResult {
653 unsafe {
654 into_u32(move || {
655 let old_path = CStr::from_ptr(old_path)
656 .to_str()
657 .map_err(|_| Error::InvalidParameter)?;
658
659 let new_path = CStr::from_ptr(new_path)
660 .to_str()
661 .map_err(|_| Error::InvalidParameter)?;
662
663 block_on(get_file_system_instance().rename(&old_path, &new_path))?;
666
667 Ok(())
668 })
669 }
670}
671
672#[unsafe(no_mangle)]
673pub extern "C" fn xila_file_system_set_times(
674 _: XilaFileIdentifier,
675 _: XilaTime,
676 _: XilaTime,
677 _: u8,
678) -> XilaFileSystemResult {
679 todo!()
680}
681
682#[unsafe(no_mangle)]
688pub unsafe extern "C" fn xila_file_system_set_times_from_path(
689 _path: *const c_char,
690 _access: XilaTime,
691 _modification: XilaTime,
692 _flags: u8,
693 _follow: bool,
694) -> XilaFileSystemResult {
695 todo!()
696}
697
698#[unsafe(no_mangle)]
704pub unsafe extern "C" fn xila_file_system_remove(_path: *const c_char) -> XilaFileSystemResult {
705 unsafe {
706 into_u32(|| {
707 let path = CStr::from_ptr(_path)
708 .to_str()
709 .map_err(|_| Error::InvalidParameter)?;
710
711 let task = context::get_instance().get_current_task_identifier();
712
713 block_on(get_file_system_instance().remove(task, path))?;
714
715 Ok(())
716 })
717 }
718}
719
720#[unsafe(no_mangle)]
722pub extern "C" fn xila_file_system_truncate(
723 _file: XilaFileIdentifier,
724 _length: XilaFileSystemSize,
725) -> XilaFileSystemResult {
726 into_u32(move || {
727 let _task = context::get_instance().get_current_task_identifier();
728
729 let _file: FileIdentifier = _file.try_into()?;
730
731 todo!();
732 })
733}
734
735#[unsafe(no_mangle)]
741pub unsafe extern "C" fn xila_file_system_link(
742 _path: *const c_char,
743 _link: *const c_char,
744) -> XilaFileSystemResult {
745 todo!()
746}
747
748#[unsafe(no_mangle)]
750pub extern "C" fn xila_file_system_advise(
751 _file: XilaFileIdentifier,
752 _offset: XilaFileSystemSize,
753 _length: XilaFileSystemSize,
754 _advice: u8,
755) -> XilaFileSystemResult {
756 todo!()
757}
758
759#[unsafe(no_mangle)]
760pub extern "C" fn xila_file_system_allocate(
761 _file: XilaFileIdentifier,
762 _offset: XilaFileSystemSize,
763 _length: XilaFileSystemSize,
764) -> XilaFileSystemResult {
765 todo!()
766}
767
768#[unsafe(no_mangle)]
769pub extern "C" fn xila_file_system_dummy(_: XilaFileSystemPollEvent) -> XilaFileSystemResult {
770 into_u32(move || Ok(()))
771}