diff options
-rw-r--r-- | CHANGELOG.md | 4 | ||||
-rw-r--r-- | nix-test/build.rs | 2 | ||||
-rw-r--r-- | src/fcntl.rs | 40 | ||||
-rw-r--r-- | src/sys/aio.rs | 42 | ||||
-rw-r--r-- | test/sys/test_aio.rs | 24 | ||||
-rw-r--r-- | test/test_fcntl.rs | 15 |
6 files changed, 123 insertions, 4 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d8be1905..664fdaff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added socket option variant that enables the timestamp socket control message: `nix::sys::socket::sockopt::ReceiveTimestamp` ([#663](https://github.com/nix-rust/nix/pull/663)) +- Added more accessor methods for `AioCb` + ([#773](https://github.com/nix-rust/nix/pull/773)) +- Add nix::sys::fallocate + ([#768](https:://github.com/nix-rust/nix/pull/768)) ### Changed - Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) diff --git a/nix-test/build.rs b/nix-test/build.rs index 0c18e1c8..5d1b1bba 100644 --- a/nix-test/build.rs +++ b/nix-test/build.rs @@ -13,7 +13,7 @@ pub fn main() { "UNKNOWN" }; - gcc::Config::new() + gcc::Build::new() .file("src/const.c") .file("src/sizes.c") .define(os, None) diff --git a/src/fcntl.rs b/src/fcntl.rs index 003c316c..f99036d6 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -341,3 +341,43 @@ pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result< Errno::result(ret).map(|r| r as usize) } +#[cfg(any(target_os = "linux"))] +libc_bitflags!( + /// Mode argument flags for fallocate determining operation performed on a given range. + pub struct FallocateFlags: libc::c_int { + /// File size is not changed. + /// + /// offset + len can be greater than file size. + FALLOC_FL_KEEP_SIZE; + /// Deallocates space by creating a hole. + /// + /// Must be ORed with FALLOC_FL_KEEP_SIZE. Byte range starts at offset and continues for len bytes. + FALLOC_FL_PUNCH_HOLE; + /// Removes byte range from a file without leaving a hole. + /// + /// Byte range to collapse starts at offset and continues for len bytes. + FALLOC_FL_COLLAPSE_RANGE; + /// Zeroes space in specified byte range. + /// + /// Byte range starts at offset and continues for len bytes. + FALLOC_FL_ZERO_RANGE; + /// Increases file space by inserting a hole within the file size. + /// + /// Does not overwrite existing data. Hole starts at offset and continues for len bytes. + FALLOC_FL_INSERT_RANGE; + /// Shared file data extants are made private to the file. + /// + /// Gaurantees that a subsequent write will not fail due to lack of space. + FALLOC_FL_UNSHARE_RANGE; + } +); + +/// Manipulates file space. +/// +/// Allows the caller to directly manipulate the allocated disk space for the +/// file referred to by fd. +#[cfg(any(target_os = "linux"))] +pub fn fallocate(fd: RawFd, mode: FallocateFlags, offset: libc::off_t, len: libc::off_t) -> Result<c_int> { + let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) }; + Errno::result(res) +} diff --git a/src/sys/aio.rs b/src/sys/aio.rs index 22bd3959..4be0da7b 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -84,6 +84,11 @@ pub struct AioCb<'a> { } impl<'a> AioCb<'a> { + /// Returns the underlying file descriptor associated with the `AioCb` + pub fn fd(&self) -> RawFd { + self.aiocb.aio_fildes + } + /// Constructs a new `AioCb` with no associated buffer. /// /// The resulting `AioCb` structure is suitable for use with `AioCb::fsync`. @@ -239,6 +244,38 @@ impl<'a> AioCb<'a> { }) } + /// Returns the `aiocb`'s `LioOpcode` field + /// + /// If the value cannot be represented as an `LioOpcode`, returns `None` + /// instead. + pub fn lio_opcode(&self) -> Option<LioOpcode> { + match self.aiocb.aio_lio_opcode { + libc::LIO_READ => Some(LioOpcode::LIO_READ), + libc::LIO_WRITE => Some(LioOpcode::LIO_WRITE), + libc::LIO_NOP => Some(LioOpcode::LIO_NOP), + _ => None + } + } + + /// Returns the requested length of the aio operation in bytes + /// + /// This method returns the *requested* length of the operation. To get the + /// number of bytes actually read or written by a completed operation, use + /// `aio_return` instead. + pub fn nbytes(&self) -> usize { + self.aiocb.aio_nbytes + } + + /// Returns the file offset stored in the `AioCb` + pub fn offset(&self) -> off_t { + self.aiocb.aio_offset + } + + /// Returns the priority of the `AioCb` + pub fn priority(&self) -> libc::c_int { + self.aiocb.aio_reqprio + } + /// 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"); @@ -250,6 +287,11 @@ impl<'a> AioCb<'a> { }) } + /// Returns the `SigEvent` stored in the `AioCb` + pub fn sigevent(&self) -> SigEvent { + SigEvent::from(&self.aiocb.aio_sigevent) + } + /// Retrieve return status of an asynchronous operation. Should only be /// called once for each `AioCb`, after `AioCb::error` indicates that it has /// completed. The result is the same as for `read`, `write`, of `fsync`. diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 67fd0850..630dff9a 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -13,7 +13,7 @@ use std::{thread, time}; use tempfile::tempfile; // Helper that polls an AioCb for completion or error -fn poll_aio(mut aiocb: &mut AioCb) -> Result<()> { +fn poll_aio(aiocb: &mut AioCb) -> Result<()> { loop { let err = aiocb.error(); if err != Err(Error::from(Errno::EINPROGRESS)) { return err; }; @@ -21,6 +21,28 @@ fn poll_aio(mut aiocb: &mut AioCb) -> Result<()> { } } +#[test] +fn test_accessors() { + let mut rbuf = vec![0; 4]; + let aiocb = AioCb::from_mut_slice( 1001, + 2, //offset + &mut rbuf, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99 + }, + LioOpcode::LIO_NOP); + assert_eq!(1001, aiocb.fd()); + assert_eq!(Some(LioOpcode::LIO_NOP), aiocb.lio_opcode()); + assert_eq!(4, aiocb.nbytes()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); +} + // Tests AioCb.cancel. We aren't trying to test the OS's implementation, only our // bindings. So it's sufficient to check that AioCb.cancel returned any // AioCancelStat value. diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 43bfc091..d171b91d 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -54,11 +54,11 @@ mod linux_android { use libc::loff_t; - use nix::fcntl::{SpliceFFlags, splice, tee, vmsplice}; + use nix::fcntl::{SpliceFFlags, FallocateFlags, fallocate, splice, tee, vmsplice}; use nix::sys::uio::IoVec; use nix::unistd::{close, pipe, read, write}; - use tempfile::tempfile; + use tempfile::{tempfile, NamedTempFile}; #[test] fn test_splice() { @@ -131,4 +131,15 @@ mod linux_android { close(wr).unwrap(); } + #[test] + fn test_fallocate() { + let tmp = NamedTempFile::new().unwrap(); + + let fd = tmp.as_raw_fd(); + fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap(); + + // Check if we read exactly 100 bytes + let mut buf = [0u8; 200]; + assert_eq!(100, read(fd, &mut buf).unwrap()); + } } |