Skip to content

Commit a229b97

Browse files
committed
Fixed INDX block parser
1 parent 9588174 commit a229b97

File tree

4 files changed

+32
-32
lines changed

4 files changed

+32
-32
lines changed

FATtools/NTFS/Index.py

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
class IndexGroup:
1010
def __init__ (self, index_root, index_allocation):
11-
self.inited = True
1211
self.index_root = index_root
1312
self.index_allocation = index_allocation
1413

@@ -21,7 +20,7 @@ def iterator(self):
2120
for o in self.index_root.iterator():
2221
if DEBUG&8: log("Internal entry", o.FileName)
2322
yield o
24-
if self.index_allocation:
23+
if self.index_allocation and self.index_allocation.valid:
2524
for o in self.index_allocation.iterator():
2625
if DEBUG&8: log("External entry", o.FileName)
2726
yield o
@@ -33,16 +32,14 @@ def find(self, name):
3332
return None
3433

3534
class Index:
36-
def __init__ (self, indxstream, bitmap, size, resident=0):
37-
#~ print('Index.init called',indxstream, bitmap, size, resident)
38-
self.inited = False
39-
self.block_size = size
35+
def __init__ (self, indxstream, bitmap, block_size, resident=0):
36+
#~ print('Index.init called',indxstream, bitmap, block_size, resident)
37+
self.valid = False
38+
self.block_size = block_size
4039
self._stream = indxstream
41-
self._bitmap = bitmap # only $INDEX_ALLOCATION has one!
40+
self._bitmap = bitmap # in $INDEX_ALLOCATION (bit set if INDX in use)
4241
self._pos = self._stream.tell()
4342
self._resident = resident
44-
# $Bitmap shows free Index clusters
45-
# Last free clusters do not require INDX marker
4643
self._buf = self._stream.read(self.block_size)
4744
if resident:
4845
#~ print('DBG: initing resident INDX')
@@ -55,22 +52,22 @@ def __init__ (self, indxstream, bitmap, size, resident=0):
5552
#~ print("New INDEX_HEADER:", self._indxh)
5653
else:
5754
#~ print('DBG: initing non resident INDX')
58-
#~ self._stream.seek(0)
59-
#~ open('INDX.BIN', 'wb').write(self._stream.read())
55+
# Sometimes an $INDEX_ALLOCATION has empty stream: full dir contents deletion?
56+
if not self._buf:
57+
if DEBUG&8: log("Empty INDX block @%X/%X", self._pos, self._stream.size)
58+
#~ print('Empty INDX block', self._pos, self._stream.size, self._stream)
59+
return
6060
block = Index_Block(self._buf)
6161
if not block:
62-
if self._bitmap and not self._bitmap.isset(self._pos//self.block_size):
63-
if DEBUG&8: log("Cluster INDX %d non used but zeroed", self._pos//self.block_size)
64-
#~ print("Cluster INDX %d non used but zeroed"% self._pos//self.block_size)
65-
return
62+
raise NTFSException('INDX initialization failed')
6663
if DEBUG&8: log("decoded INDEX_BLOCK:\n%s", block)
6764
#~ print("decoded INDEX_BLOCK:\n%s"% block)
6865
self._indxh = Index_Header(self._buf, 24)
6966
if DEBUG&8: log("decoded INDEX_HEADER:\n%s", self._indxh)
7067
#~ print("decoded INDEX_HEADER:\n%s"% self._indxh)
71-
self.inited = True
68+
self.valid = True
7269

73-
def __str__ (self): return "Index (inited=%d) @%x\n%s" % (self.inited, self._pos, self._indxh)
70+
def __str__ (self): return "Index @%x\n%s" % (self._pos, self._indxh)
7471

7572
__getattr__ = utils.common_getattr
7673

@@ -83,16 +80,12 @@ def find(self, name):
8380

8481
def iterator(self):
8582
"Iterates through index entries"
86-
if not self.inited:
87-
#~ print(self._pos)
88-
raise NTFSException("Can't scan an INDX block not initialized")
8983
while 1:
9084
i = self._indxh.dwEntriesOffset
9185
while i < self._indxh.dwIndexLength:
9286
e = Index_Entry(self._buf, i+self._indxh._i)
9387
if e:
94-
#~ print('DBG: Index.iterator yielding', e)
95-
# An entry with no name signals the INDX block end
88+
# An entry with wFlags & 2, or unnamed, signals the INDX block end
9689
if e.FileName: yield e
9790
if e.wFlags & 0x2:
9891
if DEBUG&8: log("last entry in current INDX block")
@@ -105,16 +98,22 @@ def iterator(self):
10598
#~ print("DBG: end of resident INDX")
10699
break
107100
if not self._resident:
101+
# Stops at end of Index stream
102+
if self._stream.tell() >= self._stream.size:
103+
#~ print("DBG: end of non resident INDX stream")
104+
break
105+
# Searches for the next used INDX
106+
while not self._bitmap.isset(self._stream.tell() // self.block_size):
107+
self._stream.seek(self.block_size, 1)
108+
if self._stream.tell() >= self._stream.size:
109+
return
108110
if self._stream.tell() >= self._stream.size:
109111
#~ print("DBG: end of non resident INDX stream")
110112
break
111-
# Loads the next INDX block or stops
113+
# Loads the next INDX block and continues iteration
112114
#~ print('DBG: tell', self._stream.tell())
115+
#~ print('DBG: loading next INDX @', self._stream.tell(), self._stream.size)
113116
self.__init__(self._stream, self._bitmap, self.block_size, 0)
114-
if not self.inited:
115-
#~ print('DBG: could not init next non-resident INDX block, stop scanning')
116-
return
117-
#~ print('New INDX block inited')
118117

119118
class Index_Block:
120119
layout = {
@@ -131,7 +130,9 @@ def __init__ (self, indx):
131130
self._vk = {} # { nome: offset}
132131
for k, v in self._kv.items():
133132
self._vk[v[0]] = k
134-
if self.sMagic != b'INDX': raise BadIndex
133+
# Unused blocks can be zeroed (=no INDX marker)
134+
if self.sMagic != b'INDX':
135+
raise BadIndex
135136
self.fixup()
136137

137138
__getattr__ = utils.common_getattr

FATtools/NTFS/Record.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class Record:
2828
def __init__ (self, boot, mftstream):
2929
#~ mftrecord.boot.stream --> NTFS Volume stream
3030
#~ mftrecord._stream --> $MFT stream
31-
self.no_expand = False
3231
self.boot = boot
3332
record_size = boot.record()
3433
self._i = 0 # buffer offset
@@ -58,7 +57,7 @@ def __init__ (self, boot, mftstream):
5857
if dwType == 0xFFFFFFFF: break
5958
elif dwType == 0x10:
6059
a = Standard_Information(self, offset)
61-
elif dwType == 0x20 and not self.no_expand:
60+
elif dwType == 0x20:
6261
a = Attribute_List(self, offset)
6362
self._expand_attribute_list(a)
6463
elif dwType == 0x30:

FATtools/NTFS/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
COPYRIGHT = '''Copyright (C)2012-2025, by maxpat78. GNU GPL v3 applies.
55
This free software reads NTFS file systems WITH ABSOLUTELY NO WARRANTY!'''
66

7-
VERSION = '0.9b'
7+
VERSION = '0.9.1b'

FATtools/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.1.0'
1+
__version__ = '1.1.1'

0 commit comments

Comments
 (0)