mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-10 14:57:14 +00:00
std: add read and unlink to low-level FileDescriptor + end-to-end CRUD test
This commit is contained in:
parent
dabbac1d6c
commit
c49c2921b0
@ -13,12 +13,14 @@ use ptr::null;
|
||||
use libc::c_void;
|
||||
use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
|
||||
status_to_maybe_uv_error_with_loop,
|
||||
vec_to_uv_buf};//, vec_from_uv_buf};
|
||||
vec_to_uv_buf, vec_from_uv_buf};
|
||||
use rt::uv::uvll;
|
||||
use rt::uv::uvll::*;
|
||||
use path::Path;
|
||||
use cast::transmute;
|
||||
use libc::{c_int};
|
||||
use option::{None, Some, Option};
|
||||
use vec;
|
||||
|
||||
pub struct FsRequest(*uvll::uv_fs_t);
|
||||
impl Request for FsRequest;
|
||||
@ -110,7 +112,15 @@ impl FsRequest {
|
||||
fn cleanup_and_delete(self) {
|
||||
unsafe {
|
||||
let data = uvll::get_data_for_req(self.native_handle());
|
||||
let _data = transmute::<*c_void, ~RequestData>(data);
|
||||
let mut _data = transmute::<*c_void, ~RequestData>(data);
|
||||
// if set we're going to convert the buf param back into
|
||||
// a rust vec, as that's the mechanism by which the raw
|
||||
// uv_buf_t's .base field gets freed. We immediately discard
|
||||
// the result
|
||||
if _data.buf.is_some() {
|
||||
let buf = _data.buf.take_unwrap();
|
||||
vec_from_uv_buf(buf);
|
||||
}
|
||||
uvll::set_data_for_req(self.native_handle(), null::<()>());
|
||||
uvll::fs_req_cleanup(self.native_handle());
|
||||
free_req(self.native_handle() as *c_void)
|
||||
@ -146,6 +156,15 @@ impl FileDescriptor {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn unlink(loop_: Loop, path: Path, cb: FsCallback) -> int {
|
||||
let req = FsRequest::new(Some(cb));
|
||||
path.to_str().to_c_str().with_ref(|p| unsafe {
|
||||
uvll::fs_unlink(loop_.native_handle(),
|
||||
req.native_handle(), p, complete_cb) as int
|
||||
})
|
||||
}
|
||||
|
||||
// as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write
|
||||
pub fn write(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: FsCallback)
|
||||
-> int {
|
||||
let mut req = FsRequest::new(Some(cb));
|
||||
@ -161,6 +180,31 @@ impl FileDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
// really contemplated having this just take a read_len param and have
|
||||
// the buf live in the scope of this request.. but decided that exposing
|
||||
// an unsafe mechanism that takes a buf_ptr and len would be much more
|
||||
// flexible, but the caller is now in the position of managing that
|
||||
// buf (with all of the sadface that this entails)
|
||||
pub fn read(&self, loop_: Loop, buf_ptr: Option<*c_void>, len: uint, offset: i64, cb: FsCallback)
|
||||
-> int {
|
||||
let mut req = FsRequest::new(Some(cb));
|
||||
req.get_req_data().raw_fd = Some(self.native_handle());
|
||||
unsafe {
|
||||
let buf_ptr = match buf_ptr {
|
||||
Some(ptr) => ptr,
|
||||
None => {
|
||||
let buf = vec::from_elem(len, 0u8);
|
||||
let buf = vec_to_uv_buf(buf);
|
||||
req.get_req_data().buf = Some(buf);
|
||||
buf.base as *c_void
|
||||
}
|
||||
};
|
||||
uvll::fs_read(loop_.native_handle(), req.native_handle(),
|
||||
self.native_handle(), buf_ptr,
|
||||
len, offset, complete_cb) as int
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(self, loop_: Loop, cb: FsCallback) -> int {
|
||||
let req = FsRequest::new(Some(cb));
|
||||
unsafe {
|
||||
@ -205,90 +249,99 @@ impl NativeHandle<c_int> for FileDescriptor {
|
||||
mod test {
|
||||
use super::*;
|
||||
//use rt::test::*;
|
||||
use libc::{STDOUT_FILENO};
|
||||
use str;
|
||||
use unstable::run_in_bare_thread;
|
||||
use path::Path;
|
||||
use rt::uv::{Loop};//, slice_to_uv_buf};
|
||||
use rt::uv::{Loop, vec_from_uv_buf};//, slice_to_uv_buf};
|
||||
use option::{None};
|
||||
|
||||
// this is equiv to touch, i guess?
|
||||
fn file_test_touch_impl() {
|
||||
fn file_test_full_simple_impl() {
|
||||
debug!("hello?")
|
||||
do run_in_bare_thread {
|
||||
debug!("In bare thread")
|
||||
let mut loop_ = Loop::new();
|
||||
let flags = map_flag(O_RDWR) |
|
||||
let create_flags = map_flag(O_RDWR) |
|
||||
map_flag(O_CREAT);
|
||||
let read_flags = map_flag(O_RDONLY);
|
||||
// 0644
|
||||
let mode = map_mode(S_IWUSR) |
|
||||
map_mode(S_IRUSR) |
|
||||
map_mode(S_IRGRP) |
|
||||
map_mode(S_IROTH);
|
||||
do FileDescriptor::open(loop_, Path("./foo.txt"), flags, mode)
|
||||
let path_str = "./file_full_simple.txt";
|
||||
let write_val = "hello";
|
||||
do FileDescriptor::open(loop_, Path(path_str), create_flags, mode)
|
||||
|req, uverr| {
|
||||
let loop_ = req.get_loop();
|
||||
assert!(uverr.is_none());
|
||||
let fd = FileDescriptor::from_open_req(req);
|
||||
do fd.close(loop_) |_, uverr| {
|
||||
assert!(uverr.is_none());
|
||||
};
|
||||
};
|
||||
loop_.run();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_test_touch() {
|
||||
file_test_touch_impl();
|
||||
}
|
||||
|
||||
fn file_test_tee_impl() {
|
||||
debug!("hello?")
|
||||
do run_in_bare_thread {
|
||||
debug!("In bare thread")
|
||||
let mut loop_ = Loop::new();
|
||||
let flags = map_flag(O_RDWR) |
|
||||
map_flag(O_CREAT);
|
||||
// 0644
|
||||
let mode = map_mode(S_IWUSR) |
|
||||
map_mode(S_IRUSR) |
|
||||
map_mode(S_IRGRP) |
|
||||
map_mode(S_IROTH);
|
||||
do FileDescriptor::open(loop_, Path("./file_tee_test.txt"), flags, mode)
|
||||
|req, uverr| {
|
||||
let loop_ = req.get_loop();
|
||||
assert!(uverr.is_none());
|
||||
let fd = FileDescriptor::from_open_req(req);
|
||||
let msg: ~[u8] = "hello world".as_bytes().to_owned();
|
||||
let msg: ~[u8] = write_val.as_bytes().to_owned();
|
||||
let raw_fd = fd.native_handle();
|
||||
do fd.write(loop_, msg, -1) |_, uverr| {
|
||||
let fd = FileDescriptor(raw_fd);
|
||||
do fd.close(loop_) |_, _| {
|
||||
do fd.close(loop_) |req, _| {
|
||||
let loop_ = req.get_loop();
|
||||
assert!(uverr.is_none());
|
||||
do FileDescriptor::open(loop_, Path(path_str), read_flags,0)
|
||||
|req, uverr| {
|
||||
assert!(uverr.is_none());
|
||||
let loop_ = req.get_loop();
|
||||
let len = 1028;
|
||||
let fd = FileDescriptor::from_open_req(req);
|
||||
let raw_fd = fd.native_handle();
|
||||
do fd.read(loop_, None, len, 0) |req, uverr| {
|
||||
assert!(uverr.is_none());
|
||||
let loop_ = req.get_loop();
|
||||
// we know nread >=0 because uverr is none..
|
||||
let nread = req.get_result() as uint;
|
||||
// nread == 0 would be EOF
|
||||
if nread > 0 {
|
||||
let buf = vec_from_uv_buf(
|
||||
req.get_req_data().buf.take_unwrap())
|
||||
.take_unwrap();
|
||||
let read_str = str::from_bytes(
|
||||
buf.slice(0,
|
||||
nread));
|
||||
assert!(read_str == ~"hello");
|
||||
do FileDescriptor(raw_fd).close(loop_) |_,uverr| {
|
||||
assert!(uverr.is_none());
|
||||
do FileDescriptor::unlink(loop_, Path(path_str))
|
||||
|_,uverr| {
|
||||
assert!(uverr.is_none());
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
loop_.run();
|
||||
loop_.close();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_test_tee() {
|
||||
file_test_tee_impl();
|
||||
fn file_test_full_simple() {
|
||||
file_test_full_simple_impl();
|
||||
}
|
||||
|
||||
fn naive_print(input: ~str) {
|
||||
fn naive_print(loop_: Loop, input: ~str) {
|
||||
let stdout = FileDescriptor(STDOUT_FILENO);
|
||||
let msg = input.as_bytes().to_owned();
|
||||
do stdout.write(loop_, msg, -1) |_, uverr| {
|
||||
assert!(uverr.is_none());
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_test_write_to_stdout() {
|
||||
do run_in_bare_thread {
|
||||
let mut loop_ = Loop::new();
|
||||
let stdout = FileDescriptor(1);
|
||||
let msg = input.as_bytes().to_owned();
|
||||
do stdout.write(loop_, msg, -1) |_, uverr| {
|
||||
assert!(uverr.is_none());
|
||||
};
|
||||
naive_print(loop_, ~"zanzibar!\n");
|
||||
loop_.run();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_test_println() {
|
||||
naive_print(~"oh yeah.\n");
|
||||
loop_.close();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -621,10 +621,19 @@ pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags:
|
||||
cb: *u8) -> c_int {
|
||||
rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb)
|
||||
}
|
||||
|
||||
pub unsafe fn fs_unlink(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
|
||||
cb: *u8) -> c_int {
|
||||
rust_uv_fs_unlink(loop_ptr, req, path, cb)
|
||||
}
|
||||
pub unsafe fn fs_write(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void,
|
||||
len: uint, offset: i64, cb: *u8) -> c_int {
|
||||
rust_uv_fs_write(loop_ptr, req, fd, buf, len as c_uint, offset, cb)
|
||||
}
|
||||
pub unsafe fn fs_read(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void,
|
||||
len: uint, offset: i64, cb: *u8) -> c_int {
|
||||
rust_uv_fs_read(loop_ptr, req, fd, buf, len as c_uint, offset, cb)
|
||||
}
|
||||
pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int,
|
||||
cb: *u8) -> c_int {
|
||||
rust_uv_fs_close(loop_ptr, req, fd, cb)
|
||||
@ -817,8 +826,12 @@ extern {
|
||||
fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int;
|
||||
fn rust_uv_fs_open(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
|
||||
flags: c_int, mode: c_int, cb: *u8) -> c_int;
|
||||
fn rust_uv_fs_unlink(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
|
||||
cb: *u8) -> c_int;
|
||||
fn rust_uv_fs_write(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
|
||||
buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int;
|
||||
fn rust_uv_fs_read(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
|
||||
buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int;
|
||||
fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
|
||||
cb: *u8) -> c_int;
|
||||
fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
|
||||
|
@ -13,11 +13,6 @@
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#ifndef __WIN32__
|
||||
// for signal
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "uv.h"
|
||||
|
||||
@ -521,6 +516,20 @@ rust_uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
|
||||
return uv_fs_open(loop, req, path, flags, mode, cb);
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
return uv_fs_unlink(loop, req, path, cb);
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
|
||||
size_t len, int64_t offset, uv_fs_cb cb) {
|
||||
return uv_fs_write(loop, req, fd, buf, len, offset, cb);
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
|
||||
size_t len, int64_t offset, uv_fs_cb cb) {
|
||||
return uv_fs_read(loop, req, fd, buf, len, offset, cb);
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
|
||||
return uv_fs_close(loop, req, fd, cb);
|
||||
}
|
||||
@ -549,6 +558,22 @@ rust_uv_get_O_TRUNC() {
|
||||
return O_TRUNC;
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_get_S_IWUSR() {
|
||||
return S_IWUSR;
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_get_S_IRUSR() {
|
||||
return S_IRUSR;
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_get_S_IRGRP() {
|
||||
return S_IRGRP;
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_get_S_IROTH() {
|
||||
return S_IROTH;
|
||||
}
|
||||
extern "C" int
|
||||
rust_uv_get_result_from_fs_req(uv_fs_t* req) {
|
||||
return req->result;
|
||||
}
|
||||
|
@ -109,7 +109,9 @@ rust_uv_idle_init
|
||||
rust_uv_idle_start
|
||||
rust_uv_idle_stop
|
||||
rust_uv_fs_open
|
||||
rust_uv_fs_unlink
|
||||
rust_uv_fs_write
|
||||
rust_uv_fs_read
|
||||
rust_uv_fs_close
|
||||
rust_uv_get_O_RDONLY
|
||||
rust_uv_get_O_WRONLY
|
||||
|
Loading…
Reference in New Issue
Block a user