Skip to content

Commit bf399d5

Browse files
committed
std: bind uv_fs_readdir(), flesh out DirectoryInfo and docs/cleanup
1 parent 25b4d8c commit bf399d5

File tree

7 files changed

+184
-16
lines changed

7 files changed

+184
-16
lines changed

src/libstd/rt/io/file.rs

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,22 @@ pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
108108
}
109109
}
110110

111+
pub fn readdir<P: PathLike>(path: &P) -> Option<~[Path]> {
112+
let readdir_result = unsafe {
113+
let io: *mut IoFactoryObject = Local::unsafe_borrow();
114+
(*io).fs_readdir(path, 0)
115+
};
116+
match readdir_result {
117+
Ok(p) => {
118+
Some(p)
119+
},
120+
Err(ioerr) => {
121+
io_error::cond.raise(ioerr);
122+
None
123+
}
124+
}
125+
}
126+
111127
/// Read-only view of file
112128
pub struct FileReader { priv stream: FileStream }
113129

@@ -272,6 +288,18 @@ pub trait FileSystemInfo {
272288
/// Represents passive information about a file (primarily exposed
273289
/// via the `stat()` method. Also provides methods for opening
274290
/// a file in various modes/permissions.
291+
///
292+
/// # Example
293+
///
294+
/// * Check if a file exists, reading from it if so
295+
///
296+
/// let f = &Path("/some/file/path.txt");
297+
/// if f.exists() {
298+
/// let reader = f.open_reader(Open);
299+
/// let mut mem = [0u8, 8*64000];
300+
/// reader.read(mem);
301+
/// // ...
302+
/// }
275303
pub trait FileInfo : FileSystemInfo {
276304
/// Whether the underlying implemention (be it a file path,
277305
/// or something else) points at a "regular file" on the FS. Will return
@@ -290,7 +318,7 @@ pub trait FileInfo : FileSystemInfo {
290318
match suppressed_stat(|| self.stat()) {
291319
Some(s) => match s.is_file {
292320
true => open(self.get_path(), mode, access),
293-
false => None // FIXME: raise condition, not a regular file..
321+
false => None
294322
},
295323
None => open(self.get_path(), mode, access)
296324
}
@@ -320,13 +348,16 @@ pub trait FileInfo : FileSystemInfo {
320348
}
321349
}
322350

323-
/// `FileSystemInfo` implementation for `Path`s
351+
/// `FileSystemInfo` implementation for `Path`s
324352
impl FileSystemInfo for Path {
325353
fn get_path<'a>(&'a self) -> &'a Path { self }
326354
}
327-
/// `FileInfo` implementation for `Path`s
355+
/// `FileInfo` implementation for `Path`s
328356
impl FileInfo for Path { }
329357

358+
/// Passive information about a directory on the filesystem. Includes
359+
/// Convenience methods to iterate over a directory's contents (via `readdir`, as
360+
/// as `mkdir` and `rmdir` operations.
330361
trait DirectoryInfo : FileSystemInfo {
331362
/// Whether the underlying implemention (be it a file path,
332363
/// or something else) points at a directory file" on the FS. Will return
@@ -368,8 +399,9 @@ trait DirectoryInfo : FileSystemInfo {
368399
let ioerr = IoError {
369400
kind: MismatchedFileTypeForOperation,
370401
desc: "Cannot do rmdir() on a non-directory",
371-
detail:
372-
Some(fmt!("%s is a non-directory; can't rmdir it", self.get_path().to_str()))
402+
detail: Some(fmt!(
403+
"%s is a non-directory; can't rmdir it",
404+
self.get_path().to_str()))
373405
};
374406
io_error::cond.raise(ioerr);
375407
}
@@ -383,14 +415,13 @@ trait DirectoryInfo : FileSystemInfo {
383415
})
384416
}
385417
}
386-
fn readdir(&self) -> ~[~str] {
387-
~[]
418+
fn readdir(&self) -> Option<~[Path]> {
419+
readdir(self.get_path())
388420
}
389421
//fn get_subdirs(&self, filter: &str) -> ~[Path];
390422
//fn get_files(&self, filter: &str) -> ~[Path];
391423
}
392424

393-
/// FIXME: DOCS
394425
impl DirectoryInfo for Path { }
395426

