use std::{
fs::File,
io::{self, Seek, Write},
path::Path,
};
use byteorder::{BigEndian, ByteOrder};
use crate::{BlockWriteError, EncryptionMethod, encrypt};
pub struct FileBlockEncryptWriteStream {
file: File,
file_size: u64,
written_size: u64,
block_size: u64,
block_count: u64,
key: Vec<u8>,
current_write_index: u64,
current_write_pt: u64,
write_buf: Vec<u8>,
}
impl FileBlockEncryptWriteStream {
pub fn new<P>(
file_path: P,
key: Vec<u8>,
file_size: u64,
block_size: u64,
) -> Result<FileBlockEncryptWriteStream, io::Error>
where
P: AsRef<Path>,
{
let mut block_count = file_size / block_size;
if file_size % block_size != 0 {
block_count += 1;
}
let mut file = File::create(file_path)?;
let mut buf: [u8; 8] = [0; 8];
BigEndian::write_u64(&mut buf, file_size);
file.write_all(&buf)?;
BigEndian::write_u64(&mut buf, block_size);
file.write_all(&buf)?;
let buf_block_index: [u8; 16] = [0; 16];
for _i in 0..block_count {
file.write_all(&buf_block_index)?;
}
Ok(FileBlockEncryptWriteStream {
file,
key,
file_size,
written_size: 0,
block_size,
block_count,
current_write_index: 0,
current_write_pt: 16 + (16 * block_count),
write_buf: Vec::new(),
})
}
pub fn get_block_count(&self) -> u64 {
self.block_count
}
fn write_current_block(&mut self, encrypted_block: &[u8]) -> Result<(), BlockWriteError> {
self.file
.seek(io::SeekFrom::Start(16 + self.current_write_index * 16))?;
let mut buf_block_index: [u8; 16] = [0; 16];
BigEndian::write_u64(&mut buf_block_index[0..8], self.current_write_pt); BigEndian::write_u64(&mut buf_block_index[8..16], encrypted_block.len() as u64);
self.file.write_all(&buf_block_index)?;
self.file.seek(io::SeekFrom::Start(self.current_write_pt))?;
self.file.write_all(encrypted_block)?;
self.current_write_index += 1;
self.current_write_pt += encrypted_block.len() as u64;
Ok(())
}
pub fn write(&mut self, data: &[u8]) -> Result<(), BlockWriteError> {
if self.current_write_index >= self.block_count {
return Err(BlockWriteError::ExceededFileSize);
}
self.written_size += data.len() as u64;
self.write_buf.append(&mut data.to_vec());
let block_size = self.block_size as usize;
while self.write_buf.len() >= block_size {
if self.current_write_index >= self.block_count {
return Err(BlockWriteError::ExceededFileSize);
}
let encrypted_block = encrypt(
&self.write_buf[0..block_size],
EncryptionMethod::Aes256Zip,
&self.key,
)?;
self.write_buf = self.write_buf[block_size..].to_vec();
self.write_current_block(&encrypted_block)?;
}
if self.written_size > self.file_size {
return Err(BlockWriteError::ExceededFileSize);
}
if !self.write_buf.is_empty() && self.written_size == self.file_size {
if self.current_write_index >= self.block_count {
return Err(BlockWriteError::ExceededFileSize);
}
let encrypted_block = encrypt(&self.write_buf, EncryptionMethod::Aes256Zip, &self.key)?;
self.write_buf.clear();
self.write_current_block(&encrypted_block)?;
}
Ok(())
}
pub fn close(self) {}
}