Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package rust1.58 for openSUSE:Factory 
checked in at 2022-01-23 12:15:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rust1.58 (Old)
 and      /work/SRC/openSUSE:Factory/.rust1.58.new.1938 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rust1.58"

Sun Jan 23 12:15:06 2022 rev:2 rq:947801 version:1.58.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/rust1.58/rust1.58.changes        2022-01-16 
23:18:47.802363663 +0100
+++ /work/SRC/openSUSE:Factory/.rust1.58.new.1938/rust1.58.changes      
2022-01-23 12:15:43.340454178 +0100
@@ -1,0 +2,12 @@
+Thu Jan 20 04:51:36 UTC 2022 - William Brown <william.br...@suse.com>
+
+- bsc#1194767 - CVE-2022-21658 - Resolve race condition in 
std::fs::remove_dir_all
+  - 0002-Fix-CVE-2022-21658-for-UNIX-like.patch
+  - 0003-Fix-CVE-2022-21658-for-WASI.patch
+
+-------------------------------------------------------------------
+Tue Jan 18 07:08:15 UTC 2022 - Guillaume GARDET <guillaume.gar...@opensuse.org>
+
+- Disable build in shm for %{arm} to fix build
+
+-------------------------------------------------------------------

New:
----
  0002-Fix-CVE-2022-21658-for-UNIX-like.patch
  0003-Fix-CVE-2022-21658-for-WASI.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rust1.58.spec ++++++
--- /var/tmp/diff_new_pack.uf9eHz/_old  2022-01-23 12:15:50.972403168 +0100
+++ /var/tmp/diff_new_pack.uf9eHz/_new  2022-01-23 12:15:50.976403141 +0100
@@ -1,7 +1,7 @@
 #
 # spec file
 #
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 # Copyright (c) 2019 Luke Jones, l...@ljones.dev
 #
 # All modifications and additions to the file contributed by third parties
@@ -16,6 +16,7 @@
 # Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
+
 %global version_suffix 1.58
 %global version_current 1.58.0
 %global version_previous 1.57.0
@@ -154,7 +155,7 @@
 %if "%{flavor}" == "test" || %with bundled_llvm
 %bcond_with dev_shm
 %else
-%ifarch x86_64 aarch64 %{arm} %{ix86} s390x
+%ifarch x86_64 aarch64 %{ix86} s390x
 %bcond_without dev_shm
 %else
 %bcond_with dev_shm
@@ -203,6 +204,9 @@
 Source1000:     README.suse-maint
 # PATCH-FIX-OPENSUSE: edit src/librustc_llvm/build.rs to ignore GCC 
incompatible flag
 Patch0:         ignore-Wstring-conversion.patch
+# Fix CVE-2022-21658
+Patch10:        0002-Fix-CVE-2022-21658-for-UNIX-like.patch
+Patch11:        0003-Fix-CVE-2022-21658-for-WASI.patch
 BuildRequires:  curl
 BuildRequires:  fdupes
 BuildRequires:  pkgconfig

++++++ 0002-Fix-CVE-2022-21658-for-UNIX-like.patch ++++++
>From 423950dd822b1fd13155b4440f249f6e593f0c6b Mon Sep 17 00:00:00 2001
From: Hans Kratz <h...@appfour.com>
Date: Mon, 17 Jan 2022 09:45:46 +0100
Subject: [PATCH 2/3] Fix CVE-2022-21658 for UNIX-like

---
 library/std/src/fs.rs            |   9 +-
 library/std/src/fs/tests.rs      |  70 ++++++++
 library/std/src/sys/unix/fs.rs   | 279 +++++++++++++++++++++++++++++--
 library/std/src/sys/unix/weak.rs |   5 +-
 4 files changed, 348 insertions(+), 15 deletions(-)

diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index a14f1e2ecb2..dd4cc93952f 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2045,11 +2045,14 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> 
io::Result<()> {
 ///
 /// # Platform-specific behavior
 ///
-/// This function currently corresponds to `opendir`, `lstat`, `rm` and 
`rmdir` functions on Unix
-/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and 
`RemoveDirectory` functions
-/// on Windows.
+/// This function currently uses the `openat`, `fdopendir`, `unlinkat` and 
`lstat` functions on
+/// Unix (execept for MacOS before version 10.10 and REDOX) and the 
`FindFirstFile`,
+/// `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions on 
Windows.
 /// Note that, this [may change in the future][changes].
 ///
+/// On MacOS before version 10.10 and on REDOX this function is not protected 
against time-of-check
+/// to time-of-Use (TOCTOU) race conditions and should not be used in 
security-sensitive code.
+///
 /// [changes]: io#platform-specific-behavior
 ///
 /// # Errors
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 9a8f1e44f1f..4d1959258be 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -4,8 +4,10 @@
 use crate::io::{ErrorKind, SeekFrom};
 use crate::path::Path;
 use crate::str;
+use crate::sync::Arc;
 use crate::sys_common::io::test::{tmpdir, TempDir};
 use crate::thread;
+use crate::time::{Duration, Instant};
 
 use rand::{rngs::StdRng, RngCore, SeedableRng};
 
@@ -602,6 +604,21 @@ fn recursive_rmdir_of_symlink() {
     assert!(canary.exists());
 }
 
+#[test]
+fn recursive_rmdir_of_file_fails() {
+    // test we do not delete a directly specified file.
+    let tmpdir = tmpdir();
+    let canary = tmpdir.join("do_not_delete");
+    check!(check!(File::create(&canary)).write(b"foo"));
+    let result = fs::remove_dir_all(&canary);
+    #[cfg(unix)]
+    error!(result, "Not a directory");
+    #[cfg(windows)]
+    error!(result, 267); // ERROR_DIRECTORY - The directory name is invalid.
+    assert!(result.is_err());
+    assert!(canary.exists());
+}
+
 #[test]
 // only Windows makes a distinction between file and directory symlinks.
 #[cfg(windows)]
@@ -621,6 +638,59 @@ fn recursive_rmdir_of_file_symlink() {
     }
 }
 
+#[test]
+#[ignore] // takes too much time
+fn recursive_rmdir_toctou() {
+    // Test for time-of-check to time-of-use issues.
+    //
+    // Scenario:
+    // The attacker wants to get directory contents deleted, to which he does 
not have access.
+    // He has a way to get a privileged Rust binary call 
`std::fs::remove_dir_all()` on a
+    // directory he controls, e.g. in his home directory.
+    //
+    // The POC sets up the `attack_dest/attack_file` which the attacker wants 
to have deleted.
+    // The attacker repeatedly creates a directory and replaces it with a 
symlink from
+    // `victim_del` to `attack_dest` while the victim code calls 
`std::fs::remove_dir_all()`
+    // on `victim_del`. After a few seconds the attack has succeeded and
+    // `attack_dest/attack_file` is deleted.
+    let tmpdir = tmpdir();
+    let victim_del_path = tmpdir.join("victim_del");
+    let victim_del_path_clone = victim_del_path.clone();
+
+    // setup dest
+    let attack_dest_dir = tmpdir.join("attack_dest");
+    let attack_dest_dir = attack_dest_dir.as_path();
+    fs::create_dir(attack_dest_dir).unwrap();
+    let attack_dest_file = tmpdir.join("attack_dest/attack_file");
+    File::create(&attack_dest_file).unwrap();
+
+    let drop_canary_arc = Arc::new(());
+    let drop_canary_weak = Arc::downgrade(&drop_canary_arc);
+
+    eprintln!("x: {:?}", &victim_del_path);
+
+    // victim just continuously removes `victim_del`
+    thread::spawn(move || {
+        while drop_canary_weak.upgrade().is_some() {
+            let _ = fs::remove_dir_all(&victim_del_path_clone);
+        }
+    });
+
+    // attacker (could of course be in a separate process)
+    let start_time = Instant::now();
+    while Instant::now().duration_since(start_time) < 
Duration::from_secs(1000) {
+        if !attack_dest_file.exists() {
+            panic!(
+                "Victim deleted symlinked file outside of victim_del. Attack 
succeeded in {:?}.",
+                Instant::now().duration_since(start_time)
+            );
+        }
+        let _ = fs::create_dir(&victim_del_path);
+        let _ = fs::remove_dir(&victim_del_path);
+        let _ = symlink_dir(attack_dest_dir, &victim_del_path);
+    }
+}
+
 #[test]
 fn unicode_path_is_dir() {
     assert!(Path::new(".").is_dir());
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index a4fff9b2e64..a150d1a9aac 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -64,7 +64,7 @@
     dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, 
readdir64_r, stat64,
 };
 
