Skip to content

Commit

Permalink
feat(Judger): 🚧 draft crate::sandbox::Context implementer in language…
Browse files Browse the repository at this point in the history
… model
  • Loading branch information
Eason0729 committed May 10, 2024
1 parent 6340782 commit d0bf656
Show file tree
Hide file tree
Showing 18 changed files with 293 additions and 274 deletions.
106 changes: 96 additions & 10 deletions judger/src/filesystem/adapter/fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ use std::{ffi::OsStr, num::NonZeroU32, path::Path, sync::Arc};
use futures_core::Future;
use spin::Mutex;
use tokio::io::{AsyncRead, AsyncSeek};
use tokio::sync::Mutex as AsyncMutex;
use tokio::sync::{Mutex as AsyncMutex, OwnedSemaphorePermit};

use crate::{
filesystem::{resource::Resource, Entry, TarTree, BLOCKSIZE},
semaphore::Permit,
};
use crate::filesystem::entry::{Entry, TarTree, BLOCKSIZE};
use crate::filesystem::resource::Resource;

use super::{error::FuseError, handle::HandleTable, reply::*};
use fuse3::{
Expand All @@ -24,19 +22,17 @@ where
handle_table: HandleTable<AsyncMutex<Entry<F>>>,
tree: Mutex<TarTree<F>>,
resource: Arc<Resource>,
_permit: Permit,
}

impl<F> Filesystem<F>
where
F: AsyncRead + AsyncSeek + Unpin + Send + Sync + 'static,
{
pub(super) fn new(tree: TarTree<F>, permit: Permit) -> Self {
pub(super) fn new(tree: TarTree<F>, permit: u64) -> Self {
Self {
handle_table: HandleTable::new(),
tree: Mutex::new(tree),
resource: Arc::new(Resource::new(permit.count())),
_permit: permit,
resource: Arc::new(Resource::new(permit)),
}
}
pub async fn mount(self, path: impl AsRef<Path> + Clone) -> std::io::Result<MountHandle> {
Expand Down Expand Up @@ -81,14 +77,30 @@ where
async move {
let tree = self.tree.lock();
let parent_node = tree.get(parent as usize).ok_or(FuseError::InvaildIno)?;
let node = parent_node.get_by_component(name).ok_or(FuseError::InvalidPath)?;
let node = parent_node
.get_by_component(name)
.ok_or(FuseError::InvalidPath)?;
// FIXME: unsure about the inode
Ok(reply_entry(&req, node.get_value(), node.get_id() as u64))
}
}
fn forget(&self, _: Request, inode: u64, _: u64) -> impl Future<Output = ()> + Send {
async {}
}
fn release(
&self,
req: Request,
inode: u64,
fh: u64,
flags: u32,
lock_owner: u64,
flush: bool,
) -> impl Future<Output = FuseResult<()>> + Send {
async move {
self.handle_table.remove(fh);
Ok(())
}
}
fn statfs(
&self,
_: Request,
Expand Down Expand Up @@ -412,3 +424,77 @@ where
}
}
}

