I recently needed to translate a logical address returned by
FSCLT_GET_FILE_RETRIEVAL_POINTERS to physical offset from the beginning of the disk (in bytes), but there aren't many articles that specify the whole process, so I've decided to write one.
Basically, there are many articles over the web that I've used to put all the pieces together, the most significant of them can be found here
Of course, I've also used FAT16 and FAT32 specifications found at Microsoft's website.
The address that returns from
FSCTL_GET_RETRIEVAL_POINTERS is returned in clusters (LCN - Logical Cluster Number), and is relative to the beginning of the data on the volume, so in order to get a physical offset, one needs to find the volume's starting offset and also find the data's starting offset inside the volume, which varies between partitions types. This article deals with FAT16, FAT32 and NTFS.
Calculating the size of a cluster on the volume
The LCN that is contained in the Extent structure that returns from
FSCTL_GET_RETRIEVAL_POINTERS is actually the number of clusters from the beginning of the volume's data. In order to convert it to bytes, we need to multiply it by
BytesPerCluster. In order to get the Cluster's size in bytes, we can call
GetDiskFreeSpace, which returns the number of bytes per sector and the number of sectors per cluster.
Calculating the data's starting offset in FAT16 and FAT32 file systems
The location of the first data sector in FAT file systems (which is also referred to as the second cluster) can be calculated in the following manner :
It is the number of Reserved Sectors + The number of FATs multiplied by Sectors per FAT + The number of
RootDirSectors. In other words:
FirstDataSector = ReservedSectors + (FATCount * SectorsPerFAT) + RootDirSectors
All of this information can be found directly at the boot sector, except
RootDirSectors, which is calculated in the following manner :
RootDirSectors = ((MaxRootEntries * 32) + (BytesPerSector - 1)) / BytesPerSector
Of course that, in order to get the offset in bytes (and not in sectors), we will multiply by
SectorSize (which also can be found at the boot sector, but is received from
GetDiskFreeSpace we called earlier).
What about NTFS ?
In NTFS, things are a lot more simple. There's an IOCTL which is called
IOCTL_VOLUME_LOGICAL_TO_PHYSICAL, which works fine with NTFS volumes. Simple, eh ??
Using the code
Unfortunately, the code runs on Windows XP and above, and in order to compile the code, you must have WIndows DDK installed on your machine (Because of
IOCTL_VOLUME_LOGICAL_TO_PHYSICAL, which is defined only in Windows DDK). Make sure you add the DDK's include directory to your project settings.
The code is extremely easy to understand, and is pretty commented.