about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorJeff Olson <olson.jeffery@gmail.com>2013-09-14 09:33:53 -0700
committerJeff Olson <olson.jeffery@gmail.com>2013-09-16 23:17:46 -0700
commitb49fc4cf4eb7299a08d83ed8880d1002ecef9257 (patch)
treea958f857bd3750f8fba3bcedd6e3b6dc8ce5cad7 /src/libstd/rt
parent055488df1a6a4500de565ac2531d7bc42dd02f83 (diff)
downloadrust-b49fc4cf4eb7299a08d83ed8880d1002ecef9257.tar.gz
rust-b49fc4cf4eb7299a08d83ed8880d1002ecef9257.zip
std: adding file::{stat,mkdir,rmdir}, FileInfo and FileReader/FileWriter
add ignores for win32 tests on previous file io stuff...
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/io/file.rs284
-rw-r--r--src/libstd/rt/rtio.rs2
-rw-r--r--src/libstd/rt/uv/file.rs6
-rw-r--r--src/libstd/rt/uv/uvio.rs104
-rw-r--r--src/libstd/rt/uv/uvll.rs4
5 files changed, 269 insertions, 131 deletions
diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs
index ee102c3a97f..4968f327602 100644
--- a/src/libstd/rt/io/file.rs
+++ b/src/libstd/rt/io/file.rs
@@ -12,7 +12,7 @@ use prelude::*;
 use super::support::PathLike;
 use super::{Reader, Writer, Seek};
 use super::{SeekStyle,SeekSet, SeekCur, SeekEnd,
-            Open, Read, Create, ReadWrite};
+            Open, Read, Write, Create, ReadWrite};
 use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject};
 use rt::io::{io_error, read_error, EndOfFile,
             FileMode, FileAccess, FileStat};
@@ -57,26 +57,108 @@ pub fn unlink<P: PathLike>(path: &P) {
     }
 }
 
-/// Abstraction representing *positional* access to a file. In this case,
-/// *positional* refers to it keeping an encounter *cursor* of where in the
-/// file a subsequent `read` or `write` will begin from. Users of a `FileStream`
-/// can `seek` to move the cursor to a given location *within the bounds of the
-/// file* and can ask to have the `FileStream` `tell` them the location, in
-/// bytes, of the cursor.
-///
-/// This abstraction is roughly modeled on the access workflow as represented
-/// by `open(2)`, `read(2)`, `write(2)` and friends.
+/// Create a new directory with default permissions (process user
+/// has read/write privs)
+pub fn mkdir<P: PathLike>(path: &P) {
+    let mkdir_result = unsafe {
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
+        (*io).fs_mkdir(path)
+    };
+    match mkdir_result {
+        Ok(_) => (),
+        Err(ioerr) => {
+            io_error::cond.raise(ioerr);
+        }
+    }
+}
+/// Removes a directory
+pub fn rmdir<P: PathLike>(path: &P) {
+    let rmdir_result = unsafe {
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
+        (*io).fs_rmdir(path)
+    };
+    match rmdir_result {
+        Ok(_) => (),
+        Err(ioerr) => {
+            io_error::cond.raise(ioerr);
+        }
+    }
+}
+
+/// Given a `rt::io::support::PathLike`, query the file system to get
+/// information about a file, directory, etc.
 ///
-/// The `open` and `unlink` static methods are provided to manage creation/removal
-/// of files. All other methods operatin on an instance of `FileStream`.
+/// Returns a `Some(PathInfo)` on success, and raises a `rt::io::IoError` condition
+/// on failure and returns `None`.
+pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
+    let open_result = unsafe {
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
+        (*io).fs_stat(path)
+    };
+    match open_result {
+        Ok(p) => {
+            Some(p)
+        },
+        Err(ioerr) => {
+            read_error::cond.raise(ioerr);
+            None
+        }
+    }
+}
+
+/// Read-only view of file
+pub struct FileReader { priv stream: FileStream }
+
+impl Reader for FileReader {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+        self.stream.read(buf)
+    }
+
+    fn eof(&mut self) -> bool {
+        self.stream.eof()
+    }
+}
+
+impl Seek for FileReader {
+    fn tell(&self) -> u64 {
+        self.stream.tell()
+    }
+
+    fn seek(&mut self, pos: i64, style: SeekStyle) {
+        self.stream.seek(pos, style);
+    }
+}
+
+/// Write-only view of a file
+pub struct FileWriter { priv stream: FileStream }
+
+impl Writer for FileWriter {
+    fn write(&mut self, buf: &[u8]) {
+        self.stream.write(buf);
+    }
+
+    fn flush(&mut self) {
+        self.stream.flush();
+    }
+}
+
+impl Seek for FileWriter {
+    fn tell(&self) -> u64 {
+        self.stream.tell()
+    }
+
+    fn seek(&mut self, pos: i64, style: SeekStyle) {
+        self.stream.seek(pos, style);
+    }
+}
+
+/// Internal representation of a FileStream, used to consolidate functionality
+/// exposed in the public API
 pub struct FileStream {
     fd: ~RtioFileStream,
     last_nread: int,
 }
 
