@@ -18,9 +18,10 @@ public partial class ScpClient
18
18
/// Uploads the specified file to the remote host.
19
19
/// </summary>
20
20
/// <param name="fileInfo">The file system info.</param>
21
- /// <param name="path">The path.</param>
21
+ /// <param name="path">A relative or absolute path for the remote file .</param>
22
22
/// <exception cref="ArgumentNullException"><paramref name="fileInfo" /> is <c>null</c>.</exception>
23
23
/// <exception cref="ArgumentException"><paramref name="path"/> is <c>null</c> or empty.</exception>
24
+ /// <exception cref="ScpException">A directory with the specified path exists on the remote host.</exception>
24
25
public void Upload ( FileInfo fileInfo , string path )
25
26
{
26
27
if ( fileInfo == null )
@@ -36,20 +37,25 @@ public void Upload(FileInfo fileInfo, string path)
36
37
37
38
if ( ! channel . SendExecRequest ( string . Format ( "scp -t {0}" , path . ShellQuote ( ) ) ) )
38
39
throw new SshException ( "Secure copy execution request was rejected by the server. Please consult the server logs." ) ;
39
-
40
40
CheckReturnCode ( input ) ;
41
41
42
- InternalUpload ( channel , input , fileInfo ) ;
42
+ using ( var source = fileInfo . OpenRead ( ) )
43
+ {
44
+ UploadTimes ( channel , input , fileInfo ) ;
45
+ UploadFileModeAndName ( channel , input , source . Length , string . Empty ) ;
46
+ UploadFileContent ( channel , input , source , fileInfo . Name ) ;
47
+ }
43
48
}
44
49
}
45
50
46
51
/// <summary>
47
52
/// Uploads the specified directory to the remote host.
48
53
/// </summary>
49
54
/// <param name="directoryInfo">The directory info.</param>
50
- /// <param name="path">The path.</param>
55
+ /// <param name="path">A relative or absolute path for the remote directory .</param>
51
56
/// <exception cref="ArgumentNullException">fileSystemInfo</exception>
52
57
/// <exception cref="ArgumentException"><paramref name="path"/> is <c>null</c> or empty.</exception>
58
+ /// <exception cref="ScpException"><paramref name="path"/> exists on the remote host, and is not a directory.</exception>
53
59
public void Upload ( DirectoryInfo directoryInfo , string path )
54
60
{
55
61
if ( directoryInfo == null )
@@ -67,17 +73,9 @@ public void Upload(DirectoryInfo directoryInfo, string path)
67
73
channel . SendExecRequest ( string . Format ( "scp -rt {0}" , path . ShellQuote ( ) ) ) ;
68
74
CheckReturnCode ( input ) ;
69
75
70
- // set last write and last access time on specified remote path
71
- InternalSetTimestamp ( channel , input , directoryInfo . LastWriteTimeUtc , directoryInfo . LastAccessTimeUtc ) ;
72
- SendData ( channel , string . Format ( "D0755 0 {0}\n " , "." ) ) ;
73
- CheckReturnCode ( input ) ;
74
-
75
- // recursively upload files and directories in specified remote path
76
- InternalUpload ( channel , input , directoryInfo ) ;
77
-
78
- // terminate upload of specified remote path
79
- SendData ( channel , "E\n " ) ;
80
- CheckReturnCode ( input ) ;
76
+ UploadTimes ( channel , input , directoryInfo ) ;
77
+ UploadDirectoryModeAndName ( channel , input , "." ) ;
78
+ UploadDirectoryContent ( channel , input , directoryInfo ) ;
81
79
}
82
80
}
83
81
@@ -88,6 +86,7 @@ public void Upload(DirectoryInfo directoryInfo, string path)
88
86
/// <param name="fileInfo">Local file information.</param>
89
87
/// <exception cref="ArgumentNullException"><paramref name="fileInfo"/> is <c>null</c>.</exception>
90
88
/// <exception cref="ArgumentException"><paramref name="filename"/> is <c>null</c> or empty.</exception>
89
+ /// <exception cref="ScpException"><paramref name="filename"/> exists on the remote host, and is not a regular file.</exception>
91
90
public void Download ( string filename , FileInfo fileInfo )
92
91
{
93
92
if ( string . IsNullOrEmpty ( filename ) )
@@ -104,7 +103,7 @@ public void Download(string filename, FileInfo fileInfo)
104
103
// Send channel command request
105
104
channel . SendExecRequest ( string . Format ( "scp -pf {0}" , filename . ShellQuote ( ) ) ) ;
106
105
// Send reply
107
- SendConfirmation ( channel ) ;
106
+ SendSuccessConfirmation ( channel ) ;
108
107
109
108
InternalDownload ( channel , input , fileInfo ) ;
110
109
}
@@ -117,6 +116,7 @@ public void Download(string filename, FileInfo fileInfo)
117
116
/// <param name="directoryInfo">Local directory information.</param>
118
117
/// <exception cref="ArgumentException"><paramref name="directoryName"/> is <c>null</c> or empty.</exception>
119
118
/// <exception cref="ArgumentNullException"><paramref name="directoryInfo"/> is <c>null</c>.</exception>
119
+ /// <exception cref="ScpException">File or directory with the specified path does not exist on the remote host.</exception>
120
120
public void Download ( string directoryName , DirectoryInfo directoryInfo )
121
121
{
122
122
if ( string . IsNullOrEmpty ( directoryName ) )
@@ -133,51 +133,53 @@ public void Download(string directoryName, DirectoryInfo directoryInfo)
133
133
// Send channel command request
134
134
channel . SendExecRequest ( string . Format ( "scp -prf {0}" , directoryName . ShellQuote ( ) ) ) ;
135
135
// Send reply
136
- SendConfirmation ( channel ) ;
136
+ SendSuccessConfirmation ( channel ) ;
137
137
138
138
InternalDownload ( channel , input , directoryInfo ) ;
139
139
}
140
140
}
141
141
142
142
/// <summary>
143
- /// Uploads the file in the active directory context, and set
143
+ /// Upload the files and subdirectories in the specified directory.
144
144
/// </summary>
145
145
/// <param name="channel">The channel to perform the upload in.</param>
146
146
/// <param name="input">A <see cref="Stream"/> from which any feedback from the server can be read.</param>
147
- /// <param name="fileInfo">The file to upload.</param>
148
- private void InternalUpload ( IChannelSession channel , Stream input , FileInfo fileInfo )
149
- {
150
- using ( var source = fileInfo . OpenRead ( ) )
151
- {
152
- // set the last write and last access time for the next file uploaded
153
- InternalSetTimestamp ( channel , input , fileInfo . LastWriteTimeUtc , fileInfo . LastAccessTimeUtc ) ;
154
- // upload the actual file
155
- InternalUpload ( channel , input , source , fileInfo . Name ) ;
156
- }
157
- }
158
-
159
- private void InternalUpload ( IChannelSession channel , Stream input , DirectoryInfo directoryInfo )
147
+ /// <param name="directoryInfo">The directory to upload.</param>
148
+ private void UploadDirectoryContent ( IChannelSession channel , Stream input , DirectoryInfo directoryInfo )
160
149
{
161
150
// Upload files
162
151
var files = directoryInfo . GetFiles ( ) ;
163
152
foreach ( var file in files )
164
153
{
165
- InternalUpload ( channel , input , file ) ;
154
+ using ( var source = file . OpenRead ( ) )
155
+ {
156
+ UploadTimes ( channel , input , file ) ;
157
+ UploadFileModeAndName ( channel , input , source . Length , file . Name ) ;
158
+ UploadFileContent ( channel , input , source , file . Name ) ;
159
+ }
166
160
}
167
161
168
162
// Upload directories
169
163
var directories = directoryInfo . GetDirectories ( ) ;
170
164
foreach ( var directory in directories )
171
165
{
172
- InternalSetTimestamp ( channel , input , directory . LastWriteTimeUtc , directory . LastAccessTimeUtc ) ;
173
- SendData ( channel , string . Format ( "D0755 0 {0}\n " , directory . Name ) ) ;
174
- CheckReturnCode ( input ) ;
166
+ UploadTimes ( channel , input , directory ) ;
167
+ UploadDirectoryModeAndName ( channel , input , directory . Name ) ;
168
+ UploadDirectoryContent ( channel , input , directory ) ;
169
+ }
175
170
176
- InternalUpload ( channel , input , directory ) ;
171
+ // Mark upload of current directory complete
172
+ SendData ( channel , "E\n " ) ;
173
+ CheckReturnCode ( input ) ;
174
+ }
177
175
178
- SendData ( channel , "E\n " ) ;
179
- CheckReturnCode ( input ) ;
180
- }
176
+ /// <summary>
177
+ /// Sets mode and name of the directory being upload.
178
+ /// </summary>
179
+ private void UploadDirectoryModeAndName ( IChannelSession channel , Stream input , string directoryName )
180
+ {
181
+ SendData ( channel , string . Format ( "D0755 0 {0}\n " , directoryName ) ) ;
182
+ CheckReturnCode ( input ) ;
181
183
}
182
184
183
185
private void InternalDownload ( IChannelSession channel , Stream input , FileSystemInfo fileSystemInfo )
@@ -195,7 +197,7 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI
195
197
196
198
if ( message == "E" )
197
199
{
198
- SendConfirmation ( channel ) ; // Send reply
200
+ SendSuccessConfirmation ( channel ) ; // Send reply
199
201
200
202
directoryCounter -- ;
201
203
@@ -209,15 +211,15 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI
209
211
var match = DirectoryInfoRe . Match ( message ) ;
210
212
if ( match . Success )
211
213
{
212
- SendConfirmation ( channel ) ; // Send reply
214
+ SendSuccessConfirmation ( channel ) ; // Send reply
213
215
214
216
// Read directory
215
217
var filename = match . Result ( "${filename}" ) ;
216
218
217
219
DirectoryInfo newDirectoryInfo ;
218
220
if ( directoryCounter > 0 )
219
221
{
220
- newDirectoryInfo = Directory . CreateDirectory ( string . Format ( "{0}{1}{2}" , currentDirectoryFullName , Path . DirectorySeparatorChar , filename ) ) ;
222
+ newDirectoryInfo = Directory . CreateDirectory ( Path . Combine ( currentDirectoryFullName , filename ) ) ;
221
223
newDirectoryInfo . LastAccessTime = accessedTime ;
222
224
newDirectoryInfo . LastWriteTime = modifiedTime ;
223
225
}
@@ -237,15 +239,15 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI
237
239
if ( match . Success )
238
240
{
239
241
// Read file
240
- SendConfirmation ( channel ) ; // Send reply
242
+ SendSuccessConfirmation ( channel ) ; // Send reply
241
243
242
244
var length = long . Parse ( match . Result ( "${length}" ) ) ;
243
245
var fileName = match . Result ( "${filename}" ) ;
244
246
245
247
var fileInfo = fileSystemInfo as FileInfo ;
246
248
247
249
if ( fileInfo == null )
248
- fileInfo = new FileInfo ( string . Format ( "{0}{1}{2}" , currentDirectoryFullName , Path . DirectorySeparatorChar , fileName ) ) ;
250
+ fileInfo = new FileInfo ( Path . Combine ( currentDirectoryFullName , fileName ) ) ;
249
251
250
252
using ( var output = fileInfo . OpenWrite ( ) )
251
253
{
@@ -264,7 +266,7 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI
264
266
if ( match . Success )
265
267
{
266
268
// Read timestamp
267
- SendConfirmation ( channel ) ; // Send reply
269
+ SendSuccessConfirmation ( channel ) ; // Send reply
268
270
269
271
var mtime = long . Parse ( match . Result ( "${mtime}" ) ) ;
270
272
var atime = long . Parse ( match . Result ( "${atime}" ) ) ;
@@ -275,7 +277,7 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI
275
277
continue ;
276
278
}
277
279
278
- SendConfirmation ( channel , 1 , string . Format ( "\" {0}\" is not valid protocol message." , message ) ) ;
280
+ SendErrorConfirmation ( channel , string . Format ( "\" {0}\" is not valid protocol message." , message ) ) ;
279
281
}
280
282
}
281
283
}
0 commit comments