about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorJeff Olson <olson.jeffery@gmail.com>2013-08-16 17:47:35 -0700
committerJeff Olson <olson.jeffery@gmail.com>2013-08-22 16:31:57 -0700
commitc49c2921b0250fee51b935e3d164cc1bdb8a9445 (patch)
tree0e00def1ca96a9ee9a56a445b9dbbae4386091c9 /src/libstd
parentdabbac1d6c06c00f24148ffc58b42455496fdd3c (diff)
std: add read and unlink to low-level FileDescriptor + end-to-end CRUD test
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rt/uv/file.rs159
-rw-r--r--src/libstd/rt/uv/uvll.rs13
2 files changed, 119 insertions, 53 deletions
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<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};
-
-    // this is equiv to touch, i guess?
-    fn file_test_touch_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("./foo.txt"), 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();
-    }
+    use rt::uv::{Loop, vec_from_uv_buf};//, slice_to_uv_buf};
+    use option::{None};
 
-    fn file_test_tee_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("./file_tee_test.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);
-                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) {
-        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());
-            };
-            loop_.run();
-        }
+    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_println() {
-        naive_print(~"oh yeah.\n");
+    fn file_test_write_to_stdout() {
+        do run_in_bare_thread {
+            let mut loop_ = Loop::new();
+            naive_print(loop_, ~"zanzibar!\n");
+            loop_.run();
+            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);