-pub use crate::sys_common::fs::{remove_dir_all, try_exists};
+pub use crate::sys_common::fs::try_exists;
 
 pub struct File(FileDesc);
 
@@ -228,7 +228,7 @@ pub struct DirEntry {
         target_os = "fuchsia",
         target_os = "redox"
     ))]
-    name: Box<[u8]>,
+    name: CString,
 }
 
 #[derive(Clone, Debug)]
@@ -455,8 +455,6 @@ impl Iterator for ReadDir {
         target_os = "illumos"
     ))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
-        use crate::slice;
-
         unsafe {
             loop {
                 // Although readdir_r(3) would be a correct function to use 
here because
@@ -474,14 +472,10 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
                     };
                 }
 
-                let name = (*entry_ptr).d_name.as_ptr();
-                let namelen = libc::strlen(name) as usize;
-
                 let ret = DirEntry {
                     entry: *entry_ptr,
-                    name: slice::from_raw_parts(name as *const u8, namelen as 
usize)
-                        .to_owned()
-                        .into_boxed_slice(),
+                    // d_name is guaranteed to be null-terminated.
+                    name: 
CStr::from_ptr((*entry_ptr).d_name.as_ptr()).to_owned(),
                     dir: Arc::clone(&self.inner),
                 };
                 if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
@@ -664,7 +658,26 @@ fn name_bytes(&self) -> &[u8] {
         target_os = "redox"
     ))]
     fn name_bytes(&self) -> &[u8] {
-        &*self.name
+        self.name.as_bytes()
+    }
+
+    #[cfg(not(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "fuchsia",
+        target_os = "redox"
+    )))]
+    fn name_cstr(&self) -> &CStr {
+        unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
+    }
+    #[cfg(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "fuchsia",
+        target_os = "redox"
+    ))]
+    fn name_cstr(&self) -> &CStr {
+        &self.name
     }
 
     pub fn file_name_os_str(&self) -> &OsStr {
@@ -1439,3 +1452,247 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
     cvt(unsafe { libc::chroot(dir.as_ptr()) })?;
     Ok(())
 }
