1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::host::FileType;
use crate::{error::FromRawOsError, wasi, Error, Result};
use std::convert::TryInto;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io;
use std::os::windows::ffi::OsStrExt;
use std::time::{SystemTime, UNIX_EPOCH};
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<WinError> for Error {
fn from(err: WinError) -> Self {
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,
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,
_ => Self::ENOTSUP,
}
}
}
pub(crate) fn filetype_from_std(ftype: &fs::FileType) -> FileType {
if ftype.is_file() {
FileType::RegularFile
} else if ftype.is_dir() {
FileType::Directory
} else if ftype.is_symlink() {
FileType::Symlink
} else {
FileType::Unknown
}
}
fn num_hardlinks(file: &File) -> io::Result<u64> {
Ok(winx::file::get_fileinfo(file)?.nNumberOfLinks.into())
}
fn device_id(file: &File) -> io::Result<u64> {
Ok(winx::file::get_fileinfo(file)?.dwVolumeSerialNumber.into())
}
pub(crate) fn file_serial_no(file: &File) -> io::Result<u64> {
let info = winx::file::get_fileinfo(file)?;
let high = info.nFileIndexHigh;
let low = info.nFileIndexLow;
let no = (u64::from(high) << 32) | u64::from(low);
Ok(no)
}
fn change_time(file: &File) -> io::Result<i64> {
winx::file::change_time(file)
}
fn systemtime_to_timestamp(st: SystemTime) -> Result<u64> {
st.duration_since(UNIX_EPOCH)
.map_err(|_| Error::EINVAL)?
.as_nanos()
.try_into()
.map_err(Into::into)
}
pub(crate) fn filestat_from_win(file: &File) -> Result<wasi::__wasi_filestat_t> {
let metadata = file.metadata()?;
Ok(wasi::__wasi_filestat_t {
dev: device_id(file)?,
ino: file_serial_no(file)?,
nlink: num_hardlinks(file)?.try_into()?,
size: metadata.len(),
atim: systemtime_to_timestamp(metadata.accessed()?)?,
ctim: change_time(file)?.try_into()?,
mtim: systemtime_to_timestamp(metadata.modified()?)?,
filetype: filetype_from_std(&metadata.file_type()).to_wasi(),
})
}
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> Result<String> {
let vec: Vec<u16> = s.as_ref().encode_wide().collect();
String::from_utf16(&vec).map_err(|_| Error::EILSEQ)
}