forked from feix/mysqld_user_myd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathread_mysqld_user_myd.lua
162 lines (149 loc) · 4.7 KB
/
read_mysqld_user_myd.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
-- https://dev.mysql.com/doc/internals/en/layout-record-storage-frame.html
local read_len = function(content, first, l)
local sum = 0
local last = first + l - 1
for i = first, last do
sum = sum * 256 + content[i]
end
return sum
end
local min = function(a, b)
return a <= b and a or b
end
local pad = function(data_len)
local t_len = data_len % 4
if t_len == 0 then
return data_len
else
return data_len - t_len + 4
end
end
local dispatch_record
local read_record = function(content, idx, header_len, data_pos, data_l, next_pos, unused_l)
-- block
-- header
-- data with pad
local rec_type = content[idx]
local data_len = read_len(content, idx+data_pos, data_l)
local unused_len = unused_l > 0 and content[idx+unused_l] or 0
local block_len = pad(header_len + data_len + unused_len)
local next_rec = next_pos > 0 and dispatch_record(content, read_len(content, idx+next_pos, 8)+1) or nil
return {
rec_type=rec_type,
block_len=block_len,
data_len=data_len,
next_rec=next_rec,
data_begin=idx + header_len
}
end
dispatch_record = function(content, idx)
local record = {}
local rec_type = content[idx]
if rec_type == 0 then
record = read_record(content, idx, 20, 1, 3, -1, 0)
elseif rec_type == 1 then
record = read_record(content, idx, 3, 1, 2, -1, 0)
elseif rec_type == 2 then
record = read_record(content, idx, 4, 1, 3, -1, 0)
elseif rec_type == 3 then
record = read_record(content, idx, 4, 1, 2, -1, 3)
elseif rec_type == 4 then
record = read_record(content, idx, 5, 1, 3, -1, 4)
elseif rec_type == 5 then
record = read_record(content, idx, 13, 3, 2, 5, 0)
elseif rec_type == 6 then
record = read_record(content, idx, 15, 4, 3, 7, 0)
elseif rec_type == 7 then
record = read_record(content, idx, 3, 1, 2, -1, 0)
elseif rec_type == 8 then
record = read_record(content, idx, 4, 1, 3, -1, 0)
elseif rec_type == 9 then
record = read_record(content, idx, 4, 1, 2, -1, 3)
elseif rec_type == 10 then
record = read_record(content, idx, 5, 1, 3, -1, 4)
elseif rec_type == 11 then
record = read_record(content, idx, 11, 1, 2, 3, 0)
elseif rec_type == 12 then
record = read_record(content, idx, 12, 1, 3, 4, 0)
elseif rec_type == 13 then
record = read_record(content, idx, 16, 5, 3, 9, 0)
end
return record
end
local read_str = function(content, first, l)
local str = {}
local last = first + l - 1
for i = first, last do
table.insert(str, string.char(content[i]))
end
return table.concat(str)
end
local parse_record = function(content, rec)
local first = rec.data_begin + 3
local host_l = content[first]
local host = read_str(content, first+1, host_l)
local user_l = content[first+host_l+1]
local user = read_str(content, first+host_l+1+1, user_l)
local native = false
local pass_l = 40
local pass = ''
local idx = first + host_l + 1 + 1 + user_l
while true do
local n_pass_l = string.len(pass)
local last = rec.data_begin + rec.data_len
if n_pass_l == 0 then
while idx < last do
if content[idx] == 21 then
native = true
elseif content[idx] == 42 then
idx = idx + 1
break
end
idx = idx + 1
end
end
local n_pass = read_str(content, idx, min(last-idx, pass_l-n_pass_l))
pass = pass .. n_pass
if rec.next_rec == nil then
break
else
rec = rec.next_rec
idx = rec.data_begin
end
end
return {
host=host,
user=user,
pass=pass,
native=native
}
end
local read_records = function(filename)
local content = {}
local content_len = 0
local file = io.open(filename, 'rb')
while file ~= nil do
local buffer = file:read(1024)
if buffer == nil then
break
end
for i = 1, #buffer do
content[content_len+i] = buffer:byte(i)
end
content_len = content_len + #buffer
end
if file ~= nil then
file:close()
end
local idx = 1
while idx <= content_len do
local rec = dispatch_record(content, idx)
if 0 < rec.rec_type and rec.rec_type <= 6 then
local record = parse_record(content, rec)
print(record.host, record.user, record.pass, string.len(record.pass), record.native)
end
idx = idx + rec.block_len
end
return record
end
read_records('/usr/local/var/mysql/mysql/user.MYD')