net-sftp 1.1.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +23 -0
- data/Manifest +55 -0
- data/README.rdoc +96 -0
- data/Rakefile +30 -0
- data/lib/net/sftp.rb +53 -38
- data/lib/net/sftp/constants.rb +187 -0
- data/lib/net/sftp/errors.rb +34 -20
- data/lib/net/sftp/operations/dir.rb +93 -0
- data/lib/net/sftp/operations/download.rb +364 -0
- data/lib/net/sftp/operations/file.rb +176 -0
- data/lib/net/sftp/operations/file_factory.rb +60 -0
- data/lib/net/sftp/operations/upload.rb +387 -0
- data/lib/net/sftp/packet.rb +21 -0
- data/lib/net/sftp/protocol.rb +32 -0
- data/lib/net/sftp/protocol/01/attributes.rb +265 -96
- data/lib/net/sftp/protocol/01/base.rb +268 -0
- data/lib/net/sftp/protocol/01/name.rb +43 -0
- data/lib/net/sftp/protocol/02/base.rb +31 -0
- data/lib/net/sftp/protocol/03/base.rb +35 -0
- data/lib/net/sftp/protocol/04/attributes.rb +120 -195
- data/lib/net/sftp/protocol/04/base.rb +94 -0
- data/lib/net/sftp/protocol/04/name.rb +67 -0
- data/lib/net/sftp/protocol/05/base.rb +66 -0
- data/lib/net/sftp/protocol/06/attributes.rb +107 -0
- data/lib/net/sftp/protocol/06/base.rb +63 -0
- data/lib/net/sftp/protocol/base.rb +50 -0
- data/lib/net/sftp/request.rb +91 -0
- data/lib/net/sftp/response.rb +76 -0
- data/lib/net/sftp/session.rb +914 -238
- data/lib/net/sftp/version.rb +14 -21
- data/net-sftp.gemspec +60 -0
- data/setup.rb +1331 -0
- data/test/common.rb +173 -0
- data/test/protocol/01/test_attributes.rb +97 -0
- data/test/protocol/01/test_base.rb +210 -0
- data/test/protocol/01/test_name.rb +27 -0
- data/test/protocol/02/test_base.rb +26 -0
- data/test/protocol/03/test_base.rb +27 -0
- data/test/protocol/04/test_attributes.rb +148 -0
- data/test/protocol/04/test_base.rb +74 -0
- data/test/protocol/04/test_name.rb +49 -0
- data/test/protocol/05/test_base.rb +62 -0
- data/test/protocol/06/test_attributes.rb +124 -0
- data/test/protocol/06/test_base.rb +51 -0
- data/test/protocol/test_base.rb +42 -0
- data/test/test_all.rb +3 -0
- data/test/test_dir.rb +47 -0
- data/test/test_download.rb +252 -0
- data/test/test_file.rb +159 -0
- data/test/test_file_factory.rb +48 -0
- data/test/test_packet.rb +9 -0
- data/test/test_protocol.rb +17 -0
- data/test/test_request.rb +71 -0
- data/test/test_response.rb +53 -0
- data/test/test_session.rb +741 -0
- data/test/test_upload.rb +219 -0
- metadata +59 -111
- data/doc/LICENSE-BSD +0 -27
- data/doc/LICENSE-GPL +0 -280
- data/doc/LICENSE-RUBY +0 -56
- data/doc/faq/faq.html +0 -298
- data/doc/faq/faq.rb +0 -154
- data/doc/faq/faq.yml +0 -183
- data/examples/asynchronous.rb +0 -57
- data/examples/get-put.rb +0 -45
- data/examples/sftp-open-uri.rb +0 -30
- data/examples/ssh-service.rb +0 -30
- data/examples/synchronous.rb +0 -131
- data/lib/net/sftp/operations/abstract.rb +0 -108
- data/lib/net/sftp/operations/close.rb +0 -31
- data/lib/net/sftp/operations/errors.rb +0 -76
- data/lib/net/sftp/operations/fsetstat.rb +0 -36
- data/lib/net/sftp/operations/fstat.rb +0 -32
- data/lib/net/sftp/operations/lstat.rb +0 -31
- data/lib/net/sftp/operations/mkdir.rb +0 -33
- data/lib/net/sftp/operations/open.rb +0 -32
- data/lib/net/sftp/operations/opendir.rb +0 -32
- data/lib/net/sftp/operations/read.rb +0 -88
- data/lib/net/sftp/operations/readdir.rb +0 -55
- data/lib/net/sftp/operations/realpath.rb +0 -37
- data/lib/net/sftp/operations/remove.rb +0 -31
- data/lib/net/sftp/operations/rename.rb +0 -32
- data/lib/net/sftp/operations/rmdir.rb +0 -31
- data/lib/net/sftp/operations/services.rb +0 -42
- data/lib/net/sftp/operations/setstat.rb +0 -33
- data/lib/net/sftp/operations/stat.rb +0 -31
- data/lib/net/sftp/operations/write.rb +0 -63
- data/lib/net/sftp/protocol/01/impl.rb +0 -251
- data/lib/net/sftp/protocol/01/packet-assistant.rb +0 -82
- data/lib/net/sftp/protocol/01/services.rb +0 -47
- data/lib/net/sftp/protocol/02/impl.rb +0 -39
- data/lib/net/sftp/protocol/02/packet-assistant.rb +0 -32
- data/lib/net/sftp/protocol/02/services.rb +0 -44
- data/lib/net/sftp/protocol/03/impl.rb +0 -42
- data/lib/net/sftp/protocol/03/packet-assistant.rb +0 -35
- data/lib/net/sftp/protocol/03/services.rb +0 -44
- data/lib/net/sftp/protocol/04/impl.rb +0 -86
- data/lib/net/sftp/protocol/04/packet-assistant.rb +0 -45
- data/lib/net/sftp/protocol/04/services.rb +0 -44
- data/lib/net/sftp/protocol/05/impl.rb +0 -90
- data/lib/net/sftp/protocol/05/packet-assistant.rb +0 -34
- data/lib/net/sftp/protocol/05/services.rb +0 -44
- data/lib/net/sftp/protocol/constants.rb +0 -60
- data/lib/net/sftp/protocol/driver.rb +0 -235
- data/lib/net/sftp/protocol/packet-assistant.rb +0 -84
- data/lib/net/sftp/protocol/services.rb +0 -55
- data/lib/uri/open-sftp.rb +0 -54
- data/lib/uri/sftp.rb +0 -42
- data/test/ALL-TESTS.rb +0 -23
- data/test/operations/tc_abstract.rb +0 -124
- data/test/operations/tc_close.rb +0 -40
- data/test/operations/tc_fsetstat.rb +0 -48
- data/test/operations/tc_fstat.rb +0 -40
- data/test/operations/tc_lstat.rb +0 -40
- data/test/operations/tc_mkdir.rb +0 -48
- data/test/operations/tc_open.rb +0 -42
- data/test/operations/tc_opendir.rb +0 -40
- data/test/operations/tc_read.rb +0 -103
- data/test/operations/tc_readdir.rb +0 -88
- data/test/operations/tc_realpath.rb +0 -54
- data/test/operations/tc_remove.rb +0 -40
- data/test/operations/tc_rmdir.rb +0 -40
- data/test/operations/tc_setstat.rb +0 -48
- data/test/operations/tc_stat.rb +0 -40
- data/test/operations/tc_write.rb +0 -91
- data/test/protocol/01/tc_attributes.rb +0 -138
- data/test/protocol/01/tc_impl.rb +0 -294
- data/test/protocol/01/tc_packet_assistant.rb +0 -81
- data/test/protocol/02/tc_impl.rb +0 -41
- data/test/protocol/02/tc_packet_assistant.rb +0 -31
- data/test/protocol/03/tc_impl.rb +0 -48
- data/test/protocol/03/tc_packet_assistant.rb +0 -34
- data/test/protocol/04/tc_attributes.rb +0 -174
- data/test/protocol/04/tc_impl.rb +0 -91
- data/test/protocol/04/tc_packet_assistant.rb +0 -38
- data/test/protocol/05/tc_impl.rb +0 -61
- data/test/protocol/05/tc_packet_assistant.rb +0 -32
- data/test/protocol/tc_driver.rb +0 -219
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'net/ssh/loggable'
|
2
|
+
require 'net/sftp/constants'
|
3
|
+
require 'net/sftp/packet'
|
4
|
+
require 'net/sftp/protocol/base'
|
5
|
+
require 'net/sftp/protocol/01/attributes'
|
6
|
+
require 'net/sftp/protocol/01/name'
|
7
|
+
|
8
|
+
module Net; module SFTP; module Protocol; module V01
|
9
|
+
|
10
|
+
# Wraps the low-level SFTP calls for version 1 of the SFTP protocol. Also
|
11
|
+
# implements the packet parsing as defined by version 1 of the protocol.
|
12
|
+
#
|
13
|
+
# None of these protocol methods block--all of them return immediately,
|
14
|
+
# requiring the SSH event loop to be run while the server response is
|
15
|
+
# pending.
|
16
|
+
#
|
17
|
+
# You will almost certainly never need to use this driver directly. Please
|
18
|
+
# see Net::SFTP::Session for the recommended interface.
|
19
|
+
class Base < Protocol::Base
|
20
|
+
include Net::SFTP::Constants::OpenFlags
|
21
|
+
|
22
|
+
# Returns the protocol version implemented by this driver. (1, in this
|
23
|
+
# case)
|
24
|
+
def version
|
25
|
+
1
|
26
|
+
end
|
27
|
+
|
28
|
+
# Parses the given FXP_HANDLE packet and returns a hash with one key,
|
29
|
+
# :handle, which references the handle.
|
30
|
+
def parse_handle_packet(packet)
|
31
|
+
{ :handle => packet.read_string }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Parses the given FXP_STATUS packet and returns a hash with one key,
|
35
|
+
# :code, which references the status code returned by the server.
|
36
|
+
def parse_status_packet(packet)
|
37
|
+
{ :code => packet.read_long }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Parses the given FXP_DATA packet and returns a hash with one key,
|
41
|
+
# :data, which references the data returned in the packet.
|
42
|
+
def parse_data_packet(packet)
|
43
|
+
{ :data => packet.read_string }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Parses the given FXP_ATTRS packet and returns a hash with one key,
|
47
|
+
# :attrs, which references an Attributes object.
|
48
|
+
def parse_attrs_packet(packet)
|
49
|
+
{ :attrs => attribute_factory.from_buffer(packet) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Parses the given FXP_NAME packet and returns a hash with one key, :names,
|
53
|
+
# which references an array of Name objects.
|
54
|
+
def parse_name_packet(packet)
|
55
|
+
names = []
|
56
|
+
|
57
|
+
packet.read_long.times do
|
58
|
+
filename = packet.read_string
|
59
|
+
longname = packet.read_string
|
60
|
+
attrs = attribute_factory.from_buffer(packet)
|
61
|
+
names << name_factory.new(filename, longname, attrs)
|
62
|
+
end
|
63
|
+
|
64
|
+
{ :names => names }
|
65
|
+
end
|
66
|
+
|
67
|
+
# Sends a FXP_OPEN packet to the server and returns the packet identifier.
|
68
|
+
# The +flags+ parameter is either an integer (in which case it must be
|
69
|
+
# a combination of the IO constants) or a string (in which case it must
|
70
|
+
# be one of the mode strings that IO::open accepts). The +options+
|
71
|
+
# parameter is a hash that is used to construct a new Attribute object,
|
72
|
+
# to pass as part of the FXP_OPEN request.
|
73
|
+
def open(path, flags, options)
|
74
|
+
flags = normalize_open_flags(flags)
|
75
|
+
|
76
|
+
if flags & (IO::WRONLY | IO::RDWR) != 0
|
77
|
+
sftp_flags = FV1::WRITE
|
78
|
+
sftp_flags |= FV1::READ if flags & IO::RDWR != 0
|
79
|
+
sftp_flags |= FV1::APPEND if flags & IO::APPEND != 0
|
80
|
+
else
|
81
|
+
sftp_flags = FV1::READ
|
82
|
+
end
|
83
|
+
|
84
|
+
sftp_flags |= FV1::CREAT if flags & IO::CREAT != 0
|
85
|
+
sftp_flags |= FV1::TRUNC if flags & IO::TRUNC != 0
|
86
|
+
sftp_flags |= FV1::EXCL if flags & IO::EXCL != 0
|
87
|
+
|
88
|
+
attributes = attribute_factory.new(options)
|
89
|
+
|
90
|
+
send_request(FXP_OPEN, :string, path, :long, sftp_flags, :raw, attributes.to_s)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Sends a FXP_CLOSE packet to the server for the given +handle+ (such as
|
94
|
+
# would be returned via a FXP_HANDLE packet). Returns the new packet id.
|
95
|
+
def close(handle)
|
96
|
+
send_request(FXP_CLOSE, :string, handle)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Sends a FXP_READ packet to the server, requesting that +length+ bytes
|
100
|
+
# be read from the file identified by +handle+, starting at +offset+ bytes
|
101
|
+
# within the file. The handle must be one that was returned via a
|
102
|
+
# FXP_HANDLE packet. Returns the new packet id.
|
103
|
+
def read(handle, offset, length)
|
104
|
+
send_request(FXP_READ, :string, handle, :int64, offset, :long, length)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Sends a FXP_WRITE packet to the server, requesting that +data+ (a string),
|
108
|
+
# be written to the file identified by +handle+, starting at +offset+ bytes
|
109
|
+
# from the beginning of the file. The handle must be one that was returned
|
110
|
+
# via a FXP_HANDLE packet. Returns the new packet id.
|
111
|
+
def write(handle, offset, data)
|
112
|
+
send_request(FXP_WRITE, :string, handle, :int64, offset, :string, data)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Sends a FXP_LSTAT packet to the server, requesting a FXP_ATTR response
|
116
|
+
# for the file at the given remote +path+ (a string). The +flags+ parameter
|
117
|
+
# is ignored in this version of the protocol. #lstat will not follow
|
118
|
+
# symbolic links; see #stat for a version that will.
|
119
|
+
def lstat(path, flags=nil)
|
120
|
+
send_request(FXP_LSTAT, :string, path)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Sends a FXP_FSTAT packet to the server, requesting a FXP_ATTR response
|
124
|
+
# for the file represented by the given +handle+ (which must have been
|
125
|
+
# obtained from a FXP_HANDLE packet). The +flags+ parameter is ignored in
|
126
|
+
# this version of the protocol.
|
127
|
+
def fstat(handle, flags=nil)
|
128
|
+
send_request(FXP_FSTAT, :string, handle)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Sends a FXP_SETSTAT packet to the server, to update the attributes for
|
132
|
+
# the file at the given remote +path+ (a string). The +attrs+ parameter is
|
133
|
+
# a hash that defines the attributes to set.
|
134
|
+
def setstat(path, attrs)
|
135
|
+
send_request(FXP_SETSTAT, :string, path, :raw, attribute_factory.new(attrs).to_s)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Sends a FXP_FSETSTAT packet to the server, to update the attributes for
|
139
|
+
# the file represented by the given +handle+ (which must have been obtained
|
140
|
+
# from a FXP_HANDLE packet). The +attrs+ parameter is a hash that defines
|
141
|
+
# the attributes to set.
|
142
|
+
def fsetstat(handle, attrs)
|
143
|
+
send_request(FXP_FSETSTAT, :string, handle, :raw, attribute_factory.new(attrs).to_s)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Sends a FXP_OPENDIR packet to the server, to request a handle for
|
147
|
+
# manipulating the directory at the given remote +path+.
|
148
|
+
def opendir(path)
|
149
|
+
send_request(FXP_OPENDIR, :string, path)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Sends a FXP_READDIR packet to the server, to request a batch of
|
153
|
+
# directory name entries in the directory identified by +handle+ (which
|
154
|
+
# must have been obtained via a FXP_OPENDIR request).
|
155
|
+
def readdir(handle)
|
156
|
+
send_request(FXP_READDIR, :string, handle)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Sends a FXP_REMOTE packet to the server, to request that the given
|
160
|
+
# file be deleted from the remote server.
|
161
|
+
def remove(filename)
|
162
|
+
send_request(FXP_REMOVE, :string, filename)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Sends a FXP_MKDIR packet to the server, to request that a new directory
|
166
|
+
# at +path+ on the remote server be created, and with +attrs+ (a hash)
|
167
|
+
# describing the attributes of the new directory.
|
168
|
+
def mkdir(path, attrs)
|
169
|
+
send_request(FXP_MKDIR, :string, path, :raw, attribute_factory.new(attrs).to_s)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Sends a FXP_RMDIR packet to the server, to request that the directory
|
173
|
+
# at +path+ on the remote server be deleted.
|
174
|
+
def rmdir(path)
|
175
|
+
send_request(FXP_RMDIR, :string, path)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Sends a FXP_REALPATH packet to the server, to request that the given
|
179
|
+
# +path+ be canonicalized, taking into account path segments like "..".
|
180
|
+
def realpath(path)
|
181
|
+
send_request(FXP_REALPATH, :string, path)
|
182
|
+
end
|
183
|
+
|
184
|
+
# Sends a FXP_STAT packet to the server, requesting a FXP_ATTR response
|
185
|
+
# for the file at the given remote +path+ (a string). The +flags+ parameter
|
186
|
+
# is ignored in this version of the protocol. #stat will follow
|
187
|
+
# symbolic links; see #lstat for a version that will not.
|
188
|
+
def stat(path, flags=nil)
|
189
|
+
send_request(FXP_STAT, :string, path)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Not implemented in version 1 of the SFTP protocol. Raises a
|
193
|
+
# NotImplementedError if called.
|
194
|
+
def rename(name, new_name, flags=nil)
|
195
|
+
not_implemented! :rename
|
196
|
+
end
|
197
|
+
|
198
|
+
# Not implemented in version 1 of the SFTP protocol. Raises a
|
199
|
+
# NotImplementedError if called.
|
200
|
+
def readlink(path)
|
201
|
+
not_implemented! :readlink
|
202
|
+
end
|
203
|
+
|
204
|
+
# Not implemented in version 1 of the SFTP protocol. Raises a
|
205
|
+
# NotImplementedError if called.
|
206
|
+
def symlink(path, target)
|
207
|
+
not_implemented! :symlink
|
208
|
+
end
|
209
|
+
|
210
|
+
# Not implemented in version 1 of the SFTP protocol. Raises a
|
211
|
+
# NotImplementedError if called.
|
212
|
+
def link(*args)
|
213
|
+
not_implemented! :link
|
214
|
+
end
|
215
|
+
|
216
|
+
# Not implemented in version 1 of the SFTP protocol. Raises a
|
217
|
+
# NotImplementedError if called.
|
218
|
+
def block(handle, offset, length, mask)
|
219
|
+
not_implemented! :block
|
220
|
+
end
|
221
|
+
|
222
|
+
# Not implemented in version 1 of the SFTP protocol. Raises a
|
223
|
+
# NotImplementedError if called.
|
224
|
+
def unblock(handle, offset, length)
|
225
|
+
not_implemented! :unblock
|
226
|
+
end
|
227
|
+
|
228
|
+
protected
|
229
|
+
|
230
|
+
# A helper method for implementing wrappers for operations that are
|
231
|
+
# not implemented by the current SFTP protocol version. Simply raises
|
232
|
+
# NotImplementedError with a message based on the given operation name.
|
233
|
+
def not_implemented!(operation)
|
234
|
+
raise NotImplementedError, "the #{operation} operation is not available in the version of the SFTP protocol supported by your server"
|
235
|
+
end
|
236
|
+
|
237
|
+
# Normalizes the given flags parameter, converting it into a combination
|
238
|
+
# of IO constants.
|
239
|
+
def normalize_open_flags(flags)
|
240
|
+
if String === flags
|
241
|
+
case flags.tr("b", "")
|
242
|
+
when "r" then IO::RDONLY
|
243
|
+
when "r+" then IO::RDWR
|
244
|
+
when "w" then IO::WRONLY | IO::TRUNC | IO::CREAT
|
245
|
+
when "w+" then IO::RDWR | IO::TRUNC | IO::CREAT
|
246
|
+
when "a" then IO::APPEND | IO::CREAT | IO::WRONLY
|
247
|
+
when "a+" then IO::APPEND | IO::CREAT | IO::RDWR
|
248
|
+
else raise ArgumentError, "unsupported flags: #{flags.inspect}"
|
249
|
+
end
|
250
|
+
else
|
251
|
+
flags.to_i
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Returns the Attributes class used by this version of the protocol
|
256
|
+
# (Net::SFTP::Protocol::V01::Attributes, in this case)
|
257
|
+
def attribute_factory
|
258
|
+
V01::Attributes
|
259
|
+
end
|
260
|
+
|
261
|
+
# Returns the Name class used by this version of the protocol
|
262
|
+
# (Net::SFTP::Protocol::V01::Name, in this case)
|
263
|
+
def name_factory
|
264
|
+
V01::Name
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
end; end; end; end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Net; module SFTP; module Protocol; module V01
|
2
|
+
|
3
|
+
# Represents a single named item on the remote server. This includes the
|
4
|
+
# name, attributes about the item, and the "longname", which is intended
|
5
|
+
# for use when displaying directory data, and has no specified format.
|
6
|
+
class Name
|
7
|
+
# The name of the item on the remote server.
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
# The display-ready name of the item, possibly with other attributes.
|
11
|
+
attr_reader :longname
|
12
|
+
|
13
|
+
# The Attributes object describing this item.
|
14
|
+
attr_reader :attributes
|
15
|
+
|
16
|
+
# Create a new Name object with the given name, longname, and attributes.
|
17
|
+
def initialize(name, longname, attributes)
|
18
|
+
@name, @longname, @attributes = name, longname, attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns +true+ if the item appears to be a directory. It does this by
|
22
|
+
# examining the attributes. If there is insufficient information in the
|
23
|
+
# attributes, this will return nil, rather than a boolean.
|
24
|
+
def directory?
|
25
|
+
attributes.directory?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns +true+ if the item appears to be a symlink. It does this by
|
29
|
+
# examining the attributes. If there is insufficient information in the
|
30
|
+
# attributes, this will return nil, rather than a boolean.
|
31
|
+
def symlink?
|
32
|
+
attributes.symlink?
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns +true+ if the item appears to be a regular file. It does this by
|
36
|
+
# examining the attributes. If there is insufficient information in the
|
37
|
+
# attributes, this will return nil, rather than a boolean.
|
38
|
+
def file?
|
39
|
+
attributes.file?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end; end; end; end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'net/sftp/protocol/01/base'
|
2
|
+
|
3
|
+
module Net; module SFTP; module Protocol; module V02
|
4
|
+
|
5
|
+
# Wraps the low-level SFTP calls for version 2 of the SFTP protocol.
|
6
|
+
#
|
7
|
+
# None of these protocol methods block--all of them return immediately,
|
8
|
+
# requiring the SSH event loop to be run while the server response is
|
9
|
+
# pending.
|
10
|
+
#
|
11
|
+
# You will almost certainly never need to use this driver directly. Please
|
12
|
+
# see Net::SFTP::Session for the recommended interface.
|
13
|
+
class Base < V01::Base
|
14
|
+
|
15
|
+
# Returns the protocol version implemented by this driver. (2, in this
|
16
|
+
# case)
|
17
|
+
def version
|
18
|
+
2
|
19
|
+
end
|
20
|
+
|
21
|
+
# Sends a FXP_RENAME packet to the server to request that the file or
|
22
|
+
# directory with the given +name+ (must be a full path) be changed to
|
23
|
+
# +new_name+ (which must also be a path). The +flags+ parameter is
|
24
|
+
# ignored in this version of the protocol.
|
25
|
+
def rename(name, new_name, flags=nil)
|
26
|
+
send_request(FXP_RENAME, :string, name, :string, new_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end; end; end; end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'net/sftp/protocol/02/base'
|
2
|
+
|
3
|
+
module Net; module SFTP; module Protocol; module V03
|
4
|
+
|
5
|
+
# Wraps the low-level SFTP calls for version 3 of the SFTP protocol.
|
6
|
+
#
|
7
|
+
# None of these protocol methods block--all of them return immediately,
|
8
|
+
# requiring the SSH event loop to be run while the server response is
|
9
|
+
# pending.
|
10
|
+
#
|
11
|
+
# You will almost certainly never need to use this driver directly. Please
|
12
|
+
# see Net::SFTP::Session for the recommended interface.
|
13
|
+
class Base < V02::Base
|
14
|
+
|
15
|
+
# Returns the protocol version implemented by this driver. (3, in this
|
16
|
+
# case)
|
17
|
+
def version
|
18
|
+
3
|
19
|
+
end
|
20
|
+
|
21
|
+
# Sends a FXP_READLINK packet to the server to request that the target of
|
22
|
+
# the given symlink on the remote host (+path+) be returned.
|
23
|
+
def readlink(path)
|
24
|
+
send_request(FXP_READLINK, :string, path)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Sends a FXP_SYMLINK packet to the server to request that a symlink at the
|
28
|
+
# given +path+ be created, pointing at +target+..
|
29
|
+
def symlink(path, target)
|
30
|
+
send_request(FXP_SYMLINK, :string, path, :string, target)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end; end; end; end
|
@@ -1,227 +1,152 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
#
|
20
|
-
# the
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
1
|
+
require 'net/sftp/protocol/01/attributes'
|
2
|
+
|
3
|
+
module Net; module SFTP; module Protocol; module V04
|
4
|
+
|
5
|
+
# A class representing the attributes of a file or directory on the server.
|
6
|
+
# It may be used to specify new attributes, or to query existing attributes.
|
7
|
+
# This particular class is specific to versions 4 and 5 of the SFTP
|
8
|
+
# protocol.
|
9
|
+
#
|
10
|
+
# To specify new attributes, just pass a hash as the argument to the
|
11
|
+
# constructor. The following keys are supported:
|
12
|
+
#
|
13
|
+
# * :type:: the type of the item (integer, one of the T_ constants)
|
14
|
+
# * :size:: the size of the item (integer)
|
15
|
+
# * :uid:: the user-id that owns the file (integer)
|
16
|
+
# * :gid:: the group-id that owns the file (integer)
|
17
|
+
# * :owner:: the name of the user that owns the file (string)
|
18
|
+
# * :group:: the name of the group that owns the file (string)
|
19
|
+
# * :permissions:: the permissions on the file (integer, e.g. 0755)
|
20
|
+
# * :atime:: the access time of the file (integer, seconds since epoch)
|
21
|
+
# * :atime_nseconds:: the nanosecond component of atime (integer)
|
22
|
+
# * :createtime:: the time at which the file was created (integer, seconds since epoch)
|
23
|
+
# * :createtime_nseconds:: the nanosecond component of createtime (integer)
|
24
|
+
# * :mtime:: the modification time of the file (integer, seconds since epoch)
|
25
|
+
# * :mtime_nseconds:: the nanosecond component of mtime (integer)
|
26
|
+
# * :acl:: an array of ACL entries for the item
|
27
|
+
# * :extended:: a hash of name/value pairs identifying extended info
|
28
|
+
#
|
29
|
+
# Likewise, when the server sends an Attributes object, all of the
|
30
|
+
# above attributes are exposed as methods (though not all will be set with
|
31
|
+
# non-nil values from the server).
|
32
|
+
class Attributes < V01::Attributes
|
33
|
+
|
25
34
|
F_ACCESSTIME = 0x00000008
|
26
35
|
F_CREATETIME = 0x00000010
|
27
36
|
F_MODIFYTIME = 0x00000020
|
28
37
|
F_ACL = 0x00000040
|
29
38
|
F_OWNERGROUP = 0x00000080
|
30
39
|
F_SUBSECOND_TIMES = 0x00000100
|
31
|
-
F_EXTENDED = 0x80000000
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
# A simple struct for representing a single entry in an Access Control
|
42
|
+
# List. (See Net::SFTP::Constants::ACE)
|
43
|
+
ACL = Struct.new(:type, :flag, :mask, :who)
|
44
|
+
|
45
|
+
class <<self
|
46
|
+
# The list of supported elements in the attributes structure as defined
|
47
|
+
# by v4 of the sftp protocol.
|
48
|
+
def elements #:nodoc:
|
49
|
+
@elements ||= [
|
50
|
+
[:type, :byte, 0],
|
51
|
+
[:size, :int64, V01::Attributes::F_SIZE],
|
52
|
+
[:owner, :string, F_OWNERGROUP],
|
53
|
+
[:group, :string, F_OWNERGROUP],
|
54
|
+
[:permissions, :long, V01::Attributes::F_PERMISSIONS],
|
55
|
+
[:atime, :int64, F_ACCESSTIME],
|
56
|
+
[:atime_nseconds, :long, F_ACCESSTIME | F_SUBSECOND_TIMES],
|
57
|
+
[:createtime, :int64, F_CREATETIME],
|
58
|
+
[:createtime_nseconds, :long, F_CREATETIME | F_SUBSECOND_TIMES],
|
59
|
+
[:mtime, :int64, F_MODIFYTIME],
|
60
|
+
[:mtime_nseconds, :long, F_MODIFYTIME | F_SUBSECOND_TIMES],
|
61
|
+
[:acl, :special, F_ACL],
|
62
|
+
[:extended, :special, V01::Attributes::F_EXTENDED]
|
63
|
+
]
|
64
|
+
end
|
46
65
|
|
47
|
-
|
66
|
+
private
|
48
67
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
68
|
+
# A helper method for parsing the ACL entry in an Attributes struct.
|
69
|
+
def parse_acl(buffer)
|
70
|
+
acl_buf = Net::SSH::Buffer.new(buffer.read_string)
|
71
|
+
acl = []
|
72
|
+
acl_buf.read_long.times do
|
73
|
+
acl << ACL.new(acl_buf.read_long, acl_buf.read_long, acl_buf.read_long, acl_buf.read_string)
|
74
|
+
end
|
75
|
+
acl
|
76
|
+
end
|
54
77
|
end
|
55
78
|
|
56
|
-
#
|
57
|
-
|
58
|
-
@buffers
|
59
|
-
end
|
79
|
+
# The type of the item on the remote server. Must be one of the T_* constants.
|
80
|
+
attr_accessor :type
|
60
81
|
|
61
|
-
#
|
62
|
-
|
63
|
-
def buffers
|
64
|
-
self.class.buffers
|
65
|
-
end
|
82
|
+
# The owner of the item on the remote server, as a string.
|
83
|
+
attr_writer :owner
|
66
84
|
|
67
|
-
#
|
68
|
-
|
69
|
-
new
|
70
|
-
end
|
85
|
+
# The group of the item on the remote server, as a string.
|
86
|
+
attr_writer :group
|
71
87
|
|
72
|
-
#
|
73
|
-
|
74
|
-
flags = buffer.read_long
|
75
|
-
|
76
|
-
type = buffer.read_byte
|
77
|
-
size = buffer.read_int64 if ( flags & F_SIZE ) != 0
|
78
|
-
owner = buffer.read_string if ( flags & F_OWNERGROUP ) != 0
|
79
|
-
group = buffer.read_string if ( flags & F_OWNERGROUP ) != 0
|
80
|
-
permissions = buffer.read_long if ( flags & F_PERMISSIONS ) != 0
|
81
|
-
if ( flags & F_ACCESSTIME ) != 0
|
82
|
-
atime = buffer.read_int64
|
83
|
-
atime_nseconds = buffer.read_long if ( flags & F_SUBSECOND_TIMES ) != 0
|
84
|
-
end
|
85
|
-
if ( flags & F_CREATETIME ) != 0
|
86
|
-
ctime = buffer.read_int64
|
87
|
-
ctime_nseconds = buffer.read_long if ( flags & F_SUBSECOND_TIMES ) != 0
|
88
|
-
end
|
89
|
-
if ( flags & F_MODIFYTIME ) != 0
|
90
|
-
mtime = buffer.read_int64
|
91
|
-
mtime_nseconds = buffer.read_long if ( flags & F_SUBSECOND_TIMES ) != 0
|
92
|
-
end
|
93
|
-
if ( flags & F_ACL ) != 0
|
94
|
-
acl_buf = buffers.reader( buffer.read_string )
|
95
|
-
acl = []
|
96
|
-
acl_buf.read_long.times do
|
97
|
-
acl << ACL.new( acl_buf.read_long,
|
98
|
-
acl_buf.read_long,
|
99
|
-
acl_buf.read_long,
|
100
|
-
acl_buf.read_string )
|
101
|
-
end
|
102
|
-
end
|
88
|
+
# The nanosecond component of the access time.
|
89
|
+
attr_accessor :atime_nseconds
|
103
90
|
|
104
|
-
|
105
|
-
|
106
|
-
buffer.read_long.times do
|
107
|
-
extended[ buffer.read_string ] = buffer.read_string
|
108
|
-
end
|
109
|
-
end
|
91
|
+
# The creation time of the remote item, in seconds since the epoch.
|
92
|
+
attr_accessor :createtime
|
110
93
|
|
111
|
-
|
112
|
-
|
113
|
-
end
|
94
|
+
# The nanosecond component of the creation time.
|
95
|
+
attr_accessor :createtime_nseconds
|
114
96
|
|
115
|
-
#
|
116
|
-
|
117
|
-
# supported by this version of the protocol, but are instead converted
|
118
|
-
# by this method to their corresponding names, and assigned (respectively)
|
119
|
-
# to :owner and :group.
|
120
|
-
def self.from_hash( hash )
|
121
|
-
if hash.has_key?(:uid)
|
122
|
-
require 'etc'
|
123
|
-
hash[:owner] = Etc.getpwuid( hash[:uid] ).name
|
124
|
-
end
|
97
|
+
# The nanosecond component of the modification time.
|
98
|
+
attr_accessor :mtime_nseconds
|
125
99
|
|
126
|
-
|
127
|
-
|
128
|
-
hash[:group] = Etc.getgrgid( hash[:gid] ).name
|
129
|
-
end
|
100
|
+
# The array of access control entries for this item.
|
101
|
+
attr_accessor :acl
|
130
102
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
103
|
+
# Create a new Attributes instance with the given attributes. The
|
104
|
+
# following keys are supported:
|
105
|
+
#
|
106
|
+
# * :type:: the type of the item (integer, one of the T_ constants)
|
107
|
+
# * :size:: the size of the item (integer)
|
108
|
+
# * :uid:: the user-id that owns the file (integer)
|
109
|
+
# * :gid:: the group-id that owns the file (integer)
|
110
|
+
# * :owner:: the name of the user that owns the file (string)
|
111
|
+
# * :group:: the name of the group that owns the file (string)
|
112
|
+
# * :permissions:: the permissions on the file (integer, e.g. 0755)
|
113
|
+
# * :atime:: the access time of the file (integer, seconds since epoch)
|
114
|
+
# * :atime_nseconds:: the nanosecond component of atime (integer)
|
115
|
+
# * :createtime:: the time at which the file was created (integer, seconds since epoch)
|
116
|
+
# * :createtime_nseconds:: the nanosecond component of createtime (integer)
|
117
|
+
# * :mtime:: the modification time of the file (integer, seconds since epoch)
|
118
|
+
# * :mtime_nseconds:: the nanosecond component of mtime (integer)
|
119
|
+
# * :acl:: an array of ACL entries for the item
|
120
|
+
# * :extended:: a hash of name/value pairs identifying extended info
|
121
|
+
#
|
122
|
+
# All of them default to +nil+ if omitted, except for +type+, which defaults
|
123
|
+
# to T_REGULAR.
|
124
|
+
def initialize(attributes={})
|
125
|
+
super
|
126
|
+
attributes[:type] ||= T_REGULAR
|
135
127
|
end
|
136
128
|
|
137
|
-
|
138
|
-
|
139
|
-
T_REGULAR = 1
|
140
|
-
T_DIRECTORY = 2
|
141
|
-
T_SYMLINK = 3
|
142
|
-
T_SPECIAL = 4
|
143
|
-
T_UNKNOWN = 5
|
144
|
-
T_SOCKET = 6
|
145
|
-
T_CHAR_DEVICE = 7
|
146
|
-
T_BLOCK_DEVICE = 8
|
147
|
-
T_FIFO = 9
|
148
|
-
|
149
|
-
# Create a new Attributes instance with the given values.
|
150
|
-
def initialize( type=T_REGULAR, size=nil, owner=nil, group=nil,
|
151
|
-
permissions=nil, atime=nil, atime_nseconds=nil, ctime=nil,
|
152
|
-
ctime_nseconds=nil, mtime=nil, mtime_nseconds=nil, acl=nil,
|
153
|
-
extended=nil )
|
154
|
-
# begin
|
155
|
-
@type = type
|
156
|
-
@size = size
|
157
|
-
@owner = owner
|
158
|
-
@group = group
|
159
|
-
@permissions = permissions
|
160
|
-
@atime = atime
|
161
|
-
@atime_nseconds = atime_nseconds
|
162
|
-
@ctime = ctime
|
163
|
-
@ctime_nseconds = ctime_nseconds
|
164
|
-
@mtime = mtime
|
165
|
-
@mtime_nseconds = mtime_nseconds
|
166
|
-
@acl = acl
|
167
|
-
@extended = extended
|
168
|
-
end
|
129
|
+
private
|
169
130
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
flags |= F_OWNERGROUP if @owner && @group
|
177
|
-
flags |= F_PERMISSIONS if @permissions
|
178
|
-
flags |= F_ACCESSTIME if @atime
|
179
|
-
flags |= F_CREATETIME if @ctime
|
180
|
-
flags |= F_MODIFYTIME if @mtime
|
181
|
-
if @atime_nseconds && @ctime_nseconds && @mtime_nseconds
|
182
|
-
flags |= F_SUBSECOND_TIMES
|
183
|
-
end
|
184
|
-
flags |= F_ACL if @acl
|
185
|
-
flags |= F_EXTENDED if @extended
|
186
|
-
|
187
|
-
buffer = buffers.writer
|
188
|
-
buffer.write_long flags
|
189
|
-
buffer.write_byte @type
|
190
|
-
buffer.write_int64 @size if @size
|
191
|
-
buffer.write_string @owner, @group if @owner && @group
|
192
|
-
buffer.write_long @permissions if @permissions
|
193
|
-
|
194
|
-
if @atime
|
195
|
-
buffer.write_int64 @atime
|
196
|
-
buffer.write_long @atime_nseconds if ( flags & F_SUBSECOND_TIMES != 0 )
|
197
|
-
end
|
198
|
-
if @ctime
|
199
|
-
buffer.write_int64 @ctime
|
200
|
-
buffer.write_long @ctime_nseconds if ( flags & F_SUBSECOND_TIMES != 0 )
|
201
|
-
end
|
202
|
-
if @mtime
|
203
|
-
buffer.write_int64 @mtime
|
204
|
-
buffer.write_long @mtime_nseconds if ( flags & F_SUBSECOND_TIMES != 0 )
|
131
|
+
# Perform protocol-version-specific preparations for serialization.
|
132
|
+
def prepare_serialization!
|
133
|
+
# force the group/owner to be translated from uid/gid, if those keys
|
134
|
+
# were given on instantiation
|
135
|
+
owner
|
136
|
+
group
|
205
137
|
end
|
206
138
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
139
|
+
# Performs protocol-version-specific encoding of the access control
|
140
|
+
# list, if one exists.
|
141
|
+
def encode_acl(buffer)
|
142
|
+
acl_buf = Net::SSH::Buffer.from(:long, acl.length)
|
143
|
+
acl.each do |item|
|
211
144
|
acl_buf.write_long item.type, item.flag, item.mask
|
212
145
|
acl_buf.write_string item.who
|
213
146
|
end
|
214
|
-
buffer.write_string
|
147
|
+
buffer.write_string(acl_buf.to_s)
|
215
148
|
end
|
216
149
|
|
217
|
-
if @extended
|
218
|
-
buffer.write_long @extended.length
|
219
|
-
@extended.each { |k,v| buffer.write_string k, v }
|
220
|
-
end
|
221
|
-
|
222
|
-
buffer.to_s
|
223
|
-
end
|
224
|
-
|
225
150
|
end
|
226
151
|
|
227
152
|
end ; end ; end ; end
|