使用Python修改Oracle数据块(上)

近日,旧事告一段落,新事情还没有开始,有时间闲看一些资料,忘了因为什么原因,找到python 的bitarray 文档阅读,突然冒出用这个来修改一下Oracle 数据块的想法…… 这两天测试读取、解析是没问题了,修改、写入还没来得及开始——所以这是“上”篇。 这里只涉及数据文件的“header block”,一般来说说,“header block”有两个:block 0,block 1,今天这里只操作block 1,对其中的"kcvfh"结构进行读取操作。
先给出"bbed”显示的block 1结构...

struct kcvfh, 860 bytes @0
struct kcvfhbfh, 20 bytes @0
ub1 type_kcbh @0 0x0b
ub1 frmt_kcbh @1 0xa2
ub1 spare1_kcbh @2 0x00
ub1 spare2_kcbh @3 0x00
ub4 rdba_kcbh @4 0x01c00001
ub4 bas_kcbh @8 0x00000000
ub2 wrp_kcbh @12 0x0000
ub1 seq_kcbh @14 0x01
ub1 flg_kcbh @15 0x04 (KCBHFCKV)
ub2 chkval_kcbh @16 0x5ba4
ub2 spare3_kcbh @18 0x0000
struct kcvfhhdr, 76 bytes @20
ub4 kccfhswv @20 0x00000000
ub4 kccfhcvn @24 0x0b200400
ub4 kccfhdbi @28 0x1be596bb
text kccfhdbn[0] @32 P
text kccfhdbn[1] @33 R
text kccfhdbn[2] @34 O
text kccfhdbn[3] @35 D
text kccfhdbn[4] @36
text kccfhdbn[5] @37
text kccfhdbn[6] @38
text kccfhdbn[7] @39
ub4 kccfhcsq @40 0x00000b7e
ub4 kccfhfsz @44 0x00008000
s_blkz kccfhbsz @48 0x00
ub2 kccfhfno @52 0x0007
ub2 kccfhtyp @54 0x0003
ub4 kccfhacid @56 0x00000000
ub4 kccfhcks @60 0x00000000
text kccfhtag[0] @64
text kccfhtag[1] @65
text kccfhtag[2] @66
text kccfhtag[3] @67
text kccfhtag[4] @68
text kccfhtag[5] @69
text kccfhtag[6] @70
text kccfhtag[7] @71
text kccfhtag[8] @72
text kccfhtag[9] @73
text kccfhtag[10] @74
text kccfhtag[11] @75
text kccfhtag[12] @76
text kccfhtag[13] @77
text kccfhtag[14] @78
text kccfhtag[15] @79
text kccfhtag[16] @80
text kccfhtag[17] @81
text kccfhtag[18] @82
text kccfhtag[19] @83
text kccfhtag[20] @84
text kccfhtag[21] @85
text kccfhtag[22] @86
text kccfhtag[23] @87
text kccfhtag[24] @88
text kccfhtag[25] @89
text kccfhtag[26] @90
text kccfhtag[27] @91
text kccfhtag[28] @92
text kccfhtag[29] @93
text kccfhtag[30] @94
text kccfhtag[31] @95
ub4 kcvfhrdb @96 0x00000000
struct kcvfhcrs, 8 bytes @100
ub4 kscnbas @100 0x001548cc
ub2 kscnwrp @104 0x0000
ub4 kcvfhcrt @108 0x3efad368
ub4 kcvfhrlc @112 0x3ef43943
struct kcvfhrls, 8 bytes @116
ub4 kscnbas @116 0x000e2006
ub2 kscnwrp @120 0x0000
ub4 kcvfhbti @124 0x00000000
struct kcvfhbsc, 8 bytes @128
ub4 kscnbas @128 0x00000000
ub2 kscnwrp @132 0x0000
ub2 kcvfhbth @136 0x0000
ub2 kcvfhsta @138 0x0000 (NONE)
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0x00154c22
ub2 kscnwrp @488 0x0000
ub4 kcvcptim @492 0x3efad562
ub2 kcvcpthr @496 0x0002
union u, 12 bytes @500
struct kcvcprba, 12 bytes @500
ub4 kcrbaseq @500 0x00000008
ub4 kcrbabno @504 0x000005a8
ub2 kcrbabof @508 0x0010
ub1 kcvcpetb[0] @512 0x06
ub1 kcvcpetb[1] @513 0x00
ub1 kcvcpetb[2] @514 0x00
ub1 kcvcpetb[3] @515 0x00
ub1 kcvcpetb[4] @516 0x00
ub1 kcvcpetb[5] @517 0x00
ub1 kcvcpetb[6] @518 0x00
ub1 kcvcpetb[7] @519 0x00
ub4 kcvfhcpc @140 0x00000005
ub4 kcvfhrts @144 0x00000000
ub4 kcvfhccc @148 0x00000004
struct kcvfhbcp, 36 bytes @152
struct kcvcpscn, 8 bytes @152
ub4 kscnbas @152 0x00000000
ub2 kscnwrp @156 0x0000
ub4 kcvcptim @160 0x00000000
ub2 kcvcpthr @164 0x0000
union u, 12 bytes @168
struct kcvcprba, 12 bytes @168
ub4 kcrbaseq @168 0x00000000
ub4 kcrbabno @172 0x00000000
ub2 kcrbabof @176 0x0000
ub1 kcvcpetb[0] @180 0x00
ub1 kcvcpetb[1] @181 0x00
ub1 kcvcpetb[2] @182 0x00
ub1 kcvcpetb[3] @183 0x00
ub1 kcvcpetb[4] @184 0x00
ub1 kcvcpetb[5] @185 0x00
ub1 kcvcpetb[6] @186 0x00
ub1 kcvcpetb[7] @187 0x00
ub4 kcvfhbhz @312 0x00000000
struct kcvfhxcd, 16 bytes @316
ub4 space_kcvmxcd[0] @316 0x00000000
ub4 space_kcvmxcd[1] @320 0x00000000
ub4 space_kcvmxcd[2] @324 0x00000000
ub4 space_kcvmxcd[3] @328 0x00000000
sword kcvfhtsn @332 7
ub2 kcvfhtln @336 0x0008
text kcvfhtnm[0] @338 P
text kcvfhtnm[1] @339 R
text kcvfhtnm[2] @340 O
text kcvfhtnm[3] @341 D
text kcvfhtnm[4] @342 _
text kcvfhtnm[5] @343 T
text kcvfhtnm[6] @344 B
text kcvfhtnm[7] @345 S
text kcvfhtnm[8] @346
text kcvfhtnm[9] @347
text kcvfhtnm[10] @348
text kcvfhtnm[11] @349
text kcvfhtnm[12] @350
text kcvfhtnm[13] @351
text kcvfhtnm[14] @352
text kcvfhtnm[15] @353
text kcvfhtnm[16] @354
text kcvfhtnm[17] @355
text kcvfhtnm[18] @356
text kcvfhtnm[19] @357
text kcvfhtnm[20] @358
text kcvfhtnm[21] @359
text kcvfhtnm[22] @360
text kcvfhtnm[23] @361
text kcvfhtnm[24] @362
text kcvfhtnm[25] @363
text kcvfhtnm[26] @364
text kcvfhtnm[27] @365
text kcvfhtnm[28] @366
text kcvfhtnm[29] @367
ub4 kcvfhrfn @368 0x00000007
struct kcvfhrfs, 8 bytes @372
ub4 kscnbas @372 0x00000000
ub2 kscnwrp @376 0x0000
ub4 kcvfhrft @380 0x00000000
struct kcvfhafs, 8 bytes @384
ub4 kscnbas @384 0x00000000
ub2 kscnwrp @388 0x0000
ub4 kcvfhbbc @392 0x00000000
ub4 kcvfhncb @396 0x00000000
ub4 kcvfhmcb @400 0x00000000
ub4 kcvfhlcb @404 0x00000000
ub4 kcvfhbcs @408 0x00000000
ub2 kcvfhofb @412 0x0000
ub2 kcvfhnfb @414 0x0000
ub4 kcvfhprc @416 0x3121c97a
struct kcvfhprs, 8 bytes @420
ub4 kscnbas @420 0x00000001
ub2 kscnwrp @424 0x0000
struct kcvfhprfs, 8 bytes @428
ub4 kscnbas @428 0x00000000
ub2 kscnwrp @432 0x0000
ub4 kcvfhtrt @444 0x00000000

