Skip to content

Commit 2116b70

Browse files
committed
Complete merge of clamav-sys from separate repo
2 parents c48146a + 8c7a3ff commit 2116b70

File tree

8 files changed

+833
-3
lines changed

8 files changed

+833
-3
lines changed

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
[workspace]
22

3-
members = [
4-
"libclamav_rust",
5-
]
3+
members = ["clamav-sys", "libclamav_rust"]
64

75
[profile.dev.package."*"]
86
opt-level = 2

clamav-sys/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
Cargo.lock

clamav-sys/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
authors = [
3+
"Jonas Zaddach <[email protected]>",
4+
"Scott Hutton <[email protected]>",
5+
]
6+
categories = ["external-ffi-bindings"]
7+
description = "ClamAV low level bindings for Rust"
8+
edition = "2021"
9+
homepage = "https://github.com/Cisco-Talos/clamav-sys/"
10+
license = "GPL-2.0"
11+
name = "clamav-sys"
12+
repository = "https://github.com/Cisco-Talos/clamav-sys/"
13+
version = "1.0.0"
14+
15+
[build-dependencies]
16+
bindgen = "0.64.0"
17+
18+
[target.'cfg(unix)'.build-dependencies]
19+
pkg-config = "0.3"
20+
21+
[target.'cfg(windows)'.build-dependencies]
22+
vcpkg = "0.2.10"

clamav-sys/LICENSE

Lines changed: 339 additions & 0 deletions
Large diffs are not rendered by default.

