|
@@ -4,7 +4,7 @@ use crate::{msg::*, server::FsProvider};
|
|
|
use btlib::{
|
|
|
accessor::Accessor,
|
|
|
bterr,
|
|
|
- crypto::{Creds, Decrypter, Signer},
|
|
|
+ crypto::{Creds, Decrypter, Signer, SymKey},
|
|
|
error::BtErr,
|
|
|
AuthzAttrs, BlockAccessor, BlockError, BlockMeta, BlockMetaSecrets, BlockOpenOptions,
|
|
|
BlockPath, BlockReader, DirEntry, Directory, Epoch, FileBlock, FlushMeta, IssuedProcRec,
|
|
@@ -39,7 +39,7 @@ use tokio::sync::{
|
|
|
pub use private::{Authorizer, AuthzContext, Error, LocalFs, ModeAuthorizer};
|
|
|
|
|
|
mod private {
|
|
|
- use btlib::crypto::SymKey;
|
|
|
+ use btlib::crypto::HashKind;
|
|
|
|
|
|
use super::*;
|
|
|
|
|
@@ -601,6 +601,7 @@ mod private {
|
|
|
/// The credentials this blocktree instance will use for all cryptographic operations.
|
|
|
creds: C,
|
|
|
authorizer: A,
|
|
|
+ root_principal: Principal,
|
|
|
}
|
|
|
|
|
|
impl<C, A> LocalFs<C, A> {
|
|
@@ -617,10 +618,9 @@ mod private {
|
|
|
creds: C,
|
|
|
authorizer: A,
|
|
|
) -> Result<LocalFs<C, A>> {
|
|
|
- let mut root_block_path = creds
|
|
|
- .writecap()
|
|
|
- .ok_or(BlockError::MissingWritecap)?
|
|
|
- .root_block_path();
|
|
|
+ let writecap = creds.writecap().ok_or(BlockError::MissingWritecap)?;
|
|
|
+ let mut root_block_path = writecap.root_block_path();
|
|
|
+ let root_principal = writecap.root_principal();
|
|
|
|
|
|
// Initialize the superblock.
|
|
|
let mut sb_block = Self::open_block(
|
|
@@ -629,6 +629,7 @@ mod private {
|
|
|
creds.clone(),
|
|
|
root_block_path.clone(),
|
|
|
None,
|
|
|
+ &root_principal,
|
|
|
)?;
|
|
|
let sb = Superblock {
|
|
|
generation,
|
|
@@ -653,6 +654,7 @@ mod private {
|
|
|
creds.clone(),
|
|
|
root_block_path.clone(),
|
|
|
None,
|
|
|
+ &root_principal,
|
|
|
)?;
|
|
|
write_to(&Directory::new(), &mut root_block)?;
|
|
|
root_block.mut_meta_body().access_secrets(|secrets| {
|
|
@@ -666,10 +668,17 @@ mod private {
|
|
|
})?;
|
|
|
root_block.flush()?;
|
|
|
|
|
|
- let fs = Self::new(btdir, sb, sb_block, root_block, creds, authorizer)?;
|
|
|
+ let fs = Self::new(
|
|
|
+ btdir,
|
|
|
+ sb,
|
|
|
+ sb_block,
|
|
|
+ root_block,
|
|
|
+ creds,
|
|
|
+ authorizer,
|
|
|
+ root_principal,
|
|
|
+ )?;
|
|
|
let writecap = fs.creds.writecap().ok_or(BlockError::MissingWritecap)?;
|
|
|
- let root_principal = writecap.root_principal();
|
|
|
- if fs.creds.principal() != root_principal {
|
|
|
+ if fs.creds.principal() != fs.root_principal {
|
|
|
let proc_rec = IssuedProcRec {
|
|
|
addr: IpAddr::V6(Ipv6Addr::LOCALHOST),
|
|
|
pub_creds: fs.creds.concrete_pub(),
|
|
@@ -680,7 +689,7 @@ mod private {
|
|
|
supp_gids: Vec::new(),
|
|
|
},
|
|
|
};
|
|
|
- root_block_path.push_component(root_principal.to_string());
|
|
|
+ root_block_path.push_component(fs.root_principal.to_string());
|
|
|
fs.grant_access_to(
|
|
|
&Arc::new(root_block_path),
|
|
|
SpecInodes::RootDir.into(),
|
|
@@ -693,16 +702,16 @@ mod private {
|
|
|
|
|
|
/// Opens an existing blocktree stored at the given path.
|
|
|
pub fn new_existing(btdir: PathBuf, creds: C, authorizer: A) -> Result<LocalFs<C, A>> {
|
|
|
- let root_block_path = creds
|
|
|
- .writecap()
|
|
|
- .ok_or(BlockError::MissingWritecap)?
|
|
|
- .root_block_path();
|
|
|
+ let writecap = creds.writecap().ok_or(BlockError::MissingWritecap)?;
|
|
|
+ let root_block_path = writecap.root_block_path();
|
|
|
+ let root_principal = writecap.root_principal();
|
|
|
let mut sb_block = Self::open_block(
|
|
|
&btdir,
|
|
|
SpecInodes::Sb.into(),
|
|
|
creds.clone(),
|
|
|
root_block_path.to_owned(),
|
|
|
None,
|
|
|
+ &root_principal,
|
|
|
)?;
|
|
|
let sb = read_from(&mut sb_block)?;
|
|
|
let root_block = Self::open_block(
|
|
@@ -711,8 +720,17 @@ mod private {
|
|
|
creds.clone(),
|
|
|
root_block_path,
|
|
|
None,
|
|
|
+ &root_principal,
|
|
|
)?;
|
|
|
- Self::new(btdir, sb, sb_block, root_block, creds, authorizer)
|
|
|
+ Self::new(
|
|
|
+ btdir,
|
|
|
+ sb,
|
|
|
+ sb_block,
|
|
|
+ root_block,
|
|
|
+ creds,
|
|
|
+ authorizer,
|
|
|
+ root_principal,
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
fn new(
|
|
@@ -722,6 +740,7 @@ mod private {
|
|
|
root_block: Accessor<FileBlock<C>>,
|
|
|
creds: C,
|
|
|
authorizer: A,
|
|
|
+ root_principal: Principal,
|
|
|
) -> Result<LocalFs<C, A>> {
|
|
|
let mut inodes = HashMap::with_capacity(1);
|
|
|
let empty_path = Arc::new(BlockPath::default());
|
|
@@ -743,17 +762,47 @@ mod private {
|
|
|
generation: sb.generation,
|
|
|
creds,
|
|
|
authorizer,
|
|
|
+ root_principal,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ fn hex_encode<'a>(dest: &'a mut [u8], src: &[u8]) -> Result<&'a str> {
|
|
|
+ if dest.len() < 2 * src.len() {
|
|
|
+ return Err(bterr!(
|
|
|
+ "destination slice must be at least twice source slice length"
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ for (index, byte) in src.iter().enumerate() {
|
|
|
+ let upper = (byte & 0xF0) >> 4;
|
|
|
+ let lower = byte & 0x0F;
|
|
|
+ let first = char::from_digit(upper as u32, 16).unwrap();
|
|
|
+ let second = char::from_digit(lower as u32, 16).unwrap();
|
|
|
+ first.encode_utf8(&mut dest[2 * index..]);
|
|
|
+ second.encode_utf8(&mut dest[2 * index + 1..]);
|
|
|
+ }
|
|
|
+ std::str::from_utf8(&dest[..2 * src.len()]).map_err(|err| err.into())
|
|
|
+ }
|
|
|
+
|
|
|
/// Returns the path to the file storing the given inode's data.
|
|
|
- fn block_path<P: AsRef<Path>>(parent: P, inode: Inode) -> PathBuf {
|
|
|
- let group = inode / 0xFF;
|
|
|
- let mut path = PathBuf::new();
|
|
|
+ fn block_path<P: AsRef<Path>>(
|
|
|
+ parent: P,
|
|
|
+ inode: Inode,
|
|
|
+ root_principal: &Principal,
|
|
|
+ ) -> Result<PathBuf> {
|
|
|
+ const HASH: HashKind = HashKind::Sha2_256;
|
|
|
+ let mut buf = [0u8; HASH.len()];
|
|
|
+ HASH.digest(
|
|
|
+ &mut buf,
|
|
|
+ [root_principal.as_slice(), inode.to_le_bytes().as_slice()].into_iter(),
|
|
|
+ )?;
|
|
|
+ let mut hex_buf = [0u8; 2 * HASH.len()];
|
|
|
+ let hex_str = Self::hex_encode(&mut hex_buf, &buf)?;
|
|
|
+ let mut path =
|
|
|
+ PathBuf::with_capacity(parent.as_ref().as_os_str().len() + 1 + hex_str.len() + 1);
|
|
|
path.push(parent);
|
|
|
- path.push(format!("{group:02x}"));
|
|
|
- path.push(format!("{inode:x}.blk"));
|
|
|
- path
|
|
|
+ path.push(&hex_str[..2]);
|
|
|
+ path.push(&hex_str[2..]);
|
|
|
+ Ok(path)
|
|
|
}
|
|
|
|
|
|
fn open_block<P: AsRef<Path>>(
|
|
@@ -762,8 +811,9 @@ mod private {
|
|
|
creds: C,
|
|
|
block_path: BlockPath,
|
|
|
parent_key: Option<SymKey>,
|
|
|
+ root_principal: &Principal,
|
|
|
) -> Result<Accessor<FileBlock<C>>> {
|
|
|
- let path = Self::block_path(&btdir, inode);
|
|
|
+ let path = Self::block_path(&btdir, inode, root_principal)?;
|
|
|
let dir = path.ancestors().nth(1).unwrap();
|
|
|
if let Err(err) = std::fs::create_dir(dir) {
|
|
|
match err.kind() {
|
|
@@ -812,6 +862,7 @@ mod private {
|
|
|
self.creds.clone(),
|
|
|
block_path,
|
|
|
parent_key,
|
|
|
+ &self.root_principal,
|
|
|
)?;
|
|
|
let value = Arc::new(RwLock::new(InodeTableValue::new(block, from)));
|
|
|
let mut inodes = self.inodes.write().await;
|
|
@@ -871,7 +922,7 @@ mod private {
|
|
|
.map_err(|_| bterr!("LOGIC ERROR: entry for inode {inode} was still in use while it was being forgotten"))?;
|
|
|
let delete = entry.into_inner().delete;
|
|
|
if delete {
|
|
|
- let path = Self::block_path(&self.path, inode);
|
|
|
+ let path = Self::block_path(&self.path, inode, &self.root_principal)?;
|
|
|
std::fs::remove_file(path)?;
|
|
|
}
|
|
|
}
|