implement fd_readdir
This commit is contained in:
@@ -177,10 +177,11 @@ impl TableDirExt for crate::table::Table {
|
|||||||
pub struct ReaddirEntity {
|
pub struct ReaddirEntity {
|
||||||
pub next: ReaddirCursor,
|
pub next: ReaddirCursor,
|
||||||
pub inode: u64,
|
pub inode: u64,
|
||||||
pub namelen: u64,
|
pub namelen: u32,
|
||||||
pub filetype: FileType,
|
pub filetype: FileType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct ReaddirCursor(u64);
|
pub struct ReaddirCursor(u64);
|
||||||
impl From<u64> for ReaddirCursor {
|
impl From<u64> for ReaddirCursor {
|
||||||
fn from(c: u64) -> ReaddirCursor {
|
fn from(c: u64) -> ReaddirCursor {
|
||||||
@@ -254,7 +255,8 @@ impl WasiDir for cap_std::fs::Dir {
|
|||||||
cursor: ReaddirCursor,
|
cursor: ReaddirCursor,
|
||||||
) -> Result<Box<dyn Iterator<Item = Result<(ReaddirEntity, String), Error>>>, Error> {
|
) -> Result<Box<dyn Iterator<Item = Result<(ReaddirEntity, String), Error>>>, Error> {
|
||||||
let rd = self
|
let rd = self
|
||||||
.read_dir(PathBuf::new())?
|
.read_dir(Path::new("."))
|
||||||
|
.expect("always possible to readdir an open Dir") // XXX is this true?
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.skip(u64::from(cursor) as usize);
|
.skip(u64::from(cursor) as usize);
|
||||||
Ok(Box::new(rd.map(|(ix, entry)| {
|
Ok(Box::new(rd.map(|(ix, entry)| {
|
||||||
@@ -267,7 +269,7 @@ impl WasiDir for cap_std::fs::Dir {
|
|||||||
.file_name()
|
.file_name()
|
||||||
.into_string()
|
.into_string()
|
||||||
.map_err(|_| Error::Utf8(todo!()))?;
|
.map_err(|_| Error::Utf8(todo!()))?;
|
||||||
let namelen = name.as_bytes().len() as u64;
|
let namelen = name.as_bytes().len().try_into()?;
|
||||||
let entity = ReaddirEntity {
|
let entity = ReaddirEntity {
|
||||||
next: ReaddirCursor::from(ix as u64 + 1),
|
next: ReaddirCursor::from(ix as u64 + 1),
|
||||||
filetype,
|
filetype,
|
||||||
|
|||||||
@@ -545,19 +545,60 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
|
|
||||||
fn fd_readdir(
|
fn fd_readdir(
|
||||||
&self,
|
&self,
|
||||||
dirfd: types::Fd,
|
fd: types::Fd,
|
||||||
buf: &GuestPtr<u8>,
|
buf: &GuestPtr<u8>,
|
||||||
buf_len: types::Size,
|
buf_len: types::Size,
|
||||||
cookie: types::Dircookie,
|
cookie: types::Dircookie,
|
||||||
) -> Result<types::Size, Error> {
|
) -> Result<types::Size, Error> {
|
||||||
let table = self.table();
|
let table = self.table();
|
||||||
let dir_entry: Ref<DirEntry> = table.get(u32::from(dirfd))?;
|
let fd = u32::from(fd);
|
||||||
|
debug!(
|
||||||
|
"fd_readdir {} is a DirEntry: {}",
|
||||||
|
fd,
|
||||||
|
table.is::<DirEntry>(fd)
|
||||||
|
);
|
||||||
|
let dir_entry: Ref<DirEntry> = table.get(fd)?;
|
||||||
let d = dir_entry.get_cap(DirCaps::READDIR)?;
|
let d = dir_entry.get_cap(DirCaps::READDIR)?;
|
||||||
|
|
||||||
|
let mut bufused = 0;
|
||||||
|
let mut buf = buf.clone();
|
||||||
for pair in d.readdir(ReaddirCursor::from(cookie))? {
|
for pair in d.readdir(ReaddirCursor::from(cookie))? {
|
||||||
let (entity, name) = pair?;
|
let (entity, name) = pair?;
|
||||||
todo!()
|
let dirent_raw = dirent_bytes(types::Dirent::from(&entity));
|
||||||
|
let dirent_len: types::Size = dirent_raw.len().try_into()?;
|
||||||
|
let name_raw = name.as_bytes();
|
||||||
|
let name_len: types::Size = name_raw.len().try_into()?;
|
||||||
|
let offset = dirent_len.checked_add(name_len).ok_or(Error::Overflow)?;
|
||||||
|
|
||||||
|
// Copy as many bytes of the dirent as we can, up to the end of the buffer
|
||||||
|
let dirent_copy_len = std::cmp::min(dirent_len, buf_len - bufused);
|
||||||
|
buf.as_array(dirent_copy_len)
|
||||||
|
.copy_from_slice(&dirent_raw[..dirent_copy_len as usize])?;
|
||||||
|
|
||||||
|
// If the dirent struct wasnt compied entirely, return that we filled the buffer, which
|
||||||
|
// tells libc that we're not at EOF.
|
||||||
|
if dirent_copy_len < dirent_len {
|
||||||
|
return Ok(buf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = buf.add(dirent_copy_len)?;
|
||||||
|
|
||||||
|
// Copy as many bytes of the name as we can, up to the end of the buffer
|
||||||
|
let name_copy_len = std::cmp::min(name_len, buf_len - bufused);
|
||||||
|
buf.as_array(name_copy_len)
|
||||||
|
.copy_from_slice(&name_raw[..name_copy_len as usize])?;
|
||||||
|
|
||||||
|
// If the dirent struct wasn't copied entirely, return that we filled the buffer, which
|
||||||
|
// tells libc that we're not at EOF
|
||||||
|
|
||||||
|
if name_copy_len < name_len {
|
||||||
|
return Ok(buf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = buf.add(name_copy_len)?;
|
||||||
|
bufused += offset;
|
||||||
}
|
}
|
||||||
todo!()
|
Ok(bufused)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_create_directory(
|
fn path_create_directory(
|
||||||
@@ -1136,3 +1177,31 @@ impl From<Filestat> for types::Filestat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&ReaddirEntity> for types::Dirent {
|
||||||
|
fn from(e: &ReaddirEntity) -> types::Dirent {
|
||||||
|
types::Dirent {
|
||||||
|
d_ino: e.inode,
|
||||||
|
d_namlen: e.namelen,
|
||||||
|
d_type: types::Filetype::from(&e.filetype),
|
||||||
|
d_next: e.next.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dirent_bytes(dirent: types::Dirent) -> Vec<u8> {
|
||||||
|
use wiggle::GuestType;
|
||||||
|
assert_eq!(
|
||||||
|
types::Dirent::guest_size(),
|
||||||
|
std::mem::size_of::<types::Dirent>() as _,
|
||||||
|
"Dirent guest repr and host repr should match"
|
||||||
|
);
|
||||||
|
let size = types::Dirent::guest_size()
|
||||||
|
.try_into()
|
||||||
|
.expect("Dirent is smaller than 2^32");
|
||||||
|
let mut bytes = Vec::with_capacity(size);
|
||||||
|
bytes.resize(size, 0);
|
||||||
|
let ptr = bytes.as_mut_ptr() as *mut types::Dirent;
|
||||||
|
unsafe { ptr.write_unaligned(dirent) };
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user