File transmission event. This event should be queued only once. The progress will not be reported on the queue. Interested entities should add themselfs as TransmissionEventHandler on the event TransmissionStatus to get informed about the progress.
Inheritance: INotifyPropertyChanged
        private void SetUp(long length) {
            this.transmission = new Transmission(TransmissionType.DOWNLOAD_NEW_FILE, "testfile");
            this.transmission.AddDefaultConstraints();
            if (this.localFileStream != null) {
                this.localFileStream.Dispose();
            }

            this.localFileStream = new MemoryStream();
            if (this.hashAlg != null) {
                this.hashAlg.Dispose();
            }

            this.hashAlg = new SHA1Managed();
            this.remoteLength = length;
            this.remoteContent = new byte[this.remoteLength];
            if (this.random != null) {
                this.random.Dispose();
            }

            this.random = RandomNumberGenerator.Create();
            this.random.GetBytes(this.remoteContent);
            this.mockedMemStream = new Mock<MemoryStream>(this.remoteContent) { CallBase = true };
            this.mockedStream = new Mock<IContentStream>();
            this.mockedStream.Setup(stream => stream.Length).Returns(this.remoteLength);
            this.mockedStream.Setup(stream => stream.Stream).Returns(this.mockedMemStream.Object);
            this.mockedDocument = new Mock<IDocument>();
            this.mockedDocument.Setup(doc => doc.ContentStreamLength).Returns(this.remoteLength);
            this.mockedDocument.Setup(doc => doc.GetContentStream()).Returns(this.mockedStream.Object);
        }
        /// <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>
        /// <param name="update">Not or not yet used</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;
                while ((len = localFileStream.Read(buffer, 0, buffer.Length)) > 0) {
                    hashAlg.TransformBlock(buffer, 0, len, buffer, 0);
                }
            }

            long? fileLength = remoteDocument.ContentStreamLength;

            // Download content if exists
            if (fileLength > 0) {
                long offset = localFileStream.Position;
                long remainingBytes = (fileLength != null) ? (long)fileLength - offset : this.ChunkSize;
                try {
                    do {
                        offset += this.DownloadNextChunk(remoteDocument, offset, remainingBytes, transmission, localFileStream, hashAlg);
                    } while(fileLength == null);
                } catch (DotCMIS.Exceptions.CmisConstraintException) {
                }
            } else {
                transmission.Position = 0;
                transmission.Length = 0;
            }

            hashAlg.TransformFinalBlock(new byte[0], 0, 0);
        }
