Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package backhand for openSUSE:Factory checked in at 2026-03-02 17:35:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/backhand (Old) and /work/SRC/openSUSE:Factory/.backhand.new.29461 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "backhand" Mon Mar 2 17:35:26 2026 rev:6 rq:1335613 version:0.25.1 Changes: -------- --- /work/SRC/openSUSE:Factory/backhand/backhand.changes 2026-02-16 13:17:26.586327934 +0100 +++ /work/SRC/openSUSE:Factory/.backhand.new.29461/backhand.changes 2026-03-02 17:35:29.303211421 +0100 @@ -1,0 +2,12 @@ +Sun Mar 1 08:42:28 UTC 2026 - Martin Hauke <[email protected]> + +- Update to version 0.25.1: + backhand + * v3: Add kinds: BE_V3_1_LZMA_SWAP and LE_V3_1_LZMA_SWAP + + Big and little endian, with special magic. + + General support for v3.1, no on-disk changes. + * v3: Fall back to standard LZMA even if adaptive is picked. + backhand-cli + * Add --kinds: le_v3_1_lzma_swap and be_v3_1_lzma_swap + +------------------------------------------------------------------- Old: ---- backhand-0.25.0.obscpio New: ---- backhand-0.25.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ backhand.spec ++++++ --- /var/tmp/diff_new_pack.ysTM49/_old 2026-03-02 17:35:34.927445980 +0100 +++ /var/tmp/diff_new_pack.ysTM49/_new 2026-03-02 17:35:34.943446647 +0100 @@ -2,7 +2,7 @@ # spec file for package backhand # # Copyright (c) 2026 SUSE LLC and contributors -# Copyright (c) 2025, Martin Hauke <[email protected]> +# Copyright (c) 2025-2026, Martin Hauke <[email protected]> # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ Name: backhand -Version: 0.25.0 +Version: 0.25.1 Release: 0 Summary: Tools for the reading, creating, and modification of SquashFS file systems License: Apache-2.0 OR MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.ysTM49/_old 2026-03-02 17:35:35.183456657 +0100 +++ /var/tmp/diff_new_pack.ysTM49/_new 2026-03-02 17:35:35.187456824 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/wcampbell0x2a/backhand</param> <param name="versionformat">@PARENT_TAG@</param> <param name="scm">git</param> - <param name="revision">v0.25.0</param> + <param name="revision">v0.25.1</param> <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param> <param name="changesgenerate">enable</param> </service> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.ysTM49/_old 2026-03-02 17:35:35.379464831 +0100 +++ /var/tmp/diff_new_pack.ysTM49/_new 2026-03-02 17:35:35.411466166 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/wcampbell0x2a/backhand</param> - <param name="changesrevision">fa6c586fd24af3789992b8034eeec64b7bcc8498</param></service></servicedata> + <param name="changesrevision">4ac463be1071219b46fc0184ce452704ea705ba0</param></service></servicedata> (No newline at EOF) ++++++ backhand-0.25.0.obscpio -> backhand-0.25.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/CHANGELOG.md new/backhand-0.25.1/CHANGELOG.md --- old/backhand-0.25.0/CHANGELOG.md 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/CHANGELOG.md 2026-02-28 20:30:10.000000000 +0100 @@ -7,6 +7,16 @@ ## [Unreleased] +## [v0.25.1] - 2025-02-28 +### `backhand` +- v3: Add kinds: `BE_V3_1_LZMA_SWAP` and `LE_V3_1_LZMA_SWAP` + - Big and little endian, with special magic. + - General support for v3.1, no on-disk changes. +- v3: Fall back to standard LZMA even if adaptive is picked. Thanks vendors! + +### `backhand-cli` +- Add --kinds: `le_v3_1_lzma_swap` and `be_v3_1_lzma_swap` + ## [v0.25.0] - 2025-02-14 ### `backhand` - Update depends diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/Cargo.lock new/backhand-0.25.1/Cargo.lock --- old/backhand-0.25.0/Cargo.lock 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/Cargo.lock 2026-02-28 20:30:10.000000000 +0100 @@ -112,7 +112,7 @@ [[package]] name = "backhand" -version = "0.25.0" +version = "0.25.1" dependencies = [ "assert_cmd", "criterion", @@ -142,7 +142,7 @@ [[package]] name = "backhand-cli" -version = "0.25.0" +version = "0.25.1" dependencies = [ "backhand", "clap", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/Cargo.toml new/backhand-0.25.1/Cargo.toml --- old/backhand-0.25.0/Cargo.toml 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/Cargo.toml 2026-02-28 20:30:10.000000000 +0100 @@ -9,7 +9,7 @@ resolver = "2" [workspace.package] -version = "0.25.0" +version = "0.25.1" authors = ["wcampbell <[email protected]>"] license = "MIT OR Apache-2.0" edition = "2024" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand/src/kinds.rs new/backhand-0.25.1/backhand/src/kinds.rs --- old/backhand-0.25.0/backhand/src/kinds.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand/src/kinds.rs 2026-02-28 20:30:10.000000000 +0100 @@ -232,6 +232,10 @@ "netgear_be_v3_0_lzma" => NETGEAR_BE_V3_0_LZMA, #[cfg(feature = "v3_lzma")] "netgear_be_v3_0_lzma_standard" => NETGEAR_BE_V3_0_LZMA_STANDARD, + #[cfg(feature = "v3_lzma")] + "le_v3_1_lzma_swap" => LE_V3_1_LZMA_SWAP, + #[cfg(feature = "v3_lzma")] + "be_v3_1_lzma_swap" => BE_V3_1_LZMA_SWAP, _ => return Err("not a valid kind".to_string()), }; @@ -431,3 +435,27 @@ compressor: VersionedCompressor::V3LzmaStandard(&V3_LZMA_STANDARD_COMPRESSOR), bit_order: Some(deku::ctx::Order::Msb0), }; + +/// Little-Endian SquashFS v3.1 with LZMA compression and swapped magic (Thomson/Technicolor/NETGEAR) +#[cfg(feature = "v3_lzma")] +pub const LE_V3_1_LZMA_SWAP: InnerKind = InnerKind { + magic: *b"shsq", + type_endian: deku::ctx::Endian::Little, + data_endian: deku::ctx::Endian::Little, + version_major: 3, + version_minor: 1, + compressor: VersionedCompressor::V3Lzma(&V3LzmaCompressor), + bit_order: Some(deku::ctx::Order::Lsb0), +}; + +/// Big-Endian SquashFS v3.1 with LZMA compression and swapped magic (Thomson/Technicolor/NETGEAR) +#[cfg(feature = "v3_lzma")] +pub const BE_V3_1_LZMA_SWAP: InnerKind = InnerKind { + magic: *b"shsq", + type_endian: deku::ctx::Endian::Big, + data_endian: deku::ctx::Endian::Big, + version_major: 3, + version_minor: 1, + compressor: VersionedCompressor::V3Lzma(&V3LzmaCompressor), + bit_order: Some(deku::ctx::Order::Msb0), +}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand/src/lib.rs new/backhand-0.25.1/backhand/src/lib.rs --- old/backhand-0.25.0/backhand/src/lib.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand/src/lib.rs 2026-02-28 20:30:10.000000000 +0100 @@ -103,7 +103,8 @@ pub use crate::kinds::{BE_V3_0, LE_V3_0}; #[cfg(feature = "v3_lzma")] pub use crate::kinds::{ - BE_V3_0_LZMA, LE_V3_0_LZMA, NETGEAR_BE_V3_0_LZMA, NETGEAR_BE_V3_0_LZMA_STANDARD, + BE_V3_0_LZMA, BE_V3_1_LZMA_SWAP, LE_V3_0_LZMA, LE_V3_1_LZMA_SWAP, NETGEAR_BE_V3_0_LZMA, + NETGEAR_BE_V3_0_LZMA_STANDARD, }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand/src/traits/squashfs.rs new/backhand-0.25.1/backhand/src/traits/squashfs.rs --- old/backhand-0.25.0/backhand/src/traits/squashfs.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand/src/traits/squashfs.rs 2026-02-28 20:30:10.000000000 +0100 @@ -122,7 +122,7 @@ let (major, minor) = (kind.version_major(), kind.version_minor()); match (major, minor) { #[cfg(feature = "v3")] - (3, 0) => { + (3, 0) | (3, 1) => { let squashfs = crate::v3::squashfs::Squashfs::from_reader_with_offset_and_kind( reader, offset, kind, )?; @@ -130,7 +130,7 @@ Ok(Box::new(filesystem) as Box<dyn FilesystemReaderTrait + 'b>) } #[cfg(not(feature = "v3"))] - (3, 0) => Err(crate::error::BackhandError::UnsupportedSquashfsVersion(3, 0)), + (3, 0) | (3, 1) => Err(crate::error::BackhandError::UnsupportedSquashfsVersion(3, 0)), (4, 0) => { let squashfs = crate::v4::squashfs::Squashfs::from_reader_with_offset_and_kind( reader, offset, kind, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand/src/v3/metadata.rs new/backhand-0.25.1/backhand/src/v3/metadata.rs --- old/backhand-0.25.0/backhand/src/v3/metadata.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand/src/v3/metadata.rs 2026-02-28 20:30:10.000000000 +0100 @@ -18,14 +18,22 @@ let mut deku_reader = Reader::new(&mut *reader); let metadata_len = u16::from_reader_with_ctx(&mut deku_reader, kind.inner.data_endian)?; + if superblock.check_data() { + let mut check_byte = [0u8; 1]; + reader.read_exact(&mut check_byte)?; + tracing::trace!("check_data: skipped check byte 0x{:02x}", check_byte[0]); + } + let byte_len = len(metadata_len); tracing::trace!("len: 0x{:02x?}", byte_len); let mut buf = vec![0u8; byte_len as usize]; reader.read_exact(&mut buf)?; + // NOTE: We intentionally ignore superblock.inodes_uncompressed() here. + // Some v3 images set that flag but still use per-block compression, + // so we rely solely on the per-block compressed bit. let is_block_compressed = is_compressed(metadata_len); - let is_superblock_uncompressed = superblock.inodes_uncompressed(); - let bytes = if is_block_compressed && !is_superblock_uncompressed { + let bytes = if is_block_compressed { let mut out = Vec::with_capacity(8 * 1024); kind.inner.compressor.decompress(&buf, &mut out, None)?; out diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand/src/v3/reader.rs new/backhand-0.25.1/backhand/src/v3/reader.rs --- old/backhand-0.25.0/backhand/src/v3/reader.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand/src/v3/reader.rs 2026-02-28 20:30:10.000000000 +0100 @@ -10,7 +10,7 @@ use super::export::Export; use super::fragment::Fragment; -use super::inode::{Inode, InodeInner}; +use super::inode::Inode; use super::metadata::METADATA_MAXSIZE; use super::squashfs::SuperBlock; use super::{fragment, metadata}; @@ -92,23 +92,16 @@ metadata_offsets.push(self.stream_position()? - start); // parse into metadata let mut bytes = metadata::read_block(self, superblock, kind)?; - trace!("wowo"); // parse as many inodes as you can let mut inode_bytes = next; inode_bytes.append(&mut bytes); - trace!("after"); let mut c_inode_bytes = Cursor::new(inode_bytes.clone()); - // trace!("{:02x?}", &c_inode_bytes); let mut container = Reader::new(&mut c_inode_bytes); // store last successful read position let mut container_bits_read = container.bits_read; loop { - tracing::debug!( - "rest: {:02x?}", - inode_bytes.clone()[(container_bits_read / 8)..].to_vec() - ); match Inode::from_reader_with_ctx( &mut container, ( @@ -120,20 +113,17 @@ ), ) { Ok(inode) => { - // Push the new Inode to the return, with the position this was read from - tracing::debug!("new: {inode:02x?}"); ret_vec.insert(inode.header.inode_number, inode); container_bits_read = container.bits_read; } Err(e) => { - trace!("err"); if matches!(e, DekuError::Incomplete(_)) { // try next block, inodes can span multiple blocks! next = inode_bytes.clone()[(container_bits_read / 8)..].to_vec(); break; } else { - // panic!("{:?} {:02x?}", e, c_inode_bytes); - panic!("{:?}", e); + error!("Fatal error parsing inode: {:?}", e); + return Err(BackhandError::Deku(e)); } } } @@ -141,20 +131,10 @@ } if ret_vec.len() != superblock.inode_count.try_into().unwrap() { - panic!("Parsed {} inodes, expected {}", ret_vec.len(), superblock.inode_count); + error!("Parsed {} inodes, expected {}", ret_vec.len(), superblock.inode_count); + return Err(BackhandError::CorruptedOrInvalidSquashfs); } - // Debug: Print out directory inode numbers to see what we have - let mut _dir_inodes: Vec<_> = ret_vec - .iter() - .filter_map(|(inode_num, inode)| match &inode.inner { - InodeInner::BasicDirectory(_) | InodeInner::ExtendedDirectory(_) => { - Some(*inode_num) - } - _ => None, - }) - .collect(); - Ok(ret_vec) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand/src/v3/squashfs.rs new/backhand-0.25.1/backhand/src/v3/squashfs.rs --- old/backhand-0.25.0/backhand/src/v3/squashfs.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand/src/v3/squashfs.rs 2026-02-28 20:30:10.000000000 +0100 @@ -144,6 +144,11 @@ pub fn nfs_export_table_exists(&self) -> bool { u16::from(self.flags) & Flags::NFSExportTableExists as u16 != 0 } + + /// If set to true, metadata blocks have a leading check byte + pub fn check_data(&self) -> bool { + u16::from(self.flags) & Flags::Unused as u16 != 0 + } } #[derive(Default, Clone, Debug)] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand/src/v3_lzma/compressor.rs new/backhand-0.25.1/backhand/src/v3_lzma/compressor.rs --- old/backhand-0.25.0/backhand/src/v3_lzma/compressor.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand/src/v3_lzma/compressor.rs 2026-02-28 20:30:10.000000000 +0100 @@ -1,5 +1,7 @@ use std::sync::Mutex; +use no_std_io2::io::Read; + pub use crate::traits::CompressionAction; pub use crate::traits::types::Compressor; use tracing::trace; @@ -61,6 +63,16 @@ return Ok(()); } + // Fall back to standard LZMA (some blocks like fragments in le_v3_0_lzma_swap use standard format) + trace!("Adaptive LZMA failed, trying standard LZMA"); + if let Ok(mut reader) = lzma_rust2::LzmaReader::new_mem_limit(bytes, u32::MAX, None) { + if reader.read_to_end(out).is_ok() { + trace!("Standard LZMA decompression successful: {} bytes", out.len()); + return Ok(()); + } + out.clear(); + } + Err(crate::BackhandError::UnsupportedCompression( "Failed to decompress LZMA adaptive data".to_string(), )) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand-cli/Cargo.toml new/backhand-0.25.1/backhand-cli/Cargo.toml --- old/backhand-0.25.0/backhand-cli/Cargo.toml 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand-cli/Cargo.toml 2026-02-28 20:30:10.000000000 +0100 @@ -19,7 +19,7 @@ indicatif = "0.18.3" console = "0.16.1" rayon = "1.10.0" -backhand = { path = "../backhand", default-features = false, version = "0.25.0" } +backhand = { path = "../backhand", default-features = false, version = "0.25.1" } tracing = "0.1.40" color-print = "0.3.6" clap-cargo = "0.18.3" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand-cli/src/bin/unsquashfs.rs new/backhand-0.25.1/backhand-cli/src/bin/unsquashfs.rs --- old/backhand-0.25.0/backhand-cli/src/bin/unsquashfs.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand-cli/src/bin/unsquashfs.rs 2026-02-28 20:30:10.000000000 +0100 @@ -49,6 +49,10 @@ "netgear_be_v3_0_lzma_standard", #[cfg(feature = "v3_lzma")] "netgear_be_v3_0_lzma", + #[cfg(feature = "v3_lzma")] + "le_v3_1_lzma_swap", + #[cfg(feature = "v3_lzma")] + "be_v3_1_lzma_swap", "avm_be_v4_0", ]; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/backhand-test/tests/v3.rs new/backhand-0.25.1/backhand-test/tests/v3.rs --- old/backhand-0.25.0/backhand-test/tests/v3.rs 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/backhand-test/tests/v3.rs 2026-02-28 20:30:10.000000000 +0100 @@ -139,3 +139,17 @@ "be_v3_0_lzma", ); } + +#[test] +#[cfg(feature = "v3_lzma")] +fn test_v3_lzma_swap() { + use backhand::kind::LE_V3_1_LZMA_SWAP; + + common::download_asset("v3_le_lzma_swap"); + only_read( + Kind::from_const(LE_V3_1_LZMA_SWAP).unwrap(), + "test-assets/squashfs_v3_le_lzma_swap.sqfs", + 0, + "le_v3_1_lzma_swap", + ); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backhand-0.25.0/test-assets.toml new/backhand-0.25.1/test-assets.toml --- old/backhand-0.25.0/test-assets.toml 2026-02-14 22:04:50.000000000 +0100 +++ new/backhand-0.25.1/test-assets.toml 2026-02-28 20:30:10.000000000 +0100 @@ -211,3 +211,8 @@ filepath = "test-assets/many_dirs_v3/many_dirs_v3.sqsh" hash = "00d9b4d0dbe98fdb57997da7481b1a6ffaa812aa536d3d8e1c72a8c3eb71e6c4" url = "https://wcampbell.dev/squashfs/testing/many_dirs_v3.sqsh" + +[test_assets.v3_le_lzma_swap] +filepath = "test-assets/squashfs_v3_le_lzma_swap.sqfs" +hash = "2eada74aee4336c4489b4a3551b73471785bc2a7a760f4acbb8bc94faa586197" +url = "https://wcampbell.dev/squashfs/testing/squashfs_v3_le_lzma_swap.sqfs" ++++++ backhand.obsinfo ++++++ --- /var/tmp/diff_new_pack.ysTM49/_old 2026-03-02 17:35:36.439509040 +0100 +++ /var/tmp/diff_new_pack.ysTM49/_new 2026-03-02 17:35:36.471510375 +0100 @@ -1,5 +1,5 @@ name: backhand -version: 0.25.0 -mtime: 1771103090 -commit: fa6c586fd24af3789992b8034eeec64b7bcc8498 +version: 0.25.1 +mtime: 1772307010 +commit: 4ac463be1071219b46fc0184ce452704ea705ba0 ++++++ vendor.tar.zst ++++++ /work/SRC/openSUSE:Factory/backhand/vendor.tar.zst /work/SRC/openSUSE:Factory/.backhand.new.29461/vendor.tar.zst differ: char 7, line 1
