Add /dev/zero, /dev/random, /dev/urandom, and /dev/arandom

This commit is contained in:
Tate, Hongliang Tian 2019-07-19 12:30:15 +00:00
parent 8cda63ab3a
commit 8686322afb
7 changed files with 283 additions and 27 deletions

@ -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 {

@ -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
}
}

@ -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

@ -0,0 +1,5 @@
include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

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));
}