### Test the project Source: https://github.com/wcampbell0x2a/backhand/blob/master/DEVELOPMENT.md Runs the test suite. Requires squashfs-tools to be installed on the system. ```console $ just test ``` -------------------------------- ### Run Library Benchmarks Source: https://github.com/wcampbell0x2a/backhand/blob/master/BENCHMARK.md Execute the library benchmarks using Cargo. Ensure you have Rust and Cargo installed. ```bash $ cargo bench ``` -------------------------------- ### Configure SquashFS Compression in Rust Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Demonstrates setting up various compression algorithms like XZ, Gzip, Zstd, and LZ4, along with writer options for image creation. ```rust use backhand::{ FilesystemWriter, FilesystemCompressor, compression::{Compressor, CompressionOptions, Gzip, Xz, XzFilter, Zstd, Lz4}, ExtraXz, CompressionExtra, }; let mut fs = FilesystemWriter::default(); // XZ compression (best ratio, slower) let mut compressor = FilesystemCompressor::new(Compressor::Xz, None).unwrap(); let mut xz_extra = ExtraXz::default(); xz_extra.level(6).unwrap(); // 0-9, default is 6 compressor.extra(CompressionExtra::Xz(xz_extra)).unwrap(); fs.set_compressor(compressor); // Gzip compression (good balance) let gzip_options = CompressionOptions::Gzip(Gzip { compression_level: 9, window_size: 15, strategies: 0, }); let compressor = FilesystemCompressor::new(Compressor::Gzip, Some(gzip_options)).unwrap(); fs.set_compressor(compressor); // Zstd compression (fast with good ratio) let zstd_options = CompressionOptions::Zstd(Zstd { compression_level: 19, // 1-22 }); let compressor = FilesystemCompressor::new(Compressor::Zstd, Some(zstd_options)).unwrap(); fs.set_compressor(compressor); // LZ4 compression (fastest, requires options) let lz4_options = CompressionOptions::Lz4(Lz4 { version: 1, flags: 0, }); let compressor = FilesystemCompressor::new(Compressor::Lz4, Some(lz4_options)).unwrap(); fs.set_compressor(compressor); // Configure writer options fs.set_no_duplicate_files(true); // Enable deduplication (default) fs.set_emit_compression_options(true); // Write compression options to image fs.set_kib_padding(4); // 4 KiB padding at end fs.set_no_padding(); // Or disable padding entirely ``` -------------------------------- ### Build the project Source: https://github.com/wcampbell0x2a/backhand/blob/master/DEVELOPMENT.md Executes the build process using the project's Justfile. ```console $ just build ``` -------------------------------- ### Inspect SquashFS Superblock Information Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Access the low-level `Squashfs` struct directly to get detailed superblock information without parsing the entire filesystem tree. This is useful for quick inspection. ```rust use std::fs::File; use std::io::BufReader; use backhand::{Squashfs, FilesystemReader, kind::Kind}; // Read only the superblock for quick inspection let file = BufReader::new(File::open("image.squashfs").unwrap()); let squashfs = Squashfs::from_reader_with_offset(file, 0).unwrap(); let sb = &squashfs.superblock; println!("SquashFS Superblock Information:"); println!(" Inode count: {}", sb.inode_count); println!(" Block size: {} bytes", sb.block_size); println!(" Fragment count: {}", sb.frag_count); println!(" Compression: {:?}", sb.compressor); println!(" Modification time: {}", sb.mod_time); println!(" Bytes used: {}", sb.bytes_used); // Check flags if sb.inodes_uncompressed() { println!(" Flag: Inodes are uncompressed"); } if sb.data_block_stored_uncompressed() { println!(" Flag: Data blocks stored uncompressed"); } if sb.fragments_stored_uncompressed() { println!(" Flag: Fragments stored uncompressed"); } if sb.data_has_been_deduplicated() { println!(" Flag: Data has been deduplicated"); } if sb.compressor_options_are_present() { println!(" Flag: Compressor options present"); } // Now convert to FilesystemReader for full access let filesystem = squashfs.into_filesystem_reader().unwrap(); println!("Total files: {}", filesystem.files().count()); ``` -------------------------------- ### Performance Benchmarks Before and After v0.8.0 Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Compares the read/write performance of specific filesystems before and after the v0.8.0 release, demonstrating significant speed improvements. ```text ``` read/write/netgear_ax6100v2 time: [2.3553 s 2.3667 s 2.3775 s] read/write/tplink_ax1800 time: [17.996 s 18.068 s 18.140 s] ``` ``` ```text ``` write_read/netgear_ax6100v2 time: [1.2291 s 1.2363 s 1.2433 s] write_read/tplink_ax1800 time: [6.7506 s 6.8287 s 6.9349 s] only_read/netgear_ax6100v2 time: [5.1153 ms 5.1234 ms 5.1305 ms] only_read/tplink_ax1800 time: [22.383 ms 22.398 ms 22.415 ms] ``` ``` -------------------------------- ### Initialize Read Buffers for File Extraction Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Demonstrates the updated pattern for allocating read buffers and initializing a file reader. ```diff, rust +// alloc required space for file data readers +let (mut buf_read, mut buf_decompress) = filesystem.alloc_read_buffers(); -let mut reader = filesystem.file(&file.basic).reader(); +let mut reader = filesystem + .file(&file.basic) + .reader(&mut buf_read, &mut buf_decompress); ``` -------------------------------- ### Build Release Binaries Source: https://github.com/wcampbell0x2a/backhand/blob/master/backhand-test/README.md Builds the release version of the binaries for testing. ```bash $ cargo build --release --bins ``` -------------------------------- ### Creating a New SquashFS Image with FilesystemWriter Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Configures a new filesystem with specific compression settings and populates it with directories, files, and symlinks. The final image is written to disk using the write method. ```rust use std::fs::File; use std::io::Cursor; use backhand::{ FilesystemWriter, FilesystemCompressor, NodeHeader, compression::Compressor, kind::Kind, kind, DEFAULT_BLOCK_SIZE, ExtraXz, CompressionExtra, }; // Create a new empty filesystem let mut fs = FilesystemWriter::default(); fs.set_current_time(); fs.set_block_size(DEFAULT_BLOCK_SIZE); // 128 KiB default fs.set_kind(Kind::from_const(kind::LE_V4_0).unwrap()); fs.set_root_mode(0o755); fs.set_only_root_id(); // Configure XZ compression with level 9 let mut xz_extra = ExtraXz::default(); xz_extra.level(9).unwrap(); let extra = CompressionExtra::Xz(xz_extra); let mut compressor = FilesystemCompressor::new(Compressor::Xz, None).unwrap(); compressor.extra(extra).unwrap(); fs.set_compressor(compressor); // Create file header with permissions let header = NodeHeader { permissions: 0o644, uid: 1000, gid: 1000, mtime: 1700000000, }; let dir_header = NodeHeader { permissions: 0o755, uid: 0, gid: 0, mtime: 1700000000, }; // Create directory structure fs.push_dir("etc", dir_header).unwrap(); fs.push_dir("etc/config", dir_header).unwrap(); fs.push_dir("usr", dir_header).unwrap(); fs.push_dir("usr/bin", dir_header).unwrap(); // Add files from memory let config_data = b"# Configuration file\nkey=value\n"; fs.push_file(Cursor::new(config_data), "etc/config/app.conf", header).unwrap(); // Add file from disk let binary_file = File::open("/path/to/binary").unwrap(); fs.push_file(binary_file, "usr/bin/myapp", NodeHeader { permissions: 0o755, ..header }).unwrap(); // Add symlink fs.push_symlink("/usr/bin/myapp", "usr/bin/app", header).unwrap(); // Write the filesystem to a file let mut output = File::create("output.squashfs").unwrap(); let (superblock, bytes_written) = fs.write(&mut output).unwrap(); println!("Created SquashFS: {} bytes", bytes_written); ``` -------------------------------- ### Add push_symlink, push_dir, push_char_device, push_block_device Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Demonstrates adding support for pushing symbolic links, directories, character devices, and block devices to the filesystem. ```rust ```rust -Filesystem::push_symlink(..) +Filesystem::push_symlink(..) ``` ``` ```rust ```rust -Filesystem::push_dir(..) +Filesystem::push_dir(..) ``` ``` ```rust ```rust -Filesystem::push_char_device(..) +Filesystem::push_char_device(..) ``` ``` ```rust ```rust -Filesystem::push_block_device(..) +Filesystem::push_block_device(..) ``` ``` -------------------------------- ### Lint the project Source: https://github.com/wcampbell0x2a/backhand/blob/master/DEVELOPMENT.md Runs the project's linting tools via the Justfile. ```console $ just lint ``` -------------------------------- ### Squashfs Initialization Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Methods for initializing a Squashfs instance from a reader, supporting various offsets and filesystem kinds. ```APIDOC ## [FUNCTION] backhand::Squashfs::from_reader ### Description Initializes a Squashfs instance from a provided reader. ### Parameters - **reader** (R: backhand::ReadSeek) - Required - The reader source. ### Response - **Result, BackhandError>** - Returns the initialized Squashfs instance or an error. ## [FUNCTION] backhand::Squashfs::from_reader_with_offset ### Description Initializes a Squashfs instance from a reader with a specific byte offset. ### Parameters - **reader** (R) - Required - The reader source. - **offset** (u64) - Required - The byte offset to start reading from. ### Response - **Result>, BackhandError>** - Returns the initialized Squashfs instance or an error. ``` -------------------------------- ### Reading, Writing, and Modifying SquashFS Images in Rust Source: https://github.com/wcampbell0x2a/backhand/blob/master/README.md Demonstrates how to read an existing SquashFS image, convert it to a writable format, add new files, replace existing ones, and write the modified filesystem to a new file. Requires the `backhand` crate. ```rust use std::fs::File; use std::io::{Cursor, BufReader}; use backhand::{FilesystemReader, FilesystemWriter, NodeHeader}; // read let file = BufReader::new(File::open("file.squashfs").unwrap()); let read_filesystem = FilesystemReader::from_reader(file).unwrap(); // convert to writer let mut write_filesystem = FilesystemWriter::from_fs_reader(&read_filesystem).unwrap(); // add file with data from slice let d = NodeHeader::default(); let bytes = Cursor::new(b"Fear is the mind-killer."); write_filesystem.push_file(bytes, "a/d/e/new_file", d); // add file with data from file let new_file = File::open("dune").unwrap(); write_filesystem.push_file(new_file, "/root/dune", d); // modify file let bytes = Cursor::new(b"The sleeper must awaken.\n"); write_filesystem.replace_file("/a/b/c/d/e/first_file", bytes).unwrap(); // write into a new file let mut output = File::create("modified.squashfs").unwrap(); write_filesystem.write(&mut output).unwrap(); ``` -------------------------------- ### Run Benchmarks Source: https://github.com/wcampbell0x2a/backhand/blob/master/RELEASE.md Execute the benchmark script to update performance metrics. ```bash $ ./bench.bash ``` -------------------------------- ### Configure Custom SquashFS Kind Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Create custom `Kind` configurations for vendor-specific SquashFS formats with non-standard magic bytes, endianness, or compression settings. This allows for parsing non-standard images. ```rust use backhand::kind::{Kind, Endian, Magic, LE_V4_0, BE_V4_0}; // Use predefined kinds let le_kind = Kind::from_const(LE_V4_0).unwrap(); let be_kind = Kind::from_const(BE_V4_0).unwrap(); // Customize an existing kind let custom_kind = Kind::from_const(LE_V4_0) .unwrap() .with_magic(Magic::Big) // Change magic bytes .with_all_endian(Endian::Big) // Set both type and data endian .with_version(4, 0); // Set version // Parse kind from string (useful for CLI tools) let kind = Kind::from_target("le_v4_0").unwrap(); // Clone/copy a kind from another let cloned_kind = Kind::from_kind(&kind); // Access kind properties println!("Magic: {:?}", kind.magic()); println!("Version: {}.{}", kind.version_major(), kind.version_minor()); ``` -------------------------------- ### Publish to Crates.io Source: https://github.com/wcampbell0x2a/backhand/blob/master/RELEASE.md Clean the workspace and publish the backhand and backhand-cli crates to crates.io. ```bash $ git clean -xdf $ cargo publish --locked -p backhand $ cargo publish --locked -p backhand-cli ``` -------------------------------- ### Upgrade Filesystem API from v0.7.0 to v0.8.0 Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Illustrates the API changes for creating a FilesystemWriter from a reader, highlighting the introduction of FilesystemReader and FilesystemWriter. ```diff ```diff -let squashfs = Squashfs::from_reader(file).unwrap(); -let mut filesystem = squashfs.into_filesystem().unwrap(); +let filesystem = FilesystemReader::from_reader(file).unwrap(); +let mut filesystem = FilesystemWriter::from_fs_reader(&filesystem).unwrap(); ``` ``` ```diff ```diff -let filesystem = Filesystem::from_reader(file).unwrap(); +let filesystem = FilesystemReader::from_reader(file).unwrap(); +let mut filesystem = FilesystemWriter::from_fs_reader(&filesystem).unwrap(); ``` ``` ```diff ```diff -FilesystemHeader +NodeHeader ``` ``` -------------------------------- ### unsquashfs-backhand Source: https://github.com/wcampbell0x2a/backhand/blob/master/README.md Tool to uncompress, extract, and list squashfs filesystems. ```APIDOC ## unsquashfs-backhand ### Description Tool to uncompress, extract and list squashfs filesystems. ### Usage `unsquashfs-backhand [OPTIONS] [FILESYSTEM]` ### Arguments * **FILESYSTEM** (string) - Squashfs file ### Options * **-o, --offset** (BYTES) - Skip BYTES at the start of FILESYSTEM. Default: 0. * **-a, --auto-offset** - Find first instance of squashfs --kind magic. * **-l, --list** - List filesystem, do not write to DEST (ignores --quiet). * **-d, --dest** (PATHNAME) - Extract to PATHNAME. Default: "squashfs-root". * **-i, --info** - Print files as they are extracted. * **--path-filter** (PATH_FILTER) - Limit filesystem extraction. Default: "/". * **-f, --force** - If file already exists then overwrite. * **-s, --stat** - Display filesystem superblock information (ignores --quiet). * **-k, --kind** (KIND) - Kind (type of image) to parse. If not specified, will auto-detect by trying all kinds. Possible values: le_v4_0, be_v4_0, le_v3_0, be_v3_0, le_v3_0_lzma, be_v3_0_lzma, netgear_be_v3_0_lzma_standard, netgear_be_v3_0_lzma, avm_be_v4_0. * **--completions** (COMPLETIONS) - Emit shell completion scripts. Possible values: bash, elvish, fish, powershell, zsh. * **--quiet** - Silence all progress bar and RUST_LOG output. * **-h, --help** - Print help (see more with '--help'). * **-V, --version** - Print version. ``` -------------------------------- ### Extract and List SquashFS with unsquashfs-backhand Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Provides various command-line operations for extracting, listing, and inspecting SquashFS images. ```bash # Basic extraction unsquashfs-backhand firmware.squashfs # Extract to specific directory unsquashfs-backhand -d /tmp/extracted firmware.squashfs # List files without extracting unsquashfs-backhand -l firmware.squashfs # Show superblock information unsquashfs-backhand -s --kind le_v4_0 firmware.squashfs # Extract with specific offset (for embedded images) unsquashfs-backhand --offset 0x40000 firmware.bin # Auto-detect offset by searching for magic bytes unsquashfs-backhand --auto-offset --kind le_v4_0 firmware.bin # Extract specific path only unsquashfs-backhand --path-filter /etc/config firmware.squashfs # Force overwrite existing files unsquashfs-backhand -f -d /tmp/out firmware.squashfs # Specify image format explicitly unsquashfs-backhand --kind avm_be_v4_0 fritzbox_firmware.bin # Show progress and file info during extraction unsquashfs-backhand -i firmware.squashfs # Quiet mode (no progress output) unsquashfs-backhand --quiet -d /tmp/out firmware.squashfs # Generate shell completions unsquashfs-backhand --completions bash > /etc/bash_completion.d/unsquashfs-backhand ``` -------------------------------- ### unsquashfs Command Line Tool Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Details on the `unsquashfs` command-line tool, including its options for image extraction and shell completion generation. ```APIDOC ## unsquashfs Command Line Tool ### Description The `unsquashfs` command-line tool is used for extracting files from SquashFS images. It supports various options for customizing the extraction process and generating shell completions. ### Options #### `--kind ` Specifies the type of SquashFS image to parse. This option is useful for handling custom or non-standard SquashFS image formats. - **Default**: `le_v4_0` - **Possible Values**: `be_v4_0`, `le_v4_0`, `amv_be_v4_0` #### `--completions` Generates shell completion scripts for various shells, aiding in command-line usability. #### `-o, --out ` Specifies the destination directory for the extracted SquashFS image content. ### Performance Benchmarked against the SquashFS image from `TP-Link AXE5400 Mesh Wi-Fi 6E Range Extender`. #### Speed In single-threaded mode, `backhand/unsquashfs` demonstrates comparable speed performance to `squashfs-tools/unsquashfs-v4.6.1`. #### Allocations In single-threaded mode, `backhand/unsquashfs` shows significantly lower peak heap memory consumption (18.1MB) compared to `squashfs-tools/unsquashfs-v4.6.1` (74.8MB). ### Version History #### v0.11.0 - 2023-03-14 ##### Added - Support for Read/Write of non-standard custom squashfs images: `LE_V4_0`, `BE_V4_0`, `AVM_BE_V4_0`. - `FilesystemWriter`: Builder pattern for mutating images, supporting raw images and modifications to existing ones. - `FilesystemCompressor`: Replaces `.compressor`, holding the Id and options for compression. - Error `InvalidCompressionOption`. - Default XZ compression level changed to 6. - Custom XZ filters for `FilesystemWriter`. - `FilesystemWriter::write()` now returns `(Superblock, bytes_written)`. - Updated `deku` to 0.16.0. - `add` command now reads file details to derive them when adding files. - `add` command now supports `--mtime`, `--uid`, `--gid`, and `--permission` flags to override file details. - `unsquashfs` now correctly extracts ownership and permission details. ##### Fixed - `ID` supports multiple IDs for GUI and UID in the table. - `id_table` is now a `u64` pointer. - Data is no longer copied when changing compression during `FilesystemWriter` usage. ##### Changed - Renamed `SquashfsError` to `BackhandError`. #### v0.10.1 - 2023-02-22 ##### Added - Zstd compression support. ##### Fixed - `FilesystemWriter` Debug impl now works. - `FilesystemReader::from_reader_with_offset(..)` now respects given offsets. - `FilesystemWriter::write_with_offset(..)` now respects given offsets. #### v0.10.0 - 2023-02-20 ##### Added - Fuzz testing with `cargo fuzz`. - `unsquashfs`: Added `-o, --out ` flag for output destination. - `replace`: Binary to replace files in squashfs filesystems. - Support for Lzo compression (feature `lzo`). ##### Fixed - Addressed issues found with fuzz testing related to legal images, with added checks. - Fixed `Compressor` id values for Lzo and Lzma. ##### Changed - Internal raw data passed by reference, improving `only_read` benchmarks by ~9%. - Invalid `Superblock.block_size` checked against MiB(1) instead of MB(1). #### v0.9.1 - 2023-02-16 ##### Fixed - Fixed `unsquashfs` extracting wrong file data. #### v0.9.0 - 2023-02-13 ##### Fixed - `FilesystemWriter::push_file(..)` correctly enters files into the filesystem. ``` -------------------------------- ### Update Filesystem::push_symlink signature Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Illustrates the simplified signature for `Filesystem::push_symlink`, now only requiring `path` and `link`. ```rust ```rust -Filesystem::push_symlink(..) +Filesystem::push_symlink(..) ``` ``` -------------------------------- ### Compression Utilities Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md API for managing filesystem compression and decompression actions. ```APIDOC ## [TRAIT] backhand::compression::CompressionAction ### Description Defines the interface for compression and decompression operations. ### Methods - **compress(&self, bytes: &[u8], fc: FilesystemCompressor, block_size: u32) -> Result, BackhandError>** - **decompress(&self, bytes: &[u8], out: &mut Vec, compressor: Compressor) -> Result<(), BackhandError>** ## [STRUCT] backhand::compression::DefaultCompressor ### Description Default implementation of the CompressionAction trait for handling Squashfs data compression. ``` -------------------------------- ### System CPU Information Source: https://github.com/wcampbell0x2a/backhand/blob/master/BENCHMARK.md Displays detailed information about the CPU, including architecture, core count, frequency, and supported features. This is useful for understanding the hardware context of benchmark results. ```bash $ lscpu ``` -------------------------------- ### Create Filesystem with Mod Time Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Introduces the inclusion of `mod_time` from `Squashfs` when creating a new image using `to_bytes(..)`. ```rust ```rust -mod_time from `Squashfs` to `Filesystem` used in creation of new image with `to_bytes(..)` +mod_time from `Squashfs` to `Filesystem` used in creation of new image with `to_bytes(..)` ``` ``` -------------------------------- ### Build backhand CLI for distribution Source: https://github.com/wcampbell0x2a/backhand/blob/master/BENCHMARK.md Builds the backhand CLI tools using the stable Rust toolchain with the dist profile. ```bash $ cargo +stable build -p backhand-cli --bins --locked --profile=dist ``` -------------------------------- ### FilesystemWriter API Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Provides methods for creating and writing to SquashFS filesystems. ```APIDOC ## FilesystemWriter API ### Description Provides methods for creating and writing to SquashFS filesystems. ### Methods #### `from_fs_reader` - **Description**: Creates a `FilesystemWriter` from an existing `FilesystemReader`. - **Parameters**: - `reader` (&'a backhand::FilesystemReader): A reference to the `FilesystemReader` to base the writer on. - **Returns**: A `Result` containing either a `FilesystemWriter` or a `BackhandError`. #### `mut_file` - **Description**: Gets a mutable reference to a file writer for a specific file path. - **Parameters**: - `find_path` (S: `core::convert::Into`): The path to the file to modify. - **Returns**: An `Option` containing a mutable reference to a `SquashfsFileWriter` if the file exists, otherwise `None`. #### `push_block_device` - **Description**: Adds a block device entry to the filesystem. - **Parameters**: - `device_number` (u32): The device number. - `path` (P: `core::convert::Into`): The path for the block device entry. - `header` (backhand::NodeHeader): The node header for the entry. #### `push_char_device` - **Description**: Adds a character device entry to the filesystem. - **Parameters**: - `device_number` (u32): The device number. - `path` (P: `core::convert::Into`): The path for the character device entry. - `header` (backhand::NodeHeader): The node header for the entry. #### `push_dir` - **Description**: Adds a directory entry to the filesystem. - **Parameters**: - `path` (P: `core::convert::Into`): The path for the directory. - `header` (backhand::NodeHeader): The node header for the entry. #### `push_file` - **Description**: Adds a file entry to the filesystem. - **Parameters**: - `reader` (impl `std::io::Read` + 'a): A reader for the file's content. - `path` (P: `core::convert::Into`): The path for the file. - `header` (backhand::NodeHeader): The node header for the entry. #### `push_symlink` - **Description**: Adds a symbolic link entry to the filesystem. - **Parameters**: - `link` (S: `core::convert::Into`): The target path of the symlink. - `path` (P: `core::convert::Into`): The path for the symlink entry. - `header` (backhand::NodeHeader): The node header for the entry. #### `replace_file` - **Description**: Replaces an existing file in the filesystem with new content. - **Parameters**: - `find_path` (S: `core::convert::Into`): The path of the file to replace. - `reader` (impl `std::io::Read` + 'a): A reader for the new file content. - **Returns**: A `Result` indicating success or a `BackhandError`. #### `write` - **Description**: Writes the current state of the `FilesystemWriter` to a given writer. - **Parameters**: - `w` (&mut W: `std::io::Write` + `std::io::Seek`): The writer to write the filesystem to. - **Returns**: A `Result` containing the `SuperBlock` and the total bytes written, or a `BackhandError`. #### `write_with_offset` - **Description**: Writes the current state of the `FilesystemWriter` to a given writer with a specified offset. - **Parameters**: - `w` (&mut W: `std::io::Write` + `std::io::Seek`): The writer to write the filesystem to. - `offset` (u64): The offset at which to start writing. - **Returns**: A `Result` containing the `SuperBlock` and the total bytes written, or a `BackhandError`. ### Traits - **`Default`**: Implements the `Default` trait for `FilesystemWriter`. - **`Debug`**: Implements the `Debug` trait for `FilesystemWriter`. ``` -------------------------------- ### Run Workspace Tests Source: https://github.com/wcampbell0x2a/backhand/blob/master/backhand-test/README.md Executes all tests across the entire workspace with all features enabled in release mode. ```bash $ cargo test --workspace --release --all-features ``` -------------------------------- ### Bump Project Versions Source: https://github.com/wcampbell0x2a/backhand/blob/master/RELEASE.md Use cargo-release to update versions for the backhand library and CLI tool. ```bash $ cargo release version [LEVEL] -p backhand -p backhand-cli --execute $ cargo release replace -p backhand -p backhand-cli --execute ``` -------------------------------- ### Allow writing with owned or mut ref writer Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Demonstrates how to call `FilesystemWriter::write` with either an owned writer or a mutable reference to a writer. This change allows for more flexibility in how writers are handled. ```diff - let mut output = File::create(&args.out).unwrap(); - if let Err(e) = filesystem.write(&mut output) { + let output = File::create(&args.out).unwrap(); + if let Err(e) = filesystem.write(output) { ``` -------------------------------- ### Read and Iterate SquashFS Image Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Opens a SquashFS image, parses its structure, and iterates through all files and directories, printing their metadata. Requires `std::fs::File` and `backhand` crate. ```rust use std::fs::File; use std::io::BufReader; use backhand::{FilesystemReader, InnerNode}; // Open and read a SquashFS image let file = BufReader::new(File::open("firmware.squashfs").unwrap()); let filesystem = FilesystemReader::from_reader(file).unwrap(); // Access filesystem metadata println!("Block size: {}", filesystem.block_size); println!("Compressor: {:?}", filesystem.compressor); println!("Modification time: {}", filesystem.mod_time); // Iterate through all files and directories for node in filesystem.files() { let path = &node.fullpath; let header = &node.header; match &node.inner { InnerNode::File(file_info) => { println!("File: {} (size: {} bytes, mode: {:o})", path.display(), file_info.file_len(), header.permissions); } InnerNode::Dir(_) => { println!("Directory: {}", path.display()); } InnerNode::Symlink(symlink) => { println!("Symlink: {} -> {}", path.display(), symlink.link.display()); } InnerNode::CharacterDevice(dev) => { println!("Character device: {} (dev: {})", path.display(), dev.device_number); } InnerNode::BlockDevice(dev) => { println!("Block device: {} (dev: {})", path.display(), dev.device_number); } InnerNode::NamedPipe => println!("FIFO: {}", path.display()), InnerNode::Socket => println!("Socket: {}", path.display()), } } ``` -------------------------------- ### FilesystemWriter API Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Methods for constructing and modifying Squashfs filesystems. ```APIDOC ## FilesystemWriter::push_file ### Description Adds a new file to the Squashfs filesystem being constructed. ### Method Rust Function ### Parameters #### Request Body - **reader** (impl Read) - Required - The source data for the file. - **path** (AsRef) - Required - The destination path in the filesystem. - **header** (NodeHeader) - Required - Metadata for the file node. ### Response #### Success Response (Result) - **()** - Returns Ok on success or BackhandError on failure. ``` -------------------------------- ### Compression Options API Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Methods for retrieving compression options for Squashfs archives. ```APIDOC ## fn backhand::compression::DefaultCompressor::compression_options ### Description Retrieves the compression options for the default compressor. ### Parameters - **superblock** (&mut backhand::SuperBlock) - Required - The archive superblock. - **kind** (&backhand::kind::Kind) - Required - The archive kind. - **fs_compressor** (backhand::FilesystemCompressor) - Required - The filesystem compressor configuration. ### Response - **Result, backhand::BackhandError>** - Returns the compression options as a byte vector or an error. ``` -------------------------------- ### Core Library Components Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Documentation for core components and traits within the Backhand library, including file reading, data structures, and error handling. ```APIDOC ## Core Library Components ### Traits and Implementations #### `core::marker::Copy` for `backhand::SquashfsCharacterDevice` Indicates that `SquashfsCharacterDevice` can be copied. #### `core::default::Default` for `backhand::SquashfsDir` Provides a default value for `SquashfsDir`. - **Function**: `backhand::SquashfsDir::default()` returns a default `SquashfsDir`. #### `core::marker::Copy` for `backhand::SquashfsDir` Indicates that `SquashfsDir` can be copied. #### `std::io::Read` for `backhand::SquashfsReadFile<'a>` Implements the `Read` trait for `SquashfsReadFile`, allowing it to be read from. - **Function**: `backhand::SquashfsReadFile::read(&mut self, buf: &mut [u8]) -> std::io::error::Result` reads data into a buffer. #### `backhand::SuperBlock` Represents the superblock of a SquashFS file system. - **`DekuRead` Implementation**: `impl deku::DekuRead<'_, ([u8; 4], u16, u16, deku::ctx::Endian)> for backhand::SuperBlock` - **Function**: `backhand::SuperBlock::read(__deku_input_bits: &bitvec::slice::BitSlice, (ctx_magic, ctx_version_major, ctx_version_minor, ctx_type_endian): ([u8; 4], u16, u16, deku::ctx::Endian)) -> core::result::Result<(&bitvec::slice::BitSlice, Self), deku::error::DekuError>` reads the superblock from bit data. - **`DekuWrite` Implementation**: `impl deku::DekuWrite<([u8; 4], u16, u16, deku::ctx::Endian)> for backhand::SuperBlock` - **Function**: `backhand::SuperBlock::write(&self, __deku_output: &mut bitvec::vec::BitVec, (ctx_magic, ctx_version_major, ctx_version_minor, ctx_type_endian): ([u8; 4], u16, u16, deku::ctx::Endian)) -> core::result::Result<(), deku::error::DekuError>` writes the superblock to bit data. #### `backhand::BufReadSeek` Trait Combines `std::io::BufRead` and `std::io::Seek` traits. - **Implementation**: `impl backhand::BufReadSeek for T` allows any type implementing both `BufRead` and `Seek` to be used as `BufReadSeek`. ### Error Handling - **`BackhandError`**: Renamed from `SquashfsError`, this enum encompasses various errors that can occur during Backhand operations. - **`InvalidCompressionOption`**: A specific error indicating an invalid compression option was provided. ``` -------------------------------- ### add-backhand Source: https://github.com/wcampbell0x2a/backhand/blob/master/README.md Tool to add a file or directory to squashfs filesystems. ```APIDOC ## add-backhand ### Description Tool to add a file or directory to squashfs filesystems. ### Usage `add-backhand [OPTIONS] ` ### Arguments * **INPUT_IMAGE** (string) - Squashfs input image. * **FILE_PATH_IN_IMAGE** (string) - Path of file once inserted into squashfs. * **OUTPUT_IMAGE** (string) - Squashfs output image path. ### Options * **-d, --dir** - Create empty directory. * **-f, --file** (FILE) - Path of file to read, to write into squashfs. * **--mode** (MODE) - Override mode read from . * **--uid** (UID) - Override uid read from . * **--gid** (GID) - Override gid read from . * **--mtime** (MTIME) - Override mtime read from . * **--pad-len** (PAD_LEN) - Custom KiB padding length. * **--no-compression-options** - Don't emit compression options. * **-h, --help** - Print help. * **-V, --version** - Print version. ``` -------------------------------- ### Update File Iteration Method Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Replaces direct iteration over nodes with the new files() method. ```diff - for node in &filesystem.nodes { + for node in filesystem.files() { ``` -------------------------------- ### replace-backhand Source: https://github.com/wcampbell0x2a/backhand/blob/master/README.md Tool to replace files in squashfs filesystems. ```APIDOC ## replace-backhand ### Description Tool to replace files in squashfs filesystems. ### Usage `replace-backhand [OPTIONS] ` ### Arguments * **INPUT_IMAGE** (string) - Squashfs input image. * **FILE** (string) - Path of file to read, to write into squashfs. * **FILE_PATH_IN_IMAGE** (string) - Path of file replaced in image. * **OUTPUT_IMAGE** (string) - Squashfs output image. ### Options * **--pad-len** (PAD_LEN) - Custom KiB padding length. * **--no-compression-options** - Don't emit compression options. * **-h, --help** - Print help. * **-V, --version** - Print version. ``` -------------------------------- ### FilesystemReader API Source: https://github.com/wcampbell0x2a/backhand/blob/master/CHANGELOG.md Provides methods for creating and interacting with a FilesystemReader for SquashFS images. ```APIDOC ## FilesystemReader API ### Description Provides methods for creating and interacting with a FilesystemReader for SquashFS images. ### Methods #### `from_reader` - **Description**: Creates a `FilesystemReader` from a given reader. - **Parameters**: - `reader` (R): The reader to use for accessing the filesystem data. - **Returns**: A `Result` containing either a `FilesystemReader` or a `BackhandError`. #### `from_reader_with_offset` - **Description**: Creates a `FilesystemReader` from a given reader with a specified offset. - **Parameters**: - `reader` (R): The reader to use for accessing the filesystem data. - `offset` (u64): The offset within the reader where the filesystem begins. - **Returns**: A `Result` containing either a `FilesystemReader` or a `BackhandError`. #### `from_reader_with_offset_and_kind` - **Description**: Creates a `FilesystemReader` from a given reader with a specified offset and filesystem kind. - **Parameters**: - `reader` (R): The reader to use for accessing the filesystem data. - `offset` (u64): The offset within the reader where the filesystem begins. - `kind` (backhand::kind::Kind): The kind of the SquashFS filesystem. - **Returns**: A `Result` containing either a `FilesystemReader` or a `BackhandError`. ### Debugging - **Description**: Implements the `Debug` trait for `FilesystemReader`. - **Requirements**: The generic type `R` must implement `core::fmt::Debug` and `backhand::ReadSeek`. ### Formatting - **Description**: Implements the `fmt` method for formatting the `FilesystemReader`. - **Requirements**: The generic type `R` must implement `backhand::ReadSeek`. ``` -------------------------------- ### Replace Files with replace-backhand Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Commands for replacing existing files in SquashFS images while maintaining original metadata. ```bash # Replace an existing file replace-backhand input.squashfs newcontent.txt /etc/config.txt output.squashfs # Replace with custom padding replace-backhand input.squashfs newbinary /usr/bin/app output.squashfs \ --pad-len 4 # Replace without compression options replace-backhand input.squashfs newfile.txt /data/file.txt output.squashfs \ --no-compression-options ``` -------------------------------- ### Modify SquashFS with add-backhand Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Commands for adding files, directories, and setting metadata within existing SquashFS images. ```bash # Add a file to a SquashFS image add-backhand input.squashfs /etc/newfile.txt output.squashfs -f localfile.txt # Create an empty directory add-backhand input.squashfs /opt/myapp output.squashfs --dir # Add file with custom permissions and ownership add-backhand input.squashfs /usr/bin/script output.squashfs \ -f script.sh \ --mode 0755 \ --uid 0 \ --gid 0 \ --mtime 1700000000 # Custom padding length (KiB) add-backhand input.squashfs /data/file output.squashfs \ -f data.bin \ --pad-len 8 # Disable compression options in output add-backhand input.squashfs /etc/config output.squashfs \ -f config.txt \ --no-compression-options ``` -------------------------------- ### Run Coverage for Specific Binaries Source: https://github.com/wcampbell0x2a/backhand/blob/master/backhand-test/README.md Generates code coverage reports for individual binaries using cargo-llvm-cov. Use --no-clean to avoid cleaning the build artifacts before running. ```bash $ cargo llvm-cov run --bin replace --no-clean --release ``` ```bash $ cargo llvm-cov run --bin add --no-clean --release ``` ```bash $ cargo llvm-cov run --bin unsquashfs --no-clean --release ``` -------------------------------- ### Usage: unsquashfs-backhand Source: https://github.com/wcampbell0x2a/backhand/blob/master/README.md Tool to decompress, extract, and list squashfs filesystems. Use options to control extraction path, overwrite behavior, and display information. ```bash unsquashfs-backhand [OPTIONS] [FILESYSTEM] ``` -------------------------------- ### Read SquashFS File Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Opens and reads a SquashFS file using FilesystemReader. Requires standard library file operations and Backhand's reader functionality. ```rust use std::fs::File; use std::io::{BufReader, Cursor}; use backhand::{FilesystemReader, FilesystemWriter, NodeHeader, BackhandError}; fn read_squashfs(path: &str) -> Result<(), BackhandError> { let file = BufReader::new(File::open(path)?); let filesystem = FilesystemReader::from_reader(file)?; println!("Read {} files", filesystem.files().count()); Ok(()) } ``` -------------------------------- ### Usage: add-backhand Source: https://github.com/wcampbell0x2a/backhand/blob/master/README.md Tool to add a file or directory to squashfs filesystems. Specify input and output image paths, and the desired path for the new file within the image. ```bash add-backhand [OPTIONS] ``` -------------------------------- ### Modify SquashFS File with Error Handling Source: https://context7.com/wcampbell0x2a/backhand/llms.txt Demonstrates modifying a SquashFS file using FilesystemWriter, including specific error handling for duplicated filenames and invalid file paths. Also shows handling of FileNotFoundError. ```rust use std::fs::File; use std::io::{BufReader, Cursor}; use backhand::{FilesystemReader, FilesystemWriter, NodeHeader, BackhandError}; fn modify_squashfs() -> Result<(), BackhandError> { let file = BufReader::new(File::open("input.squashfs")?); let reader = FilesystemReader::from_reader(file)?; let mut writer = FilesystemWriter::from_fs_reader(&reader)?; let header = NodeHeader::default(); // Handle specific errors match writer.push_file(Cursor::new(b"data"), "existing/path/file", header) { Ok(()) => println!("File added successfully"), Err(BackhandError::DuplicatedFileName) => { println!("File already exists, replacing..."); writer.replace_file("existing/path/file", Cursor::new(b"new data"))?; } Err(BackhandError::InvalidFilePath) => { println!("Parent directory doesn't exist, creating..."); writer.push_dir_all("existing/path", header)?; writer.push_file(Cursor::new(b"data"), "existing/path/file", header)?; } Err(e) => return Err(e), } // Handle file not found match writer.replace_file("/nonexistent", Cursor::new(b"data")) { Err(BackhandError::FileNotFound) => println!("File not found in image"), _ => {} } let mut output = File::create("output.squashfs")?; writer.write(&mut output)?; Ok(()) } ``` -------------------------------- ### Generate HTML Coverage Report Source: https://github.com/wcampbell0x2a/backhand/blob/master/backhand-test/README.md Generates an HTML code coverage report for the entire workspace, including all features, in release mode. The --skip slow flag is used to exclude slow tests from the coverage run. ```bash $ cargo llvm-cov --html --workspace --all-features --release --no-clean -- --skip slow ```