@@ -17,11 +17,18 @@ pub struct File {
1717#[ derive( Clone ) ]
1818pub struct FileAttr {
1919 size : u64 ,
20+ is_dir : bool ,
2021}
2122
22- pub struct ReadDir ( !) ;
23+ #[ derive( Debug ) ]
24+ pub struct ReadDir {
25+ entries : Vec < DirEntry > ,
26+ }
2327
24- pub struct DirEntry ( !) ;
28+ #[ derive( Debug ) ]
29+ pub struct DirEntry {
30+ path : PathBuf ,
31+ }
2532
2633#[ derive( Clone , Debug ) ]
2734pub struct OpenOptions {
@@ -52,9 +59,31 @@ impl FileAttr {
5259 let size = unsafe { vex_sdk:: vexFileSize ( fd) } ;
5360
5461 if size >= 0 {
55- Ok ( Self { size : size as u64 } )
62+ Ok ( Self { size : size as u64 , is_dir : false } )
63+ } else {
64+ Err ( io:: Error :: new ( io:: ErrorKind :: InvalidData , "Failed to get file size" ) )
65+ }
66+ }
67+
68+ fn from_path ( path : & Path ) -> io:: Result < Self > {
69+ let c_path = CString :: new ( path. as_os_str ( ) . as_encoded_bytes ( ) ) . map_err ( |_| {
70+ io:: Error :: new ( io:: ErrorKind :: InvalidData , "Path contained a null byte" )
71+ } ) ?;
72+
73+ let file_type = unsafe { vex_sdk:: vexFileStatus ( c_path. as_ptr ( ) ) } ;
74+ let is_dir = file_type == 3 ;
75+ println ! ( "{is_dir}" ) ;
76+
77+ // We can't get the size if its a directory because we cant open it as a file
78+ if is_dir {
79+ Ok ( Self { size : 0 , is_dir : true } )
5680 } else {
57- Err ( io:: Error :: new ( io:: ErrorKind :: NotSeekable , "Failed to seek file" ) )
81+ let mut opts = OpenOptions :: new ( ) ;
82+ opts. read ( true ) ;
83+ let file = File :: open ( path, & opts) ?;
84+ let fd = file. fd . 0 ;
85+
86+ Self :: from_fd ( fd)
5887 }
5988 }
6089
@@ -67,7 +96,7 @@ impl FileAttr {
6796 }
6897
6998 pub fn file_type ( & self ) -> FileType {
70- FileType { is_dir : false }
99+ FileType { is_dir : self . is_dir }
71100 }
72101
73102 pub fn modified ( & self ) -> io:: Result < SystemTime > {
@@ -112,35 +141,32 @@ impl FileType {
112141 }
113142}
114143
115- impl fmt:: Debug for ReadDir {
116- fn fmt ( & self , _f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
117- self . 0
118- }
119- }
120-
121144impl Iterator for ReadDir {
122145 type Item = io:: Result < DirEntry > ;
123146
124147 fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
125- self . 0
148+ self . entries . pop ( ) . map ( Ok )
126149 }
127150}
128151
129152impl DirEntry {
130153 pub fn path ( & self ) -> PathBuf {
131- self . 0
154+ self . path . clone ( )
132155 }
133156
134157 pub fn file_name ( & self ) -> OsString {
135- self . 0
158+ self . path
159+ . file_name ( )
160+ . unwrap_or ( crate :: ffi:: OsStr :: new ( "" ) )
161+ . to_os_string ( )
136162 }
137163
138164 pub fn metadata ( & self ) -> io:: Result < FileAttr > {
139- self . 0
165+ stat ( & self . path )
140166 }
141167
142168 pub fn file_type ( & self ) -> io:: Result < FileType > {
143- self . 0
169+ Ok ( self . metadata ( ) ? . file_type ( ) )
144170 }
145171}
146172
@@ -406,8 +432,43 @@ impl Drop for File {
406432 }
407433}
408434
409- pub fn readdir ( _p : & Path ) -> io:: Result < ReadDir > {
410- todo ! ( )
435+ pub fn readdir ( p : & Path ) -> io:: Result < ReadDir > {
436+ if !stat ( p) ?. file_type ( ) . is_dir ( ) {
437+ return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "Given directory was not a path" ) ) ;
438+ }
439+
440+ // getting directory entries does not work with trailing slashes
441+ let path = p
442+ . to_str ( )
443+ . ok_or ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "Path contained invalid characters" ) ) ?
444+ . trim_end_matches ( "/" ) ;
445+ let path = CString :: new ( path. as_bytes ( ) )
446+ . map_err ( |_| io:: Error :: new ( io:: ErrorKind :: InvalidInput , "Path contained a null byte" ) ) ?;
447+
448+ //TODO: Figure out if there is any way to check the number of entries in a directory/the needed length
449+ let mut filenames_buffer = [ 0u8 ; 1000 ] ;
450+ unsafe {
451+ vex_sdk:: vexFileDirectoryGet (
452+ path. as_ptr ( ) ,
453+ filenames_buffer. as_mut_ptr ( ) . cast ( ) ,
454+ filenames_buffer. len ( ) as _ ,
455+ ) ;
456+ }
457+ let filenames_buffer = filenames_buffer. to_vec ( ) ;
458+ // stop at null-terminator
459+ let filenames = match filenames_buffer. split ( |& e| e == 0 ) . next ( ) {
460+ Some ( filenames) => filenames,
461+ None => & filenames_buffer
462+ } ;
463+ let filenames = String :: from_utf8 ( filenames. to_vec ( ) ) . map_err ( |_| io:: Error :: new ( io:: ErrorKind :: InvalidData , "Path contained a null byte" ) ) ?;
464+ let paths = filenames. split ( '\n' ) . map ( |filename| {
465+ let mut path = PathBuf :: new ( ) ;
466+ path. push ( p) ;
467+ path. push ( filename) ;
468+ DirEntry { path }
469+ } ) . collect :: < Vec < _ > > ( ) ;
470+
471+ Ok ( ReadDir { entries : paths } )
411472}
412473
413474pub fn unlink ( _p : & Path ) -> io:: Result < ( ) > {
@@ -451,12 +512,7 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
451512}
452513
453514pub fn stat ( p : & Path ) -> io:: Result < FileAttr > {
454- let mut opts = OpenOptions :: new ( ) ;
455- opts. read ( true ) ;
456- let file = File :: open ( p, & opts) ?;
457- let fd = file. fd . 0 ;
458-
459- FileAttr :: from_fd ( fd)
515+ FileAttr :: from_path ( p)
460516}
461517
462518pub fn lstat ( p : & Path ) -> io:: Result < FileAttr > {
0 commit comments