aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs275
1 files changed, 172 insertions, 103 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 1640a31..8af1bb9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,7 +20,8 @@
//!
//! [squashfs-tools-ng]: https://github.com/AgentD/squashfs-tools-ng/
-#[macro_use] extern crate lazy_static;
+#[macro_use]
+extern crate lazy_static;
extern crate libc;
extern crate memmap;
extern crate num_derive;
@@ -29,21 +30,21 @@ extern crate owning_ref;
extern crate walkdir;
extern crate xattr;
-use std::mem::MaybeUninit;
+use num_derive::FromPrimitive;
+use num_traits::FromPrimitive;
use std::ffi::{OsStr, OsString};
+use std::mem::MaybeUninit;
use std::path::PathBuf;
use std::ptr;
-use num_derive::FromPrimitive;
-use num_traits::FromPrimitive;
use thiserror::Error;
#[cfg(not(feature = "hermetic"))]
mod bindings {
- #![allow(non_camel_case_types)]
- #![allow(non_snake_case)]
- #![allow(non_upper_case_globals)]
- #![allow(dead_code)]
- include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+ #![allow(non_camel_case_types)]
+ #![allow(non_snake_case)]
+ #![allow(non_upper_case_globals)]
+ #![allow(dead_code)]
+ include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
#[cfg(feature = "hermetic")]
mod bindings;
@@ -63,23 +64,40 @@ type BoxedError = Box<dyn std::error::Error + std::marker::Send + std::marker::S
#[derive(Error, Debug, FromPrimitive)]
#[repr(i32)]
pub enum LibError {
- #[error("Failed to allocate memory")] Alloc = SQFS_ERROR_SQFS_ERROR_ALLOC,
- #[error("Generic I/O failure")] Io = SQFS_ERROR_SQFS_ERROR_IO,
- #[error("Compressor failed to extract data")] Compressor = SQFS_ERROR_SQFS_ERROR_COMPRESSOR,
- #[error("Internal error")] Internal = SQFS_ERROR_SQFS_ERROR_INTERNAL,
- #[error("Archive file appears to be corrupted")] Corrupted = SQFS_ERROR_SQFS_ERROR_CORRUPTED,
- #[error("Unsupported feature used")] Unsupported = SQFS_ERROR_SQFS_ERROR_UNSUPPORTED,
- #[error("Archive would overflow memory")] Overflow = SQFS_ERROR_SQFS_ERROR_OVERFLOW,
- #[error("Out-of-bounds access attempted")] OutOfBounds = SQFS_ERROR_SQFS_ERROR_OUT_OF_BOUNDS,
- #[error("Superblock magic number incorrect")] SuperMagic = SQFS_ERROR_SFQS_ERROR_SUPER_MAGIC,
- #[error("Unsupported archive version")] SuperVersion = SQFS_ERROR_SFQS_ERROR_SUPER_VERSION,
- #[error("Archive block size is invalid")] SuperBlockSize = SQFS_ERROR_SQFS_ERROR_SUPER_BLOCK_SIZE,
- #[error("Not a directory")] NotDir = SQFS_ERROR_SQFS_ERROR_NOT_DIR,
- #[error("Path does not exist")] NoEntry = SQFS_ERROR_SQFS_ERROR_NO_ENTRY,
- #[error("Hard link loop detected")] LinkLoop = SQFS_ERROR_SQFS_ERROR_LINK_LOOP,
- #[error("Not a regular file")] NotFile = SQFS_ERROR_SQFS_ERROR_NOT_FILE,
- #[error("Invalid argument passed")] ArgInvalid = SQFS_ERROR_SQFS_ERROR_ARG_INVALID,
- #[error("Library operations performed in incorrect order")] Sequence = SQFS_ERROR_SQFS_ERROR_SEQUENCE,
+ #[error("Failed to allocate memory")]
+ Alloc = SQFS_ERROR_SQFS_ERROR_ALLOC,
+ #[error("Generic I/O failure")]
+ Io = SQFS_ERROR_SQFS_ERROR_IO,
+ #[error("Compressor failed to extract data")]
+ Compressor = SQFS_ERROR_SQFS_ERROR_COMPRESSOR,
+ #[error("Internal error")]
+ Internal = SQFS_ERROR_SQFS_ERROR_INTERNAL,
+ #[error("Archive file appears to be corrupted")]
+ Corrupted = SQFS_ERROR_SQFS_ERROR_CORRUPTED,
+ #[error("Unsupported feature used")]
+ Unsupported = SQFS_ERROR_SQFS_ERROR_UNSUPPORTED,
+ #[error("Archive would overflow memory")]
+ Overflow = SQFS_ERROR_SQFS_ERROR_OVERFLOW,
+ #[error("Out-of-bounds access attempted")]
+ OutOfBounds = SQFS_ERROR_SQFS_ERROR_OUT_OF_BOUNDS,
+ #[error("Superblock magic number incorrect")]
+ SuperMagic = SQFS_ERROR_SFQS_ERROR_SUPER_MAGIC,
+ #[error("Unsupported archive version")]
+ SuperVersion = SQFS_ERROR_SFQS_ERROR_SUPER_VERSION,
+ #[error("Archive block size is invalid")]
+ SuperBlockSize = SQFS_ERROR_SQFS_ERROR_SUPER_BLOCK_SIZE,
+ #[error("Not a directory")]
+ NotDir = SQFS_ERROR_SQFS_ERROR_NOT_DIR,
+ #[error("Path does not exist")]
+ NoEntry = SQFS_ERROR_SQFS_ERROR_NO_ENTRY,
+ #[error("Hard link loop detected")]
+ LinkLoop = SQFS_ERROR_SQFS_ERROR_LINK_LOOP,
+ #[error("Not a regular file")]
+ NotFile = SQFS_ERROR_SQFS_ERROR_NOT_FILE,
+ #[error("Invalid argument passed")]
+ ArgInvalid = SQFS_ERROR_SQFS_ERROR_ARG_INVALID,
+ #[error("Library operations performed in incorrect order")]
+ Sequence = SQFS_ERROR_SQFS_ERROR_SEQUENCE,
}
/// Errors encountered while reading or writing an archive.
@@ -88,67 +106,98 @@ pub enum LibError {
/// operation.
#[derive(Error, Debug)]
pub enum SquashfsError {
- #[error("Input contains an invalid null character")] NullInput(#[from] std::ffi::NulError),
- #[error("Encoded string is not valid UTF-8")] Utf8(#[from] std::string::FromUtf8Error),
- #[error("OS string is not valid UTF-8")] OsUtf8(OsString),
- #[error("{0}: {1}")] LibraryError(String, LibError),
- #[error("{0}: Unknown error {1} in SquashFS library")] UnknownLibraryError(String, i32),
- #[error("{0}: Squashfs library did not return expected value")] LibraryReturnError(String),
- #[error("{0}")] LibraryNullError(String),
- #[error("Symbolic link chain exceeds {0} elements")] LinkChain(i32), // Can I use a const in the formatting string?
- #[error("Symbolic link loop detected containing {0}")] LinkLoop(PathBuf),
- #[error("Dangling symbolic link from {0} to {1}")] DanglingLink(PathBuf, PathBuf),
- #[error("{0} is type {1}, not {2}")] WrongType(String, String, String),
- #[error("Tried to copy an object that can't be copied")] Copy,
- #[error("Tried to get parent of a node with an unknown path")] NoPath,
- #[error("Inode index {0} is not within limits 1..{1}")] Range(u64, u64),
- #[error("Couldn't read file: {0}")] Read(#[from] std::io::Error),
- #[error("The filesystem does not support the feature: {0}")] Unsupported(String),
- #[error("Memory mapping failed: {0}")] Mmap(std::io::Error),
- #[error("Couldn't get the current system time: {0}")] Time(#[from] std::time::SystemTimeError),
- #[error("Refusing to create empty archive")] Empty,
- #[error("Tried to write parent directory before child node {0}")] WriteOrder(u32),
- #[error("Tried to write unknown or unsupported file type")] WriteType(std::fs::FileType),
- #[error("Callback returned an error")] WrappedError(BoxedError),
- #[error("Failed to retrieve xattrs for {0}: {1}")] Xattr(PathBuf, std::io::Error),
- #[error("Tried to add files to a writer that was already finished")] Finished,
- #[error("Internal error: {0}")] Internal(String),
+ #[error("Input contains an invalid null character")]
+ NullInput(#[from] std::ffi::NulError),
+ #[error("Encoded string is not valid UTF-8")]
+ Utf8(#[from] std::string::FromUtf8Error),
+ #[error("OS string is not valid UTF-8")]
+ OsUtf8(OsString),
+ #[error("{0}: {1}")]
+ LibraryError(String, LibError),
+ #[error("{0}: Unknown error {1} in SquashFS library")]
+ UnknownLibraryError(String, i32),
+ #[error("{0}: Squashfs library did not return expected value")]
+ LibraryReturnError(String),
+ #[error("{0}")]
+ LibraryNullError(String),
+ #[error("Symbolic link chain exceeds {0} elements")]
+ LinkChain(i32), // Can I use a const in the formatting string?
+ #[error("Symbolic link loop detected containing {0}")]
+ LinkLoop(PathBuf),
+ #[error("Dangling symbolic link from {0} to {1}")]
+ DanglingLink(PathBuf, PathBuf),
+ #[error("{0} is type {1}, not {2}")]
+ WrongType(String, String, String),
+ #[error("Tried to copy an object that can't be copied")]
+ Copy,
+ #[error("Tried to get parent of a node with an unknown path")]
+ NoPath,
+ #[error("Inode index {0} is not within limits 1..{1}")]
+ Range(u64, u64),
+ #[error("Couldn't read file: {0}")]
+ Read(#[from] std::io::Error),
+ #[error("The filesystem does not support the feature: {0}")]
+ Unsupported(String),
+ #[error("Memory mapping failed: {0}")]
+ Mmap(std::io::Error),
+ #[error("Couldn't get the current system time: {0}")]
+ Time(#[from] std::time::SystemTimeError),
+ #[error("Refusing to create empty archive")]
+ Empty,
+ #[error("Tried to write parent directory before child node {0}")]
+ WriteOrder(u32),
+ #[error("Tried to write unknown or unsupported file type")]
+ WriteType(std::fs::FileType),
+ #[error("Callback returned an error")]
+ WrappedError(BoxedError),
+ #[error("Failed to retrieve xattrs for {0}: {1}")]
+ Xattr(PathBuf, std::io::Error),
+ #[error("Tried to add files to a writer that was already finished")]
+ Finished,
+ #[error("Internal error: {0}")]
+ Internal(String),
}
/// Result type returned by SquashFS library operations.
pub type Result<T> = std::result::Result<T, SquashfsError>;
fn sfs_check(code: i32, desc: &str) -> Result<i32> {
- match code {
- i if i >= 0 => Ok(i),
- i => match FromPrimitive::from_i32(i) {
- Some(e) => Err(SquashfsError::LibraryError(desc.to_string(), e)),
- None => Err(SquashfsError::UnknownLibraryError(desc.to_string(), i)),
- }
- }
+ match code {
+ i if i >= 0 => Ok(i),
+ i => match FromPrimitive::from_i32(i) {
+ Some(e) => Err(SquashfsError::LibraryError(desc.to_string(), e)),
+ None => Err(SquashfsError::UnknownLibraryError(desc.to_string(), i)),
+ },
+ }
}
fn sfs_destroy<T>(x: *mut T) {
- unsafe {
- let obj = x as *mut sqfs_object_t;
- ((*obj).destroy.expect("SquashFS object did not provide a destroy callback"))(obj);
- }
+ unsafe {
+ let obj = x as *mut sqfs_object_t;
+ ((*obj)
+ .destroy
+ .expect("SquashFS object did not provide a destroy callback"))(obj);
+ }
}
fn libc_free<T>(x: *mut T) {
- unsafe { libc::free(x as *mut _ as *mut libc::c_void); }
+ unsafe {
+ libc::free(x as *mut _ as *mut libc::c_void);
+ }
}
fn rust_dealloc<T>(x: *mut T) {
- unsafe { std::alloc::dealloc(x as *mut u8, std::alloc::Layout::new::<T>()) }
+ unsafe { std::alloc::dealloc(x as *mut u8, std::alloc::Layout::new::<T>()) }
}
fn unpack_meta_ref(meta_ref: u64) -> (u64, u64) {
- (meta_ref >> 16 & 0xffffffff, meta_ref & 0xffff)
+ (meta_ref >> 16 & 0xffffffff, meta_ref & 0xffff)
}
fn os_to_string(s: &OsStr) -> Result<String> {
- Ok(s.to_str().ok_or_else(|| SquashfsError::OsUtf8(s.to_os_string()))?.to_string())
+ Ok(s.to_str()
+ .ok_or_else(|| SquashfsError::OsUtf8(s.to_os_string()))?
+ .to_string())
}
const NO_XATTRS: u32 = 0xffffffff;
@@ -158,65 +207,85 @@ const BLOCK_BUF_SIZE: usize = 4096;
const PAD_TO: usize = 4096;
struct ManagedPointer<T> {
- ptr: *mut T,
- destroy: fn(*mut T),
+ ptr: *mut T,
+ destroy: fn(*mut T),
}
impl<T> ManagedPointer<T> {
- fn null(destroy: fn(*mut T)) -> Self {
- Self { ptr: ptr::null_mut(), destroy: destroy }
- }
+ fn null(destroy: fn(*mut T)) -> Self {
+ Self {
+ ptr: ptr::null_mut(),
+ destroy: destroy,
+ }
+ }
+
+ fn new(ptr: *mut T, destroy: fn(*mut T)) -> Self {
+ Self {
+ ptr: ptr,
+ destroy: destroy,
+ }
+ }
- fn new(ptr: *mut T, destroy: fn(*mut T)) -> Self {
- Self { ptr: ptr, destroy: destroy }
- }
-
- fn as_const(&self) -> *const T {
- self.ptr as *const T
- }
+ fn as_const(&self) -> *const T {
+ self.ptr as *const T
+ }
}
impl<T> std::ops::Deref for ManagedPointer<T> {
- type Target = *mut T;
+ type Target = *mut T;
- fn deref(&self) -> &Self::Target {
- &self.ptr
- }
+ fn deref(&self) -> &Self::Target {
+ &self.ptr
+ }
}
impl<T> std::ops::DerefMut for ManagedPointer<T> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.ptr
- }
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.ptr
+ }
}
impl<T> Drop for ManagedPointer<T> {
- fn drop(&mut self) {
- (self.destroy)(**self)
- }
+ fn drop(&mut self) {
+ (self.destroy)(**self)
+ }
}
impl<T> std::fmt::Debug for ManagedPointer<T> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "ManagedPointer({:?})", self.ptr)
- }
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "ManagedPointer({:?})", self.ptr)
+ }
}
fn sfs_init<T>(init: &dyn Fn(*mut T) -> i32, err: &str) -> Result<T> {
- let mut ret: MaybeUninit<T> = MaybeUninit::uninit();
- sfs_check(init(ret.as_mut_ptr()), err)?;
- Ok(unsafe { ret.assume_init() })
+ let mut ret: MaybeUninit<T> = MaybeUninit::uninit();
+ sfs_check(init(ret.as_mut_ptr()), err)?;
+ Ok(unsafe { ret.assume_init() })
}
-fn sfs_init_ptr<T>(init: &dyn Fn(*mut *mut T) -> i32, err: &str, destroy: fn(*mut T)) -> Result<ManagedPointer<T>> {
- let mut ret: *mut T = ptr::null_mut();
- sfs_check(init(&mut ret), err)?;
- if ret.is_null() { Err(SquashfsError::LibraryReturnError(err.to_string())) }
- else { Ok(ManagedPointer::new(ret, destroy)) }
+fn sfs_init_ptr<T>(
+ init: &dyn Fn(*mut *mut T) -> i32,
+ err: &str,
+ destroy: fn(*mut T),
+) -> Result<ManagedPointer<T>> {
+ let mut ret: *mut T = ptr::null_mut();
+ sfs_check(init(&mut ret), err)?;
+ if ret.is_null() {
+ Err(SquashfsError::LibraryReturnError(err.to_string()))
+ } else {
+ Ok(ManagedPointer::new(ret, destroy))
+ }
}
-fn sfs_init_check_null<T>(init: &dyn Fn() -> *mut T, err: &str, destroy: fn(*mut T)) -> Result<ManagedPointer<T>> {
- let ret = init();
- if ret.is_null() { Err(SquashfsError::LibraryNullError(err.to_string())) }
- else { Ok(ManagedPointer::new(ret, destroy)) }
+fn sfs_init_check_null<T>(
+ init: &dyn Fn() -> *mut T,
+ err: &str,
+ destroy: fn(*mut T),
+) -> Result<ManagedPointer<T>> {
+ let ret = init();
+ if ret.is_null() {
+ Err(SquashfsError::LibraryNullError(err.to_string()))
+ } else {
+ Ok(ManagedPointer::new(ret, destroy))
+ }
}