Browse Source

Ensured that inodes are no longer trivially identifiable in the LocalFs.

Matthew Carr 2 years ago
parent
commit
7a5ec532ee
1 changed files with 74 additions and 23 deletions
  1. 74 23
      crates/btfproto/src/local_fs.rs

+ 74 - 23
crates/btfproto/src/local_fs.rs

@@ -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)?;
                 }
             }