clamav-sys/README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# clamav-sys
2+
3+
clamav-sys is a minimal Rust interface around [libclamav](https://www.clamav.net).
4+
This package is not supposed to be used stand-alone, but only through its safe wrapper,
5+
clamav-rs.
6+
7+
8+
## Building
9+
10+
### Unix (anything but Windows)
11+
You should have the `clamav-dev` package of your distribution installed (ClamAV
12+
with headers). The headers and library should be picked up automatically via
13+
pkg-config.
14+
15+
### Windows
16+
#### vcpkg
17+
The preferred way of handling dependencies is `vcpkg`.
18+
Point `$env:VCPKG_ROOT` to your `vcpkg` installation, and set
19+
`$env:VCPKGRS_DYNAMIC=1` to use dynamic linking (the default method of linking will
20+
likely not work, as `pdcurses` doesn't support the `x64-windows-static-md` triplet).
21+
22+
See the [vcpkg crate's documentation](https://docs.rs/vcpkg) for more details.
23+
24+
Gotchas:
25+
- Windows has its own version of a zlib dll that is incompatbile with vcpkg. If
26+
you get a message such as "The procedure entry point gzdirect could not be
27+
located in the dynamic link library", you'll want to make sure that the vcpkg
28+
dynamic libraries in your PATH variable are preceding the Windows one.
29+
```
30+
$env:PATH="$env:VCPKG_ROOT\installed\x64-windows\bin\;$env:PATH"
31+
```
32+
This error is especially hard to diagnose in PowerShell, as the process will
33+
just hang without any output. In cmd.exe you'll get the aforementioned dialog
34+
box telling you about the error.
35+
36+
37+
#### Manual
38+
If `vcpkg` is not available or cannot be found on your system, the build defaults
39+
to a manual specification of dependencies.
40+
You will need to define the following environment variables:
41+
- `CLAMAV_SOURCE`: Points to the directory where the ClamAV source is located.
42+
- `CLAMAV_BUILD`: Points to the ClamAV build directory.
43+
- `OPENSSL_INCLUDE`: Points to the include directory containing `openssl/ssl.h`.
44+
45+
### MacOS
46+
Install the development dependencies via `homebrew`:
47+
```
48+
brew install clamav [email protected]
49+
```
50+
51+
OpenSSL is not included in the environment to avoid shadowing Apple's one, so
52+
you need to tell the build script where it is located:
53+
```
54+
export OPENSSL_ROOT_DIR=/usr/local/Cellar/[email protected]/1.1.1i/
55+
```
56+
57+
## Versioning
58+
The version number of `libclamav-sys` tracks ClamAV's version number. That is,
59+
you'll require at least ClamAV 1.0.0 to build `libclamav-sys` 1.0.0. As ClamAV
60+
usually doesn't do breaking API changes, you'll be able to use `libclamav-sys`
61+
with newer ClamAV versions.
62+
63+
No attempt at preserving downward compatibility (using a `libclamav-sys` with
64+
a version number greater than ClamAV's) is made.

clamav-sys/build.rs

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
// Copyright (C) 2020-2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
2+
//
3+
// Authors: Jonas Zaddach, Scott Hutton
4+
//
5+
// This program is free software; you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License version 2 as
7+
// published by the Free Software Foundation.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program; if not, write to the Free Software
16+
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17+
// MA 02110-1301, USA.
18+
19+
use std::env;
20+
use std::path::PathBuf;
21+
22+
// Generate bindings for these functions:
23+
const BINDGEN_FUNCTIONS: &[&str] = &[
24+
"cl_cleanup_crypto",
25+
"cl_cvdfree",
26+
"cl_cvdparse",
27+
"cl_debug",
28+
"cl_engine_addref",
29+
"cl_engine_compile",
30+
"cl_engine_free",
31+
"cl_engine_get_num",
32+
"cl_engine_get_str",
33+
"cl_engine_new",
34+
"cl_engine_set_clcb_engine_compile_progress",
35+
"cl_engine_set_clcb_engine_free_progress",
36+
"cl_engine_set_clcb_file_inspection",
37+
"cl_engine_set_clcb_file_props",
38+
"cl_engine_set_clcb_hash",
39+
"cl_engine_set_clcb_meta",
40+
"cl_engine_set_clcb_post_scan",
41+
"cl_engine_set_clcb_pre_cache",
42+
"cl_engine_set_clcb_pre_scan",
43+
"cl_engine_set_clcb_sigload",
44+
"cl_engine_set_clcb_sigload_progress",
45+
"cl_engine_set_clcb_stats_add_sample",
46+
"cl_engine_set_clcb_stats_decrement_count",
47+
"cl_engine_set_clcb_stats_flush",
48+
"cl_engine_set_clcb_stats_get_hostid",
49+
"cl_engine_set_clcb_stats_get_num",
50+
"cl_engine_set_clcb_stats_get_size",
51+
"cl_engine_set_clcb_stats_remove_sample",
52+
"cl_engine_set_clcb_stats_submit",
53+
"cl_engine_set_clcb_virus_found",
54+
"cl_engine_set_num",
55+
"cl_engine_set_stats_set_cbdata",
56+
"cl_engine_set_str",
57+
"cl_engine_settings_apply",
58+
"cl_engine_settings_copy",
59+
"cl_engine_settings_free",
60+
"cl_engine_stats_enable",
61+
"cl_fmap_close",
62+
"cl_fmap_open_handle",
63+
"cl_fmap_open_memory",
64+
"cl_init",
65+
"cl_initialize_crypto",
66+
"cl_load",
67+
"cl_retdbdir",
68+
"cl_retflevel",
69+
"cl_retver",
70+
"cl_scandesc",
71+
"cl_scandesc_callback",
72+
"cl_scanfile",
73+
"cl_scanfile_callback",
74+
"cl_scanmap_callback",
75+
"cl_set_clcb_msg",
76+
"cl_strerror",
77+
"cli_append_virus",
78+
"cli_ctx",
79+
"cli_dbgmsg_no_inline",
80+
"cli_errmsg",
81+
"cli_get_debug_flag",
82+
"cli_getdsig",
83+
"cli_infomsg_simple",
84+
"cli_versig2",
85+
"cli_warnmsg",
86+
"lsig_increment_subsig_match",
87+
];
88+
89+
// Generate bindings for these types (structs, prototypes, etc.):
90+
const BINDGEN_TYPES: &[&str] = &[
91+
"cl_cvd",
92+
"clcb_file_props",
93+
"clcb_meta",
94+
"clcb_post_scan",
95+
"clcb_pre_scan",
96+
"cli_ac_data",
97+
"cli_ac_result",
98+
"cli_matcher",
99+
"time_t",
100+
];
101+
102+
// Generate "newtype" enums for these C enums
103+
const BINDGEN_ENUMS: &[&str] = &["cl_engine_field", "cl_error_t", "cl_msg"];
104+
105+
const BINDGEN_CONSTANTS: &[&str] = &[
106+
"CL_DB_.*",
107+
"CL_INIT_DEFAULT",
108+
"CL_SCAN_.*",
109+
"ENGINE_OPTIONS_.*",
110+
"LAYER_ATTRIBUTES_.*",
111+
];
112+
113+
const CLAMAV_LIBRARY_NAME: &str = "clamav";
114+
115+
fn generate_bindings(customize_bindings: &dyn Fn(bindgen::Builder) -> bindgen::Builder) {
116+
let mut bindings = bindgen::Builder::default();
117+
for function in BINDGEN_FUNCTIONS {
118+
bindings = bindings.allowlist_function(function);
119+
}
120+
121+
for typename in BINDGEN_TYPES {
122+
bindings = bindings.allowlist_type(typename);
123+
}
124+
125+
for typename in BINDGEN_ENUMS {
126+
bindings = bindings.newtype_enum(typename);
127+
}
128+
129+
for constant in BINDGEN_CONSTANTS {
130+
bindings = bindings.allowlist_var(constant);
131+
}
132+
133+
bindings = bindings
134+
.header("wrapper.h")
135+
// Tell cargo to invalidate the built crate whenever any of the
136+
// included header files changed.
137+
.parse_callbacks(Box::new(bindgen::CargoCallbacks));
138+
139+
bindings = customize_bindings(bindings);
140+
141+
// Write the bindings to the $OUT_DIR/bindings.rs file.
142+
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
143+
144+
bindings
145+
// Finish the builder and generate the bindings.
146+
.generate()
147+
// Unwrap the Result and panic on failure.
148+
.expect("Unable to generate bindings")
149+
.write_to_file(out_path.join("bindings.rs"))
150+
.expect("Couldn't write bindings!");
151+
}
152+
153+
fn cargo_common() {
154+
println!("cargo:rustc-link-lib=dylib={}", CLAMAV_LIBRARY_NAME);
155+
156+
// Tell cargo to invalidate the built crate whenever the wrapper changes
157+
println!("cargo:rerun-if-changed=wrapper.h");
158+
}
159+
160+
#[cfg(windows)]
161+
fn main() {
162+
let include_paths = match vcpkg::find_package("clamav") {
163+
Ok(pkg) => pkg.include_paths,
164+
Err(err) => {
165+
println!(
166+
"cargo:warning=Either vcpkg is not installed, or an error occurred in vcpkg: {}",
167+
err
168+
);
169+
let clamav_source = PathBuf::from(env::var("CLAMAV_SOURCE").expect("CLAMAV_SOURCE environment variable must be set and point to ClamAV's source directory"));
170+
let clamav_build = PathBuf::from(env::var("CLAMAV_BUILD").expect("CLAMAV_BUILD environment variable must be set and point to ClamAV's build directory"));
171+
let openssl_include = PathBuf::from(env::var("OPENSSL_INCLUDE").expect("OPENSSL_INCLUDE environment variable must be set and point to openssl's include directory"));
172+
let profile = env::var("PROFILE").unwrap();
173+
174+
let library_path = match profile.as_str() {
175+
"debug" => std::path::Path::new(&clamav_build).join("libclamav/Debug"),
176+
"release" => std::path::Path::new(&clamav_build).join("libclamav/Release"),
177+
_ => panic!("Unexpected build profile"),
178+
};
179+
180+
println!(
181+
"cargo:rustc-link-search=native={}",
182+
library_path.to_str().unwrap()
183+
);
184+
185+
vec![
186+
clamav_source.join("libclamav"),
187+
clamav_build,
188+
openssl_include,
189+
]
190+
}
191+
};
192+
193+
cargo_common();
194+
generate_bindings(&|x: bindgen::Builder| -> bindgen::Builder {
195+
let mut x = x;
196+
for include_path in &include_paths {
197+
x = x.clang_arg("-I").clang_arg(include_path.to_str().unwrap());
198+
}
199+
x
200+
});
201+
}
202+
203+
#[cfg(unix)]
204+
fn main() {
205+
let libclamav = pkg_config::Config::new()
206+
.atleast_version("0.103")
207+
.probe("libclamav")
208+
.unwrap();
209+
210+
let mut include_paths = libclamav.include_paths;
211+
212+
if let Some(val) = std::env::var_os("OPENSSL_ROOT_DIR") {
213+
let mut openssl_include_dir = PathBuf::from(val);
214+
openssl_include_dir.push("include");
215+
include_paths.push(openssl_include_dir);
216+
}
217+
218+
cargo_common();
219+
generate_bindings(&|x: bindgen::Builder| -> bindgen::Builder {
220+
let mut x = x;
221+
for include_path in &include_paths {
222+
x = x.clang_arg("-I").clang_arg(include_path.to_str().unwrap());
223+
}
224+
x
225+
});
226+
}

0 commit comments

Comments
 (0)