net-sftp 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/LICENSE-BSD +27 -0
- data/doc/LICENSE-GPL +280 -0
- data/doc/LICENSE-RUBY +56 -0
- data/examples/asynchronous.rb +57 -0
- data/examples/ssh-service.rb +31 -0
- data/examples/synchronous.rb +120 -0
- data/lib/net/sftp.rb +39 -0
- data/lib/net/sftp/errors.rb +25 -0
- data/lib/net/sftp/operations/abstract.rb +103 -0
- data/lib/net/sftp/operations/close.rb +31 -0
- data/lib/net/sftp/operations/errors.rb +76 -0
- data/lib/net/sftp/operations/fsetstat.rb +36 -0
- data/lib/net/sftp/operations/fstat.rb +32 -0
- data/lib/net/sftp/operations/lstat.rb +31 -0
- data/lib/net/sftp/operations/mkdir.rb +33 -0
- data/lib/net/sftp/operations/open.rb +32 -0
- data/lib/net/sftp/operations/opendir.rb +32 -0
- data/lib/net/sftp/operations/read.rb +84 -0
- data/lib/net/sftp/operations/readdir.rb +55 -0
- data/lib/net/sftp/operations/realpath.rb +37 -0
- data/lib/net/sftp/operations/remove.rb +31 -0
- data/lib/net/sftp/operations/rename.rb +32 -0
- data/lib/net/sftp/operations/rmdir.rb +31 -0
- data/lib/net/sftp/operations/services.rb +42 -0
- data/lib/net/sftp/operations/setstat.rb +33 -0
- data/lib/net/sftp/operations/stat.rb +31 -0
- data/lib/net/sftp/operations/write.rb +63 -0
- data/lib/net/sftp/protocol/01/attributes.rb +146 -0
- data/lib/net/sftp/protocol/01/impl.rb +251 -0
- data/lib/net/sftp/protocol/01/packet-assistant.rb +82 -0
- data/lib/net/sftp/protocol/01/services.rb +47 -0
- data/lib/net/sftp/protocol/02/impl.rb +39 -0
- data/lib/net/sftp/protocol/02/packet-assistant.rb +32 -0
- data/lib/net/sftp/protocol/02/services.rb +44 -0
- data/lib/net/sftp/protocol/03/impl.rb +42 -0
- data/lib/net/sftp/protocol/03/packet-assistant.rb +35 -0
- data/lib/net/sftp/protocol/03/services.rb +44 -0
- data/lib/net/sftp/protocol/04/attributes.rb +227 -0
- data/lib/net/sftp/protocol/04/impl.rb +134 -0
- data/lib/net/sftp/protocol/04/packet-assistant.rb +51 -0
- data/lib/net/sftp/protocol/04/services.rb +44 -0
- data/lib/net/sftp/protocol/05/services.rb +44 -0
- data/lib/net/sftp/protocol/constants.rb +60 -0
- data/lib/net/sftp/protocol/driver.rb +232 -0
- data/lib/net/sftp/protocol/packet-assistant.rb +84 -0
- data/lib/net/sftp/protocol/services.rb +55 -0
- data/lib/net/sftp/session.rb +215 -0
- data/lib/net/sftp/version.rb +25 -0
- data/test/ALL-TESTS.rb +21 -0
- data/test/operations/tc_abstract.rb +124 -0
- data/test/operations/tc_close.rb +40 -0
- data/test/operations/tc_fsetstat.rb +48 -0
- data/test/operations/tc_fstat.rb +40 -0
- data/test/operations/tc_lstat.rb +40 -0
- data/test/operations/tc_mkdir.rb +48 -0
- data/test/operations/tc_open.rb +42 -0
- data/test/operations/tc_opendir.rb +40 -0
- data/test/operations/tc_read.rb +103 -0
- data/test/operations/tc_readdir.rb +88 -0
- data/test/operations/tc_realpath.rb +54 -0
- data/test/operations/tc_remove.rb +40 -0
- data/test/operations/tc_rmdir.rb +40 -0
- data/test/operations/tc_setstat.rb +48 -0
- data/test/operations/tc_stat.rb +40 -0
- data/test/operations/tc_write.rb +91 -0
- data/test/protocol/01/tc_attributes.rb +138 -0
- data/test/protocol/01/tc_impl.rb +294 -0
- data/test/protocol/01/tc_packet_assistant.rb +81 -0
- data/test/protocol/02/tc_impl.rb +41 -0
- data/test/protocol/02/tc_packet_assistant.rb +31 -0
- data/test/protocol/03/tc_impl.rb +48 -0
- data/test/protocol/03/tc_packet_assistant.rb +34 -0
- data/test/protocol/04/tc_attributes.rb +174 -0
- data/test/protocol/04/tc_impl.rb +102 -0
- data/test/protocol/04/tc_packet_assistant.rb +41 -0
- data/test/protocol/tc_driver.rb +219 -0
- 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
|