abi/file_system/
functions.rs

1/// This module implements the POSIX like file system C ABI.
2use core::{
3    cmp::min,
4    ffi::{CStr, c_char},
5    num::NonZeroU32,
6    ptr::copy_nonoverlapping,
7};
8
9use futures::block_on;
10
11use file_system::{Error, FileIdentifier, Flags, Mode, Open, Status};
12use virtual_file_system::get_instance as get_file_system_instance;
13
14use crate::{XilaTime, context, into_position};
15
16use super::{
17    XilaFileSystemMode, XilaFileSystemOpen, XilaFileSystemResult, XilaFileSystemSize,
18    XilaFileSystemStatistics, XilaFileSystemStatus, XilaFileSystemWhence, XilaUniqueFileIdentifier,
19};
20
21/// This function is used to convert a function returning a Result into a u32.
22pub fn into_u32<F>(function: F) -> XilaFileSystemResult
23where
24    F: FnOnce() -> Result<(), NonZeroU32>,
25{
26    match function() {
27        Ok(()) => 0,
28        Err(error) => error.get(),
29    }
30}
31
32/// This function is used to open a file.
33///
34/// # Safety
35///
36/// This function is unsafe because it dereferences raw pointers.
37///
38/// # Errors
39///
40/// This function may return an error if the file system fails to open the file.
41#[unsafe(no_mangle)]
42pub unsafe extern "C" fn xila_file_system_get_statistics(
43    file: XilaUniqueFileIdentifier,
44    statistics: *mut XilaFileSystemStatistics,
45) -> XilaFileSystemResult {
46    unsafe {
47        into_u32(move || {
48            let task_identifier = context::get_instance().get_current_task_identifier();
49
50            let statistics = XilaFileSystemStatistics::from_mutable_pointer(statistics)
51                .ok_or(Error::InvalidParameter)?;
52
53            let file = file_system::UniqueFileIdentifier::from_raw(file);
54
55            *statistics = XilaFileSystemStatistics::from_statistics(
56                block_on(get_file_system_instance().get_statistics(file, task_identifier))
57                    .expect("Failed to get file statistics."),
58            );
59
60            Ok(())
61        })
62    }
63}
64
65/// This function is used to get the statistics of a file from its path.
66///
67/// # Safety
68///
69/// This function is unsafe because it dereferences raw pointers.
70#[unsafe(no_mangle)]
71pub unsafe extern "C" fn xila_file_system_get_statistics_from_path(
72    path: *const c_char,
73    statistics: *mut XilaFileSystemStatistics,
74    _: bool,
75) -> XilaFileSystemResult {
76    unsafe {
77        into_u32(move || {
78            let path = CStr::from_ptr(path)
79                .to_str()
80                .map_err(|_| Error::InvalidParameter)?;
81
82            let statistics = XilaFileSystemStatistics::from_mutable_pointer(statistics)
83                .ok_or(Error::InvalidParameter)?;
84
85            *statistics = XilaFileSystemStatistics::from_statistics(block_on(
86                get_file_system_instance().get_statistics_from_path(&path),
87            )?);
88
89            Ok(())
90        })
91    }
92}
93
94/// This function is used to get the access mode of a file.
95///
96/// # Safety
97///
98/// This function is unsafe because it dereferences raw pointers.
99///
100/// # Errors
101///
102/// This function may return an error if the file system fails to get the access mode of the file.
103#[unsafe(no_mangle)]
104pub unsafe extern "C" fn xila_file_system_get_access_mode(
105    file: XilaUniqueFileIdentifier,
106    mode: *mut XilaFileSystemMode,
107) -> XilaFileSystemResult {
108    unsafe {
109        // Debug: Getting file access mode
110
111        into_u32(move || {
112            let task_identifier = context::get_instance().get_current_task_identifier();
113
114            if mode.is_null() {
115                Err(Error::InvalidParameter)?;
116            }
117
118            let file = file_system::UniqueFileIdentifier::from_raw(file);
119
120            mode.write(
121                block_on(get_file_system_instance().get_mode(file, task_identifier))?.as_u8(),
122            );
123
124            Ok(())
125        })
126    }
127}
128
129/// This function is used to close a file.
130///
131/// # Errors
132///
133/// This function may return an error if the file system fails to close the file.
134///
135#[unsafe(no_mangle)]
136pub extern "C" fn xila_file_system_close(file: XilaUniqueFileIdentifier) -> XilaFileSystemResult {
137    into_u32(move || {
138        let task_identifier = context::get_instance().get_current_task_identifier();
139
140        let file = file_system::UniqueFileIdentifier::from_raw(file);
141
142        block_on(get_file_system_instance().close(file, task_identifier))?;
143
144        Ok(())
145    })
146}
147
148/// This function is used perform a vectored write operation on a file.
149///
150/// # Safety
151///
152/// This function is unsafe because it dereferences raw pointers.
153///
154/// # Errors
155///
156/// This function may return an error if the file system fails to open the file.
157///
158/// # Example
159#[unsafe(no_mangle)]
160pub unsafe extern "C" fn xila_file_system_write_vectored(
161    file: XilaUniqueFileIdentifier,
162    buffers: *const *const u8,
163    buffers_length: *const usize,
164    buffer_count: usize,
165    written: *mut usize,
166) -> XilaFileSystemResult {
167    unsafe {
168        into_u32(move || {
169            let task_identifier = context::get_instance().get_current_task_identifier();
170
171            let buffers = core::slice::from_raw_parts(buffers, buffer_count);
172            let buffers_length = core::slice::from_raw_parts(buffers_length, buffer_count);
173
174            let mut current_written = 0;
175
176            let file = file_system::UniqueFileIdentifier::from_raw(file);
177
178            for (buffer, length) in buffers.iter().zip(buffers_length.iter()) {
179                let buffer_slice = core::slice::from_raw_parts(*buffer, *length);
180
181                current_written += usize::from(block_on(get_file_system_instance().write(
182                    file,
183                    buffer_slice,
184                    task_identifier,
185                ))?);
186            }
187
188            if !written.is_null() {
189                *written = current_written;
190            }
191
192            Ok(())
193        })
194    }
195}
196
197/// This function is used to perform a write operation on a file.
198///
199/// # Safety
200///
201/// This function is unsafe because it dereferences raw pointers.
202///
203/// # Errors
204///
205/// This function may return an error if the file system fails to open the file.
206#[unsafe(no_mangle)]
207pub unsafe extern "C" fn xila_file_system_read_vectored(
208    file: XilaUniqueFileIdentifier,
209    buffers: *mut *mut u8,
210    buffers_length: *mut usize,
211    buffer_count: usize,
212    read: *mut usize,
213) -> XilaFileSystemResult {
214    unsafe {
215        into_u32(move || {
216            let task_identifier = context::get_instance().get_current_task_identifier();
217
218            let buffers = core::slice::from_raw_parts_mut(buffers, buffer_count);
219            let buffers_length = core::slice::from_raw_parts_mut(buffers_length, buffer_count);
220
221            let mut current_read = 0;
222
223            let file = file_system::UniqueFileIdentifier::from_raw(file);
224
225            for (buffer_pointer, buffer_length) in buffers.iter_mut().zip(buffers_length.iter_mut())
226            {
227                let buffer = core::slice::from_raw_parts_mut(*buffer_pointer, *buffer_length);
228
229                let read =
230                    block_on(get_file_system_instance().read(file, buffer, task_identifier))?;
231
232                current_read += usize::from(read);
233            }
234
235            if !read.is_null() {
236                *read = current_read;
237            }
238
239            Ok(())
240        })
241    }
242}
243
244/// This function is used to perform a read operation on a file at a specific position.
245///
246/// # Safety
247///
248/// This function is unsafe because it dereferences raw pointers.
249#[unsafe(no_mangle)]
250pub unsafe extern "C" fn xila_file_system_read_at_position_vectored(
251    file: XilaUniqueFileIdentifier,
252    buffers: *mut *mut u8,
253    buffers_length: *mut usize,
254    buffer_count: usize,
255    position: u64,
256    read: *mut usize,
257) -> XilaFileSystemResult {
258    unsafe {
259        into_u32(move || {
260            let task_identifier = context::get_instance().get_current_task_identifier();
261
262            let buffers = core::slice::from_raw_parts_mut(buffers, buffer_count);
263            let buffers_length = core::slice::from_raw_parts_mut(buffers_length, buffer_count);
264
265            let mut current_read = 0;
266
267            let file: file_system::UniqueFileIdentifier =
268                file_system::UniqueFileIdentifier::from_raw(file);
269
270            block_on(get_file_system_instance().set_position(
271                file,
272                &file_system::Position::Start(position),
273                task_identifier,
274            ))?;
275
276            for (buffer_pointer, buffer_length) in buffers.iter_mut().zip(buffers_length.iter_mut())
277            {
278                let buffer = core::slice::from_raw_parts_mut(*buffer_pointer, *buffer_length);
279
280                let read =
281                    block_on(get_file_system_instance().read(file, buffer, task_identifier))?;
282
283                current_read += usize::from(read);
284            }
285
286            if !read.is_null() {
287                *read = current_read;
288            }
289
290            Ok(())
291        })
292    }
293}
294
295/// This function is used to perform a write operation on a file at a specific position.
296///
297/// # Safety
298///
299/// This function is unsafe because it dereferences raw pointers.
300#[unsafe(no_mangle)]
301pub unsafe extern "C" fn xila_file_system_write_at_position_vectored(
302    file: XilaUniqueFileIdentifier,
303    buffers: *const *const u8,
304    buffers_length: *const usize,
305    buffer_count: usize,
306    position: u64,
307    written: *mut usize,
308) -> XilaFileSystemResult {
309    unsafe {
310        into_u32(move || {
311            let task_identifier = context::get_instance().get_current_task_identifier();
312
313            let buffers = core::slice::from_raw_parts(buffers, buffer_count);
314            let buffers_length = core::slice::from_raw_parts(buffers_length, buffer_count);
315
316            let mut current_written = 0;
317
318            let file: file_system::UniqueFileIdentifier =
319                file_system::UniqueFileIdentifier::from_raw(file);
320
321            block_on(get_file_system_instance().set_position(
322                file,
323                &file_system::Position::Start(position),
324                task_identifier,
325            ))?;
326
327            for (buffer, length) in buffers.iter().zip(buffers_length.iter()) {
328                let buffer_slice = core::slice::from_raw_parts(*buffer, *length);
329
330                current_written += usize::from(block_on(get_file_system_instance().write(
331                    file,
332                    buffer_slice,
333                    task_identifier,
334                ))?);
335            }
336
337            if !written.is_null() {
338                *written = current_written;
339            }
340
341            Ok(())
342        })
343    }
344}
345
346/// This function is used to check if a file is a terminal.
347///
348/// # Safety
349///
350/// This function is unsafe because it dereferences raw pointers.
351///
352/// # Errors
353///
354/// This function may return an error if the file system fails to open the file.
355#[unsafe(no_mangle)]
356pub unsafe extern "C" fn xila_file_system_is_a_terminal(
357    file: XilaUniqueFileIdentifier,
358    is_a_terminal: *mut bool,
359) -> XilaFileSystemResult {
360    unsafe {
361        into_u32(move || {
362            let task_identifier = context::get_instance().get_current_task_identifier();
363
364            if is_a_terminal.is_null() {
365                Err(Error::InvalidParameter)?;
366            }
367
368            let file = file_system::UniqueFileIdentifier::from_raw(file);
369
370            *is_a_terminal =
371                block_on(get_file_system_instance().is_a_terminal(file, task_identifier))?;
372
373            Ok(())
374        })
375    }
376}
377
378#[unsafe(no_mangle)]
379pub extern "C" fn xila_file_system_is_stdin(file: XilaUniqueFileIdentifier) -> bool {
380    let file = file_system::UniqueFileIdentifier::from_raw(file);
381
382    let (_, file) = file.split();
383
384    // Debug: Checking if file is stdin
385
386    file == FileIdentifier::STANDARD_IN
387}
388
389#[unsafe(no_mangle)]
390pub extern "C" fn xila_file_system_is_stderr(file: XilaUniqueFileIdentifier) -> bool {
391    let file = file_system::UniqueFileIdentifier::from_raw(file);
392
393    let (_, file) = file.split();
394
395    // Debug: Checking if file is stderr
396
397    file == FileIdentifier::STANDARD_ERROR
398}
399
400#[unsafe(no_mangle)]
401pub extern "C" fn xila_file_system_is_stdout(file: XilaUniqueFileIdentifier) -> bool {
402    let file = file_system::UniqueFileIdentifier::from_raw(file);
403
404    let (_, file) = file.split();
405
406    // Debug: Checking if file is stdout
407
408    file == FileIdentifier::STANDARD_OUT
409}
410
411/// This function is used to open a file.
412///
413/// # Safety
414///
415/// This function is unsafe because it dereferences raw pointers.
416#[unsafe(no_mangle)]
417pub unsafe extern "C" fn xila_file_system_open(
418    path: *const c_char,
419    mode: XilaFileSystemMode,
420    open: XilaFileSystemOpen,
421    status: XilaFileSystemStatus,
422    file: *mut XilaUniqueFileIdentifier,
423) -> XilaFileSystemResult {
424    unsafe {
425        into_u32(move || {
426            let path = core::ffi::CStr::from_ptr(path)
427                .to_str()
428                .map_err(|_| Error::InvalidParameter)?;
429
430            let mode = Mode::from_u8(mode);
431            let open = Open::from_u8(open);
432            let status = Status::from_u8(status);
433
434            let flags = Flags::new(mode, Some(open), Some(status));
435
436            // Debug: Opening file
437
438            let task = context::get_instance().get_current_task_identifier();
439
440            *file = block_on(get_file_system_instance().open(&path, flags, task))
441                .expect("Failed to open file")
442                .into_inner();
443
444            Ok(())
445        })
446    }
447}
448
449#[unsafe(no_mangle)]
450pub extern "C" fn xila_file_system_set_flags(
451    _file: XilaUniqueFileIdentifier,
452    _status: XilaFileSystemStatus,
453) -> XilaFileSystemResult {
454    todo!()
455}
456
457/// This function is used to get the flags of a file.
458///
459/// # Safety
460///
461/// This function is unsafe because it dereferences raw pointers.
462#[unsafe(no_mangle)]
463pub unsafe extern "C" fn xila_file_system_get_flags(
464    _file: XilaUniqueFileIdentifier,
465    _status: *mut XilaFileSystemStatus,
466) -> XilaFileSystemResult {
467    todo!()
468}
469
470/// This function is used to convert a path to a resolved path (i.e. a path without symbolic links or relative paths).
471///
472/// # Safety
473///
474/// This function is unsafe because it dereferences raw pointers.
475#[unsafe(no_mangle)]
476pub unsafe extern "C" fn xila_file_system_resolve_path(
477    path: *const i8,
478    resolved_path: *mut u8,
479    resolved_path_size: usize,
480) -> XilaFileSystemResult {
481    unsafe {
482        into_u32(move || {
483            let path = core::ffi::CStr::from_ptr(path)
484                .to_str()
485                .map_err(|_| Error::InvalidParameter)?;
486
487            // Debug: Resolving path
488
489            // Copy path to resolved path.
490            copy_nonoverlapping(
491                path.as_ptr(),
492                resolved_path,
493                min(resolved_path_size, path.len()),
494            );
495
496            Ok(())
497        })
498    }
499}
500
501#[unsafe(no_mangle)]
502pub extern "C" fn xila_file_system_flush(
503    file: XilaUniqueFileIdentifier,
504    _: bool,
505) -> XilaFileSystemResult {
506    into_u32(move || {
507        let task = context::get_instance().get_current_task_identifier();
508
509        let file = file_system::UniqueFileIdentifier::from_raw(file);
510
511        block_on(get_file_system_instance().flush(file, task))?;
512
513        Ok(())
514    })
515}
516
517#[unsafe(no_mangle)]
518pub extern "C" fn xila_file_system_create_symbolic_link_at(
519    _: XilaUniqueFileIdentifier,
520    _: *const c_char,
521    _: *const c_char,
522) -> XilaFileSystemResult {
523    todo!()
524}
525
526#[unsafe(no_mangle)]
527pub extern "C" fn xila_file_system_read_link_at(
528    _directory: XilaUniqueFileIdentifier,
529    _path: *mut i8,
530    _size: usize,
531    _used: *mut usize,
532) -> XilaFileSystemResult {
533    todo!()
534}
535
536/// This function is used to set the position in a file.
537///
538/// # Safety
539///
540/// This function is unsafe because it dereferences raw pointers.
541#[unsafe(no_mangle)]
542pub unsafe extern "C" fn xila_file_system_set_position(
543    file: XilaUniqueFileIdentifier,
544    offset: i64,
545    whence: XilaFileSystemWhence,
546    position: *mut XilaFileSystemSize,
547) -> XilaFileSystemResult {
548    unsafe {
549        into_u32(move || {
550            let task = context::get_instance().get_current_task_identifier();
551            let current_position = into_position(whence, offset);
552
553            // Debug: Setting position
554
555            let file = file_system::UniqueFileIdentifier::from_raw(file);
556
557            *position =
558                block_on(get_file_system_instance().set_position(file, &current_position, task))?
559                    .as_u64();
560
561            Ok(())
562        })
563    }
564}
565
566/// This function is used to get the position in a file.
567///
568/// # Safety
569///
570/// This function is unsafe because it dereferences raw pointers.
571#[unsafe(no_mangle)]
572pub unsafe extern "C" fn xila_file_system_create_directory(
573    path: *const c_char,
574) -> XilaFileSystemResult {
575    unsafe {
576        into_u32(move || {
577            let path = CStr::from_ptr(path)
578                .to_str()
579                .map_err(|_| Error::InvalidParameter)?;
580
581            // Debug: Creating directory
582
583            let task = context::get_instance().get_current_task_identifier();
584            block_on(get_file_system_instance().create_directory(&path, task))?;
585
586            Ok(())
587        })
588    }
589}
590
591/// This function is used to rename (move) a file.
592///
593/// # Safety
594///
595/// This function is unsafe because it dereferences raw pointers.
596#[unsafe(no_mangle)]
597pub unsafe extern "C" fn xila_file_system_rename(
598    old_path: *const c_char,
599    new_path: *const c_char,
600) -> XilaFileSystemResult {
601    unsafe {
602        into_u32(move || {
603            let old_path = CStr::from_ptr(old_path)
604                .to_str()
605                .map_err(|_| Error::InvalidParameter)?;
606
607            let new_path = CStr::from_ptr(new_path)
608                .to_str()
609                .map_err(|_| Error::InvalidParameter)?;
610
611            // Debug: Renaming files
612
613            block_on(get_file_system_instance().rename(&old_path, &new_path))?;
614
615            Ok(())
616        })
617    }
618}
619
620#[unsafe(no_mangle)]
621pub extern "C" fn xila_file_system_set_times(
622    _: XilaUniqueFileIdentifier,
623    _: XilaTime,
624    _: XilaTime,
625    _: u8,
626) -> XilaFileSystemResult {
627    todo!()
628}
629
630/// This function is used to set access and modification times of a file.
631///
632/// # Safety
633///
634/// This function is unsafe because it dereferences raw pointers.
635#[unsafe(no_mangle)]
636pub unsafe extern "C" fn xila_file_system_set_times_from_path(
637    _path: *const c_char,
638    _access: XilaTime,
639    _modification: XilaTime,
640    _flags: u8,
641    _follow: bool,
642) -> XilaFileSystemResult {
643    todo!()
644}
645
646/// This function is used to remove a file.
647///
648/// # Safety
649///
650/// This function is unsafe because it dereferences raw pointers.
651#[unsafe(no_mangle)]
652pub unsafe extern "C" fn xila_file_system_remove(_path: *const c_char) -> XilaFileSystemResult {
653    unsafe {
654        into_u32(|| {
655            let path = CStr::from_ptr(_path)
656                .to_str()
657                .map_err(|_| Error::InvalidParameter)?;
658
659            block_on(get_file_system_instance().remove(path))?;
660
661            Ok(())
662        })
663    }
664}
665
666/// This function is used to truncate a file.
667#[unsafe(no_mangle)]
668pub extern "C" fn xila_file_system_truncate(
669    _file: XilaUniqueFileIdentifier,
670    _length: XilaFileSystemSize,
671) -> XilaFileSystemResult {
672    into_u32(move || {
673        let _task = context::get_instance().get_current_task_identifier();
674
675        let _file = file_system::UniqueFileIdentifier::from_raw(_file);
676
677        todo!();
678    })
679}
680
681/// This function is used to create a symbolic link.
682///
683/// # Safety
684///
685/// This function is unsafe because it dereferences raw pointers.
686#[unsafe(no_mangle)]
687pub unsafe extern "C" fn xila_file_system_link(
688    _path: *const c_char,
689    _link: *const c_char,
690) -> XilaFileSystemResult {
691    todo!()
692}
693
694/// This function is used to advice the file system about the access pattern of a file.
695#[unsafe(no_mangle)]
696pub extern "C" fn xila_file_system_advise(
697    _file: XilaUniqueFileIdentifier,
698    _offset: XilaFileSystemSize,
699    _length: XilaFileSystemSize,
700    _advice: u8,
701) -> XilaFileSystemResult {
702    todo!()
703}
704
705#[unsafe(no_mangle)]
706pub extern "C" fn xila_file_system_allocate(
707    _file: XilaUniqueFileIdentifier,
708    _offset: XilaFileSystemSize,
709    _length: XilaFileSystemSize,
710) -> XilaFileSystemResult {
711    todo!()
712}