Skip to content

Commit

Permalink
Fixed error handling in AioCb::fsync, AioCb::read, and `AioCb::wr…
Browse files Browse the repository at this point in the history
…ite`

Previously, the `AioCb`'s `in_progress` field would erroneously be set
to `true`, even if the syscall had an error

Fixes nix-rust#714
  • Loading branch information
asomers committed Jul 31, 2017
1 parent a9f5c0c commit ef3caec
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))
- `AioCb::Drop` will now panic if the `AioCb` is still in-progress ([#XXX](https://github.com/nix-rust/nix/pull/XXX))

### Fixed
- Fixed error handling in `AioCb::fsync`, `AioCb::read`, and `AioCb::write` ([#XXX](https://github.com/nix-rust/nix/pull/XXX))

## [0.9.0] 2017-07-23

### Added
Expand Down
21 changes: 15 additions & 6 deletions src/sys/aio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,22 @@ impl<'a> AioCb<'a> {
/// An asynchronous version of `fsync`.
pub fn fsync(&mut self, mode: AioFsyncMode) -> Result<()> {
let p: *mut libc::aiocb = &mut self.aiocb;
self.in_progress = true;
Errno::result(unsafe { libc::aio_fsync(mode as libc::c_int, p) }).map(drop)
Errno::result(unsafe {
libc::aio_fsync(mode as libc::c_int, p)
}).map(|_| {
self.in_progress = true;
})
}

/// Asynchronously reads from a file descriptor into a buffer
pub fn read(&mut self) -> Result<()> {
assert!(self.mutable, "Can't read into an immutable buffer");
let p: *mut libc::aiocb = &mut self.aiocb;
self.in_progress = true;
Errno::result(unsafe { libc::aio_read(p) }).map(drop)
Errno::result(unsafe {
libc::aio_read(p)
}).map(|_| {
self.in_progress = true;
})
}

/// Retrieve return status of an asynchronous operation. Should only be
Expand All @@ -257,8 +263,11 @@ impl<'a> AioCb<'a> {
/// Asynchronously writes from a buffer to a file descriptor
pub fn write(&mut self) -> Result<()> {
let p: *mut libc::aiocb = &mut self.aiocb;
self.in_progress = true;
Errno::result(unsafe { libc::aio_write(p) }).map(drop)
Errno::result(unsafe {
libc::aio_write(p)
}).map(|_| {
self.in_progress = true;
})
}

}
Expand Down
50 changes: 50 additions & 0 deletions test/sys/test_aio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use nix::sys::aio::*;
use nix::sys::signal::*;
use nix::sys::time::{TimeSpec, TimeValLike};
use std::io::{Write, Read, Seek, SeekFrom};
use std::mem;
use std::ops::Deref;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
Expand Down Expand Up @@ -88,6 +89,22 @@ fn test_fsync() {
aiocb.aio_return().unwrap();
}

/// `AioCb::fsync` should not modify the `AioCb` object if libc::aio_fsync returns
/// an error
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_fsync_error() {
const INITIAL: &'static [u8] = b"abcdef123456";
// Create an invalid AioFsyncMode
let mode = unsafe { mem::transmute(666) };
let mut f = tempfile().unwrap();
f.write(INITIAL).unwrap();
let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
0, //priority
SigevNotify::SigevNone);
let err = aiocb.fsync(mode);
assert!(err.is_err());
}

#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
Expand Down Expand Up @@ -156,6 +173,24 @@ fn test_read() {
assert!(EXPECT == rbuf.deref().deref());
}

/// `AioCb::read` should not modify the `AioCb` object if libc::aio_read returns
/// an error
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_read_error() {
const INITIAL: &'static [u8] = b"abcdef123456";
let rbuf = Rc::new(vec![0; 4].into_boxed_slice());
let mut f = tempfile().unwrap();
f.write(INITIAL).unwrap();
let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
-1, //an invalid offset
rbuf.clone(),
0, //priority
SigevNotify::SigevNone,
LioOpcode::LIO_NOP);
assert!(aiocb.read().is_err());
}

// Tests from_mut_slice
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
Expand Down Expand Up @@ -230,6 +265,21 @@ fn test_write() {
assert!(rbuf == EXPECT);
}

/// `AioCb::write` should not modify the `AioCb` object if libc::aio_write returns
/// an error
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_write_error() {
let wbuf = "CDEF".to_string().into_bytes();
let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor
0, //offset
&wbuf,
0, //priority
SigevNotify::SigevNone,
LioOpcode::LIO_NOP);
assert!(aiocb.write().is_err());
}

lazy_static! {
pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
}
Expand Down

0 comments on commit ef3caec

Please sign in to comment.