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,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