SHARE
Facebook X Pinterest WhatsApp

Determining Cluster Size

Occasionally, your program may need more low-level information about the computer it’s running on than is readily available with MFC. Usually, this can be solved by a simple API call, which, with a small amount of practice and patience, can become as easy to deal with as MFC. This appears to be the case with […]

Written By
thumbnail
CodeGuru Staff
CodeGuru Staff
Sep 12, 1998
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Occasionally, your program may need more low-level information about the computer it’s running
on than is readily available with MFC. Usually, this can be solved by a simple API call, which, with
a small amount of practice and patience, can become as easy to deal with as MFC. This appears to be
the case with determining the cluster size of a local hard disk. As you may know, hard drives are
divided up into partitions, which can be in either the FAT16 or FAT32 format on a Windows/DOS machine.
(There are more, including those used by Windows NT and other operating systems) Files in the partition
are stored in clusters, which are a set size depending on the type (16 or 32) and the size of the partition.
The number of clusters a file uses can be figured using this formula: File Size / Cluster Size, rounded
up.
For example, a 20,000 byte file on a partition with 4,096 byte clusters would use 5 clusters becuase
20000 / 4096 = 4.8, rounded = 5.

Problem


As mentioned earlier, it would seem that getting the cluster size under Windows95/98 is an easy task. The


Win32 API provides the ::GetDiskFreeSpace() function, which returns the cluster size of the drive you pass


to it, along with other information about it.

However,

things aren

t that simple when you


start dealing with newer hardware. As of Windows95 OSR2, there is a new partition format available, called


FAT32. FAT32 breaks FAT16

s 2GB partition size limit, which makes it particularly useful for today

s high


capacity drives. However, the ::GetDiskFreeSpace() function does not return correct values for partitions


larger than 2GB. There is a replacement function provided in the KERNEL32.DLL included with OSR2+


(including Windows98) called ::GetDiskFreeSpaceEx(). However, this function was made to simplify getting


disk space values and no longer returns cluster size as one of its parameters. So begins the ponderence of


how to get the cluster size on drives larger than 2GB.

Solution


Unfortunately, there is no other API function to deal with the disk like this. Instead, you must delve deeper


into the operating system to find the answer. Hidden in the volumes of documentation with Developer Studio is


a list of new FAT32 functions. But these are not functions like you

re used to seeing, unless you are an


experienced Assembly language programmer. The specific function we will make use of is

Int 21h Function
7303h Get_ExtFreeSpace (FAT32)

which you can lookup in Developer Studio. This is an interrupt call


to the operating system that returns a structure containing lots of information about the disk, including


cluster size. But implementing this function is not what you might call a simple task. Rather, you need


to make a few definitions, and then do some rather low-level messing around. But, because you are reading this


it obviously means I have gone through this work for you, and you get this function wrapped up in a nice class


and member function. But if you would like to know more about it, read on. If not, skip to the end and download!



First, you need a few defintions to work with. Part of making an Int 21 call invloves setting some CPU
registers explicitly, so we need a structure to work with. Although it would seem these structures *should*
be defined somewhere, I could not find them, so I put them in the .H file. The following allows us to
work with all the applicable registers:

typedef struct _DIOC_REGISTERS
{
	DWORD reg_EBX;
	DWORD reg_EDX;
	DWORD reg_ECX;
	DWORD reg_EAX;
	DWORD reg_EDI;
	DWORD reg_ESI;
	DWORD reg_Flags;
} DIOC_REGISTERS, *PDIOC_REGISTERS;

Next, we need to define the strucure the function will return the data to use in. It needs to be packed
on 1 byte boundaries, and we also define the DeviceIoControl (more on this later) parameter constant which
again, was *supposed* to be defined already.

#pragma pack(1)
typedef struct _ExtGetDskFreSpcStruc
{
	WORD ExtFree_Size;
	WORD ExtFree_Level;
	DWORD ExtFree_SectorsPerCluster;
	DWORD ExtFree_BytesPerSector;
	DWORD ExtFree_AvailableClusters;
	DWORD ExtFree_TotalClusters;
	DWORD ExtFree_AvailablePhysSectors;
	DWORD ExtFree_TotalPhysSectors;
	DWORD ExtFree_AvailableAllocationUnits;
	DWORD ExtFree_TotalAllocationUnits;
	DWORD ExtFree_Rsvd[2];
} ExtGetDskFreSpcStruc, *pExtGetDskFreSpcStruc;
#pragma pack()

Thats it for definitions. Now the implementation. One of the first things to do is decide if we even need
to use the Int 21 function. If this is NOT an OSR2+ machine, we can still use the ::GetDiskFreeSpace() function,
and save some work. The following checks the OS version and sets the flag for OSR2.

os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&os);
if(os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
	if(LOWORD(os.dwBuildNumber) > 1000)		// is it OSR2 or newer?
		OSR2 = true;
}

Now, if it turns out that this IS an OSR2+ machine, we have to use the Int 21 function. To do this, first
you have to create a device handle to the VWIN32 device, which basically makes all this possible. It creates
a sort of virtual machine that these calls can be made though, behaving much more like a DOS environment
than Windows. Once that device is created, you initialize the registers structure to tell it exactly what to
do and where to put the data. The EAX member is like using the AX register, so the actual function number
gets put in there (0x7303). Setting the structure does not change the CPU registers though. This happens
once DeviceIoControl() is called. What DeviceIoControl() does is perform the Interrupt operation after copying our
registers structure. It then takes the state of the CPU registers AFTER the call, and returns them in the
same structure.

HANDLE hDevice;
DIOC_REGISTERS reg;
ExtGetDskFreSpcStruc spc;
BOOL bResult;
DWORD cb;

const char *sz[] = { (LPCTSTR) m_strDrive };
spc.ExtFree_Level = 0;  //Must initialize before using the structure
hDevice = CreateFile("\\.\vwin32",0,0,NULL,0,FILE_FLAG_DELETE_ON_CLOSE,NULL);

// initialize the registers to call the correct function
reg.reg_EDI = (DWORD)&spc;
reg.reg_ECX = sizeof(ExtGetDskFreSpcStruc);
reg.reg_EDX = (DWORD)(LPCTSTR)m_strDrive;
reg.reg_EAX = 0x7303;
reg.reg_Flags = 0x0001;

// copies the structure into the registers, performs the function,
// and returns the new registers in the structure
bResult = DeviceIoControl(hDevice, VWIN32_DIOC_DOS_DRIVEINFO,
	®, sizeof(reg), ®, sizeof(reg), &cb, 0);
CloseHandle(hDevice);

More important than the new register states, is if the operation went correctly, our ExtGetDskFreSpcStruc should
be filled with correct values. All that’s left to do if find the cluster size by multiplying the Sectors Per
Cluster
by the Bytes per Sector. (Of course, they couldn’t even make THAT easy on us)

Conclusion


That

s about it for getting the cluster size.

However, I DID leave out some code on this page. In order
to use this, you SHOULD download the full code (come on, it’s only 2 files).

There is also a simply sample


application that shows an easy way of implementing this using the class I created, CClusterSize. To use this


in your project, simply add

ClusterSize.h

and

ClusterSize.cpp

to your project, include the .H file appropriately,


use either the 1 or 2 step initialization (see the header file), and call GetClusterSize().

Download demo project – 13 KB

Download source – 4 KB

Recommended for you...

How To Make Windows 11 Faster
Enrique Stone
Nov 30, 2022
Working with the Windows Registry in C#
Joydip Kanjilal
Jun 17, 2022
Using Multiple Programming Languages to Create an ASP.NET Website
Tariq Siddiqui
Jun 11, 2022
Finding a Microsoft Office version with .NET
Hannes DuPreez
May 20, 2022
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.