Skip to content

Commit cca7b0a

Browse files
authored
fix wasi-fyi tests (#4708)
2 parents 58a98d0 + 6dbd4c2 commit cca7b0a

26 files changed

+254
-9
lines changed

lib/virtual-fs/src/arc_fs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ impl ArcFileSystem {
1818
}
1919

2020
impl FileSystem for ArcFileSystem {
21+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
22+
self.fs.readlink(path)
23+
}
24+
2125
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
2226
self.fs.read_dir(path)
2327
}

lib/virtual-fs/src/empty_fs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ pub struct EmptyFileSystem {}
1212

1313
#[allow(unused_variables)]
1414
impl FileSystem for EmptyFileSystem {
15+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
16+
Err(FsError::EntryNotFound)
17+
}
18+
1519
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
1620
// Special-case the root path by returning an empty iterator.
1721
// An empty file system should still be readable, just not contain

lib/virtual-fs/src/host_fs.rs

+10
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ impl FileSystem {
5252
}
5353

5454
impl crate::FileSystem for FileSystem {
55+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
56+
fs::read_link(path).map_err(Into::into)
57+
}
58+
5559
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
5660
let read_dir = fs::read_dir(path)?;
5761
let mut data = read_dir
@@ -153,6 +157,12 @@ impl crate::FileSystem for FileSystem {
153157
.and_then(TryInto::try_into)
154158
.map_err(Into::into)
155159
}
160+
161+
fn symlink_metadata(&self, path: &Path) -> Result<Metadata> {
162+
fs::symlink_metadata(path)
163+
.and_then(TryInto::try_into)
164+
.map_err(Into::into)
165+
}
156166
}
157167

158168
impl TryInto<Metadata> for std::fs::Metadata {

lib/virtual-fs/src/lib.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ pub trait ClonableVirtualFile: VirtualFile + Clone {}
9191
pub use ops::{copy_reference, copy_reference_ext};
9292

9393
pub trait FileSystem: fmt::Debug + Send + Sync + 'static + Upcastable {
94+
fn readlink(&self, path: &Path) -> Result<PathBuf>;
9495
fn read_dir(&self, path: &Path) -> Result<ReadDir>;
9596
fn create_dir(&self, path: &Path) -> Result<()>;
9697
fn remove_dir(&self, path: &Path) -> Result<()>;
@@ -99,9 +100,7 @@ pub trait FileSystem: fmt::Debug + Send + Sync + 'static + Upcastable {
99100
/// This method gets metadata without following symlinks in the path.
100101
/// Currently identical to `metadata` because symlinks aren't implemented
101102
/// yet.
102-
fn symlink_metadata(&self, path: &Path) -> Result<Metadata> {
103-
self.metadata(path)
104-
}
103+
fn symlink_metadata(&self, path: &Path) -> Result<Metadata>;
105104
fn remove_file(&self, path: &Path) -> Result<()>;
106105

107106
fn new_open_options(&self) -> OpenOptions;
@@ -128,6 +127,10 @@ where
128127
(**self).read_dir(path)
129128
}
130129

130+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
131+
(**self).readlink(path)
132+
}
133+
131134
fn create_dir(&self, path: &Path) -> Result<()> {
132135
(**self).create_dir(path)
133136
}
@@ -144,6 +147,10 @@ where
144147
(**self).metadata(path)
145148
}
146149

150+
fn symlink_metadata(&self, path: &Path) -> Result<Metadata> {
151+
(**self).symlink_metadata(path)
152+
}
153+
147154
fn remove_file(&self, path: &Path) -> Result<()> {
148155
(**self).remove_file(path)
149156
}

lib/virtual-fs/src/mem_fs/filesystem.rs

+29
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,18 @@ impl FileSystem {
257257
}
258258

