net-sftp 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/faq/faq.html +298 -0
- data/doc/faq/faq.rb +154 -0
- data/doc/faq/faq.yml +183 -0
- data/examples/sftp-open-uri.rb +30 -0
- data/examples/synchronous.rb +3 -1
- data/lib/net/sftp/errors.rb +1 -1
- data/lib/net/sftp/operations/read.rb +15 -11
- data/lib/net/sftp/session.rb +2 -2
- data/lib/net/sftp/version.rb +2 -2
- data/lib/uri/open-sftp.rb +54 -0
- data/lib/uri/sftp.rb +42 -0
- data/test/operations/tc_read.rb +3 -3
- data/test/protocol/01/tc_attributes.rb +1 -1
- data/test/protocol/04/tc_attributes.rb +2 -2
- metadata +48 -40
data/doc/faq/faq.html
ADDED
@@ -0,0 +1,298 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Net::SFTP FAQ</title>
|
4
|
+
<style type="text/css">
|
5
|
+
a, a:visited, a:active {
|
6
|
+
color: #00F;
|
7
|
+
text-decoration: none;
|
8
|
+
}
|
9
|
+
|
10
|
+
a:hover {
|
11
|
+
text-decoration: underline;
|
12
|
+
}
|
13
|
+
|
14
|
+
.faq-list {
|
15
|
+
color: #000;
|
16
|
+
font-family: vera-sans, verdana, arial, sans-serif;
|
17
|
+
}
|
18
|
+
|
19
|
+
.faq-title {
|
20
|
+
background: #007;
|
21
|
+
color: #FFF;
|
22
|
+
font-family: vera-sans, verdana, arial, sans-serif;
|
23
|
+
padding-left: 1em;
|
24
|
+
padding-top: 0.5em;
|
25
|
+
padding-bottom: 0.5em;
|
26
|
+
font-weight: bold;
|
27
|
+
font-size: large;
|
28
|
+
border: 1px solid #000;
|
29
|
+
}
|
30
|
+
|
31
|
+
.faq-answer {
|
32
|
+
margin-left: 1em;
|
33
|
+
color: #000;
|
34
|
+
font-family: vera-sans, verdana, arial, sans-serif;
|
35
|
+
}
|
36
|
+
|
37
|
+
.faq-answer pre {
|
38
|
+
margin-left: 1em;
|
39
|
+
color: #000;
|
40
|
+
background: #FFE;
|
41
|
+
font-size: normal;
|
42
|
+
border: 1px dotted #CCC;
|
43
|
+
padding: 1em;
|
44
|
+
}
|
45
|
+
|
46
|
+
h1 {
|
47
|
+
background: #005;
|
48
|
+
color: #FFF;
|
49
|
+
font-family: vera-sans, verdana, arial, sans-serif;
|
50
|
+
padding-left: 1em;
|
51
|
+
padding-top: 1em;
|
52
|
+
padding-bottom: 1em;
|
53
|
+
font-weight: bold;
|
54
|
+
font-size: x-large;
|
55
|
+
border: 1px solid #00F;
|
56
|
+
}
|
57
|
+
</style>
|
58
|
+
</head>
|
59
|
+
<body>
|
60
|
+
<h1>Net::SFTP FAQ</h1>
|
61
|
+
<div class="faq-list">
|
62
|
+
<ul>
|
63
|
+
<li><a href='#2203312'>What is Net::SFTP?</a></li>
|
64
|
+
<li>How do I…
|
65
|
+
<ul>
|
66
|
+
<li>...connect to an <span class="caps">SFTP</span> server?
|
67
|
+
<ul>
|
68
|
+
<li><a href='#2203252'>I’d like to connect without first getting a Net::SSH connection…</a></li>
|
69
|
+
<li><a href='#2203212'>I already have an open Net::SSH connection…</a></li>
|
70
|
+
</ul>
|
71
|
+
</li>
|
72
|
+
<li>...upload data?
|
73
|
+
<ul>
|
74
|
+
<li><a href='#2203132'>I want to upload an entire file on disk…</a></li>
|
75
|
+
<li><a href='#2203092'>I want to upload bytes from a string or other object…</a></li>
|
76
|
+
</ul>
|
77
|
+
</li>
|
78
|
+
<li>...download data?
|
79
|
+
<ul>
|
80
|
+
<li><a href='#2203012'>I want to download directly to a local file…</a></li>
|
81
|
+
<li><a href='#2202972'>I want to download to a string in memory…</a></li>
|
82
|
+
<li><a href='#2202932'>I want to be notified of the progress of the download…</a></li>
|
83
|
+
</ul>
|
84
|
+
</li>
|
85
|
+
<li>...manage file permissions?
|
86
|
+
<ul>
|
87
|
+
<li><a href='#2202862'>I want to query a file’s permissions…</a></li>
|
88
|
+
<li><a href='#2202822'>I want to change a file’s permissions…</a></li>
|
89
|
+
<li><a href='#2202782'>I already have an open handle for the remove file…</a></li>
|
90
|
+
</ul>
|
91
|
+
</li>
|
92
|
+
<li>...manage directories?
|
93
|
+
<ul>
|
94
|
+
<li><a href='#2202692'>I want to query the contents of a directory…</a></li>
|
95
|
+
<li><a href='#2202652'>I want to create a directory…</a></li>
|
96
|
+
<li><a href='#2202612'>I want to remove a directory…</a></li>
|
97
|
+
</ul>
|
98
|
+
</li>
|
99
|
+
<li><a href='#2202542'>...delete a file?</a></li>
|
100
|
+
<li><a href='#2202502'>...rename a file?</a></li>
|
101
|
+
</ul>
|
102
|
+
</li>
|
103
|
+
</ul>
|
104
|
+
</div>
|
105
|
+
<a name='2203312'></a>
|
106
|
+
<div class='faq-title'>What is Net::SFTP?</div>
|
107
|
+
<div class='faq-answer'><p>Net::SFTP is a pure-Ruby implementation of the <span class="caps">SFTP</span> protocol. That’s
|
108
|
+
“SFTP” as in “Secure File Transfer Protocol”, as defined as an adjuct to the
|
109
|
+
<span class="caps">SSH</span> specification. <em>Not</em> “SFTP” as in “Secure <span class="caps">FTP</span>” (a <em>completely</em> different
|
110
|
+
beast). Nor is it an implementation of the “Simple File Transfer Protocol”
|
111
|
+
(which is in no way secure).</p></div>
|
112
|
+
<a name='2203252'></a>
|
113
|
+
<div class='faq-title'>How do I… ...connect to an <span class="caps">SFTP</span> server? I’d like to connect without first getting a Net::SSH connection…</div>
|
114
|
+
<div class='faq-answer'><p>Something like this:</p>
|
115
|
+
|
116
|
+
|
117
|
+
<code><pre>
|
118
|
+
require 'net/sftp'
|
119
|
+
|
120
|
+
Net::SFTP.start(host, user, password) do |sftp|
|
121
|
+
...
|
122
|
+
end
|
123
|
+
</pre></code>
|
124
|
+
|
125
|
+
<p><code>Net::SFTP.start</code> accepts the same parameters as <code>Net::SSH.start</code>,
|
126
|
+
so I’ll direct you to that documentation for all the particulars.</p></div>
|
127
|
+
<a name='2203212'></a>
|
128
|
+
<div class='faq-title'>How do I… ...connect to an <span class="caps">SFTP</span> server? I already have an open Net::SSH connection…</div>
|
129
|
+
<div class='faq-answer'><p>You can piggy-back an <span class="caps">SFTP</span> connection on an existing Net::SSH
|
130
|
+
connection, which can be useful if you’ve already got an <span class="caps">SSH</span>
|
131
|
+
connection that you’re using for port forwarding or whatever.</p>
|
132
|
+
|
133
|
+
|
134
|
+
<code><pre>
|
135
|
+
require 'net/ssh'
|
136
|
+
require 'net/sftp'
|
137
|
+
|
138
|
+
Net::SSH.start(host, user, password) do |ssh|
|
139
|
+
...
|
140
|
+
ssh.sftp.connect do |sftp|
|
141
|
+
...
|
142
|
+
end
|
143
|
+
...
|
144
|
+
end
|
145
|
+
</pre></code></div>
|
146
|
+
<a name='2203132'></a>
|
147
|
+
<div class='faq-title'>How do I… ...upload data? I want to upload an entire file on disk…</div>
|
148
|
+
<div class='faq-answer'><p>Assuming you already have an <span class="caps">SFTP</span> connection:</p>
|
149
|
+
|
150
|
+
|
151
|
+
<code><pre>
|
152
|
+
sftp.put_file "/path/to/local.file", "/path/to/remote.file"
|
153
|
+
</pre></code></div>
|
154
|
+
<a name='2203092'></a>
|
155
|
+
<div class='faq-title'>How do I… ...upload data? I want to upload bytes from a string or other object…</div>
|
156
|
+
<div class='faq-answer'><p>Assuming you already have an <span class="caps">SFTP</span> connection, and your data is stored
|
157
|
+
in a string named <code>data</code>:</p>
|
158
|
+
|
159
|
+
|
160
|
+
<code><pre>
|
161
|
+
sftp.open_handle("/path/to/remote.file", "w") do |handle|
|
162
|
+
result = sftp.write(handle, data)
|
163
|
+
puts result.code # the result of the operation
|
164
|
+
end
|
165
|
+
</pre></code>
|
166
|
+
|
167
|
+
<p>If (for whatever reason) you’d rather not use blocks, you can do
|
168
|
+
without, but be sure to call <code>close_handle</code> when you’re done:</p>
|
169
|
+
|
170
|
+
|
171
|
+
<code><pre>
|
172
|
+
handle = sftp.open_handle("/path/to/remote.file", "w")
|
173
|
+
result = sftp.write(handle, data)
|
174
|
+
puts result.code # the result of the operation
|
175
|
+
sftp.close_handle(handle)
|
176
|
+
</pre></code></div>
|
177
|
+
<a name='2203012'></a>
|
178
|
+
<div class='faq-title'>How do I… ...download data? I want to download directly to a local file…</div>
|
179
|
+
<div class='faq-answer'><p>Assuming you already have an <span class="caps">SFTP</span> connection:</p>
|
180
|
+
|
181
|
+
|
182
|
+
<code><pre>
|
183
|
+
sftp.get_file "/path/to/remote.file", "/path/to/local.file"
|
184
|
+
</pre></code></div>
|
185
|
+
<a name='2202972'></a>
|
186
|
+
<div class='faq-title'>How do I… ...download data? I want to download to a string in memory…</div>
|
187
|
+
<div class='faq-answer'><p>Assuming you already have an <span class="caps">SFTP</span> connection:</p>
|
188
|
+
|
189
|
+
|
190
|
+
<code><pre>
|
191
|
+
data = nil
|
192
|
+
sftp.open_handle("/path/to/remote.file") do |handle|
|
193
|
+
data = sftp.read(handle)
|
194
|
+
end
|
195
|
+
</pre></code></div>
|
196
|
+
<a name='2202932'></a>
|
197
|
+
<div class='faq-title'>How do I… ...download data? I want to be notified of the progress of the download…</div>
|
198
|
+
<div class='faq-answer'><p>You can specify both a “chunk size” and a “progress callback”. The
|
199
|
+
callback will be invoked for every “chunk size” bytes that are
|
200
|
+
received:</p>
|
201
|
+
|
202
|
+
|
203
|
+
<code><pre>
|
204
|
+
sftp.open_handle("/path/to/remote.file") do |handle|
|
205
|
+
begin
|
206
|
+
STDOUT.sync = true
|
207
|
+
data = sftp.read(handle, :chunk_size => 4096,
|
208
|
+
:progress_callback => lambda { |data| print "." })
|
209
|
+
puts
|
210
|
+
ensure
|
211
|
+
STDOUT.sync = false
|
212
|
+
end
|
213
|
+
end
|
214
|
+
</pre></code></div>
|
215
|
+
<a name='2202862'></a>
|
216
|
+
<div class='faq-title'>How do I… ...manage file permissions? I want to query a file’s permissions…</div>
|
217
|
+
<div class='faq-answer'><p>File permissions are one of the <code>stat</code> attributes of files and
|
218
|
+
directories:</p>
|
219
|
+
|
220
|
+
|
221
|
+
<code><pre>
|
222
|
+
p sftp.stat("/path/to/remote.file").permissions
|
223
|
+
</pre></code></div>
|
224
|
+
<a name='2202822'></a>
|
225
|
+
<div class='faq-title'>How do I… ...manage file permissions? I want to change a file’s permissions…</div>
|
226
|
+
<div class='faq-answer'><p>Just use <code>setstat</code> to change the permissions of an existing file:</p>
|
227
|
+
|
228
|
+
|
229
|
+
<code><pre>
|
230
|
+
sftp.setstat("/path/to/remote.file", :permissions => 0644)
|
231
|
+
</pre></code></div>
|
232
|
+
<a name='2202782'></a>
|
233
|
+
<div class='faq-title'>How do I… ...manage file permissions? I already have an open handle for the remove file…</div>
|
234
|
+
<div class='faq-answer'><p>If you have a handle for the remote file, you can use <code>fstat</code> and
|
235
|
+
<code>fsetstat</code> to query and set the permissions:</p>
|
236
|
+
|
237
|
+
|
238
|
+
<code><pre>
|
239
|
+
sftp.open_handle("/path/to/remote.file") do |handle|
|
240
|
+
permissions = sftp.fstat(handle)
|
241
|
+
sftp.fsetstat(handle, :permissions => permissions | 0444)
|
242
|
+
end
|
243
|
+
</pre></code></div>
|
244
|
+
<a name='2202692'></a>
|
245
|
+
<div class='faq-title'>How do I… ...manage directories? I want to query the contents of a directory…</div>
|
246
|
+
<div class='faq-answer'><p>You query the contents of a directory by calling <code>opendir</code> to obtain
|
247
|
+
a handle to the directory, and then using <code>readdir</code> on the handle to
|
248
|
+
obtain a list of directory entries. Be sure to close the handle when
|
249
|
+
you’re done:</p>
|
250
|
+
|
251
|
+
|
252
|
+
<code><pre>
|
253
|
+
handle = sftp.opendir("/usr/lib")
|
254
|
+
items = sftp.readdir(handle)
|
255
|
+
items.each do |item|
|
256
|
+
puts item.filename
|
257
|
+
puts item.longname
|
258
|
+
p item.attributes # permissions, atime, etc.
|
259
|
+
end
|
260
|
+
sftp.close_handle(handle)
|
261
|
+
</pre></code></div>
|
262
|
+
<a name='2202652'></a>
|
263
|
+
<div class='faq-title'>How do I… ...manage directories? I want to create a directory…</div>
|
264
|
+
<div class='faq-answer'><p>Use <code>mkdir</code>:</p>
|
265
|
+
|
266
|
+
|
267
|
+
<code><pre>
|
268
|
+
sftp.mkdir("/path/to/remote/dir", :permissions => 0500)
|
269
|
+
</pre></code></div>
|
270
|
+
<a name='2202612'></a>
|
271
|
+
<div class='faq-title'>How do I… ...manage directories? I want to remove a directory…</div>
|
272
|
+
<div class='faq-answer'><p>Use <code>rmdir</code>:</p>
|
273
|
+
|
274
|
+
|
275
|
+
<code><pre>
|
276
|
+
sftp.rmdir("/path/to/remote/dir")
|
277
|
+
</pre></code></div>
|
278
|
+
<a name='2202542'></a>
|
279
|
+
<div class='faq-title'>How do I… ...delete a file?</div>
|
280
|
+
<div class='faq-answer'><p>Use <code>remove</code>:</p>
|
281
|
+
|
282
|
+
|
283
|
+
<code><pre>
|
284
|
+
sftp.remove("/path/to/remote.file")
|
285
|
+
</pre></code></div>
|
286
|
+
<a name='2202502'></a>
|
287
|
+
<div class='faq-title'>How do I… ...rename a file?</div>
|
288
|
+
<div class='faq-answer'><p>Use <code>rename</code>:</p>
|
289
|
+
|
290
|
+
|
291
|
+
<code><pre>
|
292
|
+
sftp.rename("/path/to/remote.file", "/path/to/new.file")
|
293
|
+
</pre></code>
|
294
|
+
|
295
|
+
<p>It should be noted that <code>rename</code> is only supported by version 2 or
|
296
|
+
later of the <span class="caps">SFTP</span> protocol, so if you’re using an older <span class="caps">SFTP</span> server you
|
297
|
+
might not be able to use this operation.</p></div>
|
298
|
+
</body></html>
|
data/doc/faq/faq.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
#--
|
2
|
+
# =============================================================================
|
3
|
+
# Copyright (c) 2005, Jamis Buck (jamis@jamisbuck.org)
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright
|
13
|
+
# notice, this list of conditions and the following disclaimer in the
|
14
|
+
# documentation and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * The names of its contributors may not be used to endorse or promote
|
17
|
+
# products derived from this software without specific prior written
|
18
|
+
# permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
# =============================================================================
|
31
|
+
#++
|
32
|
+
|
33
|
+
require 'yaml'
|
34
|
+
require 'redcloth'
|
35
|
+
|
36
|
+
def process_faq_list( faqs )
|
37
|
+
puts "<ul>"
|
38
|
+
faqs.each do |faq|
|
39
|
+
process_faq_list_item faq
|
40
|
+
end
|
41
|
+
puts "</ul>"
|
42
|
+
end
|
43
|
+
|
44
|
+
def process_faq_list_item( faq )
|
45
|
+
question = faq.keys.first
|
46
|
+
answer = faq.values.first
|
47
|
+
|
48
|
+
print "<li>"
|
49
|
+
|
50
|
+
question_text = RedCloth.new(question).to_html.gsub( %r{</?p>},"" )
|
51
|
+
if answer.is_a?( Array )
|
52
|
+
puts question_text
|
53
|
+
process_faq_list answer
|
54
|
+
else
|
55
|
+
print "<a href='##{question.object_id}'>#{question_text}</a>"
|
56
|
+
end
|
57
|
+
|
58
|
+
puts "</li>"
|
59
|
+
end
|
60
|
+
|
61
|
+
def process_faq_descriptions( faqs, path=nil )
|
62
|
+
faqs.each do |faq|
|
63
|
+
process_faq_description faq, path
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def process_faq_description( faq, path )
|
68
|
+
question = faq.keys.first
|
69
|
+
path = ( path ? path + " " : "" ) + question
|
70
|
+
answer = faq.values.first
|
71
|
+
|
72
|
+
if answer.is_a?( Array )
|
73
|
+
process_faq_descriptions( answer, path )
|
74
|
+
else
|
75
|
+
title = RedCloth.new( path ).to_html.gsub( %r{</?p>}, "" )
|
76
|
+
answer = RedCloth.new( answer || "" )
|
77
|
+
|
78
|
+
puts "<a name='#{question.object_id}'></a>"
|
79
|
+
puts "<div class='faq-title'>#{title}</div>"
|
80
|
+
puts "<div class='faq-answer'>#{answer.to_html}</div>"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
faqs = YAML.load( File.read( "faq.yml" ) )
|
85
|
+
|
86
|
+
puts <<-EOF
|
87
|
+
<html>
|
88
|
+
<head>
|
89
|
+
<title>Net::SFTP FAQ</title>
|
90
|
+
<style type="text/css">
|
91
|
+
a, a:visited, a:active {
|
92
|
+
color: #00F;
|
93
|
+
text-decoration: none;
|
94
|
+
}
|
95
|
+
|
96
|
+
a:hover {
|
97
|
+
text-decoration: underline;
|
98
|
+
}
|
99
|
+
|
100
|
+
.faq-list {
|
101
|
+
color: #000;
|
102
|
+
font-family: vera-sans, verdana, arial, sans-serif;
|
103
|
+
}
|
104
|
+
|
105
|
+
.faq-title {
|
106
|
+
background: #007;
|
107
|
+
color: #FFF;
|
108
|
+
font-family: vera-sans, verdana, arial, sans-serif;
|
109
|
+
padding-left: 1em;
|
110
|
+
padding-top: 0.5em;
|
111
|
+
padding-bottom: 0.5em;
|
112
|
+
font-weight: bold;
|
113
|
+
font-size: large;
|
114
|
+
border: 1px solid #000;
|
115
|
+
}
|
116
|
+
|
117
|
+
.faq-answer {
|
118
|
+
margin-left: 1em;
|
119
|
+
color: #000;
|
120
|
+
font-family: vera-sans, verdana, arial, sans-serif;
|
121
|
+
}
|
122
|
+
|
123
|
+
.faq-answer pre {
|
124
|
+
margin-left: 1em;
|
125
|
+
color: #000;
|
126
|
+
background: #FFE;
|
127
|
+
font-size: normal;
|
128
|
+
border: 1px dotted #CCC;
|
129
|
+
padding: 1em;
|
130
|
+
}
|
131
|
+
|
132
|
+
h1 {
|
133
|
+
background: #005;
|
134
|
+
color: #FFF;
|
135
|
+
font-family: vera-sans, verdana, arial, sans-serif;
|
136
|
+
padding-left: 1em;
|
137
|
+
padding-top: 1em;
|
138
|
+
padding-bottom: 1em;
|
139
|
+
font-weight: bold;
|
140
|
+
font-size: x-large;
|
141
|
+
border: 1px solid #00F;
|
142
|
+
}
|
143
|
+
</style>
|
144
|
+
</head>
|
145
|
+
<body>
|
146
|
+
<h1>Net::SFTP FAQ</h1>
|
147
|
+
<div class="faq-list">
|
148
|
+
EOF
|
149
|
+
|
150
|
+
process_faq_list( faqs )
|
151
|
+
puts "</div>"
|
152
|
+
process_faq_descriptions( faqs )
|
153
|
+
|
154
|
+
puts "</body></html>"
|
data/doc/faq/faq.yml
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
---
|
2
|
+
- "What is Net::SFTP?": |
|
3
|
+
Net::SFTP is a pure-Ruby implementation of the SFTP protocol. That's
|
4
|
+
"SFTP" as in "Secure File Transfer Protocol", as defined as an adjuct to the
|
5
|
+
SSH specification. _Not_ "SFTP" as in "Secure FTP" (a _completely_ different
|
6
|
+
beast). Nor is it an implementation of the "Simple File Transfer Protocol"
|
7
|
+
(which is in no way secure).
|
8
|
+
|
9
|
+
- "How do I...":
|
10
|
+
- "...connect to an SFTP server?":
|
11
|
+
- "I'd like to connect without first getting a Net::SSH connection...": |
|
12
|
+
Something like this:
|
13
|
+
|
14
|
+
<code><pre>
|
15
|
+
require 'net/sftp'
|
16
|
+
|
17
|
+
Net::SFTP.start(host, user, password) do |sftp|
|
18
|
+
...
|
19
|
+
end
|
20
|
+
</pre></code>
|
21
|
+
|
22
|
+
@Net::SFTP.start@ accepts the same parameters as @Net::SSH.start@,
|
23
|
+
so I'll direct you to that documentation for all the particulars.
|
24
|
+
|
25
|
+
- "I already have an open Net::SSH connection...": |
|
26
|
+
You can piggy-back an SFTP connection on an existing Net::SSH
|
27
|
+
connection, which can be useful if you've already got an SSH
|
28
|
+
connection that you're using for port forwarding or whatever.
|
29
|
+
|
30
|
+
<code><pre>
|
31
|
+
require 'net/ssh'
|
32
|
+
require 'net/sftp'
|
33
|
+
|
34
|
+
Net::SSH.start(host, user, password) do |ssh|
|
35
|
+
...
|
36
|
+
ssh.sftp.connect do |sftp|
|
37
|
+
...
|
38
|
+
end
|
39
|
+
...
|
40
|
+
end
|
41
|
+
</pre></code>
|
42
|
+
|
43
|
+
- "...upload data?":
|
44
|
+
- "I want to upload an entire file on disk...": |
|
45
|
+
Assuming you already have an SFTP connection:
|
46
|
+
|
47
|
+
<code><pre>
|
48
|
+
sftp.put_file "/path/to/local.file", "/path/to/remote.file"
|
49
|
+
</pre></code>
|
50
|
+
|
51
|
+
- "I want to upload bytes from a string or other object...": |
|
52
|
+
Assuming you already have an SFTP connection, and your data is stored
|
53
|
+
in a string named @data@:
|
54
|
+
|
55
|
+
<code><pre>
|
56
|
+
sftp.open_handle("/path/to/remote.file", "w") do |handle|
|
57
|
+
result = sftp.write(handle, data)
|
58
|
+
puts result.code # the result of the operation
|
59
|
+
end
|
60
|
+
</pre></code>
|
61
|
+
|
62
|
+
If (for whatever reason) you'd rather not use blocks, you can do
|
63
|
+
without, but be sure to call @close_handle@ when you're done:
|
64
|
+
|
65
|
+
<code><pre>
|
66
|
+
handle = sftp.open_handle("/path/to/remote.file", "w")
|
67
|
+
result = sftp.write(handle, data)
|
68
|
+
puts result.code # the result of the operation
|
69
|
+
sftp.close_handle(handle)
|
70
|
+
</pre></code>
|
71
|
+
|
72
|
+
- "...download data?":
|
73
|
+
- "I want to download directly to a local file...": |
|
74
|
+
Assuming you already have an SFTP connection:
|
75
|
+
|
76
|
+
<code><pre>
|
77
|
+
sftp.get_file "/path/to/remote.file", "/path/to/local.file"
|
78
|
+
</pre></code>
|
79
|
+
|
80
|
+
- "I want to download to a string in memory...": |
|
81
|
+
Assuming you already have an SFTP connection:
|
82
|
+
|
83
|
+
<code><pre>
|
84
|
+
data = nil
|
85
|
+
sftp.open_handle("/path/to/remote.file") do |handle|
|
86
|
+
data = sftp.read(handle)
|
87
|
+
end
|
88
|
+
</pre></code>
|
89
|
+
|
90
|
+
- "I want to be notified of the progress of the download...": |
|
91
|
+
You can specify both a "chunk size" and a "progress callback". The
|
92
|
+
callback will be invoked for every "chunk size" bytes that are
|
93
|
+
received:
|
94
|
+
|
95
|
+
<code><pre>
|
96
|
+
sftp.open_handle("/path/to/remote.file") do |handle|
|
97
|
+
begin
|
98
|
+
STDOUT.sync = true
|
99
|
+
data = sftp.read(handle, :chunk_size => 4096,
|
100
|
+
:progress_callback => lambda { |data| print "." })
|
101
|
+
puts
|
102
|
+
ensure
|
103
|
+
STDOUT.sync = false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
</pre></code>
|
107
|
+
|
108
|
+
- "...manage file permissions?":
|
109
|
+
- "I want to query a file's permissions...": |
|
110
|
+
File permissions are one of the @stat@ attributes of files and
|
111
|
+
directories:
|
112
|
+
|
113
|
+
<code><pre>
|
114
|
+
p sftp.stat("/path/to/remote.file").permissions
|
115
|
+
</pre></code>
|
116
|
+
|
117
|
+
- "I want to change a file's permissions...": |
|
118
|
+
Just use @setstat@ to change the permissions of an existing file:
|
119
|
+
|
120
|
+
<code><pre>
|
121
|
+
sftp.setstat("/path/to/remote.file", :permissions => 0644)
|
122
|
+
</pre></code>
|
123
|
+
|
124
|
+
- "I already have an open handle for the remove file...": |
|
125
|
+
If you have a handle for the remote file, you can use @fstat@ and
|
126
|
+
@fsetstat@ to query and set the permissions:
|
127
|
+
|
128
|
+
<code><pre>
|
129
|
+
sftp.open_handle("/path/to/remote.file") do |handle|
|
130
|
+
permissions = sftp.fstat(handle)
|
131
|
+
sftp.fsetstat(handle, :permissions => permissions | 0444)
|
132
|
+
end
|
133
|
+
</pre></code>
|
134
|
+
|
135
|
+
- "...manage directories?":
|
136
|
+
- "I want to query the contents of a directory...": |
|
137
|
+
You query the contents of a directory by calling @opendir@ to obtain
|
138
|
+
a handle to the directory, and then using @readdir@ on the handle to
|
139
|
+
obtain a list of directory entries. Be sure to close the handle when
|
140
|
+
you're done:
|
141
|
+
|
142
|
+
<code><pre>
|
143
|
+
handle = sftp.opendir("/usr/lib")
|
144
|
+
items = sftp.readdir(handle)
|
145
|
+
items.each do |item|
|
146
|
+
puts item.filename
|
147
|
+
puts item.longname
|
148
|
+
p item.attributes # permissions, atime, etc.
|
149
|
+
end
|
150
|
+
sftp.close_handle(handle)
|
151
|
+
</pre></code>
|
152
|
+
|
153
|
+
- "I want to create a directory...": |
|
154
|
+
Use @mkdir@:
|
155
|
+
|
156
|
+
<code><pre>
|
157
|
+
sftp.mkdir("/path/to/remote/dir", :permissions => 0500)
|
158
|
+
</pre></code>
|
159
|
+
|
160
|
+
- "I want to remove a directory...": |
|
161
|
+
Use @rmdir@:
|
162
|
+
|
163
|
+
<code><pre>
|
164
|
+
sftp.rmdir("/path/to/remote/dir")
|
165
|
+
</pre></code>
|
166
|
+
|
167
|
+
- "...delete a file?": |
|
168
|
+
Use @remove@:
|
169
|
+
|
170
|
+
<code><pre>
|
171
|
+
sftp.remove("/path/to/remote.file")
|
172
|
+
</pre></code>
|
173
|
+
|
174
|
+
- "...rename a file?": |
|
175
|
+
Use @rename@:
|
176
|
+
|
177
|
+
<code><pre>
|
178
|
+
sftp.rename("/path/to/remote.file", "/path/to/new.file")
|
179
|
+
</pre></code>
|
180
|
+
|
181
|
+
It should be noted that @rename@ is only supported by version 2 or
|
182
|
+
later of the SFTP protocol, so if you're using an older SFTP server you
|
183
|
+
might not be able to use this operation.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#--
|
2
|
+
# =============================================================================
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# This source file is distributed as part of the Net::SFTP Secure FTP Client
|
7
|
+
# library for Ruby. This file (and the library as a whole) may be used only as
|
8
|
+
# allowed by either the BSD license, or the Ruby license (or, by association
|
9
|
+
# with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SFTP
|
10
|
+
# distribution for the texts of these licenses.
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
# net-sftp website: http://net-ssh.rubyforge.org/sftp
|
13
|
+
# project website : http://rubyforge.org/projects/net-ssh
|
14
|
+
# =============================================================================
|
15
|
+
#++
|
16
|
+
|
17
|
+
$:.unshift "../lib"
|
18
|
+
require 'uri/open-sftp'
|
19
|
+
|
20
|
+
uri = URI.parse( "sftp://localhost" +
|
21
|
+
"/home/jgb3/temp/out" +
|
22
|
+
"?encryption=blowfish-cbc&compression=zlib" )
|
23
|
+
|
24
|
+
data = uri.open.read
|
25
|
+
p data.length
|
26
|
+
|
27
|
+
stream = uri.open( :chunk_size=>128,
|
28
|
+
:progress_proc => proc { |d| print "."; $stdout.flush } )
|
29
|
+
puts
|
30
|
+
p stream.read.length
|
data/examples/synchronous.rb
CHANGED
@@ -25,7 +25,9 @@ Net::SFTP.start( 'localhost',
|
|
25
25
|
handle = sftp.open_handle( "temp/out" )
|
26
26
|
puts "got handle: #{handle.inspect}"
|
27
27
|
puts "reading..."
|
28
|
-
data = sftp.read( handle
|
28
|
+
data = sftp.read( handle,
|
29
|
+
:chunk_size => 4*1024,
|
30
|
+
:progress_callback => proc { |data| puts " [#{data.length}]" } )
|
29
31
|
puts "got data: #{data.length} bytes"
|
30
32
|
sftp.close_handle( handle )
|
31
33
|
|
data/lib/net/sftp/errors.rb
CHANGED
@@ -24,22 +24,24 @@ module Net ; module SFTP ; module Operations
|
|
24
24
|
# file in one chunk.
|
25
25
|
class Read < Abstract
|
26
26
|
|
27
|
-
# The maximum amount of data to read at once when reading an entire
|
28
|
-
#
|
29
|
-
|
30
|
-
CHUNK_SIZE = 64 * 1024
|
27
|
+
# The default maximum amount of data to read at once when reading an entire
|
28
|
+
# file.
|
29
|
+
DEFAULT_CHUNK_SIZE = 64 * 1024
|
31
30
|
|
32
31
|
# Perform the operation. If length is less than 0 (the default), then the
|
33
32
|
# entire file (from the given offset) will be read and returned in "one
|
34
33
|
# fell swoop". Otherwise, the given length of data will be requested.
|
35
|
-
def perform( handle,
|
36
|
-
@length = length
|
34
|
+
def perform( handle, options={} )
|
35
|
+
@length = options[:length] || -1
|
37
36
|
@handle = handle
|
38
|
-
@offset = offset
|
37
|
+
@offset = options[:offset] || 0
|
38
|
+
@chunk_size = options[:chunk_size] || DEFAULT_CHUNK_SIZE
|
39
|
+
@progress_callback = options[:progress_callback]
|
39
40
|
@data = ""
|
40
41
|
|
41
|
-
real_length = ( length
|
42
|
-
|
42
|
+
real_length = ( @length >= 0 && @length < @chunk_size ?
|
43
|
+
@length : @chunk_size )
|
44
|
+
@driver.read( nil, @handle, @offset, real_length )
|
43
45
|
end
|
44
46
|
|
45
47
|
# Invoked when a data packet is received from the server. If the original
|
@@ -50,12 +52,14 @@ module Net ; module SFTP ; module Operations
|
|
50
52
|
@log.debug "[#{@id}] got #{data.length} bytes" if @log.debug?
|
51
53
|
|
52
54
|
@data << data
|
55
|
+
@progress_callback[@data] if @progress_callback
|
56
|
+
|
53
57
|
if @length < 0 || @data.length < @length
|
54
58
|
if @length < 0
|
55
|
-
length =
|
59
|
+
length = @chunk_size
|
56
60
|
else
|
57
61
|
length = @length - @data.length
|
58
|
-
length = length >
|
62
|
+
length = length > @chunk_size ? @chunk_size : length
|
59
63
|
end
|
60
64
|
|
61
65
|
@log.debug "[#{@id}] requesting #{length} more bytes" if @log.debug?
|
data/lib/net/sftp/session.rb
CHANGED
@@ -181,14 +181,14 @@ module Net ; module SFTP
|
|
181
181
|
def get_file( remote_path, local_path )
|
182
182
|
open_handle( remote_path ) do |handle|
|
183
183
|
contents = read( handle )
|
184
|
-
File.open( local_path, "
|
184
|
+
File.open( local_path, "wb" ) { |f| f.write contents }
|
185
185
|
end
|
186
186
|
end
|
187
187
|
|
188
188
|
# This stores the given local file at the given remote path. This will
|
189
189
|
# overwrite any file at the remote path name. The local file must exist.
|
190
190
|
def put_file( local_path, remote_path )
|
191
|
-
contents = File.
|
191
|
+
contents = File.open( local_path, "rb" ) { |f| f.read }
|
192
192
|
open_handle( remote_path, "w" ) { |handle| write( handle, contents ) }
|
193
193
|
end
|
194
194
|
|
data/lib/net/sftp/version.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
# =======================================================================
|
2
|
+
# Net::SSH -- A Ruby module implementing the SSH2 client protocol
|
3
|
+
# Copyright (C) 2004 Jamis Buck (jgb3@email.byu.edu)
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
# =======================================================================
|
19
|
+
|
20
|
+
require 'open-uri'
|
21
|
+
require 'uri/sftp'
|
22
|
+
require 'net/sftp'
|
23
|
+
|
24
|
+
OpenURI::Options[ :chunk_size ] = true
|
25
|
+
|
26
|
+
module URI
|
27
|
+
|
28
|
+
class SFTP
|
29
|
+
def direct_open( buf, open_options )
|
30
|
+
Net::SFTP.start( host, port, user, password, options ) do |sftp|
|
31
|
+
if open_options[:content_length_proc]
|
32
|
+
open_options[:content_length_proc].call( sftp.lstat( path ).size )
|
33
|
+
end
|
34
|
+
|
35
|
+
body = nil
|
36
|
+
sftp.open_handle( path ) do |handle|
|
37
|
+
body = sftp.read( handle,
|
38
|
+
:chunk_size => open_options[:chunk_size],
|
39
|
+
:progress_callback => open_options[:progress_proc] )
|
40
|
+
end
|
41
|
+
|
42
|
+
if body.nil?
|
43
|
+
raise Net::SSH::SFTP::SFTPError, sftp.status[:message]
|
44
|
+
end
|
45
|
+
|
46
|
+
buf << body
|
47
|
+
buf.io.rewind
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
include OpenURI::OpenRead
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/uri/sftp.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'uri/generic'
|
2
|
+
|
3
|
+
module URI
|
4
|
+
|
5
|
+
class SFTP < Generic
|
6
|
+
DEFAULT_PORT = 22
|
7
|
+
|
8
|
+
COMPONENT = [
|
9
|
+
:scheme,
|
10
|
+
:userinfo,
|
11
|
+
:host, :port, :path,
|
12
|
+
:query
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
attr_reader :options
|
16
|
+
|
17
|
+
def self.new2( user, password, host, port, path, query )
|
18
|
+
new( 'sftp',
|
19
|
+
[ user, password ],
|
20
|
+
host, port,
|
21
|
+
nil, path,
|
22
|
+
nil, query )
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize( *args )
|
26
|
+
super( *args )
|
27
|
+
|
28
|
+
@options = Hash.new
|
29
|
+
( query || "" ).split( /&/ ).each do |pair|
|
30
|
+
name, value = pair.split( /=/ )
|
31
|
+
opt_name = name.intern
|
32
|
+
values = value.split( /,/ ).map { |v| v.to_i.to_s == v ? v.to_i : v }
|
33
|
+
values = values.first if values.length == 1
|
34
|
+
options[ opt_name ] = values
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
@@schemes['SFTP'] = SFTP
|
41
|
+
|
42
|
+
end
|
data/test/operations/tc_read.rb
CHANGED
@@ -45,7 +45,7 @@ class TC_Operations_Read < Test::Unit::TestCase
|
|
45
45
|
def test_perform_explicit
|
46
46
|
id = handle = offset = length = nil
|
47
47
|
@driver.mock_handle( :read ) { |i,h,o,l| id, handle, offset, length = i, h, o, l; 10 }
|
48
|
-
assert_equal 10, @operation.perform( "foo", 15, 72 )
|
48
|
+
assert_equal 10, @operation.perform( "foo", :offset=>15, :length=>72 )
|
49
49
|
assert_nil id
|
50
50
|
assert_equal "foo", handle
|
51
51
|
assert_equal 15, offset
|
@@ -72,7 +72,7 @@ class TC_Operations_Read < Test::Unit::TestCase
|
|
72
72
|
@session.mock_handle( :loop )
|
73
73
|
@session.mock_handle( :status= )
|
74
74
|
called = false
|
75
|
-
@operation.execute( "foo", 15, 20 ) { called = true }
|
75
|
+
@operation.execute( "foo", :offset=>15, :length=>20 ) { called = true }
|
76
76
|
@operation.do_data( "harbinger of doom" )
|
77
77
|
@operation.do_data( "abc" )
|
78
78
|
assert_equal 2, @driver.mock_count( :read )
|
@@ -89,7 +89,7 @@ class TC_Operations_Read < Test::Unit::TestCase
|
|
89
89
|
@session.mock_handle( :loop )
|
90
90
|
@session.mock_handle( :status= )
|
91
91
|
called = false
|
92
|
-
@operation.execute( "foo", 15, 20 ) { called = true }
|
92
|
+
@operation.execute( "foo", :offset=>15, :length=>20 ) { called = true }
|
93
93
|
assert_nothing_raised { @operation.do_status( 1, nil, nil ) }
|
94
94
|
assert called
|
95
95
|
end
|
@@ -126,7 +126,7 @@ class TC_01_Attributes < Test::Unit::TestCase
|
|
126
126
|
[ { :mtime => 789012 }, :mtime, 789012 ],
|
127
127
|
[ { :extended => { "foo" => "bar" } }, :extended, { "foo" => "bar" } ],
|
128
128
|
[ { :owner => ENV['USER'] }, :uid, Etc.getpwnam(ENV['USER']).uid ],
|
129
|
-
[ { :group => '
|
129
|
+
[ { :group => 'wheel' }, :gid, Etc.getgrnam('wheel').gid ]
|
130
130
|
].each do |fixture|
|
131
131
|
define_method( "test_from_hash_#{fixture[1]}" ) do
|
132
132
|
attrs = @factory.from_hash( fixture[0] )
|
@@ -150,9 +150,9 @@ class TC_04_Attributes < Test::Unit::TestCase
|
|
150
150
|
[ { :type => 3 }, :type, 3 ],
|
151
151
|
[ { :size => 1000 }, :size, 1000, :permissions ],
|
152
152
|
[ { :owner => ENV['USER'] }, :owner, ENV['USER'] ],
|
153
|
-
[ { :group => '
|
153
|
+
[ { :group => 'wheel' }, :group, 'wheel' ],
|
154
154
|
[ { :uid => Etc.getpwnam(ENV['USER']).uid }, :owner, ENV['USER'] ],
|
155
|
-
[ { :gid => Etc.getgrnam('
|
155
|
+
[ { :gid => Etc.getgrnam('wheel').gid }, :group, 'wheel' ],
|
156
156
|
[ { :permissions => 0600 }, :permissions, 0600 ],
|
157
157
|
[ { :atime => 1 }, :atime, 1 ],
|
158
158
|
[ { :atime_nseconds => 2 }, :atime_nseconds, 2 ],
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.10
|
3
3
|
specification_version: 1
|
4
4
|
name: net-sftp
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2005-
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2005-06-17
|
8
8
|
summary: Net::SFTP is a pure-Ruby implementation of the SFTP client protocol.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
|
-
email:
|
11
|
+
email: jamis@jamisbuck.org
|
12
12
|
homepage: http://net-ssh.rubyforge.org/sftp
|
13
13
|
rubyforge_project:
|
14
14
|
description:
|
@@ -27,98 +27,106 @@ platform: ruby
|
|
27
27
|
authors:
|
28
28
|
- Jamis Buck
|
29
29
|
files:
|
30
|
-
- doc/
|
30
|
+
- doc/faq
|
31
31
|
- doc/LICENSE-BSD
|
32
32
|
- doc/LICENSE-GPL
|
33
|
+
- doc/LICENSE-RUBY
|
34
|
+
- doc/faq/faq.html
|
35
|
+
- doc/faq/faq.rb
|
36
|
+
- doc/faq/faq.yml
|
33
37
|
- lib/net
|
38
|
+
- lib/uri
|
34
39
|
- lib/net/sftp
|
35
40
|
- lib/net/sftp.rb
|
41
|
+
- lib/net/sftp/errors.rb
|
36
42
|
- lib/net/sftp/operations
|
37
|
-
- lib/net/sftp/session.rb
|
38
43
|
- lib/net/sftp/protocol
|
44
|
+
- lib/net/sftp/session.rb
|
39
45
|
- lib/net/sftp/version.rb
|
40
|
-
- lib/net/sftp/
|
46
|
+
- lib/net/sftp/operations/abstract.rb
|
41
47
|
- lib/net/sftp/operations/close.rb
|
42
|
-
- lib/net/sftp/operations/
|
43
|
-
- lib/net/sftp/operations/
|
44
|
-
- lib/net/sftp/operations/
|
45
|
-
- lib/net/sftp/operations/stat.rb
|
46
|
-
- lib/net/sftp/operations/readdir.rb
|
48
|
+
- lib/net/sftp/operations/errors.rb
|
49
|
+
- lib/net/sftp/operations/fsetstat.rb
|
50
|
+
- lib/net/sftp/operations/fstat.rb
|
47
51
|
- lib/net/sftp/operations/lstat.rb
|
48
|
-
- lib/net/sftp/operations/setstat.rb
|
49
|
-
- lib/net/sftp/operations/abstract.rb
|
50
52
|
- lib/net/sftp/operations/mkdir.rb
|
51
|
-
- lib/net/sftp/operations/services.rb
|
52
53
|
- lib/net/sftp/operations/open.rb
|
53
54
|
- lib/net/sftp/operations/opendir.rb
|
54
|
-
- lib/net/sftp/operations/
|
55
|
+
- lib/net/sftp/operations/read.rb
|
56
|
+
- lib/net/sftp/operations/readdir.rb
|
57
|
+
- lib/net/sftp/operations/realpath.rb
|
55
58
|
- lib/net/sftp/operations/remove.rb
|
56
|
-
- lib/net/sftp/operations/
|
59
|
+
- lib/net/sftp/operations/rename.rb
|
60
|
+
- lib/net/sftp/operations/rmdir.rb
|
61
|
+
- lib/net/sftp/operations/services.rb
|
62
|
+
- lib/net/sftp/operations/setstat.rb
|
63
|
+
- lib/net/sftp/operations/stat.rb
|
57
64
|
- lib/net/sftp/operations/write.rb
|
58
|
-
- lib/net/sftp/operations/fstat.rb
|
59
|
-
- lib/net/sftp/operations/errors.rb
|
60
65
|
- lib/net/sftp/protocol/01
|
61
66
|
- lib/net/sftp/protocol/02
|
62
67
|
- lib/net/sftp/protocol/03
|
63
68
|
- lib/net/sftp/protocol/04
|
64
69
|
- lib/net/sftp/protocol/05
|
65
|
-
- lib/net/sftp/protocol/driver.rb
|
66
70
|
- lib/net/sftp/protocol/constants.rb
|
71
|
+
- lib/net/sftp/protocol/driver.rb
|
67
72
|
- lib/net/sftp/protocol/packet-assistant.rb
|
68
73
|
- lib/net/sftp/protocol/services.rb
|
69
74
|
- lib/net/sftp/protocol/01/attributes.rb
|
75
|
+
- lib/net/sftp/protocol/01/impl.rb
|
70
76
|
- lib/net/sftp/protocol/01/packet-assistant.rb
|
71
77
|
- lib/net/sftp/protocol/01/services.rb
|
72
|
-
- lib/net/sftp/protocol/
|
78
|
+
- lib/net/sftp/protocol/02/impl.rb
|
73
79
|
- lib/net/sftp/protocol/02/packet-assistant.rb
|
74
80
|
- lib/net/sftp/protocol/02/services.rb
|
75
|
-
- lib/net/sftp/protocol/
|
81
|
+
- lib/net/sftp/protocol/03/impl.rb
|
76
82
|
- lib/net/sftp/protocol/03/packet-assistant.rb
|
77
83
|
- lib/net/sftp/protocol/03/services.rb
|
78
|
-
- lib/net/sftp/protocol/03/impl.rb
|
79
84
|
- lib/net/sftp/protocol/04/attributes.rb
|
85
|
+
- lib/net/sftp/protocol/04/impl.rb
|
80
86
|
- lib/net/sftp/protocol/04/packet-assistant.rb
|
81
87
|
- lib/net/sftp/protocol/04/services.rb
|
82
|
-
- lib/net/sftp/protocol/04/impl.rb
|
83
88
|
- lib/net/sftp/protocol/05/services.rb
|
89
|
+
- lib/uri/open-sftp.rb
|
90
|
+
- lib/uri/sftp.rb
|
91
|
+
- examples/asynchronous.rb
|
84
92
|
- examples/get-put.rb
|
93
|
+
- examples/sftp-open-uri.rb
|
85
94
|
- examples/ssh-service.rb
|
86
95
|
- examples/synchronous.rb
|
87
|
-
- examples/asynchronous.rb
|
88
|
-
- test/operations
|
89
96
|
- test/ALL-TESTS.rb
|
97
|
+
- test/operations
|
90
98
|
- test/protocol
|
91
|
-
- test/operations/tc_write.rb
|
92
|
-
- test/operations/tc_fstat.rb
|
93
|
-
- test/operations/tc_close.rb
|
94
99
|
- test/operations/tc_abstract.rb
|
95
|
-
- test/operations/
|
96
|
-
- test/operations/tc_rmdir.rb
|
97
|
-
- test/operations/tc_open.rb
|
98
|
-
- test/operations/tc_remove.rb
|
99
|
-
- test/operations/tc_read.rb
|
100
|
+
- test/operations/tc_close.rb
|
100
101
|
- test/operations/tc_fsetstat.rb
|
102
|
+
- test/operations/tc_fstat.rb
|
101
103
|
- test/operations/tc_lstat.rb
|
102
|
-
- test/operations/tc_readdir.rb
|
103
104
|
- test/operations/tc_mkdir.rb
|
105
|
+
- test/operations/tc_open.rb
|
106
|
+
- test/operations/tc_opendir.rb
|
107
|
+
- test/operations/tc_read.rb
|
108
|
+
- test/operations/tc_readdir.rb
|
104
109
|
- test/operations/tc_realpath.rb
|
105
|
-
- test/operations/
|
110
|
+
- test/operations/tc_remove.rb
|
111
|
+
- test/operations/tc_rmdir.rb
|
106
112
|
- test/operations/tc_setstat.rb
|
113
|
+
- test/operations/tc_stat.rb
|
114
|
+
- test/operations/tc_write.rb
|
107
115
|
- test/protocol/01
|
108
116
|
- test/protocol/02
|
109
117
|
- test/protocol/03
|
110
118
|
- test/protocol/04
|
111
119
|
- test/protocol/tc_driver.rb
|
112
|
-
- test/protocol/01/tc_packet_assistant.rb
|
113
120
|
- test/protocol/01/tc_attributes.rb
|
114
121
|
- test/protocol/01/tc_impl.rb
|
115
|
-
- test/protocol/
|
122
|
+
- test/protocol/01/tc_packet_assistant.rb
|
116
123
|
- test/protocol/02/tc_impl.rb
|
117
|
-
- test/protocol/
|
124
|
+
- test/protocol/02/tc_packet_assistant.rb
|
118
125
|
- test/protocol/03/tc_impl.rb
|
119
|
-
- test/protocol/
|
126
|
+
- test/protocol/03/tc_packet_assistant.rb
|
120
127
|
- test/protocol/04/tc_attributes.rb
|
121
128
|
- test/protocol/04/tc_impl.rb
|
129
|
+
- test/protocol/04/tc_packet_assistant.rb
|
122
130
|
test_files:
|
123
131
|
- test/ALL-TESTS.rb
|
124
132
|
rdoc_options: []
|