| 
					
				 | 
			
			
				@@ -25,7 +25,7 @@ use log::{error, warn}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 use serde::{de::DeserializeOwned, Deserialize, Serialize}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 use serde_big_array::BigArray; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 use std::{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    collections::HashMap, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    collections::{BTreeMap, HashMap}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     convert::{Infallible, TryFrom}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fmt::{self, Display, Formatter}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     hash::Hash as Hashable, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -223,7 +223,7 @@ impl<T: Read> ReadExt for T {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 pub struct BlockMetaBody { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     path: Path, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    readcaps: HashMap<Principal, Ciphertext<SymKey>>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    readcaps: BTreeMap<Principal, Ciphertext<SymKey>>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     writecap: Option<Writecap>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /// A hash which provides integrity for the contents of the block body. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     integrity: Option<Hash>, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -235,7 +235,7 @@ impl BlockMetaBody { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fn new<C: Creds>(creds: &C) -> BlockMetaBody { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         BlockMetaBody { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             path: Path::default(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            readcaps: HashMap::new(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            readcaps: BTreeMap::new(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             writecap: creds.writecap().map(|e| e.to_owned()), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             integrity: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             signing_key: creds.public_sign().to_owned(), 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -269,8 +269,11 @@ impl<T: Read + Seek, C: Creds> BlockStream<T, C> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fn new(inner: T, creds: C) -> Result<BlockStream<T, C>> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let (trailered, trailer) = Trailered::<_, BlockMeta>::new(inner)?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let trailer = match trailer { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Some(trailer) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                crypto::verify_header(&trailer.body, &trailer.sig)?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Some(mut trailer) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                trailer.assert_valid()?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // We need to use the writecap and signing_key provided by the current credentials. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                trailer.body.writecap = creds.writecap().map(|e| e.to_owned()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                trailer.body.signing_key = creds.public_sign().to_owned(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 trailer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             None => { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1001,7 +1004,9 @@ impl FragmentRecord { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /// An identifier for a security principal, which is any entity that can be authenticated. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Hashable, Clone, Default)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[derive( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Debug, PartialEq, Eq, Serialize, Deserialize, Hashable, Clone, Default, PartialOrd, Ord, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 pub struct Principal(Hash); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 impl Principal { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1010,6 +1015,12 @@ impl Principal { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+impl Display for Principal { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.0.fmt(f) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /// Trait for types which are owned by a `Principal`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 trait Principaled { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /// Returns the `Principal` that owns `self`, using the given hash algorithm. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1207,9 +1218,12 @@ struct FragmentSerial(u32); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #[cfg(test)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 mod tests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    use std::{fs::OpenOptions, io::Cursor}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use std::{fs::OpenOptions, io::Cursor, path::PathBuf}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    use crate::crypto::{tpm::TpmCredStore, CredStore, CredsPriv}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use crate::crypto::{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tpm::{TpmCredStore, TpmCreds}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ConcreteCreds, CredStore, CredsPriv, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     use super::*; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     use tempdir::TempDir; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1678,57 +1692,199 @@ mod tests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .expect("failed to open block"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    #[test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    fn block_contents_persisted() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        const EXPECTED: &[u8] = b"Silly sordid sulking sultans."; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let temp_dir = TempDir::new("btlib").expect("failed to create temp dir"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let file_path = temp_dir.path().join("test.blk").to_owned(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let harness = SwtpmHarness::new().expect("failed to start swtpm"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let context = harness.context().expect("failed to retrieve context"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let cred_store = TpmCredStore::new(context, harness.state_path()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .expect("failed to create TpmCredStore"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let root_creds = cred_store 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .gen_root_creds("(1337Prestidigitation7331)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .expect("failed to get root creds"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let mut node_creds = cred_store.node_creds().expect("failed to get node creds"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let writecap = root_creds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .issue_writecap( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                node_creds.principal(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                vec!["nodes".to_string(), "phone".to_string()], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Epoch::now() + Duration::from_secs(3600), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .expect("failed to issue writecap"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let path = writecap.path.clone(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        node_creds.set_writecap(writecap); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    struct BlockTestCase { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        root_creds: TpmCreds, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        node_creds: TpmCreds, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        swtpm: SwtpmHarness, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        temp_dir: TempDir, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    impl BlockTestCase { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const ROOT_PASSWORD: &'static str = "(1337Prestidigitation7331)"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn new() -> BlockTestCase { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let temp_dir = TempDir::new("block_test").expect("failed to create temp dir"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let swtpm = SwtpmHarness::new().expect("failed to start swtpm"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let context = swtpm.context().expect("failed to retrieve context"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let cred_store = TpmCredStore::new(context, swtpm.state_path()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to create TpmCredStore"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let root_creds = cred_store 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .gen_root_creds(Self::ROOT_PASSWORD) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to get root creds"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut node_creds = cred_store.node_creds().expect("failed to get node creds"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let writecap = root_creds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .issue_writecap( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    node_creds.principal(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    vec!["nodes".to_string(), "phone".to_string()], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Epoch::now() + Duration::from_secs(3600), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to issue writecap"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            node_creds.set_writecap(writecap); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BlockTestCase { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                temp_dir, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                swtpm, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                node_creds, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                root_creds, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn fs_path(&self, path: &crate::Path) -> PathBuf { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut fs_path = self.temp_dir.path().to_owned(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fs_path.extend(path.components.iter()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fs_path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn open_new(&mut self, path: &crate::Path) -> Box<dyn Block> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             let file = OpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .create_new(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .write(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .read(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .open(&file_path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .write(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .open(&self.fs_path(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .expect("failed to open file"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             let mut block = BlockOpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .with_inner(file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .with_creds(node_creds.clone()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_creds(self.node_creds.clone()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .with_encrypt(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .open() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .expect("failed to open block"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            block.set_path(path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.set_path(self.node_creds.writecap().unwrap().path.clone()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn open_existing(&mut self, path: &crate::Path) -> Box<dyn Block> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let file = OpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .read(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .write(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .open(&self.fs_path(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to reopen file"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BlockOpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_inner(file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_creds(self.node_creds.clone()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_encrypt(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .open() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to reopen block") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fn block_contents_persisted() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const EXPECTED: &[u8] = b"Silly sordid sulking sultans."; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const BLOCK_NAME: &'static str = "test.blk"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut case = BlockTestCase::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let path = Path { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            root: case.root_creds.principal(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            components: vec!["test.blk".to_string()], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut block = case.open_new(&path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             block.write(EXPECTED).expect("failed to write"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             block.flush().expect("flush failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let file = OpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .read(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .open(&file_path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .expect("failed to reopen file"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let mut block = BlockOpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .with_inner(file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .with_creds(node_creds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .with_encrypt(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .open() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .expect("failed to reopen block"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut block = case.open_existing(&path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let mut actual = [0u8; EXPECTED.len()]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         block.read(&mut actual).expect("read failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert_eq!(EXPECTED, actual); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fn block_write_twice() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const EXPECTED: &[u8] = b"Cool callous calamitous colonels."; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const MID: usize = EXPECTED.len() / 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const BLOCK_NAME: &'static str = "test.blk"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut case = BlockTestCase::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let path = Path { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            root: case.root_creds.principal(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            components: vec!["test.blk".to_string()], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut block = case.open_new(&path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.write(&EXPECTED[..MID]).expect("first write failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.flush().expect("first flush failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut block = case.open_existing(&path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .seek(SeekFrom::Start(MID.try_into().unwrap())) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("seek failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.write(&EXPECTED[MID..]).expect("second write failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.flush().expect("second flush failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut block = case.open_existing(&path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut actual = [0u8; EXPECTED.len()]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.read(&mut actual).expect("read failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            assert_eq!(EXPECTED, actual); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fn block_write_with_different_creds() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const EXPECTED: &[u8] = b"Cool callous calamitous colonels."; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const MID: usize = EXPECTED.len() / 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const BLOCK_NAME: &'static str = "test.blk"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut case = BlockTestCase::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let path = Path { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            root: case.root_creds.principal(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            components: vec!["test.blk".to_string()], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let app_creds = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut app_creds = ConcreteCreds::generate().expect("failed to generate app creds"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let writecap = case 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .root_creds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .issue_writecap( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    app_creds.principal(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    path.components.clone(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Epoch::now() + Duration::from_secs(60), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to issue writecap"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            app_creds.set_writecap(writecap); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            app_creds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut block = case.open_new(&path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .add_readcap_for(app_creds.principal(), &app_creds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to add readcap"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.write(&EXPECTED[..MID]).expect("first write failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.flush().expect("first flush failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let file = OpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .read(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .write(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .open(case.fs_path(&path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to reopen file"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut block = BlockOpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_inner(file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Note that this write is performed using app_creds. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_creds(app_creds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_encrypt(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .open() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to reopen block"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .seek(SeekFrom::Start(MID.try_into().unwrap())) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("seek failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.write(&EXPECTED[MID..]).expect("second write failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.flush().expect("second flush failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let file = OpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .read(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .write(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .open(case.fs_path(&path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to reopen file"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut block = BlockOpenOptions::new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_inner(file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_creds(case.node_creds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with_encrypt(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .open() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("failed to reopen block"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut actual = [0u8; EXPECTED.len()]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            block.read(&mut actual).expect("read failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            assert_eq!(EXPECTED, actual); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |