net-sftp 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/doc/LICENSE-BSD +27 -0
  2. data/doc/LICENSE-GPL +280 -0
  3. data/doc/LICENSE-RUBY +56 -0
  4. data/examples/asynchronous.rb +57 -0
  5. data/examples/ssh-service.rb +31 -0
  6. data/examples/synchronous.rb +120 -0
  7. data/lib/net/sftp.rb +39 -0
  8. data/lib/net/sftp/errors.rb +25 -0
  9. data/lib/net/sftp/operations/abstract.rb +103 -0
  10. data/lib/net/sftp/operations/close.rb +31 -0
  11. data/lib/net/sftp/operations/errors.rb +76 -0
  12. data/lib/net/sftp/operations/fsetstat.rb +36 -0
  13. data/lib/net/sftp/operations/fstat.rb +32 -0
  14. data/lib/net/sftp/operations/lstat.rb +31 -0
  15. data/lib/net/sftp/operations/mkdir.rb +33 -0
  16. data/lib/net/sftp/operations/open.rb +32 -0
  17. data/lib/net/sftp/operations/opendir.rb +32 -0
  18. data/lib/net/sftp/operations/read.rb +84 -0
  19. data/lib/net/sftp/operations/readdir.rb +55 -0
  20. data/lib/net/sftp/operations/realpath.rb +37 -0
  21. data/lib/net/sftp/operations/remove.rb +31 -0
  22. data/lib/net/sftp/operations/rename.rb +32 -0
  23. data/lib/net/sftp/operations/rmdir.rb +31 -0
  24. data/lib/net/sftp/operations/services.rb +42 -0
  25. data/lib/net/sftp/operations/setstat.rb +33 -0
  26. data/lib/net/sftp/operations/stat.rb +31 -0
  27. data/lib/net/sftp/operations/write.rb +63 -0
  28. data/lib/net/sftp/protocol/01/attributes.rb +146 -0
  29. data/lib/net/sftp/protocol/01/impl.rb +251 -0
  30. data/lib/net/sftp/protocol/01/packet-assistant.rb +82 -0
  31. data/lib/net/sftp/protocol/01/services.rb +47 -0
  32. data/lib/net/sftp/protocol/02/impl.rb +39 -0
  33. data/lib/net/sftp/protocol/02/packet-assistant.rb +32 -0
  34. data/lib/net/sftp/protocol/02/services.rb +44 -0
  35. data/lib/net/sftp/protocol/03/impl.rb +42 -0
  36. data/lib/net/sftp/protocol/03/packet-assistant.rb +35 -0
  37. data/lib/net/sftp/protocol/03/services.rb +44 -0
  38. data/lib/net/sftp/protocol/04/attributes.rb +227 -0
  39. data/lib/net/sftp/protocol/04/impl.rb +134 -0
  40. data/lib/net/sftp/protocol/04/packet-assistant.rb +51 -0
  41. data/lib/net/sftp/protocol/04/services.rb +44 -0
  42. data/lib/net/sftp/protocol/05/services.rb +44 -0
  43. data/lib/net/sftp/protocol/constants.rb +60 -0
  44. data/lib/net/sftp/protocol/driver.rb +232 -0
  45. data/lib/net/sftp/protocol/packet-assistant.rb +84 -0
  46. data/lib/net/sftp/protocol/services.rb +55 -0
  47. data/lib/net/sftp/session.rb +215 -0
  48. data/lib/net/sftp/version.rb +25 -0
  49. data/test/ALL-TESTS.rb +21 -0
  50. data/test/operations/tc_abstract.rb +124 -0
  51. data/test/operations/tc_close.rb +40 -0
  52. data/test/operations/tc_fsetstat.rb +48 -0
  53. data/test/operations/tc_fstat.rb +40 -0
  54. data/test/operations/tc_lstat.rb +40 -0
  55. data/test/operations/tc_mkdir.rb +48 -0
  56. data/test/operations/tc_open.rb +42 -0
  57. data/test/operations/tc_opendir.rb +40 -0
  58. data/test/operations/tc_read.rb +103 -0
  59. data/test/operations/tc_readdir.rb +88 -0
  60. data/test/operations/tc_realpath.rb +54 -0
  61. data/test/operations/tc_remove.rb +40 -0
  62. data/test/operations/tc_rmdir.rb +40 -0
  63. data/test/operations/tc_setstat.rb +48 -0
  64. data/test/operations/tc_stat.rb +40 -0
  65. data/test/operations/tc_write.rb +91 -0
  66. data/test/protocol/01/tc_attributes.rb +138 -0
  67. data/test/protocol/01/tc_impl.rb +294 -0
  68. data/test/protocol/01/tc_packet_assistant.rb +81 -0
  69. data/test/protocol/02/tc_impl.rb +41 -0
  70. data/test/protocol/02/tc_packet_assistant.rb +31 -0
  71. data/test/protocol/03/tc_impl.rb +48 -0
  72. data/test/protocol/03/tc_packet_assistant.rb +34 -0
  73. data/test/protocol/04/tc_attributes.rb +174 -0
  74. data/test/protocol/04/tc_impl.rb +102 -0
  75. data/test/protocol/04/tc_packet_assistant.rb +41 -0
  76. data/test/protocol/tc_driver.rb +219 -0
  77. metadata +137 -0
