summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/sys/aio.rs67
-rw-r--r--test/sys/test_aio.rs65
3 files changed, 133 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 624f0c7f..573e167c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
### Added
+- Added `AioCb::from_ptr` and `AioCb::from_mut_ptr`
+ ([#820](https://github.com/nix-rust/nix/pull/820))
- Added specialized wrappers: `sys::ptrace::{traceme, syscall, cont, attach}`. Using the matching routines
with `sys::ptrace::ptrace` is now deprecated.
- Added `nix::poll` module for all platforms
diff --git a/src/sys/aio.rs b/src/sys/aio.rs
index d85ecfa1..94837a12 100644
--- a/src/sys/aio.rs
+++ b/src/sys/aio.rs
@@ -178,6 +178,73 @@ impl<'a> AioCb<'a> {
}
}
+ /// Constructs a new `AioCb` from a mutable raw pointer
+ ///
+ /// * `fd` File descriptor. Required for all aio functions.
+ /// * `offs` File offset
+ /// * `buf` Pointer to the memory buffer
+ /// * `len` Length of the buffer pointed to by `buf`
+ /// * `prio` If POSIX Prioritized IO is supported, then the operation will
+ /// be prioritized at the process's priority level minus `prio`
+ /// * `sigev_notify` Determines how you will be notified of event
+ /// completion.
+ /// * `opcode` This field is only used for `lio_listio`. It determines
+ /// which operation to use for this individual aiocb
+ ///
+ /// # Safety
+ ///
+ /// Unsafe because using this `AioCb` will cause `libc::aio_read` or
+ /// `libc::aio_write` to dereference a raw pointer, without type, bounds, or
+ /// lifetime checking.
+ pub unsafe fn from_mut_ptr(fd: RawFd, offs: off_t,
+ buf: *mut c_void, len: usize,
+ prio: libc::c_int, sigev_notify: SigevNotify,
+ opcode: LioOpcode) -> AioCb<'a> {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ a.aio_offset = offs;
+ a.aio_nbytes = len;
+ a.aio_buf = buf;
+ a.aio_lio_opcode = opcode as libc::c_int;
+
+ let aiocb = AioCb { aiocb: a, mutable: true, in_progress: false,
+ keeper: Keeper::none};
+ aiocb
+ }
+
+ /// Constructs a new `AioCb` from a raw pointer
+ ///
+ /// * `fd` File descriptor. Required for all aio functions.
+ /// * `offs` File offset
+ /// * `buf` Pointer to the memory buffer
+ /// * `len` Length of the buffer pointed to by `buf`
+ /// * `prio` If POSIX Prioritized IO is supported, then the operation will
+ /// be prioritized at the process's priority level minus `prio`
+ /// * `sigev_notify` Determines how you will be notified of event
+ /// completion.
+ /// * `opcode` This field is only used for `lio_listio`. It determines
+ /// which operation to use for this individual aiocb
+ ///
+ /// # Safety
+ ///
+ /// Unsafe because using this `AioCb` will cause `libc::aio_write` to
+ /// dereference a raw pointer, without type, bounds, or lifetime checking.
+ pub unsafe fn from_ptr(fd: RawFd, offs: off_t,
+ buf: *const c_void, len: usize,
+ prio: libc::c_int, sigev_notify: SigevNotify,
+ opcode: LioOpcode) -> AioCb<'a> {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ a.aio_offset = offs;
+ a.aio_nbytes = len;
+ // casting a const ptr to a mutable ptr here is ok, because we set the
+ // AioCb's mutable field to false
+ a.aio_buf = buf as *mut c_void;
+ a.aio_lio_opcode = opcode as libc::c_int;
+
+ let aiocb = AioCb { aiocb: a, mutable: false, in_progress: false,
+ keeper: Keeper::none};
+ aiocb
+ }
+
/// Like `from_mut_slice`, but works on constant slices rather than
/// mutable slices.
///
diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs
index 1f807585..42e71fdb 100644
--- a/test/sys/test_aio.rs
+++ b/test/sys/test_aio.rs
@@ -1,4 +1,4 @@
-use libc::c_int;
+use libc::{c_int, c_void};
use nix::{Error, Result};
use nix::errno::*;
use nix::sys::aio::*;
@@ -244,6 +244,36 @@ fn test_read_into_mut_slice() {
assert!(rbuf == EXPECT);
}
+// Tests from_ptr
+#[test]
+#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
+fn test_read_into_pointer() {
+ const INITIAL: &'static [u8] = b"abcdef123456";
+ let mut rbuf = vec![0; 4];
+ const EXPECT: &'static [u8] = b"cdef";
+ let mut f = tempfile().unwrap();
+ f.write(INITIAL).unwrap();
+ {
+ // Safety: ok because rbuf lives until after poll_aio
+ let mut aiocb = unsafe {
+ AioCb::from_mut_ptr( f.as_raw_fd(),
+ 2, //offset
+ rbuf.as_mut_ptr() as *mut c_void,
+ rbuf.len(),
+ 0, //priority
+ SigevNotify::SigevNone,
+ LioOpcode::LIO_NOP)
+ };
+ aiocb.read().unwrap();
+
+ let err = poll_aio(&mut aiocb);
+ assert!(err == Ok(()));
+ assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
+ }
+
+ assert!(rbuf == EXPECT);
+}
+
// Test reading into an immutable buffer. It should fail
// FIXME: This test fails to panic on Linux/musl
#[test]
@@ -292,6 +322,39 @@ fn test_write() {
assert!(rbuf == EXPECT);
}
+// Tests `AioCb::from_ptr`
+#[test]
+#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
+fn test_write_into_pointer() {
+ const INITIAL: &'static [u8] = b"abcdef123456";
+ let wbuf = "CDEF".to_string().into_bytes();
+ let mut rbuf = Vec::new();
+ const EXPECT: &'static [u8] = b"abCDEF123456";
+
+ let mut f = tempfile().unwrap();
+ f.write(INITIAL).unwrap();
+ // Safety: ok because aiocb outlives poll_aio
+ let mut aiocb = unsafe {
+ AioCb::from_ptr( f.as_raw_fd(),
+ 2, //offset
+ wbuf.as_ptr() as *const c_void,
+ wbuf.len(),
+ 0, //priority
+ SigevNotify::SigevNone,
+ LioOpcode::LIO_NOP)
+ };
+ aiocb.write().unwrap();
+
+ let err = poll_aio(&mut aiocb);
+ assert!(err == Ok(()));
+ assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
+
+ f.seek(SeekFrom::Start(0)).unwrap();
+ let len = f.read_to_end(&mut rbuf).unwrap();
+ assert!(len == EXPECT.len());
+ assert!(rbuf == EXPECT);
+}
+
/// `AioCb::write` should not modify the `AioCb` object if libc::aio_write returns
/// an error
// Skip on Linux, because Linux's AIO implementation can't detect errors