1 /* -------------------------------------------------------------------------- *
3 * Copyright 2011 Shao Miller - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ------------------------------------------------------------------------- */
16 * Fetch NTFS file cluster & sector information via Windows
18 * With special thanks to Mark Roddy for his article:
19 * http://www.wd-3.com/archive/luserland.htm
30 #define M_ERR(msg) (NtfsSectLastErrorMessage = (msg))
32 /*** Function declarations */
33 static DWORD NtfsSectGetVolumeHandle(
35 S_NTFSSECT_VOLINFO * VolumeInfo
37 static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo);
40 CHAR * NtfsSectLastErrorMessage;
42 /*** Function definitions */
43 DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent(
46 S_NTFSSECT_EXTENT * Extent
49 DWORD output_size, rc;
50 STARTING_VCN_INPUT_BUFFER input;
51 RETRIEVAL_POINTERS_BUFFER output;
54 File == INVALID_HANDLE_VALUE ||
60 return ERROR_INVALID_PARAMETER;
62 input.StartingVcn = *Vcn;
65 FSCTL_GET_RETRIEVAL_POINTERS,
77 Extent->FirstVcn = output.StartingVcn;
78 Extent->NextVcn = output.Extents[0].NextVcn;
79 Extent->FirstLcn = output.Extents[0].Lcn;
82 case ERROR_HANDLE_EOF:
86 M_ERR("NtfsSectGetFileVcnExtent(): Unknown status!");
92 /* Internal use only */
93 static DWORD NtfsSectGetVolumeHandle(
95 S_NTFSSECT_VOLINFO * VolumeInfo
97 #define M_VOL_PREFIX "\\\\.\\"
98 CHAR volname[sizeof M_VOL_PREFIX - 1 + MAX_PATH + 1] = M_VOL_PREFIX;
99 CHAR * const volname_short = volname + sizeof M_VOL_PREFIX - 1;
103 /* Prefix "\\.\" onto the passed volume name */
104 strcpy(volname + sizeof M_VOL_PREFIX - 1, VolumeName);
106 /* Find the last non-null character */
107 for (c = volname_short; *c; ++c)
110 /* Remove trailing back-slash */
114 /* Open the volume */
115 VolumeInfo->Handle = CreateFile(
118 FILE_SHARE_READ | FILE_SHARE_WRITE,
125 if (VolumeInfo->Handle == INVALID_HANDLE_VALUE) {
126 M_ERR("Unable to open volume handle!");
130 return ERROR_SUCCESS;
132 CloseHandle(VolumeInfo->Handle);
138 DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo(
140 S_NTFSSECT_VOLINFO * VolumeInfo
142 S_NTFSSECT_XPFUNCS xp_funcs;
143 DWORD rc, free_clusts, total_clusts;
146 if (!VolumeName || !VolumeInfo)
147 return ERROR_INVALID_PARAMETER;
149 rc = NtfsSectGetVolumeHandle(VolumeName, VolumeInfo);
150 if (rc != ERROR_SUCCESS)
153 rc = NtfsSectLoadXpFuncs(&xp_funcs);
154 if (rc != ERROR_SUCCESS)
157 ok = xp_funcs.GetDiskFreeSpace(
159 &VolumeInfo->SectorsPerCluster,
160 &VolumeInfo->BytesPerSector,
166 M_ERR("GetDiskFreeSpace() failed!");
170 rc = NtfsSectGetVolumePartitionLba(VolumeInfo);
171 if (rc != ERROR_SUCCESS)
174 VolumeInfo->Size = sizeof *VolumeInfo;
181 NtfsSectUnloadXpFuncs(&xp_funcs);
184 if (rc != ERROR_SUCCESS) {
185 CloseHandle(VolumeInfo->Handle);
186 VolumeInfo->Handle = INVALID_HANDLE_VALUE;
193 DWORD M_NTFSSECT_API NtfsSectGetVolumeInfoFromFileName(
195 S_NTFSSECT_VOLINFO * VolumeInfo
197 S_NTFSSECT_XPFUNCS xp_funcs;
199 CHAR volname[MAX_PATH + 1];
202 if (!FileName || !VolumeInfo)
203 return ERROR_INVALID_PARAMETER;
205 rc = NtfsSectLoadXpFuncs(&xp_funcs);
206 if (rc != ERROR_SUCCESS) {
210 ok = xp_funcs.GetVolumePathName(
217 M_ERR("GetVolumePathName() failed!");
221 rc = NtfsSectGetVolumeInfo(volname, VolumeInfo);
225 NtfsSectUnloadXpFuncs(&xp_funcs);
231 /* Internal use only */
232 static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo) {
234 VOLUME_DISK_EXTENTS vol_disk_extents;
235 DWORD output_size, rc;
237 ok = DeviceIoControl(
239 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
243 sizeof vol_disk_extents,
249 M_ERR("Couldn't fetch volume disk extent(s)!");
250 goto err_vol_disk_extents;
253 if (vol_disk_extents.NumberOfDiskExtents != 1) {
254 M_ERR("Unsupported number of volume disk extents!");
255 goto err_num_of_extents;
258 VolumeInfo->PartitionLba.QuadPart = (
259 vol_disk_extents.Extents[0].StartingOffset.QuadPart /
260 VolumeInfo->BytesPerSector
263 return ERROR_SUCCESS;
267 err_vol_disk_extents:
272 DWORD M_NTFSSECT_API NtfsSectLcnToLba(
273 const S_NTFSSECT_VOLINFO * VolumeInfo,
274 const LARGE_INTEGER * Lcn,
280 !VolumeInfo->BytesPerSector ||
281 !VolumeInfo->SectorsPerCluster ||
287 return ERROR_INVALID_PARAMETER;
290 VolumeInfo->PartitionLba.QuadPart +
292 VolumeInfo->SectorsPerCluster
294 return ERROR_SUCCESS;
297 DWORD M_NTFSSECT_API NtfsSectLoadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
301 return ERROR_INVALID_PARAMETER;
303 XpFuncs->Size = sizeof *XpFuncs;
305 XpFuncs->Kernel32 = LoadLibrary("kernel32.dll");
307 if (!XpFuncs->Kernel32) {
308 M_ERR("KERNEL32.DLL not found!");
312 XpFuncs->GetVolumePathName = (F_KERNEL32_GETVOLUMEPATHNAME *) (
319 if (!XpFuncs->GetVolumePathName) {
320 M_ERR("GetVolumePathName() not found in KERNEL32.DLL!");
324 XpFuncs->GetDiskFreeSpace = (F_KERNEL32_GETDISKFREESPACE *) (
331 if (!XpFuncs->GetDiskFreeSpace) {
332 M_ERR("GetDiskFreeSpace() not found in KERNEL32.DLL!");
336 return ERROR_SUCCESS;
339 NtfsSectUnloadXpFuncs(XpFuncs);
343 VOID M_NTFSSECT_API NtfsSectUnloadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
347 XpFuncs->GetDiskFreeSpace = NULL;
348 XpFuncs->GetVolumePathName = NULL;
349 if (XpFuncs->Kernel32)
350 FreeLibrary(XpFuncs->Kernel32);
351 XpFuncs->Kernel32 = NULL;