2013-10-22 15:13:18 -07:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
use std::ptr::null;
|
|
|
|
use std::c_str;
|
|
|
|
use std::c_str::CString;
|
|
|
|
use std::cast::transmute;
|
|
|
|
use std::libc;
|
2013-10-29 23:31:07 -07:00
|
|
|
use std::libc::{c_int, c_char, c_void};
|
2013-10-22 15:13:18 -07:00
|
|
|
|
|
|
|
use super::{Request, NativeHandle, Loop, FsCallback, Buf,
|
|
|
|
status_to_maybe_uv_error, UvError};
|
|
|
|
use uvll;
|
|
|
|
use uvll::*;
|
|
|
|
|
|
|
|
pub struct FsRequest(*uvll::uv_fs_t);
|
|
|
|
impl Request for FsRequest {}
|
|
|
|
|
|
|
|
pub struct RequestData {
|
|
|
|
priv complete_cb: Option<FsCallback>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FsRequest {
|
|
|
|
pub fn new() -> FsRequest {
|
|
|
|
let fs_req = unsafe { malloc_req(UV_FS) };
|
|
|
|
assert!(fs_req.is_not_null());
|
|
|
|
let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
|
|
|
|
fs_req
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn open(self, loop_: &Loop, path: &CString, flags: int, mode: int,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = {
|
|
|
|
let mut me = self;
|
|
|
|
me.req_boilerplate(Some(cb))
|
|
|
|
};
|
|
|
|
let ret = path.with_ref(|p| unsafe {
|
|
|
|
uvll::fs_open(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, flags, mode, complete_cb_ptr)
|
|
|
|
});
|
|
|
|
assert_eq!(ret, 0);
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn open_sync(mut self, loop_: &Loop, path: &CString,
|
2013-10-22 15:13:18 -07:00
|
|
|
flags: int, mode: int) -> Result<c_int, UvError> {
|
2013-10-29 23:31:07 -07:00
|
|
|
let complete_cb_ptr = self.req_boilerplate(None);
|
2013-10-22 15:13:18 -07:00
|
|
|
let result = path.with_ref(|p| unsafe {
|
|
|
|
uvll::fs_open(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, flags, mode, complete_cb_ptr)
|
|
|
|
});
|
|
|
|
self.sync_cleanup(result)
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn unlink(mut self, loop_: &Loop, path: &CString, cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
2013-10-22 15:13:18 -07:00
|
|
|
let ret = path.with_ref(|p| unsafe {
|
|
|
|
uvll::fs_unlink(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, complete_cb_ptr)
|
|
|
|
});
|
|
|
|
assert_eq!(ret, 0);
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn unlink_sync(mut self, loop_: &Loop, path: &CString)
|
2013-10-22 15:13:18 -07:00
|
|
|
-> Result<c_int, UvError> {
|
2013-10-29 23:31:07 -07:00
|
|
|
let complete_cb_ptr = self.req_boilerplate(None);
|
2013-10-22 15:13:18 -07:00
|
|
|
let result = path.with_ref(|p| unsafe {
|
|
|
|
uvll::fs_unlink(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, complete_cb_ptr)
|
|
|
|
});
|
|
|
|
self.sync_cleanup(result)
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn lstat(mut self, loop_: &Loop, path: &CString, cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
let ret = path.with_ref(|p| unsafe {
|
|
|
|
uvll::uv_fs_lstat(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, complete_cb_ptr)
|
|
|
|
});
|
|
|
|
assert_eq!(ret, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn stat(mut self, loop_: &Loop, path: &CString, cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
2013-10-22 15:13:18 -07:00
|
|
|
let ret = path.with_ref(|p| unsafe {
|
|
|
|
uvll::fs_stat(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, complete_cb_ptr)
|
|
|
|
});
|
|
|
|
assert_eq!(ret, 0);
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn write(mut self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
2013-10-22 15:13:18 -07:00
|
|
|
let base_ptr = buf.base as *c_void;
|
|
|
|
let len = buf.len as uint;
|
|
|
|
let ret = unsafe {
|
|
|
|
uvll::fs_write(loop_.native_handle(), self.native_handle(),
|
|
|
|
fd, base_ptr,
|
|
|
|
len, offset, complete_cb_ptr)
|
|
|
|
};
|
|
|
|
assert_eq!(ret, 0);
|
|
|
|
}
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn write_sync(mut self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
|
2013-10-22 15:13:18 -07:00
|
|
|
-> Result<c_int, UvError> {
|
2013-10-29 23:31:07 -07:00
|
|
|
let complete_cb_ptr = self.req_boilerplate(None);
|
2013-10-22 15:13:18 -07:00
|
|
|
let base_ptr = buf.base as *c_void;
|
|
|
|
let len = buf.len as uint;
|
|
|
|
let result = unsafe {
|
|
|
|
uvll::fs_write(loop_.native_handle(), self.native_handle(),
|
|
|
|
fd, base_ptr,
|
|
|
|
len, offset, complete_cb_ptr)
|
|
|
|
};
|
|
|
|
self.sync_cleanup(result)
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn read(mut self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
2013-10-22 15:13:18 -07:00
|
|
|
let buf_ptr = buf.base as *c_void;
|
|
|
|
let len = buf.len as uint;
|
|
|
|
let ret = unsafe {
|
|
|
|
uvll::fs_read(loop_.native_handle(), self.native_handle(),
|
|
|
|
fd, buf_ptr,
|
|
|
|
len, offset, complete_cb_ptr)
|
|
|
|
};
|
|
|
|
assert_eq!(ret, 0);
|
|
|
|
}
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn read_sync(mut self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
|
2013-10-22 15:13:18 -07:00
|
|
|
-> Result<c_int, UvError> {
|
2013-10-29 23:31:07 -07:00
|
|
|
let complete_cb_ptr = self.req_boilerplate(None);
|
2013-10-22 15:13:18 -07:00
|
|
|
let buf_ptr = buf.base as *c_void;
|
|
|
|
let len = buf.len as uint;
|
|
|
|
let result = unsafe {
|
|
|
|
uvll::fs_read(loop_.native_handle(), self.native_handle(),
|
|
|
|
fd, buf_ptr,
|
|
|
|
len, offset, complete_cb_ptr)
|
|
|
|
};
|
|
|
|
self.sync_cleanup(result)
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn close(mut self, loop_: &Loop, fd: c_int, cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(unsafe {
|
2013-10-22 15:13:18 -07:00
|
|
|
uvll::fs_close(loop_.native_handle(), self.native_handle(),
|
|
|
|
fd, complete_cb_ptr)
|
2013-10-29 23:31:07 -07:00
|
|
|
}, 0);
|
2013-10-22 15:13:18 -07:00
|
|
|
}
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn close_sync(mut self, loop_: &Loop,
|
|
|
|
fd: c_int) -> Result<c_int, UvError> {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(None);
|
2013-10-22 15:13:18 -07:00
|
|
|
let result = unsafe {
|
|
|
|
uvll::fs_close(loop_.native_handle(), self.native_handle(),
|
|
|
|
fd, complete_cb_ptr)
|
|
|
|
};
|
|
|
|
self.sync_cleanup(result)
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn mkdir(mut self, loop_: &Loop, path: &CString, mode: c_int,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(path.with_ref(|p| unsafe {
|
2013-10-22 15:13:18 -07:00
|
|
|
uvll::fs_mkdir(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, mode, complete_cb_ptr)
|
2013-10-29 23:31:07 -07:00
|
|
|
}), 0);
|
2013-10-22 15:13:18 -07:00
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn rmdir(mut self, loop_: &Loop, path: &CString, cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(path.with_ref(|p| unsafe {
|
2013-10-22 15:13:18 -07:00
|
|
|
uvll::fs_rmdir(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, complete_cb_ptr)
|
2013-10-29 23:31:07 -07:00
|
|
|
}), 0);
|
2013-10-22 15:13:18 -07:00
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn rename(mut self, loop_: &Loop, path: &CString, to: &CString,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(unsafe {
|
2013-10-25 16:50:08 -07:00
|
|
|
uvll::fs_rename(loop_.native_handle(),
|
|
|
|
self.native_handle(),
|
|
|
|
path.with_ref(|p| p),
|
|
|
|
to.with_ref(|p| p),
|
|
|
|
complete_cb_ptr)
|
2013-10-29 23:31:07 -07:00
|
|
|
}, 0);
|
2013-10-25 16:50:08 -07:00
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn chmod(mut self, loop_: &Loop, path: &CString, mode: c_int,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(path.with_ref(|p| unsafe {
|
2013-10-25 17:04:37 -07:00
|
|
|
uvll::fs_chmod(loop_.native_handle(), self.native_handle(), p, mode,
|
|
|
|
complete_cb_ptr)
|
2013-10-29 23:31:07 -07:00
|
|
|
}), 0);
|
2013-10-25 17:04:37 -07:00
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn readdir(mut self, loop_: &Loop, path: &CString,
|
2013-10-22 15:13:18 -07:00
|
|
|
flags: c_int, cb: FsCallback) {
|
2013-10-29 23:31:07 -07:00
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(path.with_ref(|p| unsafe {
|
2013-10-22 15:13:18 -07:00
|
|
|
uvll::fs_readdir(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, flags, complete_cb_ptr)
|
2013-10-29 23:31:07 -07:00
|
|
|
}), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn readlink(mut self, loop_: &Loop, path: &CString, cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(path.with_ref(|p| unsafe {
|
|
|
|
uvll::uv_fs_readlink(loop_.native_handle(),
|
|
|
|
self.native_handle(), p, complete_cb_ptr)
|
|
|
|
}), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn chown(mut self, loop_: &Loop, path: &CString, uid: int, gid: int,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(path.with_ref(|p| unsafe {
|
|
|
|
uvll::uv_fs_chown(loop_.native_handle(),
|
|
|
|
self.native_handle(), p,
|
|
|
|
uid as uvll::uv_uid_t,
|
|
|
|
gid as uvll::uv_gid_t,
|
|
|
|
complete_cb_ptr)
|
|
|
|
}), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn truncate(mut self, loop_: &Loop, file: c_int, offset: i64,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(unsafe {
|
|
|
|
uvll::uv_fs_ftruncate(loop_.native_handle(),
|
|
|
|
self.native_handle(), file, offset,
|
|
|
|
complete_cb_ptr)
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn link(mut self, loop_: &Loop, src: &CString, dst: &CString,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(unsafe {
|
|
|
|
uvll::uv_fs_link(loop_.native_handle(), self.native_handle(),
|
|
|
|
src.with_ref(|p| p),
|
|
|
|
dst.with_ref(|p| p),
|
|
|
|
complete_cb_ptr)
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn symlink(mut self, loop_: &Loop, src: &CString, dst: &CString,
|
|
|
|
cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(unsafe {
|
|
|
|
uvll::uv_fs_symlink(loop_.native_handle(), self.native_handle(),
|
|
|
|
src.with_ref(|p| p),
|
|
|
|
dst.with_ref(|p| p),
|
2013-10-31 15:15:30 -07:00
|
|
|
0,
|
2013-10-29 23:31:07 -07:00
|
|
|
complete_cb_ptr)
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fsync(mut self, loop_: &Loop, fd: c_int, cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(unsafe {
|
|
|
|
uvll::uv_fs_fsync(loop_.native_handle(), self.native_handle(), fd,
|
|
|
|
complete_cb_ptr)
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn datasync(mut self, loop_: &Loop, fd: c_int, cb: FsCallback) {
|
|
|
|
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
|
|
|
assert_eq!(unsafe {
|
|
|
|
uvll::uv_fs_fdatasync(loop_.native_handle(), self.native_handle(), fd,
|
|
|
|
complete_cb_ptr)
|
|
|
|
}, 0);
|
2013-10-22 15:13:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// accessors/utility funcs
|
|
|
|
fn sync_cleanup(self, result: c_int)
|
|
|
|
-> Result<c_int, UvError> {
|
|
|
|
self.cleanup_and_delete();
|
|
|
|
match status_to_maybe_uv_error(result as i32) {
|
|
|
|
Some(err) => Err(err),
|
|
|
|
None => Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn req_boilerplate(&mut self, cb: Option<FsCallback>) -> *u8 {
|
|
|
|
let result = match cb {
|
|
|
|
Some(_) => {
|
|
|
|
compl_cb as *u8
|
|
|
|
},
|
|
|
|
None => 0 as *u8
|
|
|
|
};
|
|
|
|
self.install_req_data(cb);
|
|
|
|
result
|
|
|
|
}
|
|
|
|
pub fn install_req_data(&mut self, cb: Option<FsCallback>) {
|
|
|
|
let fs_req = (self.native_handle()) as *uvll::uv_write_t;
|
|
|
|
let data = ~RequestData {
|
|
|
|
complete_cb: cb
|
|
|
|
};
|
|
|
|
unsafe {
|
|
|
|
let data = transmute::<~RequestData, *c_void>(data);
|
|
|
|
uvll::set_data_for_req(fs_req, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
|
|
|
|
unsafe {
|
|
|
|
let data = uvll::get_data_for_req((self.native_handle()));
|
|
|
|
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
|
|
|
|
&mut **data
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 23:31:07 -07:00
|
|
|
pub fn get_path(&self) -> *c_char {
|
|
|
|
unsafe { uvll::get_path_from_fs_req(self.native_handle()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_result(&self) -> c_int {
|
|
|
|
unsafe { uvll::get_result_from_fs_req(self.native_handle()) }
|
2013-10-22 15:13:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_loop(&self) -> Loop {
|
|
|
|
unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_stat(&self) -> uv_stat_t {
|
|
|
|
let stat = uv_stat_t::new();
|
|
|
|
unsafe { uvll::populate_stat(self.native_handle(), &stat); }
|
|
|
|
stat
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_ptr(&self) -> *libc::c_void {
|
|
|
|
unsafe {
|
|
|
|
uvll::get_ptr_from_fs_req(self.native_handle())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn each_path(&mut self, f: &fn(&CString)) {
|
|
|
|
let ptr = self.get_ptr();
|
|
|
|
match self.get_result() {
|
|
|
|
n if (n <= 0) => {}
|
|
|
|
n => {
|
|
|
|
let n_len = n as uint;
|
|
|
|
// we pass in the len that uv tells us is there
|
|
|
|
// for the entries and we don't continue past that..
|
|
|
|
// it appears that sometimes the multistring isn't
|
|
|
|
// correctly delimited and we stray into garbage memory?
|
|
|
|
// in any case, passing Some(n_len) fixes it and ensures
|
|
|
|
// good results
|
|
|
|
unsafe {
|
|
|
|
c_str::from_c_multistring(ptr as *libc::c_char,
|
|
|
|
Some(n_len), f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cleanup_and_delete(self) {
|
|
|
|
unsafe {
|
|
|
|
let data = uvll::get_data_for_req(self.native_handle());
|
|
|
|
let _data = transmute::<*c_void, ~RequestData>(data);
|
|
|
|
uvll::set_data_for_req(self.native_handle(), null::<()>());
|
|
|
|
uvll::fs_req_cleanup(self.native_handle());
|
|
|
|
free_req(self.native_handle() as *c_void)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
|
|
|
|
fn from_native_handle(handle: *uvll:: uv_fs_t) -> FsRequest {
|
|
|
|
FsRequest(handle)
|
|
|
|
}
|
|
|
|
fn native_handle(&self) -> *uvll::uv_fs_t {
|
|
|
|
match self { &FsRequest(ptr) => ptr }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sync_cleanup(result: int)
|
|
|
|
-> Result<int, UvError> {
|
|
|
|
match status_to_maybe_uv_error(result as i32) {
|
|
|
|
Some(err) => Err(err),
|
|
|
|
None => Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn compl_cb(req: *uv_fs_t) {
|
|
|
|
let mut req: FsRequest = NativeHandle::from_native_handle(req);
|
|
|
|
// pull the user cb out of the req data
|
|
|
|
let cb = {
|
|
|
|
let data = req.get_req_data();
|
|
|
|
assert!(data.complete_cb.is_some());
|
|
|
|
// option dance, option dance. oooooh yeah.
|
|
|
|
data.complete_cb.take_unwrap()
|
|
|
|
};
|
|
|
|
// in uv_fs_open calls, the result will be the fd in the
|
|
|
|
// case of success, otherwise it's -1 indicating an error
|
|
|
|
let result = req.get_result();
|
|
|
|
let status = status_to_maybe_uv_error(result);
|
|
|
|
// we have a req and status, call the user cb..
|
|
|
|
// only giving the user a ref to the FsRequest, as we
|
|
|
|
// have to clean it up, afterwards (and they aren't really
|
|
|
|
// reusable, anyways
|
|
|
|
cb(&mut req, status);
|
|
|
|
// clean up the req (and its data!) after calling the user cb
|
|
|
|
req.cleanup_and_delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
//use std::rt::test::*;
|
2013-10-29 23:31:07 -07:00
|
|
|
use std::libc::{STDOUT_FILENO, c_int};
|
2013-10-22 15:13:18 -07:00
|
|
|
use std::vec;
|
|
|
|
use std::str;
|
|
|
|
use std::unstable::run_in_bare_thread;
|
|
|
|
use super::super::{Loop, Buf, slice_to_uv_buf};
|
|
|
|
use std::libc::{O_CREAT, O_RDWR, O_RDONLY, S_IWUSR, S_IRUSR};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn file_test_full_simple() {
|
|
|
|
do run_in_bare_thread {
|
|
|
|
let mut loop_ = Loop::new();
|
|
|
|
let create_flags = O_RDWR | O_CREAT;
|
|
|
|
let read_flags = O_RDONLY;
|
|
|
|
// 0644 BZZT! WRONG! 0600! See below.
|
|
|
|
let mode = S_IWUSR |S_IRUSR;
|
|
|
|
// these aren't defined in std::libc :(
|
|
|
|
//map_mode(S_IRGRP) |
|
|
|
|
//map_mode(S_IROTH);
|
|
|
|
let path_str = "./tmp/file_full_simple.txt";
|
|
|
|
let write_val = "hello".as_bytes().to_owned();
|
|
|
|
let write_buf = slice_to_uv_buf(write_val);
|
|
|
|
let write_buf_ptr: *Buf = &write_buf;
|
|
|
|
let read_buf_len = 1028;
|
|
|
|
let read_mem = vec::from_elem(read_buf_len, 0u8);
|
|
|
|
let read_buf = slice_to_uv_buf(read_mem);
|
|
|
|
let read_buf_ptr: *Buf = &read_buf;
|
|
|
|
let open_req = FsRequest::new();
|
|
|
|
do open_req.open(&loop_, &path_str.to_c_str(), create_flags as int,
|
|
|
|
mode as int) |req, uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let fd = req.get_result();
|
|
|
|
let buf = unsafe { *write_buf_ptr };
|
|
|
|
let write_req = FsRequest::new();
|
|
|
|
do write_req.write(&req.get_loop(), fd, buf, -1) |req, uverr| {
|
|
|
|
let close_req = FsRequest::new();
|
|
|
|
do close_req.close(&req.get_loop(), fd) |req, _| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let open_req = FsRequest::new();
|
|
|
|
do open_req.open(&loop_, &path_str.to_c_str(),
|
|
|
|
read_flags as int,0) |req, uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let fd = req.get_result();
|
|
|
|
let read_buf = unsafe { *read_buf_ptr };
|
|
|
|
let read_req = FsRequest::new();
|
|
|
|
do read_req.read(&loop_, fd, read_buf, 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 read_str = unsafe {
|
|
|
|
let read_buf = *read_buf_ptr;
|
|
|
|
str::from_utf8(
|
|
|
|
vec::from_buf(
|
|
|
|
read_buf.base, nread))
|
|
|
|
};
|
|
|
|
assert!(read_str == ~"hello");
|
|
|
|
let close_req = FsRequest::new();
|
|
|
|
do close_req.close(&loop_, fd) |req,uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = &req.get_loop();
|
|
|
|
let unlink_req = FsRequest::new();
|
|
|
|
do unlink_req.unlink(loop_,
|
|
|
|
&path_str.to_c_str())
|
|
|
|
|_,uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
loop_.run();
|
|
|
|
loop_.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn file_test_full_simple_sync() {
|
|
|
|
do run_in_bare_thread {
|
|
|
|
// setup
|
|
|
|
let mut loop_ = Loop::new();
|
|
|
|
let create_flags = O_RDWR |
|
|
|
|
O_CREAT;
|
|
|
|
let read_flags = O_RDONLY;
|
|
|
|
// 0644
|
|
|
|
let mode = S_IWUSR |
|
|
|
|
S_IRUSR;
|
|
|
|
//S_IRGRP |
|
|
|
|
//S_IROTH;
|
|
|
|
let path_str = "./tmp/file_full_simple_sync.txt";
|
|
|
|
let write_val = "hello".as_bytes().to_owned();
|
|
|
|
let write_buf = slice_to_uv_buf(write_val);
|
|
|
|
// open/create
|
|
|
|
let open_req = FsRequest::new();
|
|
|
|
let result = open_req.open_sync(&loop_, &path_str.to_c_str(),
|
|
|
|
create_flags as int, mode as int);
|
|
|
|
assert!(result.is_ok());
|
|
|
|
let fd = result.unwrap();
|
|
|
|
// write
|
|
|
|
let write_req = FsRequest::new();
|
|
|
|
let result = write_req.write_sync(&loop_, fd, write_buf, -1);
|
|
|
|
assert!(result.is_ok());
|
|
|
|
// close
|
|
|
|
let close_req = FsRequest::new();
|
|
|
|
let result = close_req.close_sync(&loop_, fd);
|
|
|
|
assert!(result.is_ok());
|
|
|
|
// re-open
|
|
|
|
let open_req = FsRequest::new();
|
|
|
|
let result = open_req.open_sync(&loop_, &path_str.to_c_str(),
|
|
|
|
read_flags as int,0);
|
|
|
|
assert!(result.is_ok());
|
|
|
|
let len = 1028;
|
|
|
|
let fd = result.unwrap();
|
|
|
|
// read
|
|
|
|
let read_mem: ~[u8] = vec::from_elem(len, 0u8);
|
|
|
|
let buf = slice_to_uv_buf(read_mem);
|
|
|
|
let read_req = FsRequest::new();
|
|
|
|
let result = read_req.read_sync(&loop_, fd, buf, 0);
|
|
|
|
assert!(result.is_ok());
|
|
|
|
let nread = result.unwrap();
|
|
|
|
// nread == 0 would be EOF.. we know it's >= zero because otherwise
|
|
|
|
// the above assert would fail
|
|
|
|
if nread > 0 {
|
|
|
|
let read_str = str::from_utf8(
|
|
|
|
read_mem.slice(0, nread as uint));
|
|
|
|
assert!(read_str == ~"hello");
|
|
|
|
// close
|
|
|
|
let close_req = FsRequest::new();
|
|
|
|
let result = close_req.close_sync(&loop_, fd);
|
|
|
|
assert!(result.is_ok());
|
|
|
|
// unlink
|
|
|
|
let unlink_req = FsRequest::new();
|
|
|
|
let result = unlink_req.unlink_sync(&loop_, &path_str.to_c_str());
|
|
|
|
assert!(result.is_ok());
|
|
|
|
} else { fail!("nread was 0.. wudn't expectin' that."); }
|
|
|
|
loop_.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn naive_print(loop_: &Loop, input: &str) {
|
|
|
|
let write_val = input.as_bytes();
|
|
|
|
let write_buf = slice_to_uv_buf(write_val);
|
|
|
|
let write_req = FsRequest::new();
|
|
|
|
write_req.write_sync(loop_, STDOUT_FILENO, write_buf, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
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();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn file_test_stat_simple() {
|
|
|
|
do run_in_bare_thread {
|
|
|
|
let mut loop_ = Loop::new();
|
|
|
|
let path = "./tmp/file_test_stat_simple.txt";
|
|
|
|
let create_flags = O_RDWR |
|
|
|
|
O_CREAT;
|
|
|
|
let mode = S_IWUSR |
|
|
|
|
S_IRUSR;
|
|
|
|
let write_val = "hello".as_bytes().to_owned();
|
|
|
|
let write_buf = slice_to_uv_buf(write_val);
|
|
|
|
let write_buf_ptr: *Buf = &write_buf;
|
|
|
|
let open_req = FsRequest::new();
|
|
|
|
do open_req.open(&loop_, &path.to_c_str(), create_flags as int,
|
|
|
|
mode as int) |req, uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let fd = req.get_result();
|
|
|
|
let buf = unsafe { *write_buf_ptr };
|
|
|
|
let write_req = FsRequest::new();
|
|
|
|
do write_req.write(&req.get_loop(), fd, buf, 0) |req, uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let stat_req = FsRequest::new();
|
|
|
|
do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let stat = req.get_stat();
|
|
|
|
let sz: uint = stat.st_size as uint;
|
|
|
|
assert!(sz > 0);
|
|
|
|
let close_req = FsRequest::new();
|
|
|
|
do close_req.close(&loop_, fd) |req, uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let unlink_req = FsRequest::new();
|
|
|
|
do unlink_req.unlink(&loop_,
|
|
|
|
&path.to_c_str()) |req,uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let stat_req = FsRequest::new();
|
|
|
|
do stat_req.stat(&loop_,
|
|
|
|
&path.to_c_str()) |_, uverr| {
|
|
|
|
// should cause an error because the
|
|
|
|
// file doesn't exist anymore
|
|
|
|
assert!(uverr.is_some());
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
loop_.run();
|
|
|
|
loop_.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn file_test_mk_rm_dir() {
|
|
|
|
do run_in_bare_thread {
|
|
|
|
let mut loop_ = Loop::new();
|
|
|
|
let path = "./tmp/mk_rm_dir";
|
|
|
|
let mode = S_IWUSR |
|
|
|
|
S_IRUSR;
|
|
|
|
let mkdir_req = FsRequest::new();
|
|
|
|
do mkdir_req.mkdir(&loop_, &path.to_c_str(),
|
2013-10-25 17:04:37 -07:00
|
|
|
mode as c_int) |req,uverr| {
|
2013-10-22 15:13:18 -07:00
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let stat_req = FsRequest::new();
|
|
|
|
do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let stat = req.get_stat();
|
|
|
|
naive_print(&loop_, format!("{:?}", stat));
|
|
|
|
assert!(stat.is_dir());
|
|
|
|
let rmdir_req = FsRequest::new();
|
|
|
|
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let stat_req = FsRequest::new();
|
|
|
|
do stat_req.stat(&loop_, &path.to_c_str()) |_req, uverr| {
|
|
|
|
assert!(uverr.is_some());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
loop_.run();
|
|
|
|
loop_.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn file_test_mkdir_chokes_on_double_create() {
|
|
|
|
do run_in_bare_thread {
|
|
|
|
let mut loop_ = Loop::new();
|
|
|
|
let path = "./tmp/double_create_dir";
|
|
|
|
let mode = S_IWUSR |
|
|
|
|
S_IRUSR;
|
|
|
|
let mkdir_req = FsRequest::new();
|
2013-10-25 17:04:37 -07:00
|
|
|
do mkdir_req.mkdir(&loop_, &path.to_c_str(), mode as c_int) |req,uverr| {
|
2013-10-22 15:13:18 -07:00
|
|
|
assert!(uverr.is_none());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let mkdir_req = FsRequest::new();
|
|
|
|
do mkdir_req.mkdir(&loop_, &path.to_c_str(),
|
2013-10-25 17:04:37 -07:00
|
|
|
mode as c_int) |req,uverr| {
|
2013-10-22 15:13:18 -07:00
|
|
|
assert!(uverr.is_some());
|
|
|
|
let loop_ = req.get_loop();
|
|
|
|
let _stat = req.get_stat();
|
|
|
|
let rmdir_req = FsRequest::new();
|
|
|
|
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| {
|
|
|
|
assert!(uverr.is_none());
|
|
|
|
let _loop = req.get_loop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
loop_.run();
|
|
|
|
loop_.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn file_test_rmdir_chokes_on_nonexistant_path() {
|
|
|
|
do run_in_bare_thread {
|
|
|
|
let mut loop_ = Loop::new();
|
|
|
|
let path = "./tmp/never_existed_dir";
|
|
|
|
let rmdir_req = FsRequest::new();
|
|
|
|
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |_req, uverr| {
|
|
|
|
assert!(uverr.is_some());
|
|
|
|
}
|
|
|
|
loop_.run();
|
|
|
|
loop_.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|