diff --git a/crates/wasi-common/src/fdentry.rs b/crates/wasi-common/src/fdentry.rs
index 644e06ffa751..c2c9a719dae8 100644
--- a/crates/wasi-common/src/fdentry.rs
+++ b/crates/wasi-common/src/fdentry.rs
@@ -10,64 +10,6 @@ use std::ops::{Deref, DerefMut};
 use std::path::PathBuf;
 use std::{fmt, fs, io};
 
-pub(crate) enum HandleMut<'handle> {
-    OsHandle(&'handle mut OsHandle),
-    VirtualFile(&'handle mut dyn VirtualFile),
-    Stream(OsHandleRef<'handle>),
-}
-
-impl<'descriptor> fmt::Debug for HandleMut<'descriptor> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            HandleMut::OsHandle(file) => {
-                // coerce to the target debug-printable type
-                let file: &fs::File = file;
-                write!(f, "{:?}", file)
-            }
-            HandleMut::Stream(stream) => {
-                // coerce to the target debug-printable type
-                let file: &fs::File = stream;
-                write!(f, "{:?}", file)
-            }
-            HandleMut::VirtualFile(_) => write!(f, "VirtualFile"),
-        }
-    }
-}
-
-pub(crate) enum Handle<'handle> {
-    OsHandle(&'handle OsHandle),
-    VirtualFile(&'handle dyn VirtualFile),
-    Stream(OsHandleRef<'handle>),
-}
-
-impl<'descriptor> Handle<'descriptor> {
-    pub(crate) fn try_clone(&self) -> io::Result<Descriptor> {
-        match self {
-            Handle::OsHandle(file) => file.try_clone().map(|f| OsHandle::from(f).into()),
-            Handle::Stream(stream) => stream.try_clone().map(|f| OsHandle::from(f).into()),
-            Handle::VirtualFile(virt) => virt.try_clone().map(Descriptor::VirtualFile),
-        }
-    }
-}
-
-impl<'descriptor> fmt::Debug for Handle<'descriptor> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Handle::OsHandle(file) => {
-                // coerce to the target debug-printable type
-                let file: &fs::File = file;
-                write!(f, "{:?}", file)
-            }
-            Handle::Stream(stream) => {
-                // coerce to the target debug-printable type
-                let file: &fs::File = stream;
-                write!(f, "{:?}", file)
-            }
-            Handle::VirtualFile(_) => write!(f, "VirtualFile"),
-        }
-    }
-}
-
 pub(crate) enum Descriptor {
     OsHandle(OsHandle),
     VirtualFile(Box<dyn VirtualFile>),
@@ -101,13 +43,23 @@ impl fmt::Debug for Descriptor {
 }
 
 impl Descriptor {
+    pub(crate) fn try_clone(&self) -> io::Result<Descriptor> {
+        match self {
+            Descriptor::OsHandle(file) => file.try_clone().map(|f| OsHandle::from(f).into()),
+            Descriptor::VirtualFile(virt) => virt.try_clone().map(Descriptor::VirtualFile),
+            Descriptor::Stdin => Ok(Descriptor::Stdin),
+            Descriptor::Stdout => Ok(Descriptor::Stdout),
+            Descriptor::Stderr => Ok(Descriptor::Stderr),
+        }
+    }
+
     /// Return a reference to the `OsHandle` or `VirtualFile` treating it as an
     /// actual file/dir, and allowing operations which require an actual file and
     /// not just a stream or socket file descriptor.
-    pub(crate) fn as_file<'descriptor>(&'descriptor self) -> Result<Handle<'descriptor>> {
+    pub(crate) fn as_file<'descriptor>(&'descriptor self) -> Result<&'descriptor Descriptor> {
         match self {
-            Self::OsHandle(handle) => Ok(Handle::OsHandle(handle)),
-            Self::VirtualFile(virt) => Ok(Handle::VirtualFile(virt.as_ref())),
+            Self::OsHandle(_) => Ok(self),
+            Self::VirtualFile(_) => Ok(self),
             _ => Err(Error::EBADF),
         }
     }
@@ -115,34 +67,14 @@ impl Descriptor {
     /// Like `as_file`, but return a mutable reference.
     pub(crate) fn as_file_mut<'descriptor>(
         &'descriptor mut self,
-    ) -> Result<HandleMut<'descriptor>> {
+    ) -> Result<&'descriptor mut Descriptor> {
         match self {
-            Self::OsHandle(handle) => Ok(HandleMut::OsHandle(handle)),
-            Self::VirtualFile(virt) => Ok(HandleMut::VirtualFile(virt.as_mut())),
+            Self::OsHandle(_) => Ok(self),
+            Self::VirtualFile(_) => Ok(self),
             _ => Err(Error::EBADF),
         }
     }
 
