protected void SaveOuterManifest() { // Serialize the manifest to memory MemoryStream serializedManifestStream = new MemoryStream(); OuterManifest.WriteManifestStream(serializedManifestStream); serializedManifestStream.Position = 0; String tempFilePath = Path.Combine( InnerProxy.TempDirectory.FullName, DefaultOuterManifestFileName); // We use the inner GUID as salt for the outer manifest, so update // it each time we write the outer manifest. The inner GUID is // really useless anyways. InnerProxy.Manifest.ChangeGUID(); byte[] outerKeyData = CryptUtilities.MakeKeyBytesFromString( OuterKeyString, InnerProxy.Manifest.Guid.ToByteArray()); byte[] cryptHash = WriteCryptFileAndHash( serializedManifestStream, outerKeyData, tempFilePath); // The new ManifestFileInfo is actually rooted in the inner // Manifest object, but that is ok - although it is kind of a // hack. The fact is that we don't maintain an actual Manifest // object to mirror the inner manifest - and we know that the // implementation of PutFile won't be affected by doing this. ManifestDirectoryInfo parentDirectory = InnerProxy.Manifest.RootDirectory; ManifestFileInfo destManifestFile = new ManifestFileInfo( DefaultOuterManifestFileName, parentDirectory); destManifestFile.RegisteredUtc = DateTime.Now; FileInfo outerManifestFileInfo = new FileInfo(tempFilePath); destManifestFile.LastModifiedUtc = outerManifestFileInfo.LastWriteTimeUtc; destManifestFile.FileLength = outerManifestFileInfo.Length; destManifestFile.FileHash = new FileHash(cryptHash, CryptUtilities.DefaultHashType); InnerProxy.PutFile(ProxyToInner, destManifestFile); }
public void PutFile( IRepositoryProxy sourceRepository, ManifestFileInfo sourceManifestFile) { // Name the inner file with the hash of the hash. We protect // the hash in this way because it is used as the salt to // encrypt the data in the file, and it might provide some // benefit to a cryptographic attack. FileHash hashedHash = FileHash.ComputeHash( sourceManifestFile.FileHash.HashData); String hashedHashString = hashedHash.ToString(); // Only add the file data if we don't have it already. if (myHashedStringMap.ContainsKey(hashedHashString) == false) { FileInfo sourceFileInfo = sourceRepository.GetFile(sourceManifestFile); byte[] keyData = CryptUtilities.MakeKeyBytesFromString( OuterKeyString, sourceManifestFile.FileHash.HashData); // Use the inner proxy temp directory because that is likely // the ultimate destination of the file and we don't want to // copy the data if we can avoid it. This is a minor break in // encapsulation but has a significant impact on performance. String destFilePath = Path.Combine( InnerProxy.TempDirectory.FullName, hashedHashString); Stream sourceFileStream = sourceFileInfo.OpenRead(); byte[] cryptHash = WriteCryptFileAndHash( sourceFileStream, keyData, destFilePath); FileInfo cryptFileInfo = new FileInfo(destFilePath); // Make a dummy parent manifest directory to give to the inner // proxy. This is actually rooted in the inner manifest, but // that is ok - although it is kind of a hack. The fact is // that we don't maintain an actual manifest to mirror the // inner manifest - and we know that the implementation of // PutFile won't be affected by doing this. ManifestDirectoryInfo parentDirectory = MakeInnerParentDirectory( hashedHashString, InnerProxy.Manifest.RootDirectory); ManifestFileInfo destManifestFile = new ManifestFileInfo( hashedHashString, parentDirectory); destManifestFile.RegisteredUtc = DateTime.UtcNow; destManifestFile.LastModifiedUtc = cryptFileInfo.LastWriteTimeUtc; destManifestFile.FileLength = cryptFileInfo.Length; destManifestFile.FileHash = new FileHash(cryptHash, CryptUtilities.DefaultHashType); InnerProxy.PutFile(ProxyToInner, destManifestFile); myHashedStringMap.Add(hashedHashString, destManifestFile); myNeedToRegenerateFileMap = true; } ManifestFileInfo outerManifestFileInfo = Manifest.PutFileFromOtherManifest(sourceManifestFile); myManifestChanged = true; }