severity 1123504 serious found 1123504 1.1.0-5 retitle 1123504 thin-provisioning-tools - rust dependency updates
I hope to update rust-termion to version 4 soon, the debian dependencies in thin-provisioning-tools allow the new version but the cargo dependencies do not.
The new version of termion is now in sid, so this is now a ftbfs I also have a couple more rust package updates coming up that will affect thin-privisioning-tools, I've prepared an updated debdiff to cover those too.
diff -Nru thin-provisioning-tools-1.1.0/debian/changelog thin-provisioning-tools-1.1.0/debian/changelog --- thin-provisioning-tools-1.1.0/debian/changelog 2025-10-19 12:15:27.000000000 +0000 +++ thin-provisioning-tools-1.1.0/debian/changelog 2025-12-17 00:59:31.000000000 +0000 @@ -1,3 +1,12 @@ +thin-provisioning-tools (1.1.0-5.1) UNRELEASED; urgency=medium + + * Non-maintainer upload. + * Relax cargo dependencies on termion, fixedbitset, roaring. + * Add patch based on upstream commit to deal with changed type of + slice entries in fixedbitset. + + -- Peter Michael Green <[email protected]> Wed, 17 Dec 2025 00:59:31 +0000 + thin-provisioning-tools (1.1.0-5) unstable; urgency=medium * Update rust dependencies, again. (closes: #1117378) diff -Nru thin-provisioning-tools-1.1.0/debian/.gitignore thin-provisioning-tools-1.1.0/debian/.gitignore --- thin-provisioning-tools-1.1.0/debian/.gitignore 2025-10-19 12:15:27.000000000 +0000 +++ thin-provisioning-tools-1.1.0/debian/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -/debhelper* -/*.debhelper* -/*.substvars -/cargo_home/ -/cargo_registry/ -/files -/thin-provisioning-tools/ diff -Nru thin-provisioning-tools-1.1.0/debian/patches/debian-changes thin-provisioning-tools-1.1.0/debian/patches/debian-changes --- thin-provisioning-tools-1.1.0/debian/patches/debian-changes 2025-10-19 12:15:27.000000000 +0000 +++ thin-provisioning-tools-1.1.0/debian/patches/debian-changes 2025-12-17 00:59:31.000000000 +0000 @@ -1,11 +1,7 @@ -diff --git a/.cargo-checksum.json b/.cargo-checksum.json -new file mode 100644 -index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 -diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml -new file mode 100644 -index 0000000000000000000000000000000000000000..a3240a084f5f4374c38470467d51462e4d6bf905 +Index: thin-provisioning-tools-1.1.0/.gitlab-ci.yml +=================================================================== --- /dev/null -+++ b/.gitlab-ci.yml ++++ thin-provisioning-tools-1.1.0/.gitlab-ci.yml @@ -0,0 +1,6 @@ +include: +- local: debian/pipeline/workflow.yml @@ -13,10 +9,9 @@ +- local: debian/pipeline/source.yml +- local: debian/pipeline/build.yml +- local: debian/pipeline/test.yml -diff --git a/Cargo.lock b/Cargo.lock -deleted file mode 100644 -index a21223c91a816a1c90ea05632f6c1357213c86ba..0000000000000000000000000000000000000000 ---- a/Cargo.lock +Index: thin-provisioning-tools-1.1.0/Cargo.lock +=================================================================== +--- thin-provisioning-tools-1.1.0.orig/Cargo.lock +++ /dev/null @@ -1,1226 +0,0 @@ -# This file is automatically @generated by Cargo. @@ -1245,10 +1240,10 @@ - "quote", - "syn 2.0.72", -] -diff --git a/Cargo.toml b/Cargo.toml -index 47703bfc3d68581367458a98eee7e8cd18d016fd..3e1e74e476590413ea097d5643a35a2e8e0f310f 100644 ---- a/Cargo.toml -+++ b/Cargo.toml +Index: thin-provisioning-tools-1.1.0/Cargo.toml +=================================================================== +--- thin-provisioning-tools-1.1.0.orig/Cargo.toml ++++ thin-provisioning-tools-1.1.0/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-only" [dependencies] atty = "0.2" @@ -1258,7 +1253,7 @@ byteorder = "1.4" clap = { version = "4.5", default-features = false, features = [ "std", -@@ -19,7 +19,7 @@ clap = { version = "4.5", default-features = false, features = [ +@@ -19,7 +19,7 @@ clap = { version = "4.5", default-featur ] } crc32c = "0.6" data-encoding = "2.5" @@ -1278,9 +1273,10 @@ +quick-xml = ">= 0.36" rand = "0.8" -rangemap = "1.5" -+rangemap = "1" - roaring = "0.10" +-roaring = "0.10" -rio = { git = "https://github.com/jthornber/rio", branch = "master", optional = true } ++rangemap = "1" ++roaring = ">= 0.10" safemem = "0.3" threadpool = "1.8" -thiserror = "1.0" @@ -1288,13 +1284,14 @@ tui = { version = "0.19", default-features = false, features = [ "termion", ], optional = true } - termion = { version = "1.5", optional = true } +-termion = { version = "1.5", optional = true } -udev = "0.7" ++termion = { version = ">= 1.5", optional = true } +udev = "0" [dev-dependencies] duct = "0.13" -@@ -55,7 +54,7 @@ thinp = { path = ".", features = ["devtools"] } +@@ -55,7 +54,7 @@ thinp = { path = ".", features = ["devto [features] devtools = ["tui", "termion"] diff -Nru thin-provisioning-tools-1.1.0/debian/patches/fixedbitset-0.5 thin-provisioning-tools-1.1.0/debian/patches/fixedbitset-0.5 --- thin-provisioning-tools-1.1.0/debian/patches/fixedbitset-0.5 1970-01-01 00:00:00.000000000 +0000 +++ thin-provisioning-tools-1.1.0/debian/patches/fixedbitset-0.5 2025-12-17 00:59:31.000000000 +0000 @@ -0,0 +1,309 @@ +This patch is based on the upstream commit described below, adapted +by Peter Michael Green to support both the old and new versions of +fixedbitset. + +commit af7fdbf6f2d5b1db3ba6d20abf8f6eb5a1dc21a9 +Author: Ming-Hung Tsai <[email protected]> +Date: Tue Jun 17 21:18:57 2025 +0800 + + [build] Update fixedbitset to v0.5.7 + + Since v0.5, FixedBitSet has used 64-bit blocks where possible, + improving performance on set operations. + +Index: thin-provisioning-tools-1.1.0/src/era/dump.rs +=================================================================== +--- thin-provisioning-tools-1.1.0.orig/src/era/dump.rs ++++ thin-provisioning-tools-1.1.0/src/era/dump.rs +@@ -242,9 +242,11 @@ fn dump_writeset( + let mut end: u32 = 0; + for (index, entry) in bits.as_slice().iter().enumerate() { + let mut n = *entry; ++ let bits_per_block = (std::mem::size_of_val(&n) * 8) as u32; ++ let bits_shift = bits_per_block.trailing_zeros(); + +- if n == u32::MAX { +- end = std::cmp::min(end + 32, ws.nr_bits); ++ if n == !0 { ++ end = std::cmp::min(end + bits_per_block, ws.nr_bits); + continue; + } + +@@ -269,7 +271,7 @@ fn dump_writeset( + } + + // emit the range if it ends before the entry boundary +- let endpos = ((index as u32) << 5) + 32; ++ let endpos = (index as u32 + 1) << bits_shift; + if end < endpos { + if end > begin { + let m = ir::MarkedBlocks { +Index: thin-provisioning-tools-1.1.0/src/pdata/bitset.rs +=================================================================== +--- thin-provisioning-tools-1.1.0.orig/src/pdata/bitset.rs ++++ thin-provisioning-tools-1.1.0/src/pdata/bitset.rs +@@ -7,6 +7,9 @@ use crate::pdata::array::{self, ArrayBlo + use crate::pdata::array_walker::{ArrayVisitor, ArrayWalker}; + use crate::pdata::space_map::*; + ++#[cfg(test)] ++mod tests; ++ + //------------------------------------------ + + pub struct CheckedBitSet { +@@ -89,13 +92,21 @@ impl ArrayVisitor<u64> for BitsetVisitor + struct BitsetCollector { + bits: Mutex<FixedBitSet>, + nr_bits: usize, ++ nr_entries: usize, ++} ++ ++fn elementsize<T>(_v : &[T]) -> usize { ++ std::mem::size_of::<T>() + } + + impl BitsetCollector { + fn new(nr_bits: usize) -> BitsetCollector { ++ let bits = FixedBitSet::with_capacity(nr_bits); ++ let bitsperelement = elementsize(bits.as_slice()) * 8; + BitsetCollector { +- bits: Mutex::new(FixedBitSet::with_capacity(nr_bits)), ++ bits: Mutex::new(bits), + nr_bits, ++ nr_entries: div_up(nr_bits, bitsperelement as usize), + } + } + +@@ -104,30 +115,77 @@ impl BitsetCollector { + } + } + ++//#[cfg(target_pointer_width = "32")] ++fn copy_to_32_bit_slice_le<T: std::convert::TryFrom<u64>>(dest: &mut [T], src: &[u64]) where <T as TryFrom<u64>>::Error: std::fmt::Debug { ++ assert!((std::mem::size_of::<T>() * 8) == 32); ++ ++ let mut pos = 0; ++ for &val in src { ++ if pos == dest.len() { ++ break; ++ } ++ ++ dest[pos] = (val & u32::MAX as u64).try_into().unwrap(); ++ pos += 1; ++ ++ if pos < dest.len() { ++ dest[pos] = (val >> 32 as u64).try_into().unwrap(); ++ pos += 1; ++ } ++ } ++} ++ + impl ArrayVisitor<u64> for BitsetCollector { + fn visit(&self, index: u64, b: ArrayBlock<u64>) -> array::Result<()> { +- let mut bitset = self.bits.lock().unwrap(); +- let mut idx = (index as usize * b.header.max_entries as usize) << 1; // index of u32 in bitset array +- let idx_end = div_up(self.nr_bits, 32); +- let mut dest = bitset.as_mut_slice().iter_mut().skip(idx); +- for entry in b.values.iter() { +- let lower = (*entry & (u32::MAX as u64)) as u32; +- *(dest.next().ok_or_else(|| { +- array::value_err(format!("bitset size exceeds limit: {} bits", self.nr_bits)) +- })?) = lower; +- idx += 1; ++ let mut bitset = self.bits.lock().unwrap(); ++ let bitsperentry = elementsize(bitset.as_slice()) * 8; ++ if bitsperentry == 64 { ++ let begin = index as usize * b.header.max_entries as usize; ++ let end = begin + b.values.len(); + +- if idx == idx_end { +- break; +- } ++ if begin >= self.nr_entries || end > self.nr_entries { ++ return Err(array::value_err(format!( ++ "bitset size exceeds limit: {} bits", ++ self.nr_bits ++ ))); ++ } ++ ++ let src: &[_] = unsafe { ++ std::slice::from_raw_parts(b.values.as_ptr() as *const _, b.values.len()) ++ }; ++ let dest: &mut [_] = &mut bitset.as_mut_slice()[begin..end]; ++ dest.copy_from_slice(src); + +- let upper = (*entry >> 32) as u32; +- *(dest.next().ok_or_else(|| { +- array::value_err(format!("bitset size exceeds limit: {} bits", self.nr_bits)) +- })?) = upper; +- idx += 1; ++ Ok(()) ++ } else { ++ let begin = (index as usize * b.header.max_entries as usize) * 2; ++ let end = begin + b.values.len() * 2; ++ ++ /* ++ * For 32-bit targets, FixedBitSet stores its bits as an array of 32-bit ++ * usize entries, while the source ArrayBlock uses u64. When the number of ++ * 32-bit usize entries required to represent the bitset is odd, the upper ++ * half of the last u64 in the source is unused during conversion. ++ * The check below ensures the source ArrayBlock fits the allocated ++ * FixedBitSet, allowing at most one unused usize entry from the source. ++ * ++ * The check below is safe and correct when `self.nr_entries` is even, ++ * since the estimated size `end` is even as well, making ++ * `end == self.nr_entries + 1` impossible in this case. ++ */ ++ if begin >= self.nr_entries || end > self.nr_entries + 1 { ++ return Err(array::value_err(format!( ++ "bitset size exceeds limit: {} bits", ++ self.nr_bits ++ ))); + } ++ ++ let end = std::cmp::min(end, self.nr_entries); ++ let dest = &mut bitset.as_mut_slice()[begin..end]; ++ copy_to_32_bit_slice_le(dest, &b.values); ++ + Ok(()) ++ } + } + } + +Index: thin-provisioning-tools-1.1.0/src/pdata/bitset/tests.rs +=================================================================== +--- /dev/null ++++ thin-provisioning-tools-1.1.0/src/pdata/bitset/tests.rs +@@ -0,0 +1,118 @@ ++use super::*; ++ ++use anyhow::Result; ++ ++use crate::io_engine::core::CoreIoEngine; ++use crate::pdata::array::{calc_max_entries, unpack_array_block, ArrayBlock}; ++use crate::pdata::array_builder::ArrayBlockBuilder; ++use crate::write_batcher::WriteBatcher; ++ ++struct BitsetBuilder { ++ w: WriteBatcher, ++} ++ ++impl BitsetBuilder { ++ fn new(engine: Arc<dyn IoEngine + Send + Sync>) -> Self { ++ let sm = Arc::new(Mutex::new(CoreSpaceMap::<u8>::new(engine.get_nr_blocks()))); ++ Self { ++ w: WriteBatcher::new(engine, sm, 16), ++ } ++ } ++ ++ fn build_bitset_blocks(&mut self, bits: &FixedBitSet) -> Result<Vec<u64>> { ++ let nr_entries = div_up(bits.len(), 64); ++ let mut builder = ArrayBlockBuilder::<u64>::new(nr_entries as u64); ++ let mut cur_pos = 0; ++ let mut entry = 0; ++ ++ for bit in bits.ones() { ++ let pos = (bit >> 6) as u64; ++ let mask = 1 << (bit & 63); ++ if pos == cur_pos { ++ entry |= mask; ++ } else { ++ builder.push_value(&mut self.w, cur_pos, entry)?; ++ cur_pos = pos; ++ entry = mask; ++ } ++ } ++ builder.push_value(&mut self.w, cur_pos, entry)?; ++ ++ let ablocks = builder.complete(&mut self.w)?; ++ self.w.flush()?; ++ ++ Ok(ablocks) ++ } ++ ++ fn read_bitset_blocks(&mut self, blocks: &[u64]) -> Result<Vec<ArrayBlock<u64>>> { ++ let mut ablocks = Vec::with_capacity(blocks.len()); ++ ++ for &bn in blocks { ++ let b = self.w.engine.read(bn)?; ++ let ablock = unpack_array_block::<u64>(&[bn], b.get_data())?; ++ ablocks.push(ablock); ++ } ++ ++ Ok(ablocks) ++ } ++} ++ ++fn build_bitset_blocks(expected: &FixedBitSet) -> Result<Vec<ArrayBlock<u64>>> { ++ let engine = Arc::new(CoreIoEngine::new(64)); ++ let mut t = BitsetBuilder::new(engine); ++ let blocks = t.build_bitset_blocks(expected)?; ++ t.read_bitset_blocks(&blocks) ++} ++ ++fn test_bitset_conversion(expected: &FixedBitSet) -> Result<()> { ++ let blocks = build_bitset_blocks(expected)?; ++ ++ let collector = BitsetCollector::new(expected.len()); ++ for (i, b) in blocks.into_iter().enumerate() { ++ collector.visit(i as u64, b)?; ++ } ++ let actual = collector.get_bitset(); ++ assert_eq!(expected.as_slice(), actual.as_slice()); // compare slices to facilitate debugging ++ ++ Ok(()) ++} ++ ++#[test] ++fn convert_to_single_entry() { ++ let usize_bits = usize::BITS as usize; ++ let bitset_len = usize_bits; ++ let mut expected = FixedBitSet::with_capacity(bitset_len); ++ expected.insert_range(0..2); ++ expected.insert_range(bitset_len - 2..bitset_len); ++ assert!(test_bitset_conversion(&expected).is_ok()); ++} ++ ++#[test] ++fn convert_to_multiple_entries() { ++ let usize_bits = usize::BITS as usize; ++ let bitset_len = usize_bits * 2; ++ let mut expected = FixedBitSet::with_capacity(bitset_len); ++ expected.insert_range(0..2); ++ expected.insert_range(usize_bits - 1..usize_bits + 1); ++ assert!(test_bitset_conversion(&expected).is_ok()); ++} ++ ++#[test] ++fn convert_from_multiple_blocks() { ++ let bits_per_block = calc_max_entries::<u64>() * 64; ++ let bitset_len = bits_per_block * 2 + 1; ++ let mut expected = FixedBitSet::with_capacity(bitset_len); ++ expected.insert_range(0..2); ++ expected.insert_range(bits_per_block - 2..bits_per_block + 1); ++ assert!(test_bitset_conversion(&expected).is_ok()); ++} ++ ++#[test] ++fn insufficient_collector_size_should_fail() { ++ let expected = FixedBitSet::with_capacity(128); ++ let mut blocks = build_bitset_blocks(&expected).unwrap(); ++ ++ let collector = BitsetCollector::new(64); ++ let ret = collector.visit(0, blocks.remove(0)); ++ assert!(ret.is_err()); ++} +Index: thin-provisioning-tools-1.1.0/Cargo.toml +=================================================================== +--- thin-provisioning-tools-1.1.0.orig/Cargo.toml ++++ thin-provisioning-tools-1.1.0/Cargo.toml +@@ -21,7 +21,7 @@ crc32c = "0.6" + data-encoding = "2.5" + devicemapper = "0.34" + exitcode = "1.1.2" +-fixedbitset = "0.4" ++fixedbitset = ">= 0.4" + flate2 = "1.0" + iovec = "0.1" + indicatif = "0.17" diff -Nru thin-provisioning-tools-1.1.0/debian/patches/series thin-provisioning-tools-1.1.0/debian/patches/series --- thin-provisioning-tools-1.1.0/debian/patches/series 2025-10-19 12:15:27.000000000 +0000 +++ thin-provisioning-tools-1.1.0/debian/patches/series 2025-12-17 00:59:31.000000000 +0000 @@ -1 +1,2 @@ debian-changes +fixedbitset-0.5

