[wasi-common]: winx now returns io::Error directly (#1243)
* Winx now returns io::Error This commit is a spiritual follower of #1242 in the sense that it adjusts `winx` to also return `io::Error` directly rather than tossing a custom error type here and there. * Adapt wasi-common to changes in winx * Run cargo fmt * Swap overly big map_err with explicit match
This commit is contained in:
@@ -12,43 +12,36 @@ use std::io;
|
|||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::os::windows::fs::OpenOptionsExt;
|
use std::os::windows::fs::OpenOptionsExt;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
use winapi::shared::winerror;
|
||||||
use winx::file::{AccessMode, Attributes, CreationDisposition, Flags};
|
use winx::file::{AccessMode, Attributes, CreationDisposition, Flags};
|
||||||
use winx::winerror::WinError;
|
|
||||||
|
|
||||||
impl FromRawOsError for Error {
|
impl FromRawOsError for Error {
|
||||||
fn from_raw_os_error(code: i32) -> Self {
|
fn from_raw_os_error(code: i32) -> Self {
|
||||||
Self::from(WinError::from_u32(code as u32))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WinError> for Error {
|
|
||||||
fn from(err: WinError) -> Self {
|
|
||||||
// TODO: implement error mapping between Windows and WASI
|
// TODO: implement error mapping between Windows and WASI
|
||||||
use winx::winerror::WinError::*;
|
match code as u32 {
|
||||||
match err {
|
winerror::ERROR_SUCCESS => Self::ESUCCESS,
|
||||||
ERROR_SUCCESS => Self::ESUCCESS,
|
winerror::ERROR_BAD_ENVIRONMENT => Self::E2BIG,
|
||||||
ERROR_BAD_ENVIRONMENT => Self::E2BIG,
|
winerror::ERROR_FILE_NOT_FOUND => Self::ENOENT,
|
||||||
ERROR_FILE_NOT_FOUND => Self::ENOENT,
|
winerror::ERROR_PATH_NOT_FOUND => Self::ENOENT,
|
||||||
ERROR_PATH_NOT_FOUND => Self::ENOENT,
|
winerror::ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE,
|
||||||
ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE,
|
winerror::ERROR_ACCESS_DENIED => Self::EACCES,
|
||||||
ERROR_ACCESS_DENIED => Self::EACCES,
|
winerror::ERROR_SHARING_VIOLATION => Self::EACCES,
|
||||||
ERROR_SHARING_VIOLATION => Self::EACCES,
|
winerror::ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping?
|
||||||
ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping?
|
winerror::ERROR_INVALID_HANDLE => Self::EBADF,
|
||||||
ERROR_INVALID_HANDLE => Self::EBADF,
|
winerror::ERROR_INVALID_NAME => Self::ENOENT,
|
||||||
ERROR_INVALID_NAME => Self::ENOENT,
|
winerror::ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM,
|
||||||
ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM,
|
winerror::ERROR_OUTOFMEMORY => Self::ENOMEM,
|
||||||
ERROR_OUTOFMEMORY => Self::ENOMEM,
|
winerror::ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY,
|
||||||
ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY,
|
winerror::ERROR_NOT_READY => Self::EBUSY,
|
||||||
ERROR_NOT_READY => Self::EBUSY,
|
winerror::ERROR_BUSY => Self::EBUSY,
|
||||||
ERROR_BUSY => Self::EBUSY,
|
winerror::ERROR_NOT_SUPPORTED => Self::ENOTSUP,
|
||||||
ERROR_NOT_SUPPORTED => Self::ENOTSUP,
|
winerror::ERROR_FILE_EXISTS => Self::EEXIST,
|
||||||
ERROR_FILE_EXISTS => Self::EEXIST,
|
winerror::ERROR_BROKEN_PIPE => Self::EPIPE,
|
||||||
ERROR_BROKEN_PIPE => Self::EPIPE,
|
winerror::ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG,
|
||||||
ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG,
|
winerror::ERROR_NOT_A_REPARSE_POINT => Self::EINVAL,
|
||||||
ERROR_NOT_A_REPARSE_POINT => Self::EINVAL,
|
winerror::ERROR_NEGATIVE_SEEK => Self::EINVAL,
|
||||||
ERROR_NEGATIVE_SEEK => Self::EINVAL,
|
winerror::ERROR_DIRECTORY => Self::ENOTDIR,
|
||||||
ERROR_DIRECTORY => Self::ENOTDIR,
|
winerror::ERROR_ALREADY_EXISTS => Self::EEXIST,
|
||||||
ERROR_ALREADY_EXISTS => Self::EEXIST,
|
|
||||||
_ => Self::ENOTSUP,
|
_ => Self::ENOTSUP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use std::io::{self, Seek, SeekFrom};
|
|||||||
use std::os::windows::fs::{FileExt, OpenOptionsExt};
|
use std::os::windows::fs::{FileExt, OpenOptionsExt};
|
||||||
use std::os::windows::prelude::{AsRawHandle, FromRawHandle};
|
use std::os::windows::prelude::{AsRawHandle, FromRawHandle};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use winapi::shared::winerror;
|
||||||
use winx::file::{AccessMode, CreationDisposition, FileModeInformation, Flags};
|
use winx::file::{AccessMode, CreationDisposition, FileModeInformation, Flags};
|
||||||
|
|
||||||
fn read_at(mut file: &File, buf: &mut [u8], offset: u64) -> io::Result<usize> {
|
fn read_at(mut file: &File, buf: &mut [u8], offset: u64) -> io::Result<usize> {
|
||||||
@@ -149,20 +150,18 @@ pub(crate) fn path_open(
|
|||||||
return Err(Error::ENOTDIR);
|
return Err(Error::ENOTDIR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => match e.raw_os_error() {
|
Err(err) => match err.raw_os_error() {
|
||||||
Some(e) => {
|
Some(code) => {
|
||||||
use winx::winerror::WinError;
|
log::debug!("path_open at symlink_metadata error code={:?}", code);
|
||||||
log::debug!("path_open at symlink_metadata error code={:?}", e);
|
|
||||||
let e = WinError::from_u32(e as u32);
|
|
||||||
|
|
||||||
if e != WinError::ERROR_FILE_NOT_FOUND {
|
if code as u32 != winerror::ERROR_FILE_NOT_FOUND {
|
||||||
return Err(e.into());
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
// file not found, let it proceed to actually
|
// file not found, let it proceed to actually
|
||||||
// trying to open it
|
// trying to open it
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
log::debug!("Inconvertible OS error: {}", err);
|
||||||
return Err(Error::EIO);
|
return Err(Error::EIO);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -388,27 +387,28 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO handle symlinks
|
// TODO handle symlinks
|
||||||
|
let err = match fs::rename(&old_path, &new_path) {
|
||||||
fs::rename(&old_path, &new_path).or_else(|e| match e.raw_os_error() {
|
Ok(()) => return Ok(()),
|
||||||
Some(e) => {
|
Err(e) => e,
|
||||||
use winx::winerror::WinError;
|
};
|
||||||
|
match err.raw_os_error() {
|
||||||
log::debug!("path_rename at rename error code={:?}", e);
|
Some(code) => {
|
||||||
match WinError::from_u32(e as u32) {
|
log::debug!("path_rename at rename error code={:?}", code);
|
||||||
WinError::ERROR_ACCESS_DENIED => {
|
match code as u32 {
|
||||||
|
winerror::ERROR_ACCESS_DENIED => {
|
||||||
// So most likely dealing with new_path == dir.
|
// So most likely dealing with new_path == dir.
|
||||||
// Eliminate case old_path == file first.
|
// Eliminate case old_path == file first.
|
||||||
if old_path.is_file() {
|
if old_path.is_file() {
|
||||||
Err(Error::EISDIR)
|
return Err(Error::EISDIR);
|
||||||
} else {
|
} else {
|
||||||
// Ok, let's try removing an empty dir at new_path if it exists
|
// Ok, let's try removing an empty dir at new_path if it exists
|
||||||
// and is a nonempty dir.
|
// and is a nonempty dir.
|
||||||
fs::remove_dir(&new_path)
|
fs::remove_dir(&new_path)?;
|
||||||
.and_then(|()| fs::rename(old_path, new_path))
|
fs::rename(old_path, new_path)?;
|
||||||
.map_err(Into::into)
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WinError::ERROR_INVALID_NAME => {
|
winerror::ERROR_INVALID_NAME => {
|
||||||
// If source contains trailing slashes, check if we are dealing with
|
// If source contains trailing slashes, check if we are dealing with
|
||||||
// a file instead of a dir, and if so, throw ENOTDIR.
|
// a file instead of a dir, and if so, throw ENOTDIR.
|
||||||
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? {
|
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);
|
return Err(Error::ENOTDIR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(WinError::ERROR_INVALID_NAME.into())
|
|
||||||
}
|
}
|
||||||
e => Err(e.into()),
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err(err.into())
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
log::debug!("Inconvertible OS error: {}", err);
|
||||||
Err(Error::EIO)
|
Err(Error::EIO)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
||||||
@@ -458,52 +459,51 @@ pub(crate) fn path_filestat_set_times(
|
|||||||
|
|
||||||
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
||||||
use std::os::windows::fs::{symlink_dir, symlink_file};
|
use std::os::windows::fs::{symlink_dir, symlink_file};
|
||||||
use winx::winerror::WinError;
|
|
||||||
|
|
||||||
let old_path = concatenate(resolved.dirfd(), Path::new(old_path))?;
|
let old_path = concatenate(resolved.dirfd(), Path::new(old_path))?;
|
||||||
let new_path = resolved.concatenate()?;
|
let new_path = resolved.concatenate()?;
|
||||||
|
|
||||||
// try creating a file symlink
|
// try creating a file symlink
|
||||||
symlink_file(&old_path, &new_path).or_else(|e| {
|
let err = match symlink_file(&old_path, &new_path) {
|
||||||
match e.raw_os_error() {
|
Ok(()) => return Ok(()),
|
||||||
Some(e) => {
|
Err(e) => e,
|
||||||
log::debug!("path_symlink at symlink_file error code={:?}", e);
|
};
|
||||||
match WinError::from_u32(e as u32) {
|
match err.raw_os_error() {
|
||||||
WinError::ERROR_NOT_A_REPARSE_POINT => {
|
Some(code) => {
|
||||||
// try creating a dir symlink instead
|
log::debug!("path_symlink at symlink_file error code={:?}", code);
|
||||||
symlink_dir(old_path, new_path).map_err(Into::into)
|
match code as u32 {
|
||||||
}
|
winerror::ERROR_NOT_A_REPARSE_POINT => {
|
||||||
WinError::ERROR_ACCESS_DENIED => {
|
// try creating a dir symlink instead
|
||||||
// does the target exist?
|
return symlink_dir(old_path, new_path).map_err(Into::into);
|
||||||
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()),
|
|
||||||
}
|
}
|
||||||
|
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(err.into())
|
||||||
Err(Error::EIO)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
None => {
|
||||||
|
log::debug!("Inconvertible OS error: {}", err);
|
||||||
|
Err(Error::EIO)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
|
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use winx::winerror::WinError;
|
|
||||||
|
|
||||||
let path = resolved.concatenate()?;
|
let path = resolved.concatenate()?;
|
||||||
let file_type = path
|
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
|
// [std::os::windows::fs::FileTypeExt]: https://doc.rust-lang.org/std/os/windows/fs/trait.FileTypeExt.html
|
||||||
if file_type.is_symlink() {
|
if file_type.is_symlink() {
|
||||||
fs::remove_file(&path).or_else(|e| {
|
let err = match fs::remove_file(&path) {
|
||||||
match e.raw_os_error() {
|
Ok(()) => return Ok(()),
|
||||||
Some(e) => {
|
Err(e) => e,
|
||||||
log::debug!("path_unlink_file at symlink_file error code={:?}", e);
|
};
|
||||||
match WinError::from_u32(e as u32) {
|
match err.raw_os_error() {
|
||||||
WinError::ERROR_ACCESS_DENIED => {
|
Some(code) => {
|
||||||
// try unlinking a dir symlink instead
|
log::debug!("path_unlink_file at symlink_file error code={:?}", code);
|
||||||
fs::remove_dir(path).map_err(Into::into)
|
if code as u32 == winerror::ERROR_ACCESS_DENIED {
|
||||||
}
|
// try unlinking a dir symlink instead
|
||||||
e => Err(e.into()),
|
return fs::remove_dir(path).map_err(Into::into);
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
|
||||||
Err(Error::EIO)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err(err.into())
|
||||||
}
|
}
|
||||||
})
|
None => {
|
||||||
|
log::debug!("Inconvertible OS error: {}", err);
|
||||||
|
Err(Error::EIO)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if file_type.is_dir() {
|
} else if file_type.is_dir() {
|
||||||
Err(Error::EISDIR)
|
Err(Error::EISDIR)
|
||||||
} else if file_type.is_file() {
|
} else if file_type.is_file() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use std::ffi::{OsStr, OsString};
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use winapi::shared::winerror;
|
||||||
|
|
||||||
pub(crate) trait PathGetExt {
|
pub(crate) trait PathGetExt {
|
||||||
fn concatenate(&self) -> Result<PathBuf>;
|
fn concatenate(&self) -> Result<PathBuf>;
|
||||||
@@ -49,34 +50,30 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
|
|||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::os::windows::fs::OpenOptionsExt;
|
use std::os::windows::fs::OpenOptionsExt;
|
||||||
use winx::file::Flags;
|
use winx::file::Flags;
|
||||||
use winx::winerror::WinError;
|
|
||||||
|
|
||||||
let path = concatenate(dirfd, Path::new(path))?;
|
let path = concatenate(dirfd, Path::new(path))?;
|
||||||
OpenOptions::new()
|
let err = match OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.custom_flags(Flags::FILE_FLAG_BACKUP_SEMANTICS.bits())
|
.custom_flags(Flags::FILE_FLAG_BACKUP_SEMANTICS.bits())
|
||||||
.open(&path)
|
.open(&path)
|
||||||
.map_err(|e| match e.raw_os_error() {
|
{
|
||||||
Some(e) => {
|
Ok(file) => return Ok(file),
|
||||||
log::debug!("openat error={:?}", e);
|
Err(e) => e,
|
||||||
match WinError::from_u32(e as u32) {
|
};
|
||||||
WinError::ERROR_INVALID_NAME => Error::ENOTDIR,
|
if let Some(code) = err.raw_os_error() {
|
||||||
e => e.into(),
|
log::debug!("openat error={:?}", code);
|
||||||
}
|
if code as u32 == winerror::ERROR_INVALID_NAME {
|
||||||
}
|
return Err(Error::ENOTDIR);
|
||||||
None => {
|
}
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
}
|
||||||
Error::EIO
|
Err(err.into())
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
|
pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
|
||||||
use winx::file::get_file_path;
|
use winx::file::get_file_path;
|
||||||
use winx::winerror::WinError;
|
|
||||||
|
|
||||||
let path = concatenate(dirfd, Path::new(s_path))?;
|
let path = concatenate(dirfd, Path::new(s_path))?;
|
||||||
match path.read_link() {
|
let err = match path.read_link() {
|
||||||
Ok(target_path) => {
|
Ok(target_path) => {
|
||||||
// since on Windows we are effectively emulating 'at' syscalls
|
// since on Windows we are effectively emulating 'at' syscalls
|
||||||
// we need to strip the prefix from the absolute path
|
// we need to strip the prefix from the absolute path
|
||||||
@@ -84,37 +81,27 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
|
|||||||
// of dealing with absolute paths
|
// of dealing with absolute paths
|
||||||
let dir_path = get_file_path(dirfd)?;
|
let dir_path = get_file_path(dirfd)?;
|
||||||
let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
|
let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
|
||||||
target_path
|
let target_path = target_path
|
||||||
.strip_prefix(dir_path)
|
.strip_prefix(dir_path)
|
||||||
.map_err(|_| Error::ENOTCAPABLE)
|
.map_err(|_| Error::ENOTCAPABLE)?;
|
||||||
.and_then(|path| path.to_str().map(String::from).ok_or(Error::EILSEQ))
|
let target_path = target_path.to_str().ok_or(Error::EILSEQ)?;
|
||||||
|
return Ok(target_path.to_owned());
|
||||||
}
|
}
|
||||||
Err(e) => match e.raw_os_error() {
|
Err(e) => e,
|
||||||
Some(e) => {
|
};
|
||||||
log::debug!("readlinkat error={:?}", e);
|
if let Some(code) = err.raw_os_error() {
|
||||||
match WinError::from_u32(e as u32) {
|
log::debug!("readlinkat error={:?}", code);
|
||||||
WinError::ERROR_INVALID_NAME => {
|
if code as u32 == winerror::ERROR_INVALID_NAME {
|
||||||
if s_path.ends_with('/') {
|
if s_path.ends_with('/') {
|
||||||
// strip "/" and check if exists
|
// strip "/" and check if exists
|
||||||
let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?;
|
let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?;
|
||||||
if path.exists() && !path.is_dir() {
|
if path.exists() && !path.is_dir() {
|
||||||
Err(Error::ENOTDIR)
|
return Err(Error::ENOTDIR);
|
||||||
} else {
|
|
||||||
Err(Error::ENOENT)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(Error::ENOENT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e => Err(e.into()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
}
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
|
||||||
Err(Error::EIO)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
Err(err.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn strip_extended_prefix<P: AsRef<OsStr>>(path: P) -> OsString {
|
pub(crate) fn strip_extended_prefix<P: AsRef<OsStr>>(path: P) -> OsString {
|
||||||
|
|||||||
@@ -7,42 +7,35 @@ use std::fs::{self, File};
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use winx::winerror::WinError;
|
use winapi::shared::winerror;
|
||||||
|
|
||||||
impl FromRawOsError for Error {
|
impl FromRawOsError for Error {
|
||||||
fn from_raw_os_error(code: i32) -> Self {
|
fn from_raw_os_error(code: i32) -> Self {
|
||||||
Self::from(WinError::from_u32(code as u32))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WinError> for Error {
|
|
||||||
fn from(err: WinError) -> Self {
|
|
||||||
// TODO: implement error mapping between Windows and WASI
|
// TODO: implement error mapping between Windows and WASI
|
||||||
use winx::winerror::WinError::*;
|
match code as u32 {
|
||||||
match err {
|
winerror::ERROR_SUCCESS => Self::ESUCCESS,
|
||||||
ERROR_SUCCESS => Self::ESUCCESS,
|
winerror::ERROR_BAD_ENVIRONMENT => Self::E2BIG,
|
||||||
ERROR_BAD_ENVIRONMENT => Self::E2BIG,
|
winerror::ERROR_FILE_NOT_FOUND => Self::ENOENT,
|
||||||
ERROR_FILE_NOT_FOUND => Self::ENOENT,
|
winerror::ERROR_PATH_NOT_FOUND => Self::ENOENT,
|
||||||
ERROR_PATH_NOT_FOUND => Self::ENOENT,
|
winerror::ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE,
|
||||||
ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE,
|
winerror::ERROR_ACCESS_DENIED => Self::EACCES,
|
||||||
ERROR_ACCESS_DENIED => Self::EACCES,
|
winerror::ERROR_SHARING_VIOLATION => Self::EACCES,
|
||||||
ERROR_SHARING_VIOLATION => Self::EACCES,
|
winerror::ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping?
|
||||||
ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping?
|
winerror::ERROR_INVALID_HANDLE => Self::EBADF,
|
||||||
ERROR_INVALID_HANDLE => Self::EBADF,
|
winerror::ERROR_INVALID_NAME => Self::ENOENT,
|
||||||
ERROR_INVALID_NAME => Self::ENOENT,
|
winerror::ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM,
|
||||||
ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM,
|
winerror::ERROR_OUTOFMEMORY => Self::ENOMEM,
|
||||||
ERROR_OUTOFMEMORY => Self::ENOMEM,
|
winerror::ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY,
|
||||||
ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY,
|
winerror::ERROR_NOT_READY => Self::EBUSY,
|
||||||
ERROR_NOT_READY => Self::EBUSY,
|
winerror::ERROR_BUSY => Self::EBUSY,
|
||||||
ERROR_BUSY => Self::EBUSY,
|
winerror::ERROR_NOT_SUPPORTED => Self::ENOTSUP,
|
||||||
ERROR_NOT_SUPPORTED => Self::ENOTSUP,
|
winerror::ERROR_FILE_EXISTS => Self::EEXIST,
|
||||||
ERROR_FILE_EXISTS => Self::EEXIST,
|
winerror::ERROR_BROKEN_PIPE => Self::EPIPE,
|
||||||
ERROR_BROKEN_PIPE => Self::EPIPE,
|
winerror::ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG,
|
||||||
ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG,
|
winerror::ERROR_NOT_A_REPARSE_POINT => Self::EINVAL,
|
||||||
ERROR_NOT_A_REPARSE_POINT => Self::EINVAL,
|
winerror::ERROR_NEGATIVE_SEEK => Self::EINVAL,
|
||||||
ERROR_NEGATIVE_SEEK => Self::EINVAL,
|
winerror::ERROR_DIRECTORY => Self::ENOTDIR,
|
||||||
ERROR_DIRECTORY => Self::ENOTDIR,
|
winerror::ERROR_ALREADY_EXISTS => Self::EEXIST,
|
||||||
ERROR_ALREADY_EXISTS => Self::EEXIST,
|
|
||||||
_ => Self::ENOTSUP,
|
_ => Self::ENOTSUP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use std::io::{self, Seek, SeekFrom};
|
|||||||
use std::os::windows::fs::{FileExt, OpenOptionsExt};
|
use std::os::windows::fs::{FileExt, OpenOptionsExt};
|
||||||
use std::os::windows::prelude::{AsRawHandle, FromRawHandle};
|
use std::os::windows::prelude::{AsRawHandle, FromRawHandle};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use winapi::shared::winerror;
|
||||||
use winx::file::{AccessMode, CreationDisposition, FileModeInformation, Flags};
|
use winx::file::{AccessMode, CreationDisposition, FileModeInformation, Flags};
|
||||||
|
|
||||||
fn read_at(mut file: &File, buf: &mut [u8], offset: u64) -> io::Result<usize> {
|
fn read_at(mut file: &File, buf: &mut [u8], offset: u64) -> io::Result<usize> {
|
||||||
@@ -178,20 +179,18 @@ pub(crate) fn path_open(
|
|||||||
return Err(Error::ENOTDIR);
|
return Err(Error::ENOTDIR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => match e.raw_os_error() {
|
Err(err) => match err.raw_os_error() {
|
||||||
Some(e) => {
|
Some(code) => {
|
||||||
use winx::winerror::WinError;
|
log::debug!("path_open at symlink_metadata error code={:?}", code);
|
||||||
log::debug!("path_open at symlink_metadata error code={:?}", e);
|
|
||||||
let e = WinError::from_u32(e as u32);
|
|
||||||
|
|
||||||
if e != WinError::ERROR_FILE_NOT_FOUND {
|
if code as u32 != winerror::ERROR_FILE_NOT_FOUND {
|
||||||
return Err(e.into());
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
// file not found, let it proceed to actually
|
// file not found, let it proceed to actually
|
||||||
// trying to open it
|
// trying to open it
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
log::debug!("Inconvertible OS error: {}", err);
|
||||||
return Err(Error::EIO);
|
return Err(Error::EIO);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -428,27 +427,28 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO handle symlinks
|
// TODO handle symlinks
|
||||||
|
let err = match fs::rename(&old_path, &new_path) {
|
||||||
fs::rename(&old_path, &new_path).or_else(|e| match e.raw_os_error() {
|
Ok(()) => return Ok(()),
|
||||||
Some(e) => {
|
Err(e) => e,
|
||||||
use winx::winerror::WinError;
|
};
|
||||||
|
match err.raw_os_error() {
|
||||||
log::debug!("path_rename at rename error code={:?}", e);
|
Some(code) => {
|
||||||
match WinError::from_u32(e as u32) {
|
log::debug!("path_rename at rename error code={:?}", code);
|
||||||
WinError::ERROR_ACCESS_DENIED => {
|
match code as u32 {
|
||||||
|
winerror::ERROR_ACCESS_DENIED => {
|
||||||
// So most likely dealing with new_path == dir.
|
// So most likely dealing with new_path == dir.
|
||||||
// Eliminate case old_path == file first.
|
// Eliminate case old_path == file first.
|
||||||
if old_path.is_file() {
|
if old_path.is_file() {
|
||||||
Err(Error::EISDIR)
|
return Err(Error::EISDIR);
|
||||||
} else {
|
} else {
|
||||||
// Ok, let's try removing an empty dir at new_path if it exists
|
// Ok, let's try removing an empty dir at new_path if it exists
|
||||||
// and is a nonempty dir.
|
// and is a nonempty dir.
|
||||||
fs::remove_dir(&new_path)
|
fs::remove_dir(&new_path)?;
|
||||||
.and_then(|()| fs::rename(old_path, new_path))
|
fs::rename(old_path, new_path)?;
|
||||||
.map_err(Into::into)
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WinError::ERROR_INVALID_NAME => {
|
winerror::ERROR_INVALID_NAME => {
|
||||||
// If source contains trailing slashes, check if we are dealing with
|
// If source contains trailing slashes, check if we are dealing with
|
||||||
// a file instead of a dir, and if so, throw ENOTDIR.
|
// a file instead of a dir, and if so, throw ENOTDIR.
|
||||||
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? {
|
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);
|
return Err(Error::ENOTDIR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(WinError::ERROR_INVALID_NAME.into())
|
|
||||||
}
|
}
|
||||||
e => Err(e.into()),
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err(err.into())
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
log::debug!("Inconvertible OS error: {}", err);
|
||||||
Err(Error::EIO)
|
Err(Error::EIO)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
||||||
@@ -499,52 +500,51 @@ pub(crate) fn path_filestat_set_times(
|
|||||||
|
|
||||||
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
||||||
use std::os::windows::fs::{symlink_dir, symlink_file};
|
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 old_path = concatenate(&resolved.dirfd().as_os_handle(), Path::new(old_path))?;
|
||||||
let new_path = resolved.concatenate()?;
|
let new_path = resolved.concatenate()?;
|
||||||
|
|
||||||
// try creating a file symlink
|
// try creating a file symlink
|
||||||
symlink_file(&old_path, &new_path).or_else(|e| {
|
let err = match symlink_file(&old_path, &new_path) {
|
||||||
match e.raw_os_error() {
|
Ok(()) => return Ok(()),
|
||||||
Some(e) => {
|
Err(e) => e,
|
||||||
log::debug!("path_symlink at symlink_file error code={:?}", e);
|
};
|
||||||
match WinError::from_u32(e as u32) {
|
match err.raw_os_error() {
|
||||||
WinError::ERROR_NOT_A_REPARSE_POINT => {
|
Some(code) => {
|
||||||
// try creating a dir symlink instead
|
log::debug!("path_symlink at symlink_file error code={:?}", code);
|
||||||
symlink_dir(old_path, new_path).map_err(Into::into)
|
match code as u32 {
|
||||||
}
|
winerror::ERROR_NOT_A_REPARSE_POINT => {
|
||||||
WinError::ERROR_ACCESS_DENIED => {
|
// try creating a dir symlink instead
|
||||||
// does the target exist?
|
return symlink_dir(old_path, new_path).map_err(Into::into);
|
||||||
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()),
|
|
||||||
}
|
}
|
||||||
|
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(err.into())
|
||||||
Err(Error::EIO)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
None => {
|
||||||
|
log::debug!("Inconvertible OS error: {}", err);
|
||||||
|
Err(Error::EIO)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
|
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use winx::winerror::WinError;
|
|
||||||
|
|
||||||
let path = resolved.concatenate()?;
|
let path = resolved.concatenate()?;
|
||||||
let file_type = path
|
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
|
// [std::os::windows::fs::FileTypeExt]: https://doc.rust-lang.org/std/os/windows/fs/trait.FileTypeExt.html
|
||||||
if file_type.is_symlink() {
|
if file_type.is_symlink() {
|
||||||
fs::remove_file(&path).or_else(|e| {
|
let err = match fs::remove_file(&path) {
|
||||||
match e.raw_os_error() {
|
Ok(()) => return Ok(()),
|
||||||
Some(e) => {
|
Err(e) => e,
|
||||||
log::debug!("path_unlink_file at symlink_file error code={:?}", e);
|
};
|
||||||
match WinError::from_u32(e as u32) {
|
match err.raw_os_error() {
|
||||||
WinError::ERROR_ACCESS_DENIED => {
|
Some(code) => {
|
||||||
// try unlinking a dir symlink instead
|
log::debug!("path_unlink_file at symlink_file error code={:?}", code);
|
||||||
fs::remove_dir(path).map_err(Into::into)
|
if code as u32 == winerror::ERROR_ACCESS_DENIED {
|
||||||
}
|
// try unlinking a dir symlink instead
|
||||||
e => Err(e.into()),
|
return fs::remove_dir(path).map_err(Into::into);
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
|
||||||
Err(Error::EIO)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err(err.into())
|
||||||
}
|
}
|
||||||
})
|
None => {
|
||||||
|
log::debug!("Inconvertible OS error: {}", err);
|
||||||
|
Err(Error::EIO)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if file_type.is_dir() {
|
} else if file_type.is_dir() {
|
||||||
Err(Error::EISDIR)
|
Err(Error::EISDIR)
|
||||||
} else if file_type.is_file() {
|
} else if file_type.is_file() {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use std::ffi::{OsStr, OsString};
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use winapi::shared::winerror;
|
||||||
|
|
||||||
pub(crate) trait PathGetExt {
|
pub(crate) trait PathGetExt {
|
||||||
fn concatenate(&self) -> Result<PathBuf>;
|
fn concatenate(&self) -> Result<PathBuf>;
|
||||||
@@ -58,34 +59,30 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
|
|||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::os::windows::fs::OpenOptionsExt;
|
use std::os::windows::fs::OpenOptionsExt;
|
||||||
use winx::file::Flags;
|
use winx::file::Flags;
|
||||||
use winx::winerror::WinError;
|
|
||||||
|
|
||||||
let path = concatenate(dirfd, Path::new(path))?;
|
let path = concatenate(dirfd, Path::new(path))?;
|
||||||
OpenOptions::new()
|
let err = match OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.custom_flags(Flags::FILE_FLAG_BACKUP_SEMANTICS.bits())
|
.custom_flags(Flags::FILE_FLAG_BACKUP_SEMANTICS.bits())
|
||||||
.open(&path)
|
.open(&path)
|
||||||
.map_err(|e| match e.raw_os_error() {
|
{
|
||||||
Some(e) => {
|
Ok(file) => return Ok(file),
|
||||||
log::debug!("openat error={:?}", e);
|
Err(e) => e,
|
||||||
match WinError::from_u32(e as u32) {
|
};
|
||||||
WinError::ERROR_INVALID_NAME => Error::ENOTDIR,
|
if let Some(code) = err.raw_os_error() {
|
||||||
e => e.into(),
|
log::debug!("openat error={:?}", code);
|
||||||
}
|
if code as u32 == winerror::ERROR_INVALID_NAME {
|
||||||
}
|
return Err(Error::ENOTDIR);
|
||||||
None => {
|
}
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
}
|
||||||
Error::EIO
|
Err(err.into())
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
|
pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
|
||||||
use winx::file::get_file_path;
|
use winx::file::get_file_path;
|
||||||
use winx::winerror::WinError;
|
|
||||||
|
|
||||||
let path = concatenate(dirfd, Path::new(s_path))?;
|
let path = concatenate(dirfd, Path::new(s_path))?;
|
||||||
match path.read_link() {
|
let err = match path.read_link() {
|
||||||
Ok(target_path) => {
|
Ok(target_path) => {
|
||||||
// since on Windows we are effectively emulating 'at' syscalls
|
// since on Windows we are effectively emulating 'at' syscalls
|
||||||
// we need to strip the prefix from the absolute path
|
// we need to strip the prefix from the absolute path
|
||||||
@@ -93,37 +90,27 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
|
|||||||
// of dealing with absolute paths
|
// of dealing with absolute paths
|
||||||
let dir_path = get_file_path(dirfd)?;
|
let dir_path = get_file_path(dirfd)?;
|
||||||
let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
|
let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
|
||||||
target_path
|
let target_path = target_path
|
||||||
.strip_prefix(dir_path)
|
.strip_prefix(dir_path)
|
||||||
.map_err(|_| Error::ENOTCAPABLE)
|
.map_err(|_| Error::ENOTCAPABLE)?;
|
||||||
.and_then(|path| path.to_str().map(String::from).ok_or(Error::EILSEQ))
|
let target_path = target_path.to_str().ok_or(Error::EILSEQ)?;
|
||||||
|
return Ok(target_path.to_owned());
|
||||||
}
|
}
|
||||||
Err(e) => match e.raw_os_error() {
|
Err(e) => e,
|
||||||
Some(e) => {
|
};
|
||||||
log::debug!("readlinkat error={:?}", e);
|
if let Some(code) = err.raw_os_error() {
|
||||||
match WinError::from_u32(e as u32) {
|
log::debug!("readlinkat error={:?}", code);
|
||||||
WinError::ERROR_INVALID_NAME => {
|
if code as u32 == winerror::ERROR_INVALID_NAME {
|
||||||
if s_path.ends_with('/') {
|
if s_path.ends_with('/') {
|
||||||
// strip "/" and check if exists
|
// strip "/" and check if exists
|
||||||
let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?;
|
let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?;
|
||||||
if path.exists() && !path.is_dir() {
|
if path.exists() && !path.is_dir() {
|
||||||
Err(Error::ENOTDIR)
|
return Err(Error::ENOTDIR);
|
||||||
} else {
|
|
||||||
Err(Error::ENOENT)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(Error::ENOENT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e => Err(e.into()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
}
|
||||||
log::debug!("Inconvertible OS error: {}", e);
|
|
||||||
Err(Error::EIO)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
Err(err.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn strip_extended_prefix<P: AsRef<OsStr>>(path: P) -> OsString {
|
pub(crate) fn strip_extended_prefix<P: AsRef<OsStr>>(path: P) -> OsString {
|
||||||
|
|||||||
@@ -4,16 +4,15 @@ use crate::ntdll::{
|
|||||||
NtQueryInformationFile, RtlNtStatusToDosError, FILE_ACCESS_INFORMATION, FILE_INFORMATION_CLASS,
|
NtQueryInformationFile, RtlNtStatusToDosError, FILE_ACCESS_INFORMATION, FILE_INFORMATION_CLASS,
|
||||||
FILE_MODE_INFORMATION, IO_STATUS_BLOCK,
|
FILE_MODE_INFORMATION, IO_STATUS_BLOCK,
|
||||||
};
|
};
|
||||||
use crate::{winerror, Result};
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use cvt::cvt;
|
use cvt::cvt;
|
||||||
use std::ffi::{c_void, OsString};
|
use std::ffi::{c_void, OsString};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io::{Error, Result};
|
||||||
use std::os::windows::prelude::{AsRawHandle, OsStringExt, RawHandle};
|
use std::os::windows::prelude::{AsRawHandle, OsStringExt, RawHandle};
|
||||||
use winapi::shared::{
|
use winapi::shared::{
|
||||||
minwindef::{self, DWORD},
|
minwindef::{self, DWORD},
|
||||||
ntstatus,
|
ntstatus, winerror,
|
||||||
};
|
};
|
||||||
use winapi::um::{fileapi, fileapi::GetFileType, minwinbase, winbase, winnt};
|
use winapi::um::{fileapi, fileapi::GetFileType, minwinbase, winbase, winnt};
|
||||||
|
|
||||||
@@ -57,8 +56,8 @@ impl FileType {
|
|||||||
|
|
||||||
pub unsafe fn get_file_type(handle: RawHandle) -> Result<FileType> {
|
pub unsafe fn get_file_type(handle: RawHandle) -> Result<FileType> {
|
||||||
let file_type = FileType(GetFileType(handle));
|
let file_type = FileType(GetFileType(handle));
|
||||||
let err = winerror::WinError::last();
|
let err = Error::last_os_error();
|
||||||
if file_type.is_unknown() && err != winerror::WinError::ERROR_SUCCESS {
|
if file_type.is_unknown() && err.raw_os_error().unwrap() as u32 != winerror::ERROR_SUCCESS {
|
||||||
Err(err)
|
Err(err)
|
||||||
} else {
|
} else {
|
||||||
Ok(file_type)
|
Ok(file_type)
|
||||||
@@ -341,23 +340,20 @@ pub fn get_file_path(file: &File) -> Result<OsString> {
|
|||||||
|
|
||||||
let handle = file.as_raw_handle();
|
let handle = file.as_raw_handle();
|
||||||
let read_len =
|
let read_len =
|
||||||
unsafe { GetFinalPathNameByHandleW(handle, raw_path.as_mut_ptr(), WIDE_MAX_PATH, 0) };
|
cvt(unsafe { GetFinalPathNameByHandleW(handle, raw_path.as_mut_ptr(), WIDE_MAX_PATH, 0) })?;
|
||||||
|
|
||||||
if read_len == 0 {
|
|
||||||
// failed to read
|
|
||||||
return Err(winerror::WinError::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
// obtain a slice containing the written bytes, and check for it being too long
|
// obtain a slice containing the written bytes, and check for it being too long
|
||||||
// (practically probably impossible)
|
// (practically probably impossible)
|
||||||
let written_bytes = raw_path
|
let written_bytes = raw_path
|
||||||
.get(..read_len as usize)
|
.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))
|
Ok(OsString::from_wide(written_bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fileinfo(file: &File) -> io::Result<fileapi::BY_HANDLE_FILE_INFORMATION> {
|
pub fn get_fileinfo(file: &File) -> Result<fileapi::BY_HANDLE_FILE_INFORMATION> {
|
||||||
use fileapi::{GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION};
|
use fileapi::{GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@@ -371,7 +367,7 @@ pub fn get_fileinfo(file: &File) -> io::Result<fileapi::BY_HANDLE_FILE_INFORMATI
|
|||||||
Ok(info)
|
Ok(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_time(file: &File) -> io::Result<i64> {
|
pub fn change_time(file: &File) -> Result<i64> {
|
||||||
use fileapi::FILE_BASIC_INFO;
|
use fileapi::FILE_BASIC_INFO;
|
||||||
use minwinbase::FileBasicInfo;
|
use minwinbase::FileBasicInfo;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -407,7 +403,9 @@ pub fn query_access_information(handle: RawHandle) -> Result<AccessMode> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if status != ntstatus::STATUS_SUCCESS {
|
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<FileModeInformation>
|
|||||||
);
|
);
|
||||||
|
|
||||||
if status != ntstatus::STATUS_SUCCESS {
|
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 {
|
if new_handle == winapi::um::handleapi::INVALID_HANDLE_VALUE {
|
||||||
return Err(winerror::WinError::last());
|
return Err(Error::last_os_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(new_handle)
|
Ok(new_handle)
|
||||||
|
|||||||
@@ -24,8 +24,3 @@
|
|||||||
pub mod file;
|
pub mod file;
|
||||||
mod ntdll;
|
mod ntdll;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod winerror;
|
|
||||||
|
|
||||||
use winerror::WinError;
|
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, WinError>;
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use cvt::cvt;
|
use cvt::cvt;
|
||||||
|
use std::io::Result;
|
||||||
use winapi::um::{profileapi::QueryPerformanceFrequency, winnt::LARGE_INTEGER};
|
use winapi::um::{profileapi::QueryPerformanceFrequency, winnt::LARGE_INTEGER};
|
||||||
|
|
||||||
pub fn perf_counter_frequency() -> std::io::Result<u64> {
|
pub fn perf_counter_frequency() -> Result<u64> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut frequency: LARGE_INTEGER = std::mem::zeroed();
|
let mut frequency: LARGE_INTEGER = std::mem::zeroed();
|
||||||
cvt(QueryPerformanceFrequency(&mut frequency))?;
|
cvt(QueryPerformanceFrequency(&mut frequency))?;
|
||||||
|
|||||||
@@ -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<WinError> for std::io::Error {
|
|
||||||
fn from(err: WinError) -> Self {
|
|
||||||
Self::from_raw_os_error(err as i32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user