block: qcow: Read refcount rebuild markers positionally

The refcount rebuild check issued a seek to the refcount table and to
the first refblock before each cursor read. Read the fixed size fields
with read_exact_at at their offsets and decode with from_be_bytes. The
seeks and the matching error paths go away.

The result is unchanged.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-06-30 17:33:19 +02:00
committed by Rob Bradford
parent f893a13af0
commit abc03f998a

View File

@@ -18,6 +18,7 @@ use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::fs::{OpenOptions, read_link};
use std::io::{self, Seek, SeekFrom};
use std::os::fd::AsRawFd;
use std::os::unix::fs::FileExt;
use std::path::Path;
use std::{result, str};
@@ -387,15 +388,15 @@ pub(crate) fn parse_qcow(
// The first cluster should always have a non-zero refcount, so if it is 0,
// this is an old file with broken refcounts, which requires a rebuild.
let mut refcount_rebuild_required = true;
file.seek(SeekFrom::Start(header.refcount_table_offset))
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::SeekingFile(e)))?;
let first_refblock_addr = u64::read_be(&mut file)
let mut first_refblock_bytes = [0u8; 8];
file.read_exact_at(&mut first_refblock_bytes, header.refcount_table_offset)
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ReadingHeader(e)))?;
let first_refblock_addr = u64::from_be_bytes(first_refblock_bytes);
if first_refblock_addr != 0 {
file.seek(SeekFrom::Start(first_refblock_addr))
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::SeekingFile(e)))?;
let first_cluster_refcount = u16::read_be(&mut file)
let mut refcount_bytes = [0u8; 2];
file.read_exact_at(&mut refcount_bytes, first_refblock_addr)
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ReadingHeader(e)))?;
let first_cluster_refcount = u16::from_be_bytes(refcount_bytes);
if first_cluster_refcount != 0 {
refcount_rebuild_required = false;
}