|
|
|
@ -180,6 +180,14 @@ impl DupeMap
|
|
|
|
|
/// Save this list to a file
|
|
|
|
|
pub fn save<W: Write>(&self, to: &mut W) -> io::Result<usize>
|
|
|
|
|
{
|
|
|
|
|
use lzzzz::{
|
|
|
|
|
lz4f::{
|
|
|
|
|
PreferencesBuilder,
|
|
|
|
|
WriteCompressor,
|
|
|
|
|
CLEVEL_MAX,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
let mut to = WriteCompressor::new(to, PreferencesBuilder::new().compression_level(CLEVEL_MAX).build())?;
|
|
|
|
|
let mut done=0;
|
|
|
|
|
for (path, (hash, _)) in self.table.iter()
|
|
|
|
|
{
|
|
|
|
@ -201,18 +209,29 @@ impl DupeMap
|
|
|
|
|
{
|
|
|
|
|
use tokio::prelude::*;
|
|
|
|
|
|
|
|
|
|
let mut done=0;
|
|
|
|
|
let mut done=0usize;
|
|
|
|
|
|
|
|
|
|
use lzzzz::{
|
|
|
|
|
lz4f::{
|
|
|
|
|
PreferencesBuilder,
|
|
|
|
|
AsyncWriteCompressor,
|
|
|
|
|
CLEVEL_MAX,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
let mut to = AsyncWriteCompressor::new(to, PreferencesBuilder::new().compression_level(CLEVEL_MAX).build())?;
|
|
|
|
|
for (path, (hash, _)) in self.table.iter()
|
|
|
|
|
{
|
|
|
|
|
let path = path_bytes(path.as_ref());
|
|
|
|
|
let hash: &[u8] = hash.as_ref();
|
|
|
|
|
|
|
|
|
|
to.write(ENTRY_HEADER).await?;
|
|
|
|
|
to.write(bytes::reinterpret(&path.len())).await?;
|
|
|
|
|
to.write(path).await?;
|
|
|
|
|
to.write(hash).await?;
|
|
|
|
|
to.write_all(ENTRY_HEADER).await?;
|
|
|
|
|
to.write_all(bytes::reinterpret(&path.len())).await?; ////ASD OASDI AJOSID OAISNDO I
|
|
|
|
|
to.write_all(path).await?;
|
|
|
|
|
to.write_all(hash).await?;
|
|
|
|
|
done+=1;
|
|
|
|
|
}
|
|
|
|
|
to.flush().await?;
|
|
|
|
|
to.shutdown().await?;
|
|
|
|
|
Ok(done)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -223,7 +242,9 @@ impl DupeMap
|
|
|
|
|
let mut read;
|
|
|
|
|
let mut header_buffer = [0u8; ENTRY_HEADER.len() + std::mem::size_of::<usize>()];
|
|
|
|
|
let mut hash_buffer = [0u8; hash::SHA256_SIZE];
|
|
|
|
|
let mut from = lzzzz::lz4f::ReadDecompressor::new(from)?;
|
|
|
|
|
|
|
|
|
|
//XXX: Change to read_exact
|
|
|
|
|
while {read = from.read(&mut header_buffer[..])?; read == header_buffer.len() && &header_buffer[..ENTRY_HEADER.len()] == ENTRY_HEADER}
|
|
|
|
|
{
|
|
|
|
|
let sz = *bytes::reinterpret_back(&header_buffer[ENTRY_HEADER.len()..]);
|
|
|
|
@ -258,14 +279,26 @@ impl DupeMap
|
|
|
|
|
let mut header_buffer = [0u8; ENTRY_HEADER.len() + std::mem::size_of::<usize>()];
|
|
|
|
|
let mut hash_buffer = [0u8; hash::SHA256_SIZE];
|
|
|
|
|
|
|
|
|
|
while {read = from.read(&mut header_buffer[..]).await?; read == header_buffer.len() && &header_buffer[..ENTRY_HEADER.len()] == ENTRY_HEADER}
|
|
|
|
|
let mut from = lzzzz::lz4f::AsyncReadDecompressor::new(from)?;
|
|
|
|
|
while {read = match from.read_exact(&mut header_buffer[..]).await {
|
|
|
|
|
Ok(v) => Ok(v),
|
|
|
|
|
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
|
|
|
|
|
if let Some(re) = e.get_ref() {
|
|
|
|
|
if format!("{}", re) == "early eof" { // Is there a better way to compare these? `Any` trait? Is it worth it? Don't care, it's an error anyway.
|
|
|
|
|
return Ok(done); // This is fine
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(e)
|
|
|
|
|
},
|
|
|
|
|
v => v,
|
|
|
|
|
}?; read == header_buffer.len() && &header_buffer[..ENTRY_HEADER.len()] == ENTRY_HEADER}
|
|
|
|
|
{
|
|
|
|
|
let sz = *bytes::reinterpret_back(&header_buffer[ENTRY_HEADER.len()..]);
|
|
|
|
|
if sz > 0 {
|
|
|
|
|
let mut path = vec![0u8; sz];
|
|
|
|
|
if from.read(&mut path[..]).await? == sz {
|
|
|
|
|
if from.read_exact(&mut path[..]).await? == sz {
|
|
|
|
|
let path = bytes_path(&path[..]);
|
|
|
|
|
if from.read(&mut hash_buffer[..]).await? == hash::SHA256_SIZE
|
|
|
|
|
if from.read_exact(&mut hash_buffer[..]).await? == hash::SHA256_SIZE
|
|
|
|
|
{
|
|
|
|
|
if !trans && self.cache(path, hash::Sha256Hash::new(hash_buffer)) {
|
|
|
|
|
done +=1;
|
|
|
|
|