#[cfg(test)]
mod test {
use std::{
ffi::OsStr,
sync::atomic::{AtomicU64, Ordering},
};

use fuse3::{
raw::{Filesystem as _, Request},
Errno,
};
use tokio::fs::File;

use crate::filesystem::adapter::Template;

use super::Filesystem;

const UNIQUE_COUNTER: AtomicU64 = AtomicU64::new(0);

async fn nested_tar() -> Filesystem<File> {
let template = Template::new("test/nested.tar").await.unwrap();
template.as_filesystem(1024 * 1024)
}
fn spawn_request() -> Request {
Request {
unique: UNIQUE_COUNTER.fetch_add(1, Ordering::AcqRel),
uid: 1000,
gid: 1000,
pid: 2,
}
}

#[tokio::test]
async fn lookup() {
let fs = nested_tar().await;
assert_eq!(
fs.lookup(spawn_request(), 1, OsStr::new("nest"))
.await
.unwrap()
.attr
.ino,
2
);
assert_eq!(
fs.lookup(spawn_request(), 1, OsStr::new("o.txt"))
.await
.unwrap()
.attr
.ino,
5
);
assert_eq!(
fs.lookup(spawn_request(), 2, OsStr::new("a.txt"))
.await
.unwrap()
.attr
.ino,
3
);
assert_eq!(
fs.lookup(spawn_request(), 2, OsStr::new("o.txt"))
.await
.unwrap_err(),
Errno::new_not_exist()
);
assert_eq!(
fs.lookup(spawn_request(), 100, OsStr::new("o.txt"))
.await
.unwrap_err(),
libc::ENOENT.into()
)
}
}
14 changes: 3 additions & 11 deletions judger/src/filesystem/adapter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub use template::Template;
#[cfg(test)]
mod test {
use super::*;
use crate::semaphore::Semaphore;
// use crate::semaphore::Semaphore;
use env_logger::*;

#[tokio::test]
Expand All @@ -22,17 +22,9 @@ mod test {
.ok();

log::info!("mounting test tarball in .temp ...");
let global_resource = Semaphore::new(4096 * 1024 * 1024, 1);
let template = Template::new("test/nested.tar").await.unwrap();
let filesystem = template
.as_filesystem(
global_resource
.get_permit(1024 * 1024 * 1024)
.await
.unwrap(),
)
.await;
let mut mount_handle = filesystem.mount("./.temp/18").await.unwrap();
let filesystem = template.as_filesystem(1024 * 1024 * 1024);
let mut mount_handle = filesystem.mount("./.temp/1").await.unwrap();
let handle = &mut mount_handle;

tokio::select! {
Expand Down
2 changes: 1 addition & 1 deletion judger/src/filesystem/adapter/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use fuse3::{
};
use tokio::io::{AsyncRead, AsyncSeek};

use crate::filesystem::{Entry, BLOCKSIZE};
use crate::filesystem::{entry::Entry, entry::BLOCKSIZE};

const TTL: Duration = Duration::from_secs(1);

Expand Down
10 changes: 5 additions & 5 deletions judger/src/filesystem/adapter/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ use tokio::{
io::{AsyncRead, AsyncSeek},
};

use crate::{
filesystem::{table::DeepClone, TarTree},
semaphore::Permit,
};
use crate::filesystem::entry::TarTree;

use super::fuse::Filesystem;

Expand All @@ -26,9 +23,12 @@ where
pub fn new_inner(tree: TarTree<F>) -> Self {
Self { tree }
}
pub async fn as_filesystem(&self, permit: Permit) -> Filesystem<F> {
pub fn as_filesystem(&self, permit: u64) -> Filesystem<F> {
Filesystem::new(self.tree.clone(), permit)
}
pub async fn read_by_path(&self, path: impl AsRef<Path>) -> Option<Vec<u8>> {
self.tree.read_by_path(path).await
}
}

impl Template<File> {
Expand Down
17 changes: 10 additions & 7 deletions judger/src/filesystem/entry/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
mod ro;
mod rw;
mod tar;
pub mod prelude {
pub use super::tar::TarTree;
pub use super::Entry;
pub use super::MEMBLOCK_BLOCKSIZE as BLOCKSIZE;
}

use self::{ro::TarBlock, rw::MemBlock};
use bytes::Bytes;
Expand All @@ -16,9 +11,10 @@ use tokio::{
sync::{Mutex, OwnedMutexGuard},
};

use super::{resource::Resource, table::DeepClone};
use super::resource::Resource;

pub const MEMBLOCK_BLOCKSIZE: usize = 4096;
pub use tar::TarTree;
pub const BLOCKSIZE: usize = 4096;

pub trait FuseReadTrait {
async fn read(&mut self, offset: u64, size: u32) -> std::io::Result<Bytes>;
Expand Down Expand Up @@ -97,6 +93,13 @@ where
_ => None,
}
}
pub async fn read_all(&self) -> Option<Vec<u8>> {
match self {
Self::TarFile(block) => Some(block.read_all().await.expect("tar ball corrupted")),
Self::MemFile(block) => None,
_ => None,
}
}
pub async fn write(
self_: Arc<Mutex<Self>>,
offset: u64,
Expand Down
15 changes: 7 additions & 8 deletions judger/src/filesystem/entry/ro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,13 @@ where
pub fn get_size(&self) -> u32 {
self.size
}
// pub async fn read_all(&self) -> std::io::Result<Vec<u8>> {
// // let mut buf = Vec::with_capacity(self.size as usize);
// // let mut block = self.clone();
// // block.seek(SeekFrom::Start(0)).await?;
// // block.read_to_end(&mut buf).await?;
// // Ok(buf)
// todo!()
// }
pub async fn read_all(&self) -> std::io::Result<Vec<u8>> {
let mut lock = self.file.lock().await;
lock.seek(SeekFrom::Start(self.start)).await?;
let mut buf = vec![0_u8; self.size as usize];
lock.read_exact(&mut buf).await?;
Ok(buf)
}
#[cfg(test)]
fn from_raw(file: F, start: u64, size: u32) -> Self {
Self {
Expand Down
2 changes: 1 addition & 1 deletion judger/src/filesystem/entry/rw.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{io, ops::Deref, sync::Arc};
use tokio::sync::Mutex;

use super::{FuseReadTrait, FuseWriteTrait, MEMBLOCK_BLOCKSIZE};
use super::{FuseReadTrait, FuseWriteTrait, BLOCKSIZE};

/// A block in memory
///
Expand Down
4 changes: 4 additions & 0 deletions judger/src/filesystem/entry/tar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ impl<F> TarTree<F>
where
F: AsyncRead + AsyncSeek + Unpin + Send + 'static,
{
pub async fn read_by_path(&self, path: impl AsRef<Path>) -> Option<Vec<u8>> {
let node = self.0.get_by_path(to_internal_path(path.as_ref()))?;
Some(node.get_value().read_all().await.unwrap())
}
async fn parse_entry<R: Read>(
&mut self,
entry: tar::Entry<'_, R>,
Expand Down
33 changes: 33 additions & 0 deletions judger/src/filesystem/mkdtemp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use std::{
ffi::{CStr, CString, OsStr},
os::unix::ffi::OsStrExt,
path::{Path, PathBuf},
};

use tokio::fs::remove_dir;

pub struct MkdTemp(PathBuf);

impl Drop for MkdTemp {
fn drop(&mut self) {
tokio::spawn(remove_dir(self.0.clone()));
}
}

impl MkdTemp {
pub fn new() -> Self {
Self(unsafe { Self::new_inner("mdoj-XXXXXX") })
}
pub unsafe fn new_inner(template: &str) -> PathBuf {
let template = CString::new(template).unwrap();
let tmp_ptr = libc::mkdtemp(template.as_ptr() as *mut _);
let tmp_path = CStr::from_ptr(tmp_ptr);
let str_path = OsStr::from_bytes(tmp_path.to_bytes());
drop(template);
// libc::free(tmp_ptr as *mut _);
PathBuf::from(str_path)
}
pub fn get_path(&self) -> &Path {
self.0.as_path()
}
}
4 changes: 3 additions & 1 deletion judger/src/filesystem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
mod adapter;
mod entry;
mod error;
mod mkdtemp;
mod resource;
mod table;

pub use entry::prelude::*;
pub use adapter::{Filesystem, Template};
pub use fuse3::raw::MountHandle;
14 changes: 0 additions & 14 deletions judger/src/filesystem/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,13 @@ pub fn to_internal_path<'a>(path: &'a Path) -> impl Iterator<Item = &OsStr> + 'a
// .collect::<Vec<_>>()
}

pub trait DeepClone {
async fn deep_clone(&self) -> Self;
}

#[derive(Clone)]
struct Node<V> {
parent_idx: usize,
value: V,
children: BTreeMap<OsString, usize>, // FIXME: use BtreeMap
}

impl<V: DeepClone> DeepClone for Node<V> {
async fn deep_clone(&self) -> Self {
Self {
parent_idx: self.parent_idx,
value: self.value.deep_clone().await,
children: self.children.iter().map(|(k, v)| (k.clone(), *v)).collect(),
}
}
}

#[derive(Clone)]
pub struct AdjTable<V> {
by_id: Vec<Node<V>>,
Expand Down
Loading

0 comments on commit d0bf656

Please sign in to comment.