需要注意的是, Oracle ub4,ub2,ub1之类的数据类型的意义。最关键的是第二列 @ 符号后的数字,这个是该成员在结构中(struct)的偏移量(offset),单位是byte。
DBA做恢复关注的是下面几个地方:

  • 1. rdba_kcbh(offset 4) 文件头block的rdba地址
  • 2. kccfhfsz (offset 44) 文件大小
  • 3. kccfhfno (offset 52) datafile文件号
  • 4. kcvfhrdb (offset 96) root dba
  • 5. kscnbas (offset 100) v$datafile.creation_change#
  • 6. kcvfhcrt (offset 108) v$datafile.creation_time
  • 7. kcvfhsta (offset 138) 文件状态
  • 8. kcvfhtsn (offset 332) 表空间号v$datafile.ts#
  • 9.kcvfhtln (offset 336) 表空间名称字符长度
  • 10. kcvfhtnm (offset 338) 表空间名称v$tablespace.name
  • 11. kcvfhrfn (offset 368) 相对文件号v$datafile.rfile#
  • 12. kscnbas (offset 484) checkpoint scn
  • 13.kcvcptim (offset 492) last checkpoint time
  • 14.kcvfhcpc (offset 144) Datafile checkpoint count

下面给出python代码示例,要解释的都放在python注释中:

