private int DownloadNextChunk(IDocument remoteDocument, long offset, long remainingBytes, Transmission transmission, Stream outputstream, HashAlgorithm hashAlg) { lock (this.disposeLock) { if (this.disposed) { transmission.Status = TransmissionStatus.ABORTED; throw new ObjectDisposedException(transmission.Path); } IContentStream contentStream = remoteDocument.GetContentStream(remoteDocument.ContentStreamId, offset, remainingBytes); transmission.Length = remoteDocument.ContentStreamLength; transmission.Position = offset; using (var remoteStream = contentStream.Stream) using (var forwardstream = new ForwardReadingStream(remoteStream)) using (var offsetstream = new OffsetStream(forwardstream, offset)) using (var progress = transmission.CreateStream(offsetstream)) { byte[] buffer = new byte[8 * 1024]; int result = 0; int len; while ((len = progress.Read(buffer, 0, buffer.Length)) > 0) { outputstream.Write(buffer, 0, len); hashAlg.TransformBlock(buffer, 0, len, buffer, 0); result += len; outputstream.Flush(); } return(result); } } }
/// <summary> /// Appends the localFileStream to the remoteDocument. /// </summary> /// <returns> /// The new CMIS document. /// </returns> /// <param name='remoteDocument'> /// Remote document where the local content should be appended to. /// </param> /// <param name='localFileStream'> /// Local file stream. /// </param> /// <param name='status'> /// Transmission status where the uploader should report its appending status. /// </param> /// <param name='hashAlg'> /// Hash alg which should be used to calculate a checksum over the appended content. /// </param> /// <exception cref="CmisSync.Lib.Tasks.UploadFailedException">If Upload fails</exception> public virtual IDocument AppendFile(IDocument remoteDocument, Stream localFileStream, Transmission transmission, HashAlgorithm hashAlg) { using (var transmissionStream = transmission.CreateStream(localFileStream)) using (var hashstream = new CryptoStream(transmissionStream, hashAlg, CryptoStreamMode.Read)) { ContentStream contentStream = new ContentStream(); contentStream.FileName = remoteDocument.Name; contentStream.MimeType = Cmis.MimeType.GetMIMEType(contentStream.FileName); contentStream.Stream = hashstream; try { return(remoteDocument.AppendContentStream(contentStream, true)); } catch (Exception e) { throw new UploadFailedException(e, remoteDocument); } } }
/// <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> /// Downloads the file and returns the SHA-1 hash of the content of the saved file /// </summary> /// <param name="remoteDocument">Remote document.</param> /// <param name="localFileStream">Local taget file stream.</param> /// <param name="transmission">Transmission status.</param> /// <param name="hashAlg">Hash algoritm, which should be used to calculate hash of the uploaded stream content</param> /// <exception cref="IOException">On any disc or network io exception</exception> /// <exception cref="DisposeException">If the remote object has been disposed before the dowload is finished</exception> /// <exception cref="AbortException">If download is aborted</exception> /// <exception cref="CmisException">On exceptions thrown by the CMIS Server/Client</exception> public void DownloadFile( IDocument remoteDocument, Stream localFileStream, Transmission transmission, HashAlgorithm hashAlg, UpdateChecksum update = null) { byte[] buffer = new byte[8 * 1024]; int len; if (localFileStream.Length > 0) { localFileStream.Seek(0, SeekOrigin.Begin); while ((len = localFileStream.Read(buffer, 0, buffer.Length)) > 0) { hashAlg.TransformBlock(buffer, 0, len, buffer, 0); } } long offset = localFileStream.Position; long? fileLength = remoteDocument.ContentStreamLength; if (fileLength <= offset) { transmission.Length = fileLength.GetValueOrDefault(); transmission.Position = offset; hashAlg.TransformFinalBlock(new byte[0], 0, 0); return; } DotCMIS.Data.IContentStream contentStream = null; if (offset > 0) { long remainingBytes = (long)fileLength - offset; transmission.Length = remoteDocument.ContentStreamLength; transmission.Position = offset; contentStream = remoteDocument.GetContentStream(remoteDocument.ContentStreamId, offset, remainingBytes); } else { contentStream = remoteDocument.GetContentStream(); } using (var transmissionStream = transmission.CreateStream(localFileStream)) using (CryptoStream hashstream = new CryptoStream(transmissionStream, hashAlg, CryptoStreamMode.Write)) using (Stream remoteStream = contentStream != null ? contentStream.Stream : new MemoryStream(0)) { transmission.Length = remoteDocument.ContentStreamLength; transmission.Position = offset; int written = 0; while ((len = remoteStream.Read(buffer, 0, buffer.Length)) > 0) { lock (this.disposeLock) { if (this.disposed) { transmission.Status = TransmissionStatus.ABORTED; throw new ObjectDisposedException(transmission.Path); } try { hashstream.Write(buffer, 0, len); hashstream.Flush(); written += len; } catch (Exception) { this.UpdateHash(hashAlg, localFileStream.Length, update); throw; } if (written >= 1024 * 1024) { this.UpdateHash(hashAlg, localFileStream.Length, update); written = 0; } } } if (written > 0) { this.UpdateHash(hashAlg, localFileStream.Length, update); } } }
/// <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; }
private int DownloadNextChunk(IDocument remoteDocument, long offset, long remainingBytes, Transmission transmission, Stream outputstream, HashAlgorithm hashAlg) { lock(this.disposeLock) { if (this.disposed) { transmission.Status = TransmissionStatus.ABORTED; throw new ObjectDisposedException(transmission.Path); } IContentStream contentStream = remoteDocument.GetContentStream(remoteDocument.ContentStreamId, offset, remainingBytes); transmission.Length = remoteDocument.ContentStreamLength; transmission.Position = offset; using (var remoteStream = contentStream.Stream) using (var forwardstream = new ForwardReadingStream(remoteStream)) using (var offsetstream = new OffsetStream(forwardstream, offset)) using (var progress = transmission.CreateStream(offsetstream)) { byte[] buffer = new byte[8 * 1024]; int result = 0; int len; while ((len = progress.Read(buffer, 0, buffer.Length)) > 0) { outputstream.Write(buffer, 0, len); hashAlg.TransformBlock(buffer, 0, len, buffer, 0); result += len; outputstream.Flush(); } return result; } } }
/// <summary> /// Downloads the file and returns the SHA-1 hash of the content of the saved file /// </summary> /// <param name="remoteDocument">Remote document.</param> /// <param name="localFileStream">Local taget file stream.</param> /// <param name="transmission">Transmission status.</param> /// <param name="hashAlg">Hash algoritm, which should be used to calculate hash of the uploaded stream content</param> /// <exception cref="IOException">On any disc or network io exception</exception> /// <exception cref="DisposeException">If the remote object has been disposed before the dowload is finished</exception> /// <exception cref="AbortException">If download is aborted</exception> /// <exception cref="CmisException">On exceptions thrown by the CMIS Server/Client</exception> public void DownloadFile( IDocument remoteDocument, Stream localFileStream, Transmission transmission, HashAlgorithm hashAlg, UpdateChecksum update = null) { byte[] buffer = new byte[8 * 1024]; int len; if (localFileStream.Length > 0) { localFileStream.Seek(0, SeekOrigin.Begin); while ((len = localFileStream.Read(buffer, 0, buffer.Length)) > 0) { hashAlg.TransformBlock(buffer, 0, len, buffer, 0); } } long offset = localFileStream.Position; long?fileLength = remoteDocument.ContentStreamLength; if (fileLength <= offset) { transmission.Length = fileLength.GetValueOrDefault(); transmission.Position = offset; hashAlg.TransformFinalBlock(new byte[0], 0, 0); return; } DotCMIS.Data.IContentStream contentStream = null; if (offset > 0) { long remainingBytes = (long)fileLength - offset; transmission.Length = remoteDocument.ContentStreamLength; transmission.Position = offset; contentStream = remoteDocument.GetContentStream(remoteDocument.ContentStreamId, offset, remainingBytes); } else { contentStream = remoteDocument.GetContentStream(); } using (var transmissionStream = transmission.CreateStream(localFileStream)) using (CryptoStream hashstream = new CryptoStream(transmissionStream, hashAlg, CryptoStreamMode.Write)) using (Stream remoteStream = contentStream != null ? contentStream.Stream : new MemoryStream(0)) { transmission.Length = remoteDocument.ContentStreamLength; transmission.Position = offset; int written = 0; while ((len = remoteStream.Read(buffer, 0, buffer.Length)) > 0) { lock (this.disposeLock) { if (this.disposed) { transmission.Status = TransmissionStatus.ABORTED; throw new ObjectDisposedException(transmission.Path); } try { hashstream.Write(buffer, 0, len); hashstream.Flush(); written += len; } catch (Exception) { this.UpdateHash(hashAlg, localFileStream.Length, update); throw; } if (written >= 1024 * 1024) { this.UpdateHash(hashAlg, localFileStream.Length, update); written = 0; } } } if (written > 0) { this.UpdateHash(hashAlg, localFileStream.Length, update); } } }
/// <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 CreateStreamReturnsNewTransmissionStreamInstance() { var underTest = new Transmission(TransmissionType.DOWNLOAD_NEW_FILE, this.path); using (var stream = new MemoryStream()) using (var newStream = underTest.CreateStream(stream)) using (var secondNewStream = underTest.CreateStream(stream)) { Assert.That(newStream, Is.Not.Null); Assert.That(newStream, Is.InstanceOf<TransmissionStream>()); Assert.That(secondNewStream, Is.Not.Null); Assert.That(secondNewStream, Is.InstanceOf<TransmissionStream>()); Assert.That(newStream != secondNewStream, Is.True); } }
/// <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> /// Appends the localFileStream to the remoteDocument. /// </summary> /// <returns> /// The new CMIS document. /// </returns> /// <param name='remoteDocument'> /// Remote document where the local content should be appended to. /// </param> /// <param name='localFileStream'> /// Local file stream. /// </param> /// <param name='status'> /// Transmission status where the uploader should report its appending status. /// </param> /// <param name='hashAlg'> /// Hash alg which should be used to calculate a checksum over the appended content. /// </param> /// <exception cref="CmisSync.Lib.Tasks.UploadFailedException">If Upload fails</exception> public virtual IDocument AppendFile(IDocument remoteDocument, Stream localFileStream, Transmission transmission, HashAlgorithm hashAlg) { using (var transmissionStream = transmission.CreateStream(localFileStream)) using (var hashstream = new CryptoStream(transmissionStream, hashAlg, CryptoStreamMode.Read)) { ContentStream contentStream = new ContentStream(); contentStream.FileName = remoteDocument.Name; contentStream.MimeType = Cmis.MimeType.GetMIMEType(contentStream.FileName); contentStream.Stream = hashstream; try { return remoteDocument.AppendContentStream(contentStream, true); } catch(Exception e) { throw new UploadFailedException(e, remoteDocument); } } }