Click here to Skip to main content
15,879,348 members
Articles / Desktop Programming / MFC
Article

Translating logical offsets into physical offsets

Rate me:
Please Sign up or sign in to vote.
4.62/5 (13 votes)
11 Apr 20052 min read 57.3K   1K   27   7
An article explaining how to convert logical offsets returned by FSCTL_GET_FILE_RETRIEVAL_POINTERS to physical offsets from the beginning of the disk.

Introduction

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.

Background

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.

Basic Concepts

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Israel Israel
Omri started programming 8 years ago, worked a lot in B2B systems (Microsoft BizTalk Server), and spent the last 2 years developing UI for several small companies in Israel.

Comments and Discussions

 
QuestionHow to use memset, memcpy C++ function when build with 64bit platform? Pin
DQDAT23-Dec-08 23:36
DQDAT23-Dec-08 23:36 
Generalcapture file access events Pin
W M Suleiman30-Jan-06 8:11
W M Suleiman30-Jan-06 8:11 
GeneralBeware to use this code with non-trivial disks Pin
Valery A. Boronin31-May-05 8:13
Valery A. Boronin31-May-05 8:13 
GeneralRe: Beware to use this code with non-trivial disks Pin
Omri Shaked31-May-05 20:52
Omri Shaked31-May-05 20:52 
GeneralAn Easier Way Pin
NickSills23-May-05 5:40
NickSills23-May-05 5:40 
Hi
There is an easier way that appears to work for all file systems. Basicaly, the cluster map is alligned on the last disk sector of the partition.

// The following code should work for NTFS, FAT32.....
static char	volumeName[] = "C:\\";<br />
GetDiskFreeSpace(volumeName, &SectorsPerCluster, &BytesPerSector,,&NumberOfFreeClusters, &TotalNumberOfClusters);<br />
<br />
DWORD dwClusterSize = SectorsPerCluster * BytesPerSector;<br />
<br />
HANDLE hFile = CreateFile("\\\\.\\C:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);<br />
<br />
PARTITION_INFORMATION_EX pinfo;  <br />
<br />
DeviceIoControl(hFile, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &pinfo, sizeof(PARTITION_INFORMATION_EX), &dw,NULL));<br />
<br />
BITMAP_DESCRIPTOR bitMap;<br />
LARGE_INTEGER li1; li1.QuadPart = 0;<br />
NtFsControlFile( hFile, NULL, NULL, 0, &ioStatus,FSCTL_GET_VOLUME_BITMAP, &li1.QuadPart, sizeof( ULONGLONG),&bitMap, sizeof(BITMAP_DESCRIPTOR) );<br />
<br />
LARGE_INTEGER liDiff, liFirstClusterPos;<br />
liDiff.QuadPart = pinfo.PartitionLength.QuadPart -  ((_int64)Bitmap.ClustersToEndOfVol * (_int64)dwClusterSize); <br />
DWORD dwDiff = (DWORD)((_int64)liDiff.QuadPart / (_int64)dwClusterSize);<br />
liDiff.QuadPart = (_int64)dwDiff * (_int64)dwClusterSize;

// Here is the exact position of the 1st cluster on the disk
liFirstClusterPos.QuadPart = pinfo.StartingOffset.QuadPart + liDiff.QuadPart;

GeneralRe: An Easier Way Pin
Armen Hakobyan1-Sep-08 4:45
professionalArmen Hakobyan1-Sep-08 4:45 
GeneralRe: An Easier Way Pin
Armen Hakobyan26-Sep-08 2:06
professionalArmen Hakobyan26-Sep-08 2:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.