1use alloc::ffi::CString;
2use log::Debug;
3
4use core::{
5 ffi::{CStr, c_char},
6 ptr::null_mut,
7};
8
9use file_system::Error;
10use futures::block_on;
11use virtual_file_system::get_instance as get_file_system_instance;
12
13use crate::context::get_instance as get_context_instance;
14
15use super::{
16 XilaFileKind, XilaFileSystemInode, XilaFileSystemSize, XilaUniqueFileIdentifier, into_u32,
17};
18
19#[unsafe(no_mangle)]
25pub unsafe extern "C" fn xila_file_system_open_directory(
26 path: *const c_char,
27 directory: *mut XilaUniqueFileIdentifier,
28) -> u32 {
29 unsafe {
30 into_u32(move || {
31 if path.is_null() || directory.is_null() {
32 Err(Error::InvalidParameter)?;
33 }
34
35 let path = CStr::from_ptr(path)
36 .to_str()
37 .map_err(|_| Error::InvalidParameter)?;
38
39 let task = get_context_instance().get_current_task_identifier();
40
41 Debug!("Opening directory {path:?} for task {task:?}");
42
43 *directory =
44 block_on(get_file_system_instance().open_directory(&path, task))?.into_inner();
45
46 Ok(())
47 })
48 }
49}
50
51#[unsafe(no_mangle)]
57pub unsafe extern "C" fn xila_file_system_read_directory(
58 file: XilaUniqueFileIdentifier,
59 entry_name: *mut *const c_char,
60 entry_type: *mut XilaFileKind,
61 entry_size: *mut XilaFileSystemSize,
62 entry_inode: *mut XilaFileSystemInode,
63) -> u32 {
64 unsafe {
65 into_u32(move || {
66 let task = get_context_instance().get_current_task_identifier();
67
68 Debug!("Reading directory {file:?} for task {task:?}");
69
70 let file = file_system::UniqueFileIdentifier::from_raw(file);
71
72 let entry = block_on(get_file_system_instance().read_directory(file, task))?;
73
74 if let Some(entry) = entry {
75 *entry_name = CString::new(entry.get_name().as_str()).unwrap().into_raw();
76 *entry_type = entry.get_type().into();
77 *entry_size = entry.get_size().as_u64();
78 *entry_inode = entry.get_inode().into();
79 } else {
80 *entry_name = null_mut();
81 }
82
83 Ok(())
84 })
85 }
86}
87
88#[unsafe(no_mangle)]
89pub extern "C" fn xila_file_system_close_directory(directory: XilaUniqueFileIdentifier) -> u32 {
90 into_u32(move || {
91 let task = get_context_instance().get_current_task_identifier();
92
93 let directory = file_system::UniqueFileIdentifier::from_raw(directory);
94
95 Debug!("Closing directory {directory:?} for task {task:?}");
96
97 block_on(get_file_system_instance().close_directory(directory, task))?;
98
99 Ok(())
100 })
101}
102
103#[unsafe(no_mangle)]
104pub extern "C" fn xila_file_system_rewind_directory(directory: XilaUniqueFileIdentifier) -> u32 {
105 into_u32(move || {
106 let task = get_context_instance().get_current_task_identifier();
107
108 let directory = file_system::UniqueFileIdentifier::from_raw(directory);
109
110 Debug!("Rewinding directory {directory:?} for task {task:?}");
111
112 block_on(get_file_system_instance().rewind_directory(directory, task))?;
113
114 Ok(())
115 })
116}
117
118#[unsafe(no_mangle)]
119pub extern "C" fn xila_file_system_directory_set_position(
120 directory: XilaUniqueFileIdentifier,
121 offset: XilaFileSystemSize,
122) -> u32 {
123 into_u32(move || {
124 let task = get_context_instance().get_current_task_identifier();
125
126 let directory = file_system::UniqueFileIdentifier::from_raw(directory);
127
128 Debug!("Setting position in directory {directory:?} to offset {offset} for task {task:?}");
129
130 block_on(get_file_system_instance().set_position_directory(
131 directory,
132 offset.into(),
133 task,
134 ))?;
135
136 Ok(())
137 })
138}
139
140#[cfg(test)]
141mod tests {
142 extern crate std;
143
144 use super::*;
145 use crate::context::get_instance as get_context_instance;
146 use alloc::{ffi::CString, format, vec::Vec};
147 use file_system::{MemoryDevice, Mode, Open, PathOwned, create_device, create_file_system};
148 use task::{TaskIdentifier, test};
149 use virtual_file_system::VirtualFileSystem;
150
151 async fn initialize_test_environment() -> (TaskIdentifier, &'static VirtualFileSystem<'static>)
152 {
153 let _ = users::initialize();
154
155 let _ = time::initialize(create_device!(drivers::native::TimeDriver::new()));
156
157 let task = task::get_instance().get_current_task_identifier().await;
158
159 let device = create_device!(MemoryDevice::<512>::new(1024 * 512));
160
161 let cache_size = 256;
162
163 little_fs::FileSystem::format(device.clone(), cache_size).unwrap();
164 let file_system = little_fs::FileSystem::new(device, cache_size).unwrap();
165
166 let virtual_file_system =
167 virtual_file_system::initialize(create_file_system!(file_system), None).unwrap();
168
169 (task, virtual_file_system)
170 }
171
172 #[test]
173 async fn test_null_pointer_handling() {
174 let (_task, _vfs) = initialize_test_environment().await;
176
177 let context = get_context_instance();
178
179 let mut directory_id: XilaUniqueFileIdentifier = 0;
181 let result = context
182 .call_abi(async || unsafe {
183 xila_file_system_open_directory(core::ptr::null(), &mut directory_id)
184 })
185 .await;
186 assert_ne!(result, 0, "Opening directory with null path should fail");
187
188 let invalid_handle: XilaUniqueFileIdentifier = 999999;
190 let result = context
191 .call_abi(async || unsafe {
192 xila_file_system_read_directory(
193 invalid_handle,
194 core::ptr::null_mut(),
195 core::ptr::null_mut(),
196 core::ptr::null_mut(),
197 core::ptr::null_mut(),
198 )
199 })
200 .await;
201 assert_ne!(
202 result, 0,
203 "Reading directory with null pointers should fail"
204 );
205 }
206
207 #[test]
208 async fn test_invalid_handle_operations() {
209 initialize_test_environment().await; let invalid_handle: XilaUniqueFileIdentifier = 999999;
212 let context = get_context_instance();
213
214 let result = context
216 .call_abi(|| async { xila_file_system_close_directory(invalid_handle) })
217 .await;
218 assert_ne!(result, 0, "Closing invalid directory handle should fail");
219
220 let result = context
222 .call_abi(|| async { xila_file_system_rewind_directory(invalid_handle) })
223 .await;
224 assert_ne!(result, 0, "Rewinding invalid directory handle should fail");
225
226 let result = context
228 .call_abi(|| async { xila_file_system_directory_set_position(invalid_handle, 0) })
229 .await;
230 assert_ne!(
231 result, 0,
232 "Setting position on invalid directory handle should fail"
233 );
234 }
235
236 #[test]
237 async fn test_read_directory_parameter_validation() {
238 initialize_test_environment().await; let invalid_handle: XilaUniqueFileIdentifier = 0;
242 let mut entry_name: *const c_char = core::ptr::null();
243 let mut entry_type: XilaFileKind = XilaFileKind::File;
244 let mut entry_size: XilaFileSystemSize = 0;
245 let mut entry_inode: XilaFileSystemInode = 0;
246 let context = get_context_instance();
247
248 let result = context
250 .call_abi(async || unsafe {
251 xila_file_system_read_directory(
252 invalid_handle,
253 &mut entry_name,
254 &mut entry_type,
255 &mut entry_size,
256 &mut entry_inode,
257 )
258 })
259 .await;
260 assert_ne!(result, 0, "Reading from invalid handle should fail");
261 }
262
263 #[test]
264 async fn test_set_position_boundary_values() {
265 initialize_test_environment().await; let invalid_handle: XilaUniqueFileIdentifier = 999999;
268 let context = get_context_instance();
269
270 let result = context
272 .call_abi(|| async {
273 xila_file_system_directory_set_position(invalid_handle, u64::MAX)
274 })
275 .await;
276 assert_ne!(
277 result, 0,
278 "Setting position with max value on invalid handle should fail"
279 );
280
281 let result = context
283 .call_abi(|| async { xila_file_system_directory_set_position(invalid_handle, 0) })
284 .await;
285 assert_ne!(
286 result, 0,
287 "Setting position with zero on invalid handle should fail"
288 );
289 }
290
291 #[test]
292 async fn test_open_directory_valid_path() {
293 let (_task, _vfs) = initialize_test_environment().await;
294 let context = get_context_instance();
295
296 let path = CString::new("/").unwrap();
297 let mut directory_id: XilaUniqueFileIdentifier = 0;
298
299 let result = context
300 .call_abi(async || unsafe {
301 xila_file_system_open_directory(path.as_ptr(), &mut directory_id)
302 })
303 .await;
304 assert_eq!(result, 0, "Opening root directory should succeed");
305 assert_ne!(directory_id, 0, "Directory identifier should be non-zero");
306
307 let close_result = context
309 .call_abi(|| async { xila_file_system_close_directory(directory_id) })
310 .await;
311 assert_eq!(close_result, 0, "Closing directory should succeed");
312 }
313
314 #[test]
315 async fn test_open_directory_invalid_path() {
316 let (_task, _vfs) = initialize_test_environment().await;
317 let context = get_context_instance();
318
319 let path = CString::new("/nonexistent").unwrap();
320 let mut directory_id: XilaUniqueFileIdentifier = 0;
321
322 let result = context
323 .call_abi(async || unsafe {
324 xila_file_system_open_directory(path.as_ptr(), &mut directory_id)
325 })
326 .await;
327
328 assert_ne!(result, 0, "Opening nonexistent directory should fail");
329 }
330
331 #[test]
332 async fn test_open_directory_null_path() {
333 let (_task, _vfs) = initialize_test_environment().await;
334 let context = get_context_instance();
335
336 let mut directory_id: XilaUniqueFileIdentifier = 0;
337
338 let result = context
339 .call_abi(async || unsafe {
340 xila_file_system_open_directory(core::ptr::null(), &mut directory_id)
341 })
342 .await;
343
344 assert_ne!(result, 0, "Opening directory with null path should fail");
345 }
346
347 #[test]
348 async fn test_read_directory_entries() {
349 let (_task, vfs) = initialize_test_environment().await;
350 let task = _task;
351 let context = get_context_instance();
352
353 vfs.create_directory(&"/test_read_directory_entries", task)
355 .await
356 .unwrap();
357
358 let test_file = vfs
359 .open(
360 &"/test_read_directory_entries.txt",
361 file_system::Flags::new(Mode::WRITE_ONLY, Some(Open::CREATE_ONLY), None),
362 task,
363 )
364 .await
365 .unwrap();
366 vfs.close(test_file, task).await.unwrap();
367
368 let path = CString::new("/").unwrap();
370 let mut directory_id: XilaUniqueFileIdentifier = 0;
371
372 let open_result = context
373 .call_abi(async || unsafe {
374 xila_file_system_open_directory(path.as_ptr(), &mut directory_id)
375 })
376 .await;
377 assert_eq!(open_result, 0, "Opening root directory should succeed");
378
379 let mut entries_found = Vec::new();
382
383 loop {
385 let mut entry_name: *const c_char = core::ptr::null();
386 let mut entry_type: XilaFileKind = XilaFileKind::File;
387 let mut entry_size: XilaFileSystemSize = 0;
388 let mut entry_inode: XilaFileSystemInode = 0;
389
390 let read_result = context
391 .call_abi(async || unsafe {
392 xila_file_system_read_directory(
393 directory_id,
394 &mut entry_name,
395 &mut entry_type,
396 &mut entry_size,
397 &mut entry_inode,
398 )
399 })
400 .await;
401
402 assert_eq!(read_result, 0, "Reading directory entry should succeed");
403
404 if entry_name.is_null() {
405 break; }
407
408 let name = unsafe { CStr::from_ptr(entry_name).to_string_lossy().into_owned() };
409 entries_found.push((name, entry_type));
410
411 unsafe {
413 let _ = CString::from_raw(entry_name as *mut c_char);
414 }
415 }
416
417 assert!(
419 entries_found.len() >= 2,
420 "Should find at least current and parent directories"
421 );
422
423 let has_current = entries_found.iter().any(|(name, _)| name == ".");
425 let has_parent = entries_found.iter().any(|(name, _)| name == "..");
426
427 assert!(has_current, "Should find current directory entry");
428 assert!(has_parent, "Should find parent directory entry");
429
430 let close_result = context
432 .call_abi(|| async { xila_file_system_close_directory(directory_id) })
433 .await;
434 assert_eq!(close_result, 0, "Closing directory should succeed");
435 }
436
437 #[test]
438 async fn test_read_directory_invalid_handle() {
439 let (_task, _vfs) = initialize_test_environment().await;
440 let context = get_context_instance();
441
442 let invalid_directory_id: XilaUniqueFileIdentifier = 999999;
443 let mut entry_name: *const c_char = core::ptr::null();
444 let mut entry_type: XilaFileKind = XilaFileKind::File;
445 let mut entry_size: XilaFileSystemSize = 0;
446 let mut entry_inode: XilaFileSystemInode = 0;
447
448 let result = context
449 .call_abi(async || unsafe {
450 xila_file_system_read_directory(
451 invalid_directory_id,
452 &mut entry_name,
453 &mut entry_type,
454 &mut entry_size,
455 &mut entry_inode,
456 )
457 })
458 .await;
459
460 assert_ne!(
461 result, 0,
462 "Reading from invalid directory handle should fail"
463 );
464 }
465
466 #[test]
467 async fn test_close_directory_valid_handle() {
468 let (_task, _vfs) = initialize_test_environment().await;
469 let context = get_context_instance();
470
471 let path = CString::new("/").unwrap();
472 let mut directory_id: XilaUniqueFileIdentifier = 0;
473
474 let open_result = context
476 .call_abi(async || unsafe {
477 xila_file_system_open_directory(path.as_ptr(), &mut directory_id)
478 })
479 .await;
480 assert_eq!(open_result, 0, "Opening directory should succeed");
481
482 let close_result = context
484 .call_abi(|| async { xila_file_system_close_directory(directory_id) })
485 .await;
486 assert_eq!(close_result, 0, "Closing directory should succeed");
487 }
488
489 #[test]
490 async fn test_close_directory_invalid_handle() {
491 let (_task, _vfs) = initialize_test_environment().await;
492 let context = get_context_instance();
493
494 let invalid_directory_id: XilaUniqueFileIdentifier = 999999;
495
496 let result = context
497 .call_abi(|| async { xila_file_system_close_directory(invalid_directory_id) })
498 .await;
499 assert_ne!(result, 0, "Closing invalid directory handle should fail");
500 }
501
502 #[test]
503 async fn test_rewind_directory() {
504 let (_task, vfs) = initialize_test_environment().await;
505 let task = _task;
506 let context = get_context_instance();
507
508 for i in 0..3 {
510 let path = format!("/test_rewind_directory_{i}.txt");
511
512 let test_file = vfs
513 .open(
514 &PathOwned::new(path).unwrap(),
515 file_system::Flags::new(Mode::WRITE_ONLY, Some(Open::CREATE_ONLY), None),
516 task,
517 )
518 .await
519 .unwrap();
520 vfs.close(test_file, task).await.unwrap();
521 }
522
523 let path = CString::new("/").unwrap();
525 let mut directory_id: XilaUniqueFileIdentifier = 0;
526
527 let open_result = context
528 .call_abi(async || unsafe {
529 xila_file_system_open_directory(path.as_ptr(), &mut directory_id)
530 })
531 .await;
532 assert_eq!(open_result, 0, "Opening directory should succeed");
533
534 for _ in 0..2 {
536 let mut entry_name: *const c_char = core::ptr::null();
537 let mut entry_type: XilaFileKind = XilaFileKind::File;
538 let mut entry_size: XilaFileSystemSize = 0;
539 let mut entry_inode: XilaFileSystemInode = 0;
540
541 let read_result = context
542 .call_abi(async || unsafe {
543 xila_file_system_read_directory(
544 directory_id,
545 &mut entry_name,
546 &mut entry_type,
547 &mut entry_size,
548 &mut entry_inode,
549 )
550 })
551 .await;
552 assert_eq!(read_result, 0, "Reading directory should succeed");
553
554 if !entry_name.is_null() {
555 unsafe {
556 let _ = CString::from_raw(entry_name as *mut c_char);
557 }
558 }
559 }
560
561 let rewind_result = context
563 .call_abi(|| async { xila_file_system_rewind_directory(directory_id) })
564 .await;
565 assert_eq!(rewind_result, 0, "Rewinding directory should succeed");
566
567 let mut entry_name: *const c_char = core::ptr::null();
569 let mut entry_type: XilaFileKind = XilaFileKind::File;
570 let mut entry_size: XilaFileSystemSize = 0;
571 let mut entry_inode: XilaFileSystemInode = 0;
572
573 let read_result = context
574 .call_abi(async || unsafe {
575 xila_file_system_read_directory(
576 directory_id,
577 &mut entry_name,
578 &mut entry_type,
579 &mut entry_size,
580 &mut entry_inode,
581 )
582 })
583 .await;
584 assert_eq!(
585 read_result, 0,
586 "Reading directory after rewind should succeed"
587 );
588 assert!(!entry_name.is_null(), "Entry name should not be null");
589
590 let name = unsafe { CStr::from_ptr(entry_name).to_string_lossy() };
591 assert_eq!(
592 name, ".",
593 "First entry after rewind should be current directory"
594 );
595
596 unsafe {
597 let _ = CString::from_raw(entry_name as *mut c_char);
598 }
599
600 let close_result = context
602 .call_abi(|| async { xila_file_system_close_directory(directory_id) })
603 .await;
604 assert_eq!(close_result, 0, "Closing directory should succeed");
605 }
606
607 #[test]
608 async fn test_rewind_directory_invalid_handle() {
609 let (_task, _vfs) = initialize_test_environment().await;
610 let context = get_context_instance();
611
612 let invalid_directory_id: XilaUniqueFileIdentifier = 999999;
613
614 let result = context
615 .call_abi(|| async { xila_file_system_rewind_directory(invalid_directory_id) })
616 .await;
617 assert_ne!(result, 0, "Rewinding invalid directory handle should fail");
618 }
619
620 #[test]
621 async fn test_directory_set_position() {
622 let (_task, vfs) = initialize_test_environment().await;
623 let task = _task;
624 let context = get_context_instance();
625
626 for i in 0..5 {
628 let path = format!("/test_file_{i}.txt");
629
630 let test_file = vfs
631 .open(
632 &PathOwned::new(path).unwrap(),
633 file_system::Flags::new(Mode::WRITE_ONLY, Some(Open::CREATE_ONLY), None),
634 task,
635 )
636 .await
637 .unwrap();
638 vfs.close(test_file, task).await.unwrap();
639 }
640
641 let path = CString::new("/").unwrap();
643 let mut directory_id: XilaUniqueFileIdentifier = 0;
644
645 let open_result = context
646 .call_abi(async || unsafe {
647 xila_file_system_open_directory(path.as_ptr(), &mut directory_id)
648 })
649 .await;
650 assert_eq!(open_result, 0, "Opening directory should succeed");
651
652 for _ in 0..3 {
654 let mut entry_name: *const c_char = core::ptr::null();
655 let mut entry_type: XilaFileKind = XilaFileKind::File;
656 let mut entry_size: XilaFileSystemSize = 0;
657 let mut entry_inode: XilaFileSystemInode = 0;
658
659 let read_result = context
660 .call_abi(async || unsafe {
661 xila_file_system_read_directory(
662 directory_id,
663 &mut entry_name,
664 &mut entry_type,
665 &mut entry_size,
666 &mut entry_inode,
667 )
668 })
669 .await;
670 assert_eq!(read_result, 0, "Reading directory should succeed");
671
672 if !entry_name.is_null() {
673 unsafe {
674 let _ = CString::from_raw(entry_name as *mut c_char);
675 }
676 }
677 }
678
679 let set_position_result = context
681 .call_abi(|| async { xila_file_system_directory_set_position(directory_id, 0) })
682 .await;
683 assert_eq!(
684 set_position_result, 0,
685 "Setting directory position should succeed"
686 );
687
688 let mut entry_name: *const c_char = core::ptr::null();
690 let mut entry_type: XilaFileKind = XilaFileKind::File;
691 let mut entry_size: XilaFileSystemSize = 0;
692 let mut entry_inode: XilaFileSystemInode = 0;
693
694 let read_result = context
695 .call_abi(async || unsafe {
696 xila_file_system_read_directory(
697 directory_id,
698 &mut entry_name,
699 &mut entry_type,
700 &mut entry_size,
701 &mut entry_inode,
702 )
703 })
704 .await;
705 assert_eq!(
706 read_result, 0,
707 "Reading directory after position reset should succeed"
708 );
709 assert!(!entry_name.is_null(), "Entry name should not be null");
710
711 let name = unsafe { CStr::from_ptr(entry_name).to_string_lossy() };
712 assert_eq!(
713 name, ".",
714 "First entry after position reset should be current directory"
715 );
716
717 unsafe {
718 let _ = CString::from_raw(entry_name as *mut c_char);
719 }
720
721 let close_result = context
723 .call_abi(|| async { xila_file_system_close_directory(directory_id) })
724 .await;
725 assert_eq!(close_result, 0, "Closing directory should succeed");
726 }
727
728 #[test]
729 async fn test_directory_set_position_invalid_handle() {
730 let (_task, _vfs) = initialize_test_environment().await;
731 let context = get_context_instance();
732
733 let invalid_directory_id: XilaUniqueFileIdentifier = 999999;
734
735 let result = context
736 .call_abi(|| async { xila_file_system_directory_set_position(invalid_directory_id, 0) })
737 .await;
738 assert_ne!(
739 result, 0,
740 "Setting position on invalid directory handle should fail"
741 );
742 }
743
744 #[test]
745 async fn test_directory_operations_sequence() {
746 let (_task, vfs) = initialize_test_environment().await;
747 let task = _task;
748 let context = get_context_instance();
749
750 vfs.create_directory(&"/test_dir", task).await.unwrap();
752 vfs.create_directory(&"/test_dir/subdir", task)
753 .await
754 .unwrap();
755
756 let test_file = vfs
757 .open(
758 &"/test_dir/file.txt",
759 file_system::Flags::new(Mode::WRITE_ONLY, Some(Open::CREATE_ONLY), None),
760 task,
761 )
762 .await
763 .unwrap();
764 vfs.close(test_file, task).await.unwrap();
765
766 let path = CString::new("/test_dir").unwrap();
768 let mut directory_id: XilaUniqueFileIdentifier = 0;
769
770 let open_result = context
771 .call_abi(async || unsafe {
772 xila_file_system_open_directory(path.as_ptr(), &mut directory_id)
773 })
774 .await;
775 assert_eq!(open_result, 0, "Opening test directory should succeed");
776
777 let mut entry_count = 0;
779 loop {
780 let mut entry_name: *const c_char = core::ptr::null();
781 let mut entry_type: XilaFileKind = XilaFileKind::File;
782 let mut entry_size: XilaFileSystemSize = 0;
783 let mut entry_inode: XilaFileSystemInode = 0;
784
785 let read_result = context
786 .call_abi(async || unsafe {
787 xila_file_system_read_directory(
788 directory_id,
789 &mut entry_name,
790 &mut entry_type,
791 &mut entry_size,
792 &mut entry_inode,
793 )
794 })
795 .await;
796 assert_eq!(read_result, 0, "Reading directory should succeed");
797
798 if entry_name.is_null() {
799 break;
800 }
801
802 entry_count += 1;
803 unsafe {
804 let _ = CString::from_raw(entry_name as *mut c_char);
805 }
806 }
807
808 assert!(
810 entry_count >= 4,
811 "Should find at least 4 entries in test directory"
812 );
813
814 let rewind_result = context
816 .call_abi(|| async { xila_file_system_rewind_directory(directory_id) })
817 .await;
818 assert_eq!(rewind_result, 0, "Rewinding directory should succeed");
819
820 let mut rewind_count = 0;
821 loop {
822 let mut entry_name: *const c_char = core::ptr::null();
823 let mut entry_type: XilaFileKind = XilaFileKind::File;
824 let mut entry_size: XilaFileSystemSize = 0;
825 let mut entry_inode: XilaFileSystemInode = 0;
826
827 let read_result = context
828 .call_abi(async || unsafe {
829 xila_file_system_read_directory(
830 directory_id,
831 &mut entry_name,
832 &mut entry_type,
833 &mut entry_size,
834 &mut entry_inode,
835 )
836 })
837 .await;
838 assert_eq!(
839 read_result, 0,
840 "Reading directory after rewind should succeed"
841 );
842
843 if entry_name.is_null() {
844 break;
845 }
846
847 rewind_count += 1;
848 unsafe {
849 let _ = CString::from_raw(entry_name as *mut c_char);
850 }
851 }
852
853 assert_eq!(
854 entry_count, rewind_count,
855 "Entry count should be same after rewind"
856 );
857
858 let close_result = context
860 .call_abi(|| async { xila_file_system_close_directory(directory_id) })
861 .await;
862 assert_eq!(close_result, 0, "Closing directory should succeed");
863 }
864
865 #[test]
866 async fn test_directory_operations_error_handling() {
867 initialize_test_environment().await;
868
869 let context = get_context_instance();
870
871 let mut directory_id: XilaUniqueFileIdentifier = 0;
873
874 let result = context
876 .call_abi(async || unsafe {
877 xila_file_system_open_directory(core::ptr::null(), &mut directory_id)
878 })
879 .await;
880 assert_ne!(result, 0, "Null path should cause error");
881
882 let invalid_handle = 0usize;
884
885 let close_result = context
886 .call_abi(|| async { xila_file_system_close_directory(invalid_handle) })
887 .await;
888 assert_ne!(close_result, 0, "Invalid close should fail");
889
890 let rewind_result = context
891 .call_abi(|| async { xila_file_system_rewind_directory(invalid_handle) })
892 .await;
893 assert_ne!(rewind_result, 0, "Invalid rewind should fail");
894
895 let set_pos_result = context
896 .call_abi(|| async { xila_file_system_directory_set_position(invalid_handle, 0) })
897 .await;
898 assert_ne!(set_pos_result, 0, "Invalid set position should fail");
899
900 let mut entry_name: *const c_char = core::ptr::null();
901 let mut entry_type: XilaFileKind = XilaFileKind::File;
902 let mut entry_size: XilaFileSystemSize = 0;
903 let mut entry_inode: XilaFileSystemInode = 0;
904
905 let read_result = context
906 .call_abi(async || unsafe {
907 xila_file_system_read_directory(
908 invalid_handle,
909 &mut entry_name,
910 &mut entry_type,
911 &mut entry_size,
912 &mut entry_inode,
913 )
914 })
915 .await;
916 assert_ne!(read_result, 0, "Invalid read should fail");
917 }
918}