From 83faf100849705e1d090a130975ed90ccb3a3738 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Mon, 4 Feb 2019 15:12:48 +0100 Subject: openpgp-ffi: Convert pgp_reader_t to the new framework. --- openpgp-ffi/src/armor.rs | 84 +++++++++++++++++++------------------- openpgp-ffi/src/common.rs | 18 ++++----- openpgp-ffi/src/io.rs | 100 ++++++++++++++++++++++++++++++---------------- openpgp-ffi/src/parse.rs | 7 ++-- 4 files changed, 120 insertions(+), 89 deletions(-) (limited to 'openpgp-ffi') diff --git a/openpgp-ffi/src/armor.rs b/openpgp-ffi/src/armor.rs index 3c1039c2..bec0ab80 100644 --- a/openpgp-ffi/src/armor.rs +++ b/openpgp-ffi/src/armor.rs @@ -7,13 +7,18 @@ use std::mem::size_of; use std::ptr; use std::slice; -use std::io::{Read, Write}; +use std::io::Write; use libc::{self, uint8_t, c_char, c_int, size_t}; extern crate sequoia_openpgp; use self::sequoia_openpgp::armor; +use super::io::{Reader, ReaderKind}; +use Maybe; use MoveIntoRaw; +use MoveResultIntoRaw; +use RefRaw; +use RefMutRaw; /// Represents a (key, value) pair in an armor header. #[repr(C)] @@ -102,28 +107,28 @@ fn kind_to_int(kind: Option) -> c_int { /// pgp_reader_free (bytes); /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "system" fn pgp_armor_reader_new(inner: *mut Box, - kind: c_int) - -> *mut Box { - let inner = ffi_param_ref_mut!(inner); +pub extern "system" fn pgp_armor_reader_new(inner: *mut Reader, + kind: c_int) + -> *mut Reader { + let inner = inner.ref_mut_raw(); let kind = int_to_kind(kind); - box_raw!(Box::new(armor::Reader::new(inner, kind))) + ReaderKind::Armored(armor::Reader::new(inner, kind)).move_into_raw() } /// Creates a `Reader` from a file. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_armor_reader_from_file(errp: Option<&mut *mut ::error::Error>, - filename: *const c_char, - kind: c_int) - -> *mut Box { - ffi_make_fry_from_errp!(errp); + filename: *const c_char, + kind: c_int) + -> Maybe { let filename = ffi_param_cstr!(filename).to_string_lossy().into_owned(); let kind = int_to_kind(kind); - ffi_try_box!(armor::Reader::from_file(&filename, kind) - .map(|r| Box::new(r)) - .map_err(|e| ::failure::Error::from(e))) + armor::Reader::from_file(&filename, kind) + .map(|r| ReaderKind::Armored(r)) + .map_err(|e| ::failure::Error::from(e)) + .move_into_raw(errp) } /// Creates a `Reader` from a buffer. @@ -180,17 +185,17 @@ pub extern "system" fn pgp_armor_reader_from_file(errp: Option<&mut *mut ::error /// /// pgp_reader_free (armor); /// ``` -#[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "system" fn pgp_armor_reader_from_bytes(b: *const uint8_t, len: size_t, - kind: c_int) - -> *mut Box { +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" +fn pgp_armor_reader_from_bytes(b: *const uint8_t, len: size_t, + kind: c_int) + -> *mut Reader { assert!(!b.is_null()); let buf = unsafe { slice::from_raw_parts(b, len as usize) }; let kind = int_to_kind(kind); - box_raw!(Box::new(armor::Reader::from_bytes(buf, kind))) + ReaderKind::Armored(armor::Reader::from_bytes(buf, kind)).move_into_raw() } /// Returns the kind of data this reader is for. @@ -205,16 +210,16 @@ pub extern "system" fn pgp_armor_reader_from_bytes(b: *const uint8_t, len: size_ /// /// [this]: fn.pgp_armor_reader_new.html #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "system" fn pgp_armor_reader_kind(reader: *mut Box) - -> c_int { - // We need to downcast `reader`. To do that, we need to do a - // little dance. We will momentarily take ownership of `reader`, - // wrapping it in a Box again. Then, at the end of the function, - // we will leak it again. - let reader = ffi_param_move!(reader as *mut Box); - let kind = kind_to_int(reader.kind()); - Box::into_raw(reader); - kind +pub extern "system" fn pgp_armor_reader_kind(reader: *const Reader) + -> c_int { + if let ReaderKind::Armored(ref armor_reader) = reader.ref_raw() + { + kind_to_int(armor_reader.kind()) + } else { + panic!( + "FFI contract violation: Wrong parameter type: \ + expected an armor reader") + } } /// Returns the armored headers. @@ -236,21 +241,20 @@ pub extern "system" fn pgp_armor_reader_kind(reader: *mut Box) /// [this]: fn.pgp_armor_reader_new.html #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_armor_reader_headers(errp: Option<&mut *mut ::error::Error>, - reader: *mut Box, + reader: *mut Reader, len: *mut size_t) -> *mut ArmorHeader { ffi_make_fry_from_errp!(errp); let len = ffi_param_ref_mut!(len); - // We need to downcast `reader`. To do that, we need to do a - // little dance. We will momentarily take ownership of `reader`, - // wrapping it in a Box again. Then, at the end of the function, - // we will leak it again. - let mut reader = ffi_param_move!(reader as *mut Box); + let reader = if let ReaderKind::Armored(ref mut reader) = reader.ref_mut_raw() { + reader + } else { + panic!("FFI contract violation: Wrong parameter type: \ + expected armor reader"); + }; - // We need to be extra careful here in order not to keep ownership - // of `reader` in case of errors. - let result = match reader.headers().map_err(|e| ::failure::Error::from(e)) { + match reader.headers().map_err(|e| ::failure::Error::from(e)) { Ok(headers) => { // Allocate space for the result. let buf = unsafe { @@ -276,11 +280,7 @@ pub extern "system" fn pgp_armor_reader_headers(errp: Option<&mut *mut ::error:: } ptr::null_mut() }, - }; - - // Release temporary ownership. - Box::into_raw(reader); - result + } } /// Constructs a new filter for the given type of data. diff --git a/openpgp-ffi/src/common.rs b/openpgp-ffi/src/common.rs index e6c67db4..45d788e0 100644 --- a/openpgp-ffi/src/common.rs +++ b/openpgp-ffi/src/common.rs @@ -573,8 +573,8 @@ impl VerificationHelper for VHelper { } } -fn verify_real<'a>(input: &'a mut Box<'a + Read>, - dsig: Option<&'a mut Box<'a + Read>>, +fn verify_real<'a>(input: &'a mut Read, + dsig: Option<&mut io::ReaderKind>, output: Option<&'a mut Box<'a + Write>>, get_public_keys: GetPublicKeysCallback, check_signatures: CheckSignaturesCallback, @@ -624,8 +624,8 @@ fn verify_real<'a>(input: &'a mut Box<'a + Read>, /// Note: output may be NULL, if the output is not required. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub fn pgp_verify<'a>(errp: Option<&mut *mut ::error::Error>, - input: *mut Box<'a + Read>, - dsig: Option<&'a mut Box<'a + Read>>, + input: *mut io::Reader, + dsig: Maybe, output: Option<&'a mut Box<'a + Write>>, get_public_keys: GetPublicKeysCallback, check_signatures: CheckSignaturesCallback, @@ -633,9 +633,9 @@ pub fn pgp_verify<'a>(errp: Option<&mut *mut ::error::Error>, -> Status { ffi_make_fry_from_errp!(errp); - let input = ffi_param_ref_mut!(input); + let input = input.ref_mut_raw(); - let r = verify_real(input, dsig, output, + let r = verify_real(input, dsig.ref_mut_raw(), output, get_public_keys, check_signatures, cookie); ffi_try_status!(r) @@ -707,7 +707,7 @@ impl DecryptionHelper for DHelper { // A helper function that returns a Result so that we can use ? to // propagate errors. -fn decrypt_real<'a>(input: &'a mut Box<'a + Read>, +fn decrypt_real<'a>(input: &'a mut io::ReaderKind, output: &'a mut Box<'a + Write>, get_public_keys: GetPublicKeysCallback, get_secret_keys: GetSecretKeysCallback, @@ -747,7 +747,7 @@ fn decrypt_real<'a>(input: &'a mut Box<'a + Read>, /// Note: all of the parameters are required; none may be NULL. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub fn pgp_decrypt<'a>(errp: Option<&mut *mut ::error::Error>, - input: *mut Box<'a + Read>, + input: *mut io::Reader, output: *mut Box<'a + Write>, get_public_keys: GetPublicKeysCallback, get_secret_keys: GetSecretKeysCallback, @@ -756,7 +756,7 @@ pub fn pgp_decrypt<'a>(errp: Option<&mut *mut ::error::Error>, -> Status { ffi_make_fry_from_errp!(errp); - let input = ffi_param_ref_mut!(input); + let input = input.ref_mut_raw(); let output = ffi_param_ref_mut!(output); let r = decrypt_real(input, output, diff --git a/openpgp-ffi/src/io.rs b/openpgp-ffi/src/io.rs index e6ca0eda..42f78558 100644 --- a/openpgp-ffi/src/io.rs +++ b/openpgp-ffi/src/io.rs @@ -9,57 +9,87 @@ use libc::{uint8_t, c_void, c_char, c_int, size_t, ssize_t, realloc}; #[cfg(unix)] use std::os::unix::io::FromRawFd; +extern crate sequoia_openpgp as openpgp; + +use Maybe; + +/// Wraps a generic reader. +#[::ffi_wrapper_type(prefix = "pgp_")] +pub struct Reader(ReaderKind); + +/// Specializes readers. +/// +/// In some cases, we want to call functions on concrete types. To +/// avoid nasty hacks, we have specialized variants for that. +pub(crate) enum ReaderKind { + Generic(Box), + Armored(openpgp::armor::Reader<'static>), +} + +impl Read for ReaderKind { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + use self::ReaderKind::*; + match self { + Generic(ref mut r) => r.read(buf), + Armored(ref mut r) => r.read(buf), + } + } +} + /// Opens a file returning a reader. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_reader_from_file(errp: Option<&mut *mut ::error::Error>, - filename: *const c_char) - -> *mut Box { - ffi_make_fry_from_errp!(errp); + filename: *const c_char) + -> Maybe { let filename = ffi_param_cstr!(filename).to_string_lossy().into_owned(); - ffi_try_box!(File::open(Path::new(&filename)) - .map(|r| Box::new(r)) - .map_err(|e| ::failure::Error::from(e))) + File::open(Path::new(&filename)) + .map(|r| ReaderKind::Generic(Box::new(r))) + .map_err(|e| ::failure::Error::from(e)) + .move_into_raw(errp) } /// Opens a file descriptor returning a reader. #[cfg(unix)] #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_reader_from_fd(fd: c_int) - -> *mut Box { - box_raw!(Box::new(unsafe { File::from_raw_fd(fd) })) + -> *mut Reader { + ReaderKind::Generic(Box::new(unsafe { + File::from_raw_fd(fd) + })).move_into_raw() } /// Creates a reader from a buffer. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_reader_from_bytes(buf: *const uint8_t, - len: size_t) - -> *mut Box { + len: size_t) + -> *mut Reader { assert!(!buf.is_null()); let buf = unsafe { slice::from_raw_parts(buf, len as usize) }; - box_raw!(Box::new(Cursor::new(buf))) -} - -/// Frees a reader. -#[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "system" fn pgp_reader_free(reader: Option<&mut Box>) { - ffi_free!(reader) + ReaderKind::Generic(Box::new(Cursor::new(buf))).move_into_raw() } /// Reads up to `len` bytes into `buf`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_reader_read(errp: Option<&mut *mut ::error::Error>, - reader: *mut Box, - buf: *mut uint8_t, len: size_t) - -> ssize_t { - ffi_make_fry_from_errp!(errp); - let reader = ffi_param_ref_mut!(reader); + reader: *mut Reader, + buf: *mut uint8_t, len: size_t) + -> ssize_t { assert!(!buf.is_null()); let buf = unsafe { slice::from_raw_parts_mut(buf, len as usize) }; - ffi_try_or!(reader.read(buf).map_err(|e| ::failure::Error::from(e)), -1) as ssize_t + reader.ref_mut_raw().read(buf) + .map(|n_read| n_read as ssize_t) + .unwrap_or_else(|e| { + if let Some(errp) = errp { + *errp = ::failure::Error::from(e).move_into_raw(); + }; + + // Signal failure. + -1 + }) } @@ -69,28 +99,28 @@ pub extern "system" fn pgp_reader_read(errp: Option<&mut *mut ::error::Error>, /// otherwise. If you need more control, use `pgp_writer_from_fd`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_writer_from_file(errp: Option<&mut *mut ::error::Error>, - filename: *const c_char) - -> *mut Box { + filename: *const c_char) + -> *mut Box { ffi_make_fry_from_errp!(errp); let filename = ffi_param_cstr!(filename).to_string_lossy().into_owned(); ffi_try_box!(File::create(Path::new(&filename)) - .map(|r| Box::new(r)) - .map_err(|e| ::failure::Error::from(e))) + .map(|r| Box::new(r)) + .map_err(|e| ::failure::Error::from(e))) } /// Opens a file descriptor returning a writer. #[cfg(unix)] #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_writer_from_fd(fd: c_int) - -> *mut Box { + -> *mut Box { box_raw!(Box::new(unsafe { File::from_raw_fd(fd) })) } /// Creates a writer from a buffer. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_writer_from_bytes(buf: *mut uint8_t, - len: size_t) - -> *mut Box { + len: size_t) + -> *mut Box { assert!(!buf.is_null()); let buf = unsafe { slice::from_raw_parts_mut(buf, len as usize) @@ -108,8 +138,8 @@ pub extern "system" fn pgp_writer_from_bytes(buf: *mut uint8_t, /// destroyed. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_writer_alloc(buf: *mut *mut c_void, - len: *mut size_t) - -> *mut Box { + len: *mut size_t) + -> *mut Box { let buf = ffi_param_ref_mut!(buf); let len = ffi_param_ref_mut!(len); @@ -161,9 +191,9 @@ pub extern "system" fn pgp_writer_free(writer: Option<&mut Box>) { /// Writes up to `len` bytes of `buf` into `writer`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_writer_write(errp: Option<&mut *mut ::error::Error>, - writer: *mut Box, - buf: *const uint8_t, len: size_t) - -> ssize_t { + writer: *mut Box, + buf: *const uint8_t, len: size_t) + -> ssize_t { ffi_make_fry_from_errp!(errp); let writer = ffi_param_ref_mut!(writer); assert!(!buf.is_null()); diff --git a/openpgp-ffi/src/parse.rs b/openpgp-ffi/src/parse.rs index 3cdba933..d3a1567a 100644 --- a/openpgp-ffi/src/parse.rs +++ b/openpgp-ffi/src/parse.rs @@ -9,7 +9,6 @@ use std::mem::forget; use std::ptr; use std::slice; -use std::io::Read; use libc::{uint8_t, c_char, c_int, size_t}; extern crate sequoia_openpgp as openpgp; @@ -25,8 +24,10 @@ use self::openpgp::parse::{ PacketParserEOF, }; +use super::io::Reader; use error::Status; use MoveIntoRaw; +use RefMutRaw; /// Starts parsing OpenPGP packets stored in a `pgp_reader_t` /// object. @@ -35,10 +36,10 @@ use MoveIntoRaw; /// the stream. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "system" fn pgp_packet_parser_from_reader<'a> - (errp: Option<&mut *mut ::error::Error>, reader: *mut Box<'a + Read>) + (errp: Option<&mut *mut ::error::Error>, reader: *mut Reader) -> *mut PacketParserResult<'a> { ffi_make_fry_from_errp!(errp); - let reader = ffi_param_ref_mut!(reader); + let reader = reader.ref_mut_raw(); ffi_try_box!(PacketParser::from_reader(reader)) } -- cgit v1.2.3