@@ -16,7 +16,7 @@ use crate::sys::time::SystemTime;
16
16
use crate :: sys:: unsupported;
17
17
use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
18
18
19
- pub use crate :: sys_common:: fs:: { remove_dir_all , try_exists} ;
19
+ pub use crate :: sys_common:: fs:: try_exists;
20
20
21
21
pub struct File {
22
22
fd : WasiFd ,
@@ -130,6 +130,18 @@ impl FileType {
130
130
}
131
131
}
132
132
133
+ impl ReadDir {
134
+ fn new ( dir : File , root : PathBuf ) -> ReadDir {
135
+ ReadDir {
136
+ cookie : Some ( 0 ) ,
137
+ buf : vec ! [ 0 ; 128 ] ,
138
+ offset : 0 ,
139
+ cap : 0 ,
140
+ inner : Arc :: new ( ReadDirInner { dir, root } ) ,
141
+ }
142
+ }
143
+ }
144
+
133
145
impl fmt:: Debug for ReadDir {
134
146
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
135
147
f. debug_struct ( "ReadDir" ) . finish_non_exhaustive ( )
@@ -516,13 +528,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
516
528
opts. directory ( true ) ;
517
529
opts. read ( true ) ;
518
530
let dir = File :: open ( p, & opts) ?;
519
- Ok ( ReadDir {
520
- cookie : Some ( 0 ) ,
521
- buf : vec ! [ 0 ; 128 ] ,
522
- offset : 0 ,
523
- cap : 0 ,
524
- inner : Arc :: new ( ReadDirInner { dir, root : p. to_path_buf ( ) } ) ,
525
- } )
531
+ Ok ( ReadDir :: new ( dir, p. to_path_buf ( ) ) )
526
532
}
527
533
528
534
pub fn unlink ( p : & Path ) -> io:: Result < ( ) > {
@@ -716,3 +722,52 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
716
722
717
723
io:: copy ( & mut reader, & mut writer)
718
724
}
725
+
726
+ pub fn remove_dir_all ( path : & Path ) -> io:: Result < ( ) > {
727
+ let ( parent, path) = open_parent ( path) ?;
728
+ remove_dir_all_recursive ( & parent, & path)
729
+ }
730
+
731
+ fn remove_dir_all_recursive ( parent : & WasiFd , path : & Path ) -> io:: Result < ( ) > {
732
+ // Open up a file descriptor for the directory itself. Note that we don't
733
+ // follow symlinks here and we specifically open directories.
734
+ //
735
+ // At the root invocation of this function this will correctly handle
736
+ // symlinks passed to the top-level `remove_dir_all`. At the recursive
737
+ // level this will double-check that after the `readdir` call deduced this
738
+ // was a directory it's still a directory by the time we open it up.
739
+ //
740
+ // If the opened file was actually a symlink then the symlink is deleted,
741
+ // not the directory recursively.
742
+ let mut opts = OpenOptions :: new ( ) ;
743
+ opts. lookup_flags ( 0 ) ;
744
+ opts. directory ( true ) ;
745
+ opts. read ( true ) ;
746
+ let fd = open_at ( parent, path, & opts) ?;
747
+ if fd. file_attr ( ) ?. file_type ( ) . is_symlink ( ) {
748
+ return parent. unlink_file ( osstr2str ( path. as_ref ( ) ) ?) ;
749
+ }
750
+
751
+ // this "root" is only used by `DirEntry::path` which we don't use below so
752
+ // it's ok for this to be a bogus value
753
+ let dummy_root = PathBuf :: new ( ) ;
754
+
755
+ // Iterate over all the entries in this directory, and travel recursively if
756
+ // necessary
757
+ for entry in ReadDir :: new ( fd, dummy_root) {
758
+ let entry = entry?;
759
+ let path = crate :: str:: from_utf8 ( & entry. name ) . map_err ( |_| {
760
+ io:: Error :: new_const ( io:: ErrorKind :: Uncategorized , & "invalid utf-8 file name found" )
761
+ } ) ?;
762
+
763
+ if entry. file_type ( ) ?. is_dir ( ) {
764
+ remove_dir_all_recursive ( & entry. inner . dir . fd , path. as_ref ( ) ) ?;
765
+ } else {
766
+ entry. inner . dir . fd . unlink_file ( path) ?;
767
+ }
768
+ }
769
+
770
+ // Once all this directory's contents are deleted it should be safe to
771
+ // delete the directory tiself.
772
+ parent. remove_directory ( osstr2str ( path. as_ref ( ) ) ?)
773
+ }
0 commit comments