source: bootcd/isolinux/syslinux-6.03/win/ntfssect.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 8.2 KB
RevLine 
[e16e8f2]1/* -------------------------------------------------------------------------- *
2 *
3 *   Copyright 2011 Shao Miller - All Rights Reserved
4 *
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.
10 *
11 * ------------------------------------------------------------------------- */
12
13/****
14 * ntfssect.c
15 *
16 * Fetch NTFS file cluster & sector information via Windows
17 *
18 * With special thanks to Mark Roddy for his article:
19 *   http://www.wd-3.com/archive/luserland.htm
20 */
21
22#include <windows.h>
23#include <winioctl.h>
24#include <stddef.h>
25#include <string.h>
26
27#include "ntfssect.h"
28
29/*** Macros */
30#define M_ERR(msg) (NtfsSectLastErrorMessage = (msg))
31
32/*** Function declarations */
33static DWORD NtfsSectGetVolumeHandle(
34    CHAR * VolumeName,
35    S_NTFSSECT_VOLINFO * VolumeInfo
36  );
37static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo);
38
39/*** Objects */
40CHAR * NtfsSectLastErrorMessage;
41
42/*** Function definitions */
43DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent(
44    HANDLE File,
45    LARGE_INTEGER * Vcn,
46    S_NTFSSECT_EXTENT * Extent
47  ) {
48    BOOL bad, ok;
49    DWORD output_size, rc;
50    STARTING_VCN_INPUT_BUFFER input;
51    RETRIEVAL_POINTERS_BUFFER output;
52
53    bad = (
54        File == INVALID_HANDLE_VALUE ||
55        !Vcn ||
56        Vcn->QuadPart < 0 ||
57        !Extent
58      );
59    if (bad)
60      return ERROR_INVALID_PARAMETER;
61
62    input.StartingVcn = *Vcn;
63    ok = DeviceIoControl(
64        File,
65        FSCTL_GET_RETRIEVAL_POINTERS,
66        &input,
67        sizeof input,
68        &output,
69        sizeof output,
70        &output_size,
71        NULL
72      );
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;
81
82        case ERROR_HANDLE_EOF:
83          break;
84
85        default:
86          M_ERR("NtfsSectGetFileVcnExtent(): Unknown status!");
87      }
88
89    return rc;
90  }
91
92/* Internal use only */
93static 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;
102
103    /* Prefix "\\.\" onto the passed volume name */
104    strcpy(volname + sizeof M_VOL_PREFIX - 1, VolumeName);
105
106    /* Find the last non-null character */
107    for (c = volname_short; *c; ++c)
108      ;
109
110    /* Remove trailing back-slash */
111    if (c[-1] == '\\')
112      c[-1] = 0;
113
114    /* Open the volume */
115    VolumeInfo->Handle = CreateFile(
116        volname,
117        GENERIC_READ,
118        FILE_SHARE_READ | FILE_SHARE_WRITE,
119        NULL,
120        OPEN_EXISTING,
121        0,
122        NULL
123      );
124    rc = GetLastError();
125    if (VolumeInfo->Handle == INVALID_HANDLE_VALUE) {
126        M_ERR("Unable to open volume handle!");
127        goto err_handle;
128      }
129
130    return ERROR_SUCCESS;
131
132    CloseHandle(VolumeInfo->Handle);
133    err_handle:
134
135    return rc;
136  }
137
138DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo(
139    CHAR * VolumeName,
140    S_NTFSSECT_VOLINFO * VolumeInfo
141  ) {
142    S_NTFSSECT_XPFUNCS xp_funcs;
143    DWORD rc, free_clusts, total_clusts;
144    BOOL ok;
145
146    if (!VolumeName || !VolumeInfo)
147      return ERROR_INVALID_PARAMETER;
148
149    rc = NtfsSectGetVolumeHandle(VolumeName, VolumeInfo);
150    if (rc != ERROR_SUCCESS)
151      goto err_handle;
152
153    rc = NtfsSectLoadXpFuncs(&xp_funcs);
154    if (rc != ERROR_SUCCESS)
155      goto err_xp_funcs;
156
157    ok = xp_funcs.GetDiskFreeSpace(
158        VolumeName,
159        &VolumeInfo->SectorsPerCluster,
160        &VolumeInfo->BytesPerSector,
161        &free_clusts,
162        &total_clusts
163      );
164    rc = GetLastError();
165    if (!ok) {
166        M_ERR("GetDiskFreeSpace() failed!");
167        goto err_freespace;
168      }
169
170    rc = NtfsSectGetVolumePartitionLba(VolumeInfo);
171    if (rc != ERROR_SUCCESS)
172      goto err_lba;
173
174    VolumeInfo->Size = sizeof *VolumeInfo;
175    rc = ERROR_SUCCESS;
176
177    err_lba:
178
179    err_freespace:
180
181    NtfsSectUnloadXpFuncs(&xp_funcs);
182    err_xp_funcs:
183
184    if (rc != ERROR_SUCCESS) {
185        CloseHandle(VolumeInfo->Handle);
186        VolumeInfo->Handle = INVALID_HANDLE_VALUE;
187      }
188    err_handle:
189
190    return rc;
191  }
192
193DWORD M_NTFSSECT_API NtfsSectGetVolumeInfoFromFileName(
194    CHAR * FileName,
195    S_NTFSSECT_VOLINFO * VolumeInfo
196  ) {
197    S_NTFSSECT_XPFUNCS xp_funcs;
198    DWORD rc;
199    CHAR volname[MAX_PATH + 1];
200    BOOL ok;
201
202    if (!FileName || !VolumeInfo)
203      return ERROR_INVALID_PARAMETER;
204
205    rc = NtfsSectLoadXpFuncs(&xp_funcs);
206    if (rc != ERROR_SUCCESS) {
207        goto err_xp_funcs;
208      }
209
210    ok = xp_funcs.GetVolumePathName(
211        FileName,
212        volname,
213        sizeof volname
214      );
215    rc = GetLastError();
216    if (!ok) {
217        M_ERR("GetVolumePathName() failed!");
218        goto err_volname;
219      }
220
221    rc = NtfsSectGetVolumeInfo(volname, VolumeInfo);
222
223    err_volname:
224
225    NtfsSectUnloadXpFuncs(&xp_funcs);
226    err_xp_funcs:
227
228    return rc;
229  }
230
231/* Internal use only */
232static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo) {
233    BOOL ok;
234    VOLUME_DISK_EXTENTS vol_disk_extents;
235    DWORD output_size, rc;
236
237    ok = DeviceIoControl(
238        VolumeInfo->Handle,
239        IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
240        NULL,
241        0,
242        &vol_disk_extents,
243        sizeof vol_disk_extents,
244        &output_size,
245        NULL
246      );
247    rc = GetLastError();
248    if (!ok) {
249        M_ERR("Couldn't fetch volume disk extent(s)!");
250        goto err_vol_disk_extents;
251      }
252
253    if (vol_disk_extents.NumberOfDiskExtents != 1) {
254        M_ERR("Unsupported number of volume disk extents!");
255        goto err_num_of_extents;
256      }
257
258    VolumeInfo->PartitionLba.QuadPart = (
259        vol_disk_extents.Extents[0].StartingOffset.QuadPart /
260        VolumeInfo->BytesPerSector
261      );
262
263    return ERROR_SUCCESS;
264
265    err_num_of_extents:
266
267    err_vol_disk_extents:
268
269    return rc;
270  }
271
272DWORD M_NTFSSECT_API NtfsSectLcnToLba(
273    const S_NTFSSECT_VOLINFO * VolumeInfo,
274    const LARGE_INTEGER * Lcn,
275    LARGE_INTEGER * Lba
276  ) {
277    BOOL bad;
278    bad = (
279        !VolumeInfo ||
280        !VolumeInfo->BytesPerSector ||
281        !VolumeInfo->SectorsPerCluster ||
282        !Lcn ||
283        Lcn->QuadPart < 0 ||
284        !Lba
285      );
286    if (bad)
287      return ERROR_INVALID_PARAMETER;
288
289    Lba->QuadPart = (
290        VolumeInfo->PartitionLba.QuadPart +
291        Lcn->QuadPart *
292        VolumeInfo->SectorsPerCluster
293      );
294    return ERROR_SUCCESS;
295  }
296
297DWORD M_NTFSSECT_API NtfsSectLoadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
298    DWORD rc;
299
300    if (!XpFuncs)
301      return ERROR_INVALID_PARAMETER;
302
303    XpFuncs->Size = sizeof *XpFuncs;
304
305    XpFuncs->Kernel32 = LoadLibrary("kernel32.dll");
306    rc = GetLastError();
307    if (!XpFuncs->Kernel32) {
308        M_ERR("KERNEL32.DLL not found!");
309        goto err;
310      }
311
312    XpFuncs->GetVolumePathName = (F_KERNEL32_GETVOLUMEPATHNAME *) (
313        GetProcAddress(
314            XpFuncs->Kernel32,
315            "GetVolumePathNameA"
316          )
317      );
318    rc = GetLastError();
319    if (!XpFuncs->GetVolumePathName) {
320        M_ERR("GetVolumePathName() not found in KERNEL32.DLL!");
321        goto err;
322      }
323
324    XpFuncs->GetDiskFreeSpace = (F_KERNEL32_GETDISKFREESPACE *) (
325        GetProcAddress(
326            XpFuncs->Kernel32,
327            "GetDiskFreeSpaceA"
328          )
329      );
330    rc = GetLastError();
331    if (!XpFuncs->GetDiskFreeSpace) {
332        M_ERR("GetDiskFreeSpace() not found in KERNEL32.DLL!");
333        goto err;
334      }
335
336    return ERROR_SUCCESS;
337
338    err:
339    NtfsSectUnloadXpFuncs(XpFuncs);
340    return rc;
341  }
342
343VOID M_NTFSSECT_API NtfsSectUnloadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
344    if (!XpFuncs)
345      return;
346
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;
354  }
355
Note: See TracBrowser for help on using the repository browser.