prune: fix repo corruption with compressed blobs

Only happens when compressed blobs are repacked and if --repack-fast is
not given
This commit is contained in:
Alexander Weiss 2022-07-28 22:47:06 +02:00
parent 56d2a7f35d
commit 62a63251da
5 changed files with 26 additions and 17 deletions

View File

@ -1,4 +1,5 @@
use std::fs::File;
use std::num::NonZeroU32;
use anyhow::{bail, Result};
use async_trait::async_trait;
@ -23,6 +24,7 @@ pub trait DecryptReadBackend: ReadBackend {
cacheable: bool,
offset: u32,
length: u32,
uncompressed_length: Option<NonZeroU32>,
) -> Result<Vec<u8>>;
async fn get_file<F: RepoFile>(&self, id: &Id) -> Result<F> {
@ -176,13 +178,21 @@ impl<R: ReadBackend, C: CryptoKey> DecryptReadBackend for DecryptBackend<R, C> {
cacheable: bool,
offset: u32,
length: u32,
uncompressed_length: Option<NonZeroU32>,
) -> Result<Vec<u8>> {
Ok(self.key.decrypt_data(
let mut data = self.key.decrypt_data(
&self
.backend
.read_partial(tpe, id, cacheable, offset, length)
.await?,
)?)
)?;
if let Some(length) = uncompressed_length {
data = decode_all(&*data).unwrap();
if data.len() != length.get() as usize {
bail!("length of uncompressed data does not match!");
}
}
Ok(data)
}
}

View File

@ -1,4 +1,5 @@
use std::fs::File;
use std::num::NonZeroU32;
use anyhow::Result;
use async_trait::async_trait;
@ -32,9 +33,10 @@ impl<BE: DecryptFullBackend> DecryptReadBackend for DryRunBackend<BE> {
cacheable: bool,
offset: u32,
length: u32,
uncompressed_length: Option<NonZeroU32>,
) -> Result<Vec<u8>> {
self.be
.read_encrypted_partial(tpe, id, cacheable, offset, length)
.read_encrypted_partial(tpe, id, cacheable, offset, length, uncompressed_length)
.await
}
}

View File

@ -359,6 +359,7 @@ impl<BE: DecryptFullBackend> Repacker<BE> {
blob.tpe.is_cacheable(),
blob.offset,
blob.length,
blob.uncompressed_length,
)
.await?;
self.packer

View File

@ -8,7 +8,6 @@ use derive_getters::Dissolve;
use futures::{stream::FuturesUnordered, TryStreamExt};
use tokio::spawn;
use vlog::*;
use zstd::decode_all;
use super::{progress_bytes, progress_counter};
use crate::backend::{DecryptReadBackend, FileType, LocalBackend};
@ -131,17 +130,17 @@ async fn restore_contents(
stream.push(spawn(async move {
// read pack at blob_offset with length blob_length
let data = be
.read_encrypted_partial(FileType::Pack, &pack, false, bl.offset, bl.length)
.read_encrypted_partial(
FileType::Pack,
&pack,
false,
bl.offset,
bl.length,
bl.uncompressed_length,
)
.await
.unwrap();
let data = match bl.uncompressed_length.is_some() {
false => data,
true => decode_all(&*data).unwrap(),
};
// TODO: check length of uncomressed data
if !dry_run {
// save into needed files in parallel
for (name, start) in name_dests {

View File

@ -9,7 +9,6 @@ use derive_more::Constructor;
use futures::StreamExt;
use indicatif::ProgressBar;
use vlog::*;
use zstd::decode_all;
use crate::backend::{DecryptReadBackend, FileType};
use crate::blob::BlobType;
@ -51,12 +50,10 @@ impl IndexEntry {
self.blob_type.is_cacheable(),
self.offset,
self.length,
self.uncompressed_length,
)
.await?;
Ok(match self.uncompressed_length {
None => data,
Some(_) => decode_all(&*data)?,
})
Ok(data)
}
pub fn data_length(&self) -> u32 {