Forráskód Böngészése

Refactor RequestWrite method to write one block at a time
Add request synchronization for SftpWrite operation which should resolve issue of wrong or incomplete data to be written
Restrict SftpFileStream buffersize to maximum of 16KB.

olegkap_cp 13 éve
szülő
commit
6852e6d2a9

+ 1 - 1
Renci.SshClient/Renci.SshNet/Sftp/SftpFileStream.cs

@@ -212,7 +212,7 @@ namespace Renci.SshNet.Sftp
             {
                 throw new ArgumentNullException("path");
             }
-            if (bufferSize <= 0)
+            if (bufferSize <= 0 || bufferSize > 16 * 1024)
             {
                 throw new ArgumentOutOfRangeException("bufferSize");
             }

+ 21 - 52
Renci.SshClient/Renci.SshNet/Sftp/SftpSession.cs

@@ -107,7 +107,7 @@ namespace Renci.SshNet.Sftp
 
             if (realPathFiles != null)
             {
-                canonizedPath = realPathFiles.First().Key;                
+                canonizedPath = realPathFiles.First().Key;
             }
 
             if (!string.IsNullOrEmpty(canonizedPath))
@@ -369,62 +369,31 @@ namespace Renci.SshNet.Sftp
         /// <param name="offset">The offset.</param>
         /// <param name="data">The data to send.</param>
         /// <param name="wait">The wait event handle if needed.</param>
-        internal void RequestWrite(byte[] handle, UInt64 offset, byte[] data, EventWaitHandle wait)
+        internal void RequestWrite(byte[] handle, UInt64 offset, byte[] data, EventWaitHandle wait, Action<SftpStatusResponse> writeCompleted = null)
         {
-            var maximumDataSize = 1024 * 16;
-
-            if (data.Length < maximumDataSize + 1)
-            {
-                var request = new SftpWriteRequest(this.NextRequestId, handle, offset, data,
-                    (response) =>
-                    {
-                        if (response.StatusCode == StatusCodes.Ok)
-                        {
-                            if (wait != null)
-                                wait.Set();
-                        }
-                        else
-                        {
-                            this.ThrowSftpException(response);
-                        }
-                    });
-
-                this.SendRequest(request);
-
-                if (wait != null)
-                    this.WaitHandle(wait, this._operationTimeout);
-            }
-            else
-            {
-                var block = data.Length / maximumDataSize + 1;
-
-                for (int i = 0; i < block; i++)
+            var request = new SftpWriteRequest(this.NextRequestId, handle, offset, data,
+                (response) =>
                 {
-                    var blockBufferSize = Math.Min(data.Length - maximumDataSize * i, maximumDataSize);
-                    var blockBuffer = new byte[blockBufferSize];
-
-                    Buffer.BlockCopy(data, i * maximumDataSize, blockBuffer, 0, blockBufferSize);
+                    if (writeCompleted != null)
+                    {
+                        writeCompleted(response);
+                    }
 
-                    var request = new SftpWriteRequest(this.NextRequestId, handle, offset + (ulong)(i * maximumDataSize), blockBuffer,
-                        (response) =>
-                        {
-                            if (response.StatusCode == StatusCodes.Ok)
-                            {
-                                if (wait != null)
-                                    wait.Set();
-                            }
-                            else
-                            {
-                                this.ThrowSftpException(response);
-                            }
-                        });
+                    if (response.StatusCode == StatusCodes.Ok)
+                    {
+                        if (wait != null)
+                            wait.Set();
+                    }
+                    else
+                    {
+                        this.ThrowSftpException(response);
+                    }
+                });
 
-                    this.SendRequest(request);
+            this.SendRequest(request);
 
-                    if (wait != null)
-                        this.WaitHandle(wait, this._operationTimeout);
-                }
-            }
+            if (wait != null)
+                this.WaitHandle(wait, this._operationTimeout);
         }
 
         /// <summary>

+ 45 - 2
Renci.SshClient/Renci.SshNet/SftpClient.cs

@@ -1316,6 +1316,9 @@ namespace Renci.SshNet
 
             var uploadCompleted = false;
 
+            var expectedResponses = 0;
+            var expectedResponsesLock = new object();
+
             do
             {
                 var bytesRead = input.Read(buffer, 0, buffer.Length);
@@ -1326,13 +1329,45 @@ namespace Renci.SshNet
                     Buffer.BlockCopy(buffer, 0, data, 0, bytesRead);
                     using (var wait = new AutoResetEvent(false))
                     {
-                        this._sftpSession.RequestWrite(handle, offset, data, wait);
+                        this._sftpSession.RequestWrite(handle, offset, data, wait, (s) =>
+                        {
+                            if (s.StatusCode == StatusCodes.Ok)
+                            {
+                                lock (expectedResponsesLock)
+                                {
+                                    expectedResponses--;
+                                    System.Diagnostics.Debug.WriteLine(expectedResponses);
+                                    Monitor.Pulse(expectedResponsesLock);
+                                }
+                            }
+                        });
+                        lock (expectedResponsesLock)
+                        {
+                            expectedResponses++;
+                            System.Diagnostics.Debug.WriteLine(expectedResponses);
+                        }
                     }
                     uploadCompleted = true;
                 }
                 else
                 {
-                    this._sftpSession.RequestWrite(handle, offset, buffer, null);
+                    this._sftpSession.RequestWrite(handle, offset, buffer, null, (s) =>
+                    {
+                        if (s.StatusCode == StatusCodes.Ok)
+                        {
+                            lock (expectedResponsesLock)
+                            {
+                                expectedResponses--;
+                                System.Diagnostics.Debug.WriteLine(expectedResponses);
+                                Monitor.Pulse(expectedResponsesLock);
+                            }
+                        }
+                    });
+                    lock (expectedResponsesLock)
+                    {
+                        expectedResponses++;
+                        System.Diagnostics.Debug.WriteLine(expectedResponses);
+                    }
                 }
 
                 offset += (uint)bytesRead;
@@ -1345,6 +1380,14 @@ namespace Renci.SshNet
 
             } while (!uploadCompleted);
 
+            while (expectedResponses > 0)
+            {
+                lock (expectedResponsesLock)
+                {
+                    Monitor.Wait(expectedResponsesLock);
+                }
+            }
+
             this._sftpSession.RequestClose(handle);
         }