about summary refs log tree commit diff
path: root/src/libstd/io
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-01-29 16:33:57 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-02-03 09:32:33 -0800
commitece8a8f520697be50cbe543bebe065c5198dae4d (patch)
treefa1bf049d3b5d781c8c56e0d0491a655ece485a2 /src/libstd/io
parentbe4fc638092bf896c5c6c0672136b83b71e491ee (diff)
downloadrust-ece8a8f520697be50cbe543bebe065c5198dae4d.tar.gz
rust-ece8a8f520697be50cbe543bebe065c5198dae4d.zip
std: Remove io::io_error
* All I/O now returns IoResult<T> = Result<T, IoError>
* All formatting traits now return fmt::Result = IoResult<()>
* The if_ok!() macro was added to libstd
Diffstat (limited to 'src/libstd/io')
-rw-r--r--src/libstd/io/buffered.rs80
-rw-r--r--src/libstd/io/comm_adapters.rs17
-rw-r--r--src/libstd/io/extensions.rs2
-rw-r--r--src/libstd/io/fs.rs359
-rw-r--r--src/libstd/io/mem.rs61
-rw-r--r--src/libstd/io/mod.rs440
-rw-r--r--src/libstd/io/net/addrinfo.rs7
-rw-r--r--src/libstd/io/net/tcp.rs82
-rw-r--r--src/libstd/io/net/udp.rs49
-rw-r--r--src/libstd/io/net/unix.rs60
-rw-r--r--src/libstd/io/pipe.rs26
-rw-r--r--src/libstd/io/process.rs15
-rw-r--r--src/libstd/io/result.rs (renamed from src/libstd/io/option.rs)74
-rw-r--r--src/libstd/io/signal.rs13
-rw-r--r--src/libstd/io/stdio.rs76
-rw-r--r--src/libstd/io/timer.rs7
-rw-r--r--src/libstd/io/util.rs64
17 files changed, 630 insertions, 802 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 64e42c5480f..5e64862cbec 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -11,10 +11,11 @@
 //! Buffering wrappers for I/O traits
 
 use container::Container;
-use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE};
+use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult};
 use iter::ExactSize;
 use num;
-use option::{Option, Some, None};
+use option::{Some, None};
+use result::{Ok, Err};
 use vec::{OwnedVector, ImmutableVector, MutableVector};
 use vec;
 
@@ -86,17 +87,12 @@ impl<R: Reader> BufferedReader<R> {
 }
 
 impl<R: Reader> Buffer for BufferedReader<R> {
-    fn fill<'a>(&'a mut self) -> &'a [u8] {
-        if self.pos == self.cap {
-            match self.inner.read(self.buf) {
-                Some(cap) => {
-                    self.pos = 0;
-                    self.cap = cap;
-                }
-                None => { self.eof = true; }
-            }
+    fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> {
+        while self.pos == self.cap {
+            self.cap = if_ok!(self.inner.read(self.buf));
+            self.pos = 0;
         }
-        return self.buf.slice(self.pos, self.cap);
+        Ok(self.buf.slice(self.pos, self.cap))
     }
 
     fn consume(&mut self, amt: uint) {
@@ -106,18 +102,15 @@ impl<R: Reader> Buffer for BufferedReader<R> {
 }
 
 impl<R: Reader> Reader for BufferedReader<R> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         let nread = {
-            let available = self.fill();
+            let available = if_ok!(self.fill());
             let nread = num::min(available.len(), buf.len());
             vec::bytes::copy_memory(buf, available.slice_to(nread));
             nread
         };
         self.pos += nread;
-        if nread == 0 && buf.len() != 0 && self.eof {
-            return None;
-        }
-        Some(nread)
+        Ok(nread)
     }
 }
 
@@ -161,10 +154,13 @@ impl<W: Writer> BufferedWriter<W> {
         BufferedWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
     }
 
-    fn flush_buf(&mut self) {
+    fn flush_buf(&mut self) -> IoResult<()> {
         if self.pos != 0 {
-            self.inner.write(self.buf.slice_to(self.pos));
+            let ret = self.inner.write(self.buf.slice_to(self.pos));
             self.pos = 0;
+            ret
+        } else {
+            Ok(())
         }
     }
 
@@ -178,29 +174,30 @@ impl<W: Writer> BufferedWriter<W> {
     ///
     /// The buffer is flushed before returning the writer.
     pub fn unwrap(mut self) -> W {
-        self.flush_buf();
+        // FIXME: is failing the right thing to do if flushing fails?
+        self.flush_buf().unwrap();
         self.inner
     }
 }
 
 impl<W: Writer> Writer for BufferedWriter<W> {
-    fn write(&mut self, buf: &[u8]) {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         if self.pos + buf.len() > self.buf.len() {
-            self.flush_buf();
+            if_ok!(self.flush_buf());
         }
 
         if buf.len() > self.buf.len() {
-            self.inner.write(buf);
+            self.inner.write(buf)
         } else {
             let dst = self.buf.mut_slice_from(self.pos);
             vec::bytes::copy_memory(dst, buf);
             self.pos += buf.len();
+            Ok(())
         }
     }
 
-    fn flush(&mut self) {
-        self.flush_buf();
-        self.inner.flush();
+    fn flush(&mut self) -> IoResult<()> {
+        self.flush_buf().and_then(|()| self.inner.flush())
     }
 }
 
@@ -234,18 +231,19 @@ impl<W: Writer> LineBufferedWriter<W> {
 }
 
 impl<W: Writer> Writer for LineBufferedWriter<W> {
-    fn write(&mut self, buf: &[u8]) {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         match buf.iter().rposition(|&b| b == '\n' as u8) {
             Some(i) => {
-                self.inner.write(buf.slice_to(i + 1));
-                self.inner.flush();
-                self.inner.write(buf.slice_from(i + 1));
+                if_ok!(self.inner.write(buf.slice_to(i + 1)));
+                if_ok!(self.inner.flush());
+                if_ok!(self.inner.write(buf.slice_from(i + 1)));
+                Ok(())
             }
             None => self.inner.write(buf),
         }
     }
 
-    fn flush(&mut self) { self.inner.flush() }
+    fn flush(&mut self) -> IoResult<()> { self.inner.flush() }
 }
 
 struct InternalBufferedWriter<W>(BufferedWriter<W>);
@@ -258,7 +256,9 @@ impl<W> InternalBufferedWriter<W> {
 }
 
 impl<W: Reader> Reader for InternalBufferedWriter<W> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.get_mut_ref().inner.read(buf) }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        self.get_mut_ref().inner.read(buf)
+    }
 }
 
 /// Wraps a Stream and buffers input and output to and from it
@@ -326,17 +326,23 @@ impl<S: Stream> BufferedStream<S> {
 }
 
 impl<S: Stream> Buffer for BufferedStream<S> {
-    fn fill<'a>(&'a mut self) -> &'a [u8] { self.inner.fill() }
+    fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { self.inner.fill() }
     fn consume(&mut self, amt: uint) { self.inner.consume(amt) }
 }
 
 impl<S: Stream> Reader for BufferedStream<S> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.inner.read(buf) }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        self.inner.read(buf)
+    }
 }
 
 impl<S: Stream> Writer for BufferedStream<S> {
-    fn write(&mut self, buf: &[u8]) { self.inner.inner.get_mut_ref().write(buf) }
-    fn flush(&mut self) { self.inner.inner.get_mut_ref().flush() }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        self.inner.inner.get_mut_ref().write(buf)
+    }
+    fn flush(&mut self) -> IoResult<()> {
+        self.inner.inner.get_mut_ref().flush()
+    }
 }
 
 #[cfg(test)]
diff --git a/src/libstd/io/comm_adapters.rs b/src/libstd/io/comm_adapters.rs
index 1eaa752d2a3..e86ad50d690 100644
--- a/src/libstd/io/comm_adapters.rs
+++ b/src/libstd/io/comm_adapters.rs
@@ -14,7 +14,7 @@ use comm::{Port, Chan};
 use cmp;
 use io;
 use option::{None, Option, Some};
-use super::{Reader, Writer};
+use super::{Reader, Writer, IoResult};
 use vec::{bytes, CloneableVector, MutableVector, ImmutableVector};
 
 /// Allows reading from a port.
