2 # From http://stackoverflow.com/questions/3085153/how-to-parse-the-manifest-mbdb-file-in-an-ios-4-0-itunes-backup
8 def getint(data
, offset
, intsize
):
9 """Retrieve an integer (big-endian) and new offset from the current offset"""
12 value
= (value
<<8) + ord(data
[offset
])
17 def getstring(data
, offset
):
18 """Retrieve a string and new offset from the current offset into the data"""
19 if data
[offset
] == chr(0xFF) and data
[offset
+1] == chr(0xFF):
20 return '', offset
+2 # Blank string
21 length
, offset
= getint(data
, offset
, 2) # 2-byte length
22 value
= data
[offset
:offset
+length
]
23 return value
, (offset
+ length
)
25 def process_mbdb_file(filename
):
26 mbdb
= {} # Map offset of info in this file => file info
27 data
= open(filename
).read()
28 if data
[0:4] != "mbdb": raise Exception("This does not look like an MBDB file")
30 offset
= offset
+ 2 # value x05 x00, not sure what this is
31 while offset
< len(data
):
33 fileinfo
['start_offset'] = offset
34 fileinfo
['domain'], offset
= getstring(data
, offset
)
35 fileinfo
['filename'], offset
= getstring(data
, offset
)
36 fileinfo
['linktarget'], offset
= getstring(data
, offset
)
37 fileinfo
['datahash'], offset
= getstring(data
, offset
)
38 fileinfo
['unknown1'], offset
= getstring(data
, offset
)
39 fileinfo
['mode'], offset
= getint(data
, offset
, 2)
40 fileinfo
['unknown2'], offset
= getint(data
, offset
, 4)
41 fileinfo
['unknown3'], offset
= getint(data
, offset
, 4)
42 fileinfo
['userid'], offset
= getint(data
, offset
, 4)
43 fileinfo
['groupid'], offset
= getint(data
, offset
, 4)
44 fileinfo
['mtime'], offset
= getint(data
, offset
, 4)
45 fileinfo
['atime'], offset
= getint(data
, offset
, 4)
46 fileinfo
['ctime'], offset
= getint(data
, offset
, 4)
47 fileinfo
['filelen'], offset
= getint(data
, offset
, 8)
48 fileinfo
['flag'], offset
= getint(data
, offset
, 1)
49 fileinfo
['numprops'], offset
= getint(data
, offset
, 1)
50 fileinfo
['properties'] = {}
51 for ii
in range(fileinfo
['numprops']):
52 propname
, offset
= getstring(data
, offset
)
53 propval
, offset
= getstring(data
, offset
)
54 fileinfo
['properties'][propname
] = propval
55 mbdb
[fileinfo
['start_offset']] = fileinfo
56 fullpath
= fileinfo
['domain'] + '-' + fileinfo
['filename']
57 id = hashlib
.sha1(fullpath
)
58 mbdx
[fileinfo
['start_offset']] = id.hexdigest()
63 if (val
& 0x4): r
= 'r'
65 if (val
& 0x2): w
= 'w'
67 if (val
& 0x1): x
= 'x'
70 return mode(val
>>6) + mode((val
>>3)) + mode(val
)
72 def fileinfo_str(f
, verbose
=False):
73 # if not verbose: return "(%s)%s::%s" % (f['fileID'], f['domain'], f['filename'])
74 if not verbose
: return "%s => %s (%s)" % (f
['fileID'], f
['filename'], f
['domain'])
75 if (f
['mode'] & 0xE000) == 0xA000: type = 'l' # symlink
76 elif (f
['mode'] & 0xE000) == 0x8000: type = '-' # file
77 elif (f
['mode'] & 0xE000) == 0x4000: type = 'd' # dir
79 print >> sys
.stderr
, "Unknown file type %04x for %s" % (f
['mode'], fileinfo_str(f
, False))
81 info
= ("%s%s %08x %08x %7d %10d %10d %10d (%s)%s::%s" %
82 (type, modestr(f
['mode']&0x0FFF) , f
['userid'], f
['groupid'], f
['filelen'],
83 f
['mtime'], f
['atime'], f
['ctime'], f
['fileID'], f
['domain'], f
['filename']))
84 if type == 'l': info
= info
+ ' -> ' + f
['linktarget'] # symlink destination
85 for name
, value
in f
['properties'].items(): # extra properties
86 info
= info
+ ' ' + name
+ '=' + repr(value
)
90 if __name__
== '__main__':
91 mbdb
= process_mbdb_file("Manifest.mbdb")
92 for offset
, fileinfo
in mbdb
.items():
94 fileinfo
['fileID'] = mbdx
[offset
]
96 fileinfo
['fileID'] = "<nofileID>"
97 print >> sys
.stderr
, "No fileID found for %s" % fileinfo_str(fileinfo
)
98 print fileinfo_str(fileinfo
)