from bitarray import bitarray, util
# define kcvfh
# dict:
# key: 'variable name'
# value: tuple(str'description', offset, n_bytes)
kcvfh_struct = {
'type_kcbh': (
'''block type:
1d--------KTFB Bitmapped File Space Header
06--------trans data
1e--------KTFB Bitmapped File Space Bitmap
10--------DATA SEGMENT HEADER – UNLIMITED
20--------FIRST LEVEL BITMAP BLOCK
21--------SECOND LEVEL BITMAP BLOCK
23--------PAGETABLE SEGMENT HEADER
''',0,1,),
'frmt_kcbh': ('format ',1,1),
'rdba_kcbh': ('rdba',4,4),
'chkval_kcbh': ('checksum value',16,2),
'kccfhdbi': ('dbid',28,4),
'kccfhdbnX': ('db name', 32,8),
'kccfhcsq': ('control sequence', 40,4),
'kccfhfsz': ('datafile size', 44,4),
'kccfhfno': ('file no',52,2),
'kccfhtyp': ('file type',54,2),
'kcvfhrdb': ('rdba',96,4),
'kscnbas': ('create scn',100,4),
'kscnwrp': ('create scn wrap',104,2),
'kcvfhcrt': ('file create time',108,4),
'kcvfhrlc': ('resetlogs count',112,4),
'kcvfhrls.kscnbas': ('resetlogs scn base', 116,4),
'kcvfhrls.kscnwrp': ('resetlogs scn wrap', 120,2),
'kcvfhbsc.kscnbas': ('backup taken scn base', 128,4),
'kcvfhbsc.kscnwrp': ('backup taken scn wrap', 132,2),
'kcvfhsta': ('数据文件状态,04应该为正常,00是关闭,01是begin backup', 138,2),
'kcvfhcpc': ('checkpoint count',140,4),
'kcvfhccc': ('ctl count',148,4),
'kcvfhtsn': ('表空间号',332,4),
'kcvfhtln': ('表空间名称字符长度',336,2),
'kcvfhtnm': ('表空间名称', 338, 30),
'kcvfhprc': ('prev resetlogs count',416,4),
'kcvfhprs.kscnbas': ('prev resetlogs scn base',420,4),
'kcvfhprs.kscnwrp': ('prev resetlogs scn wrap',424,2),
'kcvcpscn.kscnbas': ('checkpoint scn base', 484,4),
'kcvcpscn.kscnwrp': ('checkpoint scn wrap', 488,2),
'kcvcptim': ('checkpoint time', 492,4),
'kcvcpthr': ('checkpoint thread',496,2),
'kcvcprba.kcrbaseq': ('checkpoint rba seq',500,4),
'kcvcprba.kcrbabno': ('checkpoint rba bno',504,4),
'kcvcprba.kcrbabof': ('checkpoint rba bof',508,4),
}

# kcvfh 在 second block中,即 block 1(0是第一块)
# 根据 variable names,offset, count , blocks, blocksize 提取该出变量的 bitarray
def extract_bits(ba, vname, offset, count, block=1, blocksize=8192):
return ba[(block * blocksize + offset)*8 : (block * blocksize + offset + count)*8]

# 根据 variable names,offset, count , blocks, blocksize 提取该出变量的 int 值(ub4 是4bytes,不会溢出)
def extract_int(ba, vname, offset, count, block=1, blocksize=8192):
i = util.ba2int(ba[(block * blocksize + offset)*8 : (block * blocksize + offset + count)*8])
return i

# 根据 variable names,offset, count , blocks, blocksize 提取该出变量的 int 值,转换出Hex字符串
def extract_hex(ba, vname, offset, count, block=1, blocksize=8192):
i = util.ba2int(ba[(block * blocksize + offset)*8 : (block * blocksize + offset + count)*8])
return format(i, '0{}X'.format(count*2))

# 这是Oracle 11.2.0.4的数据文件
orcl_file = open('/Users/changzhenghe/tmp/prod_tbs.dbf','rb')

# endian 会直接影响结果
ba = bitarray(endian='little')

# 只读取了前两个block
ba.fromfile(orcl_file, 16384)
orcl_file.close()

# 把我们定义的(感兴趣的)kcvfh信息打印出来
for key in kcvfh_struct.keys():
print('{} [{}]'.format(key, kcvfh_struct[key][0]))
print('\t||{}||'.format(extract_hex(ba,key, kcvfh_struct[key][1], kcvfh_struct[key][2])))

Leave Comment