From 47f3a6bcb96ccf3a24d6f6f6784e6de0ea005f72 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 10 Dec 2020 17:31:21 -0800 Subject: [PATCH] sketchy implementation of readdir --- crates/wasi-c2/src/dir.rs | 91 +++++++++++++++++++++++ crates/wasi-c2/src/file.rs | 4 + crates/wasi-c2/src/snapshots/preview_1.rs | 30 +++++--- 3 files changed, 113 insertions(+), 12 deletions(-) diff --git a/crates/wasi-c2/src/dir.rs b/crates/wasi-c2/src/dir.rs index 62bddebe21..68e0af539d 100644 --- a/crates/wasi-c2/src/dir.rs +++ b/crates/wasi-c2/src/dir.rs @@ -20,6 +20,11 @@ pub trait WasiDir { path: &str, create: bool, ) -> Result, Error>; + + fn readdir( + &self, + cursor: ReaddirCursor, + ) -> Result>>, Error>; } pub(crate) struct DirEntry { @@ -84,3 +89,89 @@ impl TableDirExt for crate::table::Table { } } } + +pub enum DirEntityType { + File(crate::file::Filetype), + Directory, + SymbolicLink, + Unknown, +} + +pub struct ReaddirEntity { + next: ReaddirCursor, + inode: u64, + namelen: u64, + direnttype: DirEntityType, +} + +pub struct ReaddirCursor(u64); +impl From for ReaddirCursor { + fn from(c: u64) -> ReaddirCursor { + ReaddirCursor(c) + } +} +impl From for u64 { + fn from(c: ReaddirCursor) -> u64 { + c.0 + } +} + +impl WasiDir for cap_std::fs::Dir { + fn open_file( + &self, + symlink_follow: bool, + path: &str, + oflags: file::OFlags, + fdflags: file::FdFlags, + ) -> Result, Error> { + todo!() + } + + fn open_dir( + &self, + symlink_follow: bool, + path: &str, + create: bool, + ) -> Result, Error> { + todo!() + } + + fn readdir( + &self, + cursor: ReaddirCursor, + ) -> Result>>, Error> { + let rd = self + .read_dir(PathBuf::new())? + .enumerate() + .skip(u64::from(cursor) as usize); + Ok(Box::new(rd.map(|(ix, entry)| { + let entry = entry?; + let file_type = entry.file_type()?; + let direnttype = if file_type.is_dir() { + DirEntityType::Directory + } else if file_type.is_file() { + DirEntityType::File(crate::file::Filetype::RegularFile) // XXX unify this with conversion in `impl WasiFile for cap_std::fs::File { get_filetype }` + } else if file_type.is_symlink() { + DirEntityType::SymbolicLink + } else { + DirEntityType::Unknown + }; + let name = entry.file_name().into_string().map_err(|_| { + Error::Utf8(todo!( + // XXX + "idk how to make utf8 error out of osstring conversion" + )) + })?; + let namelen = name.as_bytes().len() as u64; + // XXX need the metadata casing to be reusable here + let inode = todo!(); + let entity = ReaddirEntity { + next: ReaddirCursor::from(ix as u64 + 1), + direnttype, + inode, + namelen, + }; + Ok((entity, name)) + }))) + } +} diff --git a/crates/wasi-c2/src/file.rs b/crates/wasi-c2/src/file.rs index d875be4f99..19a51db1c2 100644 --- a/crates/wasi-c2/src/file.rs +++ b/crates/wasi-c2/src/file.rs @@ -15,6 +15,10 @@ pub trait WasiFile: FileIoExt + SetTimes { fn set_filestat_size(&self, _size: u64) -> Result<(), Error>; } +// XXX missing: +// Unknown +// Directory +// SymbolicLink #[derive(Debug, Copy, Clone)] pub enum Filetype { BlockDevice, diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index 731b3377b7..7de768d2f8 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -1,5 +1,5 @@ #![allow(unused_variables)] -use crate::dir::{DirCaps, DirEntry, TableDirExt}; +use crate::dir::{DirCaps, DirEntry, ReaddirCursor, TableDirExt}; use crate::file::{FdFlags, FdStat, FileCaps, FileEntry, Filestat, Filetype, OFlags}; use crate::{Error, WasiCtx}; use fs_set_times::SystemTimeSpec; @@ -427,17 +427,6 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { Err(Error::Notsup) } } - - fn fd_readdir( - &self, - fd: types::Fd, - buf: &GuestPtr, - buf_len: types::Size, - cookie: types::Dircookie, - ) -> Result { - todo!("fd_readdir is very complicated") - } - fn fd_renumber(&self, from: types::Fd, to: types::Fd) -> Result<(), Error> { let mut table = self.table(); let from = u32::from(from); @@ -499,6 +488,23 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { Ok(offset) } + fn fd_readdir( + &self, + dirfd: types::Fd, + buf: &GuestPtr, + buf_len: types::Size, + cookie: types::Dircookie, + ) -> Result { + let table = self.table(); + let dir_entry: RefMut = table.get(u32::from(dirfd))?; + let d = dir_entry.get_cap(DirCaps::READDIR)?; + for pair in d.readdir(ReaddirCursor::from(cookie))? { + let (entity, name) = pair?; + todo!() + } + todo!() + } + fn path_create_directory( &self, dirfd: types::Fd,