|
@@ -25,7 +25,7 @@ use crypto::{
|
|
|
AsymKeyPub, Ciphertext, Creds, Decrypter, DecrypterExt, Encrypter, EncrypterExt, HashKind,
|
|
|
MerkleStream, PublicCreds, SecretStream, Sign, Signature, Signer, SymKey, SymKeyKind, VarHash,
|
|
|
};
|
|
|
-use error::BoxInIoErr;
|
|
|
+use error::{BoxInIoErr, BtErr};
|
|
|
use trailered::Trailered;
|
|
|
|
|
|
use ::log::error;
|
|
@@ -35,13 +35,14 @@ use sectored_buf::SectoredBuf;
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
use serde_big_array::BigArray;
|
|
|
use std::{
|
|
|
- collections::{btree_map, hash_map::DefaultHasher, BTreeMap, HashMap},
|
|
|
+ collections::{btree_map, BTreeMap, HashMap},
|
|
|
convert::{Infallible, TryFrom},
|
|
|
fmt::{self, Display, Formatter},
|
|
|
- hash::{Hash as Hashable, Hasher},
|
|
|
+ hash::Hash as Hashable,
|
|
|
io::{self, Read, Seek, SeekFrom, Write},
|
|
|
net::SocketAddr,
|
|
|
ops::{Add, Sub},
|
|
|
+ os::unix::prelude::MetadataExt,
|
|
|
time::{Duration, SystemTime},
|
|
|
};
|
|
|
use strum_macros::{Display, EnumDiscriminants, FromRepr};
|
|
@@ -69,8 +70,14 @@ impl Display for BlockError {
|
|
|
|
|
|
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.
|
|
|
+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;
|
|
|
|
|
|
/// ### THE BLOCK TRAIT
|
|
|
///
|
|
@@ -108,9 +115,16 @@ impl<T: Block> Block for &mut T {
|
|
|
|
|
|
// A trait for streams which only allow reads and writes in fixed sized units called sectors.
|
|
|
pub trait Sectored {
|
|
|
- // Returns the size of the sector for this stream.
|
|
|
+ /// Returns the size of the sector for this stream.
|
|
|
fn sector_sz(&self) -> usize;
|
|
|
|
|
|
+ /// Returns the sector size as a `u64`.
|
|
|
+ fn sector_sz64(&self) -> u64 {
|
|
|
+ // This is guaranteed not to truncate thanks to the `const_assert!` above
|
|
|
+ // `SECTOR_SZ_DEFAULT`.
|
|
|
+ self.sector_sz() as u64
|
|
|
+ }
|
|
|
+
|
|
|
/// Returns `Err(Error::IncorrectSize)` if the given size is not equal to the sector size.
|
|
|
fn assert_sector_sz(&self, actual: usize) -> Result<()> {
|
|
|
let expected = self.sector_sz();
|
|
@@ -133,8 +147,16 @@ pub trait Sectored {
|
|
|
|
|
|
/// Returns the offset (in bytes) from the beginning of this stream that the given 0-based
|
|
|
/// sector index corresponds to.
|
|
|
- fn offset_at(&self, index: usize) -> usize {
|
|
|
- index * self.sector_sz()
|
|
|
+ fn offset_at(&self, index: u64) -> u64 {
|
|
|
+ index * self.sector_sz64()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Sectored for ::std::fs::File {
|
|
|
+ fn sector_sz(&self) -> usize {
|
|
|
+ self.metadata()
|
|
|
+ .map(|e| e.blksize().try_into().bterr().unwrap())
|
|
|
+ .unwrap_or(SECTOR_SZ_DEFAULT)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -235,17 +257,6 @@ trait ReadExt: Read {
|
|
|
|
|
|
impl<T: Read> ReadExt for T {}
|
|
|
|
|
|
-trait HashExt: Hashable {
|
|
|
- /// Returns the hash produced by [DefaultHasher].
|
|
|
- fn default_hash(&self) -> u64 {
|
|
|
- let mut hasher = DefaultHasher::new();
|
|
|
- self.hash(&mut hasher);
|
|
|
- hasher.finish()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Hashable> HashExt for T {}
|
|
|
-
|
|
|
/// A unique identifier for a block.
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Hash)]
|
|
|
pub struct BlockId {
|
|
@@ -287,7 +298,7 @@ pub struct BlockMetaSecrets {
|
|
|
/// Number of hard links to the file.
|
|
|
nlink: u32,
|
|
|
/// The sector size used by the block.
|
|
|
- sect_sz: u32,
|
|
|
+ sect_sz: u64,
|
|
|
/// User controlled metadata.
|
|
|
tags: BTreeMap<String, Vec<u8>>,
|
|
|
}
|
|
@@ -304,13 +315,13 @@ impl BlockMetaSecrets {
|
|
|
ctime: Epoch::default(),
|
|
|
size: 0,
|
|
|
nlink: 0,
|
|
|
- sect_sz: SECTOR_SZ_DEFAULT.try_into().unwrap(),
|
|
|
+ sect_sz: SECTOR_U64_DEFAULT,
|
|
|
tags: BTreeMap::new(),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pub fn attr(&self) -> Attr {
|
|
|
- Attr {
|
|
|
+ pub fn attr(&self) -> Result<Attr> {
|
|
|
+ Ok(Attr {
|
|
|
ino: self.block_id.inode,
|
|
|
size: self.size,
|
|
|
atime: self.atime.value(),
|
|
@@ -324,23 +335,25 @@ impl BlockMetaSecrets {
|
|
|
uid: self.uid,
|
|
|
gid: self.gid,
|
|
|
rdev: 0,
|
|
|
- blksize: self.sect_sz,
|
|
|
+ blksize: self
|
|
|
+ .sect_sz
|
|
|
+ .try_into()
|
|
|
+ .map_err(|_| bterr!("BlockMetaSecrets::sect_sz could not be converted to a u32"))?,
|
|
|
blocks: self.sectors(),
|
|
|
flags: 0,
|
|
|
- }
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
- pub fn stat(&self) -> stat64 {
|
|
|
- self.attr().into()
|
|
|
+ pub fn stat(&self) -> Result<stat64> {
|
|
|
+ self.attr().map(|e| e.into())
|
|
|
}
|
|
|
|
|
|
/// Returns the number of sectors occupied by the block's data.
|
|
|
pub fn sectors(&self) -> u64 {
|
|
|
- let sect_sz = self.sect_sz as u64;
|
|
|
- if self.size % sect_sz == 0 {
|
|
|
- self.size / sect_sz
|
|
|
+ if self.size % self.sect_sz == 0 {
|
|
|
+ self.size / self.sect_sz
|
|
|
} else {
|
|
|
- self.size / sect_sz + 1
|
|
|
+ self.size / self.sect_sz + 1
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -348,7 +361,7 @@ impl BlockMetaSecrets {
|
|
|
&self.block_id
|
|
|
}
|
|
|
|
|
|
- pub fn sector_sz(&self) -> u32 {
|
|
|
+ pub fn sector_sz(&self) -> u64 {
|
|
|
self.sect_sz
|
|
|
}
|
|
|
}
|
|
@@ -365,8 +378,10 @@ impl AsRef<BlockId> for BlockMetaSecrets {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl From<&BlockMetaSecrets> for Attr {
|
|
|
- fn from(value: &BlockMetaSecrets) -> Self {
|
|
|
+impl TryFrom<&BlockMetaSecrets> for Attr {
|
|
|
+ type Error = crate::Error;
|
|
|
+
|
|
|
+ fn try_from(value: &BlockMetaSecrets) -> Result<Self> {
|
|
|
value.attr()
|
|
|
}
|
|
|
}
|
|
@@ -543,7 +558,7 @@ struct BlockStream<T, C> {
|
|
|
sect_sz: usize,
|
|
|
}
|
|
|
|
|
|
-impl<T: Read + Seek, C: Creds> BlockStream<T, C> {
|
|
|
+impl<T: Read + Seek + Sectored, 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 {
|
|
@@ -572,10 +587,14 @@ impl<T: Read + Seek, C: Creds> BlockStream<T, C> {
|
|
|
.ok_or(BlockError::MissingWritecap)?
|
|
|
.to_owned(),
|
|
|
);
|
|
|
+ meta.body.access_secrets(|secrets| {
|
|
|
+ secrets.sect_sz = trailered.sector_sz64();
|
|
|
+ Ok(())
|
|
|
+ })?;
|
|
|
meta
|
|
|
}
|
|
|
};
|
|
|
- let sect_sz = meta.body.secrets()?.sector_sz().try_into().box_err()?;
|
|
|
+ let sect_sz = meta.body.secrets()?.sector_sz().try_into().bterr()?;
|
|
|
Ok(BlockStream {
|
|
|
trailered,
|
|
|
meta_body_buf: Vec::new(),
|
|
@@ -718,7 +737,7 @@ impl<T, C> BlockOpenOptions<T, C> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Read + Write + Seek + 'static, C: Creds + 'static> BlockOpenOptions<T, C> {
|
|
|
+impl<T: Read + Write + Seek + Sectored + 'static, C: Creds + 'static> BlockOpenOptions<T, C> {
|
|
|
pub fn open(self) -> Result<Box<dyn Block>> {
|
|
|
let block_path = self.block_path.ok_or(BlockError::NoBlockPath)?;
|
|
|
let stream = BlockStream::new(self.inner, self.creds, block_path)?;
|
|
@@ -1126,7 +1145,7 @@ mod tests {
|
|
|
|
|
|
#[test]
|
|
|
fn brotli_compress_decompress() {
|
|
|
- const SECT_SZ: usize = SECTOR_SZ_DEFAULT;
|
|
|
+ const SECT_SZ: usize = SECTOR_U64_DEFAULT as usize;
|
|
|
const SECT_CT: usize = 16;
|
|
|
let params = BrotliParams::new(SECT_SZ, 8, 20);
|
|
|
let mut memory = Cursor::new([0u8; SECT_SZ * SECT_CT]);
|
|
@@ -1179,7 +1198,9 @@ mod tests {
|
|
|
}
|
|
|
|
|
|
type EncBlock = SectoredBuf<
|
|
|
- SecretStream<SignStream<BlockStream<Cursor<Vec<u8>>, ConcreteCreds>, ConcreteCreds>>,
|
|
|
+ SecretStream<
|
|
|
+ SignStream<BlockStream<SectoredCursor<Vec<u8>>, ConcreteCreds>, ConcreteCreds>,
|
|
|
+ >,
|
|
|
>;
|
|
|
|
|
|
impl InMemTestCase {
|
|
@@ -1207,7 +1228,7 @@ mod tests {
|
|
|
}
|
|
|
|
|
|
fn stream(&self, vec: Vec<u8>) -> EncBlock {
|
|
|
- let inner = Cursor::new(vec);
|
|
|
+ let inner = SectoredCursor::new(vec, SECTOR_SZ_DEFAULT).require_sect_sz(false);
|
|
|
let mut stream =
|
|
|
BlockStream::new(inner, self.node_creds.clone(), self.block_path.clone()).unwrap();
|
|
|
stream
|
|
@@ -1351,7 +1372,7 @@ mod tests {
|
|
|
fn block_can_create_empty() {
|
|
|
let case = BlockTestCase::new();
|
|
|
BlockOpenOptions::new()
|
|
|
- .with_inner(BtCursor::new(Vec::<u8>::new()))
|
|
|
+ .with_inner(SectoredCursor::new(Vec::<u8>::new(), SECTOR_SZ_DEFAULT))
|
|
|
.with_creds(case.node_creds)
|
|
|
.with_encrypt(true)
|
|
|
.with_block_path(case.root_path)
|