Example #3
0
        public void UploadWhileAnotherProcessIsWritingToFile() {
            var fileName = "slowFile.txt";
            var chunkSize = 1024;
            var chunks = 100;
            byte[] chunk = new byte[chunkSize];
            var finalLength = chunks * chunkSize;
            var file = new FileInfo(Path.Combine(this.LocalTestDir.FullName, fileName));
            var mockedDocument = new Mock<IDocument>();
            var transmissionStatus = new Transmission(TransmissionType.UPLOAD_NEW_FILE, fileName);
            mockedDocument.Setup(doc => doc.Name).Returns(fileName);
            using (var remoteStream = new MemoryStream()) {
                mockedDocument.Setup(doc => doc.SetContentStream(It.IsAny<IContentStream>(), It.Is<bool>(b => b == true), It.Is<bool>(b => b == true)))
                    .Callback<IContentStream, bool, bool>((s, b, r) => s.Stream.CopyTo(remoteStream))
                        .Returns(new Mock<IObjectId>().Object);
                using (var fileStream = file.Open(FileMode.CreateNew, FileAccess.Write, FileShare.Read)) {
                    using (var task = Task.Factory.StartNew(() => {
                        var newFileHandle = new FileInfo(file.FullName);
                        using (var hashAlg = new SHA1Managed())
                        using (var readingFileStream = newFileHandle.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                        using (var uploader = new SimpleFileUploader()) {
                            uploader.UploadFile(mockedDocument.Object, readingFileStream, transmissionStatus, hashAlg);
                        }

                        Assert.That(remoteStream.Length, Is.EqualTo(finalLength));
                    })) {
                        for (int i = 0; i < chunks; i++) {
                            Thread.Sleep(10);
                            fileStream.Write(chunk, 0, chunkSize);
                        }

                        task.Wait();
                    }
                }
            }
        }
 public void ConstructorTakesTypeFileNameAndCachePath(TransmissionType type) {
     var underTest = new Transmission(type, this.path, this.cache);
     Assert.That(underTest.Type, Is.EqualTo(type));
     Assert.That(underTest.Path, Is.EqualTo(this.path));
     Assert.That(underTest.CachePath, Is.EqualTo(this.cache));
     Assert.That(underTest.Status, Is.EqualTo(TransmissionStatus.TRANSMITTING));
 }
        public void Percent(TransmissionType type) {
            var underTest = new Transmission(type, this.path);
            double? percent = null;
            underTest.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) => {
                if (e.PropertyName == Utils.NameOf((Transmission t) => t.Percent)) {
                    percent = (sender as Transmission).Percent;
                }
            };

            Assert.That(underTest.Percent, Is.Null);

            underTest.Length = 100;
            underTest.Position = 0;

            Assert.That(percent, Is.EqualTo(0));
            underTest.Position = 10;
            Assert.That(percent, Is.EqualTo(10));
            underTest.Position = 100;
            Assert.That(percent, Is.EqualTo(100));
            underTest.Length = 1000;
            Assert.That(percent, Is.EqualTo(10));
            underTest.Position = 1000;
            underTest.Length = 2000;
            Assert.That(percent, Is.EqualTo(50));

            underTest.Position = 201;
            underTest.Length = 1000;
            Assert.That(percent, Is.EqualTo(20));
        }
        /// <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 SetUp() {
            this.transmission = new Transmission(TransmissionType.UPLOAD_NEW_FILE, "testfile");
            this.transmission.AddDefaultConstraints();
            this.fileLength = 1024 * 1024;
            this.localContent = new byte[this.fileLength];
            if (this.localFileStream != null) {
                this.localFileStream.Dispose();
            }

            this.localFileStream = new MemoryStream(this.localContent);
            if (this.hashAlg != null) {
                this.hashAlg.Dispose();
            }

            this.hashAlg = new SHA1Managed();
            using (RandomNumberGenerator random = RandomNumberGenerator.Create()) {
                random.GetBytes(this.localContent);
            }

            this.mockedMemStream = new Mock<MemoryStream>() { CallBase = true };
            this.mockedDocument = new Mock<IDocument>();
            this.mockedStream = new Mock<IContentStream>();
            this.mockedStream.Setup(stream => stream.Length).Returns(this.fileLength);
            this.mockedStream.Setup(stream => stream.Stream).Returns(this.mockedMemStream.Object);
            this.mockedDocument.Setup(doc => doc.Name).Returns("test.txt");
        }
 private void HandleDeleteTransmissionEvent(Transmission item) {
     lock (lockTransmissionItems) {
         for (int i = TransmissionItems.Count - 1; i >= 0; --i) {
             if (TransmissionItems[i].Path == item.Path) {
                 TransmissionItems.RemoveAt(i);
                 changeAll = true;
                 return;
             }
         }
     }
 }
 public void AbortWriteIfAbortIsCalled() {
     var transmission = new Transmission(TransmissionType.DOWNLOAD_MODIFIED_FILE, "path");
     using (var inputStream = new MemoryStream(new byte[1024 * 1024 * 10]))
     using (var stream = new Mock<MemoryStream>() { CallBase = true }.Object)
     using (var underTest = new TransmissionStream(stream, transmission)) {
         transmission.Abort();
         Assert.Throws<AbortException>(() => inputStream.CopyTo(underTest));
         Mock.Get(stream).Verify(s => s.WriteByte(It.IsAny<byte>()), Times.Never());
         Mock.Get(stream).Verify(s => s.Write(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>()), Times.Never());
     }
 }
 public void AbortReadIfAbortIsCalled() {
     var transmission = new Transmission(TransmissionType.DOWNLOAD_MODIFIED_FILE, "path");
     byte[] content = new byte[1024];
     using (var outputStream = new MemoryStream())
     using (var stream = new Mock<MemoryStream>() { CallBase = true }.Object)
     using (var underTest = new TransmissionStream(stream, transmission)) {
         transmission.Abort();
         Assert.Throws<AbortException>(() => underTest.CopyTo(outputStream));
         Mock.Get(stream).Verify(s => s.ReadByte(), Times.Never());
         Mock.Get(stream).Verify(s => s.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>()), Times.Never());
     }
 }
        /// <summary>
        /// Creates a new the transmission object and adds it to the manager. The manager decides when to and how the
        /// transmission gets removed from it.
        /// </summary>
        /// <returns>The transmission.</returns>
        /// <param name="type">Transmission type.</param>
        /// <param name="path">Full path.</param>
        /// <param name="cachePath">Cache path.</param>
        public Transmission CreateTransmission(TransmissionType type, string path, string cachePath = null) {
            var transmission = new Transmission(type, path, cachePath);
            lock (this.collectionLock) {
                var entry = this.pathToRepoNameMapping.FirstOrDefault(t => path.StartsWith(t.Key));
                transmission.Repository = entry.Value ?? string.Empty;
                if (entry.Key != null) {
                    transmission.RelativePath = path.Substring(entry.Key.Length).TrimStart(System.IO.Path.DirectorySeparatorChar);
                }

                transmission.PropertyChanged += this.TransmissionFinished;
                this.activeTransmissions.Add(transmission);
            }

            return transmission;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="CmisSync.Lib.Streams.TransmissionStream"/> class.
        /// </summary>
        /// <param name="wrappedStream">Wrapped stream.</param>
        /// <param name="transmission">Transmission object to be notified about changes and listened to events as well.</param>
        public TransmissionStream(Stream wrappedStream, Transmission transmission) {
            if (transmission == null) {
                throw new ArgumentNullException("transmission");
            }

            this.abort = new AbortableStream(wrappedStream);
            this.pause = new PausableStream(this.abort);
            this.bandwidthNotify = new BandwidthNotifyingStream(this.pause);
            this.progress = new ProgressStream(this.bandwidthNotify);
            this.abort.PropertyChanged += (object sender, PropertyChangedEventArgs e) => {
                var a = sender as AbortableStream;
                if (e.PropertyName == Utils.NameOf(() => a.Exception)) {
                    transmission.Status = TransmissionStatus.ABORTED;
                    transmission.FailedException = a.Exception;
                }
            };
            this.bandwidthNotify.PropertyChanged += (object sender, PropertyChangedEventArgs e) => {
                var s = sender as BandwidthNotifyingStream;
                if (e.PropertyName == Utils.NameOf(() => s.BitsPerSecond)) {
                    transmission.BitsPerSecond = s.BitsPerSecond;
                }
            };
            this.progress.PropertyChanged += (object sender, PropertyChangedEventArgs e) => {
                var p = sender as ProgressStream;
                if (e.PropertyName == Utils.NameOf(() => p.Position)) {
                    transmission.Position = p.Position;
                } else if (e.PropertyName == Utils.NameOf(() => p.Length)) {
                    transmission.Length = p.Length;
                }
            };
            transmission.PropertyChanged += (object sender, PropertyChangedEventArgs e) => {
                var t = sender as Transmission;
                if (e.PropertyName == Utils.NameOf(() => t.Status)) {
                    if (t.Status == TransmissionStatus.ABORTING) {
                        this.abort.Abort();
                        this.pause.Resume();
                    } else if (t.Status == TransmissionStatus.PAUSED) {
                        this.pause.Pause();
                    } else if (t.Status == TransmissionStatus.TRANSMITTING) {
                        this.pause.Resume();
                    }
                }
            };
            if (transmission.Status == TransmissionStatus.ABORTING || transmission.Status == TransmissionStatus.ABORTED) {
                this.abort.Abort();
            }
        }
        public void NotifyLengthChange(TransmissionType type) {
            var underTest = new Transmission(type, this.path);
            long expectedLength = 0;
            int lengthChanged = 0;
            underTest.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) => {
                if (e.PropertyName == Utils.NameOf((Transmission t) => t.Length)) {
                    Assert.That((sender as Transmission).Length, Is.EqualTo(expectedLength));
                    lengthChanged++;
                }
            };

            underTest.Length = expectedLength;
            underTest.Length = expectedLength;
            Assert.That(lengthChanged, Is.EqualTo(1));

            expectedLength = 1024;
            underTest.Length = expectedLength;
            Assert.That(lengthChanged, Is.EqualTo(2));
        }
        private void HandleUpdateTransmissionEvent(Transmission item) {
            lock (lockTransmissionItems) {
                for (int i = 0; i < TransmissionItems.Count; ++i) {
                    if (TransmissionItems[i].Path == item.Path) {
                        TransmissionItems[i] = item;
                        if (item.Done) {
                            // finished TransmissionItem should put to the tail
                            if (i < TransmissionItems.Count - 1 && !TransmissionItems[i + 1].Done) {
                                TransmissionItems[i] = TransmissionItems[i + 1];
                                TransmissionItems[i + 1] = item;
                                changeAll = true;
                                continue;
                            }
                        }

                        return;
                    }
                }
            }
        }
        /// <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;
        }
        public void SetUp() {
            this.transmission = new Transmission(TransmissionType.UPLOAD_NEW_FILE, "testfile");
            this.transmission.AddDefaultConstraints();
            this.lastChunk = 0;
            this.localContent = new byte[this.fileLength];
            if (this.localFileStream != null) {
                this.localFileStream.Dispose();
            }

            this.localFileStream = new MemoryStream(this.localContent);
            if (this.hashAlg != null) {
                this.hashAlg.Dispose();
            }

            this.hashAlg = new SHA1Managed();
            using (RandomNumberGenerator random = RandomNumberGenerator.Create()) {
                random.GetBytes(this.localContent);
            }

            if (this.remoteStream != null) {
                this.remoteStream.Dispose();
            }

            this.remoteStream = new MemoryStream();
            this.mockedDocument = new Mock<IDocument>();
            this.mockedStream = new Mock<IContentStream>();
            this.returnedObjectId = new Mock<IObjectId>();
            this.mockedStream.Setup(stream => stream.Length).Returns(this.fileLength);
            this.mockedStream.Setup(stream => stream.Stream).Returns(this.remoteStream);
            this.mockedDocument.Setup(doc => doc.Name).Returns("test.txt");
            this.mockedDocument.Setup(doc => doc.AppendContentStream(It.IsAny<IContentStream>(), It.Is<bool>(b => b == true), It.Is<bool>(b => b == true)))
                .Callback<IContentStream, bool, bool>((s, b, r) => s.Stream.CopyTo(this.remoteStream))
                    .Returns(this.returnedObjectId.Object)
                    .Callback(() => this.lastChunk++);
            this.mockedDocument.Setup(doc => doc.AppendContentStream(It.IsAny<IContentStream>(), It.Is<bool>(b => b == false), It.Is<bool>(b => b == true)))
                .Callback<IContentStream, bool, bool>((s, b, r) => s.Stream.CopyTo(this.remoteStream))
                    .Returns(this.returnedObjectId.Object);
        }
        public void SetUp() {
            this.transmission = new Transmission(TransmissionType.DOWNLOAD_NEW_FILE, "testfile");
            this.transmission.AddDefaultConstraints();
            if (this.localFileStream != null) {
                this.localFileStream.Dispose();
            }

            this.localFileStream = new MemoryStream();
            if (this.hashAlg != null) {
                this.hashAlg.Dispose();
            }

            this.hashAlg = new SHA1CryptoServiceProvider();
            this.remoteContent = new byte[this.remoteLength];
            using (var random = RandomNumberGenerator.Create()) {
                random.GetBytes(this.remoteContent);
            }

            this.mock = new Mock<IDocument>();
            this.mockedStream = new Mock<IContentStream>();

            this.localFile = Path.GetTempFileName();
        }
 /// <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);
             }
         }
 }
