hrr_rb_sftp 0.1.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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +25 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +135 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/demo/hrr_rb_sftp_server.rb +23 -0
  13. data/demo/instantiate_hrr_rb_sftp_server.rb +67 -0
  14. data/demo/spawn_hrr_rb_sftp_server.rb +66 -0
  15. data/hrr_rb_sftp.gemspec +26 -0
  16. data/lib/hrr_rb_sftp.rb +13 -0
  17. data/lib/hrr_rb_sftp/loggable.rb +41 -0
  18. data/lib/hrr_rb_sftp/protocol.rb +62 -0
  19. data/lib/hrr_rb_sftp/protocol/common.rb +10 -0
  20. data/lib/hrr_rb_sftp/protocol/common/data_type.rb +15 -0
  21. data/lib/hrr_rb_sftp/protocol/common/data_type/byte.rb +22 -0
  22. data/lib/hrr_rb_sftp/protocol/common/data_type/extension_pair.rb +23 -0
  23. data/lib/hrr_rb_sftp/protocol/common/data_type/extension_pairs.rb +24 -0
  24. data/lib/hrr_rb_sftp/protocol/common/data_type/string.rb +24 -0
  25. data/lib/hrr_rb_sftp/protocol/common/data_type/uint32.rb +22 -0
  26. data/lib/hrr_rb_sftp/protocol/common/data_type/uint64.rb +22 -0
  27. data/lib/hrr_rb_sftp/protocol/common/packet.rb +11 -0
  28. data/lib/hrr_rb_sftp/protocol/common/packet/001_ssh_fxp_init.rb +18 -0
  29. data/lib/hrr_rb_sftp/protocol/common/packet/002_ssh_fxp_version.rb +19 -0
  30. data/lib/hrr_rb_sftp/protocol/common/packetable.rb +72 -0
  31. data/lib/hrr_rb_sftp/protocol/version1.rb +10 -0
  32. data/lib/hrr_rb_sftp/protocol/version1/data_type.rb +11 -0
  33. data/lib/hrr_rb_sftp/protocol/version1/data_type/attrs.rb +54 -0
  34. data/lib/hrr_rb_sftp/protocol/version1/packet.rb +29 -0
  35. data/lib/hrr_rb_sftp/protocol/version1/packet/003_ssh_fxp_open.rb +109 -0
  36. data/lib/hrr_rb_sftp/protocol/version1/packet/004_ssh_fxp_close.rb +44 -0
  37. data/lib/hrr_rb_sftp/protocol/version1/packet/005_ssh_fxp_read.rb +53 -0
  38. data/lib/hrr_rb_sftp/protocol/version1/packet/006_ssh_fxp_write.rb +46 -0
  39. data/lib/hrr_rb_sftp/protocol/version1/packet/007_ssh_fxp_lstat.rb +62 -0
  40. data/lib/hrr_rb_sftp/protocol/version1/packet/008_ssh_fxp_fstat.rb +48 -0
  41. data/lib/hrr_rb_sftp/protocol/version1/packet/009_ssh_fxp_setstat.rb +63 -0
  42. data/lib/hrr_rb_sftp/protocol/version1/packet/010_ssh_fxp_fsetstat.rb +48 -0
  43. data/lib/hrr_rb_sftp/protocol/version1/packet/011_ssh_fxp_opendir.rb +65 -0
  44. data/lib/hrr_rb_sftp/protocol/version1/packet/012_ssh_fxp_readdir.rb +134 -0
  45. data/lib/hrr_rb_sftp/protocol/version1/packet/013_ssh_fxp_remove.rb +57 -0
  46. data/lib/hrr_rb_sftp/protocol/version1/packet/014_ssh_fxp_mkdir.rb +57 -0
  47. data/lib/hrr_rb_sftp/protocol/version1/packet/015_ssh_fxp_rmdir.rb +73 -0
  48. data/lib/hrr_rb_sftp/protocol/version1/packet/016_ssh_fxp_realpath.rb +30 -0
  49. data/lib/hrr_rb_sftp/protocol/version1/packet/017_ssh_fxp_stat.rb +62 -0
  50. data/lib/hrr_rb_sftp/protocol/version1/packet/101_ssh_fxp_status.rb +29 -0
  51. data/lib/hrr_rb_sftp/protocol/version1/packet/102_ssh_fxp_handle.rb +19 -0
  52. data/lib/hrr_rb_sftp/protocol/version1/packet/103_ssh_fxp_data.rb +19 -0
  53. data/lib/hrr_rb_sftp/protocol/version1/packet/104_ssh_fxp_name.rb +33 -0
  54. data/lib/hrr_rb_sftp/protocol/version1/packet/105_ssh_fxp_attrs.rb +19 -0
  55. data/lib/hrr_rb_sftp/protocol/version2.rb +10 -0
  56. data/lib/hrr_rb_sftp/protocol/version2/data_type.rb +9 -0
  57. data/lib/hrr_rb_sftp/protocol/version2/packet.rb +11 -0
  58. data/lib/hrr_rb_sftp/protocol/version2/packet/018_ssh_fxp_rename.rb +70 -0
  59. data/lib/hrr_rb_sftp/protocol/version3.rb +10 -0
  60. data/lib/hrr_rb_sftp/protocol/version3/data_type.rb +9 -0
  61. data/lib/hrr_rb_sftp/protocol/version3/packet.rb +16 -0
  62. data/lib/hrr_rb_sftp/protocol/version3/packet/014_ssh_fxp_mkdir.rb +58 -0
  63. data/lib/hrr_rb_sftp/protocol/version3/packet/019_ssh_fxp_readlink.rb +57 -0
  64. data/lib/hrr_rb_sftp/protocol/version3/packet/020_ssh_fxp_symlink.rb +58 -0
  65. data/lib/hrr_rb_sftp/protocol/version3/packet/101_ssh_fxp_status.rb +31 -0
  66. data/lib/hrr_rb_sftp/protocol/version3/packet/200_ssh_fxp_extended.rb +34 -0
  67. data/lib/hrr_rb_sftp/protocol/version3/packet/201_ssh_fxp_extended_reply.rb +23 -0
  68. data/lib/hrr_rb_sftp/receiver.rb +22 -0
  69. data/lib/hrr_rb_sftp/sender.rb +13 -0
  70. data/lib/hrr_rb_sftp/server.rb +96 -0
  71. data/lib/hrr_rb_sftp/version.rb +3 -0
  72. metadata +114 -0