259259
impl crate::FileSystem for FileSystem {
260+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
261+
// Read lock.
262+
let guard = self.inner.read().map_err(|_| FsError::Lock)?;
263+
264+
// Canonicalize the path.
265+
let (_, inode_of_directory) = guard.canonicalize(path)?;
266+
match inode_of_directory {
267+
InodeResolution::Found(_) => Err(FsError::InvalidInput),
268+
InodeResolution::Redirect(fs, path) => fs.readlink(path.as_path()),
269+
}
270+
}
271+
260272
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
261273
// Read lock.
262274
let guard = self.inner.read().map_err(|_| FsError::Lock)?;
@@ -591,6 +603,23 @@ impl crate::FileSystem for FileSystem {
591603
}
592604
}
593605

606+
fn symlink_metadata(&self, path: &Path) -> Result<Metadata> {
607+
// Read lock.
608+
let guard = self.inner.read().map_err(|_| FsError::Lock)?;
609+
match guard.inode_of(path)? {
610+
InodeResolution::Found(inode) => Ok(guard
611+
.storage
612+
.get(inode)
613+
.ok_or(FsError::UnknownError)?
614+
.metadata()
615+
.clone()),
616+
InodeResolution::Redirect(fs, path) => {
617+
drop(guard);
618+
fs.symlink_metadata(path.as_path())
619+
}
620+
}
621+
}
622+
594623
fn remove_file(&self, path: &Path) -> Result<()> {
595624
let (inode_of_parent, position, inode_of_file) = {
596625
// Read lock.

lib/virtual-fs/src/overlay_fs.rs

+58
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,35 @@ where
113113
S: for<'a> FileSystems<'a> + Send + Sync + 'static,
114114
for<'a> <<S as FileSystems<'a>>::Iter as IntoIterator>::IntoIter: Send,
115115
{
116+
fn readlink(&self, path: &Path) -> crate::Result<PathBuf> {
117+
// Whiteout files can not be read, they are just markers
118+
if ops::is_white_out(path).is_some() {
119+
return Err(FsError::EntryNotFound);
120+
}
121+
122+
// Check if the file is in the primary
123+
match self.primary.readlink(path) {
124+
Ok(meta) => return Ok(meta),
125+
Err(e) if should_continue(e) => {}
126+
Err(e) => return Err(e),
127+
}
128+
129+
// There might be a whiteout, search for this
130+
if ops::has_white_out(&self.primary, path) {
131+
return Err(FsError::EntryNotFound);
132+
}
133+
134+
// Otherwise scan the secondaries
135+
for fs in self.secondaries.filesystems() {
136+
match fs.readlink(path) {
137+
Err(e) if should_continue(e) => continue,
138+
other => return other,
139+
}
140+
}
141+
142+
Err(FsError::EntryNotFound)
143+
}
144+
116145
fn read_dir(&self, path: &Path) -> Result<ReadDir, FsError> {
117146
let mut entries = Vec::new();
118147
let mut had_at_least_one_success = false;
@@ -328,6 +357,35 @@ where
328357
Err(FsError::EntryNotFound)
329358
}
330359

360+
fn symlink_metadata(&self, path: &Path) -> crate::Result<Metadata> {
361+
// Whiteout files can not be read, they are just markers
362+
if ops::is_white_out(path).is_some() {
363+
return Err(FsError::EntryNotFound);
364+
}
365+
366+
// Check if the file is in the primary
367+
match self.primary.symlink_metadata(path) {
368+
Ok(meta) => return Ok(meta),
369+
Err(e) if should_continue(e) => {}
370+
Err(e) => return Err(e),
371+
}
372+
373+
// There might be a whiteout, search for this
374+
if ops::has_white_out(&self.primary, path) {
375+
return Err(FsError::EntryNotFound);
376+
}
377+
378+
// Otherwise scan the secondaries
379+
for fs in self.secondaries.filesystems() {
380+
match fs.symlink_metadata(path) {
381+
Err(e) if should_continue(e) => continue,
382+
other => return other,
383+
}
384+
}
385+
386+
Err(FsError::EntryNotFound)
387+
}
388+
331389
fn remove_file(&self, path: &Path) -> Result<(), FsError> {
332390
// It is not possible to delete whiteout files directly, instead
333391
// one must delete the original file

lib/virtual-fs/src/passthru_fs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ impl PassthruFileSystem {
1818
}
1919

2020
impl FileSystem for PassthruFileSystem {
21+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
22+
self.fs.readlink(path)
23+
}
24+
2125
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
2226
self.fs.read_dir(path)
2327
}

lib/virtual-fs/src/scoped_directory_fs.rs

+10
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ impl ScopedDirectoryFileSystem {
5151
}
5252

5353
impl FileSystem for ScopedDirectoryFileSystem {
54+
fn readlink(&self, path: &Path) -> crate::Result<PathBuf> {
55+
let path = self.prepare_path(path);
56+
self.inner.readlink(&path)
57+
}
58+
5459
fn read_dir(&self, path: &Path) -> Result<ReadDir, FsError> {
5560
let path = self.prepare_path(path);
5661

@@ -94,6 +99,11 @@ impl FileSystem for ScopedDirectoryFileSystem {
9499
self.inner.metadata(&path)
95100
}
96101

102+
fn symlink_metadata(&self, path: &Path) -> crate::Result<Metadata> {
103+
let path = self.prepare_path(path);
104+
self.inner.symlink_metadata(&path)
105+
}
106+
97107
fn remove_file(&self, path: &Path) -> Result<(), FsError> {
98108
let path = self.prepare_path(path);
99109
self.inner.remove_file(&path)

lib/virtual-fs/src/static_fs.rs

+14
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,20 @@ fn transform_into_read_dir(path: &Path, fs_entries: &[FsEntry<'_>]) -> crate::Re
238238
}
239239

240240
impl FileSystem for StaticFileSystem {
241+
fn readlink(&self, path: &Path) -> crate::Result<PathBuf> {
242+
let path = normalizes_path(path);
243+
if self
244+
.volumes
245+
.values()
246+
.find_map(|v| v.get_file_entry(&path).ok())
247+
.is_some()
248+
{
249+
Err(FsError::InvalidInput)
250+
} else {
251+
self.memory.readlink(Path::new(&path))
252+
}
253+
}
254+
241255
fn read_dir(&self, path: &Path) -> Result<ReadDir, FsError> {
242256
let path = normalizes_path(path);
243257
for volume in self.volumes.values() {

lib/virtual-fs/src/tmp_fs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ impl TmpFileSystem {
6161
}
6262

6363
impl FileSystem for TmpFileSystem {
64+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
65+
self.fs.readlink(path)
66+
}
67+
6468
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
6569
self.fs.read_dir(path)
6670
}

lib/virtual-fs/src/trace_fs.rs

+10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ impl<F> FileSystem for TraceFileSystem<F>
3939
where
4040
F: FileSystem,
4141
{
42+
#[tracing::instrument(level = "trace", skip(self), err)]
43+
fn readlink(&self, path: &std::path::Path) -> crate::Result<PathBuf> {
44+
self.0.readlink(path)
45+
}
46+
4247
#[tracing::instrument(level = "trace", skip(self), err)]
4348
fn read_dir(&self, path: &std::path::Path) -> crate::Result<crate::ReadDir> {
4449
self.0.read_dir(path)
@@ -68,6 +73,11 @@ where
6873
self.0.metadata(path)
6974
}
7075

76+
#[tracing::instrument(level = "trace", skip(self), err)]
77+
fn symlink_metadata(&self, path: &std::path::Path) -> crate::Result<crate::Metadata> {
78+
self.0.symlink_metadata(path)
79+
}
80+
7181
#[tracing::instrument(level = "trace", skip(self), err)]
7282
fn remove_file(&self, path: &std::path::Path) -> crate::Result<()> {
7383
self.0.remove_file(path)

lib/virtual-fs/src/union_fs.rs

+26
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,32 @@ impl UnionFileSystem {
206206
}
207207

208208
impl FileSystem for UnionFileSystem {
209+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
210+
debug!("readlink: path={}", path.display());
211+
let mut ret_error = FsError::EntryNotFound;
212+
let path = path.to_string_lossy();
213+
for (path_inner, mount) in filter_mounts(&self.mounts, path.as_ref()) {
214+
match mount.fs.readlink(Path::new(path_inner.as_str())) {
215+
Ok(ret) => {
216+
return Ok(ret);
217+
}
218+
Err(err) => {
219+
// This fixes a bug when attempting to create the directory /usr when it does not exist
220+
// on the x86 version of memfs
221+
// TODO: patch virtual-fs and remove
222+
if let FsError::NotAFile = &err {
223+
ret_error = FsError::EntryNotFound;
224+
} else {
225+
debug!("readlink failed: (path={}) - {}", path, err);
226+
ret_error = err;
227+
}
228+
}
229+
}
230+
}
231+
debug!("readlink: failed={}", ret_error);
232+
Err(ret_error)
233+
}
234+
209235
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
210236
debug!("read_dir: path={}", path.display());
211237
self.read_dir_internal(path)

lib/virtual-fs/src/webc_fs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ where
304304
T: std::fmt::Debug + Send + Sync + 'static,
305305
T: Deref<Target = WebC<'static>>,
306306
{
307+
fn readlink(&self, _path: &Path) -> crate::Result<PathBuf> {
308+
Err(FsError::InvalidInput)
309+
}
310+
307311
fn read_dir(&self, path: &Path) -> Result<ReadDir, FsError> {
308312
let path = normalizes_path(path);
309313
let read_dir_result = self

lib/virtual-fs/src/webc_volume_fs.rs

+8
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ impl WebcVolumeFileSystem {
4949
}
5050

5151
impl FileSystem for WebcVolumeFileSystem {
52+
fn readlink(&self, _path: &Path) -> crate::Result<PathBuf> {
53+
Err(FsError::InvalidInput)
54+
}
55+
5256
fn read_dir(&self, path: &Path) -> Result<crate::ReadDir, FsError> {
5357
let meta = self.metadata(path)?;
5458

@@ -134,6 +138,10 @@ impl FileSystem for WebcVolumeFileSystem {
134138
.ok_or(FsError::EntryNotFound)
135139
}
136140

141+
fn symlink_metadata(&self, path: &Path) -> crate::Result<Metadata> {
142+
self.metadata(path)
143+
}
144+
137145
fn remove_file(&self, path: &Path) -> Result<(), FsError> {
138146
let meta = self.metadata(path)?;
139147

lib/wasix/src/fs/mod.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,13 @@ impl WasiFsRoot {
308308
}
309309

310310
impl FileSystem for WasiFsRoot {
311+
fn readlink(&self, path: &Path) -> virtual_fs::Result<PathBuf> {
312+
match self {
313+
WasiFsRoot::Sandbox(fs) => fs.readlink(path),
314+
WasiFsRoot::Backing(fs) => fs.readlink(path),
315+
}
316+
}
317+
311318
fn read_dir(&self, path: &Path) -> virtual_fs::Result<virtual_fs::ReadDir> {
312319
match self {
313320
WasiFsRoot::Sandbox(fs) => fs.read_dir(path),
@@ -992,7 +999,8 @@ impl WasiFs {
992999
}
9931000
} else if file_type.is_symlink() {
9941001
should_insert = false;
995-
let link_value = file.read_link().map_err(map_io_err)?;
1002+
let link_value =
1003+
self.root_fs.readlink(&file).ok().ok_or(Errno::Noent)?;
9961004
debug!("attempting to decompose path {:?}", link_value);
9971005

9981006
let (pre_open_dir_fd, relative_path) = if link_value.is_relative() {
@@ -2026,6 +2034,9 @@ impl FallbackFileSystem {
20262034
}
20272035

20282036
impl FileSystem for FallbackFileSystem {
2037+
fn readlink(&self, _path: &Path) -> virtual_fs::Result<PathBuf> {
2038+
Self::fail()
2039+
}
20292040
fn read_dir(&self, _path: &Path) -> Result<virtual_fs::ReadDir, FsError> {
20302041
Self::fail();
20312042
}

0 commit comments

Comments
 (0)