11using System ;
2+ using System . Diagnostics ;
23using System . Diagnostics . CodeAnalysis ;
34using System . Globalization ;
45using System . IO ;
@@ -191,7 +192,7 @@ public TimeSpan Timeout
191192 }
192193 }
193194
194- private SftpFileStream ( ISftpSession session , string path , FileAccess access , int bufferSize , byte [ ] handle , long position )
195+ private SftpFileStream ( ISftpSession session , string path , FileAccess access , int readBufferSize , int writeBufferSize , byte [ ] handle , long position )
195196 {
196197 Timeout = TimeSpan . FromSeconds ( 30 ) ;
197198 Name = path ;
@@ -202,25 +203,24 @@ private SftpFileStream(ISftpSession session, string path, FileAccess access, int
202203 _canWrite = ( access & FileAccess . Write ) == FileAccess . Write ;
203204
204205 _handle = handle ;
206+ _readBufferSize = readBufferSize ;
207+ _writeBufferSize = writeBufferSize ;
208+ _position = position ;
209+ }
205210
206- /*
207- * Instead of using the specified buffer size as is, we use it to calculate a buffer size
208- * that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ
209- * or SSH_FXP_WRITE message.
210- */
211-
212- _readBufferSize = ( int ) session . CalculateOptimalReadLength ( ( uint ) bufferSize ) ;
213- _writeBufferSize = ( int ) session . CalculateOptimalWriteLength ( ( uint ) bufferSize , _handle ) ;
211+ internal static SftpFileStream Open ( ISftpSession session , string path , FileMode mode , FileAccess access , int bufferSize )
212+ {
213+ return Open ( session , path , mode , access , bufferSize , isAsync : false , CancellationToken . None ) . GetAwaiter ( ) . GetResult ( ) ;
214+ }
214215
215- _position = position ;
216+ internal static Task < SftpFileStream > OpenAsync ( ISftpSession session , string path , FileMode mode , FileAccess access , int bufferSize , CancellationToken cancellationToken )
217+ {
218+ return Open ( session , path , mode , access , bufferSize , isAsync : true , cancellationToken ) ;
216219 }
217220
218- internal SftpFileStream ( ISftpSession session , string path , FileMode mode , FileAccess access , int bufferSize )
221+ private static async Task < SftpFileStream > Open ( ISftpSession session , string path , FileMode mode , FileAccess access , int bufferSize , bool isAsync , CancellationToken cancellationToken )
219222 {
220- if ( session is null )
221- {
222- throw new SshConnectionException ( "Client not connected." ) ;
223- }
223+ Debug . Assert ( isAsync || cancellationToken == default ) ;
224224
225225 ThrowHelper . ThrowIfNull ( path ) ;
226226
@@ -229,14 +229,10 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc
229229 throw new ArgumentOutOfRangeException ( nameof ( bufferSize ) , "Cannot be less than or equal to zero." ) ;
230230 }
231231
232- Timeout = TimeSpan . FromSeconds ( 30 ) ;
233- Name = path ;
234-
235- // Initialize the object state.
236- _session = session ;
237- _canRead = ( access & FileAccess . Read ) == FileAccess . Read ;
238- _canSeek = true ;
239- _canWrite = ( access & FileAccess . Write ) == FileAccess . Write ;
232+ if ( session is null )
233+ {
234+ throw new SshConnectionException ( "Client not connected." ) ;
235+ }
240236
241237 var flags = Flags . None ;
242238
@@ -284,16 +280,7 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc
284280 flags |= Flags . Append | Flags . CreateNewOrOpen ;
285281 break ;
286282 case FileMode . Create :
287- _handle = _session . RequestOpen ( path , flags | Flags . Truncate , nullOnError : true ) ;
288- if ( _handle is null )
289- {
290- flags |= Flags . CreateNew ;
291- }
292- else
293- {
294- flags |= Flags . Truncate ;
295- }
296-
283+ flags |= Flags . CreateNewOrOpen | Flags . Truncate ;
297284 break ;
298285 case FileMode . CreateNew :
299286 flags |= Flags . CreateNew ;
@@ -310,127 +297,44 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc
310297 throw new ArgumentOutOfRangeException ( nameof ( mode ) ) ;
311298 }
312299
313- _handle ??= _session . RequestOpen ( path , flags ) ;
300+ byte [ ] handle ;
301+
302+ if ( isAsync )
303+ {
304+ handle = await session . RequestOpenAsync ( path , flags , cancellationToken ) . ConfigureAwait ( false ) ;
305+ }
306+ else
307+ {
308+ handle = session . RequestOpen ( path , flags ) ;
309+ }
314310
315311 /*
316312 * Instead of using the specified buffer size as is, we use it to calculate a buffer size
317313 * that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ
318314 * or SSH_FXP_WRITE message.
319315 */
320316
321- _readBufferSize = ( int ) session . CalculateOptimalReadLength ( ( uint ) bufferSize ) ;
322- _writeBufferSize = ( int ) session . CalculateOptimalWriteLength ( ( uint ) bufferSize , _handle ) ;
317+ var readBufferSize = ( int ) session . CalculateOptimalReadLength ( ( uint ) bufferSize ) ;
318+ var writeBufferSize = ( int ) session . CalculateOptimalWriteLength ( ( uint ) bufferSize , handle ) ;
323319
320+ long position = 0 ;
324321 if ( mode == FileMode . Append )
325322 {
326- var attributes = _session . RequestFStat ( _handle , nullOnError : false ) ;
327- _position = attributes . Size ;
328- }
329- }
330-
331- internal static async Task < SftpFileStream > OpenAsync ( ISftpSession session , string path , FileMode mode , FileAccess access , int bufferSize , CancellationToken cancellationToken )
332- {
333- if ( session is null )
334- {
335- throw new SshConnectionException ( "Client not connected." ) ;
336- }
337-
338- ThrowHelper . ThrowIfNull ( path ) ;
339-
340- if ( bufferSize <= 0 )
341- {
342- throw new ArgumentOutOfRangeException ( nameof ( bufferSize ) , "Cannot be less than or equal to zero." ) ;
343- }
344-
345- var flags = Flags . None ;
346-
347- switch ( access )
348- {
349- case FileAccess . Read :
350- flags |= Flags . Read ;
351- break ;
352- case FileAccess . Write :
353- flags |= Flags . Write ;
354- break ;
355- case FileAccess . ReadWrite :
356- flags |= Flags . Read ;
357- flags |= Flags . Write ;
358- break ;
359- default :
360- throw new ArgumentOutOfRangeException ( nameof ( access ) ) ;
361- }
362-
363- if ( ( access & FileAccess . Read ) == FileAccess . Read && mode == FileMode . Append )
364- {
365- throw new ArgumentException ( string . Format ( CultureInfo . InvariantCulture ,
366- "{0} mode can be requested only when combined with write-only access." ,
367- mode . ToString ( "G" ) ) ,
368- nameof ( mode ) ) ;
369- }
323+ SftpFileAttributes attributes ;
370324
371- if ( ( access & FileAccess . Write ) != FileAccess . Write )
372- {
373- if ( mode is FileMode . Create or FileMode . CreateNew or FileMode . Truncate or FileMode . Append )
325+ if ( isAsync )
374326 {
375- throw new ArgumentException ( string . Format ( CultureInfo . InvariantCulture ,
376- "Combining {0}: {1} with {2}: {3} is invalid." ,
377- nameof ( FileMode ) ,
378- mode ,
379- nameof ( FileAccess ) ,
380- access ) ,
381- nameof ( mode ) ) ;
327+ attributes = await session . RequestFStatAsync ( handle , cancellationToken ) . ConfigureAwait ( false ) ;
382328 }
383- }
384-
385- switch ( mode )
386- {
387- case FileMode . Append :
388- flags |= Flags . Append | Flags . CreateNewOrOpen ;
389- break ;
390- case FileMode . Create :
391- flags |= Flags . CreateNewOrOpen | Flags . Truncate ;
392- break ;
393- case FileMode . CreateNew :
394- flags |= Flags . CreateNew ;
395- break ;
396- case FileMode . Open :
397- break ;
398- case FileMode . OpenOrCreate :
399- flags |= Flags . CreateNewOrOpen ;
400- break ;
401- case FileMode . Truncate :
402- flags |= Flags . Truncate ;
403- break ;
404- default :
405- throw new ArgumentOutOfRangeException ( nameof ( mode ) ) ;
406- }
407-
408- var handle = await session . RequestOpenAsync ( path , flags , cancellationToken ) . ConfigureAwait ( false ) ;
409-
410- long position = 0 ;
411- if ( mode == FileMode . Append )
412- {
413- try
329+ else
414330 {
415- var attributes = await session . RequestFStatAsync ( handle , cancellationToken ) . ConfigureAwait ( false ) ;
416- position = attributes . Size ;
331+ attributes = session . RequestFStat ( handle , nullOnError : false ) ;
417332 }
418- catch
419- {
420- try
421- {
422- await session . RequestCloseAsync ( handle , cancellationToken ) . ConfigureAwait ( false ) ;
423- }
424- catch
425- {
426- // The original exception is presumably more informative, so we just ignore this one.
427- }
428333
429- throw ;
430- }
334+ position = attributes . Size ;
431335 }
432336
433- return new SftpFileStream ( session , path , access , bufferSize , handle , position ) ;
337+ return new SftpFileStream ( session , path , access , readBufferSize , writeBufferSize , handle , position ) ;
434338 }
435339
436340 /// <summary>
0 commit comments