Add /dev/zero, /dev/random, /dev/urandom, and /dev/arandom
This commit is contained in:
parent
8cda63ab3a
commit
8686322afb
@ -1,35 +1,35 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NullFile;
|
||||
|
||||
impl File for NullFile {
|
||||
fn read(&self, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
pub struct DevNull;
|
||||
|
||||
impl File for DevNull {
|
||||
fn write(&self, _buf: &[u8]) -> Result<usize, Error> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
unimplemented!()
|
||||
Ok(_buf.len())
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> {
|
||||
unimplemented!()
|
||||
Ok(_buf.len())
|
||||
}
|
||||
|
||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> {
|
||||
unimplemented!()
|
||||
Ok(bufs.iter().map(|buf| buf.len()).sum())
|
||||
}
|
||||
|
||||
fn read(&self, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support reads")
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support reads")
|
||||
}
|
||||
|
||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support reads")
|
||||
}
|
||||
|
||||
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> {
|
||||
unimplemented!()
|
||||
errno!(EINVAL, "device not support seeks")
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Metadata, Error> {
|
||||
@ -37,19 +37,19 @@ impl File for NullFile {
|
||||
}
|
||||
|
||||
fn set_len(&self, len: u64) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
errno!(EINVAL, "device not support resizing")
|
||||
}
|
||||
|
||||
fn sync_all(&self) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sync_data(&self) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_entry(&self) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
errno!(ENOTDIR, "device is not a directory")
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &Any {
|
84
src/libos/src/fs/dev_random.rs
Normal file
84
src/libos/src/fs/dev_random.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DevRandom;
|
||||
|
||||
extern "C" {
|
||||
fn sgx_read_rand(rand_buf: *mut u8, buf_size: usize) -> sgx_status_t;
|
||||
}
|
||||
|
||||
impl File for DevRandom {
|
||||
fn read(&self, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
let buf = _buf.as_mut_ptr();
|
||||
let size = _buf.len();
|
||||
let status = unsafe { sgx_read_rand(buf, size) };
|
||||
if status != sgx_status_t::SGX_SUCCESS {
|
||||
return errno!(EAGAIN, "failed to get random number from sgx");
|
||||
}
|
||||
Ok(size)
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
self.read(_buf)
|
||||
}
|
||||
|
||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> {
|
||||
let mut total_nbytes = 0;
|
||||
for buf in bufs {
|
||||
match self.read(buf) {
|
||||
Ok(this_nbytes) => {
|
||||
total_nbytes += this_nbytes;
|
||||
}
|
||||
Err(e) => {
|
||||
if total_nbytes > 0 {
|
||||
break
|
||||
}
|
||||
else {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(total_nbytes)
|
||||
}
|
||||
|
||||
fn write(&self, _buf: &[u8]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support writes")
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support writes")
|
||||
}
|
||||
|
||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support writes")
|
||||
}
|
||||
|
||||
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> {
|
||||
errno!(EINVAL, "device not support seeks")
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Metadata, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_len(&self, len: u64) -> Result<(), Error> {
|
||||
errno!(EINVAL, "device not support resizing")
|
||||
}
|
||||
|
||||
fn sync_all(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sync_data(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_entry(&self) -> Result<String, Error> {
|
||||
errno!(ENOTDIR, "device is not a directory")
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &Any {
|
||||
self
|
||||
}
|
||||
}
|
65
src/libos/src/fs/dev_zero.rs
Normal file
65
src/libos/src/fs/dev_zero.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DevZero;
|
||||
|
||||
impl File for DevZero {
|
||||
fn read(&self, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
for b in _buf.iter_mut() {
|
||||
*b = 0;
|
||||
}
|
||||
Ok(_buf.len())
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
self.read(_buf)
|
||||
}
|
||||
|
||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> {
|
||||
let mut total_nbytes = 0;
|
||||
for buf in bufs {
|
||||
total_nbytes += self.read(buf)?;
|
||||
}
|
||||
Ok(total_nbytes)
|
||||
}
|
||||
|
||||
fn write(&self, _buf: &[u8]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support writes")
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support writes")
|
||||
}
|
||||
|
||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> {
|
||||
errno!(EINVAL, "device not support writes")
|
||||
}
|
||||
|
||||
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> {
|
||||
errno!(EINVAL, "device not support seeks")
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Metadata, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_len(&self, len: u64) -> Result<(), Error> {
|
||||
errno!(EINVAL, "device not support resizing")
|
||||
}
|
||||
|
||||
fn sync_all(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sync_data(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_entry(&self) -> Result<String, Error> {
|
||||
errno!(ENOTDIR, "device is not a directory")
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &Any {
|
||||
self
|
||||
}
|
||||
}
|
@ -12,7 +12,9 @@ pub use self::file_table::{FileDesc, FileTable};
|
||||
use self::inode_file::OpenOptions;
|
||||
pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE};
|
||||
pub use self::io_multiplexing::*;
|
||||
use self::null::NullFile;
|
||||
use self::dev_null::DevNull;
|
||||
use self::dev_zero::DevZero;
|
||||
use self::dev_random::DevRandom;
|
||||
pub use self::pipe::Pipe;
|
||||
pub use self::socket_file::{AsSocket, SocketFile};
|
||||
pub use self::unix_socket::{AsUnixSocket, UnixSocketFile};
|
||||
@ -25,7 +27,9 @@ mod file_table;
|
||||
mod hostfs;
|
||||
mod inode_file;
|
||||
mod io_multiplexing;
|
||||
mod null;
|
||||
mod dev_null;
|
||||
mod dev_zero;
|
||||
mod dev_random;
|
||||
mod pipe;
|
||||
mod sgx_impl;
|
||||
mod socket_file;
|
||||
@ -410,7 +414,13 @@ impl Process {
|
||||
/// Open a file on the process. But DO NOT add it to file table.
|
||||
pub fn open_file(&self, path: &str, flags: OpenFlags, mode: u32) -> Result<Box<File>, Error> {
|
||||
if path == "/dev/null" {
|
||||
return Ok(Box::new(NullFile));
|
||||
return Ok(Box::new(DevNull));
|
||||
}
|
||||
if path == "/dev/zero" {
|
||||
return Ok(Box::new(DevZero));
|
||||
}
|
||||
if path == "/dev/random" || path == "/dev/urandom" || path == "/dev/arandom" {
|
||||
return Ok(Box::new(DevRandom));
|
||||
}
|
||||
let inode = if flags.contains(OpenFlags::CREATE) {
|
||||
let (dir_path, file_name) = split_path(&path);
|
||||
|
@ -4,8 +4,9 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
||||
# Dependencies: need to be compiled but not to run by any Makefile target
|
||||
TEST_DEPS := dev_null
|
||||
# Tests: need to be compiled and run by test-% target
|
||||
#TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket cout hostfs cpuid rdtsc
|
||||
TESTS := hello_world file readdir mkdir link hostfs
|
||||
TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time \
|
||||
truncate readdir mkdir link tls pthread uname rlimit client server \
|
||||
server_epoll unix_socket cout hostfs cpuid rdtsc device
|
||||
# Benchmarks: need to be compiled and run by bench-% target
|
||||
BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput
|
||||
|
||||
|
5
test/device/Makefile
Normal file
5
test/device/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
91
test/device/main.c
Normal file
91
test/device/main.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "test.h"
|
||||
|
||||
// ============================================================================
|
||||
// Test utilities
|
||||
// ============================================================================
|
||||
|
||||
static int check_file_readable(const char* filename) {
|
||||
int fd;
|
||||
char buf[512] = {0};
|
||||
int len;
|
||||
if ((fd = open(filename, O_RDONLY)) < 0) {
|
||||
throw_error("failed to open the file");
|
||||
}
|
||||
if ((len = read(fd, buf, sizeof(buf))) != sizeof(buf)) {
|
||||
throw_error("failed to read the file");
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_file_writable(const char* filename) {
|
||||
int fd;
|
||||
char buf[512] = {0};
|
||||
int len;
|
||||
if ((fd = open(filename, O_WRONLY)) < 0) {
|
||||
throw_error("failed to open the file");
|
||||
}
|
||||
if ((len = write(fd, buf, sizeof(buf))) != sizeof(buf)) {
|
||||
throw_error("failed to read the file");
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Test cases for /dev/random, /dev/urandom, /dev/
|
||||
// ============================================================================
|
||||
|
||||
int test_dev_null() {
|
||||
if (check_file_writable("/dev/null")) {
|
||||
throw_error("failed to write to /dev/null");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_dev_zero() {
|
||||
if (check_file_readable("/dev/zero")) {
|
||||
throw_error("failed to read from /dev/null");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_dev_random() {
|
||||
if (check_file_readable("/dev/random")) {
|
||||
throw_error("failed to read from /dev/random");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_dev_urandom() {
|
||||
if (check_file_readable("/dev/urandom")) {
|
||||
throw_error("failed to read from /dev/urandom");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_dev_arandom() {
|
||||
if (check_file_readable("/dev/arandom")) {
|
||||
throw_error("failed to read from /dev/arandom");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Test suite
|
||||
// ============================================================================
|
||||
|
||||
static test_case_t test_cases[] = {
|
||||
TEST_CASE(test_dev_null),
|
||||
TEST_CASE(test_dev_zero),
|
||||
TEST_CASE(test_dev_random),
|
||||
TEST_CASE(test_dev_urandom),
|
||||
TEST_CASE(test_dev_arandom),
|
||||
};
|
||||
|
||||
int main() {
|
||||
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
|
||||
}
|
Loading…
Reference in New Issue
Block a user