private void InternalUploadFile(Stream input, string path, SftpUploadAsyncResult asynchResult, Flags flags) { if (input == null) throw new ArgumentNullException("input"); if (path.IsNullOrWhiteSpace()) throw new ArgumentException("path"); // Ensure that connection is established. this.EnsureConnection(); var fullPath = this._sftpSession.GetCanonicalPath(path); var handle = this._sftpSession.RequestOpen(fullPath, flags); ulong offset = 0; var buffer = new byte[this.BufferSize]; var uploadCompleted = false; do { var bytesRead = input.Read(buffer, 0, buffer.Length); if (bytesRead < this.BufferSize) { var data = new byte[bytesRead]; Buffer.BlockCopy(buffer, 0, data, 0, bytesRead); using (var wait = new AutoResetEvent(false)) { this._sftpSession.RequestWrite(handle, offset, data, wait); } uploadCompleted = true; } else { this._sftpSession.RequestWrite(handle, offset, buffer, null); } offset += (uint)bytesRead; // Call callback to report number of bytes read if (asynchResult != null) { asynchResult.Update(offset); } } while (!uploadCompleted); this._sftpSession.RequestClose(handle); }
/// <summary> /// Begins an asynchronous uploading the steam into remote file. /// </summary> /// <param name="input">Data input stream.</param> /// <param name="path">Remote file path.</param> /// <param name="canOverride">if set to <c>true</c> then existing file will be overwritten.</param> /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</param> /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests.</param> /// <param name="uploadCallback">The upload callback.</param> /// <returns> /// An <see cref="IAsyncResult" /> that references the asynchronous operation. /// </returns> /// <exception cref="ArgumentNullException"><paramref name="input" /> is <b>null</b>.</exception> /// <exception cref="ArgumentException"><paramref name="path" /> is <b>null</b> or contains whitespace characters.</exception> /// <exception cref="SshConnectionException">Client is not connected.</exception> /// <exception cref="SftpPermissionDeniedException">Permission to list the contents of the directory was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception> /// <exception cref="SshException">A SSH error where <see cref="P:System.Exception.Message" /> is the message from the remote host.</exception> /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception> /// <remarks> /// Method calls made by this method to <paramref name="input" />, may under certain conditions result in exceptions thrown by the stream. /// </remarks> public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, AsyncCallback asyncCallback, object state, Action<ulong> uploadCallback = null) { CheckDisposed(); if (input == null) throw new ArgumentNullException("input"); if (path.IsNullOrWhiteSpace()) throw new ArgumentException("path"); var flags = Flags.Write | Flags.Truncate; if (canOverride) flags |= Flags.CreateNewOrOpen; else flags |= Flags.CreateNew; var asyncResult = new SftpUploadAsyncResult(asyncCallback, state); ExecuteThread(() => { try { InternalUploadFile(input, path, flags, asyncResult, offset => { asyncResult.Update(offset); if (uploadCallback != null) { uploadCallback(offset); } }); asyncResult.SetAsCompleted(null, false); } catch (Exception exp) { asyncResult.SetAsCompleted(exp, false); } }); return asyncResult; }