@@ -49,7 +49,7 @@ impl PortReader {
 }
 
 impl Reader for PortReader {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         let mut num_read = 0;
         loop {
             match self.buf {
@@ -71,10 +71,9 @@ impl Reader for PortReader {
             self.closed = self.buf.is_none();
         }
         if self.closed && num_read == 0 {
-            io::io_error::cond.raise(io::standard_error(io::EndOfFile));
-            None
+            Err(io::standard_error(io::EndOfFile))
         } else {
-            Some(num_read)
+            Ok(num_read)
         }
     }
 }
@@ -98,13 +97,15 @@ impl ChanWriter {
 }
 
 impl Writer for ChanWriter {
-    fn write(&mut self, buf: &[u8]) {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         if !self.chan.try_send(buf.to_owned()) {
-            io::io_error::cond.raise(io::IoError {
+            Err(io::IoError {
                 kind: io::BrokenPipe,
                 desc: "Pipe closed",
                 detail: None
-            });
+            })
+        } else {
+            Ok(())
         }
     }
 }
diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs
index 548dc3efe92..7e1dbcaeade 100644
--- a/src/libstd/io/extensions.rs
+++ b/src/libstd/io/extensions.rs
@@ -46,7 +46,7 @@ impl<'r, R: Reader> Bytes<'r, R> {
 impl<'r, R: Reader> Iterator<u8> for Bytes<'r, R> {
     #[inline]
     fn next(&mut self) -> Option<u8> {
-        self.reader.read_byte()
+        self.reader.read_byte().ok()
     }
 }
 
diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs
index 8904101dd05..867e0ebd6ee 100644
--- a/src/libstd/io/fs.rs
+++ b/src/libstd/io/fs.rs
@@ -27,21 +27,25 @@ particular bits of it, etc.
 
 # Example
 
-    use std::io::{File, fs};
+```rust
+# #[allow(unused_must_use)];
+use std::io::{File, fs};
 
-    let path = Path::new("foo.txt");
+let path = Path::new("foo.txt");
 
-    // create the file, whether it exists or not
-    let mut file = File::create(&path);
-    file.write(bytes!("foobar"));
+// create the file, whether it exists or not
+let mut file = File::create(&path);
+file.write(bytes!("foobar"));
+# drop(file);
 
-    // open the file in read-only mode
-    let mut file = File::open(&path);
-    file.read_to_end();
+// open the file in read-only mode
+let mut file = File::open(&path);
+file.read_to_end();
 
-    println!("{}", path.stat().size);
-    fs::symlink(&path, &Path::new("bar.txt"));
-    fs::unlink(&path);
+println!("{}", path.stat().size);
+# drop(file);
+fs::unlink(&path);
+```
 
 */
 
@@ -50,7 +54,7 @@ use clone::Clone;
 use iter::Iterator;
 use super::{Reader, Writer, Seek};
 use super::{SeekStyle, Read, Write, Open, IoError, Truncate,
-            FileMode, FileAccess, FileStat, io_error, FilePermission};
+            FileMode, FileAccess, FileStat, IoResult, FilePermission};
 use rt::rtio::{RtioFileStream, IoFactory, LocalIo};
 use io;
 use option::{Some, None, Option};
@@ -81,22 +85,19 @@ impl File {
     ///
     /// # Example
     ///
-    ///     use std::io::{File, io_error, Open, ReadWrite};
+    /// ```rust
+    /// use std::io::{File, Open, ReadWrite};
     ///
-    ///     let p = Path::new("/some/file/path.txt");
+    /// let p = Path::new("/some/file/path.txt");
     ///
-    ///     io_error::cond.trap(|_| {
-    ///         // hoo-boy...
-    ///     }).inside(|| {
-    ///         let file = match File::open_mode(&p, Open, ReadWrite) {
-    ///             Some(s) => s,
-    ///             None => fail!("whoops! I'm sure this raised, anyways..")
-    ///         };
-    ///         // do some stuff with that file
+    /// let file = match File::open_mode(&p, Open, ReadWrite) {
+    ///     Ok(f) => f,
+    ///     Err(e) => fail!("file error: {}", e),
+    /// };
+    /// // do some stuff with that file
     ///
-    ///         // the file will be closed at the end of this block
-    ///     })
-    ///     // ..
+    /// // the file will be closed at the end of this block
+    /// ```
     ///
     /// `FileMode` and `FileAccess` provide information about the permissions
     /// context in which a given stream is created. More information about them
@@ -119,7 +120,7 @@ impl File {
     /// * Filesystem-level errors (full disk, etc)
     pub fn open_mode(path: &Path,
                      mode: FileMode,
-                     access: FileAccess) -> Option<File> {
+                     access: FileAccess) -> IoResult<File> {
         LocalIo::maybe_raise(|io| {
             io.fs_open(&path.to_c_str(), mode, access).map(|fd| {
                 File {
@@ -139,10 +140,12 @@ impl File {
     ///
     /// # Example
     ///
-    ///     use std::io::File;
+    /// ```rust
+    /// use std::io::File;
     ///
-    ///     let contents = File::open(&Path::new("foo.txt")).read_to_end();
-    pub fn open(path: &Path) -> Option<File> {
+    /// let contents = File::open(&Path::new("foo.txt")).read_to_end();
+    /// ```
+    pub fn open(path: &Path) -> IoResult<File> {
         File::open_mode(path, Open, Read)
     }
 
@@ -154,11 +157,16 @@ impl File {
     ///
     /// # Example
     ///
-    ///     use std::io::File;
+    /// ```rust
+    /// # #[allow(unused_must_use)];
+    /// use std::io::File;
     ///
-    ///     let mut f = File::create(&Path::new("foo.txt"));
-    ///     f.write(bytes!("This is a sample file"));
-    pub fn create(path: &Path) -> Option<File> {
+    /// let mut f = File::create(&Path::new("foo.txt"));
+    /// f.write(bytes!("This is a sample file"));
+    /// # drop(f);
+    /// # ::std::io::fs::unlnk(&Path::new("foo.txt"));
+    /// ```
+    pub fn create(path: &Path) -> IoResult<File> {
         File::open_mode(path, Truncate, Write)
     }
 
@@ -174,8 +182,8 @@ impl File {
     /// # Errors
     ///
     /// This function will raise on the `io_error` condition on failure.
-    pub fn fsync(&mut self) {
-        let _ = self.fd.fsync().map_err(|e| io_error::cond.raise(e));
+    pub fn fsync(&mut self) -> IoResult<()> {
+        self.fd.fsync()
     }
 
     /// This function is similar to `fsync`, except that it may not synchronize
@@ -186,8 +194,8 @@ impl File {
     /// # Errors
     ///
     /// This function will raise on the `io_error` condition on failure.
-    pub fn datasync(&mut self) {
-        let _ = self.fd.datasync().map_err(|e| io_error::cond.raise(e));
+    pub fn datasync(&mut self) -> IoResult<()> {
+        self.fd.datasync()
     }
 
     /// Either truncates or extends the underlying file, updating the size of
@@ -202,8 +210,8 @@ impl File {
     /// # Errors
     ///
     /// On error, this function will raise on the `io_error` condition.
-    pub fn truncate(&mut self, size: i64) {
-        let _ = self.fd.truncate(size).map_err(|e| io_error::cond.raise(e));
+    pub fn truncate(&mut self, size: i64) -> IoResult<()> {
+        self.fd.truncate(size)
     }
 
     /// Tests whether this stream has reached EOF.
@@ -219,12 +227,13 @@ impl File {
 ///
 /// # Example
 ///
-///     use std::io::fs;
+/// ```rust
+/// # #[allow(unused_must_use)];
+/// use std::io::fs;
 ///
-///     let p = Path::new("/some/file/path.txt");
-///     fs::unlink(&p);
-///     // if we made it here without failing, then the
-///     // unlink operation was successful
+/// let p = Path::new("/some/file/path.txt");
+/// fs::unlink(&p);
+/// ```
 ///
 /// Note that, just because an unlink call was successful, it is not
 /// guaranteed that a file is immediately deleted (e.g. depending on
@@ -235,8 +244,8 @@ impl File {
 /// This function will raise an `io_error` condition if the path points to a
 /// directory, the user lacks permissions to remove the file, or if some
 /// other filesystem-level error occurs.
-pub fn unlink(path: &Path) {
-    LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str()));
+pub fn unlink(path: &Path) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str()))
 }
 
 /// Given a path, query the file system to get information about a file,
@@ -249,48 +258,26 @@ pub fn unlink(path: &Path) {
 ///
 /// # Example
 ///
-///     use std::io;
-///     use std::io::fs;
+/// ```rust
+/// use std::io;
+/// use std::io::fs;
 ///
-///     let p = Path::new("/some/file/path.txt");
-///     match io::result(|| fs::stat(&p)) {
-///         Ok(stat) => { /* ... */ }
-///         Err(e) => { /* handle error */ }
-///     }
+/// let p = Path::new("/some/file/path.txt");
+/// match fs::stat(&p) {
+///     Ok(stat) => { /* ... */ }
+///     Err(e) => { /* handle error */ }
+/// }
+/// ```
 ///
 /// # Errors
 ///
 /// This call will raise an `io_error` condition if the user lacks the
 /// requisite permissions to perform a `stat` call on the given path or if
 /// there is no entry in the filesystem at the provided path.
-pub fn stat(path: &Path) -> FileStat {
+pub fn stat(path: &Path) -> IoResult<FileStat> {
     LocalIo::maybe_raise(|io| {
         io.fs_stat(&path.to_c_str())
-    }).unwrap_or_else(dummystat)
-}
-
-fn dummystat() -> FileStat {
-    FileStat {
-        path: Path::new(""),
-        size: 0,
-        kind: io::TypeFile,
-        perm: 0,
-        created: 0,
-        modified: 0,
-        accessed: 0,
-        unstable: io::UnstableFileStat {
-            device: 0,
-            inode: 0,
-            rdev: 0,
-            nlink: 0,
-            uid: 0,
-            gid: 0,
-            blksize: 0,
-            blocks: 0,
-            flags: 0,
-            gen: 0,
-        }
-    }
+    })
 }
 
 /// Perform the same operation as the `stat` function, except that this
@@ -301,28 +288,30 @@ fn dummystat() -> FileStat {
 /// # Errors
 ///
 /// See `stat`
-pub fn lstat(path: &Path) -> FileStat {
+pub fn lstat(path: &Path) -> IoResult<FileStat> {
     LocalIo::maybe_raise(|io| {
         io.fs_lstat(&path.to_c_str())
-    }).unwrap_or_else(dummystat)
+    })
 }
 
 /// Rename a file or directory to a new name.
 ///
 /// # Example
 ///
-///     use std::io::fs;
+/// ```rust
+/// # #[allow(unused_must_use)];
+/// use std::io::fs;
 ///
-///     fs::rename(&Path::new("foo"), &Path::new("bar"));
-///     // Oh boy, nothing was raised!
+/// fs::rename(&Path::new("foo"), &Path::new("bar"));
+/// ```
 ///
 /// # Errors
 ///
 /// Will raise an `io_error` condition if the provided `path` doesn't exist,
 /// the process lacks permissions to view the contents, or if some other
 /// intermittent I/O error occurs.
-pub fn rename(from: &Path, to: &Path) {
-    LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str()));
+pub fn rename(from: &Path, to: &Path) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str()))
 }
 
 /// Copies the contents of one file to another. This function will also
@@ -333,10 +322,12 @@ pub fn rename(from: &Path, to: &Path) {
 ///
 /// # Example
 ///
-///     use std::io::fs;
+/// ```rust
+/// # #[allow(unused_must_use)];
+/// use std::io::fs;
 ///
-///     fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt"));
-///     // Oh boy, nothing was raised!
+/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt"));
+/// ```
 ///
 /// # Errors
 ///
@@ -351,27 +342,29 @@ pub fn rename(from: &Path, to: &Path) {
 /// Note that this copy is not atomic in that once the destination is
 /// ensured to not exist, there is nothing preventing the destination from
 /// being created and then destroyed by this operation.
-pub fn copy(from: &Path, to: &Path) {
+pub fn copy(from: &Path, to: &Path) -> IoResult<()> {
     if !from.is_file() {
-        return io_error::cond.raise(IoError {
+        return Err(IoError {
             kind: io::MismatchedFileTypeForOperation,
             desc: "the source path is not an existing file",
             detail: None,
-        });
+        })
     }
 
-    let mut reader = match File::open(from) { Some(f) => f, None => return };
-    let mut writer = match File::create(to) { Some(f) => f, None => return };
+    let mut reader = if_ok!(File::open(from));
+    let mut writer = if_ok!(File::create(to));
     let mut buf = [0, ..io::DEFAULT_BUF_SIZE];
 
     loop {
-        match reader.read(buf) {
-            Some(amt) => writer.write(buf.slice_to(amt)),
-            None => break
-        }
+        let amt = match reader.read(buf) {
+            Ok(n) => n,
+            Err(ref e) if e.kind == io::EndOfFile => { break }
+            Err(e) => return Err(e)
+        };
+        if_ok!(writer.write(buf.slice_to(amt)));
     }
 
-    chmod(to, from.stat().perm)
+    chmod(to, if_ok!(from.stat()).perm)
 }
 
 /// Changes the permission mode bits found on a file or a directory. This
@@ -379,21 +372,24 @@ pub fn copy(from: &Path, to: &Path) {
 ///
 /// # Example
 ///
-///     use std::io;
-///     use std::io::fs;
+/// ```rust
+/// # #[allow(unused_must_use)]
+/// use std::io;
+/// use std::io::fs;
 ///
-///     fs::chmod(&Path::new("file.txt"), io::UserFile);
-///     fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite);
-///     fs::chmod(&Path::new("dir"),      io::UserDir);
-///     fs::chmod(&Path::new("file.exe"), io::UserExec);
+/// fs::chmod(&Path::new("file.txt"), io::UserFile);
+/// fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite);
+/// fs::chmod(&Path::new("dir"),      io::UserDir);
+/// fs::chmod(&Path::new("file.exe"), io::UserExec);
+/// ```
 ///
 /// # Errors
 ///
 /// If this function encounters an I/O error, it will raise on the `io_error`
 /// condition. Some possible error situations are not having the permission to
 /// change the attributes of a file or the file not existing.
-pub fn chmod(path: &Path, mode: io::FilePermission) {
-    LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode));
+pub fn chmod(path: &Path, mode: io::FilePermission) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode))
 }
 
 /// Change the user and group owners of a file at the specified path.
@@ -401,8 +397,8 @@ pub fn chmod(path: &Path, mode: io::FilePermission) {
 /// # Errors
 ///
 /// This function will raise on the `io_error` condition on failure.
-pub fn chown(path: &Path, uid: int, gid: int) {
-    LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid));
+pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid))
 }
 
 /// Creates a new hard link on the filesystem. The `dst` path will be a
@@ -412,8 +408,8 @@ pub fn chown(path: &Path, uid: int, gid: int) {
 /// # Errors
 ///
 /// This function will raise on the `io_error` condition on failure.
-pub fn link(src: &Path, dst: &Path) {
-    LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str()));
+pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str()))
 }
 
 /// Creates a new symbolic link on the filesystem. The `dst` path will be a
@@ -422,8 +418,8 @@ pub fn link(src: &Path, dst: &Path) {
 /// # Errors
 ///
 /// This function will raise on the `io_error` condition on failure.
-pub fn symlink(src: &Path, dst: &Path) {
-    LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str()));
+pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str()))
 }
 
 /// Reads a symlink, returning the file that the symlink points to.
@@ -433,7 +429,7 @@ pub fn symlink(src: &Path, dst: &Path) {
 /// This function will raise on the `io_error` condition on failure. Failure
 /// conditions include reading a file that does not exist or reading a file
 /// which is not a symlink.
-pub fn readlink(path: &Path) -> Option<Path> {
+pub fn readlink(path: &Path) -> IoResult<Path> {
     LocalIo::maybe_raise(|io| io.fs_readlink(&path.to_c_str()))
 }
 
@@ -441,75 +437,81 @@ pub fn readlink(path: &Path) -> Option<Path> {
 ///
 /// # Example
 ///
-///     use std::libc::S_IRWXU;
-///     use std::io::fs;
+/// ```rust
+/// # #[allow(unused_must_use)];
+/// use std::io;
+/// use std::io::fs;
 ///
-///     let p = Path::new("/some/dir");
-///     fs::mkdir(&p, S_IRWXU as int);
-///     // If we got here, our directory exists! Hooray!
+/// let p = Path::new("/some/dir");
+/// fs::mkdir(&p, io::UserRWX);
+/// ```
 ///
 /// # Errors
 ///
 /// This call will raise an `io_error` condition if the user lacks permissions
 /// to make a new directory at the provided path, or if the directory already
 /// exists.
-pub fn mkdir(path: &Path, mode: FilePermission) {
-    LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode));
+pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode))
 }
 
 /// Remove an existing, empty directory
 ///
 /// # Example
 ///
-///     use std::io::fs;
+/// ```rust
+/// # #[allow(unused_must_use)];
+/// use std::io::fs;
 ///
-///     let p = Path::new("/some/dir");
-///     fs::rmdir(&p);
-///     // good riddance, you mean ol' directory
+/// let p = Path::new("/some/dir");
+/// fs::rmdir(&p);
+/// ```
 ///
 /// # Errors
 ///
 /// This call will raise an `io_error` condition if the user lacks permissions
 /// to remove the directory at the provided path, or if the directory isn't
 /// empty.
-pub fn rmdir(path: &Path) {
-    LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str()));
+pub fn rmdir(path: &Path) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str()))
 }
 
 /// Retrieve a vector containing all entries within a provided directory
 ///
 /// # Example
 ///