Example #19
0
        /// <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 ConstructorTakesTransmissionAndStream() {
     var transmission = new Transmission(TransmissionType.DOWNLOAD_MODIFIED_FILE, "path");
     using (var stream = new MemoryStream())
     using (var underTest = new TransmissionStream(stream, transmission)) {
     }
 }
 private void UpdateSizeAndPositionStatus(Transmission t) {
     string pos = t.Position != null && t.Position != t.Length ? CmisSync.Lib.Utils.FormatSize(t.Position.GetValueOrDefault()) + "/" : string.Empty;
     string size = t.Length != null ? CmisSync.Lib.Utils.FormatSize(t.Length.GetValueOrDefault()) : string.Empty;
     this.statusDetailsLabel.Markup = string.Format("<small>{0}{1}</small>", pos, size);
 }
 private void Controller_DeleteTransmissionEvent(Transmission item) {
     Dispatcher.BeginInvoke((Action)delegate {
         this.TransmissionList.Remove(item);
     });
 }
 private void HandleInsertTransmissionEvent(Transmission item) {
     lock (lockTransmissionItems) {
         TransmissionItems.Insert(0, item);
         changeAll = true;
     }
 }
        public void UpdateTableView(NSTableView tableView, Transmission item) {
            if (changeAll) {
                changeAll = false;
                BeginInvokeOnMainThread(delegate {
                    tableView.ReloadData();
                });
                return;
            }

            if (item == null) {
                return;
            }

//            lock (lockTransmissionItems) {
//                for (int i = 0; i < TransmissionItems.Count; ++i) {
//                    if (TransmissionItems[i].Path == item.Path) {
//                        BeginInvokeOnMainThread(delegate {
//                            tableView.ReloadData(new NSIndexSet(i), new NSIndexSet(0));
//                        });
//                        return;
//                    }
//                }
//            }
        }
        /// <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;
            }
        }
 private void UpdateViewProgress(TransmissionWidgetItem widget, Transmission t) {
     if (widget != null) {
         widget.progress.Hidden = t.Percent.GetValueOrDefault() == 100;
         widget.progress.DoubleValue = t.Percent.GetValueOrDefault();
         if (widget.progress.Hidden) {
             System.Drawing.SizeF size = widget.Frame.Size;
             size.Height = widget.labelName.Frame.Height + widget.labelStatus.Frame.Height;
             widget.SetFrameSize(size);
         } else {
             System.Drawing.SizeF size = widget.Frame.Size;
             size.Height = widget.labelName.Frame.Height + widget.progress.Frame.Height + widget.labelStatus.Frame.Height;
             widget.SetFrameSize(size);
         }
     }
 }
 private void UpdateWidgetStatus(TransmissionWidgetItem widget, Transmission t) {
     if (widget != null) {
         string pos = t.Position != null && t.Position != t.Length ? string.Format("{0}/", CmisSync.Lib.Utils.FormatSize(t.Position.GetValueOrDefault())) : string.Empty;
         string size = t.Length != null ? CmisSync.Lib.Utils.FormatSize(t.Length.GetValueOrDefault()) : string.Empty;
         string speed = !t.Done ? CmisSync.Lib.Utils.FormatBandwidth(t.BitsPerSecond.GetValueOrDefault()): string.Empty;
         widget.labelStatus.StringValue = string.Format("{0}{1}\t{2}", pos, size, speed);
     }
 }
Example #28
0
        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);
                            }
            }
        }
        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;
                }
            }
        }
Example #30
0
        /// <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>
        /// 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);
                }
            }
        }
        private void SaveRemotePWCDocument(IFileInfo localFile, IDocument remoteDocument, IDocument remotePWCDocument, byte[] checksum, Transmission transmissionEvent) {
            if (remotePWCDocument == null) {
                return;
            }

            var obj = new FileTransmissionObject(transmissionEvent.Type, localFile, remoteDocument) {
                ChecksumAlgorithmName = "SHA-1",
                RemoteObjectPWCId = remotePWCDocument.Id,
                LastChangeTokenPWC = remotePWCDocument.ChangeToken,
                LastChecksumPWC = checksum
            };
            this.TransmissionStorage.SaveObject(obj);
        }
 private void Controller_UpdateTransmissionEvent(Transmission item) {
     Dispatcher.BeginInvoke((Action)delegate {
         if (TransmissionList.Contains(item)) {
             ListView_SelectionChanged(this, null);
         }
     });
 }
 private void Controller_InsertTransmissionEvent(Transmission item) {
     Dispatcher.BeginInvoke((Action)delegate {
         TransmissionList.Insert(0, item);
     });
 }