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