mojique
mojique implements a safe Rust wrapper around libmagic, providing a
Send-safe Handle into the library, along with an optional Pool that can
be used to provide thread-safe access to libmagic.
Basic usage
It's probably easiest to look at the documentation, but if you want a very basic example just to get a taste of the API, here's how to detect the type of a path given as a command line argument:
use PathBuf;
use ;
FAQ
(Nobody's actually asked any questions yet, but here are the questions I expect to be asked eventually if this sees any real use.)
Why not magic?
The venerable magic crate has existed for over a decade, and also
provides a safe wrapper around libmagic. I elected to write my own take on this
for a few reasons:
- I needed to be able to perform magic checks in parallel within a set of Tokio tasks, which implied some sort of pool or thread-local architecture.
- I found the
magicAPI a little unwieldy, especially around the hidden state types. - I wanted
Readsupport within the API, whichmagicdoesn't currently provide.
All that said, if magic suits your purposes, you should use magic. It's
considerably more battle tested.
What parts of the libmagic API are not exposed?
For now, there are two major omissions in the API:
- Support for database manipulation, specifically the
magic_checkandmagic_compilefunctions. I don't need them, and my suspicion is that the average user also doesn't. - Support for getting and setting parameters using
magic_getparamandmagic_setparam, respectively.
If you do need either of these functions, note the Handle::raw method, which
gives you direct access to the underlying magic_t * in a safe way to use with
magic-sys, which is re-exported from mojique. (Well, until you
actually make an FFI call, at which point you'll have to use unsafe.)
What about async support?
In theory, it should be possible to implement a Handle::async_read method
that takes an AsyncRead and bridges it into libmagic.
Realistically, though, this is going to be executor-dependent. On Tokio, you'd
want to use SyncIoBridge to get in there. So, for now, I think it's best left
as an exercise for the reader.
What about a pure Rust implementation of the magic algorithm?
This is something Trail of Bits did with PolyFile for Python. I definitely understand the impulse.
For now, I don't really have the time to implement this. But never say never. (And if someone out there does do so, please let me know! I'd love to use it.)