public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSession, uint bufferSize) { const int defaultMaxPendingReads = 3; // Issue #292: Avoid overlapping SSH_FXP_OPEN and SSH_FXP_LSTAT requests for the same file as this // causes a performance degradation on Sun SSH var openAsyncResult = sftpSession.BeginOpen(fileName, Flags.Read, null, null); var handle = sftpSession.EndOpen(openAsyncResult); var statAsyncResult = sftpSession.BeginLStat(fileName, null, null); long?fileSize; int maxPendingReads; var chunkSize = sftpSession.CalculateOptimalReadLength(bufferSize); // fallback to a default maximum of pending reads when remote server does not allow us to obtain // the attributes of the file try { var fileAttributes = sftpSession.EndLStat(statAsyncResult); fileSize = fileAttributes.Size; maxPendingReads = Math.Min(10, (int)Math.Ceiling((double)fileAttributes.Size / chunkSize) + 1); } catch (SshException ex) { fileSize = null; maxPendingReads = defaultMaxPendingReads; DiagnosticAbstraction.Log(string.Format("Failed to obtain size of file. Allowing maximum {0} pending reads: {1}", maxPendingReads, ex)); } return(sftpSession.CreateFileReader(handle, sftpSession, chunkSize, maxPendingReads, fileSize)); }
/// <summary> /// Initializes a new <see cref="SftpFileReader"/> instance with the specified handle, /// <see cref="ISftpSession"/> and the maximum number of pending reads. /// </summary> /// <param name="handle"></param> /// <param name="sftpSession"></param> /// <param name="chunkSize">The size of a individual read-ahead chunk.</param> /// <param name="maxPendingReads">The maximum number of pending reads.</param> /// <param name="fileSize">The size of the file, if known; otherwise, <c>null</c>.</param> public SftpFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, int maxPendingReads, long?fileSize) { _handle = handle; _sftpSession = sftpSession; _chunkSize = chunkSize; _fileSize = fileSize; _semaphore = new SemaphoreLight(maxPendingReads); _queue = new Dictionary <int, BufferedRead>(maxPendingReads); _readLock = new object(); _readAheadCompleted = new ManualResetEvent(false); _disposingWaitHandle = new ManualResetEvent(false); _waitHandles = _sftpSession.CreateWaitHandleArray(_disposingWaitHandle, _semaphore.AvailableWaitHandle); StartReadAhead(); }
/// <summary> /// Initializes a new instance of the <see cref="SftpFile"/> class. /// </summary> /// <param name="sftpSession">The SFTP session.</param> /// <param name="fullName">Full path of the directory or file.</param> /// <param name="attributes">Attributes of the directory or file.</param> /// <exception cref="ArgumentNullException"><paramref name="sftpSession"/> or <paramref name="fullName"/> is null.</exception> internal SftpFile(ISftpSession sftpSession, string fullName, SftpFileAttributes attributes) { if (sftpSession == null) throw new SshConnectionException("Client not connected."); if (attributes == null) throw new ArgumentNullException("attributes"); if (fullName == null) throw new ArgumentNullException("fullName"); _sftpSession = sftpSession; Attributes = attributes; Name = fullName.Substring(fullName.LastIndexOf('/') + 1); FullName = fullName; }
/// <summary> /// Releases the unmanaged resources used by the <see cref="T:System.IO.Stream"/> and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { base.Dispose(disposing); if (_session != null) { if (disposing) { lock (_lock) { if (_session != null) { _canRead = false; _canSeek = false; _canWrite = false; if (_handle != null) { if (_session.IsOpen) { if (_bufferOwnedByWrite) { FlushWriteBuffer(); } if (_ownsHandle) { _session.RequestClose(_handle); } } _handle = null; } _session = null; } } } } }
/// <summary> /// Initializes a new instance of the <see cref="SftpFile"/> class. /// </summary> /// <param name="sftpSession">The SFTP session.</param> /// <param name="fullName">Full path of the directory or file.</param> /// <param name="attributes">Attributes of the directory or file.</param> /// <exception cref="ArgumentNullException"><paramref name="sftpSession"/> or <paramref name="fullName"/> is null.</exception> internal SftpFile(ISftpSession sftpSession, string fullName, SftpFileAttributes attributes) { if (sftpSession == null) { throw new SshConnectionException("Client not connected."); } if (attributes == null) { throw new ArgumentNullException("attributes"); } if (fullName == null) { throw new ArgumentNullException("fullName"); } _sftpSession = sftpSession; Attributes = attributes; Name = fullName.Substring(fullName.LastIndexOf('/') + 1); FullName = fullName; }
/// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param> protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { if (_sftpSession != null) { _sftpSession.Dispose(); _sftpSession = null; } } }
/// <summary> /// Called when client is disconnecting from the server. /// </summary> protected override void OnDisconnecting() { base.OnDisconnecting(); // disconnect, dispose and dereference the SFTP session since we create a new SFTP session // on each connect if (_sftpSession != null) { _sftpSession.Disconnect(); _sftpSession.Dispose(); _sftpSession = null; } }
/// <summary> /// Called when client is connected to the server. /// </summary> protected override void OnConnected() { base.OnConnected(); _sftpSession = ServiceFactory.CreateSftpSession(Session, OperationTimeout, ConnectionInfo.Encoding); _sftpSession.Connect(); }
internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize) { if (session == null) { throw new SshConnectionException("Client not connected."); } if (path == null) { throw new ArgumentNullException("path"); } if (bufferSize <= 0) { throw new ArgumentOutOfRangeException("bufferSize"); } Timeout = TimeSpan.FromSeconds(30); Name = path; // Initialize the object state. _session = session; _canRead = (access & FileAccess.Read) != 0; _canSeek = true; _canWrite = (access & FileAccess.Write) != 0; var flags = Flags.None; switch (access) { case FileAccess.Read: flags |= Flags.Read; break; case FileAccess.Write: flags |= Flags.Write; break; case FileAccess.ReadWrite: flags |= Flags.Read; flags |= Flags.Write; break; default: throw new ArgumentOutOfRangeException("access"); } if ((access & FileAccess.Read) != 0 && mode == FileMode.Append) { throw new ArgumentException(string.Format("{0} mode can be requested only when combined with write-only access.", mode.ToString("G"))); } if ((access & FileAccess.Write) == 0) { if (mode == FileMode.Create || mode == FileMode.CreateNew || mode == FileMode.Truncate || mode == FileMode.Append) { throw new ArgumentException(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, mode, typeof(FileAccess).Name, access)); } } switch (mode) { case FileMode.Append: flags |= Flags.Append | Flags.CreateNewOrOpen; break; case FileMode.Create: _handle = _session.RequestOpen(path, flags | Flags.Truncate, true); if (_handle == null) { flags |= Flags.CreateNew; } else { flags |= Flags.Truncate; } break; case FileMode.CreateNew: flags |= Flags.CreateNew; break; case FileMode.Open: break; case FileMode.OpenOrCreate: flags |= Flags.CreateNewOrOpen; break; case FileMode.Truncate: flags |= Flags.Truncate; break; default: throw new ArgumentOutOfRangeException("mode"); } if (_handle == null) { _handle = _session.RequestOpen(path, flags); } // instead of using the specified buffer size as is, we use it to calculate a buffer size // that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ // or SSH_FXP_WRITE message _readBufferSize = (int)session.CalculateOptimalReadLength((uint)bufferSize); _writeBufferSize = (int)session.CalculateOptimalWriteLength((uint)bufferSize, _handle); if (mode == FileMode.Append) { var attributes = _session.RequestFStat(_handle, false); _position = attributes.Size; } }
internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize, bool useAsync) { // Validate the parameters. if (session == null) throw new SshConnectionException("Client not connected."); if (path == null) { throw new ArgumentNullException("path"); } if (bufferSize <= 0) { throw new ArgumentOutOfRangeException("bufferSize"); } if (access < FileAccess.Read || access > FileAccess.ReadWrite) { throw new ArgumentOutOfRangeException("access"); } if (mode < FileMode.CreateNew || mode > FileMode.Append) { throw new ArgumentOutOfRangeException("mode"); } Timeout = TimeSpan.FromSeconds(30); Name = path; // Initialize the object state. _session = session; _ownsHandle = true; _isAsync = useAsync; _bufferPosition = 0; _bufferLen = 0; _bufferOwnedByWrite = false; _canRead = ((access & FileAccess.Read) != 0); _canSeek = true; _canWrite = ((access & FileAccess.Write) != 0); _position = 0; _serverFilePosition = 0; var flags = Flags.None; switch (access) { case FileAccess.Read: flags |= Flags.Read; break; case FileAccess.Write: flags |= Flags.Write; break; case FileAccess.ReadWrite: flags |= Flags.Read; flags |= Flags.Write; break; } switch (mode) { case FileMode.Append: flags |= Flags.Append; break; case FileMode.Create: _handle = _session.RequestOpen(path, flags | Flags.Truncate, true); if (_handle == null) { flags |= Flags.CreateNew; } else { flags |= Flags.Truncate; } break; case FileMode.CreateNew: flags |= Flags.CreateNew; break; case FileMode.Open: break; case FileMode.OpenOrCreate: flags |= Flags.CreateNewOrOpen; break; case FileMode.Truncate: flags |= Flags.Truncate; break; } if (_handle == null) _handle = _session.RequestOpen(path, flags); _attributes = _session.RequestFStat(_handle); // instead of using the specified buffer size as is, we use it to calculate a buffer size // that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ // or SSH_FXP_WRITE message _readBufferSize = (int)session.CalculateOptimalReadLength((uint)bufferSize); _readBuffer = new byte[_readBufferSize]; _writeBufferSize = (int)session.CalculateOptimalWriteLength((uint)bufferSize, _handle); _writeBuffer = new byte[_writeBufferSize]; if (mode == FileMode.Append) { _position = _attributes.Size; _serverFilePosition = (ulong)_attributes.Size; } }
internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize) : this(session, path, mode, access, bufferSize, false) { }
internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize, bool useAsync) { // Validate the parameters. if (session == null) { throw new SshConnectionException("Client not connected."); } if (path == null) { throw new ArgumentNullException("path"); } if (bufferSize <= 0) { throw new ArgumentOutOfRangeException("bufferSize"); } if (access < FileAccess.Read || access > FileAccess.ReadWrite) { throw new ArgumentOutOfRangeException("access"); } if (mode < FileMode.CreateNew || mode > FileMode.Append) { throw new ArgumentOutOfRangeException("mode"); } Timeout = TimeSpan.FromSeconds(30); Name = path; // Initialize the object state. _session = session; _ownsHandle = true; _isAsync = useAsync; _bufferPosition = 0; _bufferLen = 0; _bufferOwnedByWrite = false; _canRead = ((access & FileAccess.Read) != 0); _canSeek = true; _canWrite = ((access & FileAccess.Write) != 0); _position = 0; _serverFilePosition = 0; var flags = Flags.None; switch (access) { case FileAccess.Read: flags |= Flags.Read; break; case FileAccess.Write: flags |= Flags.Write; break; case FileAccess.ReadWrite: flags |= Flags.Read; flags |= Flags.Write; break; } switch (mode) { case FileMode.Append: flags |= Flags.Append; break; case FileMode.Create: _handle = _session.RequestOpen(path, flags | Flags.Truncate, true); if (_handle == null) { flags |= Flags.CreateNew; } else { flags |= Flags.Truncate; } break; case FileMode.CreateNew: flags |= Flags.CreateNew; break; case FileMode.Open: break; case FileMode.OpenOrCreate: flags |= Flags.CreateNewOrOpen; break; case FileMode.Truncate: flags |= Flags.Truncate; break; } if (_handle == null) { _handle = _session.RequestOpen(path, flags); } _attributes = _session.RequestFStat(_handle); _readBufferSize = (int)session.CalculateOptimalReadLength((uint)bufferSize); _readBuffer = new byte[_readBufferSize]; _writeBufferSize = (int)session.CalculateOptimalWriteLength((uint)bufferSize, _handle); _writeBuffer = new byte[_writeBufferSize]; if (mode == FileMode.Append) { _position = _attributes.Size; _serverFilePosition = (ulong)_attributes.Size; } }
/// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { var sftpSession = _sftpSession; if (sftpSession != null) { _sftpSession = null; sftpSession.Dispose(); } } }
internal SftpContextStream(ISftpSession session, string path, FileMode mode, FileAccess access, SftpFileAttributes attributes) { Flags flags = Flags.None; switch (access) { case FileAccess.Read: flags = Flags.Read; break; case FileAccess.Write: flags = Flags.Write; break; case FileAccess.ReadWrite: flags = Flags.Read | Flags.Write; break; } switch (mode) { case FileMode.Append: flags |= Flags.Append; break; case FileMode.Create: if (attributes == null) { flags |= Flags.CreateNew; } else { flags |= Flags.Truncate; } break; case FileMode.CreateNew: flags |= Flags.CreateNew; break; case FileMode.Open: break; case FileMode.OpenOrCreate: flags |= Flags.CreateNewOrOpen; break; case FileMode.Truncate: flags |= Flags.Truncate; break; } _session = session; _handle = _session.RequestOpen(path, flags); _attributes = attributes ?? _session.RequestFStat(_handle); this.optimalReadRequestSize = checked ((int)this._session.CalculateOptimalReadLength(uint.MaxValue)); this.readBuffer = new byte[this.optimalReadRequestSize]; this.readBufferCount = 0; WRITE_BUFFER_SIZE = (int)_session.CalculateOptimalWriteLength(65536, _handle); if (access.HasFlag(FileAccess.Write)) { _writeBuffer = new byte[WRITE_BUFFER_SIZE]; _writeMode = true; } _position = mode != FileMode.Append ? 0 : _attributes.Size; }