Skip to content

Commit

Permalink
feat(preview1): implement fd_readdir
Browse files Browse the repository at this point in the history
Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
  • Loading branch information
rvolosatovs committed May 25, 2023
1 parent c17a015 commit 0294f48
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ async fn fd_flags_set() {
run("fd_flags_set", true).await.unwrap()
}
#[test_log::test(tokio::test(flavor = "multi_thread"))]
#[should_panic]
async fn fd_readdir() {
run("fd_readdir", true).await.unwrap()
}
Expand Down
83 changes: 82 additions & 1 deletion crates/wasi/src/preview2/preview1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
#![allow(unused_variables)]

use crate::preview2::filesystem::TableFsExt;
use crate::preview2::preview2::filesystem::TableReaddirExt;
use crate::preview2::{wasi, TableError, WasiView};

use core::borrow::Borrow;
use core::cell::Cell;
use core::mem::size_of;
use core::ops::{Deref, DerefMut};
use core::slice;
use core::sync::atomic::{AtomicU64, Ordering};

use std::collections::BTreeMap;
Expand Down Expand Up @@ -1373,7 +1376,85 @@ impl<
buf_len: types::Size,
cookie: types::Dircookie,
) -> Result<types::Size, types::Error> {
todo!()
let fd = self.get_dir_fd(fd).await?;
let stream = self.read_directory(fd).await.map_err(|e| {
e.try_into()
.context("failed to call `read-directory`")
.unwrap_or_else(types::Error::trap)
})?;
let wasi::filesystem::DescriptorStat {
inode: fd_inode, ..
} = self.stat(fd).await.map_err(|e| {
e.try_into()
.context("failed to call `stat`")
.unwrap_or_else(types::Error::trap)
})?;
let cookie = cookie.try_into().map_err(|_| types::Errno::Overflow)?;
let dir = self.table_mut().delete_readdir(stream)?;
[
(
types::Dirent {
d_next: 1,
d_ino: fd_inode,
d_type: types::Filetype::Directory,
d_namlen: 1,
},
".".into(),
),
(
types::Dirent {
d_next: 2,
d_ino: fd_inode, // NOTE: legacy implementation returns `fd` inode here
d_type: types::Filetype::Directory,
d_namlen: 2,
},
"..".into(),
),
]
.into_iter()
.map(Ok::<_, types::Error>)
.chain(dir.into_iter().zip(3..).map(|(entry, d_next)| {
let wasi::filesystem::DirectoryEntry { inode, type_, name } = entry.map_err(|e| {
e.try_into()
.context("failed to inspect `read-directory` entry")
.unwrap_or_else(types::Error::trap)
})?;
let d_ino = inode.unwrap_or_default();
let d_type = type_.try_into().map_err(types::Error::trap)?;
let d_namlen = name.len().try_into().map_err(|_| types::Errno::Overflow)?;
Ok((
types::Dirent {
d_next,
d_ino,
d_type,
d_namlen,
},
name,
))
}))
.skip(cookie)
.try_fold((*buf, buf_len, 0u32), |(buf, buf_len, n), e| {
// assume that `types::Dirent` always fits in `u32`
const DIRENT_SIZE: u32 = size_of::<types::Dirent>() as _;
let (ref entry, mut path) = e?;

let entry_len = buf_len.min(DIRENT_SIZE);
let entry = entry as *const _ as _;
let entry = unsafe { slice::from_raw_parts(entry, entry_len as _) };
let buf_len = buf_len.checked_sub(entry_len).unwrap();
let n = n.checked_add(entry_len).unwrap();
let buf = write_bytes(buf, entry)?;

if let Ok(buf_len) = buf_len.try_into() {
path.truncate(buf_len);
}
let buf_len = buf_len.checked_sub(path.len() as _).unwrap();
let n = n.checked_add(path.len() as _).unwrap();
let buf = write_bytes(buf, path)?;

Ok((buf, buf_len, n))
})
.map(|(_, _, n)| n)
}

#[instrument(skip(self))]
Expand Down

0 comments on commit 0294f48

Please sign in to comment.