magic_sys/
lib.rs

1// Technically this crate doesn't need Rust `std`
2// but you'll still have to get the `libmagic` C library working for your target
3#![cfg_attr(not(test), no_std)]
4
5extern crate libc;
6#[cfg(feature = "v5-20")]
7use libc::c_void;
8use libc::{c_char, c_int, size_t};
9
10// `libmagic` API as in "magic.h"
11
12#[allow(non_camel_case_types)]
13// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
14#[repr(C)]
15pub struct magic_set {
16    _data: [u8; 0],
17    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
18}
19
20#[allow(non_camel_case_types)]
21pub type magic_t = *mut magic_set;
22
23pub const MAGIC_NONE: c_int = 0x000_0000;
24pub const MAGIC_DEBUG: c_int = 0x000_0001;
25pub const MAGIC_SYMLINK: c_int = 0x000_0002;
26pub const MAGIC_COMPRESS: c_int = 0x000_0004;
27pub const MAGIC_DEVICES: c_int = 0x000_0008;
28pub const MAGIC_MIME_TYPE: c_int = 0x000_0010;
29pub const MAGIC_CONTINUE: c_int = 0x000_0020;
30pub const MAGIC_CHECK: c_int = 0x000_0040;
31pub const MAGIC_PRESERVE_ATIME: c_int = 0x000_0080;
32pub const MAGIC_RAW: c_int = 0x000_0100;
33pub const MAGIC_ERROR: c_int = 0x000_0200;
34pub const MAGIC_MIME_ENCODING: c_int = 0x000_0400;
35pub const MAGIC_MIME: c_int = MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING;
36pub const MAGIC_APPLE: c_int = 0x00_0800;
37#[cfg(feature = "v5-23")]
38pub const MAGIC_EXTENSION: c_int = 0x100_0000;
39#[cfg(feature = "v5-23")]
40pub const MAGIC_COMPRESS_TRANSP: c_int = 0x200_0000;
41#[cfg(feature = "v5-23")]
42pub const MAGIC_NODESC: c_int = MAGIC_EXTENSION | MAGIC_MIME | MAGIC_APPLE;
43
44pub const MAGIC_NO_CHECK_COMPRESS: c_int = 0x000_1000;
45pub const MAGIC_NO_CHECK_TAR: c_int = 0x000_2000;
46pub const MAGIC_NO_CHECK_SOFT: c_int = 0x000_4000;
47pub const MAGIC_NO_CHECK_APPTYPE: c_int = 0x000_8000;
48pub const MAGIC_NO_CHECK_ELF: c_int = 0x001_0000;
49pub const MAGIC_NO_CHECK_TEXT: c_int = 0x002_0000;
50pub const MAGIC_NO_CHECK_CDF: c_int = 0x004_0000;
51#[cfg(feature = "v5-38")]
52pub const MAGIC_NO_CHECK_CSV: c_int = 0x008_0000;
53pub const MAGIC_NO_CHECK_TOKENS: c_int = 0x010_0000;
54pub const MAGIC_NO_CHECK_ENCODING: c_int = 0x020_0000;
55#[cfg(feature = "v5-35")]
56pub const MAGIC_NO_CHECK_JSON: c_int = 0x040_0000;
57
58#[cfg(all(feature = "v5-05", not(feature = "v5-10")))]
59pub const MAGIC_NO_CHECK_BUILTIN: c_int = 0x3f_b000;
60#[cfg(all(feature = "v5-10", not(feature = "v5-35")))]
61pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
62MAGIC_NO_CHECK_TAR      |
63// MAGIC_NO_CHECK_SOFT  |
64MAGIC_NO_CHECK_APPTYPE  |
65MAGIC_NO_CHECK_ELF      |
66MAGIC_NO_CHECK_TEXT     |
67MAGIC_NO_CHECK_CDF      |
68MAGIC_NO_CHECK_TOKENS   |
69MAGIC_NO_CHECK_ENCODING;
70#[cfg(all(feature = "v5-35", not(feature = "v5-38")))]
71pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
72MAGIC_NO_CHECK_TAR      |
73// MAGIC_NO_CHECK_SOFT  |
74MAGIC_NO_CHECK_APPTYPE  |
75MAGIC_NO_CHECK_ELF      |
76MAGIC_NO_CHECK_TEXT     |
77MAGIC_NO_CHECK_CDF      |
78MAGIC_NO_CHECK_TOKENS   |
79MAGIC_NO_CHECK_ENCODING |
80MAGIC_NO_CHECK_JSON;
81#[cfg(feature = "v5-38")]
82pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
83MAGIC_NO_CHECK_TAR      |
84// MAGIC_NO_CHECK_SOFT  |
85MAGIC_NO_CHECK_APPTYPE  |
86MAGIC_NO_CHECK_ELF      |
87MAGIC_NO_CHECK_TEXT     |
88MAGIC_NO_CHECK_CSV      |
89MAGIC_NO_CHECK_CDF      |
90MAGIC_NO_CHECK_TOKENS   |
91MAGIC_NO_CHECK_ENCODING |
92MAGIC_NO_CHECK_JSON;
93
94#[deprecated]
95pub const MAGIC_NO_CHECK_ASCII: c_int = MAGIC_NO_CHECK_TEXT;
96
97#[deprecated]
98pub const MAGIC_NO_CHECK_FORTRAN: c_int = 0x00_0000;
99#[deprecated]
100pub const MAGIC_NO_CHECK_TROFF: c_int = 0x00_0000;
101
102// TODO: MAGIC_VERSION string
103
104// TODO: MAGIC_SNPRINTB bytes
105
106#[cfg(feature = "v5-21")]
107pub const MAGIC_PARAM_INDIR_MAX: c_int = 0;
108#[cfg(feature = "v5-21")]
109pub const MAGIC_PARAM_NAME_MAX: c_int = 1;
110#[cfg(feature = "v5-21")]
111pub const MAGIC_PARAM_ELF_PHNUM_MAX: c_int = 2;
112#[cfg(feature = "v5-21")]
113pub const MAGIC_PARAM_ELF_SHNUM_MAX: c_int = 3;
114#[cfg(feature = "v5-22")]
115pub const MAGIC_PARAM_ELF_NOTES_MAX: c_int = 4;
116#[cfg(feature = "v5-25")]
117pub const MAGIC_PARAM_REGEX_MAX: c_int = 5;
118#[cfg(feature = "v5-27")]
119pub const MAGIC_PARAM_BYTES_MAX: c_int = 6;
120#[cfg(feature = "v5-40")]
121pub const MAGIC_PARAM_ENCODING_MAX: c_int = 7;
122
123// NOTE: the following are from `file.h`, but part of `magic.h` API
124#[cfg(feature = "v5-04")]
125pub const FILE_LOAD: c_int = 0;
126#[cfg(feature = "v5-04")]
127pub const FILE_CHECK: c_int = 1;
128#[cfg(feature = "v5-04")]
129pub const FILE_COMPILE: c_int = 2;
130#[cfg(feature = "v5-05")]
131pub const FILE_LIST: c_int = 3;
132
133extern "C" {
134    pub fn magic_open(flags: c_int) -> magic_t;
135    pub fn magic_close(cookie: magic_t);
136
137    #[cfg(feature = "v5-04")]
138    pub fn magic_getpath(magicfile: *const c_char, action: c_int) -> *const c_char;
139    pub fn magic_file(cookie: magic_t, filename: *const c_char) -> *const c_char;
140    pub fn magic_descriptor(cookie: magic_t, fd: c_int) -> *const c_char;
141    pub fn magic_buffer(cookie: magic_t, buffer: *const u8, length: size_t) -> *const c_char;
142
143    pub fn magic_error(cookie: magic_t) -> *const c_char;
144    #[cfg(feature = "v5-32")]
145    pub fn magic_getflags(cookie: magic_t) -> c_int;
146    #[must_use]
147    pub fn magic_setflags(cookie: magic_t, flags: c_int) -> c_int;
148
149    #[cfg(feature = "v5-13")]
150    pub fn magic_version() -> c_int;
151    #[must_use]
152    pub fn magic_load(cookie: magic_t, filename: *const c_char) -> c_int;
153    #[cfg(feature = "v5-20")]
154    #[must_use]
155    pub fn magic_load_buffers(
156        cookie: magic_t,
157        buffers: *mut *mut c_void,
158        sizes: *mut size_t,
159        nbuffers: size_t,
160    ) -> c_int;
161
162    #[must_use]
163    pub fn magic_compile(cookie: magic_t, filename: *const c_char) -> c_int;
164    #[must_use]
165    pub fn magic_check(cookie: magic_t, filename: *const c_char) -> c_int;
166    #[cfg(feature = "v5-05")]
167    #[must_use]
168    pub fn magic_list(cookie: magic_t, filename: *const c_char) -> c_int;
169    pub fn magic_errno(cookie: magic_t) -> c_int;
170
171    #[cfg(feature = "v5-21")]
172    #[must_use]
173    pub fn magic_setparam(cookie: magic_t, param: c_int, value: *const c_void) -> c_int;
174    #[cfg(feature = "v5-21")]
175    #[must_use]
176    pub fn magic_getparam(cookie: magic_t, param: c_int, value: *mut c_void) -> c_int;
177}
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182
183    // Those tests are mostly just sanity checks to see if linkage works,
184    // they are NOT testing `libmagic` API/implementation
185
186    #[test]
187    fn test_magic_open() {
188        unsafe {
189            magic_open(MAGIC_NONE);
190        }
191    }
192
193    #[test]
194    fn test_magic_close() {
195        unsafe {
196            magic_close(std::ptr::null_mut());
197        }
198    }
199
200    #[cfg(feature = "v5-04")]
201    #[test]
202    fn test_magic_getpath() {
203        unsafe {
204            magic_getpath(std::ptr::null(), FILE_CHECK);
205        }
206    }
207
208    #[test]
209    fn test_magic_file() {
210        unsafe {
211            magic_file(std::ptr::null_mut(), std::ptr::null());
212        }
213    }
214
215    #[test]
216    fn test_magic_descriptor() {
217        unsafe {
218            magic_descriptor(std::ptr::null_mut(), -1);
219        }
220    }
221
222    #[test]
223    fn test_magic_buffer() {
224        unsafe {
225            magic_buffer(std::ptr::null_mut(), std::ptr::null(), 0);
226        }
227    }
228
229    #[test]
230    fn test_magic_error() {
231        unsafe {
232            magic_error(std::ptr::null_mut());
233        }
234    }
235
236    #[cfg(feature = "v5-32")]
237    #[test]
238    fn test_magic_getflags() {
239        unsafe {
240            magic_getflags(std::ptr::null_mut());
241        }
242    }
243
244    #[test]
245    fn test_magic_setflags() {
246        unsafe {
247            let _ = magic_setflags(std::ptr::null_mut(), MAGIC_NONE);
248        }
249    }
250
251    #[cfg(feature = "v5-13")]
252    #[test]
253    fn test_magic_version() {
254        unsafe {
255            magic_version();
256        }
257    }
258
259    #[test]
260    fn test_magic_load() {
261        unsafe {
262            let _ = magic_load(std::ptr::null_mut(), std::ptr::null());
263        }
264    }
265
266    #[cfg(feature = "v5-20")]
267    #[test]
268    fn test_magic_load_buffers() {
269        unsafe {
270            let _ = magic_load_buffers(
271                std::ptr::null_mut(),
272                std::ptr::null_mut(),
273                std::ptr::null_mut(),
274                0,
275            );
276        }
277    }
278
279    #[test]
280    fn test_magic_compile() {
281        unsafe {
282            let _ = magic_compile(std::ptr::null_mut(), std::ptr::null());
283        }
284    }
285
286    #[test]
287    fn test_magic_check() {
288        unsafe {
289            let _ = magic_check(std::ptr::null_mut(), std::ptr::null());
290        }
291    }
292
293    #[cfg(feature = "v5-05")]
294    #[test]
295    fn test_magic_list() {
296        unsafe {
297            let _ = magic_list(std::ptr::null_mut(), std::ptr::null());
298        }
299    }
300
301    #[test]
302    fn test_magic_errno() {
303        unsafe {
304            magic_errno(std::ptr::null_mut());
305        }
306    }
307
308    #[cfg(feature = "v5-21")]
309    #[test]
310    fn test_magic_setparam() {
311        unsafe {
312            let _ = magic_setparam(
313                std::ptr::null_mut(),
314                MAGIC_PARAM_INDIR_MAX,
315                std::ptr::null(),
316            );
317        }
318    }
319
320    #[cfg(feature = "v5-21")]
321    #[test]
322    fn test_magic_getparam() {
323        unsafe {
324            let _ = magic_getparam(
325                std::ptr::null_mut(),
326                MAGIC_PARAM_INDIR_MAX,
327                std::ptr::null_mut(),
328            );
329        }
330    }
331}