public void ConstructorTest() { var mock = new Mock<Stream>(); var hashAlg = new Mock<HashAlgorithm>(); using (var stream = new NonClosingHashStream(mock.Object, hashAlg.Object, CryptoStreamMode.Read)) { Assert.AreEqual(CryptoStreamMode.Read, stream.CipherMode); } using (var stream = new NonClosingHashStream(mock.Object, hashAlg.Object, CryptoStreamMode.Write)) { Assert.AreEqual(CryptoStreamMode.Write, stream.CipherMode); } }
public void WriteTest() { byte[] content = new byte[1024]; using (var stream = new MemoryStream(content)) using (var hashAlg = new SHA1Managed()) using (var outputstream = new MemoryStream()) { using (var hashstream = new NonClosingHashStream(outputstream, hashAlg, CryptoStreamMode.Write)) { stream.CopyTo(hashstream); } Assert.AreEqual(content, outputstream.ToArray()); hashAlg.TransformFinalBlock(new byte[0], 0, 0); Assert.AreEqual(SHA1.Create().ComputeHash(content), hashAlg.Hash); } }
/// <summary> /// Uploads the localFileStream to remoteDocument. /// </summary> /// <returns> /// The new CMIS document. /// </returns> /// <param name='remoteDocument'> /// Remote document where the local content should be uploaded to. /// </param> /// <param name='localFileStream'> /// Local file stream. /// </param> /// <param name='transmission'> /// Transmission status where the uploader should report its uploading status. /// </param> /// <param name='hashAlg'> /// Hash alg which should be used to calculate a checksum over the uploaded content. /// </param> /// <param name='overwrite'> /// If true, the local content will overwrite the existing content. /// </param> /// <exception cref="CmisSync.Lib.Tasks.UploadFailedException">If upload fails</exception> public virtual IDocument UploadFile( IDocument remoteDocument, Stream localFileStream, Transmission transmission, HashAlgorithm hashAlg, bool overwrite = true, UpdateChecksum update = null) { if (remoteDocument == null) { throw new ArgumentException("remoteDocument can not be null"); } if (localFileStream == null) { throw new ArgumentException("localFileStream can not be null"); } if (transmission == null) { throw new ArgumentException("status can not be null"); } if (hashAlg == null) { throw new ArgumentException("hashAlg can not be null"); } using(NonClosingHashStream hashstream = new NonClosingHashStream(localFileStream, hashAlg, CryptoStreamMode.Read)) using(var transmissionStream = transmission.CreateStream(hashstream)) { ContentStream contentStream = new ContentStream(); contentStream.FileName = remoteDocument.Name; contentStream.MimeType = Cmis.MimeType.GetMIMEType(contentStream.FileName); contentStream.Stream = transmissionStream; try { remoteDocument.SetContentStream(contentStream, overwrite, true); } catch(Exception e) { throw new UploadFailedException(e, remoteDocument); } } hashAlg.TransformFinalBlock(new byte[0], 0, 0); return remoteDocument; }
/// <summary> /// Uploads the file. /// Resumes an upload if the given localFileStream.Position is larger than zero. /// </summary> /// <returns> /// The new CMIS document. /// </returns> /// <param name='remoteDocument'> /// Remote document where the local content should be uploaded to. /// </param> /// <param name='localFileStream'> /// Local file stream. /// </param> /// <param name='transmission'> /// Transmission status where the uploader should report its uploading status. /// </param> /// <param name='hashAlg'> /// Hash alg which should be used to calculate a checksum over the uploaded content. /// </param> /// <param name='overwrite'> /// If true, the local content will overwrite the existing content. /// </param> /// <param name="update">Is called on every new chunk, if not <c>null</c>.</param> /// <exception cref="CmisSync.Lib.Tasks.UploadFailedException"> /// Contains the last successful remote document state. This is needed for continue a failed upload. /// </exception> public override IDocument UploadFile( IDocument remoteDocument, Stream localFileStream, Transmission transmission, HashAlgorithm hashAlg, bool overwrite = true, UpdateChecksum update = null) { IDocument result = remoteDocument; for (long offset = localFileStream.Position; offset < localFileStream.Length; offset += this.ChunkSize) { bool isFirstChunk = offset == 0; bool isLastChunk = (offset + this.ChunkSize) >= localFileStream.Length; using (var hashstream = new NonClosingHashStream(localFileStream, hashAlg, CryptoStreamMode.Read)) using (var chunkstream = new ChunkedStream(hashstream, this.ChunkSize)) using (var offsetstream = new OffsetStream(chunkstream, offset)) using (var transmissionStream = transmission.CreateStream(offsetstream)) { transmission.Length = localFileStream.Length; transmission.Position = offset; chunkstream.ChunkPosition = offset; ContentStream contentStream = new ContentStream(); contentStream.FileName = remoteDocument.Name; contentStream.MimeType = Cmis.MimeType.GetMIMEType(remoteDocument.Name); if (isLastChunk) { contentStream.Length = localFileStream.Length - offset; } else { contentStream.Length = this.ChunkSize; } contentStream.Stream = transmissionStream; try { if (isFirstChunk && result.ContentStreamId != null && overwrite) { result.DeleteContentStream(true); } result.AppendContentStream(contentStream, isLastChunk, true); HashAlgorithmReuse reuse = hashAlg as HashAlgorithmReuse; if (reuse != null && update != null) { using (HashAlgorithm hash = (HashAlgorithm)reuse.Clone()) { hash.TransformFinalBlock(new byte[0], 0, 0); update(hash.Hash, result.ContentStreamLength.GetValueOrDefault()); } } } catch (Exception e) { if (e is FileTransmission.AbortException) { throw; } if (e.InnerException is FileTransmission.AbortException) { throw e.InnerException; } throw new UploadFailedException(e, result); } } } hashAlg.TransformFinalBlock(new byte[0], 0, 0); return result; }
public void ConstructorFailsOnStreamIsNull() { Assert.Throws<ArgumentNullException>(() => { using (var stream = new NonClosingHashStream(null, new Mock<HashAlgorithm>().Object, CryptoStreamMode.Write)); }); }
/// <summary> /// Uploads the file content to the remote document. /// </summary> /// <returns>The SHA-1 hash of the uploaded file content.</returns> /// <param name="localFile">Local file.</param> /// <param name="doc">Remote document.</param> /// <param name="transmissionManager">Transmission manager.</param> /// <param name="transmissionEvent">File Transmission event.</param> /// <param name="mappedObject">Mapped object saved in <c>Storage</c></param> protected byte[] UploadFileWithPWC(IFileInfo localFile, ref IDocument doc, Transmission transmission, IMappedObject mappedObject = null) { byte[] checksum = null; var docPWC = this.LoadRemotePWCDocument(doc, ref checksum); using (var file = localFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { if (checksum != null) { // check PWC checksum for integration using (var hashAlg = new SHA1Managed()) { int bufsize = 8 * 1024; byte[] buffer = new byte[bufsize]; for (long offset = 0; offset < docPWC.ContentStreamLength.GetValueOrDefault();) { int readsize = bufsize; if (readsize + offset > docPWC.ContentStreamLength.GetValueOrDefault()) { readsize = (int)(docPWC.ContentStreamLength.GetValueOrDefault() - offset); } readsize = file.Read(buffer, 0, readsize); hashAlg.TransformBlock(buffer, 0, readsize, buffer, 0); offset += readsize; if (readsize == 0) { break; } } hashAlg.TransformFinalBlock(new byte[0], 0, 0); if (!hashAlg.Hash.SequenceEqual(checksum)) { docPWC.DeleteContentStream(); } file.Seek(0, SeekOrigin.Begin); } } byte[] hash = null; var uploader = FileTransmission.ContentTaskUtils.CreateUploader(this.TransmissionStorage.ChunkSize); using (var hashAlg = new SHA1Reuse()) { try { using (var hashstream = new NonClosingHashStream(file, hashAlg, CryptoStreamMode.Read)) { int bufsize = 8 * 1024; byte[] buffer = new byte[bufsize]; for (long offset = 0; offset < docPWC.ContentStreamLength.GetValueOrDefault();) { int readsize = bufsize; if (readsize + offset > docPWC.ContentStreamLength.GetValueOrDefault()) { readsize = (int)(docPWC.ContentStreamLength.GetValueOrDefault() - offset); } readsize = hashstream.Read(buffer, 0, readsize); offset += readsize; if (readsize == 0) { break; } } } var document = doc; uploader.UploadFile(docPWC, file, transmission, hashAlg, false, (byte[] checksumUpdate, long length) => this.SaveRemotePWCDocument(localFile, document, docPWC, checksumUpdate, transmission)); hash = hashAlg.Hash; } catch (Exception ex) { transmission.FailedException = ex; throw; } } this.TransmissionStorage.RemoveObjectByRemoteObjectId(doc.Id); var properties = new Dictionary<string, object>(); properties.Add(PropertyIds.LastModificationDate, localFile.LastWriteTimeUtc); doc = this.Session.GetObject(docPWC.CheckIn(true, properties, null, string.Empty)) as IDocument; // Refresh is required, or DotCMIS will use cached one only doc.Refresh(); transmission.Status = TransmissionStatus.FINISHED; return hash; } }