|
@@ -1,17 +1,16 @@
|
|
|
-pub use block_path::{BlockPath, BlockPathError};
|
|
|
pub mod blocktree;
|
|
|
/// Code which enables cryptographic operations.
|
|
|
pub mod crypto;
|
|
|
pub mod error;
|
|
|
pub mod log;
|
|
|
pub mod msg;
|
|
|
-pub use error::{Error, Result};
|
|
|
-
|
|
|
+pub mod accessor;
|
|
|
+pub mod buf_reader;
|
|
|
+pub mod sectored_buf;
|
|
|
mod block_path;
|
|
|
-mod sectored_buf;
|
|
|
+mod trailered;
|
|
|
#[cfg(test)]
|
|
|
mod test_helpers;
|
|
|
-mod trailered;
|
|
|
|
|
|
#[macro_use]
|
|
|
extern crate static_assertions;
|
|
@@ -21,17 +20,10 @@ extern crate static_assertions;
|
|
|
extern crate lazy_static;
|
|
|
|
|
|
use btserde::{read_from, write_to};
|
|
|
-use crypto::{
|
|
|
- AsymKeyPub, Ciphertext, Creds, Decrypter, DecrypterExt, Encrypter, EncrypterExt, HashKind,
|
|
|
- MerkleStream, PublicCreds, SecretStream, Sign, Signature, Signer, SymKey, SymKeyKind, VarHash,
|
|
|
-};
|
|
|
-use error::{BoxInIoErr, BtErr};
|
|
|
-use trailered::Trailered;
|
|
|
-
|
|
|
use ::log::error;
|
|
|
use brotli::{CompressorWriter, Decompressor};
|
|
|
use fuse_backend_rs::abi::fuse_abi::{stat64, Attr};
|
|
|
-use sectored_buf::SectoredBuf;
|
|
|
+use positioned_io::{ReadAt, Size, WriteAt};
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
use serde_big_array::BigArray;
|
|
|
use std::{
|
|
@@ -47,12 +39,23 @@ use std::{
|
|
|
};
|
|
|
use strum_macros::{Display, EnumDiscriminants, FromRepr};
|
|
|
|
|
|
+pub use error::{Error, Result};
|
|
|
+pub use block_path::{BlockPath, BlockPathError};
|
|
|
+use crypto::{
|
|
|
+ AsymKeyPub, Ciphertext, Creds, Decrypter, DecrypterExt, Encrypter, EncrypterExt, HashKind,
|
|
|
+ MerkleStream, PublicCreds, SecretStream, Sign, Signature, Signer, SymKey, SymKeyKind, VarHash,
|
|
|
+};
|
|
|
+use error::{BoxInIoErr, BtErr};
|
|
|
+use trailered::Trailered;
|
|
|
+use accessor::Accessor;
|
|
|
+
|
|
|
#[derive(Debug)]
|
|
|
pub enum BlockError {
|
|
|
MissingWritecap,
|
|
|
IncorrectSize { expected: usize, actual: usize },
|
|
|
NoBlockKey,
|
|
|
NoBlockPath,
|
|
|
+ UnknownSize,
|
|
|
}
|
|
|
|
|
|
impl Display for BlockError {
|
|
@@ -64,6 +67,7 @@ impl Display for BlockError {
|
|
|
}
|
|
|
BlockError::NoBlockKey => write!(f, "no block key is present"),
|
|
|
BlockError::NoBlockPath => write!(f, "no block path was specified"),
|
|
|
+ BlockError::UnknownSize => write!(f, "size could not be determined"),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -73,45 +77,78 @@ impl std::error::Error for BlockError {}
|
|
|
// This assertion ensures that conversions from `usize` to `u64` will not cause truncation. This
|
|
|
// prevents this code from compiling for 128 bit platforms, but that's not really a concern for the
|
|
|
// foreseeable future.
|
|
|
+// If this assumption is ever to be removed, you'll need to evaluate every occurrence of `as u64`.
|
|
|
const_assert!(::std::mem::size_of::<usize>() <= ::std::mem::size_of::<u64>());
|
|
|
/// The default sector size to use for new blocks.
|
|
|
pub const SECTOR_SZ_DEFAULT: usize = 4096;
|
|
|
/// `SECTOR_SZ_DEFAULT` converted to a `u64`.
|
|
|
pub const SECTOR_U64_DEFAULT: u64 = SECTOR_SZ_DEFAULT as u64;
|
|
|
|
|
|
+pub trait MetaReader: AsRef<BlockMeta> + Size {
|
|
|
+ fn meta(&self) -> &BlockMeta {
|
|
|
+ self.as_ref()
|
|
|
+ }
|
|
|
+
|
|
|
+ fn meta_body(&self) -> &BlockMetaBody {
|
|
|
+ self.meta().body()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: AsRef<BlockMeta> + Size + ?Sized> MetaReader for T {}
|
|
|
+
|
|
|
+/// Trait for accessing the metadata associated with a block.
|
|
|
+pub trait MetaAccess: AsMut<BlockMeta> + MetaReader {
|
|
|
+ fn mut_meta(&mut self) -> &mut BlockMeta {
|
|
|
+ self.as_mut()
|
|
|
+ }
|
|
|
+
|
|
|
+ fn mut_meta_body(&mut self) -> &mut BlockMetaBody {
|
|
|
+ self.mut_meta().mut_body()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: AsMut<BlockMeta> + MetaReader + ?Sized> MetaAccess for T {}
|
|
|
+
|
|
|
+pub trait FlushMeta {
|
|
|
+ /// Flushes metadata to persistent storage.
|
|
|
+ fn flush_meta(&mut self) -> Result<()>;
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: FlushMeta + ?Sized> FlushMeta for &mut T {
|
|
|
+ fn flush_meta(&mut self) -> Result<()> {
|
|
|
+ (*self).flush_meta()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// ### THE BLOCK TRAIT
|
|
|
///
|
|
|
/// Trait for types which provide read and write access to blocks.
|
|
|
-pub trait Block: Read + Write + Seek + MetaAccess {
|
|
|
- /// Flushes metadata to persistent storage.
|
|
|
- fn flush_meta(&mut self) -> Result<()>;
|
|
|
+pub trait Block: ReadAt + WriteAt + MetaAccess + Sectored + FlushMeta {}
|
|
|
+
|
|
|
+impl<T: ReadAt + WriteAt + MetaAccess + Sectored + FlushMeta + ?Sized> Block for T {}
|
|
|
|
|
|
+pub trait BlockReader: Read + Seek + AsRef<BlockMeta> + Size + Sectored {
|
|
|
fn read_dir(&mut self) -> Result<Directory> {
|
|
|
- self.seek(SeekFrom::Start(0))?;
|
|
|
- // &mut &mut Self has to be passed because rustc complains that &mut Self is not sized,
|
|
|
- // for some reason (implicit dereference?). You can't pass in `&mut self` because `self`
|
|
|
- // is not declared as mutable. Hence this hack.
|
|
|
- let mut selfie = self;
|
|
|
- let dir: Directory = read_from(&mut selfie)?;
|
|
|
+ self.rewind()?;
|
|
|
+ let mut selphie = self;
|
|
|
+ let dir: Directory = read_from(&mut selphie)?;
|
|
|
Ok(dir)
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Read + Seek + AsRef<BlockMeta> + Size + Sectored + ?Sized> BlockReader for T {}
|
|
|
|
|
|
+pub trait BlockAccessor: BlockReader + Write + MetaAccess {
|
|
|
fn write_dir(&mut self, dir: &Directory) -> Result<()> {
|
|
|
- self.seek(SeekFrom::Start(0))?;
|
|
|
- let mut selfie = self;
|
|
|
- write_to(dir, &mut selfie)?;
|
|
|
- selfie.flush()?;
|
|
|
+ self.rewind()?;
|
|
|
+ let mut selphie = self;
|
|
|
+ write_to(dir, &mut selphie)?;
|
|
|
+ selphie.flush()?;
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: MetaAccess> MetaAccess for &mut T {}
|
|
|
-
|
|
|
-impl<T: Block> Block for &mut T {
|
|
|
- fn flush_meta(&mut self) -> Result<()> {
|
|
|
- (*self).flush_meta()
|
|
|
- }
|
|
|
-}
|
|
|
+impl<T: Read + Write + Seek + MetaAccess + Sectored + ?Sized> BlockAccessor for T {}
|
|
|
|
|
|
// A trait for streams which only allow reads and writes in fixed sized units called sectors.
|
|
|
pub trait Sectored {
|
|
@@ -152,6 +189,18 @@ pub trait Sectored {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+impl<T: Sectored + ?Sized> Sectored for &T {
|
|
|
+ fn sector_sz(&self) -> usize {
|
|
|
+ (**self).sector_sz()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Sectored + ?Sized> Sectored for &mut T {
|
|
|
+ fn sector_sz(&self) -> usize {
|
|
|
+ (**self).sector_sz()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
impl Sectored for ::std::fs::File {
|
|
|
fn sector_sz(&self) -> usize {
|
|
|
self.metadata()
|
|
@@ -160,16 +209,36 @@ impl Sectored for ::std::fs::File {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// A version of the `Write` trait, which allows integrity information to be supplied when flushing.
|
|
|
-pub trait WriteInteg: Write {
|
|
|
+impl<T: Sectored + Size> Sectored for Cursor<T> {
|
|
|
+ fn sector_sz(&self) -> usize {
|
|
|
+ self.cursor.get_ref().sector_sz()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub trait SizeExt: Size {
|
|
|
+ fn size_or_err(&self) -> Result<u64> {
|
|
|
+ self.size()?.ok_or_else(|| bterr!(BlockError::UnknownSize))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Size> SizeExt for T {}
|
|
|
+
|
|
|
+/// A version of the `WriteAt` trait, which allows integrity information to be supplied when
|
|
|
+/// flushing.
|
|
|
+pub trait WriteInteg: WriteAt {
|
|
|
fn flush_integ(&mut self, integrity: &[u8]) -> io::Result<()>;
|
|
|
}
|
|
|
|
|
|
-trait Decompose<T> {
|
|
|
+pub trait Decompose<T> {
|
|
|
fn into_inner(self) -> T;
|
|
|
}
|
|
|
|
|
|
-trait TryCompose<T, U: Decompose<T>> {
|
|
|
+pub trait Split<L, R> {
|
|
|
+ fn split(self) -> (L, R);
|
|
|
+ fn combine(left: L, right: R) -> Self;
|
|
|
+}
|
|
|
+
|
|
|
+pub trait TryCompose<T, U: Decompose<T>> {
|
|
|
type Error;
|
|
|
fn try_compose(self, inner: T) -> std::result::Result<U, Self::Error>;
|
|
|
}
|
|
@@ -185,25 +254,6 @@ impl<T, U: Decompose<T>, S: TryCompose<T, U, Error = Infallible>> Compose<T, U>
|
|
|
unsafe { result.unwrap_unchecked() }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-/// Trait for accessing the metadata associated with a block.
|
|
|
-pub trait MetaAccess: AsRef<BlockMeta> + AsMut<BlockMeta> {
|
|
|
- fn meta(&self) -> &BlockMeta {
|
|
|
- self.as_ref()
|
|
|
- }
|
|
|
- fn mut_meta(&mut self) -> &mut BlockMeta {
|
|
|
- self.as_mut()
|
|
|
- }
|
|
|
-
|
|
|
- fn meta_body(&self) -> &BlockMetaBody {
|
|
|
- self.meta().body()
|
|
|
- }
|
|
|
-
|
|
|
- fn mut_meta_body(&mut self) -> &mut BlockMetaBody {
|
|
|
- self.mut_meta().mut_body()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
impl AsRef<BlockMeta> for &BlockMeta {
|
|
|
fn as_ref(&self) -> &BlockMeta {
|
|
|
self
|
|
@@ -222,7 +272,92 @@ impl AsMut<BlockMeta> for &mut BlockMeta {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl MetaAccess for &mut BlockMeta {}
|
|
|
+#[derive(Debug)]
|
|
|
+pub struct Cursor<T: Size> {
|
|
|
+ cursor: positioned_io::SizeCursor<T>,
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Size> Cursor<T> {
|
|
|
+ pub fn new(inner: T) -> Cursor<T> {
|
|
|
+ Self {
|
|
|
+ cursor: positioned_io::SizeCursor::new(inner),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn new_pos(inner: T, pos: u64) -> Cursor<T> {
|
|
|
+ Self {
|
|
|
+ cursor: positioned_io::SizeCursor::new_pos(inner, pos),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn get_ref(&self) -> &T {
|
|
|
+ self.cursor.get_ref()
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn get_mut(&mut self) -> &mut T {
|
|
|
+ self.cursor.get_mut()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: ReadAt + Size> Read for Cursor<T> {
|
|
|
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
+ self.cursor.read(buf)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: WriteAt + Size> Write for Cursor<T> {
|
|
|
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
|
+ self.cursor.write(buf)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn flush(&mut self) -> io::Result<()> {
|
|
|
+ self.cursor.flush()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Size> Seek for Cursor<T> {
|
|
|
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
|
|
+ self.cursor.seek(pos)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Size> Decompose<T> for Cursor<T> {
|
|
|
+ fn into_inner(self) -> T {
|
|
|
+ self.cursor.into_inner()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<U, T: AsRef<U> + Size> AsRef<U> for Cursor<T> {
|
|
|
+ fn as_ref(&self) -> &U {
|
|
|
+ self.cursor.get_ref().as_ref()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<U, T: AsMut<U> + Size> AsMut<U> for Cursor<T> {
|
|
|
+ fn as_mut(&mut self) -> &mut U {
|
|
|
+ self.cursor.get_mut().as_mut()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Size> Size for Cursor<T> {
|
|
|
+ fn size(&self) -> io::Result<Option<u64>> {
|
|
|
+ self.cursor.get_ref().size()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub const EMPTY_SLICE: &[u8] = &[0u8; 0];
|
|
|
+
|
|
|
+impl<T: Size> Split<Cursor<&'static [u8]>, T> for Cursor<T> {
|
|
|
+ fn split(self) -> (Cursor<&'static [u8]>, T) {
|
|
|
+ let pos = self.cursor.position();
|
|
|
+ (Cursor::new_pos(EMPTY_SLICE, pos), self.cursor.into_inner())
|
|
|
+ }
|
|
|
+
|
|
|
+ fn combine(left: Cursor<&'static [u8]>, right: T) -> Self {
|
|
|
+ let pos = left.cursor.position();
|
|
|
+ Self::new_pos(right, pos)
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
/// Extensions to the `Read` trait.
|
|
|
trait ReadExt: Read {
|
|
@@ -257,6 +392,62 @@ trait ReadExt: Read {
|
|
|
|
|
|
impl<T: Read> ReadExt for T {}
|
|
|
|
|
|
+trait SeekFromExt {
|
|
|
+ /// Returns the absolute position (offset from the start) this `SeekFrom` refers to.
|
|
|
+ /// `curr` is called in the case this `SeekFrom` is `Current`, and is expected to return the
|
|
|
+ /// current position.
|
|
|
+ /// `end` is called in the case this `SeekFrom` is `End`, and is expected to return the
|
|
|
+ /// the position of the end.
|
|
|
+ fn abs<F, G>(&self, curr: F, end: G) -> Result<u64>
|
|
|
+ where
|
|
|
+ F: FnOnce() -> Result<u64>,
|
|
|
+ G: FnOnce() -> Result<u64>;
|
|
|
+
|
|
|
+ /// Like [SeekFromExt::abs] except that an error is always returned when [SeekFrom::End] is
|
|
|
+ /// given.
|
|
|
+ fn abs_no_end<F>(&self, curr: F) -> Result<u64>
|
|
|
+ where
|
|
|
+ F: FnOnce() -> Result<u64>,
|
|
|
+ {
|
|
|
+ self.abs(curr, || Err(bterr!("SeekFrom::End is not supported")))
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Converts a C-style `(whence, offset)` pair into a [SeekFrom] enum value.
|
|
|
+ /// See the POSIX man page of `lseek` for more details.
|
|
|
+ fn whence_offset(whence: u32, offset: u64) -> io::Result<SeekFrom> {
|
|
|
+ let whence = whence as i32;
|
|
|
+ match whence {
|
|
|
+ libc::SEEK_SET => Ok(SeekFrom::Start(offset)),
|
|
|
+ libc::SEEK_CUR => Ok(SeekFrom::Current(offset as i64)),
|
|
|
+ libc::SEEK_END => Ok(SeekFrom::End(offset as i64)),
|
|
|
+ _ => Err(io::Error::new(
|
|
|
+ io::ErrorKind::InvalidInput,
|
|
|
+ "`whence` was not one of `libc::{SEEK_SET, SEEK_CUR, SEEK_END}`",
|
|
|
+ )),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl SeekFromExt for SeekFrom {
|
|
|
+ fn abs<F, G>(&self, curr: F, end: G) -> Result<u64>
|
|
|
+ where
|
|
|
+ F: FnOnce() -> Result<u64>,
|
|
|
+ G: FnOnce() -> Result<u64>,
|
|
|
+ {
|
|
|
+ match self {
|
|
|
+ SeekFrom::Start(start) => Ok(*start),
|
|
|
+ SeekFrom::Current(from_curr) => {
|
|
|
+ let curr = curr()?;
|
|
|
+ Ok(curr.wrapping_add_signed(*from_curr))
|
|
|
+ }
|
|
|
+ SeekFrom::End(from_end) => {
|
|
|
+ let end = end()?;
|
|
|
+ Ok(end.wrapping_add_signed(*from_end))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// A unique identifier for a block.
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Hash)]
|
|
|
pub struct BlockId {
|
|
@@ -550,7 +741,7 @@ impl AsMut<BlockMetaBody> for BlockMeta {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-struct BlockStream<T, C> {
|
|
|
+pub struct BlockStream<T, C> {
|
|
|
trailered: Trailered<T, BlockMeta>,
|
|
|
meta: BlockMeta,
|
|
|
meta_body_buf: Vec<u8>,
|
|
@@ -558,7 +749,7 @@ struct BlockStream<T, C> {
|
|
|
sect_sz: usize,
|
|
|
}
|
|
|
|
|
|
-impl<T: Read + Seek + Sectored, C: Creds> BlockStream<T, C> {
|
|
|
+impl<T: ReadAt + Sectored + Size, C: Creds> BlockStream<T, C> {
|
|
|
fn new(inner: T, creds: C, block_path: BlockPath) -> Result<BlockStream<T, C>> {
|
|
|
let (trailered, meta) = Trailered::<_, BlockMeta>::new(inner)?;
|
|
|
let meta = match meta {
|
|
@@ -605,7 +796,7 @@ impl<T: Read + Seek + Sectored, C: Creds> BlockStream<T, C> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Write + Seek, C: Signer> BlockStream<T, C> {
|
|
|
+impl<T: WriteAt + Size, C: Signer> BlockStream<T, C> {
|
|
|
fn sign_flush_meta(&mut self) -> io::Result<()> {
|
|
|
self.meta_body_buf.clear();
|
|
|
self.meta.sig = self
|
|
@@ -615,9 +806,9 @@ impl<T: Write + Seek, C: Signer> BlockStream<T, C> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Write + Seek, C: Signer + Principaled + Decrypter> Write for BlockStream<T, C> {
|
|
|
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
|
- self.trailered.write(buf)
|
|
|
+impl<T: WriteAt + Size, C: Signer + Principaled + Decrypter> WriteAt for BlockStream<T, C> {
|
|
|
+ fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
|
|
|
+ self.trailered.write_at(pos, buf)
|
|
|
}
|
|
|
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
@@ -625,7 +816,7 @@ impl<T: Write + Seek, C: Signer + Principaled + Decrypter> Write for BlockStream
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Write + Seek, C: Signer + Principaled + Decrypter> WriteInteg for BlockStream<T, C> {
|
|
|
+impl<T: WriteAt + Size, C: Signer + Principaled + Decrypter> WriteInteg for BlockStream<T, C> {
|
|
|
fn flush_integ(&mut self, integrity: &[u8]) -> io::Result<()> {
|
|
|
let meta_body = &mut self.meta.body;
|
|
|
let integ = meta_body.integrity.get_or_insert_with(VarHash::default);
|
|
@@ -634,17 +825,9 @@ impl<T: Write + Seek, C: Signer + Principaled + Decrypter> WriteInteg for BlockS
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Read + Seek, C> Read for BlockStream<T, C> {
|
|
|
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
- self.trailered.read(buf)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Seek, C> Seek for BlockStream<T, C> {
|
|
|
- /// Seeks to the given position in the stream. If a position beyond the end of the stream is
|
|
|
- /// specified, the the seek will be to the end of the stream.
|
|
|
- fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
|
|
- self.trailered.seek(pos)
|
|
|
+impl<T: ReadAt + Size, C> ReadAt for BlockStream<T, C> {
|
|
|
+ fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
+ self.trailered.read_at(pos, buf)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -660,15 +843,19 @@ impl<T, C> AsMut<BlockMeta> for BlockStream<T, C> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T, C> MetaAccess for BlockStream<T, C> {}
|
|
|
-
|
|
|
impl<T, C> Sectored for BlockStream<T, C> {
|
|
|
fn sector_sz(&self) -> usize {
|
|
|
self.sect_sz
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Read + Write + Seek, C: Creds> Block for BlockStream<T, C> {
|
|
|
+impl<T: Size, C> Size for BlockStream<T, C> {
|
|
|
+ fn size(&self) -> io::Result<Option<u64>> {
|
|
|
+ self.trailered.size()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: WriteAt + Size, C: Signer> FlushMeta for BlockStream<T, C> {
|
|
|
fn flush_meta(&mut self) -> Result<()> {
|
|
|
self.sign_flush_meta().map_err(|err| err.into())
|
|
|
}
|
|
@@ -737,21 +924,22 @@ impl<T, C> BlockOpenOptions<T, C> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Read + Write + Seek + Sectored + 'static, C: Creds + 'static> BlockOpenOptions<T, C> {
|
|
|
- pub fn open(self) -> Result<Box<dyn Block>> {
|
|
|
+pub type ConcreteBlock<T, C> = MerkleStream<BlockStream<T, C>>;
|
|
|
+pub type FileBlock<C> = ConcreteBlock<std::fs::File, C>;
|
|
|
+
|
|
|
+impl<T: ReadAt + WriteAt + Size + Sectored + 'static, C: Creds + 'static> BlockOpenOptions<T, C> {
|
|
|
+ pub fn open_bare(self) -> Result<ConcreteBlock<T, C>> {
|
|
|
let block_path = self.block_path.ok_or(BlockError::NoBlockPath)?;
|
|
|
let stream = BlockStream::new(self.inner, self.creds, block_path)?;
|
|
|
- let block_key = stream.meta_body().block_key().map(|e| e.to_owned())?;
|
|
|
let mut stream = MerkleStream::new(stream)?;
|
|
|
stream.assert_root_integrity()?;
|
|
|
- if self.encrypt {
|
|
|
- let stream = SecretStream::new(block_key).try_compose(stream)?;
|
|
|
- let stream = SectoredBuf::new().try_compose(stream)?;
|
|
|
- Ok(Box::new(stream))
|
|
|
- } else {
|
|
|
- let stream = SectoredBuf::new().try_compose(stream)?;
|
|
|
- Ok(Box::new(stream))
|
|
|
- }
|
|
|
+ Ok(stream)
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn open(self) -> Result<Accessor<ConcreteBlock<T, C>>> {
|
|
|
+ let stream = self.open_bare()?;
|
|
|
+ let stream = Accessor::new(stream)?;
|
|
|
+ Ok(stream)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1134,14 +1322,21 @@ impl<F: FnOnce()> Drop for DropTrigger<F> {
|
|
|
|
|
|
#[cfg(test)]
|
|
|
mod tests {
|
|
|
- use std::{fs::OpenOptions, io::Cursor, path::PathBuf};
|
|
|
-
|
|
|
- use crate::crypto::{ConcreteCreds, CredsPriv, SignStream};
|
|
|
-
|
|
|
- use super::*;
|
|
|
use btserde::{from_vec, to_vec};
|
|
|
+ use std::{
|
|
|
+ fs::OpenOptions,
|
|
|
+ io::{Cursor, Write},
|
|
|
+ path::PathBuf,
|
|
|
+ };
|
|
|
use tempdir::TempDir;
|
|
|
- use test_helpers::*;
|
|
|
+
|
|
|
+ use super::*;
|
|
|
+ use crate::{
|
|
|
+ crypto::{ConcreteCreds, CredsPriv},
|
|
|
+ sectored_buf::SectoredBuf,
|
|
|
+ test_helpers::*,
|
|
|
+ Cursor as PioCursor,
|
|
|
+ };
|
|
|
|
|
|
#[test]
|
|
|
fn brotli_compress_decompress() {
|
|
@@ -1198,9 +1393,7 @@ mod tests {
|
|
|
}
|
|
|
|
|
|
type EncBlock = SectoredBuf<
|
|
|
- SecretStream<
|
|
|
- SignStream<BlockStream<SectoredCursor<Vec<u8>>, ConcreteCreds>, ConcreteCreds>,
|
|
|
- >,
|
|
|
+ SecretStream<PioCursor<MerkleStream<BlockStream<SectoredCursor<Vec<u8>>, ConcreteCreds>>>>,
|
|
|
>;
|
|
|
|
|
|
impl InMemTestCase {
|
|
@@ -1239,7 +1432,9 @@ mod tests {
|
|
|
})
|
|
|
.unwrap();
|
|
|
let block_key = stream.meta_body().block_key().unwrap().to_owned();
|
|
|
- let stream = SignStream::new(stream, self.node_creds.clone()).unwrap();
|
|
|
+ let mut stream = MerkleStream::new(stream).unwrap();
|
|
|
+ stream.assert_root_integrity().unwrap();
|
|
|
+ let stream = PioCursor::new(stream);
|
|
|
let stream = SecretStream::new(block_key).try_compose(stream).unwrap();
|
|
|
SectoredBuf::new().try_compose(stream).unwrap()
|
|
|
}
|
|
@@ -1250,6 +1445,7 @@ mod tests {
|
|
|
.into_inner()
|
|
|
.into_inner()
|
|
|
.into_inner()
|
|
|
+ .into_inner()
|
|
|
.0
|
|
|
.into_inner()
|
|
|
}
|
|
@@ -1325,7 +1521,7 @@ mod tests {
|
|
|
fs_path
|
|
|
}
|
|
|
|
|
|
- fn open_new(&mut self, path: crate::BlockPath) -> Box<dyn Block> {
|
|
|
+ fn open_new(&mut self, path: crate::BlockPath) -> Accessor<impl Block + 'static> {
|
|
|
let file = OpenOptions::new()
|
|
|
.create_new(true)
|
|
|
.read(true)
|
|
@@ -1345,7 +1541,7 @@ mod tests {
|
|
|
block
|
|
|
}
|
|
|
|
|
|
- fn open_existing(&mut self, path: crate::BlockPath) -> Box<dyn Block> {
|
|
|
+ fn open_existing(&mut self, path: crate::BlockPath) -> Accessor<impl Block + 'static> {
|
|
|
let file = OpenOptions::new()
|
|
|
.read(true)
|
|
|
.write(true)
|