45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
# File 'lib/ruby_smb/server/share/provider/disk/processor/create.rb', line 45
def do_create_smb2(request)
unless request.create_disposition == RubySMB::Dispositions::FILE_OPEN
logger.warn("Can not handle CREATE request for disposition: #{request.create_disposition}")
raise NotImplementedError
end
request.name.read_now!
unless request.contexts_offset == 0
request.contexts.read_now!
request.contexts.each do |context|
context.name.read_now!
context.data.read_now!
end
end
path = request.name.snapshot
local_path = get_local_path(path)
unless local_path && (local_path.file? || local_path.directory?)
logger.warn("Requested path does not exist: #{local_path}")
response = RubySMB::SMB2::Packet::ErrorPacket.new
response..nt_status = WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND
return response
end
durable = false
response = RubySMB::SMB2::Packet::CreateResponse.new
response.create_action = RubySMB::CreateActions::FILE_OPENED
set_common_info(response, local_path)
response.file_id.persistent = Zlib::crc32(path)
response.file_id.volatile = rand(0xffffffff)
request.contexts.each do |req_ctx|
case req_ctx.name
when SMB2::CreateContext::CREATE_DURABLE_HANDLE
next if request.contexts.any? { |ctx| ctx.name == SMB2::CreateContext::CREATE_DURABLE_HANDLE_RECONNECT }
if request.contexts.any? { |ctx| [ SMB2::CreateContext::CREATE_DURABLE_HANDLE_V2, SMB2::CreateContext::CREATE_DURABLE_HANDLE_RECONNECT_v2 ].include?(ctx.name) }
response = RubySMB::SMB2::Packet::ErrorPacket.new
response..nt_status = WindowsError::NTStatus::STATUS_INVALID_PARAMETER
return response
end
durable = true
res_ctx = SMB2::CreateContext::CreateDurableHandleResponse.new
when SMB2::CreateContext::CREATE_DURABLE_HANDLE_V2
if request.contexts.any? { |ctx| [ SMB2::CreateContext::CREATE_DURABLE_HANDLE, SMB2::CreateContext::CREATE_DURABLE_HANDLE_RECONNECT, SMB2::CreateContext::CREATE_DURABLE_HANDLE_RECONNECT_v2 ].include?(ctx.name) }
response = RubySMB::SMB2::Packet::ErrorPacket.new
response..nt_status = WindowsError::NTStatus::STATUS_INVALID_PARAMETER
return response
end
durable = true
res_ctx = SMB2::CreateContext::CreateDurableHandleV2Response.new(
timeout: 1000,
flags: req_ctx.data.flags
)
when SMB2::CreateContext::CREATE_QUERY_MAXIMAL_ACCESS
res_ctx = SMB2::CreateContext::CreateQueryMaximalAccessResponse.new(
maximal_access: maximal_access(path)
)
when SMB2::CreateContext::CREATE_QUERY_ON_DISK_ID
res_ctx = SMB2::CreateContext::CreateQueryOnDiskIdResponse.new(
disk_file_id: local_path.stat.ino,
volume_id: local_path.stat.dev
)
else
logger.warn("Can not handle CREATE context: #{req_ctx.name}")
next
end
response.contexts << SMB2::CreateContext::CreateContextResponse.new(name: res_ctx.class::NAME, data: res_ctx)
end
if response.contexts.length > 0
response.contexts[0...-1].each do |ctx|
ctx.next_offset = ctx.num_bytes
end
response.contexts[-1].next_offset = 0
response.contexts_offset = response.buffer.abs_offset
response.contexts_length = response.buffer.num_bytes
else
response.contexts_offset = 0
response.contexts_length = 0
end
@handles[response.file_id.to_binary_s] = Handle.new(path, local_path, durable, local_path.file? ? local_path.open : nil)
response
end
|