Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions parseusn.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,13 @@ def main(argv):
if mftfilename:
mft_to_path = parse_mft(mftfilename)

create_temp_file(infile)
if args.tempfile:
tmpname = create_temp_file(infile)
else:
tmpname = infile

it = file(tmpname,'rb')

it = file("{}.tmp".format(infile), 'rb')
if outfile is None:
ot = sys.stdout
else:
Expand Down Expand Up @@ -147,30 +151,41 @@ def main(argv):

read_length = 800
position_marker = 0
go = True
oldpos = -4
go = True

while (go == True):
if (position_marker <= oldpos):
#We NEVER sit still, skip to next page boundary
position_marker = oldpos + (0x1000 + 4)
position_marker = position_marker & 0xfffffffffffff000
oldpos = position_marker

while (go is True):
try:
# Read the record size, read the next record
# sys.stderr.write("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b Offset {}".format(position_marker))

it.seek(position_marker, os.SEEK_SET)
data = it.read(read_length)
if len(data) < 60:
print("End of File at %d" % position_marker);
go = False
continue

recordsize = struct.unpack_from('I', data)[0]

if (recordsize < 0):
go = False # Invalid data can create an endless loop
if (recordsize < 0) :
continue
if (recordsize >1024) :
continue

if (recordsize < 60):
# Note: There are places in the test $USNJRNL$J file where there are gaps between records that are not accounted for by the record size.
# The gaps are always 0x00 filled. If the record size is zero, move forward until the next non zero byte is found. The largest gap I found was 296 bytes.

gap_size = len(data.lstrip('\x00'))
if gap_size < 1:
break
continue
if gap_size == read_length:
position_marker += 8
continue
Expand All @@ -181,7 +196,7 @@ def main(argv):
position_marker = position_marker + 800 - gap_size
# records are aligned at 0x0 or 0x8, so zero out least significant 3 bits
# this is necessary if the first non-zero byte is not found at an 0x0 or 0x8 offset
position_marker = position_marker & 0xfffffff8
position_marker = position_marker & 0xfffffffffffffff8
continue

it.seek(position_marker)
Expand All @@ -193,8 +208,8 @@ def main(argv):
sys.stderr.write("\nLength of data is {}\n".format(len(data)))
position_marker = position_marker + recordsize # Initially forgot this. A struct error would loop forever...
continue
if usn_record is None:
position_marker = position_marker + recordsize
if usn_record == None:
position_marker = position_marker + 4
continue
usn_record = deflag_item(usn_record, flags)

Expand Down Expand Up @@ -276,23 +291,21 @@ def main(argv):

except struct.error, e:
sys.stderr.write(e.message)
go = False
sys.stderr.write("Struct format error at Tell: {}\n".format(it.tell()))

except:
go = False
print ("Unexpected error:", sys.exc_info()[0])
raise
print ("Unexpected error at %d:" % position_marker, sys.exc_info()[0])

it.close()
ot.close()

if args.tempfile:
# replace original sparse file USN with temp to save space since beginning of file is just NULLs
if args.replace:
os.unlink("{}".format(infile))
os.rename("{}.tmp".format(infile), "{}".format(infile))
else:
os.unlink("{}.tmp".format(infile))
if args.replace:
os.unlink("{}".format(infile))
os.rename(tmpname, "{}".format(infile))
else:
os.unlink(tmpname)

exit(0)

Expand All @@ -318,6 +331,8 @@ def cliargs():
parser.add_argument('-r', '--replace', required=False, action='store_true', dest='replace', default=False,
help='Replace original file with temp file (removes NULLs in sparse file).'
)
parser.add_argument('-n', '--notemp', required=False, action='store_false', dest='tempfile', default=True,
help='Do not create a tempfile without leading 0x00 bytes, this saves copy time')
args = parser.parse_args()
return args

Expand All @@ -334,8 +349,9 @@ def create_temp_file(infile):
position = it.tell() - len(data)
it.seek(position)

# replace main file with working file, then clean up
ot = file("{}.tmp".format(infile), 'wb')
tmpname = "{}.tmp".format(infile)
#replace main file with working file, then clean up
ot = file(tmpname,'wb')
while (True):
data = it.read(655360)
if len(data) < 655359:
Expand All @@ -347,6 +363,7 @@ def create_temp_file(infile):
it.close()
ot.close()
data = ''
return tmpname


def parse_mft(mftfile):
Expand Down