Skip to content

Commit e724921

Browse files
committed
dedup SftpFileStream init logic
1 parent fb80bc6 commit e724921

File tree

3 files changed

+106
-174
lines changed

3 files changed

+106
-174
lines changed

src/Renci.SshNet/Sftp/SftpFileStream.cs

Lines changed: 40 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Diagnostics.CodeAnalysis;
34
using System.Globalization;
45
using 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>

src/Renci.SshNet/SftpClient.cs

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ public StreamWriter AppendText(string path, Encoding encoding)
13961396
CheckDisposed();
13971397
ThrowHelper.ThrowIfNull(encoding);
13981398

1399-
return new StreamWriter(new SftpFileStream(_sftpSession, path, FileMode.Append, FileAccess.Write, (int)_bufferSize), encoding);
1399+
return new StreamWriter(Open(path, FileMode.Append, FileAccess.Write), encoding);
14001400
}
14011401

14021402
/// <summary>
@@ -1415,9 +1415,7 @@ public StreamWriter AppendText(string path, Encoding encoding)
14151415
/// </remarks>
14161416
public SftpFileStream Create(string path)
14171417
{
1418-
CheckDisposed();
1419-
1420-
return new SftpFileStream(_sftpSession, path, FileMode.Create, FileAccess.ReadWrite, (int)_bufferSize);
1418+
return Create(path, (int)_bufferSize);
14211419
}
14221420

14231421
/// <summary>
@@ -1439,7 +1437,7 @@ public SftpFileStream Create(string path, int bufferSize)
14391437
{
14401438
CheckDisposed();
14411439

1442-
return new SftpFileStream(_sftpSession, path, FileMode.Create, FileAccess.ReadWrite, bufferSize);
1440+
return SftpFileStream.Open(_sftpSession, path, FileMode.Create, FileAccess.ReadWrite, bufferSize);
14431441
}
14441442

14451443
/// <summary>
@@ -1615,7 +1613,7 @@ public SftpFileStream Open(string path, FileMode mode, FileAccess access)
16151613
{
16161614
CheckDisposed();
16171615

1618-
return new SftpFileStream(_sftpSession, path, mode, access, (int)_bufferSize);
1616+
return SftpFileStream.Open(_sftpSession, path, mode, access, (int)_bufferSize);
16191617
}
16201618

16211619
/// <summary>
@@ -1635,14 +1633,6 @@ public SftpFileStream Open(string path, FileMode mode, FileAccess access)
16351633
public Task<SftpFileStream> OpenAsync(string path, FileMode mode, FileAccess access, CancellationToken cancellationToken)
16361634
{
16371635
CheckDisposed();
1638-
ThrowHelper.ThrowIfNull(path);
1639-
1640-
if (_sftpSession is null)
1641-
{
1642-
throw new SshConnectionException("Client not connected.");
1643-
}
1644-
1645-
cancellationToken.ThrowIfCancellationRequested();
16461636

16471637
return SftpFileStream.OpenAsync(_sftpSession, path, mode, access, (int)_bufferSize, cancellationToken);
16481638
}
@@ -1692,9 +1682,7 @@ public StreamReader OpenText(string path)
16921682
/// </remarks>
16931683
public SftpFileStream OpenWrite(string path)
16941684
{
1695-
CheckDisposed();
1696-
1697-
return new SftpFileStream(_sftpSession, path, FileMode.OpenOrCreate, FileAccess.Write, (int)_bufferSize);
1685+
return Open(path, FileMode.OpenOrCreate, FileAccess.Write);
16981686
}
16991687

17001688
/// <summary>

0 commit comments

Comments
 (0)