ruby_smb 3.1.0 → 3.1.3
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/examples/file_server.rb +6 -61
- data/examples/virtual_file_server.rb +91 -0
- data/lib/ruby_smb/client/negotiation.rb +7 -7
- data/lib/ruby_smb/client.rb +2 -2
- data/lib/ruby_smb/fscc/file_information/file_access_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_alignment_information.rb +45 -0
- data/lib/ruby_smb/fscc/file_information/file_all_information.rb +23 -0
- data/lib/ruby_smb/fscc/file_information/file_basic_information.rb +20 -0
- data/lib/ruby_smb/fscc/file_information/file_both_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_ea_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_information/file_full_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_id_both_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_id_full_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_internal_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_mode_information.rb +29 -0
- data/lib/ruby_smb/fscc/file_information/file_name_information.rb +16 -0
- data/lib/ruby_smb/fscc/file_information/file_names_information.rb +1 -1
- data/lib/ruby_smb/fscc/file_information/file_normalized_name_information.rb +16 -0
- data/lib/ruby_smb/fscc/file_information/file_position_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_rename_information.rb +1 -1
- data/lib/ruby_smb/fscc/file_information/file_standard_information.rb +20 -0
- data/lib/ruby_smb/fscc/file_information/file_stream_information.rb +3 -0
- data/lib/ruby_smb/fscc/file_information.rb +41 -8
- data/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_system_information.rb +4 -0
- data/lib/ruby_smb/gss/provider/ntlm.rb +20 -3
- data/lib/ruby_smb/gss/provider.rb +10 -1
- data/lib/ruby_smb/ntlm/client.rb +74 -0
- data/lib/ruby_smb/ntlm.rb +1 -0
- data/lib/ruby_smb/server/cli.rb +121 -0
- data/lib/ruby_smb/server/server_client/session_setup.rb +4 -2
- data/lib/ruby_smb/server/server_client.rb +9 -1
- data/lib/ruby_smb/server/session.rb +5 -1
- data/lib/ruby_smb/server/share/provider/disk/processor/close.rb +9 -5
- data/lib/ruby_smb/server/share/provider/disk/processor/create.rb +2 -2
- data/lib/ruby_smb/server/share/provider/disk/processor/query.rb +2 -2
- data/lib/ruby_smb/server/share/provider/disk/processor/read.rb +15 -14
- data/lib/ruby_smb/server/share/provider/disk/processor.rb +76 -12
- data/lib/ruby_smb/server/share/provider/disk.rb +8 -2
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_file.rb +85 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_pathname.rb +196 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_stat.rb +175 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk.rb +116 -0
- data/lib/ruby_smb/server/share/provider.rb +1 -0
- data/lib/ruby_smb/server.rb +14 -3
- data/lib/ruby_smb/smb2/tree.rb +1 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +11 -2
- data/spec/lib/ruby_smb/fscc/file_information/file_access_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_alignment_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_all_information_spec.rb +61 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_basic_information_spec.rb +41 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_both_directory_information_spec.rb +59 -10
- data/spec/lib/ruby_smb/fscc/file_information/file_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_ea_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_full_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_id_both_directory_information_spec.rb +63 -10
- data/spec/lib/ruby_smb/fscc/file_information/file_id_full_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_internal_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_mode_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_name_information_spec.rb +44 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_names_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_network_open_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_normalized_name_information_spec.rb +44 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_position_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_rename_information_spec.rb +1 -1
- data/spec/lib/ruby_smb/fscc/file_information/file_standard_information_spec.rb +41 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_stream_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_information_spec.rb +14 -0
- data/spec/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information_spec.rb +46 -0
- data/spec/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_system_information_spec.rb +14 -0
- data/spec/lib/ruby_smb/ntlm/client/session_spec.rb +114 -0
- data/spec/lib/ruby_smb/ntlm/client_spec.rb +36 -0
- data/spec/lib/ruby_smb/server/server_client_spec.rb +15 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk/virtual_pathname_spec.rb +581 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk/virtual_stat_spec.rb +207 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk_spec.rb +122 -0
- data.tar.gz.sig +2 -2
- metadata +63 -2
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require 'ruby_smb/server/share/provider/disk'
|
|
2
|
+
require 'ruby_smb/server/share/provider/virtual_disk/virtual_file'
|
|
3
|
+
require 'ruby_smb/server/share/provider/virtual_disk/virtual_pathname'
|
|
4
|
+
require 'ruby_smb/server/share/provider/virtual_disk/virtual_stat'
|
|
5
|
+
|
|
6
|
+
module RubySMB
|
|
7
|
+
class Server
|
|
8
|
+
module Share
|
|
9
|
+
module Provider
|
|
10
|
+
# This is a share provider that exposes a virtual file system whose entries do not exist on disk.
|
|
11
|
+
# @since 3.1.1
|
|
12
|
+
class VirtualDisk < Disk
|
|
13
|
+
HASH_METHODS = %i[ [] each each_key each_value keys length values ]
|
|
14
|
+
private_constant :HASH_METHODS
|
|
15
|
+
|
|
16
|
+
# @param [String] name The name of this share.
|
|
17
|
+
def initialize(name)
|
|
18
|
+
@vfs = {}
|
|
19
|
+
super(name, add(VirtualPathname.new(self, File::SEPARATOR)))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Add a dynamic file to the virtual file system. A dynamic file is one whose contents are generated by the
|
|
23
|
+
# specified block. The contents are generated when the share is opened.
|
|
24
|
+
#
|
|
25
|
+
# @param [String] path The path of the file to add, relative to the share root.
|
|
26
|
+
# @param [File::Stat] stat An explicit stat object describing the file.
|
|
27
|
+
# @yield The content generation routine.
|
|
28
|
+
# @yieldreturn [String] The generated file content.
|
|
29
|
+
def add_dynamic_file(path, stat: nil, &block)
|
|
30
|
+
raise ArgumentError.new('a block must be specified for dynamic files') unless block_given?
|
|
31
|
+
path = VirtualPathname.cleanpath(path)
|
|
32
|
+
path = File::SEPARATOR + path unless path.start_with?(File::SEPARATOR)
|
|
33
|
+
raise ArgumentError.new('must be a file') if stat && !stat.file?
|
|
34
|
+
|
|
35
|
+
vf = VirtualDynamicFile.new(self, path, stat: stat, &block)
|
|
36
|
+
add(vf)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Add a mapped file to the virtual file system. A mapped file is one who is backed by an entry on
|
|
40
|
+
# disk. The path need not be present, but if it does exist, it must be a file.
|
|
41
|
+
#
|
|
42
|
+
# @param [String] path The path of the file to add, relative to the share root.
|
|
43
|
+
# @param [String, Pathname] mapped_path The path on the local file system to map into the virtual file system.
|
|
44
|
+
def add_mapped_file(path, mapped_path)
|
|
45
|
+
path = VirtualPathname.cleanpath(path)
|
|
46
|
+
path = File::SEPARATOR + path unless path.start_with?(File::SEPARATOR)
|
|
47
|
+
|
|
48
|
+
vf = VirtualMappedFile.new(self, path, mapped_path)
|
|
49
|
+
add(vf)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Add a static file to the virtual file system. A static file is one whose contents are known at creation time
|
|
53
|
+
# and do not change. If *content* is a file-like object that responds to #read, the data will be read using
|
|
54
|
+
# that method. Likewise, if *content* has a #stat attribute and *stat* was not specified, then the value of
|
|
55
|
+
# content's #stat attribute will be used.
|
|
56
|
+
#
|
|
57
|
+
# @param [String] path The path of the file to add, relative to the share root.
|
|
58
|
+
# @param [String, #read, #stat] content The static content to add.
|
|
59
|
+
# @param [File::Stat] stat An explicit stat object describing the file.
|
|
60
|
+
def add_static_file(path, content, stat: nil)
|
|
61
|
+
path = VirtualPathname.cleanpath(path)
|
|
62
|
+
path = File::SEPARATOR + path unless path.start_with?(File::SEPARATOR)
|
|
63
|
+
raise ArgumentError.new('must be a file') if stat && !stat.file?
|
|
64
|
+
|
|
65
|
+
stat = content.stat if content.respond_to?(:stat) && stat.nil?
|
|
66
|
+
content = content.read if content.respond_to?(:read)
|
|
67
|
+
vf = VirtualStaticFile.new(self, path, content, stat: stat)
|
|
68
|
+
add(vf)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def add(virtual_pathname)
|
|
72
|
+
raise ArgumentError.new('paths must be absolute') unless virtual_pathname.absolute?
|
|
73
|
+
|
|
74
|
+
path = virtual_pathname.to_s
|
|
75
|
+
raise ArgumentError.new('paths must be normalized') unless VirtualPathname.cleanpath(path) == path
|
|
76
|
+
|
|
77
|
+
path_parts = path.split(VirtualPathname::SEPARATOR)
|
|
78
|
+
2.upto(path_parts.length - 1) do |idx|
|
|
79
|
+
ancestor = path_parts[0...idx].join(path[VirtualPathname::SEPARATOR])
|
|
80
|
+
next if @vfs[ancestor]&.directory?
|
|
81
|
+
|
|
82
|
+
@vfs[ancestor] = VirtualPathname.new(self, ancestor, stat: VirtualStat.new(directory?: true))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@vfs[path] = virtual_pathname
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def new_processor(server_client, session)
|
|
89
|
+
scoped_virtual_disk = self.class.new(@name)
|
|
90
|
+
@vfs.each_value do |path|
|
|
91
|
+
path = path.dup
|
|
92
|
+
path.virtual_disk = scoped_virtual_disk if path.is_a?(VirtualPathname)
|
|
93
|
+
path = path.generate(server_client, session) if path.is_a?(VirtualDynamicFile)
|
|
94
|
+
scoped_virtual_disk.add(path)
|
|
95
|
+
end
|
|
96
|
+
self.class::Processor.new(scoped_virtual_disk, server_client, session)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def method_missing(symbol, *args)
|
|
102
|
+
if HASH_METHODS.include?(symbol)
|
|
103
|
+
return @vfs.send(symbol, *args)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
raise NoMethodError, "undefined method `#{symbol}' for #{self.class}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def respond_to_missing?(symbol, include_private = false)
|
|
110
|
+
HASH_METHODS.include?(symbol)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
data/lib/ruby_smb/server.rb
CHANGED
|
@@ -6,6 +6,7 @@ module RubySMB
|
|
|
6
6
|
# Currently, the server only supports negotiating and authenticating requests. No other server functionality is
|
|
7
7
|
# available at this time. The negotiating and authentication is supported for SMB versions 1 through 3.1.1.
|
|
8
8
|
class Server
|
|
9
|
+
require 'ruby_smb/server/cli'
|
|
9
10
|
require 'ruby_smb/server/server_client'
|
|
10
11
|
require 'ruby_smb/server/session'
|
|
11
12
|
require 'ruby_smb/server/share'
|
|
@@ -14,8 +15,10 @@ module RubySMB
|
|
|
14
15
|
Connection = Struct.new(:client, :thread)
|
|
15
16
|
|
|
16
17
|
# @param server_sock the socket on which the server should listen
|
|
17
|
-
# @param [Gss::Provider] the authentication provider
|
|
18
|
-
|
|
18
|
+
# @param [Gss::Provider] gss_provider the authentication provider
|
|
19
|
+
# @param [::Logger] logger the logger to use for diagnostic messages
|
|
20
|
+
# @param thread_factory a block to create threads for serving clients
|
|
21
|
+
def initialize(server_sock: nil, gss_provider: nil, logger: nil, thread_factory: nil)
|
|
19
22
|
server_sock = ::TCPServer.new(445) if server_sock.nil?
|
|
20
23
|
|
|
21
24
|
@guid = Random.new.bytes(16)
|
|
@@ -36,6 +39,14 @@ module RubySMB
|
|
|
36
39
|
@logger = logger
|
|
37
40
|
end
|
|
38
41
|
|
|
42
|
+
if thread_factory.nil?
|
|
43
|
+
# the default thread factory uses Ruby's standard Thread#new
|
|
44
|
+
thread_factory = Proc.new do |_server_client, &block|
|
|
45
|
+
Thread.new(&block)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
@thread_factory = thread_factory
|
|
49
|
+
|
|
39
50
|
# share name => provider instance
|
|
40
51
|
@shares = {
|
|
41
52
|
'IPC$' => Share::Provider::IpcPipe.new
|
|
@@ -53,7 +64,7 @@ module RubySMB
|
|
|
53
64
|
loop do
|
|
54
65
|
sock = @socket.accept
|
|
55
66
|
server_client = ServerClient.new(self, RubySMB::Dispatcher::Socket.new(sock, read_timeout: nil))
|
|
56
|
-
@connections << Connection.new(server_client,
|
|
67
|
+
@connections << Connection.new(server_client, @thread_factory.call(server_client) { server_client.run })
|
|
57
68
|
|
|
58
69
|
break unless block.nil? || block.call(server_client)
|
|
59
70
|
end
|
data/lib/ruby_smb/smb2/tree.rb
CHANGED
data/lib/ruby_smb/version.rb
CHANGED
|
@@ -1279,6 +1279,9 @@ RSpec.describe RubySMB::Client do
|
|
|
1279
1279
|
end
|
|
1280
1280
|
|
|
1281
1281
|
it 'calls the backing methods' do
|
|
1282
|
+
request_packet = double('Request packet')
|
|
1283
|
+
allow(client).to receive(:negotiate_request).and_return(request_packet)
|
|
1284
|
+
allow(request_packet).to receive(:packet_smb_version)
|
|
1282
1285
|
expect(client).to receive(:negotiate_request)
|
|
1283
1286
|
expect(client).to receive(:send_recv)
|
|
1284
1287
|
expect(client).to receive(:negotiate_response)
|
|
@@ -1319,14 +1322,20 @@ RSpec.describe RubySMB::Client do
|
|
|
1319
1322
|
|
|
1320
1323
|
it 'increments the message ID' do
|
|
1321
1324
|
expect(client).to receive(:smb2_message_id=).with(1)
|
|
1325
|
+
expect(client).to receive(:negotiate_request).twice.and_call_original
|
|
1326
|
+
expect(client).to receive(:parse_negotiate_response).twice do
|
|
1327
|
+
client.smb1 = false
|
|
1328
|
+
end
|
|
1322
1329
|
client.negotiate
|
|
1323
1330
|
end
|
|
1324
1331
|
|
|
1325
1332
|
it 're-negotiates' do
|
|
1326
|
-
expect(client).to receive(:negotiate_request).twice
|
|
1333
|
+
expect(client).to receive(:negotiate_request).twice.and_call_original
|
|
1327
1334
|
expect(client).to receive(:send_recv).twice
|
|
1328
1335
|
expect(client).to receive(:negotiate_response).twice
|
|
1329
|
-
expect(client).to receive(:parse_negotiate_response).twice
|
|
1336
|
+
expect(client).to receive(:parse_negotiate_response).twice do
|
|
1337
|
+
client.smb1 = false
|
|
1338
|
+
end
|
|
1330
1339
|
client.negotiate
|
|
1331
1340
|
end
|
|
1332
1341
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileAccessInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_ACCESS_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :access_flags }
|
|
12
|
+
|
|
13
|
+
it 'is little endian' do
|
|
14
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'tracks the access flags in a Uint32 field' do
|
|
18
|
+
expect(struct.access_flags).to be_a BinData::Uint32le
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileAlignmentInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_ALIGNMENT_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :alignment_requirement }
|
|
12
|
+
|
|
13
|
+
it 'is little endian' do
|
|
14
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'tracks the alignment requirement in a Uint32 field' do
|
|
18
|
+
expect(struct.alignment_requirement).to be_a BinData::Uint32le
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileAllInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_ALL_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :basic_information }
|
|
12
|
+
it { should respond_to :standard_information }
|
|
13
|
+
it { should respond_to :internal_information }
|
|
14
|
+
it { should respond_to :ea_information }
|
|
15
|
+
it { should respond_to :access_information }
|
|
16
|
+
it { should respond_to :position_information }
|
|
17
|
+
it { should respond_to :mode_information }
|
|
18
|
+
it { should respond_to :alignment_information }
|
|
19
|
+
it { should respond_to :name_information }
|
|
20
|
+
|
|
21
|
+
it 'is little endian' do
|
|
22
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'tracks the basic information in a FileBasicInformation field' do
|
|
26
|
+
expect(struct.basic_information).to be_a RubySMB::Fscc::FileInformation::FileBasicInformation
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'tracks the standard information in a FileStandardInformation field' do
|
|
30
|
+
expect(struct.standard_information).to be_a RubySMB::Fscc::FileInformation::FileStandardInformation
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'tracks the internal information in a FileInternalInformation field' do
|
|
34
|
+
expect(struct.internal_information).to be_a RubySMB::Fscc::FileInformation::FileInternalInformation
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'tracks the ea information in a FileEaInformation field' do
|
|
38
|
+
expect(struct.ea_information).to be_a RubySMB::Fscc::FileInformation::FileEaInformation
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'tracks the access information in a FileAccessInformation field' do
|
|
42
|
+
expect(struct.access_information).to be_a RubySMB::Fscc::FileInformation::FileAccessInformation
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'tracks the position information in a FilePositionInformation field' do
|
|
46
|
+
expect(struct.position_information).to be_a RubySMB::Fscc::FileInformation::FilePositionInformation
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'tracks the mode information in a FileModeInformation field' do
|
|
50
|
+
expect(struct.mode_information).to be_a RubySMB::Fscc::FileInformation::FileModeInformation
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'tracks the alignment information in a FileAlignmentInformation field' do
|
|
54
|
+
expect(struct.alignment_information).to be_a RubySMB::Fscc::FileInformation::FileAlignmentInformation
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'tracks the name information in a FileNameInformation field' do
|
|
58
|
+
expect(struct.name_information).to be_a RubySMB::Fscc::FileInformation::FileNameInformation
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileBasicInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_BASIC_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :create_time }
|
|
12
|
+
it { should respond_to :last_access }
|
|
13
|
+
it { should respond_to :last_write }
|
|
14
|
+
it { should respond_to :last_change }
|
|
15
|
+
it { should respond_to :file_attributes }
|
|
16
|
+
|
|
17
|
+
it 'is little endian' do
|
|
18
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'tracks the create time in a FileTime field' do
|
|
22
|
+
expect(struct.create_time).to be_a RubySMB::Field::FileTime
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'tracks the last access time in a FileTime field' do
|
|
26
|
+
expect(struct.last_access).to be_a RubySMB::Field::FileTime
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'tracks the last write time in a FileTime field' do
|
|
30
|
+
expect(struct.last_write).to be_a RubySMB::Field::FileTime
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'tracks the last modified time in a FileTime field' do
|
|
34
|
+
expect(struct.last_change).to be_a RubySMB::Field::FileTime
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'tracks the file attributes in a FileAttributes field' do
|
|
38
|
+
expect(struct.file_attributes).to be_a RubySMB::Fscc::FileAttributes
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -27,6 +27,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileBothDirectoryInformation do
|
|
|
27
27
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
it 'tracks the next offset in a Uint32 field' do
|
|
31
|
+
expect(struct.next_offset).to be_a BinData::Uint32le
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'tracks the file index in a Uint32 field' do
|
|
35
|
+
expect(struct.file_index).to be_a BinData::Uint32le
|
|
36
|
+
end
|
|
37
|
+
|
|
30
38
|
it 'tracks the creation time in a Filetime field' do
|
|
31
39
|
expect(struct.create_time).to be_a RubySMB::Field::FileTime
|
|
32
40
|
end
|
|
@@ -43,6 +51,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileBothDirectoryInformation do
|
|
|
43
51
|
expect(struct.last_change).to be_a RubySMB::Field::FileTime
|
|
44
52
|
end
|
|
45
53
|
|
|
54
|
+
it 'tracks the file size in a Int64 field' do
|
|
55
|
+
expect(struct.end_of_file).to be_a BinData::Int64le
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'tracks the allocation size in a Int64 field' do
|
|
59
|
+
expect(struct.allocation_size).to be_a BinData::Int64le
|
|
60
|
+
end
|
|
61
|
+
|
|
46
62
|
it 'contains the file attributes of the file' do
|
|
47
63
|
expect(struct.file_attributes).to be_a RubySMB::Fscc::FileAttributes
|
|
48
64
|
end
|
|
@@ -52,20 +68,53 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileBothDirectoryInformation do
|
|
|
52
68
|
expect(struct.file_name_length).to eq struct.file_name.do_num_bytes
|
|
53
69
|
end
|
|
54
70
|
|
|
55
|
-
it '
|
|
56
|
-
|
|
57
|
-
struct.file_name = name
|
|
58
|
-
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
71
|
+
it 'tracks the extended attributes size in a Uint32 field' do
|
|
72
|
+
expect(struct.ea_size).to be_a BinData::Uint32le
|
|
59
73
|
end
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
it 'tracks the short name length in a Uint8 field' do
|
|
76
|
+
expect(struct.short_name_length).to be_a BinData::Uint8
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'tracks the short name in a String16 field' do
|
|
80
|
+
expect(struct.short_name).to be_a RubySMB::Field::String16
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'tracks the file name in a String16 field' do
|
|
84
|
+
expect(struct.file_name).to be_a RubySMB::Field::String16
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe '#short_name' do
|
|
88
|
+
it 'automatically encodes the short name in UTF-16LE' do
|
|
89
|
+
name = 'Hello_world.'
|
|
90
|
+
struct.short_name = name
|
|
91
|
+
expect(struct.short_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'is always exactly 24 bytes in length' do
|
|
95
|
+
struct.short_name = ''
|
|
96
|
+
expect(struct.short_name.num_bytes).to eq 24
|
|
97
|
+
struct.short_name = 'Hello_world.'
|
|
98
|
+
expect(struct.short_name.num_bytes).to eq 24
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe '#file_name' do
|
|
103
|
+
it 'automatically encodes the file name in UTF-16LE' do
|
|
63
104
|
name = 'Hello_world.txt'
|
|
64
105
|
struct.file_name = name
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
106
|
+
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe 'reading in from a blob' do
|
|
110
|
+
it 'uses the file_name_length to know when to stop reading' do
|
|
111
|
+
name = 'Hello_world.txt'
|
|
112
|
+
struct.file_name = name
|
|
113
|
+
blob = struct.to_binary_s
|
|
114
|
+
blob << 'AAAA'
|
|
115
|
+
new_from_blob = described_class.read(blob)
|
|
116
|
+
expect(new_from_blob.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
117
|
+
end
|
|
69
118
|
end
|
|
70
119
|
end
|
|
71
120
|
end
|
|
@@ -24,6 +24,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileDirectoryInformation do
|
|
|
24
24
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
it 'tracks the next offset in a Uint32 field' do
|
|
28
|
+
expect(struct.next_offset).to be_a BinData::Uint32le
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'tracks the file index in a Uint32 field' do
|
|
32
|
+
expect(struct.file_index).to be_a BinData::Uint32le
|
|
33
|
+
end
|
|
34
|
+
|
|
27
35
|
it 'tracks the creation time in a Filetime field' do
|
|
28
36
|
expect(struct.create_time).to be_a RubySMB::Field::FileTime
|
|
29
37
|
end
|
|
@@ -40,6 +48,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileDirectoryInformation do
|
|
|
40
48
|
expect(struct.last_change).to be_a RubySMB::Field::FileTime
|
|
41
49
|
end
|
|
42
50
|
|
|
51
|
+
it 'tracks the file size in a Int64 field' do
|
|
52
|
+
expect(struct.end_of_file).to be_a BinData::Int64le
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'tracks the allocation size in a Int64 field' do
|
|
56
|
+
expect(struct.allocation_size).to be_a BinData::Int64le
|
|
57
|
+
end
|
|
58
|
+
|
|
43
59
|
it 'contains the file attributes of the file' do
|
|
44
60
|
expect(struct.file_attributes).to be_a RubySMB::Fscc::FileAttributes
|
|
45
61
|
end
|
|
@@ -49,20 +65,22 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileDirectoryInformation do
|
|
|
49
65
|
expect(struct.file_name_length).to eq struct.file_name.do_num_bytes
|
|
50
66
|
end
|
|
51
67
|
|
|
52
|
-
|
|
53
|
-
name
|
|
54
|
-
struct.file_name = name
|
|
55
|
-
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
describe 'reading in from a blob' do
|
|
59
|
-
it 'uses the file_name_length to know when to stop reading' do
|
|
68
|
+
describe '#file_name' do
|
|
69
|
+
it 'automatically encodes the file name in UTF-16LE' do
|
|
60
70
|
name = 'Hello_world.txt'
|
|
61
71
|
struct.file_name = name
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe 'reading in from a blob' do
|
|
76
|
+
it 'uses the file_name_length to know when to stop reading' do
|
|
77
|
+
name = 'Hello_world.txt'
|
|
78
|
+
struct.file_name = name
|
|
79
|
+
blob = struct.to_binary_s
|
|
80
|
+
blob << 'AAAA'
|
|
81
|
+
new_from_blob = described_class.read(blob)
|
|
82
|
+
expect(new_from_blob.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
83
|
+
end
|
|
66
84
|
end
|
|
67
85
|
end
|
|
68
86
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileEaInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_EA_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :ea_size }
|
|
12
|
+
|
|
13
|
+
it 'is little endian' do
|
|
14
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'tracks the extended attributes size in a Uint32 field' do
|
|
18
|
+
expect(struct.ea_size).to be_a BinData::Uint32le
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -25,6 +25,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileFullDirectoryInformation do
|
|
|
25
25
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
it 'tracks the next offset in a Uint32 field' do
|
|
29
|
+
expect(struct.next_offset).to be_a BinData::Uint32le
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'tracks the file index in a Uint32 field' do
|
|
33
|
+
expect(struct.file_index).to be_a BinData::Uint32le
|
|
34
|
+
end
|
|
35
|
+
|
|
28
36
|
it 'tracks the creation time in a Filetime field' do
|
|
29
37
|
expect(struct.create_time).to be_a RubySMB::Field::FileTime
|
|
30
38
|
end
|
|
@@ -41,6 +49,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileFullDirectoryInformation do
|
|
|
41
49
|
expect(struct.last_change).to be_a RubySMB::Field::FileTime
|
|
42
50
|
end
|
|
43
51
|
|
|
52
|
+
it 'tracks the file size in a Int64 field' do
|
|
53
|
+
expect(struct.end_of_file).to be_a BinData::Int64le
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'tracks the allocation size in a Int64 field' do
|
|
57
|
+
expect(struct.allocation_size).to be_a BinData::Int64le
|
|
58
|
+
end
|
|
59
|
+
|
|
44
60
|
it 'contains the file attributes of the file' do
|
|
45
61
|
expect(struct.file_attributes).to be_a RubySMB::Fscc::FileAttributes
|
|
46
62
|
end
|
|
@@ -50,20 +66,22 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileFullDirectoryInformation do
|
|
|
50
66
|
expect(struct.file_name_length).to eq struct.file_name.do_num_bytes
|
|
51
67
|
end
|
|
52
68
|
|
|
53
|
-
|
|
54
|
-
name
|
|
55
|
-
struct.file_name = name
|
|
56
|
-
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
describe 'reading in from a blob' do
|
|
60
|
-
it 'uses the file_name_length to know when to stop reading' do
|
|
69
|
+
describe '#file_name' do
|
|
70
|
+
it 'automatically encodes the file name in UTF-16LE' do
|
|
61
71
|
name = 'Hello_world.txt'
|
|
62
72
|
struct.file_name = name
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe 'reading in from a blob' do
|
|
77
|
+
it 'uses the file_name_length to know when to stop reading' do
|
|
78
|
+
name = 'Hello_world.txt'
|
|
79
|
+
struct.file_name = name
|
|
80
|
+
blob = struct.to_binary_s
|
|
81
|
+
blob << 'AAAA'
|
|
82
|
+
new_from_blob = described_class.read(blob)
|
|
83
|
+
expect(new_from_blob.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
84
|
+
end
|
|
67
85
|
end
|
|
68
86
|
end
|
|
69
87
|
end
|