+
+pub use remove_dir_impl::remove_dir_all;
+
+// Fallback for REDOX
+#[cfg(target_os = "redox")]
+mod remove_dir_impl {
+    pub use crate::sys_common::fs::remove_dir_all;
+}
+
+// Dynamically choose implementation Macos x86-64: modern for 10.10+, fallback 
for older versions
+#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
+mod remove_dir_impl {
+    use super::{cstr, lstat, Dir, InnerReadDir, ReadDir};
+    use crate::ffi::CStr;
+    use crate::io;
+    use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+    use crate::os::unix::prelude::{OwnedFd, RawFd};
+    use crate::path::{Path, PathBuf};
+    use crate::sync::Arc;
+    use crate::sys::weak::weak;
+    use crate::sys::{cvt, cvt_r};
+    use libc::{c_char, c_int, DIR};
+
+    pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> 
io::Result<OwnedFd> {
+        weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
+        let fd = cvt_r(|| unsafe {
+            openat.get().unwrap()(
+                parent_fd.unwrap_or(libc::AT_FDCWD),
+                p.as_ptr(),
+                libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | 
libc::O_DIRECTORY,
+            )
+        })?;
+        Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+    }
+
+    fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> {
+        weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64");
+        let ptr = unsafe { fdopendir.get().unwrap()(dir_fd.as_raw_fd()) };
+        if ptr.is_null() {
+            return Err(io::Error::last_os_error());
+        }
+        let dirp = Dir(ptr);
+        // file descriptor is automatically closed by libc::closedir() now, so 
give up ownership
+        let new_parent_fd = dir_fd.into_raw_fd();
+        // a valid root is not needed because we do not call any functions 
involving the full path
+        // of the DirEntrys.
+        let dummy_root = PathBuf::new();
+        Ok((
+            ReadDir {
+                inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
+                end_of_stream: false,
+            },
+            new_parent_fd,
+        ))
+    }
+
+    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> 
io::Result<()> {
+        weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int);
+
+        let pcstr = cstr(p)?;
+
+        // entry is expected to be a directory, open as such
+        let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
+
+        // open the directory passing ownership of the fd
+        let (dir, fd) = fdreaddir(fd)?;
+        for child in dir {
+            let child = child?;
+            match child.entry.d_type {
+                libc::DT_DIR => {
+                    remove_dir_all_recursive(Some(fd), 
Path::new(&child.file_name()))?;
+                }
+                libc::DT_UNKNOWN => {
+                    match cvt(unsafe { unlinkat.get().unwrap()(fd, 
child.name_cstr().as_ptr(), 0) })
+                    {
+                        // type unknown - try to unlink
+                        Err(err) if err.raw_os_error() == Some(libc::EPERM) => 
{
+                            // if the file is a directory unlink fails with 
EPERM
+                            remove_dir_all_recursive(Some(fd), 
Path::new(&child.file_name()))?;
+                        }
+                        result => {
+                            result?;
+                        }
+                    }
+                }
+                _ => {
+                    // not a directory -> unlink
+                    cvt(unsafe { unlinkat.get().unwrap()(fd, 
child.name_cstr().as_ptr(), 0) })?;
+                }
+            }
+        }
+
+        // unlink the directory after removing its contents
+        cvt(unsafe {
+            unlinkat.get().unwrap()(
+                parent_fd.unwrap_or(libc::AT_FDCWD),
+                pcstr.as_ptr(),
+                libc::AT_REMOVEDIR,
+            )
+        })?;
+        Ok(())
+    }
+
+    fn remove_dir_all_modern(p: &Path) -> io::Result<()> {
+        // We cannot just call remove_dir_all_recursive() here because that 
would not delete a passed
+        // symlink. No need to worry about races, because 
remove_dir_all_recursive() does not recurse
+        // into symlinks.
+        let attr = lstat(p)?;
+        if attr.file_type().is_symlink() {
+            crate::fs::remove_file(p)
+        } else {
+            remove_dir_all_recursive(None, p)
+        }
+    }
+
+    pub fn remove_dir_all(p: &Path) -> io::Result<()> {
+        weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
+        if openat.get().is_some() {
+            // openat() is available with macOS 10.10+, just like unlinkat() 
and fdopendir()
+            remove_dir_all_modern(p)
+        } else {
+            // fall back to classic implementation
+            crate::sys_common::fs::remove_dir_all(p)
+        }
+    }
+}
+
+// Modern implementation using openat(), unlinkat() and fdopendir()
+#[cfg(not(any(all(target_os = "macos", target_arch = "x86_64"), target_os = 
"redox")))]
+mod remove_dir_impl {
+    use super::{cstr, lstat, Dir, InnerReadDir, ReadDir};
+    use crate::ffi::CStr;
+    use crate::io;
+    use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+    use crate::os::unix::prelude::{OwnedFd, RawFd};
+    use crate::path::{Path, PathBuf};
+    use crate::sync::Arc;
+    use crate::sys::{cvt, cvt_r};
+    use libc::{fdopendir, openat, unlinkat};
+
+    pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> 
io::Result<OwnedFd> {
+        let fd = cvt_r(|| unsafe {
+            openat(
+                parent_fd.unwrap_or(libc::AT_FDCWD),
+                p.as_ptr(),
+                libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | 
libc::O_DIRECTORY,
+            )
+        })?;
+        Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+    }
+
+    fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> {
+        let ptr = unsafe { fdopendir(dir_fd.as_raw_fd()) };
+        if ptr.is_null() {
+            return Err(io::Error::last_os_error());
+        }
+        let dirp = Dir(ptr);
+        // file descriptor is automatically closed by libc::closedir() now, so 
give up ownership
+        let new_parent_fd = dir_fd.into_raw_fd();
+        // a valid root is not needed because we do not call any functions 
involving the full path
+        // of the DirEntrys.
+        let dummy_root = PathBuf::new();
+        Ok((
+            ReadDir {
+                inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
+                #[cfg(not(any(
+                    target_os = "solaris",
+                    target_os = "illumos",
+                    target_os = "fuchsia",
+                    target_os = "redox",
+                )))]
+                end_of_stream: false,
+            },
+            new_parent_fd,
+        ))
+    }
+
+    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> 
io::Result<()> {
+        let pcstr = cstr(p)?;
+
+        // entry is expected to be a directory, open as such
+        let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
+
+        // open the directory passing ownership of the fd
+        let (dir, fd) = fdreaddir(fd)?;
+        for child in dir {
+            let child = child?;
+            let child_is_dir = if cfg!(any(
+                target_os = "solaris",
+                target_os = "illumos",
+                target_os = "haiku",
+                target_os = "vxworks"
+            )) {
+                // no d_type in dirent
+                None
+            } else {
+                match child.entry.d_type {
+                    libc::DT_UNKNOWN => None,
+                    libc::DT_DIR => Some(true),
+                    _ => Some(false),
+                }
+            };
+            match child_is_dir {
+                Some(true) => {
+                    remove_dir_all_recursive(Some(fd), 
Path::new(&child.file_name()))?;
+                }
+                Some(false) => {
+                    cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) 
})?;
+                }
+                None => match cvt(unsafe { unlinkat(fd, 
child.name_cstr().as_ptr(), 0) }) {
+                    // type unknown - try to unlink
+                    Err(err)
+                        if err.raw_os_error() == Some(libc::EISDIR)
+                            || err.raw_os_error() == Some(libc::EPERM) =>
+                    {
+                        // if the file is a directory unlink fails with EISDIR 
on Linux and EPERM everyhwere else
+                        remove_dir_all_recursive(Some(fd), 
Path::new(&child.file_name()))?;
+                    }
+                    result => {
+                        result?;
+                    }
+                },
+            }
+        }
+
+        // unlink the directory after removing its contents
+        cvt(unsafe {
+            unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), 
libc::AT_REMOVEDIR)
+        })?;
+        Ok(())
+    }
+
+    pub fn remove_dir_all(p: &Path) -> io::Result<()> {
+        // We cannot just call remove_dir_all_recursive() here because that 
would not delete a passed
+        // symlink. No need to worry about races, because 
remove_dir_all_recursive() does not recurse
+        // into symlinks.
+        let attr = lstat(p)?;
+        if attr.file_type().is_symlink() {
+            crate::fs::remove_file(p)
+        } else {
+            remove_dir_all_recursive(None, p)
+        }
+    }
+}
diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs
index ba432ec5494..83ff78fa7a2 100644
--- a/library/std/src/sys/unix/weak.rs
+++ b/library/std/src/sys/unix/weak.rs
@@ -28,9 +28,12 @@
 
 pub(crate) macro weak {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+        weak!(fn $name($($t),*) -> $ret, stringify!($name));
+    ),
+    (fn $name:ident($($t:ty),*) -> $ret:ty, $sym:expr) => (
         #[allow(non_upper_case_globals)]
         static $name: crate::sys::weak::Weak<unsafe extern "C" fn($($t),*) -> 
$ret> =
-            crate::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
+            crate::sys::weak::Weak::new(concat!($sym, '\0'));
     )
 }
 
