std: bind uv_fs_readdir(), flesh out DirectoryInfo and docs/cleanup
This commit is contained in:
parent
25b4d8c1d7
commit
bf399d558e
@ -108,6 +108,22 @@ pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readdir<P: PathLike>(path: &P) -> Option<~[Path]> {
|
||||
let readdir_result = unsafe {
|
||||
let io: *mut IoFactoryObject = Local::unsafe_borrow();
|
||||
(*io).fs_readdir(path, 0)
|
||||
};
|
||||
match readdir_result {
|
||||
Ok(p) => {
|
||||
Some(p)
|
||||
},
|
||||
Err(ioerr) => {
|
||||
io_error::cond.raise(ioerr);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read-only view of file
|
||||
pub struct FileReader { priv stream: FileStream }
|
||||
|
||||
@ -272,6 +288,18 @@ pub trait FileSystemInfo {
|
||||
/// Represents passive information about a file (primarily exposed
|
||||
/// via the `stat()` method. Also provides methods for opening
|
||||
/// a file in various modes/permissions.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// * Check if a file exists, reading from it if so
|
||||
///
|
||||
/// let f = &Path("/some/file/path.txt");
|
||||
/// if f.exists() {
|
||||
/// let reader = f.open_reader(Open);
|
||||
/// let mut mem = [0u8, 8*64000];
|
||||
/// reader.read(mem);
|
||||
/// // ...
|
||||
/// }
|
||||
pub trait FileInfo : FileSystemInfo {
|
||||
/// Whether the underlying implemention (be it a file path,
|
||||
/// or something else) points at a "regular file" on the FS. Will return
|
||||
@ -290,7 +318,7 @@ pub trait FileInfo : FileSystemInfo {
|
||||
match suppressed_stat(|| self.stat()) {
|
||||
Some(s) => match s.is_file {
|
||||
true => open(self.get_path(), mode, access),
|
||||
false => None // FIXME: raise condition, not a regular file..
|
||||
false => None
|
||||
},
|
||||
None => open(self.get_path(), mode, access)
|
||||
}
|
||||
@ -320,13 +348,16 @@ pub trait FileInfo : FileSystemInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/// `FileSystemInfo` implementation for `Path`s
|
||||
/// `FileSystemInfo` implementation for `Path`s
|
||||
impl FileSystemInfo for Path {
|
||||
fn get_path<'a>(&'a self) -> &'a Path { self }
|
||||
}
|
||||
/// `FileInfo` implementation for `Path`s
|
||||
/// `FileInfo` implementation for `Path`s
|
||||
impl FileInfo for Path { }
|
||||
|
||||
/// Passive information about a directory on the filesystem. Includes
|
||||
/// Convenience methods to iterate over a directory's contents (via `readdir`, as
|
||||
/// as `mkdir` and `rmdir` operations.
|
||||
trait DirectoryInfo : FileSystemInfo {
|
||||
/// Whether the underlying implemention (be it a file path,
|
||||
/// or something else) points at a directory file" on the FS. Will return
|
||||
@ -368,8 +399,9 @@ trait DirectoryInfo : FileSystemInfo {
|
||||
let ioerr = IoError {
|
||||
kind: MismatchedFileTypeForOperation,
|
||||
desc: "Cannot do rmdir() on a non-directory",
|
||||
detail:
|
||||
Some(fmt!("%s is a non-directory; can't rmdir it", self.get_path().to_str()))
|
||||
detail: Some(fmt!(
|
||||
"%s is a non-directory; can't rmdir it",
|
||||
self.get_path().to_str()))
|
||||
};
|
||||
io_error::cond.raise(ioerr);
|
||||
}
|
||||
@ -383,14 +415,13 @@ trait DirectoryInfo : FileSystemInfo {
|
||||
})
|
||||
}
|
||||
}
|
||||
fn readdir(&self) -> ~[~str] {
|
||||
~[]
|
||||
fn readdir(&self) -> Option<~[Path]> {
|
||||
readdir(self.get_path())
|
||||
}
|
||||
//fn get_subdirs(&self, filter: &str) -> ~[Path];
|
||||
//fn get_files(&self, filter: &str) -> ~[Path];
|
||||
}
|
||||
|
||||
/// FIXME: DOCS
|
||||
impl DirectoryInfo for Path { }
|
||||
|
||||
fn file_test_smoke_test_impl() {
|
||||
@ -663,3 +694,41 @@ fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
|
||||
assert!(!dir.exists());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_test_directoryinfo_readdir() {
|
||||
use str;
|
||||
do run_in_mt_newsched_task {
|
||||
let dir = &Path("./tmp/di_readdir");
|
||||
dir.mkdir();
|
||||
let prefix = "foo";
|
||||
for n in range(0,3) {
|
||||
let f = dir.push(fmt!("%d.txt", n));
|
||||
let mut w = f.open_writer(Create);
|
||||
let msg_str = (prefix + n.to_str().to_owned()).to_owned();
|
||||
let msg = msg_str.as_bytes();
|
||||
w.write(msg);
|
||||
}
|
||||
match dir.readdir() {
|
||||
Some(files) => {
|
||||
let mut mem = [0u8, .. 4];
|
||||
for f in files.iter() {
|
||||
{
|
||||
let n = f.filestem();
|
||||
let mut r = f.open_reader(Open);
|
||||
r.read(mem);
|
||||
let read_str = str::from_utf8(mem);
|
||||
let expected = match n {
|
||||
Some(n) => prefix+n,
|
||||
None => fail!("really shouldn't happen..")
|
||||
};
|
||||
assert!(expected == read_str);
|
||||
}
|
||||
f.unlink();
|
||||
}
|
||||
},
|
||||
None => fail!("shouldn't happen")
|
||||
}
|
||||
dir.rmdir();
|
||||
}
|
||||
}
|
@ -78,6 +78,8 @@ pub trait IoFactory {
|
||||
//fn fs_fstat(&mut self, fd: c_int) -> Result<FileStat, IoError>;
|
||||
fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
|
||||
fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
|
||||
fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
|
||||
Result<~[Path], IoError>;
|
||||
}
|
||||
|
||||
pub trait RtioStream {
|
||||
|
@ -17,6 +17,7 @@ use rt::uv::uvll;
|
||||
use rt::uv::uvll::*;
|
||||
use super::super::io::support::PathLike;
|
||||
use cast::transmute;
|
||||
use libc;
|
||||
use libc::{c_int};
|
||||
use option::{None, Some, Option};
|
||||
|
||||
@ -28,14 +29,6 @@ pub struct RequestData {
|
||||
}
|
||||
|
||||
impl FsRequest {
|
||||
pub fn new_REFACTOR_ME(cb: Option<FsCallback>) -> 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.install_req_data(cb);
|
||||
fs_req
|
||||
}
|
||||
|
||||
pub fn new() -> FsRequest {
|
||||
let fs_req = unsafe { malloc_req(UV_FS) };
|
||||
assert!(fs_req.is_not_null());
|
||||
@ -180,6 +173,17 @@ impl FsRequest {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn readdir<P: PathLike>(self, loop_: &Loop, path: &P,
|
||||
flags: c_int, cb: FsCallback) {
|
||||
let complete_cb_ptr = self.req_boilerplate(Some(cb));
|
||||
path.path_as_str(|p| {
|
||||
p.to_c_str().with_ref(|p| unsafe {
|
||||
uvll::fs_readdir(loop_.native_handle(),
|
||||
self.native_handle(), p, flags, complete_cb_ptr)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// accessors/utility funcs
|
||||
fn sync_cleanup(self, result: c_int)
|
||||
-> Result<c_int, UvError> {
|
||||
@ -235,6 +239,36 @@ impl FsRequest {
|
||||
stat
|
||||
}
|
||||
|
||||
pub fn get_ptr(&self) -> *libc::c_void {
|
||||
unsafe {
|
||||
uvll::get_ptr_from_fs_req(self.native_handle())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_paths(&mut self) -> ~[~str] {
|
||||
use str;
|
||||
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
|
||||
let raw_path_strs = unsafe {
|
||||
str::raw::from_c_multistring(ptr as *libc::c_char, Some(n_len)) };
|
||||
let raw_len = raw_path_strs.len();
|
||||
assert_eq!(raw_len, n_len);
|
||||
raw_path_strs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cleanup_and_delete(self) {
|
||||
unsafe {
|
||||
let data = uvll::get_data_for_req(self.native_handle());
|
||||
|
@ -704,6 +704,44 @@ impl IoFactory for UvIoFactory {
|
||||
};
|
||||
}
|
||||
}
|
||||
fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
|
||||
Result<~[Path], IoError> {
|
||||
use str::StrSlice;
|
||||
let result_cell = Cell::new_empty();
|
||||
let result_cell_ptr: *Cell<Result<~[Path],
|
||||
IoError>> = &result_cell;
|
||||
let path_cell = Cell::new(path);
|
||||
do task::unkillable { // FIXME(#8674)
|
||||
let scheduler: ~Scheduler = Local::take();
|
||||
let stat_req = file::FsRequest::new();
|
||||
do scheduler.deschedule_running_task_and_then |_, task| {
|
||||
let task_cell = Cell::new(task);
|
||||
let path = path_cell.take();
|
||||
let path_str = path.path_as_str(|p| p.to_owned());
|
||||
do stat_req.readdir(self.uv_loop(), path, flags)
|
||||
|req,err| {
|
||||
let res = match err {
|
||||
None => {
|
||||
let rel_paths = req.get_paths();
|
||||
let mut paths = ~[];
|
||||
for r in rel_paths.iter() {
|
||||
paths.push(Path(path_str+"/"+*r));
|
||||
}
|
||||
Ok(paths)
|
||||
},
|
||||
Some(e) => {
|
||||
Err(uv_error_to_io_error(e))
|
||||
}
|
||||
};
|
||||
unsafe { (*result_cell_ptr).put_back(res); }
|
||||
let scheduler: ~Scheduler = Local::take();
|
||||
scheduler.resume_blocked_task_immediately(task_cell.take());
|
||||
};
|
||||
};
|
||||
};
|
||||
assert!(!result_cell.is_empty());
|
||||
return result_cell.take();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UvTcpListener {
|
||||
|
@ -811,6 +811,12 @@ pub unsafe fn fs_rmdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
|
||||
|
||||
rust_uv_fs_rmdir(loop_ptr, req, path, cb)
|
||||
}
|
||||
pub unsafe fn fs_readdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
|
||||
flags: c_int, cb: *u8) -> c_int {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
|
||||
rust_uv_fs_readdir(loop_ptr, req, path, flags, cb)
|
||||
}
|
||||
pub unsafe fn populate_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t) {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
|
||||
@ -828,6 +834,11 @@ pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
|
||||
|
||||
rust_uv_get_result_from_fs_req(req)
|
||||
}
|
||||
pub unsafe fn get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
|
||||
rust_uv_get_ptr_from_fs_req(req)
|
||||
}
|
||||
pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
|
||||
@ -1014,9 +1025,12 @@ extern {
|
||||
mode: c_int, cb: *u8) -> c_int;
|
||||
fn rust_uv_fs_rmdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
|
||||
cb: *u8) -> c_int;
|
||||
fn rust_uv_fs_readdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
|
||||
flags: c_int, cb: *u8) -> c_int;
|
||||
fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
|
||||
fn rust_uv_populate_uv_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t);
|
||||
fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
|
||||
fn rust_uv_get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void;
|
||||
fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
|
||||
fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t;
|
||||
|
||||
|
@ -542,6 +542,10 @@ extern "C" int
|
||||
rust_uv_get_result_from_fs_req(uv_fs_t* req) {
|
||||
return req->result;
|
||||
}
|
||||
extern "C" void*
|
||||
rust_uv_get_ptr_from_fs_req(uv_fs_t* req) {
|
||||
return req->ptr;
|
||||
}
|
||||
extern "C" uv_loop_t*
|
||||
rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
|
||||
return req->loop;
|
||||
@ -593,3 +597,8 @@ extern "C" int
|
||||
rust_uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
return uv_fs_rmdir(loop, req, path, cb);
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
rust_uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) {
|
||||
return uv_fs_readdir(loop, req, path, flags, cb);
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ rust_uv_fs_write
|
||||
rust_uv_fs_read
|
||||
rust_uv_fs_close
|
||||
rust_uv_get_result_from_fs_req
|
||||
rust_uv_get_ptr_from_fs_req
|
||||
rust_uv_get_loop_from_fs_req
|
||||
rust_uv_fs_stat
|
||||
rust_uv_fs_fstat
|
||||
@ -120,6 +121,7 @@ rust_uv_fs_req_cleanup
|
||||
rust_uv_populate_uv_stat
|
||||
rust_uv_fs_mkdir
|
||||
rust_uv_fs_rmdir
|
||||
rust_uv_fs_readdir
|
||||
rust_dbg_lock_create
|
||||
rust_dbg_lock_destroy
|
||||
rust_dbg_lock_lock
|
||||
|
Loading…
x
Reference in New Issue
Block a user