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