@@ -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 ( )
@@ -512,13 +524,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
512
524
opts. directory ( true ) ;
513
525
opts. read ( true ) ;
514
526
let dir = File :: open ( p, & opts) ?;
515
- Ok ( ReadDir {
516
- cookie : Some ( 0 ) ,
517
- buf : vec ! [ 0 ; 128 ] ,
518
- offset : 0 ,
519
- cap : 0 ,
520
- inner : Arc :: new ( ReadDirInner { dir, root : p. to_path_buf ( ) } ) ,
521
- } )
527
+ Ok ( ReadDir :: new ( dir, p. to_path_buf ( ) ) )
522
528
}
523
529
524
530
pub fn unlink ( p : & Path ) -> io:: Result < ( ) > {
@@ -712,3 +718,52 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
712
718
713
719
io:: copy ( & mut reader, & mut writer)
714
720
}
721
+
722
+ pub fn remove_dir_all ( path : & Path ) -> io:: Result < ( ) > {
723
+ let ( parent, path) = open_parent ( path) ?;
724
+ remove_dir_all_recursive ( & parent, & path)
725
+ }
726
+
727
+ fn remove_dir_all_recursive ( parent : & WasiFd , path : & Path ) -> io:: Result < ( ) > {
728
+ // Open up a file descriptor for the directory itself. Note that we don't
729
+ // follow symlinks here and we specifically open directories.
730
+ //
731
+ // At the root invocation of this function this will correctly handle
732
+ // symlinks passed to the top-level `remove_dir_all`. At the recursive
733
+ // level this will double-check that after the `readdir` call deduced this
734
+ // was a directory it's still a directory by the time we open it up.
735
+ //
736
+ // If the opened file was actually a symlink then the symlink is deleted,
737
+ // not the directory recursively.
738
+ let mut opts = OpenOptions :: new ( ) ;
739
+ opts. lookup_flags ( 0 ) ;
740
+ opts. directory ( true ) ;
741
+ opts. read ( true ) ;
742
+ let fd = open_at ( parent, path, & opts) ?;
743
+ if fd. file_attr ( ) ?. file_type ( ) . is_symlink ( ) {
744
+ return parent. unlink_file ( osstr2str ( path. as_ref ( ) ) ?) ;
745
+ }
746
+
747
+ // this "root" is only used by `DirEntry::path` which we don't use below so
748
+ // it's ok for this to be a bogus value
749
+ let dummy_root = PathBuf :: new ( ) ;
750
+
751
+ // Iterate over all the entries in this directory, and travel recursively if
752
+ // necessary
753
+ for entry in ReadDir :: new ( fd, dummy_root) {
754
+ let entry = entry?;
755
+ let path = crate :: str:: from_utf8 ( & entry. name ) . map_err ( |_| {
756
+ io:: Error :: new_const ( io:: ErrorKind :: Uncategorized , & "invalid utf-8 file name found" )
757
+ } ) ?;
758
+
759
+ if entry. file_type ( ) ?. is_dir ( ) {
760
+ remove_dir_all_recursive ( & entry. inner . dir . fd , path. as_ref ( ) ) ?;
761
+ } else {
762
+ entry. inner . dir . fd . unlink_file ( path) ?;
763
+ }
764
+ }
765
+
766
+ // Once all this directory's contents are deleted it should be safe to
767
+ // delete the directory tiself.
768
+ parent. remove_directory ( osstr2str ( path. as_ref ( ) ) ?)
769
+ }
0 commit comments