diff options
| author | Ronald Kinard <[email protected]> | 2017-02-25 21:19:47 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2017-02-25 21:19:47 -0600 |
| commit | 4ecade8af14dff869c4d41dcd60040b69f06b64e (patch) | |
| tree | 0bfc16fd5a5e1b5698e0fe9b786caf9a0c4062ae /ctr-std/src/sys | |
| parent | Merge pull request #23 from panicbit/unmarked_api (diff) | |
| parent | implement buffered stdio (diff) | |
| download | ctru-rs-4ecade8af14dff869c4d41dcd60040b69f06b64e.tar.xz ctru-rs-4ecade8af14dff869c4d41dcd60040b69f06b64e.zip | |
Merge pull request #22 from FenrirWolf/stdio
Implement synchronized stdio
Diffstat (limited to 'ctr-std/src/sys')
| -rw-r--r-- | ctr-std/src/sys/unix/fd.rs | 137 | ||||
| -rw-r--r-- | ctr-std/src/sys/unix/io.rs | 81 | ||||
| -rw-r--r-- | ctr-std/src/sys/unix/mod.rs | 2 | ||||
| -rw-r--r-- | ctr-std/src/sys/unix/stdio.rs | 81 |
4 files changed, 301 insertions, 0 deletions
diff --git a/ctr-std/src/sys/unix/fd.rs b/ctr-std/src/sys/unix/fd.rs new file mode 100644 index 0000000..917a34b --- /dev/null +++ b/ctr-std/src/sys/unix/fd.rs @@ -0,0 +1,137 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <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. + +#![unstable(reason = "not public", issue = "0", feature = "fd")] + +use cmp; +use io::{self, Read}; +use libc::{self, c_int, c_void, ssize_t}; +use mem; +use sys::cvt; +use sys_common::AsInner; +use sys_common::io::read_to_end_uninitialized; + +#[derive(Debug)] +pub struct FileDesc { + fd: c_int, +} + +fn max_len() -> usize { + // The maximum read limit on most posix-like systems is `SSIZE_MAX`, + // with the man page quoting that if the count of bytes to read is + // greater than `SSIZE_MAX` the result is "unspecified". + // + // On OSX, however, apparently the 64-bit libc is either buggy or + // intentionally showing odd behavior by rejecting any read with a size + // larger than or equal to INT_MAX. To handle both of these the read + // size is capped on both platforms. + if cfg!(target_os = "macos") { + <c_int>::max_value() as usize - 1 + } else { + <ssize_t>::max_value() as usize + } +} + +impl FileDesc { + pub fn new(fd: c_int) -> FileDesc { + FileDesc { fd: fd } + } + + pub fn raw(&self) -> c_int { self.fd } + + /// Extracts the actual filedescriptor without closing it. + pub fn into_raw(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { + let ret = cvt(unsafe { + libc::read(self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len())) + })?; + Ok(ret as usize) + } + + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + let mut me = self; + (&mut me).read_to_end(buf) + } + + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { + unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) + -> io::Result<isize> + { + use libc::pread as pread64; + cvt(pread64(fd, buf, count, offset)) + } + + unsafe { + cvt_pread64(self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len()), + offset as i64) + .map(|n| n as usize) + } + } + + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { + let ret = cvt(unsafe { + libc::write(self.fd, + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), max_len())) + })?; + Ok(ret as usize) + } + + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { + unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) + -> io::Result<isize> + { + use libc::pwrite as pwrite64; + cvt(pwrite64(fd, buf, count, offset)) + } + + unsafe { + cvt_pwrite64(self.fd, + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), max_len()), + offset as i64) + .map(|n| n as usize) + } + } +} + +impl<'a> Read for &'a FileDesc { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + (**self).read(buf) + } + + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } +} + +impl AsInner<c_int> for FileDesc { + fn as_inner(&self) -> &c_int { &self.fd } +} + +impl Drop for FileDesc { + fn drop(&mut self) { + // Note that errors are ignored when closing a file descriptor. The + // reason for this is that if an error occurs we don't actually know if + // the file descriptor was closed or not, and if we retried (for + // something like EINTR), we might close another valid file descriptor + // (opened after we closed ours. + let _ = unsafe { libc::close(self.fd) }; + } +} diff --git a/ctr-std/src/sys/unix/io.rs b/ctr-std/src/sys/unix/io.rs new file mode 100644 index 0000000..6d38b00 --- /dev/null +++ b/ctr-std/src/sys/unix/io.rs @@ -0,0 +1,81 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <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 io; +use libc; +use sys::fd::FileDesc; + +pub struct Stdin(()); +pub struct Stdout(()); +pub struct Stderr(()); + +impl Stdin { + pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) } + + pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDIN_FILENO); + let ret = fd.read(data); + fd.into_raw(); + ret + } + + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDIN_FILENO); + let ret = fd.read_to_end(buf); + fd.into_raw(); + ret + } +} + +impl Stdout { + pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) } + + pub fn write(&self, data: &[u8]) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDOUT_FILENO); + let ret = fd.write(data); + fd.into_raw(); + ret + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) } + + pub fn write(&self, data: &[u8]) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDERR_FILENO); + let ret = fd.write(data); + fd.into_raw(); + ret + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +// FIXME: right now this raw stderr handle is used in a few places because +// std::io::stderr_raw isn't exposed, but once that's exposed this impl +// should go away +impl io::Write for Stderr { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { + Stderr::write(self, data) + } + + fn flush(&mut self) -> io::Result<()> { + Stderr::flush(self) + } +} + +pub const EBADF_ERR: i32 = ::libc::EBADF as i32; +pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs index ec657d8..0da1d3b 100644 --- a/ctr-std/src/sys/unix/mod.rs +++ b/ctr-std/src/sys/unix/mod.rs @@ -15,6 +15,8 @@ use libc; pub mod ext; pub mod fast_thread_local; +pub mod fd; +pub mod stdio; pub mod memchr; pub mod mutex; pub mod os; diff --git a/ctr-std/src/sys/unix/stdio.rs b/ctr-std/src/sys/unix/stdio.rs new file mode 100644 index 0000000..6d38b00 --- /dev/null +++ b/ctr-std/src/sys/unix/stdio.rs @@ -0,0 +1,81 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <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 io; +use libc; +use sys::fd::FileDesc; + +pub struct Stdin(()); +pub struct Stdout(()); +pub struct Stderr(()); + +impl Stdin { + pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) } + + pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDIN_FILENO); + let ret = fd.read(data); + fd.into_raw(); + ret + } + + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDIN_FILENO); + let ret = fd.read_to_end(buf); + fd.into_raw(); + ret + } +} + +impl Stdout { + pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) } + + pub fn write(&self, data: &[u8]) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDOUT_FILENO); + let ret = fd.write(data); + fd.into_raw(); + ret + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) } + + pub fn write(&self, data: &[u8]) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDERR_FILENO); + let ret = fd.write(data); + fd.into_raw(); + ret + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +// FIXME: right now this raw stderr handle is used in a few places because +// std::io::stderr_raw isn't exposed, but once that's exposed this impl +// should go away +impl io::Write for Stderr { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { + Stderr::write(self, data) + } + + fn flush(&mut self) -> io::Result<()> { + Stderr::flush(self) + } +} + +pub const EBADF_ERR: i32 = ::libc::EBADF as i32; +pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; |