diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 816f7e08eab..65db76d5ef7 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -13,34 +13,45 @@ use super::support::PathLike; use super::{Reader, Writer, Seek}; use super::{SeekSet, SeekCur, SeekEnd, SeekStyle}; use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject}; -use rt::io::{io_error, read_error, EndOfFile}; +use rt::io::{io_error, read_error, EndOfFile, + FileMode, FileAccess, Open, Read, Create, ReadWrite}; use rt::local::Local; use rt::test::*; -use libc::{O_RDWR, O_RDONLY, O_WRONLY, S_IWUSR, S_IRUSR, - O_CREAT, O_TRUNC, O_APPEND}; -/// Instructions on how to open a file and return a `FileStream`. -enum FileMode { - /// Opens an existing file. IoError if file does not exist. - Open, - /// Creates a file. IoError if file exists. - Create, - /// Opens an existing file or creates a new one. - OpenOrCreate, - /// Opens an existing file or creates a new one, positioned at EOF. - Append, - /// Opens an existing file, truncating it to 0 bytes. - Truncate, - /// Opens an existing file or creates a new one, truncating it to 0 bytes. - CreateOrTruncate, +/// Open a file for reading/writing, as indicated by `path`. +pub fn open(path: &P, + mode: FileMode, + access: FileAccess + ) -> Option { + let open_result = unsafe { + let io = Local::unsafe_borrow::(); + (*io).fs_open(path, mode, access) + }; + match open_result { + Ok(fd) => Some(FileStream { + fd: fd, + last_nread: -1 + }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } } -/// How should the file be opened? `FileStream`s opened with `Read` will -/// raise an `io_error` condition if written to. -enum FileAccess { - Read, - Write, - ReadWrite +/// Unlink (remove) a file from the filesystem, as indicated +/// by `path`. +pub fn unlink(path: &P) { + let unlink_result = unsafe { + let io = Local::unsafe_borrow::(); + (*io).fs_unlink(path) + }; + match unlink_result { + Ok(_) => (), + Err(ioerr) => { + io_error::cond.raise(ioerr); + } + } } /// Abstraction representing *positional* access to a file. In this case, @@ -61,55 +72,6 @@ pub struct FileStream { } impl FileStream { - pub fn open(path: &P, - mode: FileMode, - access: FileAccess - ) -> Option { - let open_result = unsafe { - let io = Local::unsafe_borrow::(); - let mut flags = match mode { - Open => 0, - Create => O_CREAT, - OpenOrCreate => O_CREAT, - Append => O_APPEND, - Truncate => O_TRUNC, - CreateOrTruncate => O_TRUNC | O_CREAT - }; - flags = match access { - Read => flags | O_RDONLY, - Write => flags | O_WRONLY, - ReadWrite => flags | O_RDWR - }; - let create_mode = match mode { - Create|OpenOrCreate|CreateOrTruncate => - S_IRUSR | S_IWUSR, - _ => 0 - }; - (*io).fs_open(path, flags as int, create_mode as int) - }; - match open_result { - Ok(fd) => Some(FileStream { - fd: fd, - last_nread: -1 - }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } - } - fn unlink(path: &P) { - let unlink_result = unsafe { - let io = Local::unsafe_borrow::(); - (*io).fs_unlink(path) - }; - match unlink_result { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } } impl Reader for FileStream { @@ -188,12 +150,12 @@ fn file_test_smoke_test_impl() { let message = "it's alright. have a good time"; let filename = &Path("./tmp/file_rt_io_file_test.txt"); { - let mut write_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut write_stream = open(filename, Create, ReadWrite).unwrap(); write_stream.write(message.as_bytes()); } { use str; - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); let mut read_buf = [0, .. 1028]; let read_str = match read_stream.read(read_buf).unwrap() { -1|0 => fail!("shouldn't happen"), @@ -201,7 +163,7 @@ fn file_test_smoke_test_impl() { }; assert!(read_str == message.to_owned()); } - FileStream::unlink(filename); + unlink(filename); } } @@ -217,7 +179,7 @@ fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() { do io_error::cond.trap(|_| { called = true; }).inside { - let result = FileStream::open(filename, Open, Read); + let result = open(filename, Open, Read); assert!(result.is_none()); } assert!(called); @@ -235,7 +197,7 @@ fn file_test_unlinking_invalid_path_should_raise_condition_impl() { do io_error::cond.trap(|_| { called = true; }).inside { - FileStream::unlink(filename); + unlink(filename); } assert!(called); } @@ -252,11 +214,11 @@ fn file_test_io_non_positional_read_impl() { let mut read_mem = [0, .. 8]; let filename = &Path("./tmp/file_rt_io_file_test_positional.txt"); { - let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); rw_stream.write(message.as_bytes()); } { - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); { let read_buf = read_mem.mut_slice(0, 4); read_stream.read(read_buf); @@ -266,7 +228,7 @@ fn file_test_io_non_positional_read_impl() { read_stream.read(read_buf); } } - FileStream::unlink(filename); + unlink(filename); let read_str = str::from_bytes(read_mem); assert!(read_str == message.to_owned()); } @@ -287,17 +249,17 @@ fn file_test_io_seeking_impl() { let mut tell_pos_post_read; let filename = &Path("./tmp/file_rt_io_file_test_seeking.txt"); { - let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); rw_stream.write(message.as_bytes()); } { - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); read_stream.seek(set_cursor as i64, SeekSet); tell_pos_pre_read = read_stream.tell(); read_stream.read(read_mem); tell_pos_post_read = read_stream.tell(); } - FileStream::unlink(filename); + unlink(filename); let read_str = str::from_bytes(read_mem); assert!(read_str == message.slice(4, 8).to_owned()); assert!(tell_pos_pre_read == set_cursor); @@ -320,16 +282,16 @@ fn file_test_io_seek_and_write_impl() { let mut read_mem = [0, .. 13]; let filename = &Path("./tmp/file_rt_io_file_test_seek_and_write.txt"); { - let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); rw_stream.write(initial_msg.as_bytes()); rw_stream.seek(seek_idx as i64, SeekSet); rw_stream.write(overwrite_msg.as_bytes()); } { - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); read_stream.read(read_mem); } - FileStream::unlink(filename); + unlink(filename); let read_str = str::from_bytes(read_mem); io::println(fmt!("read_str: '%?' final_msg: '%?'", read_str, final_msg)); assert!(read_str == final_msg.to_owned()); @@ -350,11 +312,11 @@ fn file_test_io_seek_shakedown_impl() { let mut read_mem = [0, .. 4]; let filename = &Path("./tmp/file_rt_io_file_test_seek_shakedown.txt"); { - let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); rw_stream.write(initial_msg.as_bytes()); } { - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); read_stream.seek(-4, SeekEnd); read_stream.read(read_mem); @@ -371,7 +333,7 @@ fn file_test_io_seek_shakedown_impl() { let read_str = str::from_bytes(read_mem); assert!(read_str == chunk_one.to_owned()); } - FileStream::unlink(filename); + unlink(filename); } } #[test] diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 23b8017bc51..116d240308a 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -540,3 +540,27 @@ pub fn placeholder_error() -> IoError { detail: None } } + +/// Instructions on how to open a file and return a `FileStream`. +pub enum FileMode { + /// Opens an existing file. IoError if file does not exist. + Open, + /// Creates a file. IoError if file exists. + Create, + /// Opens an existing file or creates a new one. + OpenOrCreate, + /// Opens an existing file or creates a new one, positioned at EOF. + Append, + /// Opens an existing file, truncating it to 0 bytes. + Truncate, + /// Opens an existing file or creates a new one, truncating it to 0 bytes. + CreateOrTruncate, +} + +/// Access permissions with which the file should be opened. +/// `FileStream`s opened with `Read` will raise an `io_error` condition if written to. +pub enum FileAccess { + Read, + Write, + ReadWrite +} diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index b73200bcda1..1788b7a04e3 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -18,6 +18,7 @@ use rt::uv::uvio; use path::Path; use super::io::support::PathLike; use super::io::{SeekStyle}; +use super::io::{FileMode, FileAccess}; // XXX: ~object doesn't work currently so these are some placeholder // types to use instead @@ -68,7 +69,7 @@ pub trait IoFactory { fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>; fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>; fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; - fn fs_open(&mut self, path: &P, flags: int, mode:int) + fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 93d87fb5495..b1b5f9f919c 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -31,7 +31,10 @@ use rt::uv::idle::IdleWatcher; use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; use unstable::sync::Exclusive; use super::super::io::support::PathLike; -use libc::{lseek, c_long}; +use libc::{lseek, c_long, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, + S_IRUSR, S_IWUSR}; +use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, + CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite}; #[cfg(test)] use container::Container; #[cfg(test)] use unstable::run_in_bare_thread; @@ -466,8 +469,26 @@ impl IoFactory for UvIoFactory { ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream } - fn fs_open(&mut self, path: &P, flags: int, mode: int) + fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError> { + let mut flags = match fm { + Open => 0, + Create => O_CREAT, + OpenOrCreate => O_CREAT, + Append => O_APPEND, + Truncate => O_TRUNC, + CreateOrTruncate => O_TRUNC | O_CREAT + }; + flags = match fa { + Read => flags | O_RDONLY, + Write => flags | O_WRONLY, + ReadWrite => flags | O_RDWR + }; + let create_mode = match fm { + Create|OpenOrCreate|CreateOrTruncate => + S_IRUSR | S_IWUSR, + _ => 0 + }; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -476,7 +497,8 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - do file::FsRequest::open(self.uv_loop(), path, flags, mode) |req,err| { + do file::FsRequest::open(self.uv_loop(), path, flags as int, create_mode as int) + |req,err| { if err.is_none() { let loop_ = Loop {handle: req.get_loop().native_handle()}; let home = get_handle_to_current_scheduler!(); @@ -1699,26 +1721,26 @@ fn test_timer_sleep_simple() { } fn file_test_uvio_full_simple_impl() { - use libc::{O_CREAT, O_RDWR, O_RDONLY, - S_IWUSR, S_IRUSR}; use str::StrSlice; // why does this have to be explicitly imported to work? // compiler was complaining about no trait for str that // does .as_bytes() .. use path::Path; + use rt::io::{Open, Create, ReadWrite, Read}; unsafe { let io = Local::unsafe_borrow::(); - let create_flags = O_RDWR | O_CREAT; - let ro_flags = O_RDONLY; let write_val = "hello uvio!"; - let mode = S_IWUSR | S_IRUSR; let path = "./tmp/file_test_uvio_full.txt"; { - let mut fd = (*io).fs_open(&Path(path), create_flags as int, mode as int).unwrap(); + let create_fm = Create; + let create_fa = ReadWrite; + let mut fd = (*io).fs_open(&Path(path), create_fm, create_fa).unwrap(); let write_buf = write_val.as_bytes(); fd.write(write_buf); } { - let mut fd = (*io).fs_open(&Path(path), ro_flags as int, mode as int).unwrap(); + let ro_fm = Open; + let ro_fa = Read; + let mut fd = (*io).fs_open(&Path(path), ro_fm, ro_fa).unwrap(); let mut read_vec = [0, .. 1028]; let nread = fd.read(read_vec).unwrap(); let read_val = str::from_bytes(read_vec.slice(0, nread as uint));