diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs index f616295c73d1b..e1f168b745eec 100644 --- a/src/libnative/io/file_unix.rs +++ b/src/libnative/io/file_unix.rs @@ -14,6 +14,7 @@ use alloc::arc::Arc; use libc::{mod, c_int, c_void}; use std::c_str::CString; use std::mem; +use std::num::{mod, Zero}; use std::rt::rtio::{mod, IoResult}; use io::{retry, keep_going}; @@ -30,6 +31,40 @@ pub struct FileDesc { inner: Arc } +enum CheckEofMode { + MayHaveEof, + NeverEof +} + +#[inline] +fn check_error + (ret: I, check_eof: CheckEofMode) -> IoResult +{ + let zero = num::zero::(); + match check_eof { + MayHaveEof if ret == zero => Err(util::eof()), + _ => { + if ret < zero { + Err(super::last_error()) + } else { + // ToPrimitive and NumCast help us here because + // we can't simply typecast by writing "ret as Ret"; + // http://stackoverflow.com/questions/26042703/ + Ok(NumCast::from(ret).unwrap()) + } + } + } +} + +#[inline] +fn check_error_unit(ret: int) -> IoResult<()> { + if ret < 0 { + Err(super::last_error()) + } else { + Ok(()) + } +} + impl FileDesc { /// Create a `FileDesc` from an open C file descriptor. /// @@ -50,31 +85,19 @@ impl FileDesc { // native::io wanting to use them is forced to have all the // rtio traits in scope pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult { - let ret = retry(|| unsafe { + check_error(retry(|| unsafe { libc::read(self.fd(), buf.as_mut_ptr() as *mut libc::c_void, buf.len() as libc::size_t) - }); - if ret == 0 { - Err(util::eof()) - } else if ret < 0 { - Err(super::last_error()) - } else { - Ok(ret as uint) - } + }), MayHaveEof) } pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> { - let ret = keep_going(buf, |buf, len| { + check_error_unit(keep_going(buf, |buf, len| { unsafe { libc::write(self.fd(), buf as *const libc::c_void, - len as libc::size_t) as i64 + len as libc::size_t) as int } - }); - if ret < 0 { - Err(super::last_error()) - } else { - Ok(()) - } + })) } pub fn fd(&self) -> fd_t { self.inner.fd } @@ -88,19 +111,20 @@ impl rtio::RtioFileStream for FileDesc { self.inner_write(buf) } fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { - match retry(|| unsafe { - libc::pread(self.fd(), buf.as_ptr() as *mut _, - buf.len() as libc::size_t, - offset as libc::off_t) - }) { - -1 => Err(super::last_error()), - n => Ok(n as int) - } + check_error(retry(|| unsafe { + libc::pread(self.fd(), buf.as_mut_ptr() as *mut libc::c_void, + buf.len() as libc::size_t, offset as libc::off_t) + }), MayHaveEof) } fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()> { - super::mkerr_libc(retry(|| unsafe { - libc::pwrite(self.fd(), buf.as_ptr() as *const _, - buf.len() as libc::size_t, offset as libc::off_t) + let mut offset = offset as libc::off_t; + check_error_unit(keep_going(buf, |buf, len| { + let r = unsafe { libc::pwrite(self.fd(), buf as *const libc::c_void, + len as libc::size_t, offset) }; + if 0 < r { + offset += r as libc::off_t + } + r as int })) } fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult { @@ -109,20 +133,14 @@ impl rtio::RtioFileStream for FileDesc { rtio::SeekEnd => libc::SEEK_END, rtio::SeekCur => libc::SEEK_CUR, }; - let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) }; - if n < 0 { - Err(super::last_error()) - } else { - Ok(n as u64) - } + check_error(unsafe { + libc::lseek(self.fd(), pos as libc::off_t, whence) + }, NeverEof) } fn tell(&self) -> IoResult { - let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) }; - if n < 0 { - Err(super::last_error()) - } else { - Ok(n as u64) - } + check_error(unsafe { + libc::lseek(self.fd(), 0, libc::SEEK_CUR) + }, NeverEof) } fn fsync(&mut self) -> IoResult<()> { super::mkerr_libc(retry(|| unsafe { libc::fsync(self.fd()) })) @@ -242,33 +260,21 @@ impl CFile { impl rtio::RtioFileStream for CFile { fn read(&mut self, buf: &mut [u8]) -> IoResult { - let ret = keep_going(buf, |buf, len| { + check_error(keep_going(buf, |buf, len| { unsafe { libc::fread(buf as *mut libc::c_void, 1, len as libc::size_t, - self.file) as i64 + self.file) as int } - }); - if ret == 0 { - Err(util::eof()) - } else if ret < 0 { - Err(super::last_error()) - } else { - Ok(ret as int) - } + }), MayHaveEof) } fn write(&mut self, buf: &[u8]) -> IoResult<()> { - let ret = keep_going(buf, |buf, len| { + check_error_unit(keep_going(buf, |buf, len| { unsafe { libc::fwrite(buf as *const libc::c_void, 1, len as libc::size_t, - self.file) as i64 + self.file) as int } - }); - if ret < 0 { - Err(super::last_error()) - } else { - Ok(()) - } + })) } fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { @@ -283,20 +289,12 @@ impl rtio::RtioFileStream for CFile { rtio::SeekEnd => libc::SEEK_END, rtio::SeekCur => libc::SEEK_CUR, }; - let n = unsafe { libc::fseek(self.file, pos as libc::c_long, whence) }; - if n < 0 { - Err(super::last_error()) - } else { - Ok(n as u64) - } + check_error(unsafe { + libc::fseek(self.file, pos as libc::c_long, whence) + }, NeverEof) } fn tell(&self) -> IoResult { - let ret = unsafe { libc::ftell(self.file) }; - if ret < 0 { - Err(super::last_error()) - } else { - Ok(ret as u64) - } + check_error( unsafe { libc::ftell(self.file) }, NeverEof) } fn fsync(&mut self) -> IoResult<()> { self.flush().and_then(|()| self.fd.fsync()) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 954f7bbc59adc..ef57ffa68d0bf 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -27,7 +27,7 @@ use libc::{mod, c_int}; use std::c_str::CString; use std::os; use std::rt::rtio::{mod, IoResult, IoError}; -use std::num; +use std::num::{mod, Zero, One}; // Local re-exports pub use self::file::FileDesc; @@ -96,7 +96,7 @@ fn last_error() -> IoError { } // unix has nonzero values as errors -fn mkerr_libc (ret: Int) -> IoResult<()> { +fn mkerr_libc (ret: Int) -> IoResult<()> { if !ret.is_zero() { Err(last_error()) } else { @@ -120,7 +120,7 @@ fn retry (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020 #[cfg(unix)] #[inline] -fn retry> (f: || -> I) -> I { +fn retry> (f: || -> I) -> I { let minus_one = -num::one::(); loop { let n = f(); @@ -129,8 +129,11 @@ fn retry> (f: || -> I) -> I { } } - -fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 { +// 32-bit Windows with 4GT (aka 3G/1G split) enabled is practically the only platform +// whose I/O system calls can handle a buffer longer than int::MAX bytes. +// It is such a rare configuration that the user should know what they is doing. +// Moreover, it would be unlikely to succeed in allocating such a large buffer. +fn keep_going(data: &[u8], f: |*const u8, uint| -> int) -> int { let origamt = data.len(); let mut data = data.as_ptr(); let mut amt = origamt; @@ -140,12 +143,12 @@ fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 { break } else if ret != -1 { amt -= ret as uint; - data = unsafe { data.offset(ret as int) }; + data = unsafe { data.offset(ret) }; } else { return ret; } } - return (origamt - amt) as i64; + return (origamt - amt) as int; } /// Implementation of rt::rtio's IoFactory trait to generate handles to the diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index a4b97a3eb84ef..7fe5674003257 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -326,7 +326,7 @@ impl rtio::RtioTcpStream for TcpStream { libc::recv(fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len() as wrlen, - flags) as libc::c_int + flags) as int }; read(fd, self.read_deadline, dolock, doread) } @@ -339,7 +339,7 @@ impl rtio::RtioTcpStream for TcpStream { libc::send(fd, buf as *const _, len as wrlen, - flags) as i64 + flags) as int }; match write(fd, self.write_deadline, buf, true, dolock, dowrite) { Ok(_) => Ok(()), @@ -780,7 +780,7 @@ impl rtio::RtioUdpSocket for UdpSocket { buf.len() as msglen_t, flags, storagep, - &mut addrlen) as libc::c_int + &mut addrlen) as int })); sockaddr_to_addr(&storage, addrlen as uint).and_then(|addr| { Ok((n as uint, addr)) @@ -801,7 +801,7 @@ impl rtio::RtioUdpSocket for UdpSocket { len as msglen_t, flags, dstp, - dstlen) as i64 + dstlen) as int }; let n = try!(write(fd, self.write_deadline, buf, false, dolock, dowrite)); @@ -933,7 +933,7 @@ impl rtio::RtioUdpSocket for UdpSocket { pub fn read(fd: sock_t, deadline: u64, lock: || -> T, - read: |bool| -> libc::c_int) -> IoResult { + read: |bool| -> int) -> IoResult { let mut ret = -1; if deadline == 0 { ret = retry(|| read(false)); @@ -977,14 +977,17 @@ pub fn write(fd: sock_t, buf: &[u8], write_everything: bool, lock: || -> T, - write: |bool, *const u8, uint| -> i64) -> IoResult { + write: |bool, *const u8, uint| -> int) -> IoResult { let mut ret = -1; let mut written = 0; if deadline == 0 { if write_everything { ret = keep_going(buf, |inner, len| { - written = buf.len() - len; - write(false, inner, len) + let n = write(false, inner, len); + if 0 < n { + written += n as uint + } + n }); } else { ret = retry(|| { write(false, buf.as_ptr(), buf.len()) }); diff --git a/src/libnative/io/pipe_unix.rs b/src/libnative/io/pipe_unix.rs index 48f31615339a0..f7c98c5a8fa75 100644 --- a/src/libnative/io/pipe_unix.rs +++ b/src/libnative/io/pipe_unix.rs @@ -162,7 +162,7 @@ impl rtio::RtioPipe for UnixStream { libc::recv(fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len() as libc::size_t, - flags) as libc::c_int + flags) as int }; net::read(fd, self.read_deadline, dolock, doread) } @@ -175,7 +175,7 @@ impl rtio::RtioPipe for UnixStream { libc::send(fd, buf as *const _, len as libc::size_t, - flags) as i64 + flags) as int }; match net::write(fd, self.write_deadline, buf, true, dolock, dowrite) { Ok(_) => Ok(()),