aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthew Schauer <matthew.schauer@e10x.net>2020-06-15 21:38:05 -0700
committerMatthew Schauer <matthew.schauer@e10x.net>2020-06-16 08:21:51 -0700
commit13b29a539bb63c0bca07fd4e8d5c0da4569277b8 (patch)
tree6736cd7b011c9f43b4b8a2909907024ab4a1fbf9 /src
parentdb988ae442b0827019cd2f51b2f214cf300e7e8d (diff)
First pass at error handling
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs119
1 files changed, 84 insertions, 35 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 6b9e438..46d0c50 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,8 @@
#![allow(dead_code)] // FIXME
extern crate libc;
+extern crate num_derive;
+extern crate num_traits;
mod bindings {
#![allow(non_camel_case_types)]
@@ -14,21 +16,70 @@ use std::ffi::{CStr, CString};
use std::mem::MaybeUninit;
use std::ptr;
use bindings::*;
+use num_derive::FromPrimitive;
+use num_traits::FromPrimitive;
+use thiserror::Error;
+
+#[derive(Error, Debug, FromPrimitive)]
+#[repr(i32)]
+pub enum LibError {
+ #[error("Failed to allocate memory")] Alloc = -1,
+ #[error("Generic I/O failure occurred")] Io = -2,
+ #[error("Compressor failed to extract data")] Compressor = -3,
+ #[error("Internal error occurred")] Internal = -4,
+ #[error("Archive file appears to be corrupted")] Corrupted = -5,
+ #[error("Unsupported feature used")] Unsupported = -6,
+ #[error("Archive would overflow memory")] Overflow = -7,
+ #[error("Out-of-bounds access attempted")] OutOfBounds = -8,
+ #[error("Superblock magic number incorrect")] SuperMagic = -9,
+ #[error("Unsupported archive version")] SuperVersion = -10,
+ #[error("Archive block size is invalid")] SuperBlockSize = -11,
+ #[error("Not a directory")] NotDir = -12,
+ #[error("Path does not exist")] NoEntry = -13,
+ #[error("Hard link loop detected")] LinkLoop = -14,
+ #[error("Not a regular file")] NotFile = -15,
+ #[error("Invalid argument passed")] ArgInvalid = -16,
+ #[error("Library operations performed in incorrect order")] Sequence = -17,
+}
+
+#[derive(Error, Debug)]
+pub enum SquashfsError {
+ #[error("Input contains an invalid null character")] NullInput(std::ffi::NulError),
+ #[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),
+}
+
+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)),
+ }
+ }
+}
+
+fn sfs_err(desc: &str) -> Result<()> {
+ Err(SquashfsError::LibraryReturnError(desc.to_string()))
+}
const NO_XATTRS: u32 = 0xffffffff;
-unsafe fn destroy(obj: *mut sqfs_object_t) {
- ((*obj).destroy.unwrap())(obj);
+unsafe fn sfs_destroy(obj: *mut sqfs_object_t) {
+ ((*obj).destroy.expect("Squashfs object did not provide a destory callback"))(obj);
}
-pub fn test() {
+pub fn test() -> Result<()> {
let fname = "/home/matt/Scratch/wikivoyage.sfs";
unsafe {
- let file = sqfs_open_file(CString::new(fname).unwrap().as_ptr(), SQFS_FILE_OPEN_FLAGS_SQFS_FILE_OPEN_READ_ONLY);
- if file.is_null() { panic!("Couldn't open file"); }
+ let file = sqfs_open_file(CString::new(fname).map_err(|e| SquashfsError::NullInput(e))?.as_ptr(), SQFS_FILE_OPEN_FLAGS_SQFS_FILE_OPEN_READ_ONLY);
+ if file.is_null() { sfs_err("Couldn't open input file")?; }
let superblock = {
let mut ret: MaybeUninit<sqfs_super_t> = MaybeUninit::uninit();
- if sqfs_super_read(ret.as_mut_ptr(), file) != 0 { panic!("Couldn't get superblock"); }
+ sfs_check(sqfs_super_read(ret.as_mut_ptr(), file), "Couldn't read archive superblock")?;
ret.assume_init()
};
let compressor_config = {
@@ -38,75 +89,72 @@ pub fn test() {
};
let compressor = {
let mut ret: *mut sqfs_compressor_t = ptr::null_mut();
- if sqfs_compressor_create(&compressor_config, &mut ret) != 0 { panic!("Couldn't create compressor"); }
- if ret.is_null() { panic!("No error reported creating compressor, but got empty result"); }
+ sfs_check(sqfs_compressor_create(&compressor_config, &mut ret), "Couldn't create compressor")?;
+ if ret.is_null() { sfs_err("Couldn't create compressor")?; }
ret
};
let dir_reader = sqfs_dir_reader_create(&superblock, compressor, file, 0);
- if dir_reader.is_null() { panic!("Couldn't create directory reader"); }
+ if dir_reader.is_null() { sfs_err("Couldn't create directory reader")?; }
let root = {
let mut ret: *mut sqfs_inode_generic_t = ptr::null_mut();
- if sqfs_dir_reader_get_root_inode(dir_reader, &mut ret) != 0 { panic!("Couldn't get root inode"); }
- if ret.is_null() { panic!("No error reported getting root inode, but got empty result"); }
+ sfs_check(sqfs_dir_reader_get_root_inode(dir_reader, &mut ret), "Couldn't get root inode")?;
+ if ret.is_null() { sfs_err("Couldn't get root inode")?; }
ret
};
- if sqfs_dir_reader_open_dir(dir_reader, root, 0) != 0 { panic!("Couldn't open root directory"); }
+ sfs_check(sqfs_dir_reader_open_dir(dir_reader, root, 0), "Couldn't open directory")?;
let mut dir_entry: *mut sqfs_dir_entry_t = ptr::null_mut();
loop {
- let readres = sqfs_dir_reader_read(dir_reader, &mut dir_entry);
- if readres > 0 { break; }
- if readres < 0 { panic!("Couldn't list directory contents"); }
- if dir_entry.is_null() { panic!("No error reported reading directory, but got empty result"); }
+ if sfs_check(sqfs_dir_reader_read(dir_reader, &mut dir_entry), "Couldn't read directory")? > 0 { break; }
+ if dir_entry.is_null() { sfs_err("Couldn't read directory")?; }
let name_bytes = (*dir_entry).name.as_slice((*dir_entry).size as usize + 1);
let name = String::from_utf8_lossy(name_bytes).into_owned();
println!("{}", name);
}
let inode = {
let mut ret: *mut sqfs_inode_generic_t = ptr::null_mut();
- if sqfs_dir_reader_find_by_path(dir_reader, root, CString::new("_meta/info.lua").unwrap().as_ptr(), &mut ret) != 0 { panic!("Couldn't get internal inode"); }
- if ret.is_null() { panic!("No error reported getting internal inode, but got empty result"); }
+ sfs_check(sqfs_dir_reader_find_by_path(dir_reader, root, CString::new("_meta/info.lua").map_err(|e| SquashfsError::NullInput(e))?.as_ptr(), &mut ret), "Couldn't find path")?;
+ if ret.is_null() { sfs_err("Couldn't find path")?; }
ret
};
let mut size: u64 = 0;
sqfs_inode_get_file_size(inode, &mut size);
println!("File is {} bytes", size);
let data_reader = sqfs_data_reader_create(file, superblock.block_size as u64, compressor, 0);
- if data_reader.is_null() { panic!("Couldn't create data reader"); }
- if sqfs_data_reader_load_fragment_table(data_reader, &superblock) != 0 { panic!("Couldn't load fragment table"); };
+ if data_reader.is_null() { sfs_err("Couldn't create data reader")?; }
+ sfs_check(sqfs_data_reader_load_fragment_table(data_reader, &superblock), "Couldn't create data reader")?;
let mut off = 0 as u64;
let mut content = String::new();
- let mut buf: Vec<u8> = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+ let mut buf: Vec<u8> = vec![0; 10];
loop {
- let readres = sqfs_data_reader_read(data_reader, inode, off, buf.as_mut_ptr() as *mut libc::c_void, buf.len() as u32);
+ let readres = sfs_check(sqfs_data_reader_read(data_reader, inode, off, buf.as_mut_ptr() as *mut libc::c_void, buf.len() as u32), "Couldn't read file content")?;
if readres == 0 { break; }
- if readres < 0 { panic!(format!("Couldn't read from file: {}", readres)); }
content.push_str(&String::from_utf8_lossy(&buf[0..readres as usize]));
off += readres as u64;
}
println!("{}", content);
let xattr_reader = sqfs_xattr_reader_create(0);
- if sqfs_xattr_reader_load(xattr_reader, &superblock, file, compressor) != 0 { panic!("Couldn't create xattr reader"); }
+ sfs_check(sqfs_xattr_reader_load(xattr_reader, &superblock, file, compressor), "Couldn't create xattr reader")?;
let mut xattr_idx: u32 = NO_XATTRS;
- if sqfs_inode_get_xattr_index(inode, &mut xattr_idx) != 0 { panic!("Couldn't get xattr index for inode"); }
+ sfs_check(sqfs_inode_get_xattr_index(inode, &mut xattr_idx), "Couldn't get xattr index")?;
let xattr_id = {
let mut ret: MaybeUninit<sqfs_xattr_id_t> = MaybeUninit::uninit();
- if sqfs_xattr_reader_get_desc(xattr_reader, xattr_idx, ret.as_mut_ptr()) != 0 { panic!("Couldn't get xattr ID for inode"); }
+ sfs_check(sqfs_xattr_reader_get_desc(xattr_reader, xattr_idx, ret.as_mut_ptr()), "Couldn't get xattr descriptor")?;
ret.assume_init()
};
let xattr_type = SQFS_XATTR_TYPE_SQFS_XATTR_USER;
let mut xattrs: HashMap<Vec<u8>, Vec<u8>> = HashMap::new();
- if sqfs_xattr_reader_seek_kv(xattr_reader, &xattr_id) != 0 { panic!("Couldn't seek to xattr location"); }
+ sfs_check(sqfs_xattr_reader_seek_kv(xattr_reader, &xattr_id), "Couldn't seek to xattr location")?;
for _ in 0..xattr_id.count {
let mut xattr_key: *mut sqfs_xattr_entry_t = ptr::null_mut();
- if sqfs_xattr_reader_read_key(xattr_reader, &mut xattr_key) != 0 { panic!("Couldn't read xattr key"); }
- if xattr_key.is_null() { panic!("No error reported reading xattr key, but got an empty result"); }
+ sfs_check(sqfs_xattr_reader_read_key(xattr_reader, &mut xattr_key), "Couldn't read xattr key")?;
+ if xattr_key.is_null() { sfs_err("Couldn't read xattr key")?; }
if (*xattr_key).type_ as u32 & SQFS_XATTR_TYPE_SQFS_XATTR_FLAG_OOL != 0 {
// TODO
}
let prefixlen = CStr::from_ptr(sqfs_get_xattr_prefix((*xattr_key).type_ as u32)).to_bytes().len();
let mut xattr_val: *mut sqfs_xattr_value_t = ptr::null_mut();
- if sqfs_xattr_reader_read_value(xattr_reader, xattr_key, &mut xattr_val) != 0 { panic!("Couldn't read xattr value"); }
- if xattr_val.is_null() { panic!("No error reported reading xattr value, but got an empty result"); }
+ sfs_check(sqfs_xattr_reader_read_value(xattr_reader, xattr_key, &mut xattr_val), "Couldn't read xattr value")?;
+ if xattr_val.is_null() { sfs_err("Couldn't read xattr value")?; }
if (*xattr_key).type_ as u32 & SQFS_XATTR_TYPE_SQFS_XATTR_PREFIX_MASK == xattr_type {
let keyvec = (*xattr_key).key.as_slice((*xattr_key).size as usize + prefixlen)[prefixlen..].to_vec();
let valvec = (*xattr_val).value.as_slice((*xattr_val).size as usize).to_vec();
@@ -118,12 +166,13 @@ pub fn test() {
for (key, val) in xattrs {
println!("xattr {}: {}", String::from_utf8_lossy(&key), String::from_utf8_lossy(&val));
}
- destroy(xattr_reader as *mut sqfs_object_t);
- destroy(data_reader as *mut sqfs_object_t);
+ sfs_destroy(xattr_reader as *mut sqfs_object_t);
+ sfs_destroy(data_reader as *mut sqfs_object_t);
libc::free(inode as *mut libc::c_void);
libc::free(dir_entry as *mut libc::c_void);
libc::free(root as *mut libc::c_void);
- destroy(dir_reader as *mut sqfs_object_t);
- destroy(file as *mut sqfs_object_t);
+ sfs_destroy(dir_reader as *mut sqfs_object_t);
+ sfs_destroy(file as *mut sqfs_object_t);
+ Ok(())
}
}