net-sftp-backports 4.0.0.backports

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.
@@ -0,0 +1,315 @@
1
+ require 'net/ssh/buffer'
2
+
3
+ module Net; module SFTP; module Protocol; module V01
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
+ #
8
+ # To specify new attributes, just pass a hash as the argument to the
9
+ # constructor. The following keys are supported:
10
+ #
11
+ # * :size:: the size of the file
12
+ # * :uid:: the user-id that owns the file (integer)
13
+ # * :gid:: the group-id that owns the file (integer)
14
+ # * :owner:: the name of the user that owns the file (string)
15
+ # * :group:: the name of the group that owns the file (string)
16
+ # * :permissions:: the permissions on the file (integer, e.g. 0755)
17
+ # * :atime:: the access time of the file (integer, seconds since epoch)
18
+ # * :mtime:: the modification time of the file (integer, seconds since epoch)
19
+ # * :extended:: a hash of name/value pairs identifying extended info
20
+ #
21
+ # Likewise, when the server sends an Attributes object, all of the
22
+ # above attributes are exposed as methods (though not all will be set with
23
+ # non-nil values from the server).
24
+ class Attributes
25
+
26
+ F_SIZE = 0x00000001
27
+ F_UIDGID = 0x00000002
28
+ F_PERMISSIONS = 0x00000004
29
+ F_ACMODTIME = 0x00000008
30
+ F_EXTENDED = 0x80000000
31
+
32
+ T_REGULAR = 1
33
+ T_DIRECTORY = 2
34
+ T_SYMLINK = 3
35
+ T_SPECIAL = 4
36
+ T_UNKNOWN = 5
37
+ T_SOCKET = 6
38
+ T_CHAR_DEVICE = 7
39
+ T_BLOCK_DEVICE = 8
40
+ T_FIFO = 9
41
+
42
+ class <<self
43
+ # Returns the array of attribute meta-data that defines the structure of
44
+ # the attributes packet as described by this version of the protocol.
45
+ def elements #:nodoc:
46
+ @elements ||= [
47
+ [:size, :int64, F_SIZE],
48
+ [:uid, :long, F_UIDGID],
49
+ [:gid, :long, F_UIDGID],
50
+ [:permissions, :long, F_PERMISSIONS],
51
+ [:atime, :long, F_ACMODTIME],
52
+ [:mtime, :long, F_ACMODTIME],
53
+ [:extended, :special, F_EXTENDED]
54
+ ]
55
+ end
56
+
57
+ # Parses the given buffer and returns an Attributes object compsed from
58
+ # the data extracted from it.
59
+ def from_buffer(buffer)
60
+ flags = buffer.read_long
61
+ data = {}
62
+
63
+ elements.each do |name, type, condition|
64
+ if flags & condition == condition
65
+ if type == :special
66
+ data[name] = send("parse_#{name}", buffer)
67
+ else
68
+ data[name] = buffer.send("read_#{type}")
69
+ end
70
+ end
71
+ end
72
+
73
+ new(data)
74
+ end
75
+
76
+ # A convenience method for defining methods that expose specific
77
+ # attributes. This redefines the standard attr_accessor (an admittedly
78
+ # bad practice) because (1) I don't need any "regular" accessors, and
79
+ # (2) because rdoc will automatically pick up and note methods defined
80
+ # via attr_accessor.
81
+ def attr_accessor(name) #:nodoc:
82
+ class_eval <<-CODE
83
+ def #{name}
84
+ attributes[:#{name}]
85
+ end
86
+ CODE
87
+
88
+ attr_writer(name)
89
+ end
90
+
91
+ # A convenience method for defining methods that expose specific
92
+ # attributes. This redefines the standard attr_writer (an admittedly
93
+ # bad practice) because (1) I don't need any "regular" accessors, and
94
+ # (2) because rdoc will automatically pick up and note methods defined
95
+ # via attr_writer.
96
+ def attr_writer(name) #:nodoc:
97
+ class_eval <<-CODE
98
+ def #{name}=(value)
99
+ attributes[:#{name}] = value
100
+ end
101
+ CODE
102
+ end
103
+
104
+ private
105
+
106
+ # Parse the hash of extended data from the buffer.
107
+ def parse_extended(buffer)
108
+ extended = Hash.new
109
+ buffer.read_long.times do
110
+ extended[buffer.read_string] = buffer.read_string
111
+ end
112
+ extended
113
+ end
114
+ end
115
+
116
+ # The hash of name/value pairs that backs this Attributes instance
117
+ attr_reader :attributes
118
+
119
+ # The size of the file.
120
+ attr_accessor :size
121
+
122
+ # The user-id of the user that owns the file
123
+ attr_writer :uid
124
+
125
+ # The group-id of the user that owns the file
126
+ attr_writer :gid
127
+
128
+ # The permissions on the file
129
+ attr_accessor :permissions
130
+
131
+ # The last access time of the file
132
+ attr_accessor :atime
133
+
134
+ # The modification time of the file
135
+ attr_accessor :mtime
136
+
137
+ # The hash of name/value pairs identifying extended information about the file
138
+ attr_accessor :extended
139
+
140
+ # Create a new Attributes instance with the given attributes. The
141
+ # following keys are supported:
142
+ #
143
+ # * :size:: the size of the file
144
+ # * :uid:: the user-id that owns the file (integer)
145
+ # * :gid:: the group-id that owns the file (integer)
146
+ # * :owner:: the name of the user that owns the file (string)
147
+ # * :group:: the name of the group that owns the file (string)
148
+ # * :permissions:: the permissions on the file (integer, e.g. 0755)
149
+ # * :atime:: the access time of the file (integer, seconds since epoch)
150
+ # * :mtime:: the modification time of the file (integer, seconds since epoch)
151
+ # * :extended:: a hash of name/value pairs identifying extended info
152
+ def initialize(attributes={})
153
+ @attributes = attributes
154
+ end
155
+
156
+ # Returns the user-id of the user that owns the file, or +nil+ if that
157
+ # information is not available. If an :owner key exists, but not a :uid
158
+ # key, the Etc module will be used to reverse lookup the id from the name.
159
+ # This might fail on some systems (e.g., Windows).
160
+ def uid
161
+ if attributes[:owner] && !attributes.key?(:uid)
162
+ require 'etc'
163
+ attributes[:uid] = Etc.getpwnam(attributes[:owner]).uid
164
+ end
165
+ attributes[:uid]
166
+ end
167
+
168
+ # Returns the group-id of the group that owns the file, or +nil+ if that
169
+ # information is not available. If a :group key exists, but not a :gid
170
+ # key, the Etc module will be used to reverse lookup the id from the name.
171
+ # This might fail on some systems (e.g., Windows).
172
+ def gid
173
+ if attributes[:group] && !attributes.key?(:gid)
174
+ require 'etc'
175
+ attributes[:gid] = Etc.getgrnam(attributes[:group]).gid
176
+ end
177
+ attributes[:gid]
178
+ end
179
+
180
+ # Returns the username of the user that owns the file, or +nil+ if that
181
+ # information is not available. If the :uid is given, but not the :owner,
182
+ # the Etc module will be used to lookup the name from the id. This might
183
+ # fail on some systems (e.g. Windows).
184
+ def owner
185
+ if attributes[:uid] && !attributes[:owner]
186
+ require 'etc'
187
+ attributes[:owner] = Etc.getpwuid(attributes[:uid].to_i).name
188
+ end
189
+ attributes[:owner]
190
+ end
191
+
192
+ # Returns the group name of the group that owns the file, or +nil+ if that
193
+ # information is not available. If the :gid is given, but not the :group,
194
+ # the Etc module will be used to lookup the name from the id. This might
195
+ # fail on some systems (e.g. Windows).
196
+ def group
197
+ if attributes[:gid] && !attributes[:group]
198
+ require 'etc'
199
+ attributes[:group] = Etc.getgrgid(attributes[:gid].to_i).name
200
+ end
201
+ attributes[:group]
202
+ end
203
+
204
+ # Inspects the permissions bits to determine what type of entity this
205
+ # attributes object represents. If will return one of the T_ constants.
206
+ def type
207
+ if permissions & 0140000 == 0140000 then
208
+ T_SOCKET
209
+ elsif permissions & 0120000 == 0120000 then
210
+ T_SYMLINK
211
+ elsif permissions & 0100000 == 0100000 then
212
+ T_REGULAR
213
+ elsif permissions & 060000 == 060000 then
214
+ T_BLOCK_DEVICE
215
+ elsif permissions & 040000 == 040000 then
216
+ T_DIRECTORY
217
+ elsif permissions & 020000 == 020000 then
218
+ T_CHAR_DEVICE
219
+ elsif permissions & 010000 == 010000 then
220
+ T_FIFO
221
+ else
222
+ T_UNKNOWN
223
+ end
224
+ end
225
+
226
+ # Returns the type as a symbol, rather than an integer, for easier use in
227
+ # Ruby programs.
228
+ def symbolic_type
229
+ case type
230
+ when T_SOCKET then :socket
231
+ when T_SYMLINK then :symlink
232
+ when T_REGULAR then :regular
233
+ when T_BLOCK_DEVICE then :block_device
234
+ when T_DIRECTORY then :directory
235
+ when T_CHAR_DEVICE then :char_device
236
+ when T_FIFO then :fifo
237
+ when T_SPECIAL then :special
238
+ when T_UNKNOWN then :unknown
239
+ else raise NotImplementedError, "unknown file type #{type} (bug?)"
240
+ end
241
+ end
242
+
243
+ # Returns true if these attributes appear to describe a directory.
244
+ def directory?
245
+ case type
246
+ when T_DIRECTORY then true
247
+ when T_UNKNOWN then nil
248
+ else false
249
+ end
250
+ end
251
+
252
+ # Returns true if these attributes appear to describe a symlink.
253
+ def symlink?
254
+ case type
255
+ when T_SYMLINK then true
256
+ when T_UNKNOWN then nil
257
+ else false
258
+ end
259
+ end
260
+
261
+ # Returns true if these attributes appear to describe a regular file.
262
+ def file?
263
+ case type
264
+ when T_REGULAR then true
265
+ when T_UNKNOWN then nil
266
+ else false
267
+ end
268
+ end
269
+
270
+ # Convert the object to a string suitable for passing in an SFTP
271
+ # packet. This is the raw representation of the attribute packet payload,
272
+ # and is not intended to be human readable.
273
+ def to_s
274
+ prepare_serialization!
275
+
276
+ flags = 0
277
+
278
+ self.class.elements.each do |name, type, condition|
279
+ flags |= condition if attributes[name]
280
+ end
281
+
282
+ buffer = Net::SSH::Buffer.from(:long, flags)
283
+ self.class.elements.each do |name, type, condition|
284
+ if flags & condition == condition
285
+ if type == :special
286
+ send("encode_#{name}", buffer)
287
+ else
288
+ buffer.send("write_#{type}", attributes[name])
289
+ end
290
+ end
291
+ end
292
+
293
+ buffer.to_s
294
+ end
295
+
296
+ private
297
+
298
+ # Perform protocol-version-specific preparations for serialization.
299
+ def prepare_serialization!
300
+ # force the uid/gid to be translated from owner/group, if those keys
301
+ # were given on instantiation
302
+ uid
303
+ gid
304
+ end
305
+
306
+ # Encodes information about the extended info onto the end of the given
307
+ # buffer.
308
+ def encode_extended(buffer)
309
+ buffer.write_long extended.size
310
+ extended.each { |k,v| buffer.write_string k, v }
311
+ end
312
+
313
+ end
314
+
315
+ end ; end ; end ; end
@@ -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