-///     use std::io::fs;
+/// ```rust
+/// use std::io::fs;
 ///
-///     // one possible implementation of fs::walk_dir only visiting files
-///     fn visit_dirs(dir: &Path, cb: |&Path|) {
-///         if dir.is_dir() {
-///             let contents = fs::readdir(dir).unwrap();
-///             for entry in contents.iter() {
-///                 if entry.is_dir() { visit_dirs(entry, cb); }
-///                 else { cb(entry); }
-///             }
+/// // one possible implementation of fs::walk_dir only visiting files
+/// fn visit_dirs(dir: &Path, cb: |&Path|) {
+///     if dir.is_dir() {
+///         let contents = fs::readdir(dir).unwrap();
+///         for entry in contents.iter() {
+///             if entry.is_dir() { visit_dirs(entry, cb); }
+///             else { cb(entry); }
 ///         }
-///         else { fail!("nope"); }
 ///     }
+///     else { fail!("nope"); }
+/// }
+/// ```
 ///
 /// # Errors
 ///
 /// Will raise an `io_error` condition if the provided `from` doesn't exist,
 /// the process lacks permissions to view the contents or if the `path` points
 /// at a non-directory file
-pub fn readdir(path: &Path) -> ~[Path] {
+pub fn readdir(path: &Path) -> IoResult<~[Path]> {
     LocalIo::maybe_raise(|io| {
         io.fs_readdir(&path.to_c_str(), 0)
-    }).unwrap_or_else(|| ~[])
+    })
 }
 
 /// Returns an iterator which will recursively walk the directory structure
 /// rooted at `path`. The path given will not be iterated over, and this will
 /// perform iteration in a top-down order.
