Skip to content

libnative/io/net, file_unix: fix offset parameters. #18658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 68 additions & 70 deletions src/libnative/io/file_unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -30,6 +31,40 @@ pub struct FileDesc {
inner: Arc<Inner>
}

enum CheckEofMode {
MayHaveEof,
NeverEof
}

#[inline]
fn check_error<I: PartialEq + PartialOrd + Zero + ToPrimitive, Ret: NumCast>
(ret: I, check_eof: CheckEofMode) -> IoResult<Ret>
{
let zero = num::zero::<I>();
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.
///
Expand All @@ -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<uint> {
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 }
Expand All @@ -88,19 +111,20 @@ impl rtio::RtioFileStream for FileDesc {
self.inner_write(buf)
}
fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
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<u64> {
Expand All @@ -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<u64> {
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()) }))
Expand Down Expand Up @@ -242,33 +260,21 @@ impl CFile {

impl rtio::RtioFileStream for CFile {
fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
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<int> {
Expand All @@ -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<u64> {
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())
Expand Down
17 changes: 10 additions & 7 deletions src/libnative/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -96,7 +96,7 @@ fn last_error() -> IoError {
}

// unix has nonzero values as errors
fn mkerr_libc <Int: num::Zero>(ret: Int) -> IoResult<()> {
fn mkerr_libc <Int: Zero>(ret: Int) -> IoResult<()> {
if !ret.is_zero() {
Err(last_error())
} else {
Expand All @@ -120,7 +120,7 @@ fn retry<I> (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020

#[cfg(unix)]
#[inline]
fn retry<I: PartialEq + num::One + Neg<I>> (f: || -> I) -> I {
fn retry<I: PartialEq + One + Neg<I>> (f: || -> I) -> I {
let minus_one = -num::one::<I>();
loop {
let n = f();
Expand All @@ -129,8 +129,11 @@ fn retry<I: PartialEq + num::One + Neg<I>> (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;
Expand All @@ -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
Expand Down
19 changes: 11 additions & 8 deletions src/libnative/io/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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(()),
Expand Down Expand Up @@ -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))
Expand All @@ -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));
Expand Down Expand Up @@ -933,7 +933,7 @@ impl rtio::RtioUdpSocket for UdpSocket {
pub fn read<T>(fd: sock_t,
deadline: u64,
lock: || -> T,
read: |bool| -> libc::c_int) -> IoResult<uint> {
read: |bool| -> int) -> IoResult<uint> {
let mut ret = -1;
if deadline == 0 {
ret = retry(|| read(false));
Expand Down Expand Up @@ -977,14 +977,17 @@ pub fn write<T>(fd: sock_t,
buf: &[u8],
write_everything: bool,
lock: || -> T,
write: |bool, *const u8, uint| -> i64) -> IoResult<uint> {
write: |bool, *const u8, uint| -> int) -> IoResult<uint> {
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()) });
Expand Down
4 changes: 2 additions & 2 deletions src/libnative/io/pipe_unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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(()),
Expand Down