Skip to content

Commit

Permalink
std: bind uv_fs_readdir(), flesh out DirectoryInfo and docs/cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
olsonjeffery committed Sep 17, 2013
1 parent 25b4d8c commit bf399d5
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 16 deletions.
85 changes: 77 additions & 8 deletions src/libstd/rt/io/file.rs
Expand Up @@ -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 }

Expand Down Expand Up @@ -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
Expand All @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand All @@ -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() {
Expand Down Expand Up @@ -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();
}
}
2 changes: 2 additions & 0 deletions src/libstd/rt/rtio.rs
Expand Up @@ -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 {
Expand Down
50 changes: 42 additions & 8 deletions src/libstd/rt/uv/file.rs
Expand Up @@ -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};

Expand All @@ -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());
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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());
Expand Down
38 changes: 38 additions & 0 deletions src/libstd/rt/uv/uvio.rs
Expand Up @@ -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 {
Expand Down
14 changes: 14 additions & 0 deletions src/libstd/rt/uv/uvll.rs
Expand Up @@ -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)];

Expand All @@ -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)];

Expand Down Expand Up @@ -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;

Expand Down
9 changes: 9 additions & 0 deletions src/rt/rust_uv.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
2 changes: 2 additions & 0 deletions src/rt/rustrt.def.in
Expand Up @@ -113,13 +113,15 @@ 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
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
Expand Down

0 comments on commit bf399d5

Please sign in to comment.