diff --git a/Cargo.toml b/Cargo.toml index 8c530db..ab751aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ smallvec = {version = "1.6", features=["union"], optional = true} tokio = {version = "0.2", optional = true} [build-dependencies] +cc = "1.0.68" rustc_version = "0.2" [dev-dependencies] diff --git a/build.rs b/build.rs index 6cb813f..2072ec2 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,35 @@ extern crate rustc_version; +extern crate cc; + +use std::path::Path; use rustc_version::{version, version_meta, Channel}; +const FFI_SRC_DIR: &str = "src/ffi"; + +fn build_cookie_wrapper(floc: impl AsRef) +{ + let mut builder = cc::Build::new(); + // --std=c99 -W -Wall -Werror -pedantic -O3 -flto + builder.flag("--std=c11") + .flag("-W") + .flag("-Wall") + .flag_if_supported("-Wextra") + .flag("-Werror") + .flag("-pedantic") + .include("include/") + .opt_level(3) + .flag_if_supported("-flto") + + // Not sure if we want these two. We can check the codegen later. + .pic(false) + .use_plt(false) + + .file(Path::new(FFI_SRC_DIR).join(floc)) + .compile("cwrapper"); +} + fn main() { // Assert we haven't travelled back in time assert!(version().unwrap().major >= 1); @@ -22,4 +49,6 @@ fn main() { println!("cargo:rustc-cfg=dev"); } } + + build_cookie_wrapper("wrapper.c"); } diff --git a/include/cc20.h b/include/cc20.h index 75be682..9484ac6 100644 --- a/include/cc20.h +++ b/include/cc20.h @@ -1,5 +1,7 @@ #ifndef _CC20_H #define _CC20_H +#include +#include #define KEY_SIZE 32 #define IV_SIZE 12 @@ -12,12 +14,12 @@ enum cc20_mode { typedef uint8_t cc20_key_t[KEY_SIZE]; typedef uint8_t cc20_iv_t[IV_SIZE]; -struct cc20_metadata { +typedef struct cc20_metadata { FILE* backing; cc20_key_t key; cc20_iv_t iv; enum cc20_mode mode; -}; +} cc20_meta_t; typedef struct cc20_sink cc20_sink_t; @@ -28,14 +30,19 @@ int cc20_gen_meta(FILE* file, struct cc20_metadata* restrict output); cc20_sink_t* cc20_gen_sink(const struct cc20_metadata* meta); + cc20_sink_t* cc20_gen_sink_full(FILE* file, const cc20_key_t* key, const cc20_iv_t* iv, enum cc20_mode mode); -FILE* cc20_wrap(FILE* file, + +FILE* cc20_wrap_full(FILE* file, const cc20_key_t* key, const cc20_iv_t* iv, enum cc20_mode mode); + +FILE* cc20_gen(const struct cc20_metadata* meta); + int cc20_close_sink(cc20_sink_t* sink, struct cc20_metadata* restrict meta); diff --git a/src/ffi.rs b/src/ffi.rs index f452987..e3bdcbc 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -53,6 +53,7 @@ pub enum CMode } mod interop; +mod cookie; mod error; pub use error::*; @@ -127,8 +128,18 @@ pub use error::*; }; cc20_gen_sink(&meta as *const _) } + +#[no_mangle] pub unsafe extern "C" fn cc20_gen(meta: *const CPassthrough) -> *mut libc::FILE +{ + let sink = cc20_gen_sink(meta); + if sink.is_null() { + return ptr::null_mut(); + } + cc20_wrap_sink(sink) +} + /// Create a wrapper `FILE*` that acts as a `Sink` when written to. -#[no_mangle] pub unsafe extern "C" fn cc20_wrap(file: *mut libc::FILE, key: *const Key, iv: *const IV, mode: CMode) -> *mut libc::FILE +#[no_mangle] pub unsafe extern "C" fn cc20_wrap_full(file: *mut libc::FILE, key: *const Key, iv: *const IV, mode: CMode) -> *mut libc::FILE { // No need to `no_unwind` this, nothing here can panic. let csink = cc20_gen_sink_full(file, key, iv, mode); @@ -153,7 +164,8 @@ pub use error::*; /// Convert a `Sink` into a `FILE*`. #[no_mangle] pub unsafe extern "C" fn cc20_wrap_sink(sink: *mut CSink) -> *mut libc::FILE { - todo!("Create a Custom Stream in `wrapper.c` that allows creating a FILE* object from `sink`.") + //todo!("Create a Custom Stream in `wrapper.c` that allows creating a FILE* object from `sink`.") + cookie::create(sink) } impl Write for CPassthrough diff --git a/src/ffi/cookie.rs b/src/ffi/cookie.rs new file mode 100644 index 0000000..7e71d1f --- /dev/null +++ b/src/ffi/cookie.rs @@ -0,0 +1,12 @@ +use super::*; +use libc::{c_void, FILE}; + +//FILE* _cc20c_create(cc20_sink_t* restrict sink) +extern "C" { + fn _cc20c_create(sink: *mut c_void) -> *mut FILE; +} + +#[inline(always)] pub unsafe fn create(raw_sink: *mut CSink) -> *mut FILE +{ + _cc20c_create(raw_sink as *mut c_void) +} diff --git a/src/ffi/wrapper.c b/src/ffi/wrapper.c new file mode 100644 index 0000000..81f0699 --- /dev/null +++ b/src/ffi/wrapper.c @@ -0,0 +1,50 @@ +#define _GNU_SOURCE +#include +#include +#include + +#include + +#define IGNORE(v) ((void)(v)) + +static ssize_t cc20c_read(void* cookie, char* buffer, size_t size) +{ + IGNORE(cookie); + IGNORE(buffer); + IGNORE(size); + + return -1; +} + +static ssize_t cc20c_write(void* cookie, const char* buffer, size_t size) +{ + return cc20_write(buffer, 1, size, cookie); +} + +static int cc20c_seek(void* cookie, off64_t* pos, int w) +{ + IGNORE(cookie); + IGNORE(pos); + IGNORE(w); + + return -1; +} + +static int cc20c_close(void* cookie) +{ + struct cc20_metadata meta; + cc20_close_sink(cookie, &meta); + if(meta.backing) fclose(meta.backing); + else return 1; + return 0; +} + +FILE* _cc20c_create(cc20_sink_t* restrict sink) +{ + return fopencookie(sink, "wb", (cookie_io_functions_t){ + .read = &cc20c_read, + .write = &cc20c_write, + .seek = &cc20c_seek, + .close = &cc20c_close, + }); +}