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,84 @@
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
+ # This is the abstract base class for all packet assistant classes used by
20
+ # the supported SFTP protocol versions.
21
+ class PacketAssistant
22
+
23
+ # A helper method for defining a new packet type. The +name+ is the name
24
+ # of the packet (and of the corresponding method that is created), and the
25
+ # arguments are symbols representing the types of each element in the
26
+ # packet. The supported types are:
27
+ #
28
+ # * :long
29
+ # * :int64
30
+ # * :short
31
+ # * :byte
32
+ # * :string
33
+ # * :attrs
34
+ # * :write
35
+ #
36
+ # The :attrs and :write types both simply convert the argument to a string.
37
+ #
38
+ # The method that is created always supports an +id+ parameter in the
39
+ # first position, which if null will default to the next available request
40
+ # id. The method returns a tuple consisting of the request id, and a string
41
+ # consisting of the arguments formatted according to the packet's
42
+ # description.
43
+ def self.packet( name, *args )
44
+ body = ""
45
+ args.each do |arg|
46
+ body << "b.write"
47
+ case arg
48
+ when :long, :int64, :short, :byte
49
+ body << "_#{arg} args.shift.to_i"
50
+ when :string
51
+ body << "_#{arg} args.shift.to_s"
52
+ when :attrs, :write
53
+ body << " args.shift.to_s"
54
+ end
55
+ body << "\n"
56
+ end
57
+ class_eval <<-EOF, __FILE__, __LINE__+1
58
+ def #{name}( id, *args )
59
+ b = buffers.writer
60
+ id ||= driver.next_request_id
61
+ b.write_long id
62
+ #{body}
63
+ [ id, b.to_s ]
64
+ end
65
+ EOF
66
+ end
67
+
68
+ # The buffer factory in use by this packet assistant, used to build the
69
+ # packets.
70
+ attr_reader :buffers
71
+
72
+ # The protocol driver that will be used to obtain request ids.
73
+ attr_reader :driver
74
+
75
+ # Create a new PacketAssistant, which will use the given buffer factory and
76
+ # SFTP protocol driver.
77
+ def initialize( buffers, driver )
78
+ @buffers = buffers
79
+ @driver = driver
80
+ end
81
+
82
+ end
83
+
84
+ end ; end ; end
@@ -0,0 +1,55 @@
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
+ def register_services( container )
20
+ container.namespace_define :protocol do |ns|
21
+
22
+ # The maximum version of the SFTP protocol supported by this
23
+ # implementation. Clients may set this to a lower value to force the
24
+ # usage of a specific SFTP version. It should _not_ be set higher than
25
+ # the value that is given below.
26
+ ns.version { 5 }
27
+
28
+ # A proc object that, when invoked, returns a dispatcher object capable
29
+ # of handling the requested protocol version.
30
+ ns.dispatcher_factory do |c,|
31
+ lambda do |version, extensions|
32
+ version = "%02d" % version
33
+ c.require "net/sftp/protocol/#{version}/services",
34
+ "#{self}::V_#{version}"
35
+ impl = c["v_#{version}".to_sym][:impl]
36
+ impl.extensions = extensions
37
+ impl
38
+ end
39
+ end
40
+
41
+ # The driver service that manages the SFTP protocol-level communications
42
+ ns.driver do |c,p|
43
+ require 'net/sftp/protocol/driver'
44
+ Driver.new( c[:connection][:driver],
45
+ c[:transport][:buffers],
46
+ c[:version],
47
+ c[:dispatcher_factory],
48
+ c[:log_for, p] )
49
+ end
50
+
51
+ end
52
+ end
53
+ module_function :register_services
54
+
55
+ end ; end ; end
@@ -0,0 +1,215 @@
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/errors'
18
+ require 'net/sftp/protocol/constants'
19
+
20
+ module Net ; module SFTP
21
+
22
+ # Represents a single SFTP session, running atop an SSH session.
23
+ class Session
24
+ include Protocol::Constants
25
+
26
+ # The status of the last synchronously executed operation. This is either
27
+ # +nil+, or an object that responds to <tt>:code</tt>, <tt>:message</tt>,
28
+ # and <tt>:language</tt>.
29
+ attr_accessor :status
30
+
31
+ # Create a new SFTP session on top of the given SSH session.
32
+ def initialize( session )
33
+ @session = session
34
+ @log = @session.registry.log_for( "sftp.session" )
35
+
36
+ @session.registry.namespace_define :sftp do |ns|
37
+ ns.require "net/sftp/protocol/services", "Net::SFTP::Protocol"
38
+ ns.require "net/sftp/operations/services", "Net::SFTP::Operations"
39
+
40
+ # register a reference to myself for other services to be able to
41
+ # access me.
42
+ ns.session( :pipeline => [] ) { self }
43
+
44
+ @driver = ns.protocol.driver
45
+ @driver.on_open do |d|
46
+ d.on_attrs &method( :do_attrs )
47
+ d.on_data &method( :do_data )
48
+ d.on_handle &method( :do_handle )
49
+ d.on_name &method( :do_name )
50
+ d.on_status &method( :do_status )
51
+
52
+ if block_given?
53
+ begin
54
+ yield self
55
+ ensure
56
+ d.close
57
+ end
58
+ end
59
+ end
60
+
61
+ @operations = ns.operations
62
+ end
63
+
64
+ @requests = Hash.new
65
+
66
+ @session.loop if block_given?
67
+ end
68
+
69
+ #--
70
+ # ====================================================================
71
+ # QUERIES/GETTERS/SETTERS/ACTIONS
72
+ # ====================================================================
73
+ #++
74
+
75
+ # Return the state of the SFTP connection. (See
76
+ # Net::SFTP::Protocol::Driver#state.)
77
+ def state
78
+ @driver.state
79
+ end
80
+
81
+ # Closes the SFTP connection, but leaves the SSH connection open.
82
+ def close_channel
83
+ @driver.close
84
+ end
85
+
86
+ # Closes the underlying SSH connection.
87
+ def close
88
+ @session.close
89
+ end
90
+
91
+ # Registers the given handler with the given request id. This is used
92
+ # internally by the operations, so that the session knows who to delegate
93
+ # a response to that has been received from the server.
94
+ def register( id, handler )
95
+ @requests[ id ] = handler
96
+ end
97
+
98
+ # Delegates to Net::SSH::Session#loop. Causes the underlying SSH
99
+ # connection to process events as long as the given block returns +true+,
100
+ # or (if no block is given) until there are no more open channels.
101
+ def loop( &block )
102
+ @session.loop( &block )
103
+ end
104
+
105
+ # Waits for the underlying driver to reach a state of :open (or :closed).
106
+ # This makes it easier to use the SFTP routines synchronously without using
107
+ # the block form:
108
+ #
109
+ # sftp = Net::SFTP::Session.new( ssh_session )
110
+ # sftp.connect
111
+ # puts sftp.realpath( "." )
112
+ #
113
+ # Without the call to #connect, the call to #realpath would fail because
114
+ # the SFTP protocol has not yet been negotiated and no underlying driver has
115
+ # been selected.
116
+ #
117
+ # If no block is given, it teturns +self+, so it can be chained easily to
118
+ # other method calls. If a block _is_ given, the session is yielded to the
119
+ # block as soon as the driver successfully reports it's state as +open+,
120
+ # with the session's channel being closed automatically when the block
121
+ # finishes.
122
+ #
123
+ # require 'net/ssh'
124
+ # require 'net/sftp'
125
+ #
126
+ # Net::SSH.start( 'localhost' ) do |session|
127
+ # session.sftp.connect do |sftp|
128
+ # puts sftp.realpath( "." )
129
+ # end
130
+ # end
131
+ def connect
132
+ @session.loop do
133
+ @driver.state != :open &&
134
+ @driver.state != :closed
135
+ end
136
+ if @driver.state == :open && block_given?
137
+ begin
138
+ yield self
139
+ ensure
140
+ close_channel
141
+ end
142
+ else
143
+ self
144
+ end
145
+ end
146
+
147
+ #--
148
+ # ====================================================================
149
+ # CALLBACKS
150
+ # ====================================================================
151
+ #++
152
+
153
+ # Invoked by the underlying SFTP protocol layer when a SFTP data packet
154
+ # is received.
155
+ def do_data( driver, id, data )
156
+ @requests.delete( id ).do_data( data )
157
+ end
158
+
159
+ # Invoked by the underlying SFTP protocol layer when a SFTP status packet
160
+ # is received.
161
+ def do_status( driver, id, code, message, language )
162
+ @requests.delete( id ).do_status( code, message, language )
163
+ end
164
+
165
+ # Invoked by the underlying SFTP protocol layer when a SFTP handle packet
166
+ # is received.
167
+ def do_handle( driver, id, handle )
168
+ @requests.delete( id ).do_handle( handle )
169
+ end
170
+
171
+ # Invoked by the underlying SFTP protocol layer when a SFTP name packet
172
+ # is received.
173
+ def do_name( driver, id, items )
174
+ @requests.delete( id ).do_name( items )
175
+ end
176
+
177
+ # Invoked by the underlying SFTP protocol layer when a SFTP attrs packet
178
+ # is received.
179
+ def do_attrs( driver, id, attributes )
180
+ @requests.delete( id ).do_attrs( attributes )
181
+ end
182
+
183
+ #--
184
+ # ====================================================================
185
+ # DELEGATION
186
+ # ====================================================================
187
+ #++
188
+
189
+ # Delegates the message to the operation that has been registered with
190
+ # the given name. If no such operation exists, control is passed to the
191
+ # superclass' implementation of #method_missing.
192
+ def method_missing( sym, *args, &block )
193
+ if @operations.has_key?( sym )
194
+ @operations[ sym ].execute( *args, &block )
195
+ else
196
+ super
197
+ end
198
+ end
199
+
200
+ # Returns +true+ if the object responds to the given symbol, or if there is
201
+ # an operation registered under the given symbol.
202
+ def respond_to?( sym )
203
+ super || @operations.has_key?( sym )
204
+ end
205
+
206
+ # Returns +true+ if the underlying driver responds to the given symbol. This
207
+ # can be used by clients to determine whether the SFTP protocol version in
208
+ # use supports a particular operation.
209
+ def support?( sym )
210
+ @driver.respond_to?( sym )
211
+ end
212
+
213
+ end
214
+
215
+ end ; end
@@ -0,0 +1,25 @@
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 Version
18
+
19
+ MAJOR = 0
20
+ MINOR = 5
21
+ TINY = 0
22
+
23
+ STRING = [MAJOR,MINOR,TINY].join('.')
24
+
25
+ end ; end ; end
data/test/ALL-TESTS.rb ADDED
@@ -0,0 +1,21 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # This source file is distributed as part of the Net::SFTP Secure FTP Client
7
+ # library for Ruby. This file (and the library as a whole) may be used only as
8
+ # allowed by either the BSD license, or the Ruby license (or, by association
9
+ # with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SFTP
10
+ # distribution for the texts of these licenses.
11
+ # -----------------------------------------------------------------------------
12
+ # net-sftp website: http://net-ssh.rubyforge.org/sftp
13
+ # project website : http://rubyforge.org/projects/net-ssh
14
+ # =============================================================================
15
+ #++
16
+
17
+ $:.unshift "../lib"
18
+
19
+ $run_integration_tests = ARGV.include?( "-i" )
20
+
21
+ Dir["**/tc_*.rb"].each { |f| load f }
@@ -0,0 +1,124 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # This source file is distributed as part of the Net::SFTP Secure FTP Client
7
+ # library for Ruby. This file (and the library as a whole) may be used only as
8
+ # allowed by either the BSD license, or the Ruby license (or, by association
9
+ # with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SFTP
10
+ # distribution for the texts of these licenses.
11
+ # -----------------------------------------------------------------------------
12
+ # net-sftp website: http://net-ssh.rubyforge.org/sftp
13
+ # project website : http://rubyforge.org/projects/net-ssh
14
+ # =============================================================================
15
+ #++
16
+
17
+ $:.unshift "../../lib"
18
+
19
+ require 'test/unit'
20
+ require 'net/sftp/operations/abstract'
21
+ require 'flexmock'
22
+
23
+ class TC_Operations_Abstract < Test::Unit::TestCase
24
+
25
+ class Subclass < Net::SFTP::Operations::Abstract
26
+ attr_reader :args
27
+
28
+ def perform( *args )
29
+ @args = args
30
+ 14
31
+ end
32
+ end
33
+
34
+ def setup
35
+ @log = FlexMock.new
36
+ @log.mock_handle( :debug )
37
+ @log.mock_handle( :debug? )
38
+
39
+ @session = FlexMock.new
40
+ @session.mock_handle( :status= )
41
+ @session.mock_handle( :register )
42
+ @session.mock_handle( :loop )
43
+
44
+ @driver = FlexMock.new
45
+
46
+ @operation = Subclass.new( @log, @session, @driver )
47
+ end
48
+
49
+ def test_execute_no_block
50
+ reg_args = nil
51
+ @session.mock_handle( :register ) { |*a| reg_args = a }
52
+
53
+ @operation.execute( :foo, :bar )
54
+
55
+ assert_equal 1, @session.mock_count( :register )
56
+ assert_equal 1, @session.mock_count( :loop )
57
+ assert_equal [ 14, @operation ], reg_args
58
+ assert_equal [ :foo, :bar ], @operation.args
59
+ end
60
+
61
+ def test_execute_with_block
62
+ reg_args = nil
63
+ @session.mock_handle( :register ) { |*a| reg_args = a }
64
+
65
+ @operation.execute( :foo, :bar ) { }
66
+
67
+ assert_equal 1, @session.mock_count( :register )
68
+ assert_equal 0, @session.mock_count( :loop )
69
+ assert_equal [ 14, @operation ], reg_args
70
+ assert_equal [ :foo, :bar ], @operation.args
71
+ end
72
+
73
+ def test_do_status_bad
74
+ assert_raise( Net::SFTP::Operations::StatusException ) do
75
+ @operation.do_status( 5, nil, nil )
76
+ end
77
+ end
78
+
79
+ def test_status_ok
80
+ status = nil
81
+ @operation.execute( :foo, :bar ) { |s| status = s }
82
+ assert_nothing_raised { @operation.do_status( 0, "hello", "world" ) }
83
+ assert_equal 0, status.code
84
+ assert_equal "hello", status.message
85
+ assert_equal "world", status.language
86
+ end
87
+
88
+ def test_do_handle
89
+ status = nil
90
+ handle = nil
91
+ @operation.execute( :foo, :bar ) { |s,h| status, handle = s, h }
92
+ @operation.do_handle( "foo" )
93
+ assert_equal 0, status.code
94
+ assert_equal "foo", handle
95
+ end
96
+
97
+ def test_do_data
98
+ status = nil
99
+ data = nil
100
+ @operation.execute( :foo, :bar ) { |s,d| status, data = s, d }
101
+ @operation.do_data( "foo" )
102
+ assert_equal 0, status.code
103
+ assert_equal "foo", data
104
+ end
105
+
106
+ def test_do_name
107
+ status = nil
108
+ name = nil
109
+ @operation.execute( :foo, :bar ) { |s,n| status, name = s, n }
110
+ @operation.do_name( "foo" )
111
+ assert_equal 0, status.code
112
+ assert_equal "foo", name
113
+ end
114
+
115
+ def test_do_attrs
116
+ status = nil
117
+ attrs = nil
118
+ @operation.execute( :foo, :bar ) { |s,a| status, attrs = s, a }
119
+ @operation.do_attrs( "foo" )
120
+ assert_equal 0, status.code
121
+ assert_equal "foo", attrs
122
+ end
123
+
124
+ end