Skip to content

Commit c49c292

Browse files
committed
std: add read and unlink to low-level FileDescriptor + end-to-end CRUD test
1 parent dabbac1 commit c49c292

File tree

4 files changed

+151
-58
lines changed

4 files changed

+151
-58
lines changed

src/libstd/rt/uv/file.rs

Lines changed: 106 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ use ptr::null;
1313
use libc::c_void;
1414
use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
1515
status_to_maybe_uv_error_with_loop,
16-
vec_to_uv_buf};//, vec_from_uv_buf};
16+
vec_to_uv_buf, vec_from_uv_buf};
1717
use rt::uv::uvll;
1818
use rt::uv::uvll::*;
1919
use path::Path;
2020
use cast::transmute;
2121
use libc::{c_int};
22+
use option::{None, Some, Option};
23+
use vec;
2224

2325
pub struct FsRequest(*uvll::uv_fs_t);
2426
impl Request for FsRequest;
@@ -110,7 +112,15 @@ impl FsRequest {
110112
fn cleanup_and_delete(self) {
111113
unsafe {
112114
let data = uvll::get_data_for_req(self.native_handle());
113-
let _data = transmute::<*c_void, ~RequestData>(data);
115+
let mut _data = transmute::<*c_void, ~RequestData>(data);
116+
// if set we're going to convert the buf param back into
117+
// a rust vec, as that's the mechanism by which the raw
118+
// uv_buf_t's .base field gets freed. We immediately discard
119+
// the result
120+
if _data.buf.is_some() {
121+
let buf = _data.buf.take_unwrap();
122+
vec_from_uv_buf(buf);
123+
}
114124
uvll::set_data_for_req(self.native_handle(), null::<()>());
115125
uvll::fs_req_cleanup(self.native_handle());
116126
free_req(self.native_handle() as *c_void)
@@ -146,6 +156,15 @@ impl FileDescriptor {
146156
})
147157
}
148158

159+
pub fn unlink(loop_: Loop, path: Path, cb: FsCallback) -> int {
160+
let req = FsRequest::new(Some(cb));
161+
path.to_str().to_c_str().with_ref(|p| unsafe {
162+
uvll::fs_unlink(loop_.native_handle(),
163+
req.native_handle(), p, complete_cb) as int
164+
})
165+
}
166+
167+
// as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write
149168
pub fn write(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: FsCallback)
150169
-> int {
151170
let mut req = FsRequest::new(Some(cb));
@@ -161,6 +180,31 @@ impl FileDescriptor {
161180
}
162181
}
163182

183+
// really contemplated having this just take a read_len param and have
184+
// the buf live in the scope of this request.. but decided that exposing
185+
// an unsafe mechanism that takes a buf_ptr and len would be much more
186+
// flexible, but the caller is now in the position of managing that
187+
// buf (with all of the sadface that this entails)
188+
pub fn read(&self, loop_: Loop, buf_ptr: Option<*c_void>, len: uint, offset: i64, cb: FsCallback)
189+
-> int {
190+
let mut req = FsRequest::new(Some(cb));
191+
req.get_req_data().raw_fd = Some(self.native_handle());
192+
unsafe {
193+
let buf_ptr = match buf_ptr {
194+
Some(ptr) => ptr,
195+
None => {
196+
let buf = vec::from_elem(len, 0u8);
197+
let buf = vec_to_uv_buf(buf);
198+
req.get_req_data().buf = Some(buf);
199+
buf.base as *c_void
200+
}
201+
};
202+
uvll::fs_read(loop_.native_handle(), req.native_handle(),
203+
self.native_handle(), buf_ptr,
204+
len, offset, complete_cb) as int
205+
}
206+
}
207+
164208
pub fn close(self, loop_: Loop, cb: FsCallback) -> int {
165209
let req = FsRequest::new(Some(cb));
166210
unsafe {
@@ -205,90 +249,99 @@ impl NativeHandle<c_int> for FileDescriptor {
205249
mod test {
206250
use super::*;
207251
//use rt::test::*;
252+
use libc::{STDOUT_FILENO};
253+
use str;
208254
use unstable::run_in_bare_thread;
209255
use path::Path;
210-
use rt::uv::{Loop};//, slice_to_uv_buf};
211-
212-
// this is equiv to touch, i guess?
213-
fn file_test_touch_impl() {
214-
debug!("hello?")
215-
do run_in_bare_thread {
216-
debug!("In bare thread")
217-
let mut loop_ = Loop::new();
218-
let flags = map_flag(O_RDWR) |
219-
map_flag(O_CREAT);
220-
// 0644
221-
let mode = map_mode(S_IWUSR) |
222-
map_mode(S_IRUSR) |
223-
map_mode(S_IRGRP) |
224-
map_mode(S_IROTH);
225-
do FileDescriptor::open(loop_, Path("./foo.txt"), flags, mode)
226-
|req, uverr| {
227-
let loop_ = req.get_loop();
228-
assert!(uverr.is_none());
229-
let fd = FileDescriptor::from_open_req(req);
230-
do fd.close(loop_) |_, uverr| {
231-
assert!(uverr.is_none());
232-
};
233-
};
234-
loop_.run();
235-
}
236-
}
237-
238-
#[test]
239-
fn file_test_touch() {
240-
file_test_touch_impl();
241-
}
256+
use rt::uv::{Loop, vec_from_uv_buf};//, slice_to_uv_buf};
257+
use option::{None};
242258

243-
fn file_test_tee_impl() {
259+
fn file_test_full_simple_impl() {
244260
debug!("hello?")
245261
do run_in_bare_thread {
246262
debug!("In bare thread")
247263
let mut loop_ = Loop::new();
248-
let flags = map_flag(O_RDWR) |
264+
let create_flags = map_flag(O_RDWR) |
249265
map_flag(O_CREAT);
266+
let read_flags = map_flag(O_RDONLY);
250267
// 0644
251268
let mode = map_mode(S_IWUSR) |
252269
map_mode(S_IRUSR) |
253270
map_mode(S_IRGRP) |
254271
map_mode(S_IROTH);
255-
do FileDescriptor::open(loop_, Path("./file_tee_test.txt"), flags, mode)
272+
let path_str = "./file_full_simple.txt";
273+
let write_val = "hello";
274+
do FileDescriptor::open(loop_, Path(path_str), create_flags, mode)
256275
|req, uverr| {
257276
let loop_ = req.get_loop();
258277
assert!(uverr.is_none());
259278
let fd = FileDescriptor::from_open_req(req);
260-
let msg: ~[u8] = "hello world".as_bytes().to_owned();
279+
let msg: ~[u8] = write_val.as_bytes().to_owned();
261280
let raw_fd = fd.native_handle();
262281
do fd.write(loop_, msg, -1) |_, uverr| {
263282
let fd = FileDescriptor(raw_fd);
264-
do fd.close(loop_) |_, _| {
283+
do fd.close(loop_) |req, _| {
284+
let loop_ = req.get_loop();
265285
assert!(uverr.is_none());
286+
do FileDescriptor::open(loop_, Path(path_str), read_flags,0)
287+
|req, uverr| {
288+
assert!(uverr.is_none());
289+
let loop_ = req.get_loop();
290+
let len = 1028;
291+
let fd = FileDescriptor::from_open_req(req);
292+
let raw_fd = fd.native_handle();
293+
do fd.read(loop_, None, len, 0) |req, uverr| {
294+
assert!(uverr.is_none());
295+
let loop_ = req.get_loop();
296+
// we know nread >=0 because uverr is none..
297+
let nread = req.get_result() as uint;
298+
// nread == 0 would be EOF
299+
if nread > 0 {
300+
let buf = vec_from_uv_buf(
301+
req.get_req_data().buf.take_unwrap())
302+
.take_unwrap();
303+
let read_str = str::from_bytes(
304+
buf.slice(0,
305+
nread));
306+
assert!(read_str == ~"hello");
307+
do FileDescriptor(raw_fd).close(loop_) |_,uverr| {
308+
assert!(uverr.is_none());
309+
do FileDescriptor::unlink(loop_, Path(path_str))
310+
|_,uverr| {
311+
assert!(uverr.is_none());
312+
};
313+
};
314+
}
315+
};
316+
};
266317
};
267318
};
268319
};
269320
loop_.run();
321+
loop_.close();
270322
}
271323
}
272324
273325
#[test]
274-
fn file_test_tee() {
275-
file_test_tee_impl();
326+
fn file_test_full_simple() {
327+
file_test_full_simple_impl();
276328
}
277329
278-
fn naive_print(input: ~str) {
279-
do run_in_bare_thread {
280-
let mut loop_ = Loop::new();
281-
let stdout = FileDescriptor(1);
282-
let msg = input.as_bytes().to_owned();
283-
do stdout.write(loop_, msg, -1) |_, uverr| {
284-
assert!(uverr.is_none());
285-
};
286-
loop_.run();
287-
}
330+
fn naive_print(loop_: Loop, input: ~str) {
331+
let stdout = FileDescriptor(STDOUT_FILENO);
332+
let msg = input.as_bytes().to_owned();
333+
do stdout.write(loop_, msg, -1) |_, uverr| {
334+
assert!(uverr.is_none());
335+
};
288336
}
289337
290338
#[test]
291-
fn file_test_println() {
292-
naive_print(~"oh yeah.\n");
339+
fn file_test_write_to_stdout() {
340+
do run_in_bare_thread {
341+
let mut loop_ = Loop::new();
342+
naive_print(loop_, ~"zanzibar!\n");
343+
loop_.run();
344+
loop_.close();
345+
};
293346
}
294347
}

src/libstd/rt/uv/uvll.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,10 +621,19 @@ pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags:
621621
cb: *u8) -> c_int {
622622
rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb)
623623
}
624+
625+
pub unsafe fn fs_unlink(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
626+
cb: *u8) -> c_int {
627+
rust_uv_fs_unlink(loop_ptr, req, path, cb)
628+
}
624629
pub unsafe fn fs_write(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void,
625630
len: uint, offset: i64, cb: *u8) -> c_int {
626631
rust_uv_fs_write(loop_ptr, req, fd, buf, len as c_uint, offset, cb)
627632
}
633+
pub unsafe fn fs_read(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void,
634+
len: uint, offset: i64, cb: *u8) -> c_int {
635+
rust_uv_fs_read(loop_ptr, req, fd, buf, len as c_uint, offset, cb)
636+
}
628637
pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int,
629638
cb: *u8) -> c_int {
630639
rust_uv_fs_close(loop_ptr, req, fd, cb)
@@ -817,8 +826,12 @@ extern {
817826
fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int;
818827
fn rust_uv_fs_open(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
819828
flags: c_int, mode: c_int, cb: *u8) -> c_int;
829+
fn rust_uv_fs_unlink(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
830+
cb: *u8) -> c_int;
820831
fn rust_uv_fs_write(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
821832
buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int;
833+
fn rust_uv_fs_read(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
834+
buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int;
822835
fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
823836
cb: *u8) -> c_int;
824837
fn rust_uv_fs_req_cleanup(req: *uv_fs_t);

src/rt/rust_uv.cpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@
1313
#include <malloc.h>
1414
#endif
1515

16-
#ifndef __WIN32__
17-
// for signal
18-
#include <signal.h>
19-
#endif
20-
2116
#include <fcntl.h>
2217
#include "uv.h"
2318

@@ -521,6 +516,20 @@ rust_uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
521516
return uv_fs_open(loop, req, path, flags, mode, cb);
522517
}
523518
extern "C" int
519+
rust_uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
520+
return uv_fs_unlink(loop, req, path, cb);
521+
}
522+
extern "C" int
523+
rust_uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
524+
size_t len, int64_t offset, uv_fs_cb cb) {
525+
return uv_fs_write(loop, req, fd, buf, len, offset, cb);
526+
}
527+
extern "C" int
528+
rust_uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
529+
size_t len, int64_t offset, uv_fs_cb cb) {
530+
return uv_fs_read(loop, req, fd, buf, len, offset, cb);
531+
}
532+
extern "C" int
524533
rust_uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
525534
return uv_fs_close(loop, req, fd, cb);
526535
}
@@ -549,6 +558,22 @@ rust_uv_get_O_TRUNC() {
549558
return O_TRUNC;
550559
}
551560
extern "C" int
561+
rust_uv_get_S_IWUSR() {
562+
return S_IWUSR;
563+
}
564+
extern "C" int
565+
rust_uv_get_S_IRUSR() {
566+
return S_IRUSR;
567+
}
568+
extern "C" int
569+
rust_uv_get_S_IRGRP() {
570+
return S_IRGRP;
571+
}
572+
extern "C" int
573+
rust_uv_get_S_IROTH() {
574+
return S_IROTH;
575+
}
576+
extern "C" int
552577
rust_uv_get_result_from_fs_req(uv_fs_t* req) {
553578
return req->result;
554579
}

src/rt/rustrt.def.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ rust_uv_idle_init
109109
rust_uv_idle_start
110110
rust_uv_idle_stop
111111
rust_uv_fs_open
112+
rust_uv_fs_unlink
112113
rust_uv_fs_write
114+
rust_uv_fs_read
113115
rust_uv_fs_close
114116
rust_uv_get_O_RDONLY
115117
rust_uv_get_O_WRONLY

0 commit comments

Comments
 (0)