-impl FileStream {
-}
-
 impl Reader for FileStream {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
         match self.fd.read(buf) {
@@ -148,69 +230,85 @@ impl Seek for FileStream {
     }
 }
 
-pub struct FileInfo(Path);
-
-/// FIXME: DOCS
-impl<'self> FileInfo {
-    pub fn new<P: PathLike>(path: &P) -> FileInfo {
-        do path.path_as_str |p| {
-            FileInfo(Path(p))
-        }
-    }
-    // FIXME #8873 can't put this in FileSystemInfo
-    pub fn get_path(&'self self) -> &'self Path {
-        &(**self)
-    }
-    pub fn stat(&self) -> Option<FileStat> {
-        do io_error::cond.trap(|_| {
+/// Represents passive information about a file (primarily exposed
+/// via the `stat()` method. Also provides methods for opening
+/// a file in various modes/permissions.
+pub trait FileInfo<'self> {
+    /// Get the filesystem path that this `FileInfo` points at,
+    /// whether it is valid or not. This way, it can be used to
+    /// to specify a file path of a non-existent file which it
+    /// later create
+    fn get_file_path(&'self self) -> &'self Path;
+
+    /// Ask the operating system for information about the file
+    fn stat(&self) -> Option<FileStat> {
+        use mod_stat = super::file::stat;
+        do read_error::cond.trap(|_| {
             // FIXME: can we do something more useful here?
         }).inside {
-            stat(self.get_path())
+            mod_stat(self.get_file_path())
         }
     }
-    pub fn exists(&self) -> bool {
+
+    /// returns `true` if the location pointed at by the enclosing
+    /// exists on the filesystem
+    fn file_exists(&self) -> bool {
         match self.stat() {
-            Some(s) => {
-                match s.is_file {
-                    true => {
-                        true
-                    },
-                    false => {
-                        // FIXME: raise condition?
-                        false
-                    }
-                }
-            },
+            Some(_) => true,
             None => false
         }
     }
-    pub fn is_file(&self) -> bool {
+
+    /// Whether the underlying implemention (be it a file path
+    /// or active file descriptor) is a "regular file". Will return
+    /// false for paths to non-existent locations or directories or
+    /// other non-regular files (named pipes, etc).
+    fn is_file(&self) -> bool {
         match self.stat() {
             Some(s) => s.is_file,
-            None => {
-                // FIXME: raise condition
-                false
-            }
+            None => false
         }
     }
-    pub fn open(&self, mode: FileMode, access: FileAccess) -> Option<FileStream> {
-        match self.is_file() {
-            true => {
-                open(self.get_path(), mode, access)
+
+    /// Attempts to open a regular file for reading/writing based
+    /// on provided inputs
+    fn open_stream(&self, mode: FileMode, access: FileAccess) -> Option<FileStream> {
+        match self.stat() {
+            Some(s) => match s.is_file {
+                true => open(self.get_file_path(), mode, access),
+                false => None // FIXME: raise condition, not a regular file..
             },
-            false => {
-                // FIXME: raise condition
-                None
-            }
+            None => open(self.get_file_path(), mode, access)
+        }
+    }
+    /// Attempts to open a regular file for reading-only based
+    /// on provided inputs
+    fn open_reader(&self, mode: FileMode) -> Option<FileReader> {
+        match self.open_stream(mode, Read) {
+            Some(s) => Some(FileReader { stream: s}),
+            None => None
+        }
+    }
+
+    /// Attempts to open a regular file for writing-only based
+    /// on provided inputs
+    fn open_writer(&self, mode: FileMode) -> Option<FileWriter> {
+        match self.open_stream(mode, Write) {
+            Some(s) => Some(FileWriter { stream: s}),
+            None => None
         }
     }
-    //fn open_read(&self) -> FileStream;
-    //fn open_write(&self) -> FileStream;
-    //fn create(&self) -> FileStream;
-    //fn truncate(&self) -> FileStream;
-    //fn open_or_create(&self) -> FileStream;
-    //fn create_or_truncate(&self) -> FileStream;
-    //fn unlink(&self);
+
+    /// Attempt to remove a file from the filesystem, pending the closing
+    /// of any open file descriptors pointing to the file
+    fn unlink(&self) {
+        unlink(self.get_file_path());
+    }
+}
+
+/// `FileInfo` implementation for `Path`s 
+impl<'self> FileInfo<'self> for Path {
+    fn get_file_path(&'self self) -> &'self Path { self }
 }
 
 /*
@@ -244,27 +342,6 @@ impl DirectoryInfo<'self> {
 }
 */
 
-/// Given a `rt::io::support::PathLike`, query the file system to get
-/// information about a file, directory, etc.
-///
-/// Returns a `Some(PathInfo)` on success, and raises a `rt::io::IoError` condition
-/// on failure and returns `None`.
-pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
-    let open_result = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_stat(path)
-    };
-    match open_result {
-        Ok(p) => {
-            Some(p)
-        },
-        Err(ioerr) => {
-            read_error::cond.raise(ioerr);
-            None
-        }
-    }
-}
-
 fn file_test_smoke_test_impl() {
     do run_in_mt_newsched_task {
         let message = "it's alright. have a good time";
@@ -412,7 +489,7 @@ fn file_test_io_seek_and_write_impl() {
             read_stream.read(read_mem);
         }
         unlink(filename);
-        let read_str = str::from_bytes(read_mem);
+        let read_str = str::from_utf8(read_mem);
         assert!(read_str == final_msg.to_owned());
     }
 }
@@ -463,8 +540,9 @@ fn file_test_io_seek_shakedown() {
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_stat_is_correct_on_is_file() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let filename = &Path("./tmp/file_stat_correct_on_is_file.txt");
         {
             let mut fs = open(filename, Create, ReadWrite).unwrap();
@@ -476,20 +554,48 @@ fn file_test_stat_is_correct_on_is_file() {
             None => fail!("shouldn't happen")
         };
         assert!(stat_res.is_file);
+        unlink(filename);
     }
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_stat_is_correct_on_is_dir() {
-    //assert!(false);
+    do run_in_mt_newsched_task {
+        let filename = &Path("./tmp/file_stat_correct_on_is_dir");
+        mkdir(filename);
+        let stat_res = match stat(filename) {
+            Some(s) => s,
+            None => fail!("shouldn't happen")
+        };
+        assert!(stat_res.is_dir);
+        rmdir(filename);
+    }
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
-    //assert!(false);
+    do run_in_mt_newsched_task {
+        let dir = &Path("./tmp/fileinfo_false_on_dir");
+        mkdir(dir);
+        assert!(dir.is_file() == false);
+        rmdir(dir);
+    }
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
-    //assert!(false);
+    do run_in_mt_newsched_task {
+        let file = &Path("./tmp/fileinfo_check_exists_b_and_a.txt");
+        {
+            let msg = "foo".as_bytes();
+            let mut w = file.open_writer(Create);
+            w.write(msg);
+        }
+        assert!(file.file_exists());
+        file.unlink();
+        assert!(!file.file_exists());
+    }
 }
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs
index f08949e9165..0abf81f62de 100644
--- a/src/libstd/rt/rtio.rs
+++ b/src/libstd/rt/rtio.rs
@@ -76,6 +76,8 @@ pub trait IoFactory {
     fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>;
     fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError>;
     //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>;
 }
 
 pub trait RtioStream {
diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs
index 850b28718d0..34f87e3601e 100644
--- a/src/libstd/rt/uv/file.rs
+++ b/src/libstd/rt/uv/file.rs
@@ -183,9 +183,8 @@ impl FsRequest {
     // accessors/utility funcs
     fn sync_cleanup(self, result: c_int)
           -> Result<c_int, UvError> {
-        let loop_ = self.get_loop().native_handle();
         self.cleanup_and_delete();
-        match status_to_maybe_uv_error_with_loop(loop_,result as i32) {
+        match status_to_maybe_uv_error(result as i32) {
             Some(err) => Err(err),
             None => Ok(result)
         }
@@ -261,6 +260,8 @@ fn sync_cleanup(result: int)
     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);
@@ -522,6 +523,7 @@ mod test {
                     assert!(uverr.is_none());
                     let loop_ = req.get_loop();
                     let stat = req.get_stat();
+                    naive_print(&loop_, fmt!("%?", stat));
                     assert!(stat.is_dir());
                     let rmdir_req = FsRequest::new();
                     do rmdir_req.rmdir(&loop_, &path) |req,uverr| {
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index 4307c57529b..88d168c85d2 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -35,7 +35,7 @@ use unstable::sync::Exclusive;
 use path::Path;
 use super::super::io::support::PathLike;
 use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY,
-          S_IRUSR, S_IWUSR};
+          S_IRUSR, S_IWUSR, S_IRWXU};
 use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create,
              CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite,
              FileStat};
@@ -413,6 +413,36 @@ impl UvIoFactory {
     }
 }
 
+/// Helper for a variety of simple uv_fs_* functions that
+/// have no ret val
+fn uv_fs_helper<P: PathLike>(loop_: &mut Loop, path: &P,
+                             cb: ~fn(&mut FsRequest, &mut Loop, &P,
+                                     ~fn(&FsRequest, Option<UvError>)))
+        -> Result<(), IoError> {
+    let result_cell = Cell::new_empty();
+    let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+    let path_cell = Cell::new(path);
+    do task::unkillable { // FIXME(#8674)
+        let scheduler: ~Scheduler = Local::take();
+        let mut new_req = FsRequest::new();
+        do scheduler.deschedule_running_task_and_then |_, task| {
+            let task_cell = Cell::new(task);
+            let path = path_cell.take();
+            do cb(&mut new_req, loop_, path) |_, err| {
+                let res = match err {
+                    None => Ok(()),
+                    Some(err) => Err(uv_error_to_io_error(err))
+                };
+                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();
+}
+
 impl IoFactory for UvIoFactory {
     // Connect to an address and return a new stream
     // NB: This blocks the task waiting on the connection.
@@ -578,28 +608,11 @@ impl IoFactory for UvIoFactory {
     }
 
     fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
-        let result_cell = Cell::new_empty();
-        let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
-        let path_cell = Cell::new(path);
-        do task::unkillable { // FIXME(#8674)
-            let scheduler: ~Scheduler = Local::take();
-            let unlink_req = FsRequest::new();
-            do scheduler.deschedule_running_task_and_then |_, task| {
-                let task_cell = Cell::new(task);
-                let path = path_cell.take();
-                do unlink_req.unlink(self.uv_loop(), path) |_, err| {
-                    let res = match err {
-                        None => Ok(()),
-                        Some(err) => Err(uv_error_to_io_error(err))
-                    };
-                    unsafe { (*result_cell_ptr).put_back(res); }
-                    let scheduler: ~Scheduler = Local::take();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                };
-            }
+        do uv_fs_helper(self.uv_loop(), path) |unlink_req, l, p, cb| {
+            do unlink_req.unlink(l, p) |req, err| {
+                cb(req, err)
+            };
         }
-        assert!(!result_cell.is_empty());
-        return result_cell.take();
     }
     fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError> {
         use str::StrSlice;
@@ -616,22 +629,22 @@ impl IoFactory for UvIoFactory {
                 let path_str = path.path_as_str(|p| p.to_owned());
                 do stat_req.stat(self.uv_loop(), path)
                       |req,err| {
-                    if err.is_none() {
-                        let stat = req.get_stat();
-                        let res = Ok(FileStat {
-                            path: Path(path_str),
-                            is_file: stat.is_file(),
-                            is_dir: stat.is_dir()
-                        });
-                        unsafe { (*result_cell_ptr).put_back(res); }
-                        let scheduler: ~Scheduler = Local::take();
-                        scheduler.resume_blocked_task_immediately(task_cell.take());
-                    } else {
-                        let res = Err(uv_error_to_io_error(err.unwrap()));
-                        unsafe { (*result_cell_ptr).put_back(res); }
-                        let scheduler: ~Scheduler = Local::take();
-                        scheduler.resume_blocked_task_immediately(task_cell.take());
-                    }
+                    let res = match err {
+                        None => {
+                            let stat = req.get_stat();
+                            Ok(FileStat {
+                                path: Path(path_str),
+                                is_file: stat.is_file(),
+                                is_dir: stat.is_dir()
+                            })
+                        },
+                        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());
                 };
             };
         };
@@ -672,6 +685,21 @@ impl IoFactory for UvIoFactory {
     //fn fs_fstat(&mut self, _fd: c_int) -> Result<FileStat, IoError> {
     //    Ok(FileStat)
     //}
+    fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
+        let mode = S_IRWXU as int;
+        do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| {
+            do mkdir_req.mkdir(l, p, mode as int) |req, err| {
+                cb(req, err)
+            };
+        }
+    }
+    fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
+        do uv_fs_helper(self.uv_loop(), path) |rmdir_req, l, p, cb| {
+            do rmdir_req.rmdir(l, p) |req, err| {
+                cb(req, err)
+            };
+        }
+    }
 }
 
 pub struct UvTcpListener {
diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs
index 89ee54be349..a2d1c48c3e1 100644
--- a/src/libstd/rt/uv/uvll.rs
+++ b/src/libstd/rt/uv/uvll.rs
@@ -142,10 +142,10 @@ impl uv_stat_t {
         }
     }
     pub fn is_file(&self) -> bool {
-        ((self.st_mode as c_int) & libc::S_IFMT) == libc::S_IFREG
+        ((self.st_mode) & libc::S_IFMT as libc::uint64_t) == libc::S_IFREG as libc::uint64_t
     }
     pub fn is_dir(&self) -> bool {
-        ((self.st_mode as c_int) & libc::S_IFMT) == libc::S_IFDIR
+        ((self.st_mode) & libc::S_IFMT as libc::uint64_t) == libc::S_IFDIR as libc::uint64_t
     }
 }