* Revert fstatat on *nix and test symlinks in path_filestat calls
This commit effectively reverts too eager refactoring on my part which
resulted in incorrect `path_filestat_{get, set_times}` behaviour on
*nix hosts. In the presence of symlinks, neither of the calls would
work properly.
In order to shield ourselves from similar errors in the future, I've
augmented the `path_filestat` test cases with symlink checks as well.
* Pass appropriate flags to fstatat and utimensat
* Fix formatting
* Fix Windows build
* Expand final symlinks if follow is set on Windows
* Fix formatting
* Do not follow symlinks unless specified on Windows
* Update comments and restart CI
* Skip testing volatile atim field
143 lines
4.4 KiB
Rust
143 lines
4.4 KiB
Rust
use super::sys_impl::oshandle::RawOsHandle;
|
|
use super::{fd, path, AsFile};
|
|
use crate::handle::{Handle, HandleRights};
|
|
use crate::wasi::{types, Errno, Result};
|
|
use log::{debug, error};
|
|
use std::any::Any;
|
|
use std::io;
|
|
use std::ops::Deref;
|
|
|
|
// TODO could this be cleaned up?
|
|
// The actual `OsDir` struct is OS-dependent, therefore we delegate
|
|
// its definition to OS-specific modules.
|
|
pub(crate) use super::sys_impl::osdir::OsDir;
|
|
|
|
impl Deref for OsDir {
|
|
type Target = RawOsHandle;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.handle
|
|
}
|
|
}
|
|
|
|
impl Handle for OsDir {
|
|
fn as_any(&self) -> &dyn Any {
|
|
self
|
|
}
|
|
fn try_clone(&self) -> io::Result<Box<dyn Handle>> {
|
|
let handle = self.handle.try_clone()?;
|
|
let new = Self::new(self.rights.get(), handle)?;
|
|
Ok(Box::new(new))
|
|
}
|
|
fn get_file_type(&self) -> types::Filetype {
|
|
types::Filetype::Directory
|
|
}
|
|
fn get_rights(&self) -> HandleRights {
|
|
self.rights.get()
|
|
}
|
|
fn set_rights(&self, rights: HandleRights) {
|
|
self.rights.set(rights)
|
|
}
|
|
// FdOps
|
|
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
|
fd::fdstat_get(&*self.as_file()?)
|
|
}
|
|
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
|
if let Some(new_file) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
|
self.handle.update_from(new_file);
|
|
}
|
|
Ok(())
|
|
}
|
|
fn filestat_get(&self) -> Result<types::Filestat> {
|
|
fd::filestat_get(&*self.as_file()?)
|
|
}
|
|
fn filestat_set_times(
|
|
&self,
|
|
atim: types::Timestamp,
|
|
mtim: types::Timestamp,
|
|
fst_flags: types::Fstflags,
|
|
) -> Result<()> {
|
|
fd::filestat_set_times(&*self.as_file()?, atim, mtim, fst_flags)
|
|
}
|
|
fn readdir<'a>(
|
|
&'a self,
|
|
cookie: types::Dircookie,
|
|
) -> Result<Box<dyn Iterator<Item = Result<(types::Dirent, String)>> + 'a>> {
|
|
fd::readdir(self, cookie)
|
|
}
|
|
// PathOps
|
|
fn create_directory(&self, path: &str) -> Result<()> {
|
|
path::create_directory(self, path)
|
|
}
|
|
fn filestat_get_at(&self, path: &str, follow: bool) -> Result<types::Filestat> {
|
|
path::filestat_get_at(self, path, follow)
|
|
}
|
|
fn filestat_set_times_at(
|
|
&self,
|
|
path: &str,
|
|
atim: types::Timestamp,
|
|
mtim: types::Timestamp,
|
|
fst_flags: types::Fstflags,
|
|
follow: bool,
|
|
) -> Result<()> {
|
|
path::filestat_set_times_at(self, path, atim, mtim, fst_flags, follow)
|
|
}
|
|
fn openat(
|
|
&self,
|
|
path: &str,
|
|
read: bool,
|
|
write: bool,
|
|
oflags: types::Oflags,
|
|
fd_flags: types::Fdflags,
|
|
) -> Result<Box<dyn Handle>> {
|
|
path::open(self, path, read, write, oflags, fd_flags)
|
|
}
|
|
fn link(
|
|
&self,
|
|
old_path: &str,
|
|
new_handle: Box<dyn Handle>,
|
|
new_path: &str,
|
|
follow: bool,
|
|
) -> Result<()> {
|
|
let new_handle = match new_handle.as_any().downcast_ref::<Self>() {
|
|
None => {
|
|
error!("Tried to link with handle that's not an OsDir");
|
|
return Err(Errno::Badf);
|
|
}
|
|
Some(handle) => handle,
|
|
};
|
|
path::link(self, old_path, new_handle, new_path, follow)
|
|
}
|
|
fn symlink(&self, old_path: &str, new_path: &str) -> Result<()> {
|
|
path::symlink(old_path, self, new_path)
|
|
}
|
|
fn readlink(&self, path: &str, buf: &mut [u8]) -> Result<usize> {
|
|
path::readlink(self, path, buf)
|
|
}
|
|
fn readlinkat(&self, path: &str) -> Result<String> {
|
|
path::readlinkat(self, path)
|
|
}
|
|
fn rename(&self, old_path: &str, new_handle: Box<dyn Handle>, new_path: &str) -> Result<()> {
|
|
let new_handle = match new_handle.as_any().downcast_ref::<Self>() {
|
|
None => {
|
|
error!("Tried to rename with handle that's not an OsDir");
|
|
return Err(Errno::Badf);
|
|
}
|
|
Some(handle) => handle,
|
|
};
|
|
debug!("rename (old_dirfd, old_path)=({:?}, {:?})", self, old_path);
|
|
debug!(
|
|
"rename (new_dirfd, new_path)=({:?}, {:?})",
|
|
new_handle, new_path
|
|
);
|
|
path::rename(self, old_path, new_handle, new_path)
|
|
}
|
|
fn remove_directory(&self, path: &str) -> Result<()> {
|
|
debug!("remove_directory (dirfd, path)=({:?}, {:?})", self, path);
|
|
path::remove_directory(self, path)
|
|
}
|
|
fn unlink_file(&self, path: &str) -> Result<()> {
|
|
path::unlink_file(self, path)
|
|
}
|
|
}
|