@@ -17,11 +17,18 @@ pub struct File {
17
17
#[ derive( Clone ) ]
18
18
pub struct FileAttr {
19
19
size : u64 ,
20
+ is_dir : bool ,
20
21
}
21
22
22
- pub struct ReadDir ( !) ;
23
+ #[ derive( Debug ) ]
24
+ pub struct ReadDir {
25
+ entries : Vec < DirEntry > ,
26
+ }
23
27
24
- pub struct DirEntry ( !) ;
28
+ #[ derive( Debug ) ]
29
+ pub struct DirEntry {
30
+ path : PathBuf ,
31
+ }
25
32
26
33
#[ derive( Clone , Debug ) ]
27
34
pub struct OpenOptions {
@@ -52,9 +59,31 @@ impl FileAttr {
52
59
let size = unsafe { vex_sdk:: vexFileSize ( fd) } ;
53
60
54
61
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 } )
56
80
} 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)
58
87
}
59
88
}
60
89
@@ -67,7 +96,7 @@ impl FileAttr {
67
96
}
68
97
69
98
pub fn file_type ( & self ) -> FileType {
70
- FileType { is_dir : false }
99
+ FileType { is_dir : self . is_dir }
71
100
}
72
101
73
102
pub fn modified ( & self ) -> io:: Result < SystemTime > {
@@ -112,35 +141,32 @@ impl FileType {
112
141
}
113
142
}
114
143
115
- impl fmt:: Debug for ReadDir {
116
- fn fmt ( & self , _f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
117
- self . 0
118
- }
119
- }
120
-
121
144
impl Iterator for ReadDir {
122
145
type Item = io:: Result < DirEntry > ;
123
146
124
147
fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
125
- self . 0
148
+ self . entries . pop ( ) . map ( Ok )
126
149
}
127
150
}
128
151
129
152
impl DirEntry {
130
153
pub fn path ( & self ) -> PathBuf {
131
- self . 0
154
+ self . path . clone ( )
132
155
}
133
156
134
157
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 ( )
136
162
}
137
163
138
164
pub fn metadata ( & self ) -> io:: Result < FileAttr > {
139
- self . 0
165
+ stat ( & self . path )
140
166
}
141
167
142
168
pub fn file_type ( & self ) -> io:: Result < FileType > {
143
- self . 0
169
+ Ok ( self . metadata ( ) ? . file_type ( ) )
144
170
}
145
171
}
146
172
@@ -406,8 +432,43 @@ impl Drop for File {
406
432
}
407
433
}
408
434
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 } )
411
472
}
412
473
413
474
pub fn unlink ( _p : & Path ) -> io:: Result < ( ) > {
@@ -451,12 +512,7 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
451
512
}
452
513
453
514
pub 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)
460
516
}
461
517
462
518
pub fn lstat ( p : & Path ) -> io:: Result < FileAttr > {
0 commit comments