396427
fn file_test_smoke_test_impl() {
@@ -663,3 +694,41 @@ fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
663694
assert!(!dir.exists());
664695
}
665696
}
697+
698+
#[test]
699+
fn file_test_directoryinfo_readdir() {
700+
use str;
701+
do run_in_mt_newsched_task {
702+
let dir = &Path("./tmp/di_readdir");
703+
dir.mkdir();
704+
let prefix = "foo";
705+
for n in range(0,3) {
706+
let f = dir.push(fmt!("%d.txt", n));
707+
let mut w = f.open_writer(Create);
708+
let msg_str = (prefix + n.to_str().to_owned()).to_owned();
709+
let msg = msg_str.as_bytes();
710+
w.write(msg);
711+
}
712+
match dir.readdir() {
713+
Some(files) => {
714+
let mut mem = [0u8, .. 4];
715+
for f in files.iter() {
716+
{
717+
let n = f.filestem();
718+
let mut r = f.open_reader(Open);
719+
r.read(mem);
720+
let read_str = str::from_utf8(mem);
721+
let expected = match n {
722+
Some(n) => prefix+n,
723+
None => fail!("really shouldn't happen..")
724+
};
725+
assert!(expected == read_str);
726+
}
727+
f.unlink();
728+
}
729+
},
730+
None => fail!("shouldn't happen")
731+
}
732+
dir.rmdir();
733+
}
734+
}

src/libstd/rt/rtio.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ pub trait IoFactory {
7878
//fn fs_fstat(&mut self, fd: c_int) -> Result<FileStat, IoError>;
7979
fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
8080
fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
81+
fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
82+
Result<~[Path], IoError>;
8183
}
8284

8385
pub trait RtioStream {

src/libstd/rt/uv/file.rs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rt::uv::uvll;
1717
use rt::uv::uvll::*;
1818
use super::super::io::support::PathLike;
1919
use cast::transmute;
20+
use libc;
2021
use libc::{c_int};
2122
use option::{None, Some, Option};
2223

@@ -28,14 +29,6 @@ pub struct RequestData {
2829
}
2930

3031
impl FsRequest {
31-
pub fn new_REFACTOR_ME(cb: Option<FsCallback>) -> FsRequest {
32-
let fs_req = unsafe { malloc_req(UV_FS) };
33-
assert!(fs_req.is_not_null());
34-
let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
35-
fs_req.install_req_data(cb);
36-
fs_req
37-
}
38-
3932
pub fn new() -> FsRequest {
4033
let fs_req = unsafe { malloc_req(UV_FS) };
4134
assert!(fs_req.is_not_null());
@@ -180,6 +173,17 @@ impl FsRequest {
180173
});
181174
}
182175

176+
pub fn readdir<P: PathLike>(self, loop_: &Loop, path: &P,
177+
flags: c_int, cb: FsCallback) {
178+
let complete_cb_ptr = self.req_boilerplate(Some(cb));
179+
path.path_as_str(|p| {
180+
p.to_c_str().with_ref(|p| unsafe {
181+
uvll::fs_readdir(loop_.native_handle(),
182+
self.native_handle(), p, flags, complete_cb_ptr)
183+
})
184+
});
185+
}
186+
183187
// accessors/utility funcs
184188
fn sync_cleanup(self, result: c_int)
185189
-> Result<c_int, UvError> {
@@ -235,6 +239,36 @@ impl FsRequest {
235239
stat
236240
}
237241

242+
pub fn get_ptr(&self) -> *libc::c_void {
243+
unsafe {
244+
uvll::get_ptr_from_fs_req(self.native_handle())
245+
}
246+
}
247+
248+
pub fn get_paths(&mut self) -> ~[~str] {
249+
use str;
250+
let ptr = self.get_ptr();
251+
match self.get_result() {
252+
n if (n <= 0) => {
253+
~[]
254+
},
255+
n => {
256+
let n_len = n as uint;
257+
// we pass in the len that uv tells us is there
258+
// for the entries and we don't continue past that..
259+
// it appears that sometimes the multistring isn't
260+
// correctly delimited and we stray into garbage memory?
261+
// in any case, passing Some(n_len) fixes it and ensures
262+
// good results
263+
let raw_path_strs = unsafe {
264+
str::raw::from_c_multistring(ptr as *libc::c_char, Some(n_len)) };
265+
let raw_len = raw_path_strs.len();
266+
assert_eq!(raw_len, n_len);
267+
raw_path_strs
268+
}
269+
}
270+
}
271+
238272
fn cleanup_and_delete(self) {
239273
unsafe {
240274
let data = uvll::get_data_for_req(self.native_handle());

src/libstd/rt/uv/uvio.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,44 @@ impl IoFactory for UvIoFactory {
704704
};
705705
}
706706
}
707+
fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
708+
Result<~[Path], IoError> {
709+
use str::StrSlice;
710+
let result_cell = Cell::new_empty();
711+
let result_cell_ptr: *Cell<Result<~[Path],
712+
IoError>> = &result_cell;
713+
let path_cell = Cell::new(path);
714+
do task::unkillable { // FIXME(#8674)
715+
let scheduler: ~Scheduler = Local::take();
716+
let stat_req = file::FsRequest::new();
717+
do scheduler.deschedule_running_task_and_then |_, task| {
718+
let task_cell = Cell::new(task);
719+
let path = path_cell.take();
720+
let path_str = path.path_as_str(|p| p.to_owned());
721+
do stat_req.readdir(self.uv_loop(), path, flags)
722+
|req,err| {
723+
let res = match err {
724+
None => {
725+
let rel_paths = req.get_paths();
726+
let mut paths = ~[];
727+
for r in rel_paths.iter() {
728+
paths.push(Path(path_str+"/"+*r));
729+
}
730+
Ok(paths)
731+
},
732+
Some(e) => {
733+
Err(uv_error_to_io_error(e))
734+
}
735+
};
736+
unsafe { (*result_cell_ptr).put_back(res); }
737+
let scheduler: ~Scheduler = Local::take();
738+
scheduler.resume_blocked_task_immediately(task_cell.take());
739+
};
740+
};
741+
};
742+
assert!(!result_cell.is_empty());
743+
return result_cell.take();
744+
}
707745
}
708746

709747
pub struct UvTcpListener {

src/libstd/rt/uv/uvll.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,12 @@ pub unsafe fn fs_rmdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
811811

812812
rust_uv_fs_rmdir(loop_ptr, req, path, cb)
813813
}
814+
pub unsafe fn fs_readdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
815+
flags: c_int, cb: *u8) -> c_int {
816+
#[fixed_stack_segment]; #[inline(never)];
817+
818+
rust_uv_fs_readdir(loop_ptr, req, path, flags, cb)
819+
}
814820
pub unsafe fn populate_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t) {
815821
#[fixed_stack_segment]; #[inline(never)];
816822

@@ -828,6 +834,11 @@ pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
828834

829835
rust_uv_get_result_from_fs_req(req)
830836
}
837+
pub unsafe fn get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void {
838+
#[fixed_stack_segment]; #[inline(never)];
839+
840+
rust_uv_get_ptr_from_fs_req(req)
841+
}
831842
pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
832843
#[fixed_stack_segment]; #[inline(never)];
833844