@@ -0,0 +1,10 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ PROTOCOL_VERSION = 1
5
+ end
6
+ end
7
+ end
8
+
9
+ require "hrr_rb_sftp/protocol/version1/data_type"
10
+ require "hrr_rb_sftp/protocol/version1/packet"
@@ -0,0 +1,11 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module DataType
5
+ include Common::DataType
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ require "hrr_rb_sftp/protocol/version1/data_type/attrs"
@@ -0,0 +1,54 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module DataType
5
+ class Attrs
6
+ SSH_FILEXFER_ATTR_SIZE = 0x00000001
7
+ SSH_FILEXFER_ATTR_UIDGID = 0x00000002
8
+ SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004
9
+ SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008
10
+ SSH_FILEXFER_ATTR_EXTENDED = 0x80000000
11
+
12
+ def self.encode arg
13
+ unless arg.kind_of? ::Hash
14
+ raise ArgumentError, "must be a kind of Hash, but got #{arg.inspect}"
15
+ end
16
+
17
+ flags = 0
18
+ flags |= SSH_FILEXFER_ATTR_SIZE if arg.has_key?(:"size")
19
+ flags |= SSH_FILEXFER_ATTR_UIDGID if arg.has_key?(:"uid") && arg.has_key?(:"gid")
20
+ flags |= SSH_FILEXFER_ATTR_PERMISSIONS if arg.has_key?(:"permissions")
21
+ flags |= SSH_FILEXFER_ATTR_ACMODTIME if arg.has_key?(:"atime") && arg.has_key?(:"mtime")
22
+ flags |= SSH_FILEXFER_ATTR_EXTENDED if arg.has_key?(:"extensions")
23
+
24
+ payload = DataType::Uint32.encode flags
25
+ payload += DataType::Uint64.encode arg[:"size"] unless (flags & SSH_FILEXFER_ATTR_SIZE).zero?
26
+ payload += DataType::Uint32.encode arg[:"uid"] unless (flags & SSH_FILEXFER_ATTR_UIDGID).zero?
27
+ payload += DataType::Uint32.encode arg[:"gid"] unless (flags & SSH_FILEXFER_ATTR_UIDGID).zero?
28
+ payload += DataType::Uint32.encode arg[:"permissions"] unless (flags & SSH_FILEXFER_ATTR_PERMISSIONS).zero?
29
+ payload += DataType::Uint32.encode arg[:"atime"] unless (flags & SSH_FILEXFER_ATTR_ACMODTIME).zero?
30
+ payload += DataType::Uint32.encode arg[:"mtime"] unless (flags & SSH_FILEXFER_ATTR_ACMODTIME).zero?
31
+ payload += DataType::Uint32.encode arg[:"extensions"].size unless (flags & SSH_FILEXFER_ATTR_EXTENDED).zero?
32
+ payload += DataType::ExtensionPairs.encode arg[:"extensions"] unless (flags & SSH_FILEXFER_ATTR_EXTENDED).zero?
33
+ payload
34
+ end
35
+
36
+ def self.decode io
37
+ attrs = Hash.new
38
+ flags = DataType::Uint32.decode(io)
39
+ attrs[:"size"] = DataType::Uint64.decode(io) unless (flags & SSH_FILEXFER_ATTR_SIZE).zero?
40
+ attrs[:"uid"] = DataType::Uint32.decode(io) unless (flags & SSH_FILEXFER_ATTR_UIDGID).zero?
41
+ attrs[:"gid"] = DataType::Uint32.decode(io) unless (flags & SSH_FILEXFER_ATTR_UIDGID).zero?
42
+ attrs[:"permissions"] = DataType::Uint32.decode(io) unless (flags & SSH_FILEXFER_ATTR_PERMISSIONS).zero?
43
+ attrs[:"atime"] = DataType::Uint32.decode(io) unless (flags & SSH_FILEXFER_ATTR_ACMODTIME).zero?
44
+ attrs[:"mtime"] = DataType::Uint32.decode(io) unless (flags & SSH_FILEXFER_ATTR_ACMODTIME).zero?
45
+ extended_count = DataType::Uint32.decode(io) unless (flags & SSH_FILEXFER_ATTR_EXTENDED).zero?
46
+ attrs[:"extensions"] = Array.new(extended_count){DataType::ExtensionPair.decode(io)} unless (flags & SSH_FILEXFER_ATTR_EXTENDED).zero?
47
+ attrs
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,29 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module Packet
5
+ end
6
+ end
7
+ end
8
+ end
9
+
10
+ require "hrr_rb_sftp/protocol/version1/packet/003_ssh_fxp_open"
11
+ require "hrr_rb_sftp/protocol/version1/packet/004_ssh_fxp_close"
12
+ require "hrr_rb_sftp/protocol/version1/packet/005_ssh_fxp_read"
13
+ require "hrr_rb_sftp/protocol/version1/packet/006_ssh_fxp_write"
14
+ require "hrr_rb_sftp/protocol/version1/packet/007_ssh_fxp_lstat"
15
+ require "hrr_rb_sftp/protocol/version1/packet/008_ssh_fxp_fstat"
16
+ require "hrr_rb_sftp/protocol/version1/packet/009_ssh_fxp_setstat"
17
+ require "hrr_rb_sftp/protocol/version1/packet/010_ssh_fxp_fsetstat"
18
+ require "hrr_rb_sftp/protocol/version1/packet/011_ssh_fxp_opendir"
19
+ require "hrr_rb_sftp/protocol/version1/packet/012_ssh_fxp_readdir"
20
+ require "hrr_rb_sftp/protocol/version1/packet/013_ssh_fxp_remove"
21
+ require "hrr_rb_sftp/protocol/version1/packet/014_ssh_fxp_mkdir"
22
+ require "hrr_rb_sftp/protocol/version1/packet/015_ssh_fxp_rmdir"
23
+ require "hrr_rb_sftp/protocol/version1/packet/016_ssh_fxp_realpath"
24
+ require "hrr_rb_sftp/protocol/version1/packet/017_ssh_fxp_stat"
25
+ require "hrr_rb_sftp/protocol/version1/packet/101_ssh_fxp_status"
26
+ require "hrr_rb_sftp/protocol/version1/packet/102_ssh_fxp_handle"
27
+ require "hrr_rb_sftp/protocol/version1/packet/103_ssh_fxp_data"
28
+ require "hrr_rb_sftp/protocol/version1/packet/104_ssh_fxp_name"
29
+ require "hrr_rb_sftp/protocol/version1/packet/105_ssh_fxp_attrs"
@@ -0,0 +1,109 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module Packet
5
+ class SSH_FXP_OPEN
6
+ include Common::Packetable
7
+
8
+ TYPE = 3
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id"],
13
+ [DataType::String, :"filename" ],
14
+ [DataType::Uint32, :"pflags" ],
15
+ [DataType::Attrs, :"attrs" ],
16
+ ]
17
+
18
+ SSH_FXF_READ = 0x00000001
19
+ SSH_FXF_WRITE = 0x00000002
20
+ SSH_FXF_APPEND = 0x00000004
21
+ SSH_FXF_CREAT = 0x00000008
22
+ SSH_FXF_TRUNC = 0x00000010
23
+ SSH_FXF_EXCL = 0x00000020
24
+
25
+ class Error < StandardError
26
+ end
27
+
28
+ def convert_pflags_to_flags pflags
29
+ flags = 0
30
+ if ((pflags & SSH_FXF_READ) == SSH_FXF_READ) && ((pflags & SSH_FXF_WRITE) == SSH_FXF_WRITE)
31
+ flags |= ::File::RDWR
32
+ elsif (pflags & SSH_FXF_READ) == SSH_FXF_READ
33
+ flags |= ::File::RDONLY
34
+ elsif (pflags & SSH_FXF_WRITE) == SSH_FXF_WRITE
35
+ flags |= ::File::WRONLY
36
+ else
37
+ raise Error, "At least SSH_FXF_READ or SSH_FXF_READ must be specified"
38
+ end
39
+ if (pflags & SSH_FXF_APPEND) == SSH_FXF_APPEND
40
+ flags |= ::File::APPEND
41
+ end
42
+ if (pflags & SSH_FXF_CREAT) == SSH_FXF_CREAT
43
+ flags |= ::File::CREAT
44
+ flags |= ::File::TRUNC if (pflags & SSH_FXF_TRUNC) == SSH_FXF_TRUNC
45
+ flags |= ::File::EXCL if (pflags & SSH_FXF_EXCL ) == SSH_FXF_EXCL
46
+ elsif (pflags & SSH_FXF_TRUNC) == SSH_FXF_TRUNC
47
+ raise Error, "SSH_FXF_CREAT MUST also be specified when SSH_FXF_TRUNC is specified"
48
+ elsif (pflags & SSH_FXF_EXCL) == SSH_FXF_EXCL
49
+ raise Error, "SSH_FXF_CREAT MUST also be specified when SSH_FXF_EXCL is specified"
50
+ end
51
+ flags |= ::File::BINARY
52
+ flags
53
+ end
54
+
55
+ def respond_to request
56
+ begin
57
+ flags = convert_pflags_to_flags request[:"pflags"]
58
+ args = [request[:"filename"], flags]
59
+ if request[:"attrs"].has_key?(:"permissions")
60
+ args.push request[:"attrs"][:"permissions"]
61
+ end
62
+ file = ::File.open(*args)
63
+ handle = file.object_id.to_s(16)
64
+ @handles[handle] = file
65
+ {
66
+ :"type" => SSH_FXP_HANDLE::TYPE,
67
+ :"request-id" => request[:"request-id"],
68
+ :"handle" => handle,
69
+ }
70
+ rescue Error => e
71
+ {
72
+ :"type" => SSH_FXP_STATUS::TYPE,
73
+ :"request-id" => request[:"request-id"],
74
+ :"code" => SSH_FXP_STATUS::SSH_FX_FAILURE,
75
+ :"error message" => e.message,
76
+ :"language tag" => "",
77
+ }
78
+ rescue Errno::ENOENT
79
+ {
80
+ :"type" => SSH_FXP_STATUS::TYPE,
81
+ :"request-id" => request[:"request-id"],
82
+ :"code" => SSH_FXP_STATUS::SSH_FX_NO_SUCH_FILE,
83
+ :"error message" => "No such file or directory",
84
+ :"language tag" => "",
85
+ }
86
+ rescue Errno::EACCES
87
+ {
88
+ :"type" => SSH_FXP_STATUS::TYPE,
89
+ :"request-id" => request[:"request-id"],
90
+ :"code" => SSH_FXP_STATUS::SSH_FX_PERMISSION_DENIED,
91
+ :"error message" => "Permission denied",
92
+ :"language tag" => "",
93
+ }
94
+ rescue => e
95
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
96
+ {
97
+ :"type" => SSH_FXP_STATUS::TYPE,
98
+ :"request-id" => request[:"request-id"],
99
+ :"code" => SSH_FXP_STATUS::SSH_FX_FAILURE,
100
+ :"error message" => e.message,
101
+ :"language tag" => "",
102
+ }
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,44 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module Packet
5
+ class SSH_FXP_CLOSE
6
+ include Common::Packetable
7
+
8
+ TYPE = 4
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id"],
13
+ [DataType::String, :"handle" ],
14
+ ]
15
+
16
+ def respond_to request
17
+ begin
18
+ raise "Specified handle does not exist" unless @handles.has_key?(request[:"handle"])
19
+ handle = request[:"handle"]
20
+ @handles[handle].close rescue nil
21
+ @handles.delete(handle)
22
+ {
23
+ :"type" => SSH_FXP_STATUS::TYPE,
24
+ :"request-id" => request[:"request-id"],
25
+ :"code" => SSH_FXP_STATUS::SSH_FX_OK,
26
+ :"error message" => "Success",
27
+ :"language tag" => "",
28
+ }
29
+ rescue => e
30
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
31
+ {
32
+ :"type" => SSH_FXP_STATUS::TYPE,
33
+ :"request-id" => request[:"request-id"],
34
+ :"code" => SSH_FXP_STATUS::SSH_FX_FAILURE,
35
+ :"error message" => e.message,
36
+ :"language tag" => "",
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module Packet
5
+ class SSH_FXP_READ
6
+ include Common::Packetable
7
+
8
+ TYPE = 5
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id"],
13
+ [DataType::String, :"handle" ],
14
+ [DataType::Uint64, :"offset" ],
15
+ [DataType::Uint32, :"len" ],
16
+ ]
17
+
18
+ def respond_to request
19
+ begin
20
+ raise "Specified handle does not exist" unless @handles.has_key?(request[:"handle"])
21
+ file = @handles[request[:"handle"]]
22
+ file.pos = request[:"offset"]
23
+ unless file.eof?
24
+ {
25
+ :"type" => SSH_FXP_DATA::TYPE,
26
+ :"request-id" => request[:"request-id"],
27
+ :"data" => file.read(request[:"len"]),
28
+ }
29
+ else
30
+ {
31
+ :"type" => SSH_FXP_STATUS::TYPE,
32
+ :"request-id" => request[:"request-id"],
33
+ :"code" => SSH_FXP_STATUS::SSH_FX_EOF,
34
+ :"error message" => "End of file",
35
+ :"language tag" => "",
36
+ }
37
+ end
38
+ rescue => e
39
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
40
+ {
41
+ :"type" => SSH_FXP_STATUS::TYPE,
42
+ :"request-id" => request[:"request-id"],
43
+ :"code" => SSH_FXP_STATUS::SSH_FX_FAILURE,
44
+ :"error message" => e.message,
45
+ :"language tag" => "",
46
+ }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module Packet
5
+ class SSH_FXP_WRITE
6
+ include Common::Packetable
7
+
8
+ TYPE = 6
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id"],
13
+ [DataType::String, :"handle" ],
14
+ [DataType::Uint64, :"offset" ],
15
+ [DataType::String, :"data" ],
16
+ ]
17
+
18
+ def respond_to request
19
+ begin
20
+ raise "Specified handle does not exist" unless @handles.has_key?(request[:"handle"])
21
+ file = @handles[request[:"handle"]]
22
+ file.pos = request[:"offset"]
23
+ file.write request[:"data"]
24
+ {
25
+ :"type" => SSH_FXP_STATUS::TYPE,
26
+ :"request-id" => request[:"request-id"],
27
+ :"code" => SSH_FXP_STATUS::SSH_FX_OK,
28
+ :"error message" => "Success",
29
+ :"language tag" => "",
30
+ }
31
+ rescue => e
32
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
33
+ {
34
+ :"type" => SSH_FXP_STATUS::TYPE,
35
+ :"request-id" => request[:"request-id"],
36
+ :"code" => SSH_FXP_STATUS::SSH_FX_FAILURE,
37
+ :"error message" => e.message,
38
+ :"language tag" => "",
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module Packet
5
+ class SSH_FXP_LSTAT
6
+ include Common::Packetable
7
+
8
+ TYPE = 7
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id"],
13
+ [DataType::String, :"path" ],
14
+ ]
15
+
16
+ def respond_to request
17
+ begin
18
+ stat = File.lstat(request[:"path"])
19
+ attrs = Hash.new
20
+ attrs[:"size"] = stat.size if stat.size
21
+ attrs[:"uid"] = stat.uid if stat.uid
22
+ attrs[:"gid"] = stat.gid if stat.gid
23
+ attrs[:"permissions"] = stat.mode if stat.mode
24
+ attrs[:"atime"] = stat.atime.to_i if stat.atime
25
+ attrs[:"mtime"] = stat.mtime.to_i if stat.mtime
26
+ {
27
+ :"type" => SSH_FXP_ATTRS::TYPE,
28
+ :"request-id" => request[:"request-id"],
29
+ :"attrs" => attrs,
30
+ }
31
+ rescue Errno::ENOENT
32
+ {
33
+ :"type" => SSH_FXP_STATUS::TYPE,
34
+ :"request-id" => request[:"request-id"],
35
+ :"code" => SSH_FXP_STATUS::SSH_FX_NO_SUCH_FILE,
36
+ :"error message" => "No such file or directory",
37
+ :"language tag" => "",
38
+ }
39
+ rescue Errno::EACCES
40
+ {
41
+ :"type" => SSH_FXP_STATUS::TYPE,
42
+ :"request-id" => request[:"request-id"],
43
+ :"code" => SSH_FXP_STATUS::SSH_FX_PERMISSION_DENIED,
44
+ :"error message" => "Permission denied",
45
+ :"language tag" => "",
46
+ }
47
+ rescue => e
48
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
49
+ {
50
+ :"type" => SSH_FXP_STATUS::TYPE,
51
+ :"request-id" => request[:"request-id"],
52
+ :"code" => SSH_FXP_STATUS::SSH_FX_FAILURE,
53
+ :"error message" => e.message,
54
+ :"language tag" => "",
55
+ }
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,48 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version1
4
+ module Packet
5
+ class SSH_FXP_FSTAT
6
+ include Common::Packetable
7
+
8
+ TYPE = 8
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id"],
13
+ [DataType::String, :"handle" ],
14
+ ]
15
+
16
+ def respond_to request
17
+ begin
18
+ raise "Specified handle does not exist" unless @handles.has_key?(request[:"handle"])
19
+ file = @handles[request[:"handle"]]
20
+ stat = file.stat
21
+ attrs = Hash.new
22
+ attrs[:"size"] = stat.size if stat.size
23
+ attrs[:"uid"] = stat.uid if stat.uid
24
+ attrs[:"gid"] = stat.gid if stat.gid
25
+ attrs[:"permissions"] = stat.mode if stat.mode
26
+ attrs[:"atime"] = stat.atime.to_i if stat.atime
27
+ attrs[:"mtime"] = stat.mtime.to_i if stat.mtime
28
+ {
29
+ :"type" => SSH_FXP_ATTRS::TYPE,
30
+ :"request-id" => request[:"request-id"],
31
+ :"attrs" => attrs,
32
+ }
33
+ rescue => e
34
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
35
+ {
36
+ :"type" => SSH_FXP_STATUS::TYPE,
37
+ :"request-id" => request[:"request-id"],
38
+ :"code" => SSH_FXP_STATUS::SSH_FX_FAILURE,
39
+ :"error message" => e.message,
40
+ :"language tag" => "",
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end