-- 
2.25.1


++++++ 0003-Fix-CVE-2022-21658-for-WASI.patch ++++++
>From f49e00337d0ae9d1639ca82e8ef6d1e7e3ec717f Mon Sep 17 00:00:00 2001
From: Alex Crichton <a...@alexcrichton.com>
Date: Tue, 4 Jan 2022 08:44:15 -0800
Subject: [PATCH 3/3] Fix CVE-2022-21658 for WASI

---
 library/std/src/sys/wasi/fs.rs | 71 ++++++++++++++++++++++++++++++----
 1 file changed, 63 insertions(+), 8 deletions(-)

diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 984dda8dc0b..00b9ab3b864 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -16,7 +16,7 @@
 use crate::sys::unsupported;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
-pub use crate::sys_common::fs::{remove_dir_all, try_exists};
+pub use crate::sys_common::fs::try_exists;
 
 pub struct File {
     fd: WasiFd,
@@ -130,6 +130,18 @@ pub fn bits(&self) -> wasi::Filetype {
     }
 }
 
+impl ReadDir {
+    fn new(dir: File, root: PathBuf) -> ReadDir {
+        ReadDir {
+            cookie: Some(0),
+            buf: vec![0; 128],
+            offset: 0,
+            cap: 0,
+            inner: Arc::new(ReadDirInner { dir, root }),
+        }
+    }
+}
+
 impl fmt::Debug for ReadDir {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("ReadDir").finish_non_exhaustive()
@@ -512,13 +524,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
     opts.directory(true);
     opts.read(true);
     let dir = File::open(p, &opts)?;
-    Ok(ReadDir {
-        cookie: Some(0),
-        buf: vec![0; 128],
-        offset: 0,
-        cap: 0,
-        inner: Arc::new(ReadDirInner { dir, root: p.to_path_buf() }),
-    })
+    Ok(ReadDir::new(dir, p.to_path_buf()))
 }
 
 pub fn unlink(p: &Path) -> io::Result<()> {
@@ -712,3 +718,52 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
 
     io::copy(&mut reader, &mut writer)
 }
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+    let (parent, path) = open_parent(path)?;
+    remove_dir_all_recursive(&parent, &path)
+}
+
+fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> {
+    // Open up a file descriptor for the directory itself. Note that we don't
+    // follow symlinks here and we specifically open directories.
+    //
+    // At the root invocation of this function this will correctly handle
+    // symlinks passed to the top-level `remove_dir_all`. At the recursive
+    // level this will double-check that after the `readdir` call deduced this
+    // was a directory it's still a directory by the time we open it up.
+    //
+    // If the opened file was actually a symlink then the symlink is deleted,
+    // not the directory recursively.
+    let mut opts = OpenOptions::new();
+    opts.lookup_flags(0);
+    opts.directory(true);
+    opts.read(true);
+    let fd = open_at(parent, path, &opts)?;
+    if fd.file_attr()?.file_type().is_symlink() {
+        return parent.unlink_file(osstr2str(path.as_ref())?);
+    }
+
+    // this "root" is only used by `DirEntry::path` which we don't use below so
+    // it's ok for this to be a bogus value
+    let dummy_root = PathBuf::new();
+
+    // Iterate over all the entries in this directory, and travel recursively 
if
+    // necessary
+    for entry in ReadDir::new(fd, dummy_root) {
+        let entry = entry?;
+        let path = crate::str::from_utf8(&entry.name).map_err(|_| {
+            io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 
file name found")
+        })?;
+
+        if entry.file_type()?.is_dir() {
+            remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?;
+        } else {
+            entry.inner.dir.fd.unlink_file(path)?;
+        }
+    }
+
+    // Once all this directory's contents are deleted it should be safe to
+    // delete the directory tiself.
+    parent.remove_directory(osstr2str(path.as_ref())?)
+}
-- 
2.25.1

Reply via email to