private void InternalUploadFile(Stream input, string path, Flags flags, SftpUploadAsyncResult asyncResult, Action<ulong> uploadCallback)
{
if (input == null)
throw new ArgumentNullException("input");
if (path.IsNullOrWhiteSpace())
throw new ArgumentException("path");
if (_sftpSession == null)
throw new SshConnectionException("Client not connected.");
var fullPath = _sftpSession.GetCanonicalPath(path);
var handle = _sftpSession.RequestOpen(fullPath, flags);
ulong offset = 0;
// create buffer of optimal length
var buffer = new byte[_sftpSession.CalculateOptimalWriteLength(_bufferSize, handle)];
var bytesRead = input.Read(buffer, 0, buffer.Length);
var expectedResponses = 0;
var responseReceivedWaitHandle = new AutoResetEvent(false);
do
{
// Cancel upload
if (asyncResult != null && asyncResult.IsUploadCanceled)
break;
if (bytesRead > 0)
{
var writtenBytes = offset + (ulong) bytesRead;
_sftpSession.RequestWrite(handle, offset, buffer, 0, bytesRead, null, s =>
{
if (s.StatusCode == StatusCodes.Ok)
{
Interlocked.Decrement(ref expectedResponses);
responseReceivedWaitHandle.Set();
// Call callback to report number of bytes written
if (uploadCallback != null)
{
// Execute callback on different thread
ThreadAbstraction.ExecuteThread(() => uploadCallback(writtenBytes));
}
}
});
Interlocked.Increment(ref expectedResponses);
offset += (ulong) bytesRead;
bytesRead = input.Read(buffer, 0, buffer.Length);
}
else if (expectedResponses > 0)
{
// Wait for expectedResponses to change
_sftpSession.WaitOnHandle(responseReceivedWaitHandle, OperationTimeout);
}
} while (expectedResponses > 0 || bytesRead > 0);
_sftpSession.RequestClose(handle);
}