unrar (Rust crate)
| Language | Rust (bundles C++ code) |
|---|---|
| License | MIT or Apache-2.0 for the crate; bundled UnRAR source under the UnRAR license (not OSI open source) |
| Repository | github.com/muja/unrar.rs |
| Documentation | docs.rs/unrar |
| Depends on | a C++ compiler at build time (the unrar_sys crate compiles the UnRAR source) |
| Read / write | yes / no; RAR4 and RAR5, passwords, multi-volume |
The unrar crate is a Rust wrapper around RARLAB’s UnRAR library. It compiles the library from source during cargo build, so there is no system library to install.
The API follows the C library: entries are processed in order, front to back, with no random access. It uses the typestate pattern to enforce the order of calls: after read_header you hold an archive “before file” and must call skip, read, extract, extract_to or extract_with_base to get back to “before header”. Listing mode (open_for_listing) is an Iterator of headers.
Installation#
cargo add unrar
Basic usage: list and extract a RAR file#
use unrar::Archive;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut archive = Archive::new("archive.rar").open_for_processing()?;
while let Some(header) = archive.read_header()? {
let entry = header.entry();
println!("{} ({} bytes)", entry.filename.display(), entry.unpacked_size);
archive = if entry.is_file() {
header.extract_with_base("output")? // keeps the folder structure under output/
} else {
header.skip()?
};
}
Ok(())
}
extract() extracts relative to the current directory; extract_to(path) writes the entry to exactly that file path.
How to list files in a RAR#
use unrar::Archive;
fn main() -> Result<(), Box<dyn std::error::Error>> {
for entry in Archive::new("archive.rar").open_for_listing()? {
let entry = entry?;
println!(
"{}{} {} bytes, encrypted: {}",
entry.filename.display(),
if entry.is_directory() { "/" } else { "" },
entry.unpacked_size,
entry.is_encrypted()
);
}
Ok(())
}
A file split across volumes appears once with open_for_listing; open_for_listing_split returns one header per volume part.
How to read a file from a RAR into memory#
use std::path::Path;
use unrar::{Archive, UnrarResult};
fn read_entry(archive: &str, name: &str) -> UnrarResult<Option<Vec<u8>>> {
let mut archive = Archive::new(archive).open_for_processing()?;
while let Some(header) = archive.read_header()? {
if header.entry().filename == Path::new(name) {
let (data, _rest) = header.read()?;
return Ok(Some(data));
}
archive = header.skip()?;
}
Ok(None)
}
read decompresses the whole entry into a Vec<u8>; use extract_to for large files.
How to open a password-protected RAR#
use unrar::error::Code;
use unrar::Archive;
fn main() {
let result = Archive::with_password("secret.rar", "password")
.open_for_processing()
.and_then(|mut archive| {
while let Some(header) = archive.read_header()? {
archive = header.extract_with_base("output")?;
}
Ok(())
});
match result {
Ok(()) => println!("done"),
Err(e) if e.code == Code::BadPassword => eprintln!("wrong password"),
Err(e) if e.code == Code::MissingPassword => eprintln!("password required"),
Err(e) => eprintln!("error: {e}"),
}
}
RAR4 archives store no password check value, so a wrong password shows up as Code::BadData (CRC error) during extraction. RAR5 archives report Code::BadPassword.
How to extract a multi-volume RAR#
Open the first volume; the library opens the next ones by name. Archive::first_part finds the first volume from any part name (it only looks at the string, not the disk):
use unrar::Archive;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let part = Archive::new("movie.part3.rar");
let first = if part.is_multipart() { part.first_part() } else { "movie.part3.rar".into() };
let mut archive = Archive::new(&first).open_for_processing()?;
while let Some(header) = archive.read_header()? {
archive = header.extract_with_base("output")?;
}
Ok(())
}
Tips#
- On Windows with MSVC, unrar 0.5.8 can fail to link with unresolved
RegOpenKeyExW/RegQueryValueExW. Add abuild.rsto your crate withfn main() { println!("cargo:rustc-link-lib=advapi32"); }. archive.is_solid()andarchive.has_comment()work on any open archive.- Errors are
UnrarErrorvalues with acode(Code::BadDatafor a CRC error,Code::EOpenfor a missing file or volume) and awhen(open, read or process).