-pub fn walk_dir(path: &Path) -> Directories {
-    Directories { stack: readdir(path) }
+pub fn walk_dir(path: &Path) -> IoResult<Directories> {
+    Ok(Directories { stack: if_ok!(readdir(path)) })
 }
 
 /// An iterator which walks over a directory
@@ -522,7 +524,10 @@ impl Iterator<Path> for Directories {
         match self.stack.shift() {
             Some(path) => {
                 if path.is_dir() {
-                    self.stack.push_all_move(readdir(&path));
+                    match readdir(&path) {
+                        Ok(dirs) => { self.stack.push_all_move(dirs); }
+                        Err(..) => {}
+                    }
                 }
                 Some(path)
             }
@@ -539,14 +544,14 @@ impl Iterator<Path> for Directories {
 /// This function will raise on the `io_error` condition if an error
 /// happens, see `fs::mkdir` for more information about error conditions
 /// and performance.
-pub fn mkdir_recursive(path: &Path, mode: FilePermission) {
+pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> {
     // tjc: if directory exists but with different permissions,
     // should we return false?
     if path.is_dir() {
-        return
+        return Ok(())
     }
     if path.filename().is_some() {
-        mkdir_recursive(&path.dir_path(), mode);
+        if_ok!(mkdir_recursive(&path.dir_path(), mode));
     }
     mkdir(path, mode)
 }
@@ -559,17 +564,17 @@ pub fn mkdir_recursive(path: &Path, mode: FilePermission) {
 /// This function will raise on the `io_error` condition if an error
 /// happens. See `file::unlink` and `fs::readdir` for possible error
 /// conditions.
-pub fn rmdir_recursive(path: &Path) {
-    let children = readdir(path);
+pub fn rmdir_recursive(path: &Path) -> IoResult<()> {
+    let children = if_ok!(readdir(path));
     for child in children.iter() {
         if child.is_dir() {
-            rmdir_recursive(child);
+            if_ok!(rmdir_recursive(child));
         } else {
-            unlink(child);
+            if_ok!(unlink(child));
         }
     }
     // Directory should now be empty
-    rmdir(path);
+    rmdir(path)
 }
 
 /// Changes the timestamps for a file's last modification and access time.
@@ -582,64 +587,42 @@ pub fn rmdir_recursive(path: &Path) {
 /// This function will raise on the `io_error` condition if an error
 /// happens.
 // FIXME(#10301) these arguments should not be u64
-pub fn change_file_times(path: &Path, atime: u64, mtime: u64) {
-    LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime));
+pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> {
+    LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime))
 }
 
 impl Reader for File {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         match self.fd.read(buf) {
             Ok(read) => {
                 self.last_nread = read;
                 match read {
-                    0 => None,
-                    _ => Some(read as uint)
+                    0 => Err(io::standard_error(io::EndOfFile)),
+                    _ => Ok(read as uint)
                 }
             },
-            Err(ioerr) => {
-                // EOF is indicated by returning None
-                if ioerr.kind != io::EndOfFile {
-                    io_error::cond.raise(ioerr);
-                }
-                return None;
-            }
+            Err(e) => Err(e),
         }
     }
 }
 
 impl Writer for File {
-    fn write(&mut self, buf: &[u8]) {
-        match self.fd.write(buf) {
-            Ok(()) => (),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-            }
-        }
-    }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.fd.write(buf) }
 }
 
 impl Seek for File {
-    fn tell(&self) -> u64 {
-        let res = self.fd.tell();
-        match res {
-            Ok(cursor) => cursor,
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                return -1;
-            }
-        }
+    fn tell(&self) -> IoResult<u64> {
+        self.fd.tell()
     }
 
-    fn seek(&mut self, pos: i64, style: SeekStyle) {
+    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
         match self.fd.seek(pos, style) {
             Ok(_) => {
                 // successful seek resets EOF indicator
                 self.last_nread = -1;
-                ()
-            },
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
+                Ok(())
             }
+            Err(e) => Err(e),
         }
     }
 }
@@ -650,7 +633,7 @@ impl path::Path {
     /// Consult the `file::stat` documentation for more info.
     ///
     /// This call preserves identical runtime/error semantics with `file::stat`.
-    pub fn stat(&self) -> FileStat { stat(self) }
+    pub fn stat(&self) -> IoResult<FileStat> { stat(self) }
 
     /// Boolean value indicator whether the underlying file exists on the local
     /// filesystem. This will return true if the path points to either a
@@ -660,7 +643,7 @@ impl path::Path {
     ///
     /// Will not raise a condition
     pub fn exists(&self) -> bool {
-        io::result(|| self.stat()).is_ok()
+        self.stat().is_ok()
     }
 
     /// Whether the underlying implementation (be it a file path, or something
@@ -672,7 +655,7 @@ impl path::Path {
     ///
     /// Will not raise a condition
     pub fn is_file(&self) -> bool {
-        match io::result(|| self.stat()) {
+        match self.stat() {
             Ok(s) => s.kind == io::TypeFile,
             Err(..) => false
         }
@@ -687,7 +670,7 @@ impl path::Path {
     ///
     /// Will not raise a condition
     pub fn is_dir(&self) -> bool {
-        match io::result(|| self.stat()) {
+        match self.stat() {
             Ok(s) => s.kind == io::TypeDirectory,
             Err(..) => false
         }
diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs
index c185951feca..f3535df5c5e 100644
--- a/src/libstd/io/mem.rs
+++ b/src/libstd/io/mem.rs
@@ -13,9 +13,10 @@
 use cmp::max;
 use cmp::min;
 use container::Container;
-use option::{Option, Some, None};
-use super::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, io_error,
-            OtherIoError};
+use option::None;
+use result::{Err, Ok};
+use io;
+use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult};
 use vec;
 use vec::{Vector, ImmutableVector, MutableVector, OwnedCloneableVector};
 
@@ -59,7 +60,7 @@ impl MemWriter {
 }
 
 impl Writer for MemWriter {
-    fn write(&mut self, buf: &[u8]) {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         // Make sure the internal buffer is as least as big as where we
         // currently are
         let difference = self.pos as i64 - self.buf.len() as i64;
@@ -86,14 +87,15 @@ impl Writer for MemWriter {
 
         // Bump us forward
         self.pos += buf.len();
+        Ok(())
     }
 }
 
 // FIXME(#10432)
 impl Seek for MemWriter {
-    fn tell(&self) -> u64 { self.pos as u64 }
+    fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
 
-    fn seek(&mut self, pos: i64, style: SeekStyle) {
+    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
         // compute offset as signed and clamp to prevent overflow
         let offset = match style {
             SeekSet => { 0 }
@@ -102,6 +104,7 @@ impl Seek for MemWriter {
         } as i64;
 
         self.pos = max(0, offset+pos) as uint;
+        Ok(())
     }
 }
 
@@ -148,8 +151,8 @@ impl MemReader {
 }
 
 impl Reader for MemReader {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        if self.eof() { return None }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        if self.eof() { return Err(io::standard_error(io::EndOfFile)) }
 
         let write_len = min(buf.len(), self.buf.len() - self.pos);
         {
@@ -161,17 +164,19 @@ impl Reader for MemReader {
         self.pos += write_len;
         assert!(self.pos <= self.buf.len());
 
-        return Some(write_len);
+        return Ok(write_len);
     }
 }
 
 impl Seek for MemReader {
-    fn tell(&self) -> u64 { self.pos as u64 }
-    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
+    fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
+    fn seek(&mut self, _pos: i64, _style: SeekStyle) -> IoResult<()> { fail!() }
 }
 
 impl Buffer for MemReader {
-    fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) }
+    fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> {
+        Ok(self.buf.slice_from(self.pos))
+    }
     fn consume(&mut self, amt: uint) { self.pos += amt; }
 }
 
@@ -207,28 +212,28 @@ impl<'a> BufWriter<'a> {
 }
 
 impl<'a> Writer for BufWriter<'a> {
-    fn write(&mut self, buf: &[u8]) {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         // raises a condition if the entire write does not fit in the buffer
         let max_size = self.buf.len();
         if self.pos >= max_size || (self.pos + buf.len()) > max_size {
-            io_error::cond.raise(IoError {
-                kind: OtherIoError,
+            return Err(IoError {
+                kind: io::OtherIoError,
                 desc: "Trying to write past end of buffer",
                 detail: None
-            });
-            return;
+            })
         }
 
         vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos), buf);
         self.pos += buf.len();
+        Ok(())
     }
 }
 
 // FIXME(#10432)
 impl<'a> Seek for BufWriter<'a> {
-    fn tell(&self) -> u64 { self.pos as u64 }
+    fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
 
-    fn seek(&mut self, pos: i64, style: SeekStyle) {
+    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
         // compute offset as signed and clamp to prevent overflow
         let offset = match style {
             SeekSet => { 0 }
@@ -237,6 +242,7 @@ impl<'a> Seek for BufWriter<'a> {
         } as i64;
 
         self.pos = max(0, offset+pos) as uint;
+        Ok(())
     }
 }
 
@@ -274,8 +280,8 @@ impl<'a> BufReader<'a> {
 }
 
 impl<'a> Reader for BufReader<'a> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        if self.eof() { return None }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        if self.eof() { return Err(io::standard_error(io::EndOfFile)) }
 
         let write_len = min(buf.len(), self.buf.len() - self.pos);
         {
@@ -287,18 +293,19 @@ impl<'a> Reader for BufReader<'a> {
         self.pos += write_len;
         assert!(self.pos <= self.buf.len());
 
-        return Some(write_len);
+        return Ok(write_len);
      }
 }
 
 impl<'a> Seek for BufReader<'a> {
-    fn tell(&self) -> u64 { self.pos as u64 }
-
-    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
+    fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
+    fn seek(&mut self, _pos: i64, _style: SeekStyle) -> IoResult<()> { fail!() }
 }
 
 impl<'a> Buffer for BufReader<'a> {
-    fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) }
+    fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> {
+        Ok(self.buf.slice_from(self.pos))
+    }
     fn consume(&mut self, amt: uint) { self.pos += amt; }
 }
 
@@ -388,7 +395,7 @@ mod test {
 
         let mut called = false;
         io_error::cond.trap(|err| {
-            assert_eq!(err.kind, OtherIoError);
+            assert_eq!(err.kind, io::OtherIoError);
             called = true;
         }).inside(|| {
             writer.write([0, 0]);
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 69f0cf96ffc..1cf137279c4 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -290,15 +290,15 @@ Out of scope
 
 use cast;
 use char::Char;
-use condition::Guard;
 use container::Container;
+use fmt;
 use int;
 use iter::Iterator;
 use option::{Option, Some, None};
 use path::Path;
 use result::{Ok, Err, Result};
-use str;
 use str::{StrSlice, OwnedStr};
+use str;
 use to_str::ToStr;
 use uint;
 use unstable::finally::Finally;
@@ -347,8 +347,8 @@ mod mem;
 /// Non-blocking access to stdin, stdout, stderr
 pub mod stdio;
 
-/// Implementations for Option
-mod option;
+/// Implementations for Result
+mod result;
 
 /// Extension traits
 pub mod extensions;
@@ -373,17 +373,30 @@ mod comm_adapters;
 // https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
 static DEFAULT_BUF_SIZE: uint = 1024 * 64;
 
+pub type IoResult<T> = Result<T, IoError>;
+
 /// The type passed to I/O condition handlers to indicate error
 ///
 /// # FIXME
 ///
 /// Is something like this sufficient? It's kind of archaic
+#[deriving(Eq, Clone)]
 pub struct IoError {
     kind: IoErrorKind,
     desc: &'static str,
     detail: Option<~str>
 }
 
+impl fmt::Default for IoError {
+    fn fmt(err: &IoError, fmt: &mut fmt::Formatter) -> fmt::Result {
+        if_ok!(fmt.buf.write_str(err.desc));
+        match err.detail {
+            Some(ref s) => write!(fmt.buf, " ({})", *s),
+            None => Ok(())
+        }
+    }
+}
+
 // FIXME: #8242 implementing manually because deriving doesn't work for some reason
 impl ToStr for IoError {
     fn to_str(&self) -> ~str {
@@ -398,9 +411,8 @@ impl ToStr for IoError {
     }
 }
 
-#[deriving(Eq)]
+#[deriving(Eq, Clone)]
 pub enum IoErrorKind {
-    PreviousIoError,
     OtherIoError,
     EndOfFile,
     FileNotFound,
@@ -424,7 +436,6 @@ pub enum IoErrorKind {
 impl ToStr for IoErrorKind {
     fn to_str(&self) -> ~str {
         match *self {
-            PreviousIoError => ~"PreviousIoError",
             OtherIoError => ~"OtherIoError",
             EndOfFile => ~"EndOfFile",
             FileNotFound => ~"FileNotFound",
@@ -446,38 +457,6 @@ impl ToStr for IoErrorKind {
     }
 }
 
-// FIXME: Can't put doc comments on macros
-// Raised by `I/O` operations on error.
-condition! {
-    pub io_error: IoError -> ();
-}
-
-/// Helper for wrapper calls where you want to
-/// ignore any io_errors that might be raised
-pub fn ignore_io_error() -> Guard<'static,IoError,()> {
-    io_error::cond.trap(|_| {
-        // just swallow the error.. downstream users
-        // who can make a decision based on a None result
-        // won't care
-    }).guard()
-}
-
-/// Helper for catching an I/O error and wrapping it in a Result object. The
-/// return result will be the last I/O error that happened or the result of the
-/// closure if no error occurred.
-pub fn result<T>(cb: || -> T) -> Result<T, IoError> {
-    let mut err = None;
-    let ret = io_error::cond.trap(|e| {
-        if err.is_none() {
-            err = Some(e);
-        }
-    }).inside(cb);
-    match err {
-        Some(e) => Err(e),
-        None => Ok(ret),
-    }
-}
-
 pub trait Reader {
 
     // Only two methods which need to get implemented for this trait
@@ -504,7 +483,7 @@ pub trait Reader {
     /// Will people often need to slice their vectors to call this
     /// and will that be annoying?
     /// Is it actually possible for 0 bytes to be read successfully?
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint>;
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>;
 
     // Convenient helper methods based on the above methods
 
@@ -514,16 +493,17 @@ pub trait Reader {
     ///
     /// Raises the same conditions as the `read` method. Returns
     /// `None` if the condition is handled.
-    fn read_byte(&mut self) -> Option<u8> {
+    fn read_byte(&mut self) -> IoResult<u8> {
         let mut buf = [0];
-        match self.read(buf) {
-            Some(0) => {
-                debug!("read 0 bytes. trying again");
-                self.read_byte()
+        loop {
+            match self.read(buf) {
+                Ok(0) => {
+                    debug!("read 0 bytes. trying again");
+                }
+                Ok(1) => return Ok(buf[0]),
+                Ok(_) => unreachable!(),
+                Err(e) => return Err(e)
             }
-            Some(1) => Some(buf[0]),
-            Some(_) => unreachable!(),
-            None => None
         }
     }
 
@@ -537,30 +517,26 @@ pub trait Reader {
     /// Raises the same conditions as `read`. Additionally raises `io_error`
     /// on EOF. If `io_error` is handled then `push_bytes` may push less
     /// than the requested number of bytes.
-    fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) {
-        unsafe {
-            let start_len = buf.len();
-            let mut total_read = 0;
-
-            buf.reserve_additional(len);
-            buf.set_len(start_len + len);
-
-            (|| {
-                while total_read < len {
-                    let len = buf.len();
-                    let slice = buf.mut_slice(start_len + total_read, len);
-                    match self.read(slice) {
-                        Some(nread) => {
-                            total_read += nread;
-                        }
-                        None => {
-                            io_error::cond.raise(standard_error(EndOfFile));
-                            break;
-                        }
+    fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) -> IoResult<()> {
+        let start_len = buf.len();
+        let mut total_read = 0;
+
+        buf.reserve_additional(len);
+        unsafe { buf.set_len(start_len + len); }
+
+        (|| {
+            while total_read < len {
+                let len = buf.len();
+                let slice = buf.mut_slice(start_len + total_read, len);
+                match self.read(slice) {
+                    Ok(nread) => {
+                        total_read += nread;
                     }
+                    Err(e) => return Err(e)
                 }
-            }).finally(|| buf.set_len(start_len + total_read))
-        }
+            }
+            Ok(())
+        }).finally(|| unsafe { buf.set_len(start_len + total_read) })
     }
 
     /// Reads `len` bytes and gives you back a new vector of length `len`
@@ -570,10 +546,10 @@ pub trait Reader {
     /// Raises the same conditions as `read`. Additionally raises `io_error`
     /// on EOF. If `io_error` is handled then the returned vector may
     /// contain less than the requested number of bytes.
-    fn read_bytes(&mut self, len: uint) -> ~[u8] {
+    fn read_bytes(&mut self, len: uint) -> IoResult<~[u8]> {
         let mut buf = vec::with_capacity(len);
-        self.push_bytes(&mut buf, len);
-        return buf;
+        if_ok!(self.push_bytes(&mut buf, len));
+        return Ok(buf);
     }
 
     /// Reads all remaining bytes from the stream.
@@ -582,21 +558,16 @@ pub trait Reader {
     ///
     /// Raises the same conditions as the `read` method except for
     /// `EndOfFile` which is swallowed.
-    fn read_to_end(&mut self) -> ~[u8] {
+    fn read_to_end(&mut self) -> IoResult<~[u8]> {
         let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE);
-        let mut keep_reading = true;
-        io_error::cond.trap(|e| {
-            if e.kind == EndOfFile {
-                keep_reading = false;
-            } else {
-                io_error::cond.raise(e)
+        loop {
+            match self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) {
+                Ok(()) => {}
+                Err(ref e) if e.kind == EndOfFile => break,
+                Err(e) => return Err(e)
             }
-        }).inside(|| {
-            while keep_reading {
-                self.push_bytes(&mut buf, DEFAULT_BUF_SIZE)
-            }
-        });
-        return buf;
+        }
+        return Ok(buf);
     }
 
     /// Reads all of the remaining bytes of this stream, interpreting them as a
@@ -606,14 +577,13 @@ pub trait Reader {
     ///
     /// This function will raise all the same conditions as the `read` method,
     /// along with raising a condition if the input is not valid UTF-8.
-    fn read_to_str(&mut self) -> ~str {
-        match str::from_utf8_owned(self.read_to_end()) {
-            Some(s) => s,
-            None => {
-                io_error::cond.raise(standard_error(InvalidInput));
-                ~""
+    fn read_to_str(&mut self) -> IoResult<~str> {
+        self.read_to_end().and_then(|s| {
+            match str::from_utf8_owned(s) {
+                Some(s) => Ok(s),
+                None => Err(standard_error(InvalidInput)),
             }
-        }
+        })
     }
 
     /// Create an iterator that reads a single byte on
@@ -633,225 +603,219 @@ pub trait Reader {
     /// Reads `n` little-endian unsigned integer bytes.
     ///
     /// `n` must be between 1 and 8, inclusive.
-    fn read_le_uint_n(&mut self, nbytes: uint) -> u64 {
+    fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult<u64> {
         assert!(nbytes > 0 && nbytes <= 8);
 
         let mut val = 0u64;
         let mut pos = 0;
         let mut i = nbytes;
         while i > 0 {
-            val += (self.read_u8() as u64) << pos;
+            val += (if_ok!(self.read_u8()) as u64) << pos;
             pos += 8;
             i -= 1;
         }
-        val
+        Ok(val)
     }
 
     /// Reads `n` little-endian signed integer bytes.
     ///
     /// `n` must be between 1 and 8, inclusive.
-    fn read_le_int_n(&mut self, nbytes: uint) -> i64 {
-        extend_sign(self.read_le_uint_n(nbytes), nbytes)
+    fn read_le_int_n(&mut self, nbytes: uint) -> IoResult<i64> {
+        self.read_le_uint_n(nbytes).map(|i| extend_sign(i, nbytes))
     }
 
     /// Reads `n` big-endian unsigned integer bytes.
     ///
     /// `n` must be between 1 and 8, inclusive.
-    fn read_be_uint_n(&mut self, nbytes: uint) -> u64 {
+    fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult<u64> {
         assert!(nbytes > 0 && nbytes <= 8);
 
         let mut val = 0u64;
         let mut i = nbytes;
         while i > 0 {
             i -= 1;
-            val += (self.read_u8() as u64) << i * 8;
+            val += (if_ok!(self.read_u8()) as u64) << i * 8;
         }
-        val
+        Ok(val)
     }
 
     /// Reads `n` big-endian signed integer bytes.
     ///
     /// `n` must be between 1 and 8, inclusive.
-    fn read_be_int_n(&mut self, nbytes: uint) -> i64 {
-        extend_sign(self.read_be_uint_n(nbytes), nbytes)
+    fn read_be_int_n(&mut self, nbytes: uint) -> IoResult<i64> {
+        self.read_be_uint_n(nbytes).map(|i| extend_sign(i, nbytes))
     }
 
     /// Reads a little-endian unsigned integer.
     ///
     /// The number of bytes returned is system-dependant.
-    fn read_le_uint(&mut self) -> uint {
-        self.read_le_uint_n(uint::BYTES) as uint
+    fn read_le_uint(&mut self) -> IoResult<uint> {
+        self.read_le_uint_n(uint::BYTES).map(|i| i as uint)
     }
 
     /// Reads a little-endian integer.
     ///
     /// The number of bytes returned is system-dependant.
-    fn read_le_int(&mut self) -> int {
-        self.read_le_int_n(int::BYTES) as int
+    fn read_le_int(&mut self) -> IoResult<int> {
+        self.read_le_int_n(int::BYTES).map(|i| i as int)
     }
 
     /// Reads a big-endian unsigned integer.
     ///
     /// The number of bytes returned is system-dependant.
-    fn read_be_uint(&mut self) -> uint {
-        self.read_be_uint_n(uint::BYTES) as uint
+    fn read_be_uint(&mut self) -> IoResult<uint> {
+        self.read_be_uint_n(uint::BYTES).map(|i| i as uint)
     }
 
     /// Reads a big-endian integer.
     ///
     /// The number of bytes returned is system-dependant.
-    fn read_be_int(&mut self) -> int {
-        self.read_be_int_n(int::BYTES) as int
+    fn read_be_int(&mut self) -> IoResult<int> {
+        self.read_be_int_n(int::BYTES).map(|i| i as int)
     }
 
     /// Reads a big-endian `u64`.
     ///
     /// `u64`s are 8 bytes long.
-    fn read_be_u64(&mut self) -> u64 {
+    fn read_be_u64(&mut self) -> IoResult<u64> {
         self.read_be_uint_n(8)
     }
 
     /// Reads a big-endian `u32`.
     ///
     /// `u32`s are 4 bytes long.
-    fn read_be_u32(&mut self) -> u32 {
-        self.read_be_uint_n(4) as u32
+    fn read_be_u32(&mut self) -> IoResult<u32> {
+        self.read_be_uint_n(4).map(|i| i as u32)
     }
 
     /// Reads a big-endian `u16`.
     ///
     /// `u16`s are 2 bytes long.
-    fn read_be_u16(&mut self) -> u16 {
-        self.read_be_uint_n(2) as u16
+    fn read_be_u16(&mut self) -> IoResult<u16> {
+        self.read_be_uint_n(2).map(|i| i as u16)
     }
 
     /// Reads a big-endian `i64`.
     ///
     /// `i64`s are 8 bytes long.
-    fn read_be_i64(&mut self) -> i64 {
+    fn read_be_i64(&mut self) -> IoResult<i64> {
         self.read_be_int_n(8)
     }
 
     /// Reads a big-endian `i32`.
     ///
     /// `i32`s are 4 bytes long.
-    fn read_be_i32(&mut self) -> i32 {
-        self.read_be_int_n(4) as i32
+    fn read_be_i32(&mut self) -> IoResult<i32> {
+        self.read_be_int_n(4).map(|i| i as i32)
     }
 
     /// Reads a big-endian `i16`.
     ///
     /// `i16`s are 2 bytes long.
-    fn read_be_i16(&mut self) -> i16 {
-        self.read_be_int_n(2) as i16
+    fn read_be_i16(&mut self) -> IoResult<i16> {
+        self.read_be_int_n(2).map(|i| i as i16)
     }
 
     /// Reads a big-endian `f64`.
     ///
     /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
-    fn read_be_f64(&mut self) -> f64 {
-        unsafe {
-            cast::transmute::<u64, f64>(self.read_be_u64())
-        }
+    fn read_be_f64(&mut self) -> IoResult<f64> {
+        self.read_be_u64().map(|i| unsafe {
+            cast::transmute::<u64, f64>(i)
+        })
     }
 
     /// Reads a big-endian `f32`.
     ///
     /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
-    fn read_be_f32(&mut self) -> f32 {
-        unsafe {
-            cast::transmute::<u32, f32>(self.read_be_u32())
-        }
+    fn read_be_f32(&mut self) -> IoResult<f32> {
+        self.read_be_u32().map(|i| unsafe {
+            cast::transmute::<u32, f32>(i)
+        })
     }
 
     /// Reads a little-endian `u64`.
     ///
     /// `u64`s are 8 bytes long.
-    fn read_le_u64(&mut self) -> u64 {
+    fn read_le_u64(&mut self) -> IoResult<u64> {
         self.read_le_uint_n(8)
     }
 
     /// Reads a little-endian `u32`.
     ///
     /// `u32`s are 4 bytes long.
-    fn read_le_u32(&mut self) -> u32 {
-        self.read_le_uint_n(4) as u32
+    fn read_le_u32(&mut self) -> IoResult<u32> {
+        self.read_le_uint_n(4).map(|i| i as u32)
     }
 
     /// Reads a little-endian `u16`.
     ///
     /// `u16`s are 2 bytes long.
-    fn read_le_u16(&mut self) -> u16 {
-        self.read_le_uint_n(2) as u16
+    fn read_le_u16(&mut self) -> IoResult<u16> {
+        self.read_le_uint_n(2).map(|i| i as u16)
     }
 
     /// Reads a little-endian `i64`.
     ///
     /// `i64`s are 8 bytes long.
-    fn read_le_i64(&mut self) -> i64 {
+    fn read_le_i64(&mut self) -> IoResult<i64> {
         self.read_le_int_n(8)
     }
 
     /// Reads a little-endian `i32`.
     ///
     /// `i32`s are 4 bytes long.
-    fn read_le_i32(&mut self) -> i32 {
-        self.read_le_int_n(4) as i32
+    fn read_le_i32(&mut self) -> IoResult<i32> {
+        self.read_le_int_n(4).map(|i| i as i32)
     }
 
     /// Reads a little-endian `i16`.
     ///
     /// `i16`s are 2 bytes long.
-    fn read_le_i16(&mut self) -> i16 {
-        self.read_le_int_n(2) as i16
+    fn read_le_i16(&mut self) -> IoResult<i16> {
+        self.read_le_int_n(2).map(|i| i as i16)
     }
 
     /// Reads a little-endian `f64`.
     ///
     /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
-    fn read_le_f64(&mut self) -> f64 {
-        unsafe {
-            cast::transmute::<u64, f64>(self.read_le_u64())
-        }
+    fn read_le_f64(&mut self) -> IoResult<f64> {
+        self.read_le_u64().map(|i| unsafe {
+            cast::transmute::<u64, f64>(i)
+        })
     }
 
     /// Reads a little-endian `f32`.
     ///
     /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
-    fn read_le_f32(&mut self) -> f32 {
-        unsafe {
-            cast::transmute::<u32, f32>(self.read_le_u32())
-        }
+    fn read_le_f32(&mut self) -> IoResult<f32> {
+        self.read_le_u32().map(|i| unsafe {
+            cast::transmute::<u32, f32>(i)
+        })
     }
 
     /// Read a u8.
     ///
     /// `u8`s are 1 byte.
-    fn read_u8(&mut self) -> u8 {
-        match self.read_byte() {
-            Some(b) => b,
-            None => 0
-        }
+    fn read_u8(&mut self) -> IoResult<u8> {
+        self.read_byte()
     }
 
     /// Read an i8.
     ///
     /// `i8`s are 1 byte.
-    fn read_i8(&mut self) -> i8 {
-        match self.read_byte() {
-            Some(b) => b as i8,
-            None => 0
-        }
+    fn read_i8(&mut self) -> IoResult<i8> {
+        self.read_byte().map(|i| i as i8)
     }
 
 }
 
 impl Reader for ~Reader {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
 }
 
 impl<'a> Reader for &'a mut Reader {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
 }
 
 fn extend_sign(val: u64, nbytes: uint) -> i64 {
@@ -865,14 +829,14 @@ pub trait Writer {
     /// # Failure
     ///
     /// Raises the `io_error` condition on error
-    fn write(&mut self, buf: &[u8]);
+    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
 
     /// Flush this output stream, ensuring that all intermediately buffered
     /// contents reach their destination.
     ///
     /// This is by default a no-op and implementers of the `Writer` trait should
     /// decide whether their stream needs to be buffered or not.
-    fn flush(&mut self) {}
+    fn flush(&mut self) -> IoResult<()> { Ok(()) }
 
     /// Write a rust string into this sink.
     ///
@@ -880,8 +844,8 @@ pub trait Writer {
     /// If other encodings are desired, it is recommended to compose this stream
     /// with another performing the conversion, or to use `write` with a
     /// converted byte-array instead.
-    fn write_str(&mut self, s: &str) {
-        self.write(s.as_bytes());
+    fn write_str(&mut self, s: &str) -> IoResult<()> {
+        self.write(s.as_bytes())
     }
 
     /// Writes a string into this sink, and then writes a literal newline (`\n`)
@@ -891,125 +855,124 @@ pub trait Writer {
     ///
     /// If other encodings or line ending flavors are desired, it is recommended
     /// that the `write` method is used specifically instead.
-    fn write_line(&mut self, s: &str) {
-        self.write_str(s);
-        self.write(['\n' as u8]);
+    fn write_line(&mut self, s: &str) -> IoResult<()> {
+        self.write_str(s).and_then(|()| self.write(['\n' as u8]))
     }
 
     /// Write a single char, encoded as UTF-8.
-    fn write_char(&mut self, c: char) {
+    fn write_char(&mut self, c: char) -> IoResult<()> {
         let mut buf = [0u8, ..4];
         let n = c.encode_utf8(buf.as_mut_slice());
-        self.write(buf.slice_to(n));
+        self.write(buf.slice_to(n))
     }
 
     /// Write the result of passing n through `int::to_str_bytes`.
-    fn write_int(&mut self, n: int) {
+    fn write_int(&mut self, n: int) -> IoResult<()> {
         int::to_str_bytes(n, 10u, |bytes| self.write(bytes))
     }
 
     /// Write the result of passing n through `uint::to_str_bytes`.
-    fn write_uint(&mut self, n: uint) {
+    fn write_uint(&mut self, n: uint) -> IoResult<()> {
         uint::to_str_bytes(n, 10u, |bytes| self.write(bytes))
     }
 
     /// Write a little-endian uint (number of bytes depends on system).
-    fn write_le_uint(&mut self, n: uint) {
+    fn write_le_uint(&mut self, n: uint) -> IoResult<()> {
         extensions::u64_to_le_bytes(n as u64, uint::BYTES, |v| self.write(v))
     }
 
     /// Write a little-endian int (number of bytes depends on system).
-    fn write_le_int(&mut self, n: int) {
+    fn write_le_int(&mut self, n: int) -> IoResult<()> {
         extensions::u64_to_le_bytes(n as u64, int::BYTES, |v| self.write(v))
     }
 
     /// Write a big-endian uint (number of bytes depends on system).
-    fn write_be_uint(&mut self, n: uint) {
+    fn write_be_uint(&mut self, n: uint) -> IoResult<()> {
         extensions::u64_to_be_bytes(n as u64, uint::BYTES, |v| self.write(v))
     }
 
     /// Write a big-endian int (number of bytes depends on system).
-    fn write_be_int(&mut self, n: int) {
+    fn write_be_int(&mut self, n: int) -> IoResult<()> {
         extensions::u64_to_be_bytes(n as u64, int::BYTES, |v| self.write(v))
     }
 
     /// Write a big-endian u64 (8 bytes).
-    fn write_be_u64(&mut self, n: u64) {
+    fn write_be_u64(&mut self, n: u64) -> IoResult<()> {
         extensions::u64_to_be_bytes(n, 8u, |v| self.write(v))
     }
 
     /// Write a big-endian u32 (4 bytes).
-    fn write_be_u32(&mut self, n: u32) {
+    fn write_be_u32(&mut self, n: u32) -> IoResult<()> {
         extensions::u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
     }
 
     /// Write a big-endian u16 (2 bytes).
-    fn write_be_u16(&mut self, n: u16) {
+    fn write_be_u16(&mut self, n: u16) -> IoResult<()> {
         extensions::u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
     }
 
     /// Write a big-endian i64 (8 bytes).
-    fn write_be_i64(&mut self, n: i64) {
+    fn write_be_i64(&mut self, n: i64) -> IoResult<()> {
         extensions::u64_to_be_bytes(n as u64, 8u, |v| self.write(v))
     }
 
     /// Write a big-endian i32 (4 bytes).
-    fn write_be_i32(&mut self, n: i32) {
+    fn write_be_i32(&mut self, n: i32) -> IoResult<()> {
         extensions::u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
     }
 
     /// Write a big-endian i16 (2 bytes).
-    fn write_be_i16(&mut self, n: i16) {
+    fn write_be_i16(&mut self, n: i16) -> IoResult<()> {
         extensions::u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
     }
 
     /// Write a big-endian IEEE754 double-precision floating-point (8 bytes).
-    fn write_be_f64(&mut self, f: f64) {
+    fn write_be_f64(&mut self, f: f64) -> IoResult<()> {
         unsafe {
             self.write_be_u64(cast::transmute(f))
         }
     }
 
     /// Write a big-endian IEEE754 single-precision floating-point (4 bytes).
-    fn write_be_f32(&mut self, f: f32) {
+    fn write_be_f32(&mut self, f: f32) -> IoResult<()> {
         unsafe {
             self.write_be_u32(cast::transmute(f))
         }
     }
 
     /// Write a little-endian u64 (8 bytes).
-    fn write_le_u64(&mut self, n: u64) {
+    fn write_le_u64(&mut self, n: u64) -> IoResult<()> {
         extensions::u64_to_le_bytes(n, 8u, |v| self.write(v))
     }
 
     /// Write a little-endian u32 (4 bytes).
-    fn write_le_u32(&mut self, n: u32) {
+    fn write_le_u32(&mut self, n: u32) -> IoResult<()> {
         extensions::u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
     }
 
     /// Write a little-endian u16 (2 bytes).
-    fn write_le_u16(&mut self, n: u16) {
+    fn write_le_u16(&mut self, n: u16) -> IoResult<()> {
         extensions::u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
     }
 
     /// Write a little-endian i64 (8 bytes).
-    fn write_le_i64(&mut self, n: i64) {
+    fn write_le_i64(&mut self, n: i64) -> IoResult<()> {
         extensions::u64_to_le_bytes(n as u64, 8u, |v| self.write(v))
     }
 
     /// Write a little-endian i32 (4 bytes).
-    fn write_le_i32(&mut self, n: i32) {
+    fn write_le_i32(&mut self, n: i32) -> IoResult<()> {
         extensions::u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
     }
 
     /// Write a little-endian i16 (2 bytes).
-    fn write_le_i16(&mut self, n: i16) {
+    fn write_le_i16(&mut self, n: i16) -> IoResult<()> {
         extensions::u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
     }
 
     /// Write a little-endian IEEE754 double-precision floating-point
     /// (8 bytes).
-    fn write_le_f64(&mut self, f: f64) {
+    fn write_le_f64(&mut self, f: f64) -> IoResult<()> {
         unsafe {
             self.write_le_u64(cast::transmute(f))
         }
@@ -1017,31 +980,31 @@ pub trait Writer {
 
     /// Write a little-endian IEEE754 single-precision floating-point
     /// (4 bytes).
-    fn write_le_f32(&mut self, f: f32) {
+    fn write_le_f32(&mut self, f: f32) -> IoResult<()> {
         unsafe {
             self.write_le_u32(cast::transmute(f))
         }
     }
 
     /// Write a u8 (1 byte).
-    fn write_u8(&mut self, n: u8) {
+    fn write_u8(&mut self, n: u8) -> IoResult<()> {
         self.write([n])
     }
 
     /// Write a i8 (1 byte).
-    fn write_i8(&mut self, n: i8) {
+    fn write_i8(&mut self, n: i8) -> IoResult<()> {
         self.write([n as u8])
     }
 }
 
 impl Writer for ~Writer {
-    fn write(&mut self, buf: &[u8]) { self.write(buf) }
-    fn flush(&mut self) { self.flush() }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
+    fn flush(&mut self) -> IoResult<()> { self.flush() }
 }
 
 impl<'a> Writer for &'a mut Writer {
-    fn write(&mut self, buf: &[u8]) { self.write(buf) }
-    fn flush(&mut self) { self.flush() }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
+    fn flush(&mut self) -> IoResult<()> { self.flush() }
 }
 
 pub trait Stream: Reader + Writer { }
@@ -1068,7 +1031,7 @@ pub struct Lines<'r, T> {
 
 impl<'r, T: Buffer> Iterator<~str> for Lines<'r, T> {
     fn next(&mut self) -> Option<~str> {
-        self.buffer.read_line()
+        self.buffer.read_line().ok()
     }
 }
 
@@ -1089,7 +1052,7 @@ pub trait Buffer: Reader {
     ///
     /// This function will raise on the `io_error` condition if a read error is
     /// encountered.
-    fn fill<'a>(&'a mut self) -> &'a [u8];
+    fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]>;
 
     /// Tells this buffer that `amt` bytes have been consumed from the buffer,
     /// so they should no longer be returned in calls to `fill` or `read`.
@@ -1116,7 +1079,7 @@ pub trait Buffer: Reader {
     /// `EndOfFile` which is swallowed) if a read error is encountered.
     /// The task will also fail if sequence of bytes leading up to
     /// the newline character are not valid UTF-8.
-    fn read_line(&mut self) -> Option<~str> {
+    fn read_line(&mut self) -> IoResult<~str> {
         self.read_until('\n' as u8).map(|line| str::from_utf8_owned(line).unwrap())
     }
 
@@ -1140,39 +1103,32 @@ pub trait Buffer: Reader {
     ///
     /// This function will raise on the `io_error` condition if a read error is
     /// encountered, except that `EndOfFile` is swallowed.
-    fn read_until(&mut self, byte: u8) -> Option<~[u8]> {
+    fn read_until(&mut self, byte: u8) -> IoResult<~[u8]> {
         let mut res = ~[];
 
-        io_error::cond.trap(|e| {
-            if e.kind != EndOfFile {
-                io_error::cond.raise(e);
-            }
-        }).inside(|| {
-            let mut used;
-            loop {
-                {
-                    let available = self.fill();
-                    match available.iter().position(|&b| b == byte) {
-                        Some(i) => {
-                            res.push_all(available.slice_to(i + 1));
-                            used = i + 1;
-                            break
-                        }
-                        None => {
-                            res.push_all(available);
-                            used = available.len();
-                        }
+        let mut used;
+        loop {
+            {
+                let available = if_ok!(self.fill());
+                match available.iter().position(|&b| b == byte) {
+                    Some(i) => {
+                        res.push_all(available.slice_to(i + 1));
+                        used = i + 1;
+                        break
+                    }
+                    None => {
+                        res.push_all(available);
+                        used = available.len();
                     }
                 }
-                if used == 0 {
-                    break
-                }
-                self.consume(used);
+            }
+            if used == 0 {
+                break
             }
             self.consume(used);
-        });
-        return if res.len() == 0 {None} else {Some(res)};
-
+        }
+        self.consume(used);
+        Ok(res)
     }
 
     /// Reads the next utf8-encoded character from the underlying stream.
@@ -1184,27 +1140,26 @@ pub trait Buffer: Reader {
     ///
     /// This function will raise on the `io_error` condition if a read error is
     /// encountered.
-    fn read_char(&mut self) -> Option<char> {
+    fn read_char(&mut self) -> IoResult<char> {
         let width = {
-            let available = self.fill();
-            if available.len() == 0 { return None } // read error
+            let available = if_ok!(self.fill());
             str::utf8_char_width(available[0])
         };
-        if width == 0 { return None } // not uf8
+        if width == 0 { return Err(standard_error(InvalidInput)) } // not uf8
         let mut buf = [0, ..4];
         {
             let mut start = 0;
             loop {
-                match self.read(buf.mut_slice(start, width)) {
-                    Some(n) if n == width - start => break,
-                    Some(n) if n < width - start => { start += n; }
-                    Some(..) | None => return None // read error
+                match if_ok!(self.read(buf.mut_slice(start, width))) {
+                    n if n == width - start => break,
+                    n if n < width - start => { start += n; }
+                    _ => return Err(standard_error(InvalidInput)),
                 }
             }
         }
         match str::from_utf8(buf.slice_to(width)) {
-            Some(s) => Some(s.char_at(0)),
-            None => None
+            Some(s) => Ok(s.char_at(0)),
+            None => Err(standard_error(InvalidInput))
         }
     }
 }
@@ -1222,7 +1177,7 @@ pub enum SeekStyle {
 /// * Are `u64` and `i64` the right choices?
 pub trait Seek {
     /// Return position of file cursor in the stream
-    fn tell(&self) -> u64;
+    fn tell(&self) -> IoResult<u64>;
 
     /// Seek to an offset in a stream
     ///
@@ -1231,7 +1186,7 @@ pub trait Seek {
     /// # FIXME
     ///
     /// * What is the behavior when seeking past the end of a stream?
-    fn seek(&mut self, pos: i64, style: SeekStyle);
+    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>;
 }
 
 /// A listener is a value that can consume itself to start listening for connections.
@@ -1243,7 +1198,7 @@ pub trait Listener<T, A: Acceptor<T>> {
     ///
     /// Raises `io_error` condition. If the condition is handled,
     /// then `listen` returns `None`.
-    fn listen(self) -> Option<A>;
+    fn listen(self) -> IoResult<A>;
 }
 
 /// An acceptor is a value that presents incoming connections
@@ -1253,7 +1208,7 @@ pub trait Acceptor<T> {
     /// # Failure
     /// Raise `io_error` condition. If the condition is handled,
     /// then `accept` returns `None`.
-    fn accept(&mut self) -> Option<T>;
+    fn accept(&mut self) -> IoResult<T>;
 
     /// Create an iterator over incoming connection attempts
     fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> {
@@ -1272,15 +1227,14 @@ pub struct IncomingConnections<'a, A> {
     priv inc: &'a mut A,
 }
 
-impl<'a, T, A: Acceptor<T>> Iterator<Option<T>> for IncomingConnections<'a, A> {
-    fn next(&mut self) -> Option<Option<T>> {
+impl<'a, T, A: Acceptor<T>> Iterator<IoResult<T>> for IncomingConnections<'a, A> {
+    fn next(&mut self) -> Option<IoResult<T>> {
         Some(self.inc.accept())
     }
 }
 
 pub fn standard_error(kind: IoErrorKind) -> IoError {
     let desc = match kind {
-        PreviousIoError => "failing due to previous I/O error",
         EndOfFile => "end of file",
         IoUnavailable => "I/O is unavailable",
         InvalidInput => "invalid input",
diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs
index 29bf6261a07..1f8f8beeae3 100644
--- a/src/libstd/io/net/addrinfo.rs
+++ b/src/libstd/io/net/addrinfo.rs
@@ -17,8 +17,9 @@ getaddrinfo()
 
 */
 
-use option::{Option, Some, None};
+use io::IoResult;
 use io::net::ip::{SocketAddr, IpAddr};
+use option::{Option, Some, None};
 use rt::rtio::{IoFactory, LocalIo};
 use vec::ImmutableVector;
 
@@ -73,7 +74,7 @@ pub struct Info {
 /// # Failure
 ///
 /// On failure, this will raise on the `io_error` condition.
-pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
+pub fn get_host_addresses(host: &str) -> IoResult<~[IpAddr]> {
     lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip))
 }
 
@@ -94,7 +95,7 @@ pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
 /// FIXME: this is not public because the `Hint` structure is not ready for public
 ///      consumption just yet.
 fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option<Hint>)
-          -> Option<~[Info]> {
+          -> IoResult<~[Info]> {
     LocalIo::maybe_raise(|io| io.get_host_addresses(hostname, servname, hint))
 }
 
diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs
index 475e3b206f2..cc923d5b736 100644
--- a/src/libstd/io/net/tcp.rs
+++ b/src/libstd/io/net/tcp.rs
@@ -8,11 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use option::{Option, Some, None};
-use result::{Ok, Err};
 use io::net::ip::SocketAddr;
-use io::{Reader, Writer, Listener, Acceptor};
-use io::{io_error, EndOfFile};
+use io::{Reader, Writer, Listener, Acceptor, IoResult};
 use rt::rtio::{IoFactory, LocalIo, RtioSocket, RtioTcpListener};
 use rt::rtio::{RtioTcpAcceptor, RtioTcpStream};
 
@@ -25,57 +22,27 @@ impl TcpStream {
         TcpStream { obj: s }
     }
 
-    pub fn connect(addr: SocketAddr) -> Option<TcpStream> {
+    pub fn connect(addr: SocketAddr) -> IoResult<TcpStream> {
         LocalIo::maybe_raise(|io| {
             io.tcp_connect(addr).map(TcpStream::new)
         })
     }
 
-    pub fn peer_name(&mut self) -> Option<SocketAddr> {
-        match self.obj.peer_name() {
-            Ok(pn) => Some(pn),
-            Err(ioerr) => {
-                debug!("failed to get peer name: {:?}", ioerr);
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+    pub fn peer_name(&mut self) -> IoResult<SocketAddr> {
+        self.obj.peer_name()
     }
 
-    pub fn socket_name(&mut self) -> Option<SocketAddr> {
-        match self.obj.socket_name() {
-            Ok(sn) => Some(sn),
-            Err(ioerr) => {
-                debug!("failed to get socket name: {:?}", ioerr);
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+    pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
+        self.obj.socket_name()
     }
 }
 
 impl Reader for TcpStream {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        match self.obj.read(buf) {
-            Ok(read) => Some(read),
-            Err(ioerr) => {
-                // EOF is indicated by returning None
-                if ioerr.kind != EndOfFile {
-                    io_error::cond.raise(ioerr);
-                }
-                return None;
-            }
-        }
-    }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) }
 }
 
 impl Writer for TcpStream {
-    fn write(&mut self, buf: &[u8]) {
-        match self.obj.write(buf) {
-            Ok(_) => (),
-            Err(ioerr) => io_error::cond.raise(ioerr),
-        }
-    }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) }
 }
 
 pub struct TcpListener {
@@ -83,33 +50,20 @@ pub struct TcpListener {
 }
 
 impl TcpListener {
-    pub fn bind(addr: SocketAddr) -> Option<TcpListener> {
+    pub fn bind(addr: SocketAddr) -> IoResult<TcpListener> {
         LocalIo::maybe_raise(|io| {
             io.tcp_bind(addr).map(|l| TcpListener { obj: l })
         })
     }
 
-    pub fn socket_name(&mut self) -> Option<SocketAddr> {
-        match self.obj.socket_name() {
-            Ok(sn) => Some(sn),
-            Err(ioerr) => {
-                debug!("failed to get socket name: {:?}", ioerr);
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+    pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
+        self.obj.socket_name()
     }
 }
 
 impl Listener<TcpStream, TcpAcceptor> for TcpListener {
-    fn listen(self) -> Option<TcpAcceptor> {
-        match self.obj.listen() {
-            Ok(acceptor) => Some(TcpAcceptor { obj: acceptor }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+    fn listen(self) -> IoResult<TcpAcceptor> {
+        self.obj.listen().map(|acceptor| TcpAcceptor { obj: acceptor })
     }
 }
 
@@ -118,14 +72,8 @@ pub struct TcpAcceptor {
 }
 
 impl Acceptor<TcpStream> for TcpAcceptor {
-    fn accept(&mut self) -> Option<TcpStream> {
-        match self.obj.accept() {
-            Ok(s) => Some(TcpStream::new(s)),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+    fn accept(&mut self) -> IoResult<TcpStream> {
+        self.obj.accept().map(TcpStream::new)
     }
 }
 
diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs
index 1cf30d469f7..abb6bdea75b 100644
--- a/src/libstd/io/net/udp.rs
+++ b/src/libstd/io/net/udp.rs
@@ -8,11 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use option::{Option, Some, None};
 use result::{Ok, Err};
 use io::net::ip::SocketAddr;
-use io::{Reader, Writer};
-use io::{io_error, EndOfFile};
+use io::{Reader, Writer, IoResult};
 use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, LocalIo};
 
 pub struct UdpSocket {
@@ -20,45 +18,26 @@ pub struct UdpSocket {
 }
 
 impl UdpSocket {
-    pub fn bind(addr: SocketAddr) -> Option<UdpSocket> {
+    pub fn bind(addr: SocketAddr) -> IoResult<UdpSocket> {
         LocalIo::maybe_raise(|io| {
             io.udp_bind(addr).map(|s| UdpSocket { obj: s })
         })
     }
 
-    pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, SocketAddr)> {
-        match self.obj.recvfrom(buf) {
-            Ok((nread, src)) => Some((nread, src)),
-            Err(ioerr) => {
-                // EOF is indicated by returning None
-                if ioerr.kind != EndOfFile {
-                    io_error::cond.raise(ioerr);
-                }
-                None
-            }
-        }
+    pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> {
+        self.obj.recvfrom(buf)
     }
 
-    pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) {
-        match self.obj.sendto(buf, dst) {
-            Ok(_) => (),
-            Err(ioerr) => io_error::cond.raise(ioerr),
-        }
+    pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
+        self.obj.sendto(buf, dst)
     }
 
     pub fn connect(self, other: SocketAddr) -> UdpStream {
         UdpStream { socket: self, connectedTo: other }
     }
 
-    pub fn socket_name(&mut self) -> Option<SocketAddr> {
-        match self.obj.socket_name() {
-            Ok(sn) => Some(sn),
-            Err(ioerr) => {
-                debug!("failed to get socket name: {:?}", ioerr);
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+    pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
+        self.obj.socket_name()
     }
 }
 
@@ -76,21 +55,21 @@ impl UdpStream {
 }
 
 impl Reader for UdpStream {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         let peer = self.connectedTo;
         self.as_socket(|sock| {
             match sock.recvfrom(buf) {
-                Some((_nread, src)) if src != peer => Some(0),
-                Some((nread, _src)) => Some(nread),
-                None => None,
+                Ok((_nread, src)) if src != peer => Ok(0),
+                Ok((nread, _src)) => Ok(nread),
+                Err(e) => Err(e),
             }
         })
     }
 }
 
 impl Writer for UdpStream {
-    fn write(&mut self, buf: &[u8]) {
-        self.as_socket(|sock| sock.sendto(buf, self.connectedTo));
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        self.as_socket(|sock| sock.sendto(buf, self.connectedTo))
     }
 }
 
diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs
index d470e9bfda1..b8b396b24fd 100644
--- a/src/libstd/io/net/unix.rs
+++ b/src/libstd/io/net/unix.rs
@@ -28,7 +28,7 @@ use c_str::ToCStr;
 use rt::rtio::{IoFactory, LocalIo, RtioUnixListener};
 use rt::rtio::{RtioUnixAcceptor, RtioPipe};
 use io::pipe::PipeStream;
-use io::{io_error, Listener, Acceptor, Reader, Writer};
+use io::{Listener, Acceptor, Reader, Writer, IoResult};
 
 /// A stream which communicates over a named pipe.
 pub struct UnixStream {
@@ -52,13 +52,15 @@ impl UnixStream {
     ///
     /// # Example
     ///
-    ///     use std::io::net::unix::UnixStream;
+    /// ```rust
+    /// # #[allow(unused_must_use)];
+    /// use std::io::net::unix::UnixStream;
     ///
-    ///     let server = Path("path/to/my/socket");
-    ///     let mut stream = UnixStream::connect(&server);
-    ///     stream.write([1, 2, 3]);
-    ///
-    pub fn connect<P: ToCStr>(path: &P) -> Option<UnixStream> {
+    /// let server = Path::new("path/to/my/socket");
+    /// let mut stream = UnixStream::connect(&server);
+    /// stream.write([1, 2, 3]);
+    /// ```
+    pub fn connect<P: ToCStr>(path: &P) -> IoResult<UnixStream> {
         LocalIo::maybe_raise(|io| {
             io.unix_connect(&path.to_c_str()).map(UnixStream::new)
         })
@@ -66,11 +68,11 @@ impl UnixStream {
 }
 
 impl Reader for UnixStream {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.obj.read(buf) }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) }
 }
 
 impl Writer for UnixStream {
-    fn write(&mut self, buf: &[u8]) { self.obj.write(buf) }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) }
 }
 
 pub struct UnixListener {
@@ -91,16 +93,18 @@ impl UnixListener {
     ///
     /// # Example
     ///
-    ///     use std::io::net::unix::UnixListener;
-    ///
-    ///     let server = Path("path/to/my/socket");
-    ///     let mut stream = UnixListener::bind(&server);
-    ///     for client in stream.incoming() {
-    ///         let mut client = client;
-    ///         client.write([1, 2, 3, 4]);
-    ///     }
+    /// ```
+    /// use std::io::net::unix::UnixListener;
+    /// use std::io::Listener;
     ///
-    pub fn bind<P: ToCStr>(path: &P) -> Option<UnixListener> {
+    /// let server = Path::new("path/to/my/socket");
+    /// let mut stream = UnixListener::bind(&server);
+    /// for client in stream.incoming() {
+    ///     let mut client = client;
+    ///     client.write([1, 2, 3, 4]);
+    /// }
+    /// ```
+    pub fn bind<P: ToCStr>(path: &P) -> IoResult<UnixListener> {
         LocalIo::maybe_raise(|io| {
             io.unix_bind(&path.to_c_str()).map(|s| UnixListener { obj: s })
         })
@@ -108,14 +112,8 @@ impl UnixListener {
 }
 
 impl Listener<UnixStream, UnixAcceptor> for UnixListener {
-    fn listen(self) -> Option<UnixAcceptor> {
-        match self.obj.listen() {
-            Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+    fn listen(self) -> IoResult<UnixAcceptor> {
+        self.obj.listen().map(|obj| UnixAcceptor { obj: obj })
     }
 }
 
@@ -124,14 +122,8 @@ pub struct UnixAcceptor {
 }
 
 impl Acceptor<UnixStream> for UnixAcceptor {
-    fn accept(&mut self) -> Option<UnixStream> {
-        match self.obj.accept() {
-            Ok(s) => Some(UnixStream::new(s)),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+    fn accept(&mut self) -> IoResult<UnixStream> {
+        self.obj.accept().map(UnixStream::new)
     }
 }
 
diff --git a/src/libstd/io/pipe.rs b/src/libstd/io/pipe.rs
index 9919d333f41..34d8bf96aa2 100644
--- a/src/libstd/io/pipe.rs
+++ b/src/libstd/io/pipe.rs
@@ -14,7 +14,7 @@
 //! enough so that pipes can be created to child processes.
 
 use prelude::*;
-use io::{io_error, EndOfFile};
+use io::IoResult;
 use libc;
 use rt::rtio::{RtioPipe, LocalIo};
 
@@ -42,7 +42,7 @@ impl PipeStream {
     ///
     /// If the pipe cannot be created, an error will be raised on the
     /// `io_error` condition.
-    pub fn open(fd: libc::c_int) -> Option<PipeStream> {
+    pub fn open(fd: libc::c_int) -> IoResult<PipeStream> {
         LocalIo::maybe_raise(|io| {
             io.pipe_open(fd).map(|obj| PipeStream { obj: obj })
         })
@@ -54,29 +54,11 @@ impl PipeStream {
 }
 
 impl Reader for PipeStream {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        match self.obj.read(buf) {
-            Ok(read) => Some(read),
-            Err(ioerr) => {
-                // EOF is indicated by returning None
-                if ioerr.kind != EndOfFile {
-                    io_error::cond.raise(ioerr);
-                }
-                return None;
-            }
-        }
-    }
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) }
 }
 
 impl Writer for PipeStream {
-    fn write(&mut self, buf: &[u8]) {
-        match self.obj.write(buf) {
-            Ok(_) => (),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-            }
-        }
-    }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) }
 }
 
 #[cfg(test)]
diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs
index 6a10f24916f..62f6b3c3029 100644
--- a/src/libstd/io/process.rs
+++ b/src/libstd/io/process.rs
@@ -14,7 +14,7 @@ use prelude::*;
 
 use libc;
 use io;
-use io::io_error;
+use io::IoResult;
 use rt::rtio::{RtioProcess, IoFactory, LocalIo};
 
 use fmt;
@@ -93,7 +93,7 @@ pub enum ProcessExit {
 
 impl fmt::Show for ProcessExit {
     /// Format a ProcessExit enum, to nicely present the information.
-    fn fmt(obj: &ProcessExit, f: &mut fmt::Formatter) {
+    fn fmt(obj: &ProcessExit, f: &mut fmt::Formatter) -> fmt::Result {
         match *obj {
             ExitStatus(code) =>  write!(f.buf, "exit code: {}", code),
             ExitSignal(code) =>  write!(f.buf, "signal: {}", code),
@@ -118,7 +118,7 @@ impl ProcessExit {
 impl Process {
     /// Creates a new pipe initialized, but not bound to any particular
     /// source/destination
-    pub fn new(config: ProcessConfig) -> Option<Process> {
+    pub fn new(config: ProcessConfig) -> IoResult<Process> {
         let mut config = Some(config);
         LocalIo::maybe_raise(|io| {
             io.spawn(config.take_unwrap()).map(|(p, io)| {
@@ -142,13 +142,8 @@ impl Process {
     /// function.
     ///
     /// If the signal delivery fails, then the `io_error` condition is raised on
-    pub fn signal(&mut self, signal: int) {
-        match self.handle.kill(signal) {
-            Ok(()) => {}
-            Err(err) => {
-                io_error::cond.raise(err)
-            }
-        }
+    pub fn signal(&mut self, signal: int) -> IoResult<()> {
+        self.handle.kill(signal)
     }
 
     /// Wait for the child to exit completely, returning the status that it
diff --git a/src/libstd/io/option.rs b/src/libstd/io/result.rs
index e2eec652d9d..6eed4d146ba 100644
--- a/src/libstd/io/option.rs
+++ b/src/libstd/io/result.rs
@@ -14,80 +14,64 @@
 //! These implementations allow e.g. `Option<File>` to be used
 //! as a `Reader` without unwrapping the option first.
 
-use option::*;
-use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle};
-use super::{standard_error, PreviousIoError, io_error, IoError};
+use clone::Clone;
+use result::{Ok, Err};
+use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult};
 
-fn prev_io_error() -> IoError {
-    standard_error(PreviousIoError)
-}
-
-impl<W: Writer> Writer for Option<W> {
-    fn write(&mut self, buf: &[u8]) {
+impl<W: Writer> Writer for IoResult<W> {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         match *self {
-            Some(ref mut writer) => writer.write(buf),
-            None => io_error::cond.raise(prev_io_error())
+            Ok(ref mut writer) => writer.write(buf),
+            Err(ref e) => Err((*e).clone())
         }
     }
 
-    fn flush(&mut self) {
+    fn flush(&mut self) -> IoResult<()> {
         match *self {
-            Some(ref mut writer) => writer.flush(),
-            None => io_error::cond.raise(prev_io_error())
+            Ok(ref mut writer) => writer.flush(),
+            Err(ref e) => Err(e.clone()),
         }
     }
 }
 
-impl<R: Reader> Reader for Option<R> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+impl<R: Reader> Reader for IoResult<R> {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         match *self {
-            Some(ref mut reader) => reader.read(buf),
-            None => {
-                io_error::cond.raise(prev_io_error());
-                None
-            }
+            Ok(ref mut reader) => reader.read(buf),
+            Err(ref e) => Err(e.clone()),
         }
     }
 }
 
-impl<S: Seek> Seek for Option<S> {
-    fn tell(&self) -> u64 {
+impl<S: Seek> Seek for IoResult<S> {
+    fn tell(&self) -> IoResult<u64> {
         match *self {
-            Some(ref seeker) => seeker.tell(),
-            None => {
-                io_error::cond.raise(prev_io_error());
-                0
-            }
+            Ok(ref seeker) => seeker.tell(),
+            Err(ref e) => Err(e.clone()),
         }
     }
-    fn seek(&mut self, pos: i64, style: SeekStyle) {
+    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
         match *self {
-            Some(ref mut seeker) => seeker.seek(pos, style),
-            None => io_error::cond.raise(prev_io_error())
+            Ok(ref mut seeker) => seeker.seek(pos, style),
+            Err(ref e) => Err(e.clone())
         }
     }
 }
 
-impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for Option<L> {
-    fn listen(self) -> Option<A> {
+impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for IoResult<L> {
+    fn listen(self) -> IoResult<A> {
         match self {
-            Some(listener) => listener.listen(),
-            None => {
-                io_error::cond.raise(prev_io_error());
-                None
-            }
+            Ok(listener) => listener.listen(),
+            Err(e) => Err(e),
         }
     }
 }
 
-impl<T, A: Acceptor<T>> Acceptor<T> for Option<A> {
-    fn accept(&mut self) -> Option<T> {
+impl<T, A: Acceptor<T>> Acceptor<T> for IoResult<A> {
+    fn accept(&mut self) -> IoResult<T> {
         match *self {
-            Some(ref mut acceptor) => acceptor.accept(),
-            None => {
-                io_error::cond.raise(prev_io_error());
-                None
-            }
+            Ok(ref mut acceptor) => acceptor.accept(),
+            Err(ref e) => Err(e.clone()),
         }
     }
 }
diff --git a/src/libstd/io/signal.rs b/src/libstd/io/signal.rs
index 5575e289b59..aaec1aba4b8 100644
--- a/src/libstd/io/signal.rs
+++ b/src/libstd/io/signal.rs
@@ -20,10 +20,11 @@ definitions for a number of signals.
 */
 
 use clone::Clone;
+use result::{Ok, Err};
 use comm::{Port, SharedChan};
 use container::{Map, MutableMap};
 use hashmap;
-use option::{Some, None};
+use io;
 use rt::rtio::{IoFactory, LocalIo, RtioSignal};
 
 #[repr(int)]
@@ -117,18 +118,18 @@ impl Listener {
     /// If this function fails to register a signal handler, then an error will
     /// be raised on the `io_error` condition and the function will return
     /// false.
-    pub fn register(&mut self, signum: Signum) -> bool {
+    pub fn register(&mut self, signum: Signum) -> io::IoResult<()> {
         if self.handles.contains_key(&signum) {
-            return true; // self is already listening to signum, so succeed
+            return Ok(()); // self is already listening to signum, so succeed
         }
         match LocalIo::maybe_raise(|io| {
             io.signal(signum, self.chan.clone())
         }) {
-            Some(handle) => {
+            Ok(handle) => {
                 self.handles.insert(signum, handle);
-                true
+                Ok(())
             }
-            None => false
+            Err(e) => Err(e)
         }
     }
 
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index d9fa2a4fc33..bdf013233c0 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -28,7 +28,7 @@ out.write(bytes!("Hello, world!"));
 
 use container::Container;
 use fmt;
-use io::{Reader, Writer, io_error, IoError, OtherIoError,
+use io::{Reader, Writer, IoResult, IoError, OtherIoError,
          standard_error, EndOfFile, LineBufferedWriter};
 use libc;
 use option::{Option, Some, None};
@@ -114,7 +114,8 @@ fn reset_helper(w: ~Writer,
     match f(t.get(), w) {
         Some(mut w) => {
             drop(t);
-            w.flush();
+            // FIXME: is failing right here?
+            w.flush().unwrap();
             Some(w)
         }
         None => None
@@ -155,9 +156,9 @@ pub fn set_stderr(stderr: ~Writer) -> Option<~Writer> {
 //          // io1 aliases io2
 //      })
 //  })
-fn with_task_stdout(f: |&mut Writer|) {
+fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) {
     let task: Option<~Task> = Local::try_take();
-    match task {
+    let result = match task {
         Some(mut task) => {
             // Printing may run arbitrary code, so ensure that the task is in
             // TLS to allow all std services. Note that this means a print while
@@ -169,7 +170,7 @@ fn with_task_stdout(f: |&mut Writer|) {
             if my_stdout.is_none() {
                 my_stdout = Some(~LineBufferedWriter::new(stdout()) as ~Writer);
             }
-            f(*my_stdout.get_mut_ref());
+            let ret = f(*my_stdout.get_mut_ref());
 
             // Note that we need to be careful when putting the stdout handle
             // back into the task. If the handle was set to `Some` while
@@ -184,22 +185,29 @@ fn with_task_stdout(f: |&mut Writer|) {
             let prev = util::replace(&mut t.get().stdout, my_stdout);
             drop(t);
             drop(prev);
+            ret
         }
 
         None => {
             struct Stdout;
             impl Writer for Stdout {
-                fn write(&mut self, data: &[u8]) {
+                fn write(&mut self, data: &[u8]) -> IoResult<()> {
                     unsafe {
                         libc::write(libc::STDOUT_FILENO,
                                     data.as_ptr() as *libc::c_void,
                                     data.len() as libc::size_t);
                     }
+                    Ok(()) // just ignore the results
                 }
             }
             let mut io = Stdout;
-            f(&mut io as &mut Writer);
+            f(&mut io as &mut Writer)
         }
+    };
+
+    match result {
+        Ok(()) => {}
+        Err(e) => fail!("failed printing to stdout: {}", e),
     }
 }
 
@@ -226,8 +234,7 @@ pub fn print(s: &str) {
 /// `\n` character is printed to the console after the string.
 pub fn println(s: &str) {
     with_task_stdout(|io| {
-        io.write(s.as_bytes());
-        io.write(['\n' as u8]);
+        io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8]))
     })
 }
 
@@ -249,7 +256,7 @@ pub struct StdReader {
 }
 
 impl Reader for StdReader {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         let ret = match self.inner {
             TTY(ref mut tty) => tty.read(buf),
             File(ref mut file) => file.read(buf).map(|i| i as uint),
@@ -260,15 +267,8 @@ impl Reader for StdReader {
             // return an actual EOF error, but apparently for stdin it's a
             // little different. Hence, here we convert a 0 length read to an
             // end-of-file indicator so the caller knows to stop reading.
-            Ok(0) => {
-                io_error::cond.raise(standard_error(EndOfFile));
-                None
-            }
-            Ok(amt) => Some(amt),
-            Err(e) => {
-                io_error::cond.raise(e);
-                None
-            }
+            Ok(0) => { Err(standard_error(EndOfFile)) }
+            ret @ Ok(..) | ret @ Err(..) => ret,
         }
     }
 }
@@ -289,24 +289,15 @@ impl StdWriter {
     ///
     /// This function will raise on the `io_error` condition if an error
     /// happens.
-    pub fn winsize(&mut self) -> Option<(int, int)> {
+    pub fn winsize(&mut self) -> IoResult<(int, int)> {
         match self.inner {
-            TTY(ref mut tty) => {
-                match tty.get_winsize() {
-                    Ok(p) => Some(p),
-                    Err(e) => {
-                        io_error::cond.raise(e);
-                        None
-                    }
-                }
-            }
+            TTY(ref mut tty) => tty.get_winsize(),
             File(..) => {
-                io_error::cond.raise(IoError {
+                Err(IoError {
                     kind: OtherIoError,
                     desc: "stream is not a tty",
                     detail: None,
-                });
-                None
+                })
             }
         }
     }
@@ -318,20 +309,15 @@ impl StdWriter {
     ///
     /// This function will raise on the `io_error` condition if an error
     /// happens.
-    pub fn set_raw(&mut self, raw: bool) {
+    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
         match self.inner {
-            TTY(ref mut tty) => {
-                match tty.set_raw(raw) {
-                    Ok(()) => {},
-                    Err(e) => io_error::cond.raise(e),
-                }
-            }
+            TTY(ref mut tty) => tty.set_raw(raw),
             File(..) => {
-                io_error::cond.raise(IoError {
+                Err(IoError {
                     kind: OtherIoError,
                     desc: "stream is not a tty",
                     detail: None,
-                });
+                })
             }
         }
     }
@@ -346,14 +332,10 @@ impl StdWriter {
 }
 
 impl Writer for StdWriter {
-    fn write(&mut self, buf: &[u8]) {
-        let ret = match self.inner {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        match self.inner {
             TTY(ref mut tty) => tty.write(buf),
             File(ref mut file) => file.write(buf),
-        };
-        match ret {
-            Ok(()) => {}
-            Err(e) => io_error::cond.raise(e)
         }
     }
 }
diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs
index 24eaf6adf3f..692aaa7afd0 100644
--- a/src/libstd/io/timer.rs
+++ b/src/libstd/io/timer.rs
@@ -39,8 +39,8 @@ loop {
 */
 
 use comm::Port;
-use option::Option;
 use rt::rtio::{IoFactory, LocalIo, RtioTimer};
+use io::IoResult;
 
 pub struct Timer {
     priv obj: ~RtioTimer
@@ -48,7 +48,8 @@ pub struct Timer {
 
 /// Sleep the current task for `msecs` milliseconds.
 pub fn sleep(msecs: u64) {
-    let mut timer = Timer::new().expect("timer::sleep: could not create a Timer");
+    let timer = Timer::new();
+    let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");
 
     timer.sleep(msecs)
 }
@@ -57,7 +58,7 @@ impl Timer {
     /// Creates a new timer which can be used to put the current task to sleep
     /// for a number of milliseconds, or to possibly create channels which will
     /// get notified after an amount of time has passed.
-    pub fn new() -> Option<Timer> {
+    pub fn new() -> IoResult<Timer> {
         LocalIo::maybe_raise(|io| io.timer_init().map(|t| Timer { obj: t }))
     }
 
diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs
index a1794d24fc9..2c7f64ba747 100644
--- a/src/libstd/io/util.rs
+++ b/src/libstd/io/util.rs
@@ -7,8 +7,10 @@
 // <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 prelude::*;
 use cmp;
+use io;
 use vec::bytes::MutableByteVector;
 
 /// Wraps a `Reader`, limiting the number of bytes that can be read from it.
@@ -25,9 +27,9 @@ impl<'a, R: Reader> LimitReader<'a, R> {
 }
 
 impl<'a, R: Reader> Reader for LimitReader<'a, R> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
         if self.limit == 0 {
-            return None;
+            return Err(io::standard_error(io::EndOfFile));
         }
 
         let len = cmp::min(self.limit, buf.len());
@@ -43,7 +45,7 @@ pub struct NullWriter;
 
 impl Writer for NullWriter {
     #[inline]
-    fn write(&mut self, _buf: &[u8]) { }
+    fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> { Ok(()) }
 }
 
 /// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero.
@@ -51,9 +53,9 @@ pub struct ZeroReader;
 
 impl Reader for ZeroReader {
     #[inline]
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
         buf.set_memory(0);
-        Some(buf.len())
+        Ok(buf.len())
     }
 }
 
@@ -62,8 +64,8 @@ pub struct NullReader;
 
 impl Reader for NullReader {
     #[inline]
-    fn read(&mut self, _buf: &mut [u8]) -> Option<uint> {
-        None
+    fn read(&mut self, _buf: &mut [u8]) -> io::IoResult<uint> {
+        Err(io::standard_error(io::EndOfFile))
     }
 }
 
@@ -81,17 +83,21 @@ impl MultiWriter {
 
 impl Writer for MultiWriter {
     #[inline]
-    fn write(&mut self, buf: &[u8]) {
+    fn write(&mut self, buf: &[u8]) -> io::IoResult<()> {
+        let mut ret = Ok(());
         for writer in self.writers.mut_iter() {
-            writer.write(buf);
+            ret = ret.and(writer.write(buf));
         }
+        return ret;
     }
 
     #[inline]
-    fn flush(&mut self) {
+    fn flush(&mut self) -> io::IoResult<()> {
+        let mut ret = Ok(());
         for writer in self.writers.mut_iter() {
-            writer.flush();
+            ret = ret.and(writer.flush());
         }
+        return ret;
     }
 }
 
@@ -111,20 +117,25 @@ impl<R: Reader, I: Iterator<R>> ChainedReader<I, R> {
 }
 
 impl<R: Reader, I: Iterator<R>> Reader for ChainedReader<I, R> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
         loop {
-            match self.cur_reader {
+            let err = match self.cur_reader {
                 Some(ref mut r) => {
                     match r.read(buf) {
-                        Some(len) => return Some(len),
-                        None => {}
+                        Ok(len) => return Ok(len),
+                        Err(ref e) if e.kind == io::EndOfFile => None,
+                        Err(e) => Some(e),
                     }
                 }
                 None => break
+            };
+            self.cur_reader = self.readers.next();
+            match err {
+                Some(e) => return Err(e),
+                None => {}
             }
-            self.cur_reader = self.readers.next()
         }
-        None
+        Err(io::standard_error(io::EndOfFile))
     }
 }
 
@@ -150,22 +161,23 @@ impl<R: Reader, W: Writer> TeeReader<R, W> {
 }
 
 impl<R: Reader, W: Writer> Reader for TeeReader<R, W> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        self.reader.read(buf).map(|len| {
-            self.writer.write(buf.slice_to(len));
-            len
+    fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
+        self.reader.read(buf).and_then(|len| {
+            self.writer.write(buf.slice_to(len)).map(|()| len)
         })
     }
 }
 
 /// Copies all data from a `Reader` to a `Writer`.
-pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) {
+pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) -> io::IoResult<()> {
     let mut buf = [0, ..super::DEFAULT_BUF_SIZE];
     loop {
-        match r.read(buf) {
-            Some(len) => w.write(buf.slice_to(len)),
-            None => break
-        }
+        let len = match r.read(buf) {
+            Ok(len) => len,
+            Err(ref e) if e.kind == io::EndOfFile => return Ok(()),
+            Err(e) => return Err(e),
+        };
+        if_ok!(w.write(buf.slice_to(len)));
     }
 }