Ejemplo n.º 1
0
        public override HashValue ComputeHash(long offset, long length)
        {
            MeteringStream stream;

            if (offset == 0 && length == -1 && !this.OperatingStream.CanSeek)
            {
                var retval = StandardFileHashingService.GetHashFromCache(this.OperatingNode, this.ServiceType.AlgorithmName);

                if (retval != null)
                {
                    return(retval.Value);
                }

                stream = new MeteringStream(this.OperatingStream);

                return(new HashValue(this.hashAlgorithm.ComputeHash(stream), this.ServiceType.AlgorithmName, 0, Convert.ToInt32(stream.ReadMeter.Value)));
            }
            else
            {
                if (offset == 0 && length == this.OperatingNode.Length)
                {
                    if (StandardFileHashingService.ConfigurationSection.Default.CanCacheHash(this.OperatingNode))
                    {
                        string s;

                        if ((s = Convert.ToString(this.OperatingNode.Attributes["extended:" + ServiceType.AlgorithmName])) != "")
                        {
                            return(new HashValue(TextConversion.FromHexString(s), this.ServiceType.AlgorithmName, 0, -1));
                        }
                    }
                }

                if (!this.OperatingStream.CanSeek)
                {
                    throw new NotSupportedException("ComputeHash_StreamCannotSeek");
                }

                stream = new MeteringStream(new PartialStream(this.OperatingStream, offset, length));

                return(new HashValue(this.hashAlgorithm.ComputeHash(stream), this.ServiceType.AlgorithmName, offset, Convert.ToInt64(stream.ReadMeter.Value)));
            }
        }
        public override void DoRun()
        {
            IFile  destinationTemp;
            Stream destinationTempStream;
            string sourceHash;

            try
            {
                lock (this)
                {
                    SetTransferState(TransferState.Preparing);
                }

                Action <IFile> transferAttributes = delegate(IFile dest)
                {
                    using (dest.Attributes.AquireUpdateContext())
                    {
                        foreach (string s in this.serviceType.AttributesToTransfer)
                        {
                            dest.Attributes[s] = this.source.Attributes[s];
                        }
                    }
                };

                Stream sourceStream = null;

                for (var i = 0; i < 4; i++)
                {
                    try
                    {
                        sourceStream = this.OperatingNode.GetContent().GetInputStream(FileMode.Open, FileShare.Read);

                        break;
                    }
                    catch (NodeNotFoundException)
                    {
                        throw;
                    }
                    catch (Exception)
                    {
                        if (i == 3)
                        {
                            throw;
                        }
                    }

                    ProcessTaskStateRequest();
                }

                using (sourceStream)
                {
                    var sourceHashingService = (IHashingService)this.OperatingNode.GetService(new StreamHashingServiceType(sourceStream, this.HashAlgorithmName));

                    // Compute the hash of the source file

                    SetTransferState(TransferState.Comparing);
                    ProcessTaskStateRequest();

                    sourceHash = sourceHashingService.ComputeHash().TextValue;

                    // Try to open the destination file

                    ProcessTaskStateRequest();

                    var destinationHashingService = (IHashingService)this.TargetNode.GetService(new FileHashingServiceType(this.HashAlgorithmName));

                    string destinationHash;

                    try
                    {
                        destinationHash = destinationHashingService.ComputeHash().TextValue;
                    }
                    catch (DirectoryNodeNotFoundException)
                    {
                        this.TargetNode.ParentDirectory.Create(true);

                        try
                        {
                            destinationHash = destinationHashingService.ComputeHash().TextValue;
                        }
                        catch (NodeNotFoundException)
                        {
                            destinationHash = null;
                        }
                    }
                    catch (NodeNotFoundException)
                    {
                        destinationHash = null;
                    }

                    ProcessTaskStateRequest();

                    // Source and destination are identical

                    if (sourceHash == destinationHash)
                    {
                        SetTransferState(TransferState.Transferring);

                        this.progress.RaiseValueChanged(0, GetBytesToTransfer());

                        SetTransferState(TransferState.Tidying);

                        // Transfer attributes

                        try
                        {
                            transferAttributes((IFile)this.TargetNode);
                        }
                        catch (FileNotFoundException)
                        {
                        }

                        // Done

                        SetTransferState(TransferState.Finished);
                        ProcessTaskStateRequest();

                        return;
                    }

                    // Get a temp file for the destination based on the source's hash

                    destinationTemp = ((ITempIdentityFileService)this.destination.GetService(new TempIdentityFileServiceType(sourceHash))).GetTempFile();

                    // Get the stream for the destination temp file

                    try
                    {
                        if (!destinationTemp.ParentDirectory.Exists)
                        {
                            destinationTemp.ParentDirectory.Create(true);
                        }
                    }
                    catch (IOException)
                    {
                    }

                    using (destinationTempStream = destinationTemp.GetContent().OpenStream(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
                    {
                        Action finishUp = delegate
                        {
                            SetTransferState(TransferState.Tidying);

                            destinationTempStream.Close();

                            for (int i = 0; i < 4; i++)
                            {
                                try
                                {
                                    // Save hash value
                                    StandardFileHashingService.SaveHashToCache((IFile)destinationTemp, this.HashAlgorithmName,
                                                                               sourceHash, (IFile)this.TargetNode);

                                    try
                                    {
                                        // Transfer attributes
                                        transferAttributes(destinationTemp);
                                    }
                                    catch (FileNotFoundException e)
                                    {
                                        Console.WriteLine(e);
                                    }

                                    // Move destination temp to destination
                                    destinationTemp.MoveTo(this.TargetNode, true);

                                    break;
                                }
                                catch (Exception)
                                {
                                    if (i == 3)
                                    {
                                        throw;
                                    }
                                }

                                ProcessTaskStateRequest();
                            }

                            // Done

                            SetTransferState(TransferState.Finished);
                            ProcessTaskStateRequest();
                        };

                        // Get the hash for the destination temp file

                        var destinationTempHashingService = (IHashingService)destinationTemp.GetService(new StreamHashingServiceType(destinationTempStream));

                        // If the destination temp and the source aren't the same
                        // then complete the destination temp

                        string destinationTempHash;

                        if (destinationTempStream.Length >= sourceStream.Length)
                        {
                            // Destination is longer than source but starts source (unlikely)

                            destinationTempHash = destinationTempHashingService.ComputeHash(0, sourceStream.Length).TextValue;

                            if (destinationTempHash == sourceHash)
                            {
                                if (destinationTempStream.Length != sourceStream.Length)
                                {
                                    destinationTempStream.SetLength(sourceStream.Length);
                                }

                                finishUp();

                                return;
                            }

                            destinationTempStream.SetLength(0);
                        }

                        if (destinationTempStream.Length > 0)
                        {
                            destinationTempHash = destinationTempHashingService.ComputeHash().TextValue;

                            // Destination shorter than the source but is a partial copy of source

                            sourceHash = sourceHashingService.ComputeHash(0, destinationTempStream.Length).TextValue;

                            if (sourceHash == destinationTempHash)
                            {
                                this.offset = destinationTempStream.Length;
                            }
                            else
                            {
                                this.offset = 0;
                                destinationTempStream.SetLength(0);
                            }
                        }
                        else
                        {
                            this.offset = 0;
                        }

                        this.progress.RaiseValueChanged(0, this.offset);

                        // Transfer over the remaining part needed (or everything if offset is 0)

                        this.offset = destinationTempStream.Length;

                        Stream sourcePartialStream          = new PartialStream(sourceStream, destinationTempStream.Length);
                        Stream destinationTempPartialStream = new PartialStream(destinationTempStream, destinationTempStream.Length);

                        this.copier =
                            new StreamCopier(new BufferedStream(sourcePartialStream, this.serviceType.BufferSize), destinationTempPartialStream,
                                             false, false, this.serviceType.ChunkSize);

                        this.copier.TaskStateChanged += delegate(object sender, TaskEventArgs eventArgs)
                        {
                            if (eventArgs.TaskState == TaskState.Running ||
                                eventArgs.TaskState == TaskState.Paused ||
                                eventArgs.TaskState == TaskState.Stopped)
                            {
                                SetTaskState(eventArgs.TaskState);
                            }
                        };

                        SetTransferState(TransferState.Transferring);
                        ProcessTaskStateRequest();

                        this.copier.Run();

                        if (this.copier.TaskState == TaskState.Stopped)
                        {
                            throw new StopRequestedException();
                        }

                        finishUp();
                    }
                }
            }
            catch (StopRequestedException)
            {
            }
            finally
            {
                if (this.TransferState != TransferState.Finished)
                {
                    SetTransferState(TransferState.Stopped);
                }
            }
        }