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);
                    }
        }
Пример #3
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='status'>
        ///  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">
        /// Contains the last successful remote document state. This is needed for continue a failed upload.
        /// </exception>
        public override IDocument UploadFile(IDocument remoteDocument, Stream localFileStream, FileTransmissionEvent status, HashAlgorithm hashAlg, bool overwrite = true)
        {
            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 (NonClosingHashStream hashstream = new NonClosingHashStream(localFileStream, hashAlg, CryptoStreamMode.Read))
                    using (ChunkedStream chunkstream = new ChunkedStream(hashstream, this.ChunkSize))
                        using (OffsetStream offsetstream = new OffsetStream(chunkstream, offset))
                            using (ProgressStream progressstream = new ProgressStream(offsetstream, status))
                            {
                                status.Status.Length         = localFileStream.Length;
                                status.Status.ActualPosition = 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 = progressstream;
                                try {
                                    if (isFirstChunk && result.ContentStreamId != null && overwrite)
                                    {
                                        result.DeleteContentStream(true);
                                    }

                                    result.AppendContentStream(contentStream, isLastChunk, true);
                                } catch (Exception e) {
                                    throw new UploadFailedException(e, result);
                                }
                            }
            }

            hashAlg.TransformFinalBlock(new byte[0], 0, 0);
            return(result);
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
 public void ConstructorFailsOnStreamIsNull()
 {
     using (var stream = new NonClosingHashStream(null, new Mock <HashAlgorithm>().Object, CryptoStreamMode.Write))
     {
     }
 }
Пример #6
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 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);
            }
        }