net-sftp 0.5.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.
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