-    pub(crate) fn as_handle<'descriptor>(&'descriptor self) -> Handle<'descriptor> {
-        match self {
-            Self::VirtualFile(virt) => Handle::VirtualFile(virt.as_ref()),
-            Self::OsHandle(handle) => Handle::OsHandle(handle),
-            other @ Self::Stdin | other @ Self::Stderr | other @ Self::Stdout => {
-                Handle::Stream(other.as_os_handle())
-            }
-        }
-    }
-
-    pub(crate) fn as_handle_mut<'descriptor>(&'descriptor mut self) -> HandleMut<'descriptor> {
-        match self {
-            Self::VirtualFile(virt) => HandleMut::VirtualFile(virt.as_mut()),
-            Self::OsHandle(handle) => HandleMut::OsHandle(handle),
-            other @ Self::Stdin | other @ Self::Stderr | other @ Self::Stdout => {
-                HandleMut::Stream(other.as_os_handle())
-            }
-        }
-    }
-
     /// Return an `OsHandle`, which may be a stream or socket file descriptor.
     pub(crate) fn as_os_handle<'descriptor>(&'descriptor self) -> OsHandleRef<'descriptor> {
         descriptor_as_oshandle(self)
diff --git a/crates/wasi-common/src/hostcalls_impl/fs.rs b/crates/wasi-common/src/hostcalls_impl/fs.rs
index 13530a7efbb7..adedd18fce26 100644
--- a/crates/wasi-common/src/hostcalls_impl/fs.rs
+++ b/crates/wasi-common/src/hostcalls_impl/fs.rs
@@ -1,7 +1,7 @@
 #![allow(non_camel_case_types)]
 use super::fs_helpers::path_get;
 use crate::ctx::WasiCtx;
-use crate::fdentry::{Descriptor, FdEntry, Handle, HandleMut};
+use crate::fdentry::{Descriptor, FdEntry};
 use crate::helpers::*;
 use crate::host::Dirent;
 use crate::memory::*;
@@ -42,13 +42,12 @@ pub(crate) unsafe fn fd_datasync(
 
     let file = wasi_ctx
         .get_fd_entry(fd)?
-        .as_descriptor(wasi::__WASI_RIGHTS_FD_DATASYNC, 0)?
-        .as_handle();
+        .as_descriptor(wasi::__WASI_RIGHTS_FD_DATASYNC, 0)?;
 
     match file {
-        Handle::OsHandle(fd) => fd.sync_data().map_err(Into::into),
-        Handle::Stream(stream) => stream.sync_data().map_err(Into::into),
-        Handle::VirtualFile(virt) => virt.datasync(),
+        Descriptor::OsHandle(fd) => fd.sync_data().map_err(Into::into),
+        Descriptor::VirtualFile(virt) => virt.datasync(),
+        other => other.as_os_handle().sync_data().map_err(Into::into),
     }
 }
 
