windivert-sys 0.10.0

Raw FFI bindings for WinDivert user mode library
Documentation
mod compile;

use std::{env, fs};

pub const LIB_PATH_ARG: &str = "WINDIVERT_PATH";
pub const DLL_OUTPUT_PATH_ARG: &str = "WINDIVERT_DLL_OUTPUT";
pub const STATIC_BUILD_ARG: &str = "WINDIVERT_STATIC";

fn main() {
    // Avoid build in docs.rs
    if env::var("DOCS_RS").is_ok() {
        return;
    }

    let out_dir = env::var("OUT_DIR").unwrap();
    println!("cargo:rerun-if-env-changed={LIB_PATH_ARG}");
    println!("cargo:rerun-if-env-changed={DLL_OUTPUT_PATH_ARG}");
    println!("cargo:rerun-if-env-changed={STATIC_BUILD_ARG}");

    let arch = match env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_ref() {
        "x86" => "32",
        "x86_64" => "64",
        _ => panic!("Unsupported target architecture!"),
    };

    // Prioritize environment variables over feature flags
    if env::var(STATIC_BUILD_ARG).is_ok() || cfg!(feature = "static") {
        println!("cargo:rerun-if-changed=wrapper.h");
        compile::lib();

        println!(
            "cargo:warning=WinDivert{arch}.sys must be located in the same path as the executable."
        )
    } else if let Ok(lib_path) = env::var(LIB_PATH_ARG) {
        println!("cargo:rustc-link-search=native={lib_path}");
        println!("cargo:rustc-link-search=native={out_dir}");
        println!("cargo:rustc-link-lib=dylib=WinDivert");
        handle_provided_dll(arch, &out_dir, &lib_path);
    } else if cfg!(feature = "vendored") {
        println!("cargo:rerun-if-changed=wrapper.h");
        println!("cargo:rustc-link-search=native={out_dir}");
        println!("cargo:rustc-link-lib=dylib=WinDivert");
        compile::dll();
    } else {
        panic!("Environment variable {LIB_PATH_ARG} not found and feature vendored not enabled, please provide the path to the WinDivert library files or enable the vendored feature to compile from source.");
    }
}

fn handle_provided_dll(arch: &str, out_dir: &str, lib_path: &str) {
    println!(
        "cargo:warning=Copying windivert dll, lib & sys files from the path provided if present."
    );
    for f in fs::read_dir(lib_path).unwrap() {
        let file = f.unwrap();
        if let Some(name) = file.file_name().to_str() {
            match name {
                "WinDivert.dll" | "WinDivert.lib" | "WinDivert32.sys" | "WinDivert64.sys" => {
                    let _ = fs::copy(file.path(), format!("{out_dir}/{name}"));
                }
                _ => {}
            }
        }
    }

    if fs::metadata(format!("{lib_path}\\WinDivert{arch}.sys")).is_err() {
        println!("cargo:warning=WinDivert{arch}.sys not found on the same directory as the dll.")
    }
}