dmi: check both the AC and ID flags at the same time
[syslinux.git] / win / ntfssect.c
blob3dd6d7f0fe935ea85baa46b6b8f61141846b0766
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 * ------------------------------------------------------------------------- */
13 /****
14 * ntfssect.c
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
22 #include <windows.h>
23 #include <winioctl.h>
24 #include <stddef.h>
25 #include <string.h>
27 #include "ntfssect.h"
29 /*** Macros */
30 #define M_ERR(msg) (NtfsSectLastErrorMessage = (msg))
32 /*** Function declarations */
33 static DWORD NtfsSectGetVolumeHandle(
34 CHAR * VolumeName,
35 S_NTFSSECT_VOLINFO * VolumeInfo
37 static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo);
39 /*** Objects */
40 CHAR * NtfsSectLastErrorMessage;
42 /*** Function definitions */
43 DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent(
44 HANDLE File,
45 LARGE_INTEGER * Vcn,
46 S_NTFSSECT_EXTENT * Extent
47 ) {
48 BOOL bad;
49 DWORD output_size, rc;
50 STARTING_VCN_INPUT_BUFFER input;
51 RETRIEVAL_POINTERS_BUFFER output;
53 bad = (
54 File == INVALID_HANDLE_VALUE ||
55 !Vcn ||
56 Vcn->QuadPart < 0 ||
57 !Extent
59 if (bad)
60 return ERROR_INVALID_PARAMETER;
62 input.StartingVcn = *Vcn;
63 DeviceIoControl(
64 File,
65 FSCTL_GET_RETRIEVAL_POINTERS,
66 &input,
67 sizeof input,
68 &output,
69 sizeof output,
70 &output_size,
71 NULL
73 rc = GetLastError();
74 switch (rc) {
75 case NO_ERROR:
76 case ERROR_MORE_DATA:
77 Extent->FirstVcn = output.StartingVcn;
78 Extent->NextVcn = output.Extents[0].NextVcn;
79 Extent->FirstLcn = output.Extents[0].Lcn;
80 return ERROR_SUCCESS;
82 case ERROR_HANDLE_EOF:
83 break;
85 default:
86 M_ERR("NtfsSectGetFileVcnExtent(): Unknown status!");
89 return rc;
92 /* Internal use only */
93 static DWORD NtfsSectGetVolumeHandle(
94 CHAR * VolumeName,
95 S_NTFSSECT_VOLINFO * VolumeInfo
96 ) {
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;
100 CHAR * c;
101 DWORD rc;
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 */
111 if (c[-1] == '\\')
112 c[-1] = 0;
114 /* Open the volume */
115 VolumeInfo->Handle = CreateFileA(
116 volname,
117 GENERIC_READ,
118 FILE_SHARE_READ | FILE_SHARE_WRITE,
119 NULL,
120 OPEN_EXISTING,
122 NULL
124 rc = GetLastError();
125 if (VolumeInfo->Handle == INVALID_HANDLE_VALUE) {
126 M_ERR("Unable to open volume handle!");
127 goto err_handle;
130 return ERROR_SUCCESS;
132 CloseHandle(VolumeInfo->Handle);
133 err_handle:
135 return rc;
138 DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo(
139 CHAR * VolumeName,
140 S_NTFSSECT_VOLINFO * VolumeInfo
142 S_NTFSSECT_XPFUNCS xp_funcs;
143 DWORD rc, free_clusts, total_clusts;
144 BOOL ok;
146 if (!VolumeName || !VolumeInfo)
147 return ERROR_INVALID_PARAMETER;
149 rc = NtfsSectGetVolumeHandle(VolumeName, VolumeInfo);
150 if (rc != ERROR_SUCCESS)
151 goto err_handle;
153 rc = NtfsSectLoadXpFuncs(&xp_funcs);
154 if (rc != ERROR_SUCCESS)
155 goto err_xp_funcs;
157 ok = xp_funcs.GetDiskFreeSpace(
158 VolumeName,
159 &VolumeInfo->SectorsPerCluster,
160 &VolumeInfo->BytesPerSector,
161 &free_clusts,
162 &total_clusts
164 rc = GetLastError();
165 if (!ok) {
166 M_ERR("GetDiskFreeSpace() failed!");
167 goto err_freespace;
170 rc = NtfsSectGetVolumePartitionLba(VolumeInfo);
171 if (rc != ERROR_SUCCESS)
172 goto err_lba;
174 VolumeInfo->Size = sizeof *VolumeInfo;
175 rc = ERROR_SUCCESS;
177 err_lba:
179 err_freespace:
181 NtfsSectUnloadXpFuncs(&xp_funcs);
182 err_xp_funcs:
184 if (rc != ERROR_SUCCESS) {
185 CloseHandle(VolumeInfo->Handle);
186 VolumeInfo->Handle = INVALID_HANDLE_VALUE;
188 err_handle:
190 return rc;
193 DWORD M_NTFSSECT_API NtfsSectGetVolumeInfoFromFileName(
194 CHAR * FileName,
195 S_NTFSSECT_VOLINFO * VolumeInfo
197 S_NTFSSECT_XPFUNCS xp_funcs;
198 DWORD rc;
199 CHAR volname[MAX_PATH + 1];
200 BOOL ok;
202 if (!FileName || !VolumeInfo)
203 return ERROR_INVALID_PARAMETER;
205 rc = NtfsSectLoadXpFuncs(&xp_funcs);
206 if (rc != ERROR_SUCCESS) {
207 goto err_xp_funcs;
210 ok = xp_funcs.GetVolumePathName(
211 FileName,
212 volname,
213 sizeof volname
215 rc = GetLastError();
216 if (!ok) {
217 M_ERR("GetVolumePathName() failed!");
218 goto err_volname;
221 rc = NtfsSectGetVolumeInfo(volname, VolumeInfo);
223 err_volname:
225 NtfsSectUnloadXpFuncs(&xp_funcs);
226 err_xp_funcs:
228 return rc;
231 /* Internal use only */
232 static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo) {
233 BOOL ok;
234 VOLUME_DISK_EXTENTS vol_disk_extents;
235 DWORD output_size, rc;
237 ok = DeviceIoControl(
238 VolumeInfo->Handle,
239 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
240 NULL,
242 &vol_disk_extents,
243 sizeof vol_disk_extents,
244 &output_size,
245 NULL
247 rc = GetLastError();
248 if (!ok) {
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;
265 err_num_of_extents:
267 err_vol_disk_extents:
269 return rc;
272 DWORD M_NTFSSECT_API NtfsSectLcnToLba(
273 const S_NTFSSECT_VOLINFO * VolumeInfo,
274 const LARGE_INTEGER * Lcn,
275 LARGE_INTEGER * Lba
277 BOOL bad;
278 bad = (
279 !VolumeInfo ||
280 !VolumeInfo->BytesPerSector ||
281 !VolumeInfo->SectorsPerCluster ||
282 !Lcn ||
283 Lcn->QuadPart < 0 ||
284 !Lba
286 if (bad)
287 return ERROR_INVALID_PARAMETER;
289 Lba->QuadPart = (
290 VolumeInfo->PartitionLba.QuadPart +
291 Lcn->QuadPart *
292 VolumeInfo->SectorsPerCluster
294 return ERROR_SUCCESS;
297 DWORD M_NTFSSECT_API NtfsSectLoadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
298 DWORD rc;
300 if (!XpFuncs)
301 return ERROR_INVALID_PARAMETER;
303 XpFuncs->Size = sizeof *XpFuncs;
305 XpFuncs->Kernel32 = LoadLibraryA("kernel32.dll");
306 rc = GetLastError();
307 if (!XpFuncs->Kernel32) {
308 M_ERR("KERNEL32.DLL not found!");
309 goto err;
312 XpFuncs->GetVolumePathName = (F_KERNEL32_GETVOLUMEPATHNAME *) (
313 GetProcAddress(
314 XpFuncs->Kernel32,
315 "GetVolumePathNameA"
318 rc = GetLastError();
319 if (!XpFuncs->GetVolumePathName) {
320 M_ERR("GetVolumePathName() not found in KERNEL32.DLL!");
321 goto err;
324 XpFuncs->GetDiskFreeSpace = (F_KERNEL32_GETDISKFREESPACE *) (
325 GetProcAddress(
326 XpFuncs->Kernel32,
327 "GetDiskFreeSpaceA"
330 rc = GetLastError();
331 if (!XpFuncs->GetDiskFreeSpace) {
332 M_ERR("GetDiskFreeSpace() not found in KERNEL32.DLL!");
333 goto err;
336 return ERROR_SUCCESS;
338 err:
339 NtfsSectUnloadXpFuncs(XpFuncs);
340 return rc;
343 VOID M_NTFSSECT_API NtfsSectUnloadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
344 if (!XpFuncs)
345 return;
347 XpFuncs->GetDiskFreeSpace = NULL;
348 XpFuncs->GetVolumePathName = NULL;
349 if (XpFuncs->Kernel32)
350 FreeLibrary(XpFuncs->Kernel32);
351 XpFuncs->Kernel32 = NULL;
352 XpFuncs->Size = 0;
353 return;