diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 2a16a34070d..ef8c131688b 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -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 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(); + }; } } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 0fbf45fca97..1b257b708c4 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -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); diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index a788b0f71a4..e08b4ac21eb 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -13,11 +13,6 @@ #include #endif -#ifndef __WIN32__ -// for signal -#include -#endif - #include #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; } diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index d342ffa194a..824a3931771 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -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