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
;