added files
This commit is contained in:
parent
8be86cb1fc
commit
8eb9a58938
1
AUTHORS
Normal file
1
AUTHORS
Normal file
@ -0,0 +1 @@
|
||||
fatmapper is written and maintained by Patrick Neumann <patrick@neumannsland.de>.
|
21
CHANGES
Normal file
21
CHANGES
Normal file
@ -0,0 +1,21 @@
|
||||
Release 1.0 (in development)
|
||||
============================
|
||||
|
||||
|
||||
(Incompatible) changes
|
||||
----------------------
|
||||
|
||||
* none
|
||||
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* none
|
||||
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* none
|
||||
|
BIN
doc/fatmapper_documentation.pdf
Normal file
BIN
doc/fatmapper_documentation.pdf
Normal file
Binary file not shown.
858
fatmapper.py
Executable file
858
fatmapper.py
Executable file
@ -0,0 +1,858 @@
|
||||
#!/usr/bin/env python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Display general details of a FAT file system."""
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE:
|
||||
# ./fatmapper.py
|
||||
#
|
||||
# BASIC USAGE:
|
||||
# $ ./fatmapper.py [-h|--help] [-o|--offset OFFSET] image
|
||||
# OR
|
||||
# $ python fatmapper.py [-h|--help] [-o|--offset OFFSET] image
|
||||
#
|
||||
# OPTIONS:
|
||||
# -h,
|
||||
# --help show help message and exit
|
||||
# -o OFFSET,
|
||||
# --offset OFFSET offset in sectors (default=0)
|
||||
# image raw image file (esp. dd)
|
||||
#
|
||||
# EXIT STATES:
|
||||
# 0 = success
|
||||
# 1 = Python version not tested/supported
|
||||
# 2 = image file does not exist
|
||||
# 3 = offset is not a positive integer
|
||||
# 4 = wrong or missing data in dictionary
|
||||
# 5 = empty image file
|
||||
# 6 = image file smaller than offset
|
||||
# 7 = invalid vbr signatures
|
||||
#
|
||||
# REQUIREMENTS:
|
||||
# python2.7
|
||||
#
|
||||
# NOTES:
|
||||
# Tested on:
|
||||
# - ArchLinux (64-Bit) + python 2.7.13
|
||||
# - Raspbian GNU/Linux 8.0 (32-Bit) + python 2.7.9
|
||||
# - macOS (10.12.3) + python 2.7.10
|
||||
# - Bash on Ubuntu on Windows 10 (64-Bit) + python 2.7.6
|
||||
# with:
|
||||
# - raw images
|
||||
# - filesystem(s) in partition(s)
|
||||
# - filesystem without a partition
|
||||
# - no partition/no filesystem (empty file)
|
||||
# - invalid filesystem
|
||||
# - FAT12, FAT16 and FAT32
|
||||
#
|
||||
# WARRANTY:
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the LICENSE file for more details.
|
||||
#
|
||||
# HISTORY:
|
||||
# See the CHANGES file for more details.
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
#=== MODULES ===================================================================
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
|
||||
#=== INFO ======================================================================
|
||||
|
||||
"""@author: Patrick Neumann
|
||||
@contact: patrick@neumannsland.de
|
||||
@copyright: Copyright (C) 2017, Patrick Neumann
|
||||
@license: GNU General Public License 3.0
|
||||
@date: 2017-03-26
|
||||
@version: 1.0.0
|
||||
@status: Development
|
||||
"""
|
||||
|
||||
#=== CHECKS ====================================================================
|
||||
|
||||
"""Only tested with Python versions 2.7.9, 2.7.10 and 2.7.13!
|
||||
|
||||
Python 3.x is not supported!
|
||||
"""
|
||||
|
||||
if sys.version_info < (2, 7, 0):
|
||||
sys.stderr.write("Sorry, your Python version was not tested but may work?\n")
|
||||
sys.exit(1)
|
||||
|
||||
if sys.version_info >= (3, 0, 0):
|
||||
sys.stderr.write("Error: Python 3.x is not supported!\n")
|
||||
sys.exit(1)
|
||||
|
||||
#=== FUNCTIONS =================================================================
|
||||
|
||||
# This is a private module function only for the other module functions.
|
||||
# Unfortunately, the underscore does not prevent other developers from using
|
||||
# it directly from outside this module. :-(
|
||||
# sphinx-apidoc does ignore it. :-)
|
||||
def _checkimage(_file):
|
||||
"""Check image file.
|
||||
|
||||
Check if the image is a existing file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_file : str
|
||||
path to the image file.
|
||||
|
||||
Raises
|
||||
------
|
||||
Exits if the image does not exist.
|
||||
"""
|
||||
|
||||
if not os.path.isfile(_file):
|
||||
sys.stderr.write("Error: image file does not exist!\n")
|
||||
sys.exit(2)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# This is a private module function only for the other module functions.
|
||||
# Unfortunately, the underscore does not prevent other developers from using
|
||||
# it directly from outside this module. :-(
|
||||
# sphinx-apidoc does ignore it. :-)
|
||||
def _checkoffset(loffset):
|
||||
"""Check offset.
|
||||
|
||||
Check if the offset is an integer and is equal or greater than zero.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
Raises
|
||||
------
|
||||
Exits if the offset is not equal or greater than zero.
|
||||
"""
|
||||
|
||||
if not isinstance(loffset, int):
|
||||
sys.stderr.write("Error: offset is not an integer!\n")
|
||||
sys.exit(3)
|
||||
|
||||
if not loffset >= 0:
|
||||
sys.stderr.write("Error: offset is not equal or greater zero!\n")
|
||||
sys.exit(3)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# This is a private module function only for the other module functions.
|
||||
# Unfortunately, the underscore does not prevent other developers from using
|
||||
# it directly from outside this module. :-(
|
||||
# sphinx-apidoc does ignore it. :-)
|
||||
def _checkdict(check, _dict):
|
||||
"""Check dictionary.
|
||||
|
||||
Check if the dictionary contains all needed data and that the data has
|
||||
the right type.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
check : dict)
|
||||
dictionary with necessary keys and types of the data dictionary.
|
||||
|
||||
_dict : dict
|
||||
dictionary with mapping of parts of a fat VBR to a human readable index.
|
||||
|
||||
Raises
|
||||
------
|
||||
Exits if the data dictionary does not contain the necessary keys or the
|
||||
type of data is incorrect.
|
||||
"""
|
||||
|
||||
for key, var in check.items():
|
||||
if not key in _dict:
|
||||
sys.stderr.write("Error: necessary data is missing in dictionary!\n")
|
||||
sys.exit(4)
|
||||
# attention: on 32-Bit systems there is more often used long
|
||||
# where on 64-Bit systems is int big enough:
|
||||
if not isinstance(_dict[key], var):
|
||||
sys.stderr.write("Error: invalid type of data in dictionary!\n")
|
||||
sys.exit(4)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# This is a private module function only for the other module functions.
|
||||
# Unfortunately, the underscore does not prevent other developers from using
|
||||
# it directly from outside this module. :-(
|
||||
# sphinx-apidoc does ignore it. :-)
|
||||
def _getargs():
|
||||
"""Get command line arguments.
|
||||
|
||||
Parses the command line arguments, checks and return them.
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple
|
||||
A tuple containing the checked path to the image file
|
||||
and the offset in bytes in the image file calculated from sectors.
|
||||
|
||||
The default offset is 0.
|
||||
|
||||
For example:
|
||||
( "fat12_in_partition.dd", 1048576 )
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("image",
|
||||
type=str,
|
||||
help="raw image file (esp.: image.dd)")
|
||||
parser.add_argument("-o",
|
||||
"--offset",
|
||||
type=int,
|
||||
default=0,
|
||||
help="offset in sectors (default=0)")
|
||||
args = parser.parse_args()
|
||||
|
||||
_checkimage(args.image)
|
||||
limage = args.image
|
||||
|
||||
_checkoffset(args.offset)
|
||||
loffset = args.offset * 512
|
||||
|
||||
return (limage, loffset)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def getsize(_file, loffset):
|
||||
"""Get image file size.
|
||||
|
||||
Get size of the image file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_file : str
|
||||
path to the image file.
|
||||
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
size of image file in bytes.
|
||||
|
||||
Raises
|
||||
------
|
||||
Exits if image file is empty or smaller than offset.
|
||||
"""
|
||||
|
||||
_checkimage(_file)
|
||||
_checkoffset(loffset)
|
||||
|
||||
lsize = os.stat(_file)[6]
|
||||
|
||||
if lsize == 0:
|
||||
sys.stderr.write("Error: the image file is an empty file!\n")
|
||||
sys.exit(5)
|
||||
|
||||
if lsize < loffset + 512:
|
||||
sys.stderr.write("Error: size of the image file is smaller than offset (+ 512 byte)!\n")
|
||||
sys.exit(6)
|
||||
|
||||
return lsize
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def getmd5(_file):
|
||||
"""Get MD5 of image file.
|
||||
|
||||
Get MD5 digest in hex for the content of the image file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_file : str
|
||||
path to the image file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
MD5 digest in uppercase hex.
|
||||
"""
|
||||
|
||||
_checkimage(_file)
|
||||
|
||||
lfile = open(_file, "rb")
|
||||
lmd5 = hashlib.md5(lfile.read()).hexdigest().upper()
|
||||
lfile.close()
|
||||
|
||||
return lmd5
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def checkvbr(_file, loffset):
|
||||
"""Check for FAT VBR.
|
||||
|
||||
Check for the existence of a valid FAT12/16/32 VBR.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_file : str
|
||||
path to the image file.
|
||||
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
file_system_type (FAT1X or FAT32)
|
||||
|
||||
Raises
|
||||
------
|
||||
Exits if the VBR can not be verified as a FAT12/16/32 VBR.
|
||||
"""
|
||||
|
||||
_checkimage(_file)
|
||||
_checkoffset(loffset)
|
||||
|
||||
lfile = open(_file, "rb")
|
||||
lfile.seek(loffset + 38)
|
||||
extended_signature = lfile.read(1)
|
||||
|
||||
if extended_signature == "\x29":
|
||||
lfile.seek(15, 1)
|
||||
file_system_type = lfile.read(8)
|
||||
lfile.seek(448, 1)
|
||||
vbr_signature = lfile.read(2)
|
||||
file_system_type_switch = "FAT1X"
|
||||
else:
|
||||
lfile.seek(loffset + 66)
|
||||
extended_signature = lfile.read(1)
|
||||
lfile.seek(15, 1)
|
||||
file_system_type = lfile.read(8)
|
||||
lfile.seek(420, 1)
|
||||
vbr_signature = lfile.read(2)
|
||||
file_system_type_switch = "FAT32"
|
||||
lfile.close()
|
||||
|
||||
condition1 = extended_signature == "\x29"
|
||||
condition2 = re.search(r'FAT(1(2|6)|32) ', file_system_type)
|
||||
condition3 = vbr_signature == "\x55\xaa"
|
||||
|
||||
if not (condition1 and condition2 and condition3):
|
||||
sys.stderr.write("Error: no valid FAT12/FAT16/FAT32 VBR found!\n")
|
||||
sys.exit(7)
|
||||
|
||||
#print "fileSystemTypeSwitch:", fileSystemTypeSwitch
|
||||
|
||||
return file_system_type_switch
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def getraw(_file, loffset):
|
||||
"""Get global data.
|
||||
|
||||
Read raw data from the VBR into a python dictionary.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_file : str
|
||||
path to the image file.
|
||||
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
dictionary with mapping of parts of a fat VBR to a human readable index.
|
||||
|
||||
For example:
|
||||
|
||||
{"bytesPerSector": 512,
|
||||
"sectorsPerCluster": 64,
|
||||
"reservedSectors": 1,
|
||||
"fatCopies": 2,
|
||||
"rootDirectoryEntries": 1024,
|
||||
"sectorsInPartition": 0,
|
||||
"rawMediaDescriptor": 248,
|
||||
"sectorsPerFat": 64,
|
||||
"sectorsPerTrack": 32,
|
||||
"numberOfHeads": 64,
|
||||
"hiddenSectors": 0,
|
||||
"largerSectorsInPartition": 260096}
|
||||
"""
|
||||
|
||||
_checkimage(_file)
|
||||
_checkoffset(loffset)
|
||||
|
||||
keys = ["bytesPerSector", "sectorsPerCluster", "reservedSectors",
|
||||
"fatCopies", "rootDirectoryEntries", "sectorsInPartition",
|
||||
"rawMediaDescriptor", "sectorsPerFat", "sectorsPerTrack",
|
||||
"numberOfHeads", "hiddenSectors", "largerSectorsInPartition"]
|
||||
|
||||
lfile = open(_file, "rb")
|
||||
lfile.seek(loffset + 3) # just skip the jumpcode
|
||||
oem_name_version = lfile.read(8)
|
||||
raw = lfile.read(2 + 1 + 2 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 4 + 4)
|
||||
values = struct.unpack_from("<HBHBHHBHHHII", raw)
|
||||
_dict = dict(zip(keys, values))
|
||||
_dict["oemNameVersion"] = oem_name_version
|
||||
lfile.close()
|
||||
|
||||
#for k, v in _dict.items():
|
||||
# print k, ":", v
|
||||
|
||||
return _dict
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def getraw1x(_file, loffset):
|
||||
"""Get FAT12/16 spezial data.
|
||||
|
||||
Read raw data from the VBR into a python dictionary.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_file : str
|
||||
path to the image file.
|
||||
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
dictionary with mapping of parts of a fat VBR to a human readable index.
|
||||
|
||||
For example:
|
||||
|
||||
{"logicalDriveNumber": 128,
|
||||
"RESERVED": 0,
|
||||
"extendedSignature": 41,
|
||||
"rawVolumeSerialNumber": 549101972,
|
||||
"oemNameVersion": "mkfs.fat",
|
||||
"volumeLabel": "NO NAME ",
|
||||
"rawFileSystemType": "FAT12 ",
|
||||
"vbrSignature": "\x55\xaa"}
|
||||
"""
|
||||
|
||||
_checkimage(_file)
|
||||
_checkoffset(loffset)
|
||||
|
||||
keys = ["logicalDriveNumber", "RESERVED", "extendedSignature",
|
||||
"rawVolumeSerialNumber"]
|
||||
|
||||
lfile = open(_file, "rb")
|
||||
lfile.seek(loffset + 36) # just skip the global area
|
||||
raw = lfile.read(1 + 1 + 1 + 4)
|
||||
values = struct.unpack_from("<BBBI", raw)
|
||||
_dict = dict(zip(keys, values))
|
||||
_dict["volumeLabel"] = lfile.read(11)
|
||||
_dict["rawFileSystemType"] = lfile.read(8)
|
||||
lfile.seek(448, 1) # absolute offset 510 - actual offset 62 = relative offset 448
|
||||
_dict["vbrSignature"] = lfile.read(2)
|
||||
lfile.close()
|
||||
|
||||
#for k, v in _dict.items():
|
||||
# print k, ":", v
|
||||
|
||||
return _dict
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def getraw32(_file, loffset):
|
||||
"""Get FAT32 spezial data.
|
||||
|
||||
Read raw data from the VBR into a python dictionary.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_file :str
|
||||
path to the image file.
|
||||
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
dictionary with mapping of parts of a fat VBR to a human readable index.
|
||||
|
||||
For example:
|
||||
|
||||
{"sectorsPerFat": 947,
|
||||
"mirrorFlags": 0,
|
||||
"fileSystemVersion": 0,
|
||||
"firstClusterOfRootDirectory": 2,
|
||||
"fsinfoSector": 1,
|
||||
"backupBootSector": 6,
|
||||
"logicalDriveNumber": 128,
|
||||
"RESERVED": 0,
|
||||
"extendedSignature": 41,
|
||||
"rawVolumeSerialNumber": 774266948,
|
||||
"volumeLabel": "NO NAME ",
|
||||
"rawFileSystemType": "FAT32 ",
|
||||
"vbrSignature": "\x55\xaa"}
|
||||
"""
|
||||
|
||||
_checkimage(_file)
|
||||
_checkoffset(loffset)
|
||||
|
||||
keys1 = ["sectorsPerFat", "mirrorFlags", "fileSystemVersion",
|
||||
"firstClusterOfRootDirectory", "fsinfoSector", "backupBootSector"]
|
||||
keys2 = ["logicalDriveNumber", "RESERVED", "extendedSignature",
|
||||
"rawVolumeSerialNumber"]
|
||||
lfile = open(_file, "rb")
|
||||
lfile.seek(loffset + 36) # just skip the global area
|
||||
raw1 = lfile.read(4 + 2 + 2 + 4 + 2 + 2)
|
||||
values1 = struct.unpack_from("<IHHIHH", raw1)
|
||||
_dict = dict(zip(keys1, values1))
|
||||
lfile.seek(12, 1)
|
||||
raw2 = lfile.read(1 + 1 + 1 + 4)
|
||||
values2 = struct.unpack_from("<BBBI", raw2)
|
||||
_dict.update(dict(zip(keys2, values2)))
|
||||
_dict["volumeLabel"] = lfile.read(11)
|
||||
_dict["rawFileSystemType"] = lfile.read(8)
|
||||
lfile.seek(420, 1) # absolute offset 510 - actual offset 90 = relative offset 420
|
||||
_dict["vbrSignature"] = lfile.read(2)
|
||||
lfile.close()
|
||||
|
||||
#for k, v in _dict.items():
|
||||
# print k, ":", v
|
||||
|
||||
return _dict
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def transform(_dict):
|
||||
"""Transform data.
|
||||
|
||||
Do some modifications to the raw data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_dict : dict
|
||||
dictionary with mapping of parts of a fat VBR to a human readable index.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
dictionary with mapping of transformed parts of a fat VBR to a human
|
||||
readable index.
|
||||
"""
|
||||
|
||||
check = {"bytesPerSector": (int, long),
|
||||
"sectorsPerCluster": (int, long),
|
||||
"rawMediaDescriptor": (int, long),
|
||||
"sectorsInPartition": (int, long),
|
||||
"largerSectorsInPartition": (int, long),
|
||||
"rawFileSystemType": str,
|
||||
"rawVolumeSerialNumber": (int, long)}
|
||||
_checkdict(check, _dict)
|
||||
|
||||
_dict["bytesPerCluster"] = _dict["bytesPerSector"] * _dict["sectorsPerCluster"]
|
||||
if _dict["rawMediaDescriptor"] == 240:
|
||||
_dict["mediaDescriptor"] = "floppy disk"
|
||||
elif _dict["rawMediaDescriptor"] == 248:
|
||||
_dict["mediaDescriptor"] = "hard disk"
|
||||
else:
|
||||
sys.stderr.write("Error: no valid media descriptor found!\n")
|
||||
sys.exit(2)
|
||||
|
||||
if _dict["sectorsInPartition"] == 0:
|
||||
_dict["sectorsInPartition"] = _dict["largerSectorsInPartition"]
|
||||
_dict["fileSystemType"] = _dict["rawFileSystemType"][:3] + " " + _dict["rawFileSystemType"][3:]
|
||||
_dict["volumeSerialNumber"] = "0x" + '{:08X}'.format(_dict["rawVolumeSerialNumber"])
|
||||
|
||||
#for k, v in _dict.items():
|
||||
# print k, ":", v
|
||||
|
||||
return _dict
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def getrootdirsize32(_file, loffset, _dict):
|
||||
"""Get FAT32 root directory informations.
|
||||
|
||||
Read raw data about the root directory from the FAT32 VBR into a python dictionary.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
_dict :dict
|
||||
dictionary with mapping of parts of a fat VBR to a human readable index.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
dictionary with start, end and size of the root directory.
|
||||
"""
|
||||
|
||||
_checkoffset(loffset)
|
||||
check = {"reservedSectors": (int, long),
|
||||
"bytesPerSector": (int, long),
|
||||
"firstClusterOfRootDirectory": (int, long),
|
||||
"sectorsPerFat": (int, long),
|
||||
"sectorsPerCluster": (int, long)}
|
||||
_checkdict(check, _dict)
|
||||
|
||||
lfile = open(_file, "rb")
|
||||
lfile.seek(loffset +
|
||||
(_dict["reservedSectors"] * _dict["bytesPerSector"]) +
|
||||
(_dict["firstClusterOfRootDirectory"] * 4))
|
||||
raw = lfile.read(4)
|
||||
cluster = struct.unpack_from("<I", raw)[0]
|
||||
_min = _dict["firstClusterOfRootDirectory"]
|
||||
_max = _min
|
||||
counter = 1
|
||||
while cluster >= 2 and cluster <= 268435446:
|
||||
if cluster > _max:
|
||||
_max = cluster
|
||||
if cluster < _min:
|
||||
_min = cluster
|
||||
counter = counter + 1
|
||||
_next = loffset + (_dict["reservedSectors"] * _dict["bytesPerSector"]) + (cluster * 4)
|
||||
if not lfile.tell() == _next:
|
||||
lfile.seek(_next - lfile.tell(), 1)
|
||||
raw = lfile.read(4)
|
||||
cluster = struct.unpack_from("<I", raw)[0]
|
||||
lfile.close()
|
||||
|
||||
# In the FAT the root directory starts in the entry 2 (0 = label and 1 = reserved)
|
||||
# but in the data area it starts in cluster in the first (= 0)!
|
||||
# To find the root directory in the FAT you have to use the entry in the VBR.
|
||||
# To find the root directory in the data area you have to use the entry in the VBR - 2!
|
||||
root_directory = {"rootDirectoryStartSector": _dict["reservedSectors"] +
|
||||
2 * _dict["sectorsPerFat"] + _min - 2,
|
||||
"rootDirectoryEndSector": _dict["reservedSectors"] +
|
||||
2 * _dict["sectorsPerFat"] +
|
||||
_max -
|
||||
2 +
|
||||
_dict["sectorsPerCluster"] -
|
||||
1,
|
||||
"rootDirectorySize": counter * _dict["sectorsPerCluster"]}
|
||||
|
||||
#for k, v in rootDirectory.items():
|
||||
# print k, ":", v
|
||||
|
||||
return root_directory
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def calculate(_file, loffset, _dict):
|
||||
"""Calcuate data.
|
||||
|
||||
Do some calculations with the raw/modified data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_dict : dict
|
||||
dictionary with mapping of transformed parts of a fat VBR to
|
||||
a human readable index.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
dictionary with mapping of transformed parts and added calculations of
|
||||
a fat VBR to a human readable index.
|
||||
"""
|
||||
|
||||
_checkoffset(loffset)
|
||||
check = {"reservedSectors": (int, long),
|
||||
"sectorsPerFat": (int, long),
|
||||
"sectorsInPartition": (int, long),
|
||||
"rootDirectoryEntries": (int, long),
|
||||
"bytesPerSector": (int, long)}
|
||||
_checkdict(check, _dict)
|
||||
|
||||
_dict["FAT0StartSector"] = _dict["reservedSectors"]
|
||||
_dict["FAT0EndSector"] = _dict["reservedSectors"] + _dict["sectorsPerFat"] - 1
|
||||
_dict["FAT1StartSector"] = _dict["FAT0EndSector"] + 1
|
||||
_dict["FAT1EndSector"] = _dict["FAT1StartSector"] + _dict["sectorsPerFat"] - 1
|
||||
_dict["DataAreaStartSector"] = _dict["FAT1EndSector"] + 1
|
||||
_dict["DataAreaEndSector"] = _dict["sectorsInPartition"] - 1
|
||||
_dict["DataAreaSize"] = _dict["sectorsInPartition"] - _dict["DataAreaStartSector"]
|
||||
if _dict["rootDirectoryEntries"] != 0:
|
||||
_dict["rootDirectoryStartSector"] = _dict["DataAreaStartSector"]
|
||||
_dict["rootDirectorySize"] = _dict["rootDirectoryEntries"] * 32 / _dict["bytesPerSector"]
|
||||
_dict["rootDirectoryEndSector"] = (_dict["DataAreaStartSector"] +
|
||||
_dict["rootDirectorySize"] - 1)
|
||||
else:
|
||||
_dict.update(getrootdirsize32(_file, loffset, _dict))
|
||||
|
||||
#for k, v in _dict.items():
|
||||
# print k, ":", v
|
||||
|
||||
return _dict
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def getlabel2(_file, loffset, _dict):
|
||||
"""Get FAT32 root directory data.
|
||||
|
||||
Read raw data about the label from the FAT32 root directory into a python dictionary.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
_dict : dict
|
||||
dictionary with mapping of parts of a fat VBR to a human readable index.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
volume label from root directory
|
||||
"""
|
||||
|
||||
_checkoffset(loffset)
|
||||
check = {"rootDirectoryStartSector": (int, long),
|
||||
"bytesPerSector": (int, long)}
|
||||
_checkdict(check, _dict)
|
||||
|
||||
lfile = open(_file, "rb")
|
||||
lfile.seek(loffset + _dict["rootDirectoryStartSector"] * _dict["bytesPerSector"])
|
||||
volume_label2 = lfile.read(11)
|
||||
lfile.close()
|
||||
|
||||
#print "volumeLabel2:", volumeLabel2
|
||||
|
||||
return volume_label2
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def main(_file, loffset, _dict):
|
||||
"""Print data.
|
||||
|
||||
Insert the data into the template and print it on stdout.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
_file : str
|
||||
path to the image file.
|
||||
|
||||
loffset : int
|
||||
offset in bytes in the image file.
|
||||
|
||||
_dict : dict
|
||||
dictionary with mapping of transformed parts and added
|
||||
calculations of a fat VBR to a human readable index.
|
||||
"""
|
||||
|
||||
_checkimage(_file)
|
||||
_checkoffset(loffset)
|
||||
check = {"size": (int, long),
|
||||
"md5": str,
|
||||
"volumeLabel": str,
|
||||
"oemNameVersion": str,
|
||||
"fileSystemType": str,
|
||||
"volumeSerialNumber": str,
|
||||
"bytesPerSector": (int, long),
|
||||
"bytesPerCluster": (int, long),
|
||||
"sectorsPerCluster": (int, long),
|
||||
"sectorsInPartition": (int, long),
|
||||
"fatCopies": (int, long),
|
||||
"reservedSectors": (int, long),
|
||||
"FAT0StartSector": (int, long),
|
||||
"FAT0EndSector": (int, long),
|
||||
"sectorsPerFat": (int, long),
|
||||
"FAT1StartSector": (int, long),
|
||||
"FAT1EndSector": (int, long),
|
||||
"DataAreaStartSector": (int, long),
|
||||
"DataAreaEndSector": (int, long),
|
||||
"DataAreaSize": (int, long),
|
||||
"rootDirectoryStartSector": (int, long),
|
||||
"rootDirectoryEndSector": (int, long),
|
||||
"rootDirectorySize": (int, long)}
|
||||
_checkdict(check, _dict)
|
||||
|
||||
tpl24_1 = "{:<24}{}"
|
||||
tpl24_1b = "{:<24}{} bytes"
|
||||
tpl24_2 = "{:<24}{} bytes ({} Sectors)"
|
||||
tpl24_3 = "{:<24}{} - {} ({} Sectors)"
|
||||
tpl21 = "{:<21}{} - {} ({} Sectors)"
|
||||
print "File Information"
|
||||
print tpl24_1.format("-- Name:",
|
||||
_file)
|
||||
print tpl24_1.format("-- File Size:",
|
||||
_dict["size"])
|
||||
print tpl24_1.format("-- MD5:",
|
||||
_dict["md5"])
|
||||
print
|
||||
print "FS Information"
|
||||
print tpl24_1.format("-- Volume Label:",
|
||||
_dict["volumeLabel"])
|
||||
if _dict["fileSystemType"] == "FAT 32 ":
|
||||
print tpl24_1.format("-- Volume Label #2:",
|
||||
getlabel2(_file, loffset, _dict))
|
||||
print tpl24_1.format("-- OEM Name:",
|
||||
_dict["oemNameVersion"])
|
||||
print tpl24_1.format("-- File System:",
|
||||
_dict["fileSystemType"])
|
||||
print tpl24_1.format("-- Volume ID:",
|
||||
_dict["volumeSerialNumber"])
|
||||
print
|
||||
print tpl24_1b.format("-- Sector Size:",
|
||||
_dict["bytesPerSector"])
|
||||
print tpl24_2.format("-- Cluster Size:",
|
||||
_dict["bytesPerCluster"],
|
||||
_dict["sectorsPerCluster"])
|
||||
print tpl24_1.format("-- Number of Sectors:",
|
||||
_dict["sectorsInPartition"])
|
||||
print tpl24_1.format("-- Number of FATs:",
|
||||
_dict["fatCopies"])
|
||||
print tpl24_3.format("-- Total Range:",
|
||||
0,
|
||||
int(_dict["sectorsInPartition"]) - 1,
|
||||
_dict["sectorsInPartition"])
|
||||
print
|
||||
print "FS Layout"
|
||||
print tpl21.format("-- Reserved:",
|
||||
0,
|
||||
int(_dict["reservedSectors"]) - 1,
|
||||
_dict["reservedSectors"])
|
||||
print tpl21.format("---- VBR:", 0, 0, 1)
|
||||
print tpl21.format("-- FAT 0:",
|
||||
_dict["FAT0StartSector"],
|
||||
_dict["FAT0EndSector"],
|
||||
_dict["sectorsPerFat"])
|
||||
print tpl21.format("-- FAT 1:",
|
||||
_dict["FAT1StartSector"],
|
||||
_dict["FAT1EndSector"],
|
||||
_dict["sectorsPerFat"])
|
||||
print tpl21.format("-- Data Area:",
|
||||
_dict["DataAreaStartSector"],
|
||||
_dict["DataAreaEndSector"],
|
||||
_dict["DataAreaSize"])
|
||||
print tpl21.format("---- Root Dir:",
|
||||
_dict["rootDirectoryStartSector"],
|
||||
_dict["rootDirectoryEndSector"],
|
||||
_dict["rootDirectorySize"])
|
||||
|
||||
#=== MAIN ======================================================================
|
||||
|
||||
if __name__ == '__main__':
|
||||
(IMAGE, OFFSET) = _getargs()
|
||||
SIZE = getsize(IMAGE, OFFSET) # has to be done after _getargs()!
|
||||
SWITCH = checkvbr(IMAGE, OFFSET)
|
||||
DATA = getraw(IMAGE, OFFSET)
|
||||
if SWITCH == "FAT1X":
|
||||
DATA.update(getraw1x(IMAGE, OFFSET))
|
||||
else:
|
||||
DATA.update(getraw32(IMAGE, OFFSET))
|
||||
DATA["size"] = SIZE
|
||||
DATA["md5"] = getmd5(IMAGE)
|
||||
DATA = transform(DATA)
|
||||
DATA = calculate(IMAGE, OFFSET, DATA)
|
||||
main(IMAGE, OFFSET, DATA)
|
||||
sys.exit(0)
|
12
fatmapper_dict_missing_data.py
Executable file
12
fatmapper_dict_missing_data.py
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Only a short python script to provoke exit state 4 of the fatmapper module!
|
||||
|
||||
import fatmapper
|
||||
|
||||
empty = {}
|
||||
|
||||
fatmapper.transform( empty )
|
||||
|
||||
sys.exit( 0 )
|
18
fatmapper_dict_wrong_type.py
Executable file
18
fatmapper_dict_wrong_type.py
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Only a short python script to provoke exit state 4 of the fatmapper module!
|
||||
|
||||
import fatmapper
|
||||
|
||||
wrong = { "bytesPerSector": "string",
|
||||
"sectorsPerCluster": "string",
|
||||
"rawMediaDescriptor": "string",
|
||||
"sectorsInPartition": "string",
|
||||
"largerSectorsInPartition": "string",
|
||||
"rawFileSystemType": 1,
|
||||
"rawVolumeSerialNumber": "string" }
|
||||
|
||||
fatmapper.transform( wrong )
|
||||
|
||||
sys.exit( 0 )
|
Loading…
x
Reference in New Issue
Block a user