diff --git a/crates/wasi-common/src/old/snapshot_0/sys/windows/host_impl.rs b/crates/wasi-common/src/old/snapshot_0/sys/windows/host_impl.rs index 5fcebb052e..036c5010e4 100644 --- a/crates/wasi-common/src/old/snapshot_0/sys/windows/host_impl.rs +++ b/crates/wasi-common/src/old/snapshot_0/sys/windows/host_impl.rs @@ -12,43 +12,36 @@ use std::io; use std::os::windows::ffi::OsStrExt; use std::os::windows::fs::OpenOptionsExt; use std::time::{SystemTime, UNIX_EPOCH}; +use winapi::shared::winerror; use winx::file::{AccessMode, Attributes, CreationDisposition, Flags}; -use winx::winerror::WinError; impl FromRawOsError for Error { fn from_raw_os_error(code: i32) -> Self { - Self::from(WinError::from_u32(code as u32)) - } -} - -impl From for Error { - fn from(err: WinError) -> Self { // TODO: implement error mapping between Windows and WASI - use winx::winerror::WinError::*; - match err { - ERROR_SUCCESS => Self::ESUCCESS, - ERROR_BAD_ENVIRONMENT => Self::E2BIG, - ERROR_FILE_NOT_FOUND => Self::ENOENT, - ERROR_PATH_NOT_FOUND => Self::ENOENT, - ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE, - ERROR_ACCESS_DENIED => Self::EACCES, - ERROR_SHARING_VIOLATION => Self::EACCES, - ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping? - ERROR_INVALID_HANDLE => Self::EBADF, - ERROR_INVALID_NAME => Self::ENOENT, - ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM, - ERROR_OUTOFMEMORY => Self::ENOMEM, - ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY, - ERROR_NOT_READY => Self::EBUSY, - ERROR_BUSY => Self::EBUSY, - ERROR_NOT_SUPPORTED => Self::ENOTSUP, - ERROR_FILE_EXISTS => Self::EEXIST, - ERROR_BROKEN_PIPE => Self::EPIPE, - ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG, - ERROR_NOT_A_REPARSE_POINT => Self::EINVAL, - ERROR_NEGATIVE_SEEK => Self::EINVAL, - ERROR_DIRECTORY => Self::ENOTDIR, - ERROR_ALREADY_EXISTS => Self::EEXIST, + match code as u32 { + winerror::ERROR_SUCCESS => Self::ESUCCESS, + winerror::ERROR_BAD_ENVIRONMENT => Self::E2BIG, + winerror::ERROR_FILE_NOT_FOUND => Self::ENOENT, + winerror::ERROR_PATH_NOT_FOUND => Self::ENOENT, + winerror::ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE, + winerror::ERROR_ACCESS_DENIED => Self::EACCES, + winerror::ERROR_SHARING_VIOLATION => Self::EACCES, + winerror::ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping? + winerror::ERROR_INVALID_HANDLE => Self::EBADF, + winerror::ERROR_INVALID_NAME => Self::ENOENT, + winerror::ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM, + winerror::ERROR_OUTOFMEMORY => Self::ENOMEM, + winerror::ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY, + winerror::ERROR_NOT_READY => Self::EBUSY, + winerror::ERROR_BUSY => Self::EBUSY, + winerror::ERROR_NOT_SUPPORTED => Self::ENOTSUP, + winerror::ERROR_FILE_EXISTS => Self::EEXIST, + winerror::ERROR_BROKEN_PIPE => Self::EPIPE, + winerror::ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG, + winerror::ERROR_NOT_A_REPARSE_POINT => Self::EINVAL, + winerror::ERROR_NEGATIVE_SEEK => Self::EINVAL, + winerror::ERROR_DIRECTORY => Self::ENOTDIR, + winerror::ERROR_ALREADY_EXISTS => Self::EEXIST, _ => Self::ENOTSUP, } } diff --git a/crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs.rs b/crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs.rs index 173b8aa2b2..cc157e7882 100644 --- a/crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs.rs @@ -16,6 +16,7 @@ use std::io::{self, Seek, SeekFrom}; use std::os::windows::fs::{FileExt, OpenOptionsExt}; use std::os::windows::prelude::{AsRawHandle, FromRawHandle}; use std::path::{Path, PathBuf}; +use winapi::shared::winerror; use winx::file::{AccessMode, CreationDisposition, FileModeInformation, Flags}; fn read_at(mut file: &File, buf: &mut [u8], offset: u64) -> io::Result { @@ -149,20 +150,18 @@ pub(crate) fn path_open( return Err(Error::ENOTDIR); } } - Err(e) => match e.raw_os_error() { - Some(e) => { - use winx::winerror::WinError; - log::debug!("path_open at symlink_metadata error code={:?}", e); - let e = WinError::from_u32(e as u32); + Err(err) => match err.raw_os_error() { + Some(code) => { + log::debug!("path_open at symlink_metadata error code={:?}", code); - if e != WinError::ERROR_FILE_NOT_FOUND { - return Err(e.into()); + if code as u32 != winerror::ERROR_FILE_NOT_FOUND { + return Err(err.into()); } // file not found, let it proceed to actually // trying to open it } None => { - log::debug!("Inconvertible OS error: {}", e); + log::debug!("Inconvertible OS error: {}", err); return Err(Error::EIO); } }, @@ -388,27 +387,28 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul } // TODO handle symlinks - - fs::rename(&old_path, &new_path).or_else(|e| match e.raw_os_error() { - Some(e) => { - use winx::winerror::WinError; - - log::debug!("path_rename at rename error code={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_ACCESS_DENIED => { + let err = match fs::rename(&old_path, &new_path) { + Ok(()) => return Ok(()), + Err(e) => e, + }; + match err.raw_os_error() { + Some(code) => { + log::debug!("path_rename at rename error code={:?}", code); + match code as u32 { + winerror::ERROR_ACCESS_DENIED => { // So most likely dealing with new_path == dir. // Eliminate case old_path == file first. if old_path.is_file() { - Err(Error::EISDIR) + return Err(Error::EISDIR); } else { // Ok, let's try removing an empty dir at new_path if it exists // and is a nonempty dir. - fs::remove_dir(&new_path) - .and_then(|()| fs::rename(old_path, new_path)) - .map_err(Into::into) + fs::remove_dir(&new_path)?; + fs::rename(old_path, new_path)?; + return Ok(()); } } - WinError::ERROR_INVALID_NAME => { + winerror::ERROR_INVALID_NAME => { // If source contains trailing slashes, check if we are dealing with // a file instead of a dir, and if so, throw ENOTDIR. if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? { @@ -416,16 +416,17 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul return Err(Error::ENOTDIR); } } - Err(WinError::ERROR_INVALID_NAME.into()) } - e => Err(e.into()), + _ => {} } + + Err(err.into()) } None => { - log::debug!("Inconvertible OS error: {}", e); + log::debug!("Inconvertible OS error: {}", err); Err(Error::EIO) } - }) + } } pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result { @@ -458,52 +459,51 @@ pub(crate) fn path_filestat_set_times( pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { use std::os::windows::fs::{symlink_dir, symlink_file}; - use winx::winerror::WinError; let old_path = concatenate(resolved.dirfd(), Path::new(old_path))?; let new_path = resolved.concatenate()?; // try creating a file symlink - symlink_file(&old_path, &new_path).or_else(|e| { - match e.raw_os_error() { - Some(e) => { - log::debug!("path_symlink at symlink_file error code={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_NOT_A_REPARSE_POINT => { - // try creating a dir symlink instead - symlink_dir(old_path, new_path).map_err(Into::into) - } - WinError::ERROR_ACCESS_DENIED => { - // does the target exist? - if new_path.exists() { - Err(Error::EEXIST) - } else { - Err(WinError::ERROR_ACCESS_DENIED.into()) - } - } - WinError::ERROR_INVALID_NAME => { - // does the target without trailing slashes exist? - if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? { - if path.exists() { - return Err(Error::EEXIST); - } - } - Err(WinError::ERROR_INVALID_NAME.into()) - } - e => Err(e.into()), + let err = match symlink_file(&old_path, &new_path) { + Ok(()) => return Ok(()), + Err(e) => e, + }; + match err.raw_os_error() { + Some(code) => { + log::debug!("path_symlink at symlink_file error code={:?}", code); + match code as u32 { + winerror::ERROR_NOT_A_REPARSE_POINT => { + // try creating a dir symlink instead + return symlink_dir(old_path, new_path).map_err(Into::into); } + winerror::ERROR_ACCESS_DENIED => { + // does the target exist? + if new_path.exists() { + return Err(Error::EEXIST); + } + } + winerror::ERROR_INVALID_NAME => { + // does the target without trailing slashes exist? + if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? { + if path.exists() { + return Err(Error::EEXIST); + } + } + } + _ => {} } - None => { - log::debug!("Inconvertible OS error: {}", e); - Err(Error::EIO) - } + + Err(err.into()) } - }) + None => { + log::debug!("Inconvertible OS error: {}", err); + Err(Error::EIO) + } + } } pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { use std::fs; - use winx::winerror::WinError; let path = resolved.concatenate()?; let file_type = path @@ -516,24 +516,25 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { // // [std::os::windows::fs::FileTypeExt]: https://doc.rust-lang.org/std/os/windows/fs/trait.FileTypeExt.html if file_type.is_symlink() { - fs::remove_file(&path).or_else(|e| { - match e.raw_os_error() { - Some(e) => { - log::debug!("path_unlink_file at symlink_file error code={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_ACCESS_DENIED => { - // try unlinking a dir symlink instead - fs::remove_dir(path).map_err(Into::into) - } - e => Err(e.into()), - } - } - None => { - log::debug!("Inconvertible OS error: {}", e); - Err(Error::EIO) + let err = match fs::remove_file(&path) { + Ok(()) => return Ok(()), + Err(e) => e, + }; + match err.raw_os_error() { + Some(code) => { + log::debug!("path_unlink_file at symlink_file error code={:?}", code); + if code as u32 == winerror::ERROR_ACCESS_DENIED { + // try unlinking a dir symlink instead + return fs::remove_dir(path).map_err(Into::into); } + + Err(err.into()) } - }) + None => { + log::debug!("Inconvertible OS error: {}", err); + Err(Error::EIO) + } + } } else if file_type.is_dir() { Err(Error::EISDIR) } else if file_type.is_file() { diff --git a/crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs_helpers.rs b/crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs_helpers.rs index f05721a8dd..a89a37f6e0 100644 --- a/crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs_helpers.rs +++ b/crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs_helpers.rs @@ -5,6 +5,7 @@ use std::ffi::{OsStr, OsString}; use std::fs::File; use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::path::{Path, PathBuf}; +use winapi::shared::winerror; pub(crate) trait PathGetExt { fn concatenate(&self) -> Result; @@ -49,34 +50,30 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result { use std::fs::OpenOptions; use std::os::windows::fs::OpenOptionsExt; use winx::file::Flags; - use winx::winerror::WinError; let path = concatenate(dirfd, Path::new(path))?; - OpenOptions::new() + let err = match OpenOptions::new() .read(true) .custom_flags(Flags::FILE_FLAG_BACKUP_SEMANTICS.bits()) .open(&path) - .map_err(|e| match e.raw_os_error() { - Some(e) => { - log::debug!("openat error={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_INVALID_NAME => Error::ENOTDIR, - e => e.into(), - } - } - None => { - log::debug!("Inconvertible OS error: {}", e); - Error::EIO - } - }) + { + Ok(file) => return Ok(file), + Err(e) => e, + }; + if let Some(code) = err.raw_os_error() { + log::debug!("openat error={:?}", code); + if code as u32 == winerror::ERROR_INVALID_NAME { + return Err(Error::ENOTDIR); + } + } + Err(err.into()) } pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result { use winx::file::get_file_path; - use winx::winerror::WinError; let path = concatenate(dirfd, Path::new(s_path))?; - match path.read_link() { + let err = match path.read_link() { Ok(target_path) => { // since on Windows we are effectively emulating 'at' syscalls // we need to strip the prefix from the absolute path @@ -84,37 +81,27 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result { // of dealing with absolute paths let dir_path = get_file_path(dirfd)?; let dir_path = PathBuf::from(strip_extended_prefix(dir_path)); - target_path + let target_path = target_path .strip_prefix(dir_path) - .map_err(|_| Error::ENOTCAPABLE) - .and_then(|path| path.to_str().map(String::from).ok_or(Error::EILSEQ)) + .map_err(|_| Error::ENOTCAPABLE)?; + let target_path = target_path.to_str().ok_or(Error::EILSEQ)?; + return Ok(target_path.to_owned()); } - Err(e) => match e.raw_os_error() { - Some(e) => { - log::debug!("readlinkat error={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_INVALID_NAME => { - if s_path.ends_with('/') { - // strip "/" and check if exists - let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?; - if path.exists() && !path.is_dir() { - Err(Error::ENOTDIR) - } else { - Err(Error::ENOENT) - } - } else { - Err(Error::ENOENT) - } - } - e => Err(e.into()), + Err(e) => e, + }; + if let Some(code) = err.raw_os_error() { + log::debug!("readlinkat error={:?}", code); + if code as u32 == winerror::ERROR_INVALID_NAME { + if s_path.ends_with('/') { + // strip "/" and check if exists + let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?; + if path.exists() && !path.is_dir() { + return Err(Error::ENOTDIR); } } - None => { - log::debug!("Inconvertible OS error: {}", e); - Err(Error::EIO) - } - }, + } } + Err(err.into()) } pub(crate) fn strip_extended_prefix>(path: P) -> OsString { diff --git a/crates/wasi-common/src/sys/windows/host_impl.rs b/crates/wasi-common/src/sys/windows/host_impl.rs index ba6717e5e6..ad5ecd4483 100644 --- a/crates/wasi-common/src/sys/windows/host_impl.rs +++ b/crates/wasi-common/src/sys/windows/host_impl.rs @@ -7,42 +7,35 @@ use std::fs::{self, File}; use std::io; use std::os::windows::ffi::OsStrExt; use std::time::{SystemTime, UNIX_EPOCH}; -use winx::winerror::WinError; +use winapi::shared::winerror; impl FromRawOsError for Error { fn from_raw_os_error(code: i32) -> Self { - Self::from(WinError::from_u32(code as u32)) - } -} - -impl From for Error { - fn from(err: WinError) -> Self { // TODO: implement error mapping between Windows and WASI - use winx::winerror::WinError::*; - match err { - ERROR_SUCCESS => Self::ESUCCESS, - ERROR_BAD_ENVIRONMENT => Self::E2BIG, - ERROR_FILE_NOT_FOUND => Self::ENOENT, - ERROR_PATH_NOT_FOUND => Self::ENOENT, - ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE, - ERROR_ACCESS_DENIED => Self::EACCES, - ERROR_SHARING_VIOLATION => Self::EACCES, - ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping? - ERROR_INVALID_HANDLE => Self::EBADF, - ERROR_INVALID_NAME => Self::ENOENT, - ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM, - ERROR_OUTOFMEMORY => Self::ENOMEM, - ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY, - ERROR_NOT_READY => Self::EBUSY, - ERROR_BUSY => Self::EBUSY, - ERROR_NOT_SUPPORTED => Self::ENOTSUP, - ERROR_FILE_EXISTS => Self::EEXIST, - ERROR_BROKEN_PIPE => Self::EPIPE, - ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG, - ERROR_NOT_A_REPARSE_POINT => Self::EINVAL, - ERROR_NEGATIVE_SEEK => Self::EINVAL, - ERROR_DIRECTORY => Self::ENOTDIR, - ERROR_ALREADY_EXISTS => Self::EEXIST, + match code as u32 { + winerror::ERROR_SUCCESS => Self::ESUCCESS, + winerror::ERROR_BAD_ENVIRONMENT => Self::E2BIG, + winerror::ERROR_FILE_NOT_FOUND => Self::ENOENT, + winerror::ERROR_PATH_NOT_FOUND => Self::ENOENT, + winerror::ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE, + winerror::ERROR_ACCESS_DENIED => Self::EACCES, + winerror::ERROR_SHARING_VIOLATION => Self::EACCES, + winerror::ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping? + winerror::ERROR_INVALID_HANDLE => Self::EBADF, + winerror::ERROR_INVALID_NAME => Self::ENOENT, + winerror::ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM, + winerror::ERROR_OUTOFMEMORY => Self::ENOMEM, + winerror::ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY, + winerror::ERROR_NOT_READY => Self::EBUSY, + winerror::ERROR_BUSY => Self::EBUSY, + winerror::ERROR_NOT_SUPPORTED => Self::ENOTSUP, + winerror::ERROR_FILE_EXISTS => Self::EEXIST, + winerror::ERROR_BROKEN_PIPE => Self::EPIPE, + winerror::ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG, + winerror::ERROR_NOT_A_REPARSE_POINT => Self::EINVAL, + winerror::ERROR_NEGATIVE_SEEK => Self::EINVAL, + winerror::ERROR_DIRECTORY => Self::ENOTDIR, + winerror::ERROR_ALREADY_EXISTS => Self::EEXIST, _ => Self::ENOTSUP, } } 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 b8044d1bd5..a6e86650e6 100644 --- a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs @@ -16,6 +16,7 @@ use std::io::{self, Seek, SeekFrom}; use std::os::windows::fs::{FileExt, OpenOptionsExt}; use std::os::windows::prelude::{AsRawHandle, FromRawHandle}; use std::path::{Path, PathBuf}; +use winapi::shared::winerror; use winx::file::{AccessMode, CreationDisposition, FileModeInformation, Flags}; fn read_at(mut file: &File, buf: &mut [u8], offset: u64) -> io::Result { @@ -178,20 +179,18 @@ pub(crate) fn path_open( return Err(Error::ENOTDIR); } } - Err(e) => match e.raw_os_error() { - Some(e) => { - use winx::winerror::WinError; - log::debug!("path_open at symlink_metadata error code={:?}", e); - let e = WinError::from_u32(e as u32); + Err(err) => match err.raw_os_error() { + Some(code) => { + log::debug!("path_open at symlink_metadata error code={:?}", code); - if e != WinError::ERROR_FILE_NOT_FOUND { - return Err(e.into()); + if code as u32 != winerror::ERROR_FILE_NOT_FOUND { + return Err(err.into()); } // file not found, let it proceed to actually // trying to open it } None => { - log::debug!("Inconvertible OS error: {}", e); + log::debug!("Inconvertible OS error: {}", err); return Err(Error::EIO); } }, @@ -428,27 +427,28 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul } // TODO handle symlinks - - fs::rename(&old_path, &new_path).or_else(|e| match e.raw_os_error() { - Some(e) => { - use winx::winerror::WinError; - - log::debug!("path_rename at rename error code={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_ACCESS_DENIED => { + let err = match fs::rename(&old_path, &new_path) { + Ok(()) => return Ok(()), + Err(e) => e, + }; + match err.raw_os_error() { + Some(code) => { + log::debug!("path_rename at rename error code={:?}", code); + match code as u32 { + winerror::ERROR_ACCESS_DENIED => { // So most likely dealing with new_path == dir. // Eliminate case old_path == file first. if old_path.is_file() { - Err(Error::EISDIR) + return Err(Error::EISDIR); } else { // Ok, let's try removing an empty dir at new_path if it exists // and is a nonempty dir. - fs::remove_dir(&new_path) - .and_then(|()| fs::rename(old_path, new_path)) - .map_err(Into::into) + fs::remove_dir(&new_path)?; + fs::rename(old_path, new_path)?; + return Ok(()); } } - WinError::ERROR_INVALID_NAME => { + winerror::ERROR_INVALID_NAME => { // If source contains trailing slashes, check if we are dealing with // a file instead of a dir, and if so, throw ENOTDIR. if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? { @@ -456,16 +456,17 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul return Err(Error::ENOTDIR); } } - Err(WinError::ERROR_INVALID_NAME.into()) } - e => Err(e.into()), + _ => {} } + + Err(err.into()) } None => { - log::debug!("Inconvertible OS error: {}", e); + log::debug!("Inconvertible OS error: {}", err); Err(Error::EIO) } - }) + } } pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result { @@ -499,52 +500,51 @@ pub(crate) fn path_filestat_set_times( pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { use std::os::windows::fs::{symlink_dir, symlink_file}; - use winx::winerror::WinError; let old_path = concatenate(&resolved.dirfd().as_os_handle(), Path::new(old_path))?; let new_path = resolved.concatenate()?; // try creating a file symlink - symlink_file(&old_path, &new_path).or_else(|e| { - match e.raw_os_error() { - Some(e) => { - log::debug!("path_symlink at symlink_file error code={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_NOT_A_REPARSE_POINT => { - // try creating a dir symlink instead - symlink_dir(old_path, new_path).map_err(Into::into) - } - WinError::ERROR_ACCESS_DENIED => { - // does the target exist? - if new_path.exists() { - Err(Error::EEXIST) - } else { - Err(WinError::ERROR_ACCESS_DENIED.into()) - } - } - WinError::ERROR_INVALID_NAME => { - // does the target without trailing slashes exist? - if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? { - if path.exists() { - return Err(Error::EEXIST); - } - } - Err(WinError::ERROR_INVALID_NAME.into()) - } - e => Err(e.into()), + let err = match symlink_file(&old_path, &new_path) { + Ok(()) => return Ok(()), + Err(e) => e, + }; + match err.raw_os_error() { + Some(code) => { + log::debug!("path_symlink at symlink_file error code={:?}", code); + match code as u32 { + winerror::ERROR_NOT_A_REPARSE_POINT => { + // try creating a dir symlink instead + return symlink_dir(old_path, new_path).map_err(Into::into); } + winerror::ERROR_ACCESS_DENIED => { + // does the target exist? + if new_path.exists() { + return Err(Error::EEXIST); + } + } + winerror::ERROR_INVALID_NAME => { + // does the target without trailing slashes exist? + if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? { + if path.exists() { + return Err(Error::EEXIST); + } + } + } + _ => {} } - None => { - log::debug!("Inconvertible OS error: {}", e); - Err(Error::EIO) - } + + Err(err.into()) } - }) + None => { + log::debug!("Inconvertible OS error: {}", err); + Err(Error::EIO) + } + } } pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { use std::fs; - use winx::winerror::WinError; let path = resolved.concatenate()?; let file_type = path @@ -557,24 +557,25 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { // // [std::os::windows::fs::FileTypeExt]: https://doc.rust-lang.org/std/os/windows/fs/trait.FileTypeExt.html if file_type.is_symlink() { - fs::remove_file(&path).or_else(|e| { - match e.raw_os_error() { - Some(e) => { - log::debug!("path_unlink_file at symlink_file error code={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_ACCESS_DENIED => { - // try unlinking a dir symlink instead - fs::remove_dir(path).map_err(Into::into) - } - e => Err(e.into()), - } - } - None => { - log::debug!("Inconvertible OS error: {}", e); - Err(Error::EIO) + let err = match fs::remove_file(&path) { + Ok(()) => return Ok(()), + Err(e) => e, + }; + match err.raw_os_error() { + Some(code) => { + log::debug!("path_unlink_file at symlink_file error code={:?}", code); + if code as u32 == winerror::ERROR_ACCESS_DENIED { + // try unlinking a dir symlink instead + return fs::remove_dir(path).map_err(Into::into); } + + Err(err.into()) } - }) + None => { + log::debug!("Inconvertible OS error: {}", err); + Err(Error::EIO) + } + } } else if file_type.is_dir() { Err(Error::EISDIR) } else if file_type.is_file() { diff --git a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs_helpers.rs b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs_helpers.rs index c390596436..df77548ce9 100644 --- a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs_helpers.rs +++ b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs_helpers.rs @@ -6,6 +6,7 @@ use std::ffi::{OsStr, OsString}; use std::fs::File; use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::path::{Path, PathBuf}; +use winapi::shared::winerror; pub(crate) trait PathGetExt { fn concatenate(&self) -> Result; @@ -58,34 +59,30 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result { use std::fs::OpenOptions; use std::os::windows::fs::OpenOptionsExt; use winx::file::Flags; - use winx::winerror::WinError; let path = concatenate(dirfd, Path::new(path))?; - OpenOptions::new() + let err = match OpenOptions::new() .read(true) .custom_flags(Flags::FILE_FLAG_BACKUP_SEMANTICS.bits()) .open(&path) - .map_err(|e| match e.raw_os_error() { - Some(e) => { - log::debug!("openat error={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_INVALID_NAME => Error::ENOTDIR, - e => e.into(), - } - } - None => { - log::debug!("Inconvertible OS error: {}", e); - Error::EIO - } - }) + { + Ok(file) => return Ok(file), + Err(e) => e, + }; + if let Some(code) = err.raw_os_error() { + log::debug!("openat error={:?}", code); + if code as u32 == winerror::ERROR_INVALID_NAME { + return Err(Error::ENOTDIR); + } + } + Err(err.into()) } pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result { use winx::file::get_file_path; - use winx::winerror::WinError; let path = concatenate(dirfd, Path::new(s_path))?; - match path.read_link() { + let err = match path.read_link() { Ok(target_path) => { // since on Windows we are effectively emulating 'at' syscalls // we need to strip the prefix from the absolute path @@ -93,37 +90,27 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result { // of dealing with absolute paths let dir_path = get_file_path(dirfd)?; let dir_path = PathBuf::from(strip_extended_prefix(dir_path)); - target_path + let target_path = target_path .strip_prefix(dir_path) - .map_err(|_| Error::ENOTCAPABLE) - .and_then(|path| path.to_str().map(String::from).ok_or(Error::EILSEQ)) + .map_err(|_| Error::ENOTCAPABLE)?; + let target_path = target_path.to_str().ok_or(Error::EILSEQ)?; + return Ok(target_path.to_owned()); } - Err(e) => match e.raw_os_error() { - Some(e) => { - log::debug!("readlinkat error={:?}", e); - match WinError::from_u32(e as u32) { - WinError::ERROR_INVALID_NAME => { - if s_path.ends_with('/') { - // strip "/" and check if exists - let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?; - if path.exists() && !path.is_dir() { - Err(Error::ENOTDIR) - } else { - Err(Error::ENOENT) - } - } else { - Err(Error::ENOENT) - } - } - e => Err(e.into()), + Err(e) => e, + }; + if let Some(code) = err.raw_os_error() { + log::debug!("readlinkat error={:?}", code); + if code as u32 == winerror::ERROR_INVALID_NAME { + if s_path.ends_with('/') { + // strip "/" and check if exists + let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?; + if path.exists() && !path.is_dir() { + return Err(Error::ENOTDIR); } } - None => { - log::debug!("Inconvertible OS error: {}", e); - Err(Error::EIO) - } - }, + } } + Err(err.into()) } pub(crate) fn strip_extended_prefix>(path: P) -> OsString { diff --git a/crates/wasi-common/winx/src/file.rs b/crates/wasi-common/winx/src/file.rs index 2a1bee7cfd..d3639d9f97 100644 --- a/crates/wasi-common/winx/src/file.rs +++ b/crates/wasi-common/winx/src/file.rs @@ -4,16 +4,15 @@ use crate::ntdll::{ NtQueryInformationFile, RtlNtStatusToDosError, FILE_ACCESS_INFORMATION, FILE_INFORMATION_CLASS, FILE_MODE_INFORMATION, IO_STATUS_BLOCK, }; -use crate::{winerror, Result}; use bitflags::bitflags; use cvt::cvt; use std::ffi::{c_void, OsString}; use std::fs::File; -use std::io; +use std::io::{Error, Result}; use std::os::windows::prelude::{AsRawHandle, OsStringExt, RawHandle}; use winapi::shared::{ minwindef::{self, DWORD}, - ntstatus, + ntstatus, winerror, }; use winapi::um::{fileapi, fileapi::GetFileType, minwinbase, winbase, winnt}; @@ -57,8 +56,8 @@ impl FileType { pub unsafe fn get_file_type(handle: RawHandle) -> Result { let file_type = FileType(GetFileType(handle)); - let err = winerror::WinError::last(); - if file_type.is_unknown() && err != winerror::WinError::ERROR_SUCCESS { + let err = Error::last_os_error(); + if file_type.is_unknown() && err.raw_os_error().unwrap() as u32 != winerror::ERROR_SUCCESS { Err(err) } else { Ok(file_type) @@ -341,23 +340,20 @@ pub fn get_file_path(file: &File) -> Result { let handle = file.as_raw_handle(); let read_len = - unsafe { GetFinalPathNameByHandleW(handle, raw_path.as_mut_ptr(), WIDE_MAX_PATH, 0) }; - - if read_len == 0 { - // failed to read - return Err(winerror::WinError::last()); - } + cvt(unsafe { GetFinalPathNameByHandleW(handle, raw_path.as_mut_ptr(), WIDE_MAX_PATH, 0) })?; // obtain a slice containing the written bytes, and check for it being too long // (practically probably impossible) let written_bytes = raw_path .get(..read_len as usize) - .ok_or(winerror::WinError::ERROR_BUFFER_OVERFLOW)?; + .ok_or(Error::from_raw_os_error( + winerror::ERROR_BUFFER_OVERFLOW as i32, + ))?; Ok(OsString::from_wide(written_bytes)) } -pub fn get_fileinfo(file: &File) -> io::Result { +pub fn get_fileinfo(file: &File) -> Result { use fileapi::{GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION}; use std::mem; @@ -371,7 +367,7 @@ pub fn get_fileinfo(file: &File) -> io::Result io::Result { +pub fn change_time(file: &File) -> Result { use fileapi::FILE_BASIC_INFO; use minwinbase::FileBasicInfo; use std::mem; @@ -407,7 +403,9 @@ pub fn query_access_information(handle: RawHandle) -> Result { ); if status != ntstatus::STATUS_SUCCESS { - return Err(winerror::WinError::from_u32(RtlNtStatusToDosError(status))); + return Err(Error::from_raw_os_error( + RtlNtStatusToDosError(status) as i32 + )); } } @@ -428,7 +426,9 @@ pub fn query_mode_information(handle: RawHandle) -> Result ); if status != ntstatus::STATUS_SUCCESS { - return Err(winerror::WinError::from_u32(RtlNtStatusToDosError(status))); + return Err(Error::from_raw_os_error( + RtlNtStatusToDosError(status) as i32 + )); } } @@ -448,7 +448,7 @@ pub fn reopen_file(handle: RawHandle, access_mode: AccessMode, flags: Flags) -> }; if new_handle == winapi::um::handleapi::INVALID_HANDLE_VALUE { - return Err(winerror::WinError::last()); + return Err(Error::last_os_error()); } Ok(new_handle) diff --git a/crates/wasi-common/winx/src/lib.rs b/crates/wasi-common/winx/src/lib.rs index 779447e786..4df1e5bbe9 100644 --- a/crates/wasi-common/winx/src/lib.rs +++ b/crates/wasi-common/winx/src/lib.rs @@ -24,8 +24,3 @@ pub mod file; mod ntdll; pub mod time; -pub mod winerror; - -use winerror::WinError; - -pub type Result = std::result::Result; diff --git a/crates/wasi-common/winx/src/time.rs b/crates/wasi-common/winx/src/time.rs index 28803e1fb6..cb3e7918c8 100644 --- a/crates/wasi-common/winx/src/time.rs +++ b/crates/wasi-common/winx/src/time.rs @@ -1,7 +1,8 @@ use cvt::cvt; +use std::io::Result; use winapi::um::{profileapi::QueryPerformanceFrequency, winnt::LARGE_INTEGER}; -pub fn perf_counter_frequency() -> std::io::Result { +pub fn perf_counter_frequency() -> Result { unsafe { let mut frequency: LARGE_INTEGER = std::mem::zeroed(); cvt(QueryPerformanceFrequency(&mut frequency))?; diff --git a/crates/wasi-common/winx/src/winerror.rs b/crates/wasi-common/winx/src/winerror.rs deleted file mode 100644 index bc4e39b331..0000000000 --- a/crates/wasi-common/winx/src/winerror.rs +++ /dev/null @@ -1,127 +0,0 @@ -#![allow(non_camel_case_types)] -use winapi::shared::winerror; -use winapi::um::errhandlingapi::GetLastError; - -macro_rules! win_error_expand { - { - $( - #[doc=$doc:literal] - $error:ident, - )* - } => { - /// Wraps WINAPI error code as enum. - #[derive(Debug, Clone, Copy, Eq, PartialEq)] - #[repr(u32)] - pub enum WinError { - /// Unknown error occurred. - UnknownError = std::u32::MAX, - $( - #[doc=$doc] - $error = winerror::$error, - )* - } - - fn desc(err: WinError) -> &'static str { - use WinError::*; - match err { - UnknownError => r" Unknown error occurred.", - $($error => $doc,)* - } - } - - fn from_u32(err: u32) -> WinError { - use WinError::*; - match err { - $(winerror::$error => $error,)* - _ => UnknownError, - } - } - } -} - -win_error_expand! { - /// The operation completed successfully. - ERROR_SUCCESS, - /// The system cannot find the file specified. - ERROR_FILE_NOT_FOUND, - /// The system cannot find the path specified. - ERROR_PATH_NOT_FOUND, - /// The system cannot open the file. - ERROR_TOO_MANY_OPEN_FILES, - /// Access is denied. - ERROR_ACCESS_DENIED, - /// The handle is invalid. - ERROR_INVALID_HANDLE, - /// Not enough storage is available to process this command. - ERROR_NOT_ENOUGH_MEMORY, - /// The environment is incorrect. - ERROR_BAD_ENVIRONMENT, - /// Not enough storage is available to complete this operation. - ERROR_OUTOFMEMORY, - /// The device is not ready. - ERROR_NOT_READY, - /// The request is not supported. - ERROR_NOT_SUPPORTED, - /// The file exists. - ERROR_FILE_EXISTS, - /// The pipe has been ended. - ERROR_BROKEN_PIPE, - /// The file name is too long. - ERROR_BUFFER_OVERFLOW, - /// The directory is not empty. - ERROR_DIR_NOT_EMPTY, - /// The volume label you entered exceeds the label character limit of the destination file system. - ERROR_LABEL_TOO_LONG, - /// The requested resource is in use. - ERROR_BUSY, - /// The file name, directory name, or volume label syntax is incorrect. - ERROR_INVALID_NAME, - /// The process cannot access the file because it is being used by another process. - ERROR_SHARING_VIOLATION, - /// A required privilege is not held by the client. - ERROR_PRIVILEGE_NOT_HELD, - /// The file or directory is not a reparse point. - ERROR_NOT_A_REPARSE_POINT, - /// An attempt was made to move the file pointer before the beginning of the file. - ERROR_NEGATIVE_SEEK, - /// The directory name is invalid. - ERROR_DIRECTORY, - /// Cannot create a file when that file already exists. - ERROR_ALREADY_EXISTS, -} - -impl WinError { - /// Returns the last error as WinError. - pub fn last() -> Self { - Self::from_u32(unsafe { GetLastError() }) - } - - /// Constructs WinError from error code. - pub fn from_u32(err: u32) -> Self { - from_u32(err) - } - - /// Returns error's description string. This description matches - /// the docs for the error. - pub fn desc(self) -> &'static str { - desc(self) - } -} - -impl std::error::Error for WinError { - fn description(&self) -> &str { - self.desc() - } -} - -impl std::fmt::Display for WinError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}: {}", self, self.desc()) - } -} - -impl From for std::io::Error { - fn from(err: WinError) -> Self { - Self::from_raw_os_error(err as i32) - } -}