@@ -0,0 +1,134 @@
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
+ require 'net/sftp/protocol/03/impl'
18
+
19
+ module Net ; module SFTP ; module Protocol ; module V_04
20
+
21
+ # The implementation of the operations available to version 4 of the SFTP
22
+ # protocol.
23
+ class Impl < V_03::Impl
24
+
25
+ F_CREATE_NEW = 0x00000000
26
+ F_CREATE_TRUNCATE = 0x00000001
27
+ F_OPEN_EXISTING = 0x00000002
28
+ F_OPEN_OR_CREATE = 0x00000003
29
+ F_TRUNCATE_EXISTING = 0x00000004
30
+
31
+ F_APPEND_DATA = 0x00000008
32
+ F_APPEND_DATA_ATOMIC = 0x00000010
33
+ F_TEXT_MODE = 0x00000020
34
+ F_READ_LOCK = 0x00000040
35
+ F_WRITE_LOCK = 0x00000080
36
+ F_DELETE_LOCK = 0x00000100
37
+
38
+ module ACE
39
+ F_READ_DATA = 0x00000001
40
+ F_LIST_DIRECTORY = 0x00000001
41
+ F_WRITE_DATA = 0x00000002
42
+ F_ADD_FILE = 0x00000002
43
+ F_APPEND_DATA = 0x00000004
44
+ F_ADD_SUBDIRECTORY = 0x00000004
45
+ F_READ_NAMED_ATTRS = 0x00000008
46
+ F_WRITE_NAMED_ATTRS = 0x00000010
47
+ F_EXECUTE = 0x00000020
48
+ F_DELETE_CHILD = 0x00000040
49
+ F_READ_ATTRIBUTES = 0x00000080
50
+ F_WRITE_ATTRIBUTES = 0x00000100
51
+ F_DELETE = 0x00010000
52
+ F_READ_ACL = 0x00020000
53
+ F_WRITE_ACL = 0x00040000
54
+ F_WRITE_OWNER = 0x00080000
55
+ F_SYNCHRONIZE = 0x00100000
56
+ end
57
+
58
+ # The open operation changed in version 4. This method keeps the same
59
+ # interface as previous versions, but changes how the parameters are
60
+ # interpreted and converted into a packet.
61
+ def open( id, path, flags, mode=0660 )
62
+ sftp_flags, desired_access = case
63
+ when flags & IO::WRONLY != 0 then
64
+ [ F_CREATE_TRUNCATE,
65
+ ACE::F_WRITE_DATA | ACE::F_WRITE_ATTRIBUTES ]
66
+ when flags & IO::RDWR != 0 then
67
+ [ F_OPEN_OR_CREATE,
68
+ ACE::F_READ_DATA | ACE::F_READ_ATTRIBUTES |
69
+ ACE::F_WRITE_DATA | ACE::F_WRITE_ATTRIBUTES ]
70
+ when flags & IO::APPEND != 0 then
71
+ [ F_OPEN_OR_CREATE | F_APPEND_DATA,
72
+ ACE::F_WRITE_DATA | ACE::F_WRITE_ATTRIBUTES |
73
+ ACE::F_APPEND_DATA ]
74
+ else
75
+ [ F_OPEN_EXISTING,
76
+ ACE::F_READ_DATA | ACE::F_READ_ATTRIBUTES ]
77
+ end
78
+
79
+ sftp_flags |= F_OPEN_OR_CREATE if flags & IO::CREAT != 0
80
+ sftp_flags |= F_TRUNCATE_EXISTING if flags & IO::TRUNC != 0
81
+
82
+ attributes = @attr_factory.empty
83
+ attributes.permissions = mode
84
+
85
+ open_raw id, path, desired_access, sftp_flags, attributes
86
+ end
87
+
88
+ # In version 4, stat accepts a flags parameter. If flags is +nil+, it
89
+ # will default to returning all attributes. Otherwise, the flags parameter
90
+ # should be a bitwise combination of the F_xxx constants of
91
+ # Net::SFTP::Protocol::V_04::Attributes.
92
+ def stat( id, filename, flags=nil )
93
+ stat_raw id, filename, convert_flags( flags )
94
+ end
95
+
96
+ # In version 4, lstat accepts a flags parameter. If flags is +nil+, it
97
+ # will default to returning all attributes. Otherwise, the flags parameter
98
+ # should be a bitwise combination of the F_xxx constants of
99
+ # Net::SFTP::Protocol::V_04::Attributes.
100
+ def lstat( id, filename, flags=nil )
101
+ lstat_raw id, filename, convert_flags( flags )
102
+ end
103
+
104
+ # In version 4, fstat accepts a flags parameter. If flags is +nil+, it
105
+ # will default to returning all attributes. Otherwise, the flags parameter
106
+ # should be a bitwise combination of the F_xxx constants of
107
+ # Net::SFTP::Protocol::V_04::Attributes.
108
+ def fstat( id, handle, flags=nil )
109
+ fstat_raw id, handle, convert_flags( flags )
110
+ end
111
+
112
+ # In version 4, rename accepts a flags parameter. The valid flags are a
113
+ # combination of the following:
114
+ #
115
+ # * FXP_RENAME_OVERWRITE (0x01)
116
+ # * FXP_RENAME_ATOMIC (0x02)
117
+ # * FXP_RENAME_NATIVE (0x04)
118
+ #
119
+ # Please refer to the SSH2 specification for the description of these flags.
120
+ def rename( id, name, new_name, flags=0 )
121
+ rename_raw id, name, new_name, flags
122
+ end
123
+
124
+ # A convenience method for converting the (stat) flags parameter into a
125
+ # value acceptible to the SFTP protocol.
126
+ def convert_flags( flags )
127
+ return 0x800001FD if flags.nil?
128
+ flags
129
+ end
130
+ private :convert_flags
131
+
132
+ end
133
+
134
+ end ; end ; end ; end
@@ -0,0 +1,51 @@
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
+ require 'net/sftp/protocol/03/packet-assistant'
18
+
19
+ module Net ; module SFTP ; module Protocol ; module V_04
20
+
21
+ # Version 4 of the SFTP protocol changed the number of parameters to several
22
+ # different packet types:
23
+ #
24
+ # * open( id, path, access, flags, attrs )
25
+ # * rename( id, old, new, flags )
26
+ # * stat( id, path, flags )
27
+ # * lstat( id, path, flags )
28
+ # * fstat( id, handle, flags )
29
+ class PacketAssistant < V_03::PacketAssistant
30
+
31
+ packet :open, :string, # path
32
+ :long, # access
33
+ :long, # flags
34
+ :attrs # file attributes
35
+
36
+ packet :rename, :string, # old name
37
+ :string, # new name
38
+ :long # flags
39
+
40
+ packet :stat, :string, # path
41
+ :long # flags
42
+
43
+ packet :lstat, :string, # path
44
+ :long # flags
45
+
46
+ packet :fstat, :string, # handle
47
+ :long # flags
48
+
49
+ end
50
+
51
+ end ; end ; end ; end
@@ -0,0 +1,44 @@
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
+ module Net ; module SFTP ; module Protocol ; module V_04
18
+
19
+ def register_services( container )
20
+ container.namespace_define :v_04 do |ns|
21
+
22
+ ns.packet_assistant do |c,|
23
+ require 'net/sftp/protocol/04/packet-assistant'
24
+ PacketAssistant.new( c[:transport][:buffers],
25
+ c[:driver] )
26
+ end
27
+
28
+ ns.attr_factory do |c,|
29
+ require 'net/sftp/protocol/04/attributes'
30
+ Attributes.init( c[:transport][:buffers] )
31
+ end
32
+
33
+ ns.impl do |c,|
34
+ require 'net/sftp/protocol/04/impl'
35
+ Impl.new( c[:transport][:buffers],
36
+ c[:driver], c[:packet_assistant],
37
+ c[:attr_factory] )
38
+ end
39
+
40
+ end
41
+ end
42
+ module_function :register_services
43
+
44
+ end ; end ; end ; end
@@ -0,0 +1,44 @@
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
+ module Net ; module SFTP ; module Protocol ; module V_05
18
+
19
+ def register_services( container )
20
+ container.namespace_define :v_05 do |ns|
21
+
22
+ ns.packet_assistant do |c,|
23
+ require 'net/sftp/protocol/04/packet-assistant'
24
+ V_04::PacketAssistant.new( c[:transport][:buffers],
25
+ c[:driver] )
26
+ end
27
+
28
+ ns.attr_factory do |c,|
29
+ require 'net/sftp/protocol/04/attributes'
30
+ V_04::Attributes.init( c[:transport][:buffers] )
31
+ end
32
+
33
+ ns.impl do |c,|
34
+ require 'net/sftp/protocol/04/impl'
35
+ V_04::Impl.new( c[:transport][:buffers],
36
+ c[:driver], c[:packet_assistant],
37
+ c[:attr_factory] )
38
+ end
39
+
40
+ end
41
+ end
42
+ module_function :register_services
43
+
44
+ end ; end ; end ; end
@@ -0,0 +1,60 @@
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
+ module Net ; module SFTP ; module Protocol
18
+
19
+ module Constants
20
+
21
+ FXP_INIT = 1
22
+ FXP_VERSION = 2
23
+ FXP_OPEN = 3
24
+ FXP_CLOSE = 4
25
+ FXP_READ = 5
26
+ FXP_WRITE = 6
27
+ FXP_LSTAT = 7
28
+ FXP_FSTAT = 8
29
+ FXP_SETSTAT = 9
30
+ FXP_FSETSTAT = 10
31
+ FXP_OPENDIR = 11
32
+ FXP_READDIR = 12
33
+ FXP_REMOVE = 13
34
+ FXP_MKDIR = 14
35
+ FXP_RMDIR = 15
36
+ FXP_REALPATH = 16
37
+ FXP_STAT = 17
38
+ FXP_RENAME = 18
39
+ FXP_READLINK = 19
40
+ FXP_SYMLINK = 20
41
+
42
+ FXP_STATUS = 101
43
+ FXP_HANDLE = 102
44
+ FXP_DATA = 103
45
+ FXP_NAME = 104
46
+ FXP_ATTRS = 105
47
+
48
+ FXP_EXTENDED = 106
49
+ FXP_EXTENDED_REPLY = 107
50
+
51
+ FXP_RENAME_OVERWRITE = 0x00000001
52
+ FXP_RENAME_ATOMIC = 0x00000002
53
+ FXP_RENAME_NATIVE = 0x00000004
54
+
55
+ FX_OK = 0
56
+ FX_EOF = 1
57
+
58
+ end
59
+
60
+ end ; end ; end
@@ -0,0 +1,232 @@
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
+ require 'thread'
18
+ require 'net/sftp/errors'
19
+ require 'net/sftp/protocol/constants'
20
+
21
+ module Net ; module SFTP ; module Protocol
22
+
23
+ # This is the driver object for the SFTP protocol. It manages the SSH channel
24
+ # used to communicate with the server, as well as the negotiation of the
25
+ # protocol. The operations themselves are specific to the protocol version
26
+ # in use, and are handled by protocol-version-specific dispatcher objects.
27
+ class Driver
28
+ include Constants
29
+
30
+ # The current state of the driver. This will be one of +unconfirmed+,
31
+ # +init+, +version+, +open+, or +closed+.
32
+ attr_reader :state
33
+
34
+ # Create a new SFTP protocol driver object on the given SSH connection.
35
+ # +buffers+ is a reference to a buffer factory, +version+ is the highest
36
+ # supported SFTP protocol version, +dispatchers+ is a Proc object that
37
+ # returns a dispatcher instance for a specific protocol version, and +log+
38
+ # is a logger instance.
39
+ #
40
+ # The new protocol driver will be in an +unconfirmed+ state, initially.
41
+ # When the server validates the requested channel, the driver goes to the
42
+ # +init+ state, and requests the SFTP subsystem. When the subsystem has
43
+ # been accepted, the driver sends its supported protocol version to the
44
+ # server, and goes to the +version+ state. Lastly, when the server
45
+ # responds with its supported protocol version and the version to use has
46
+ # been successfully negotiated, the driver will go to the +open+ state,
47
+ # after which SFTP operations may be successfully performed on the driver.
48
+ def initialize( connection, buffers, version, dispatchers, log )
49
+ @buffers = buffers
50
+ @version = version
51
+ @dispatchers = dispatchers
52
+ @log = log
53
+
54
+ @next_request_id = 0
55
+ @next_request_mutex = Mutex.new
56
+ @parsed_data = nil
57
+ @on_open = nil
58
+
59
+ @state = :unconfirmed
60
+
61
+ @log.debug "opening channel for sftp" if @log.debug?
62
+ @channel = connection.open_channel( "session", &method( :do_confirm ) )
63
+ end
64
+
65
+ # Closes the underlying SSH channel that the SFTP session uses to
66
+ # communicate with the server. This moves the driver to the +closed+
67
+ # state. If the driver is already closed, this does nothing.
68
+ def close
69
+ if @state != :closed
70
+ @log.debug "closing sftp channel" if @log.debug?
71
+ @channel.close
72
+ @state = :closed
73
+ end
74
+ end
75
+
76
+ # Returns the next available request id in a thread-safe manner. The
77
+ # request-id is used to identify packets associated with request sequences.
78
+ def next_request_id
79
+ @next_request_mutex.synchronize do
80
+ request_id = @next_request_id
81
+ @next_request_id += 1
82
+ return request_id
83
+ end
84
+ end
85
+
86
+ # Specify the callback to invoke when the session has been successfully
87
+ # opened (i.e., once the driver's state has moved to +open+). The callback
88
+ # should accept a single parameter--the driver itself.
89
+ def on_open( &block )
90
+ @on_open = block
91
+ end
92
+
93
+ # The callback used internally to indicate that the requested channel has
94
+ # been confirmed. This will request the SFTP subsystem, register some
95
+ # request callbacks, and move the driver's state to +init+. This may only
96
+ # be called when the driver's state is +unconfirmed+.
97
+ def do_confirm( channel )
98
+ assert_state :unconfirmed
99
+ @log.debug "requesting sftp subsystem" if @log.debug?
100
+
101
+ channel.subsystem "sftp"
102
+ channel.on_success &method( :do_success )
103
+ channel.on_data &method( :do_data )
104
+
105
+ @state = :init
106
+ end
107
+
108
+ # The callback used internally to indicate that the SFTP subsystem was
109
+ # successfully requested. This may only be called when the driver's state
110
+ # is +init+. It sends an INIT packet containing the highest supported
111
+ # SFTP protocol version to the server, and moves the driver's state to
112
+ # +version+.
113
+ def do_success( channel )
114
+ assert_state :init
115
+ @log.debug "initializing sftp subsystem" if @log.debug?
116
+
117
+ packet = @buffers.writer
118
+ packet.write_long @version
119
+ send_data FXP_INIT, packet
120
+
121
+ @state = :version
122
+ end
123
+
124
+ # This is used internally to indicate that a VERSION packet was received
125
+ # from the server. This may only be called when the driver's state is
126
+ # +version+. It determines the highest possible protocol version supported
127
+ # by both the client and the server, selects the dispatcher that handles
128
+ # that protocol version, moves the state to +open+, and then invokes the
129
+ # +on_open+ callback (if one was registered).
130
+ def do_version( content )
131
+ assert_state :version
132
+ @log.debug "negotiating sftp protocol version" if @log.debug?
133
+ @log.debug "my sftp version is #{@version}" if @log.debug?
134
+
135
+ server_version = content.read_long
136
+ @log.debug "server reports sftp version #{server_version}" if @log.debug?
137
+
138
+ negotiated_version = [ @version, server_version ].min
139
+ @log.info "negotiated version is #{negotiated_version}" if @log.info?
140
+
141
+ extensions = Hash.new
142
+ until content.eof?
143
+ ext_name = content.read_string
144
+ ext_data = content.read_string
145
+ extensions[ ext_name ] = ext_data
146
+ end
147
+
148
+ @dispatcher = @dispatchers[ negotiated_version, extensions ]
149
+
150
+ @state = :open
151
+
152
+ @on_open.call( self ) if @on_open
153
+ end
154
+
155
+ # This is called internally when a data packet is received from the server.
156
+ # All SFTP packets are transfered as SSH data packets, so this parses the
157
+ # data packet to determine the SFTP packet type, and then sends the contents
158
+ # on to the active dispatcher for further processing. This routine correctly
159
+ # handles SFTP packets that span multiple SSH data packets.
160
+ def do_data( channel, data )
161
+ if @parsed_data
162
+ @parsed_data[:content].append data
163
+ return if @parsed_data[:length] > @parsed_data[:content].length
164
+
165
+ type = @parsed_data[:type]
166
+ content = @parsed_data[:content]
167
+ @parsed_data = nil
168
+ else
169
+ reader = @buffers.reader( data )
170
+ length = reader.read_long-1
171
+ type = reader.read_byte
172
+ content = reader.remainder_as_buffer
173
+
174
+ if length > content.length
175
+ @parsed_data = { :length => length,
176
+ :type => type,
177
+ :content => content }
178
+ return
179
+ end
180
+ end
181
+
182
+ if type == FXP_VERSION
183
+ do_version content
184
+ else
185
+ assert_state :open
186
+ @dispatcher.dispatch channel, type, content
187
+ end
188
+ end
189
+
190
+ # Delegates missing methods to the current dispatcher (if the state is
191
+ # +open+). This allows clients to register callbacks for the supported
192
+ # operations of the negotiated protocol version.
193
+ def method_missing( sym, *args, &block )
194
+ if @state == :open && @dispatcher.respond_to?( sym )
195
+ assert_state :open
196
+ @dispatcher.__send__( sym, *args, &block )
197
+ else
198
+ super
199
+ end
200
+ end
201
+
202
+ # Returns true if the driver responds to the given message, or if the
203
+ # state is +open+ and the active dispatcher responds to the given
204
+ # message.
205
+ def respond_to?( sym )
206
+ super || @state == :open && @dispatcher.respond_to?( sym )
207
+ end
208
+
209
+ # A convenience method for sending an SFTP packet of the given type,
210
+ # with the given payload. This repackages the data as an SSH data packet
211
+ # and sends it across the channel.
212
+ def send_data( type, data )
213
+ data = data.to_s
214
+
215
+ msg = @buffers.writer
216
+ msg.write_long data.length + 1
217
+ msg.write_byte type
218
+ msg.write data
219
+
220
+ @channel.send_data msg
221
+ end
222
+
223
+ # A sanity checker, to ensure that an operation is invoked only when the
224
+ # appropriate state is active.
225
+ def assert_state( state )
226
+ raise Net::SFTP::Bug, "invalid state `#{state}'" if state != @state
227
+ end
228
+ private :assert_state
229
+
230
+ end
231
+
232
+ end ; end ; end