@@ -1014,9 +1025,12 @@ extern {
10141025
mode: c_int, cb: *u8) -> c_int;
10151026
fn rust_uv_fs_rmdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
10161027
cb: *u8) -> c_int;
1028+
fn rust_uv_fs_readdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
1029+
flags: c_int, cb: *u8) -> c_int;
10171030
fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
10181031
fn rust_uv_populate_uv_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t);
10191032
fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
1033+
fn rust_uv_get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void;
10201034
fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
10211035
fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t;
10221036

src/rt/rust_uv.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,10 @@ extern "C" int
542542
rust_uv_get_result_from_fs_req(uv_fs_t* req) {
543543
return req->result;
544544
}
545+
extern "C" void*
546+
rust_uv_get_ptr_from_fs_req(uv_fs_t* req) {
547+
return req->ptr;
548+
}
545549
extern "C" uv_loop_t*
546550
rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
547551
return req->loop;
@@ -593,3 +597,8 @@ extern "C" int
593597
rust_uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
594598
return uv_fs_rmdir(loop, req, path, cb);
595599
}
600+
601+
extern "C" int
602+
rust_uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) {
603+
return uv_fs_readdir(loop, req, path, flags, cb);
604+
}

src/rt/rustrt.def.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,15 @@ rust_uv_fs_write
113113
rust_uv_fs_read
114114
rust_uv_fs_close
115115
rust_uv_get_result_from_fs_req
116+
rust_uv_get_ptr_from_fs_req
116117
rust_uv_get_loop_from_fs_req
117118
rust_uv_fs_stat
118119
rust_uv_fs_fstat
119120
rust_uv_fs_req_cleanup
120121
rust_uv_populate_uv_stat
121122
rust_uv_fs_mkdir
122123
rust_uv_fs_rmdir
124+
rust_uv_fs_readdir
123125
rust_dbg_lock_create
124126
rust_dbg_lock_destroy
125127
rust_dbg_lock_lock

0 commit comments

Comments
 (0)