Skip to content

Commit cd9ec8f

Browse files
authored
Add SftpException and SftpPathNotFoundException.Path (#1716)
This adds an SftpException which sits between the existing SftpPathNotFoundException/ SftpPermissionDeniedException and SshException, and which contains the response code from the SSH_FXP_STATUS packet, along with a default message if one was not provided. SftpPathNotFoundException also gains a Path property which is populated in cases where it makes sense.
1 parent dccdedc commit cd9ec8f

File tree

18 files changed

+477
-391
lines changed

18 files changed

+477
-391
lines changed
Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
using System;
2-
#if NETFRAMEWORK
3-
using System.Runtime.Serialization;
4-
#endif // NETFRAMEWORK
1+
#nullable enable
2+
using System;
53

64
namespace Renci.SshNet.Common
75
{
@@ -10,7 +8,7 @@ namespace Renci.SshNet.Common
108
/// </summary>
119
#if NETFRAMEWORK
1210
[Serializable]
13-
#endif // NETFRAMEWORK
11+
#endif
1412
public class NetConfServerException : SshException
1513
{
1614
/// <summary>
@@ -23,34 +21,27 @@ public NetConfServerException()
2321
/// <summary>
2422
/// Initializes a new instance of the <see cref="NetConfServerException"/> class.
2523
/// </summary>
26-
/// <param name="message">The message.</param>
27-
public NetConfServerException(string message)
24+
/// <inheritdoc cref="Exception(string)" path="/param"/>
25+
public NetConfServerException(string? message)
2826
: base(message)
2927
{
3028
}
3129

3230
/// <summary>
3331
/// Initializes a new instance of the <see cref="NetConfServerException"/> class.
3432
/// </summary>
35-
/// <param name="message">The message.</param>
36-
/// <param name="innerException">The inner exception.</param>
37-
public NetConfServerException(string message, Exception innerException)
33+
/// <inheritdoc cref="Exception(string, Exception)" path="/param"/>
34+
public NetConfServerException(string? message, Exception? innerException)
3835
: base(message, innerException)
3936
{
4037
}
4138

4239
#if NETFRAMEWORK
43-
/// <summary>
44-
/// Initializes a new instance of the <see cref="NetConfServerException"/> class.
45-
/// </summary>
46-
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
47-
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
48-
/// <exception cref="ArgumentNullException">The <paramref name="info"/> parameter is <see langword="null"/>.</exception>
49-
/// <exception cref="SerializationException">The class name is <see langword="null"/> or <see cref="Exception.HResult"/> is zero (0). </exception>
50-
protected NetConfServerException(SerializationInfo info, StreamingContext context)
40+
/// <inheritdoc/>
41+
protected NetConfServerException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
5142
: base(info, context)
5243
{
5344
}
54-
#endif // NETFRAMEWORK
45+
#endif
5546
}
5647
}
Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
using System;
2-
#if NETFRAMEWORK
3-
using System.Runtime.Serialization;
4-
#endif // NETFRAMEWORK
1+
#nullable enable
2+
using System;
53

64
namespace Renci.SshNet.Common
75
{
@@ -10,7 +8,7 @@ namespace Renci.SshNet.Common
108
/// </summary>
119
#if NETFRAMEWORK
1210
[Serializable]
13-
#endif // NETFRAMEWORK
11+
#endif
1412
public class ProxyException : SshException
1513
{
1614
/// <summary>
@@ -23,34 +21,27 @@ public ProxyException()
2321
/// <summary>
2422
/// Initializes a new instance of the <see cref="ProxyException"/> class.
2523
/// </summary>
26-
/// <param name="message">The message.</param>
27-
public ProxyException(string message)
24+
/// <inheritdoc cref="Exception(string)" path="/param"/>
25+
public ProxyException(string? message)
2826
: base(message)
2927
{
3028
}
3129

3230
/// <summary>
3331
/// Initializes a new instance of the <see cref="ProxyException"/> class.
3432
/// </summary>
35-
/// <param name="message">The message.</param>
36-
/// <param name="innerException">The inner exception.</param>
37-
public ProxyException(string message, Exception innerException)
33+
/// <inheritdoc cref="Exception(string, Exception)" path="/param"/>
34+
public ProxyException(string? message, Exception? innerException)
3835
: base(message, innerException)
3936
{
4037
}
4138

4239
#if NETFRAMEWORK
43-
/// <summary>
44-
/// Initializes a new instance of the <see cref="ProxyException"/> class.
45-
/// </summary>
46-
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
47-
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
48-
/// <exception cref="ArgumentNullException">The <paramref name="info"/> parameter is <see langword="null"/>.</exception>
49-
/// <exception cref="SerializationException">The class name is <see langword="null"/> or <see cref="Exception.HResult"/> is zero (0).</exception>
50-
protected ProxyException(SerializationInfo info, StreamingContext context)
40+
/// <inheritdoc/>
41+
protected ProxyException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
5142
: base(info, context)
5243
{
5344
}
54-
#endif // NETFRAMEWORK
45+
#endif
5546
}
5647
}
Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
using System;
2-
#if NETFRAMEWORK
3-
using System.Runtime.Serialization;
4-
#endif // NETFRAMEWORK
1+
#nullable enable
2+
using System;
53

64
namespace Renci.SshNet.Common
75
{
86
/// <summary>
9-
/// The exception that is thrown when SCP error occurred.
7+
/// The exception that is thrown when an SCP error occurs.
108
/// </summary>
119
#if NETFRAMEWORK
1210
[Serializable]
13-
#endif // NETFRAMEWORK
11+
#endif
1412
public class ScpException : SshException
1513
{
1614
/// <summary>
@@ -23,34 +21,27 @@ public ScpException()
2321
/// <summary>
2422
/// Initializes a new instance of the <see cref="ScpException"/> class.
2523
/// </summary>
26-
/// <param name="message">The message.</param>
27-
public ScpException(string message)
24+
/// <inheritdoc cref="Exception(string)" path="/param"/>
25+
public ScpException(string? message)
2826
: base(message)
2927
{
3028
}
3129

3230
/// <summary>
3331
/// Initializes a new instance of the <see cref="ScpException"/> class.
3432
/// </summary>
35-
/// <param name="message">The message.</param>
36-
/// <param name="innerException">The inner exception.</param>
37-
public ScpException(string message, Exception innerException)
33+
/// <inheritdoc cref="Exception(string, Exception)" path="/param"/>
34+
public ScpException(string? message, Exception? innerException)
3835
: base(message, innerException)
3936
{
4037
}
4138

4239
#if NETFRAMEWORK
43-
/// <summary>
44-
/// Initializes a new instance of the <see cref="ScpException"/> class.
45-
/// </summary>
46-
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
47-
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
48-
/// <exception cref="ArgumentNullException">The <paramref name="info"/> parameter is <see langword="null"/>.</exception>
49-
/// <exception cref="SerializationException">The class name is <see langword="null"/> or <see cref="Exception.HResult"/> is zero (0). </exception>
50-
protected ScpException(SerializationInfo info, StreamingContext context)
40+
/// <inheritdoc/>
41+
protected ScpException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
5142
: base(info, context)
5243
{
5344
}
54-
#endif // NETFRAMEWORK
45+
#endif
5546
}
5647
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#nullable enable
2+
using System;
3+
4+
using Renci.SshNet.Sftp;
5+
6+
namespace Renci.SshNet.Common
7+
{
8+
/// <summary>
9+
/// The exception that is thrown when an error occurs in the SFTP layer.
10+
/// </summary>
11+
#if NETFRAMEWORK
12+
[Serializable]
13+
#endif
14+
public class SftpException : SshException
15+
{
16+
/// <summary>
17+
/// Gets the status code that is associated with this exception.
18+
/// </summary>
19+
public StatusCode StatusCode { get; }
20+
21+
/// <summary>
22+
/// Initializes a new instance of the <see cref="SftpException"/> class.
23+
/// </summary>
24+
/// <param name="statusCode">The status code that indicates the error that occurred.</param>
25+
public SftpException(StatusCode statusCode)
26+
: this(statusCode, message: null, innerException: null)
27+
{
28+
}
29+
30+
/// <summary>
31+
/// Initializes a new instance of the <see cref="SftpException"/> class.
32+
/// </summary>
33+
/// <param name="statusCode">The status code that indicates the error that occurred.</param>
34+
/// <param name="message">The error message that explains the reason for the exception.</param>
35+
public SftpException(StatusCode statusCode, string? message)
36+
: this(statusCode, message, innerException: null)
37+
{
38+
}
39+
40+
/// <summary>
41+
/// Initializes a new instance of the <see cref="SftpException"/> class.
42+
/// </summary>
43+
/// <param name="statusCode">The status code that indicates the error that occurred.</param>
44+
/// <param name="message">The error message that explains the reason for the exception.</param>
45+
/// <param name="innerException">The exception that is the cause of the current exception.</param>
46+
public SftpException(StatusCode statusCode, string? message, Exception? innerException)
47+
: base(string.IsNullOrEmpty(message) ? GetDefaultMessage(statusCode) : message, innerException)
48+
{
49+
StatusCode = statusCode;
50+
}
51+
52+
private protected static string GetDefaultMessage(StatusCode statusCode)
53+
{
54+
#pragma warning disable IDE0072 // Add missing cases
55+
return statusCode switch
56+
{
57+
StatusCode.Ok => "The operation completed successfully.",
58+
StatusCode.NoSuchFile => "A reference was made to a file that does not exist.",
59+
StatusCode.PermissionDenied => "The user does not have sufficient permissions to perform the operation.",
60+
StatusCode.Failure => "An error occurred, but no specific error code exists to describe the failure.",
61+
StatusCode.BadMessage => "A badly formatted packet or SFTP protocol incompatibility was detected.",
62+
StatusCode.OperationUnsupported => "An attempt was made to perform an operation which is not supported.",
63+
_ => statusCode.ToString()
64+
};
65+
#pragma warning restore IDE0072 // Add missing cases
66+
}
67+
68+
#if NETFRAMEWORK
69+
/// <inheritdoc/>
70+
protected SftpException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
71+
: base(info, context)
72+
{
73+
}
74+
#endif
75+
}
76+
}
Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
using System;
2-
#if NETFRAMEWORK
3-
using System.Runtime.Serialization;
4-
#endif // NETFRAMEWORK
1+
#nullable enable
2+
using System;
3+
4+
using Renci.SshNet.Sftp;
55

66
namespace Renci.SshNet.Common
77
{
@@ -10,47 +10,82 @@ namespace Renci.SshNet.Common
1010
/// </summary>
1111
#if NETFRAMEWORK
1212
[Serializable]
13-
#endif // NETFRAMEWORK
14-
public class SftpPathNotFoundException : SshException
13+
#endif
14+
public class SftpPathNotFoundException : SftpException
1515
{
16+
private const StatusCode Code = StatusCode.NoSuchFile;
17+
18+
/// <summary>
19+
/// Gets the path that cannot be found.
20+
/// </summary>
21+
/// <value>
22+
/// The path that cannot be found, or <see langword="null"/> if no path was
23+
/// passed to the constructor for this instance.
24+
/// </value>
25+
public string? Path { get; }
26+
1627
/// <summary>
1728
/// Initializes a new instance of the <see cref="SftpPathNotFoundException"/> class.
1829
/// </summary>
1930
public SftpPathNotFoundException()
31+
: this(message: null, path: null, innerException: null)
2032
{
2133
}
2234

2335
/// <summary>
2436
/// Initializes a new instance of the <see cref="SftpPathNotFoundException"/> class.
2537
/// </summary>
26-
/// <param name="message">The message.</param>
27-
public SftpPathNotFoundException(string message)
28-
: base(message)
38+
/// <inheritdoc cref="Exception(string)" path="/param"/>
39+
public SftpPathNotFoundException(string? message)
40+
: this(message, path: null, innerException: null)
2941
{
3042
}
3143

3244
/// <summary>
3345
/// Initializes a new instance of the <see cref="SftpPathNotFoundException"/> class.
3446
/// </summary>
35-
/// <param name="message">The message.</param>
36-
/// <param name="innerException">The inner exception.</param>
37-
public SftpPathNotFoundException(string message, Exception innerException)
38-
: base(message, innerException)
47+
/// <inheritdoc cref="Exception(string)" path="/param"/>
48+
public SftpPathNotFoundException(string? message, string? path)
49+
: this(message, path, innerException: null)
3950
{
4051
}
4152

42-
#if NETFRAMEWORK
4353
/// <summary>
4454
/// Initializes a new instance of the <see cref="SftpPathNotFoundException"/> class.
4555
/// </summary>
46-
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
47-
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
48-
/// <exception cref="ArgumentNullException">The <paramref name="info"/> parameter is <see langword="null"/>.</exception>
49-
/// <exception cref="SerializationException">The class name is <see langword="null"/> or <see cref="Exception.HResult"/> is zero (0). </exception>
50-
protected SftpPathNotFoundException(SerializationInfo info, StreamingContext context)
56+
/// <inheritdoc cref="Exception(string, Exception)" path="/param"/>
57+
public SftpPathNotFoundException(string? message, Exception? innerException)
58+
: this(message, path: null, innerException)
59+
{
60+
}
61+
62+
/// <summary>
63+
/// Initializes a new instance of the <see cref="SftpPathNotFoundException"/> class.
64+
/// </summary>
65+
/// <param name="message">The error message that explains the reason for the exception.</param>
66+
/// <param name="path">The path that cannot be found.</param>
67+
/// <param name="innerException">The exception that is the cause of the current exception.</param>
68+
public SftpPathNotFoundException(string? message, string? path, Exception? innerException)
69+
: base(Code, string.IsNullOrEmpty(message) ? GetDefaultMessage(path) : message, innerException)
70+
{
71+
Path = path;
72+
}
73+
74+
private static string GetDefaultMessage(string? path)
75+
{
76+
var message = GetDefaultMessage(Code);
77+
78+
return path is not null
79+
? $"{message} Path: '{path}'."
80+
: message;
81+
}
82+
83+
#if NETFRAMEWORK
84+
/// <inheritdoc/>
85+
protected SftpPathNotFoundException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
5186
: base(info, context)
5287
{
5388
}
54-
#endif // NETFRAMEWORK
89+
#endif
5590
}
5691
}

0 commit comments

Comments
 (0)