@@ -83,9 +82,9 @@ pub(crate) unsafe fn fd_pread(
     let buf_size = iovs.iter().map(|v| v.buf_len).sum();
     let mut buf = vec![0; buf_size];
     let host_nread = match file {
-        Handle::OsHandle(fd) => hostcalls_impl::fd_pread(&fd, &mut buf, offset)?,
-        Handle::VirtualFile(virt) => virt.pread(&mut buf, offset)?,
-        Handle::Stream(_) => {
+        Descriptor::OsHandle(fd) => hostcalls_impl::fd_pread(&fd, &mut buf, offset)?,
+        Descriptor::VirtualFile(virt) => virt.pread(&mut buf, offset)?,
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -149,9 +148,9 @@ pub(crate) unsafe fn fd_pwrite(
         ));
     }
     let host_nwritten = match file {
-        Handle::OsHandle(fd) => hostcalls_impl::fd_pwrite(&fd, &buf, offset)?,
-        Handle::VirtualFile(virt) => virt.pwrite(buf.as_mut(), offset)?,
-        Handle::Stream(_) => {
+        Descriptor::OsHandle(fd) => hostcalls_impl::fd_pwrite(&fd, &buf, offset)?,
+        Descriptor::VirtualFile(virt) => virt.pwrite(buf.as_mut(), offset)?,
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -266,9 +265,9 @@ pub(crate) unsafe fn fd_seek(
         _ => return Err(Error::EINVAL),
     };
     let host_newoffset = match file {
-        HandleMut::OsHandle(fd) => fd.seek(pos)?,
-        HandleMut::VirtualFile(virt) => virt.seek(pos)?,
-        HandleMut::Stream(_) => {
+        Descriptor::OsHandle(fd) => fd.seek(pos)?,
+        Descriptor::VirtualFile(virt) => virt.seek(pos)?,
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -294,9 +293,9 @@ pub(crate) unsafe fn fd_tell(
         .as_file_mut()?;
 
     let host_offset = match file {
-        HandleMut::OsHandle(fd) => fd.seek(SeekFrom::Current(0))?,
-        HandleMut::VirtualFile(virt) => virt.seek(SeekFrom::Current(0))?,
-        HandleMut::Stream(_) => {
+        Descriptor::OsHandle(fd) => fd.seek(SeekFrom::Current(0))?,
+        Descriptor::VirtualFile(virt) => virt.seek(SeekFrom::Current(0))?,
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -317,12 +316,12 @@ pub(crate) unsafe fn fd_fdstat_get(
     trace!("fd_fdstat_get(fd={:?}, fdstat_ptr={:#x?})", fd, fdstat_ptr);
 
     let mut fdstat = dec_fdstat_byref(memory, fdstat_ptr)?;
-    let wasi_file = wasi_ctx.get_fd_entry(fd)?.as_descriptor(0, 0)?.as_handle();
+    let wasi_file = wasi_ctx.get_fd_entry(fd)?.as_descriptor(0, 0)?;
 
     let fs_flags = match wasi_file {
-        Handle::OsHandle(wasi_fd) => hostcalls_impl::fd_fdstat_get(&wasi_fd)?,
-        Handle::Stream(stream) => hostcalls_impl::fd_fdstat_get(&stream)?,
-        Handle::VirtualFile(virt) => virt.fdstat_get(),
+        Descriptor::OsHandle(wasi_fd) => hostcalls_impl::fd_fdstat_get(&wasi_fd)?,
+        Descriptor::VirtualFile(virt) => virt.fdstat_get(),
+        other => hostcalls_impl::fd_fdstat_get(&other.as_os_handle())?,
     };
 
     let fe = wasi_ctx.get_fd_entry(fd)?;
@@ -348,8 +347,8 @@ pub(crate) unsafe fn fd_fdstat_set_flags(
         .get_fd_entry_mut(fd)?
         .as_descriptor_mut(wasi::__WASI_RIGHTS_FD_FDSTAT_SET_FLAGS, 0)?;
 
-    match descriptor.as_handle_mut() {
-        HandleMut::OsHandle(handle) => {
+    match descriptor {
+        Descriptor::OsHandle(handle) => {
             let set_result =
                 hostcalls_impl::fd_fdstat_set_flags(&handle, fdflags)?.map(Descriptor::OsHandle);
 
@@ -357,17 +356,18 @@ pub(crate) unsafe fn fd_fdstat_set_flags(
                 *descriptor = new_descriptor;
             }
         }
-        HandleMut::Stream(handle) => {
+        Descriptor::VirtualFile(handle) => {
+            handle.fdstat_set_flags(fdflags)?;
+        }
+        _ => {
             let set_result =
-                hostcalls_impl::fd_fdstat_set_flags(&handle, fdflags)?.map(Descriptor::OsHandle);
+                hostcalls_impl::fd_fdstat_set_flags(&descriptor.as_os_handle(), fdflags)?
+                    .map(Descriptor::OsHandle);
 
             if let Some(new_descriptor) = set_result {
                 *descriptor = new_descriptor;
             }
         }
-        HandleMut::VirtualFile(handle) => {
-            handle.fdstat_set_flags(fdflags)?;
-        }
     };
 
     Ok(())
@@ -411,9 +411,9 @@ pub(crate) unsafe fn fd_sync(
         .as_descriptor(wasi::__WASI_RIGHTS_FD_SYNC, 0)?
         .as_file()?;
     match file {
-        Handle::OsHandle(fd) => fd.sync_all().map_err(Into::into),
-        Handle::VirtualFile(virt) => virt.sync(),
-        Handle::Stream(_) => {
+        Descriptor::OsHandle(fd) => fd.sync_all().map_err(Into::into),
+        Descriptor::VirtualFile(virt) => virt.sync(),
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -485,7 +485,7 @@ pub(crate) unsafe fn fd_write(
 }
 
 pub(crate) unsafe fn fd_advise(
-    wasi_ctx: &WasiCtx,
+    wasi_ctx: &mut WasiCtx,
     _memory: &mut [u8],
     fd: wasi::__wasi_fd_t,
     offset: wasi::__wasi_filesize_t,
@@ -501,14 +501,14 @@ pub(crate) unsafe fn fd_advise(
     );
 
     let file = wasi_ctx
-        .get_fd_entry(fd)?
-        .as_descriptor(wasi::__WASI_RIGHTS_FD_ADVISE, 0)?
-        .as_handle();
+        .get_fd_entry_mut(fd)?
+        .as_descriptor_mut(wasi::__WASI_RIGHTS_FD_ADVISE, 0)?
+        .as_file_mut()?;
 
     match file {
-        Handle::OsHandle(fd) => hostcalls_impl::fd_advise(&fd, advice, offset, len),
-        Handle::VirtualFile(virt) => virt.advise(advice, offset, len),
-        Handle::Stream(_) => {
+        Descriptor::OsHandle(fd) => hostcalls_impl::fd_advise(&fd, advice, offset, len),
+        Descriptor::VirtualFile(virt) => virt.advise(advice, offset, len),
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -531,7 +531,7 @@ pub(crate) unsafe fn fd_allocate(
         .as_file()?;
 
     match file {
-        Handle::OsHandle(fd) => {
+        Descriptor::OsHandle(fd) => {
             let metadata = fd.metadata()?;
 
             let current_size = metadata.len();
@@ -547,8 +547,8 @@ pub(crate) unsafe fn fd_allocate(
                 Ok(())
             }
         }
-        Handle::VirtualFile(virt) => virt.allocate(offset, len),
-        Handle::Stream(_) => {
+        Descriptor::VirtualFile(virt) => virt.allocate(offset, len),
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -829,9 +829,9 @@ pub(crate) unsafe fn fd_filestat_get(
         .as_descriptor(wasi::__WASI_RIGHTS_FD_FILESTAT_GET, 0)?
         .as_file()?;
     let host_filestat = match fd {
-        Handle::OsHandle(fd) => hostcalls_impl::fd_filestat_get(&fd)?,
-        Handle::VirtualFile(virt) => virt.filestat_get()?,
-        Handle::Stream(_) => {
+        Descriptor::OsHandle(fd) => hostcalls_impl::fd_filestat_get(&fd)?,
+        Descriptor::VirtualFile(virt) => virt.filestat_get()?,
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -868,7 +868,7 @@ pub(crate) unsafe fn fd_filestat_set_times(
 }
 
 pub(crate) fn fd_filestat_set_times_impl(
-    file: &Handle,
+    file: &Descriptor,
     st_atim: wasi::__wasi_timestamp_t,
     st_mtim: wasi::__wasi_timestamp_t,
     fst_flags: wasi::__wasi_fstflags_t,
@@ -901,9 +901,9 @@ pub(crate) fn fd_filestat_set_times_impl(
         None
     };
     match file {
-        Handle::OsHandle(fd) => set_file_handle_times(fd, atim, mtim).map_err(Into::into),
-        Handle::VirtualFile(virt) => virt.filestat_set_times(atim, mtim),
-        Handle::Stream(_) => {
+        Descriptor::OsHandle(fd) => set_file_handle_times(fd, atim, mtim).map_err(Into::into),
+        Descriptor::VirtualFile(virt) => virt.filestat_set_times(atim, mtim),
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -929,9 +929,9 @@ pub(crate) unsafe fn fd_filestat_set_size(
         return Err(Error::E2BIG);
     }
     match file {
-        Handle::OsHandle(fd) => fd.set_len(st_size).map_err(Into::into),
-        Handle::VirtualFile(virt) => virt.filestat_set_size(st_size),
-        Handle::Stream(_) => {
+        Descriptor::OsHandle(fd) => fd.set_len(st_size).map_err(Into::into),
+        Descriptor::VirtualFile(virt) => virt.filestat_set_size(st_size),
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
@@ -1240,11 +1240,11 @@ pub(crate) unsafe fn fd_readdir(
     }
 
     let host_bufused = match file {
-        HandleMut::OsHandle(file) => {
+        Descriptor::OsHandle(file) => {
             copy_entities(hostcalls_impl::fd_readdir(file, cookie)?, host_buf)?
         }
-        HandleMut::VirtualFile(virt) => copy_entities(virt.readdir(cookie)?, host_buf)?,
-        HandleMut::Stream(_) => {
+        Descriptor::VirtualFile(virt) => copy_entities(virt.readdir(cookie)?, host_buf)?,
+        _ => {
             unreachable!(
                 "implementation error: fd should have been checked to not be a stream already"
             );
diff --git a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs
index ca4299089d6d..d4677b014374 100644
--- a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs
+++ b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs
@@ -495,7 +495,7 @@ pub(crate) fn path_filestat_set_times(
         .access_mode(AccessMode::FILE_WRITE_ATTRIBUTES.bits())
         .open(path)?;
     let modifiable_fd = Descriptor::OsHandle(OsHandle::from(file));
-    fd_filestat_set_times_impl(&modifiable_fd.as_handle(), st_atim, st_mtim, fst_flags)
+    fd_filestat_set_times_impl(&modifiable_fd, st_atim, st_mtim, fst_flags)
 }
 
 pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {