summaryrefslogtreecommitdiff
path: root/win
diff options
context:
space:
mode:
Diffstat (limited to 'win')
-rw-r--r--win/ntfssect.c355
-rw-r--r--win/ntfssect.h152
-rw-r--r--win/ntfstest.c163
-rw-r--r--win/ntfstest.rc26
-rw-r--r--win/syslinux.c56
5 files changed, 743 insertions, 9 deletions
diff --git a/win/ntfssect.c b/win/ntfssect.c
new file mode 100644
index 00000000..8c2bccaa
--- /dev/null
+++ b/win/ntfssect.c
@@ -0,0 +1,355 @@
+/* -------------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Shao Miller - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+/****
+ * ntfssect.c
+ *
+ * Fetch NTFS file cluster & sector information via Windows
+ *
+ * With special thanks to Mark Roddy for his article:
+ * http://www.wd-3.com/archive/luserland.htm
+ */
+
+#include <windows.h>
+#include <winioctl.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "ntfssect.h"
+
+/*** Macros */
+#define M_ERR(msg) (NtfsSectLastErrorMessage = (msg))
+
+/*** Function declarations */
+static DWORD NtfsSectGetVolumeHandle(
+ CHAR * VolumeName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ );
+static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo);
+
+/*** Objects */
+CHAR * NtfsSectLastErrorMessage;
+
+/*** Function definitions */
+DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent(
+ HANDLE File,
+ LARGE_INTEGER * Vcn,
+ S_NTFSSECT_EXTENT * Extent
+ ) {
+ BOOL bad, ok;
+ DWORD output_size, rc;
+ STARTING_VCN_INPUT_BUFFER input;
+ RETRIEVAL_POINTERS_BUFFER output;
+
+ bad = (
+ File == INVALID_HANDLE_VALUE ||
+ !Vcn ||
+ Vcn->QuadPart < 0 ||
+ !Extent
+ );
+ if (bad)
+ return ERROR_INVALID_PARAMETER;
+
+ input.StartingVcn = *Vcn;
+ ok = DeviceIoControl(
+ File,
+ FSCTL_GET_RETRIEVAL_POINTERS,
+ &input,
+ sizeof input,
+ &output,
+ sizeof output,
+ &output_size,
+ NULL
+ );
+ rc = GetLastError();
+ switch (rc) {
+ case NO_ERROR:
+ case ERROR_MORE_DATA:
+ Extent->FirstVcn = output.StartingVcn;
+ Extent->NextVcn = output.Extents[0].NextVcn;
+ Extent->FirstLcn = output.Extents[0].Lcn;
+ return ERROR_SUCCESS;
+
+ case ERROR_HANDLE_EOF:
+ break;
+
+ default:
+ M_ERR("NtfsSectGetFileVcnExtent(): Unknown status!");
+ }
+
+ return rc;
+ }
+
+/* Internal use only */
+static DWORD NtfsSectGetVolumeHandle(
+ CHAR * VolumeName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ ) {
+ #define M_VOL_PREFIX "\\\\.\\"
+ CHAR volname[sizeof M_VOL_PREFIX - 1 + MAX_PATH + 1] = M_VOL_PREFIX;
+ CHAR * const volname_short = volname + sizeof M_VOL_PREFIX - 1;
+ CHAR * c;
+ DWORD rc;
+
+ /* Prefix "\\.\" onto the passed volume name */
+ strcpy(volname + sizeof M_VOL_PREFIX - 1, VolumeName);
+
+ /* Find the last non-null character */
+ for (c = volname_short; *c; ++c)
+ ;
+
+ /* Remove trailing back-slash */
+ if (c[-1] == '\\')
+ c[-1] = 0;
+
+ /* Open the volume */
+ VolumeInfo->Handle = CreateFile(
+ volname,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+ rc = GetLastError();
+ if (VolumeInfo->Handle == INVALID_HANDLE_VALUE) {
+ M_ERR("Unable to open volume handle!");
+ goto err_handle;
+ }
+
+ return ERROR_SUCCESS;
+
+ CloseHandle(VolumeInfo->Handle);
+ err_handle:
+
+ return rc;
+ }
+
+DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo(
+ CHAR * VolumeName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ ) {
+ S_NTFSSECT_XPFUNCS xp_funcs;
+ DWORD rc, free_clusts, total_clusts;
+ BOOL ok;
+
+ if (!VolumeName || !VolumeInfo)
+ return ERROR_INVALID_PARAMETER;
+
+ rc = NtfsSectGetVolumeHandle(VolumeName, VolumeInfo);
+ if (rc != ERROR_SUCCESS)
+ goto err_handle;
+
+ rc = NtfsSectLoadXpFuncs(&xp_funcs);
+ if (rc != ERROR_SUCCESS)
+ goto err_xp_funcs;
+
+ ok = xp_funcs.GetDiskFreeSpace(
+ VolumeName,
+ &VolumeInfo->SectorsPerCluster,
+ &VolumeInfo->BytesPerSector,
+ &free_clusts,
+ &total_clusts
+ );
+ rc = GetLastError();
+ if (!ok) {
+ M_ERR("GetDiskFreeSpace() failed!");
+ goto err_freespace;
+ }
+
+ rc = NtfsSectGetVolumePartitionLba(VolumeInfo);
+ if (rc != ERROR_SUCCESS)
+ goto err_lba;
+
+ VolumeInfo->Size = sizeof *VolumeInfo;
+ rc = ERROR_SUCCESS;
+
+ err_lba:
+
+ err_freespace:
+
+ NtfsSectUnloadXpFuncs(&xp_funcs);
+ err_xp_funcs:
+
+ if (rc != ERROR_SUCCESS) {
+ CloseHandle(VolumeInfo->Handle);
+ VolumeInfo->Handle = INVALID_HANDLE_VALUE;
+ }
+ err_handle:
+
+ return rc;
+ }
+
+DWORD M_NTFSSECT_API NtfsSectGetVolumeInfoFromFileName(
+ CHAR * FileName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ ) {
+ S_NTFSSECT_XPFUNCS xp_funcs;
+ DWORD rc;
+ CHAR volname[MAX_PATH + 1];
+ BOOL ok;
+
+ if (!FileName || !VolumeInfo)
+ return ERROR_INVALID_PARAMETER;
+
+ rc = NtfsSectLoadXpFuncs(&xp_funcs);
+ if (rc != ERROR_SUCCESS) {
+ goto err_xp_funcs;
+ }
+
+ ok = xp_funcs.GetVolumePathName(
+ FileName,
+ volname,
+ sizeof volname
+ );
+ rc = GetLastError();
+ if (!ok) {
+ M_ERR("GetVolumePathName() failed!");
+ goto err_volname;
+ }
+
+ rc = NtfsSectGetVolumeInfo(volname, VolumeInfo);
+
+ err_volname:
+
+ NtfsSectUnloadXpFuncs(&xp_funcs);
+ err_xp_funcs:
+
+ return rc;
+ }
+
+/* Internal use only */
+static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo) {
+ BOOL ok;
+ VOLUME_DISK_EXTENTS vol_disk_extents;
+ DWORD output_size, rc;
+
+ ok = DeviceIoControl(
+ VolumeInfo->Handle,
+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+ NULL,
+ 0,
+ &vol_disk_extents,
+ sizeof vol_disk_extents,
+ &output_size,
+ NULL
+ );
+ rc = GetLastError();
+ if (!ok) {
+ M_ERR("Couldn't fetch volume disk extent(s)!");
+ goto err_vol_disk_extents;
+ }
+
+ if (vol_disk_extents.NumberOfDiskExtents != 1) {
+ M_ERR("Unsupported number of volume disk extents!");
+ goto err_num_of_extents;
+ }
+
+ VolumeInfo->PartitionLba.QuadPart = (
+ vol_disk_extents.Extents[0].StartingOffset.QuadPart /
+ VolumeInfo->BytesPerSector
+ );
+
+ return ERROR_SUCCESS;
+
+ err_num_of_extents:
+
+ err_vol_disk_extents:
+
+ return rc;
+ }
+
+DWORD M_NTFSSECT_API NtfsSectLcnToLba(
+ const S_NTFSSECT_VOLINFO * VolumeInfo,
+ const LARGE_INTEGER * Lcn,
+ LARGE_INTEGER * Lba
+ ) {
+ BOOL bad;
+ bad = (
+ !VolumeInfo ||
+ !VolumeInfo->BytesPerSector ||
+ !VolumeInfo->SectorsPerCluster ||
+ !Lcn ||
+ Lcn->QuadPart < 0 ||
+ !Lba
+ );
+ if (bad)
+ return ERROR_INVALID_PARAMETER;
+
+ Lba->QuadPart = (
+ VolumeInfo->PartitionLba.QuadPart +
+ Lcn->QuadPart *
+ VolumeInfo->SectorsPerCluster
+ );
+ return ERROR_SUCCESS;
+ }
+
+DWORD M_NTFSSECT_API NtfsSectLoadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
+ DWORD rc;
+
+ if (!XpFuncs)
+ return ERROR_INVALID_PARAMETER;
+
+ XpFuncs->Size = sizeof *XpFuncs;
+
+ XpFuncs->Kernel32 = LoadLibrary("kernel32.dll");
+ rc = GetLastError();
+ if (!XpFuncs->Kernel32) {
+ M_ERR("KERNEL32.DLL not found!");
+ goto err;
+ }
+
+ XpFuncs->GetVolumePathName = (F_KERNEL32_GETVOLUMEPATHNAME *) (
+ GetProcAddress(
+ XpFuncs->Kernel32,
+ "GetVolumePathNameA"
+ )
+ );
+ rc = GetLastError();
+ if (!XpFuncs->GetVolumePathName) {
+ M_ERR("GetVolumePathName() not found in KERNEL32.DLL!");
+ goto err;
+ }
+
+ XpFuncs->GetDiskFreeSpace = (F_KERNEL32_GETDISKFREESPACE *) (
+ GetProcAddress(
+ XpFuncs->Kernel32,
+ "GetDiskFreeSpaceA"
+ )
+ );
+ rc = GetLastError();
+ if (!XpFuncs->GetDiskFreeSpace) {
+ M_ERR("GetDiskFreeSpace() not found in KERNEL32.DLL!");
+ goto err;
+ }
+
+ return ERROR_SUCCESS;
+
+ err:
+ NtfsSectUnloadXpFuncs(XpFuncs);
+ return rc;
+ }
+
+VOID M_NTFSSECT_API NtfsSectUnloadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
+ if (!XpFuncs)
+ return;
+
+ XpFuncs->GetDiskFreeSpace = NULL;
+ XpFuncs->GetVolumePathName = NULL;
+ if (XpFuncs->Kernel32)
+ FreeLibrary(XpFuncs->Kernel32);
+ XpFuncs->Kernel32 = NULL;
+ XpFuncs->Size = 0;
+ return;
+ }
+
diff --git a/win/ntfssect.h b/win/ntfssect.h
new file mode 100644
index 00000000..246c26da
--- /dev/null
+++ b/win/ntfssect.h
@@ -0,0 +1,152 @@
+/* -------------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Shao Miller - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+#ifndef M_NTFSSECT_H_
+
+/****
+ * ntfssect.h
+ *
+ * Fetch NTFS file cluster & sector information via Windows
+ *
+ * With special thanks to Mark Roddy for his article:
+ * http://www.wd-3.com/archive/luserland.htm
+ */
+
+/*** Macros */
+#define M_NTFSSECT_H_
+#define M_NTFSSECT_API
+
+/*** Object types */
+
+/* An "extent;" a contiguous range of file data */
+typedef struct S_NTFSSECT_EXTENT_ S_NTFSSECT_EXTENT;
+
+/* Volume info relevant to file cluster & sector info */
+typedef struct S_NTFSSECT_VOLINFO_ S_NTFSSECT_VOLINFO;
+
+/* Stores function pointers to some Windows functions */
+typedef struct S_NTFSSECT_XPFUNCS_ S_NTFSSECT_XPFUNCS;
+
+/*** Function types */
+
+/* The function type for Kernel32.dll's GetDiskFreeSpace() */
+typedef BOOL WINAPI F_KERNEL32_GETDISKFREESPACE(
+ LPCTSTR,
+ LPDWORD,
+ LPDWORD,
+ LPDWORD,
+ LPDWORD
+ );
+
+/* The function type for Kernel32.dll's GetVolumePathName() */
+typedef BOOL WINAPI F_KERNEL32_GETVOLUMEPATHNAME(LPCTSTR, LPCTSTR, DWORD);
+
+/*** Function declarations */
+
+/**
+ * Fetch the extent containing a particular VCN
+ *
+ * @v File
+ * @v Vcn
+ * @v Extent
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent(
+ HANDLE File,
+ LARGE_INTEGER * Vcn,
+ S_NTFSSECT_EXTENT * Extent
+ );
+
+/**
+ * Populate a volume info object
+ *
+ * @v VolumeName
+ * @v VolumeInfo
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo(
+ CHAR * VolumeName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ );
+
+/**
+ * Populate a volume info object
+ *
+ * @v FileName
+ * @v VolumeInfo
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectGetVolumeInfoFromFileName(
+ CHAR * FileName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ );
+
+/**
+ * Convert a volume LCN to an absolute disk LBA
+ *
+ * @v VolumeInfo
+ * @v Lcn
+ * @v Lba
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectLcnToLba(
+ const S_NTFSSECT_VOLINFO * VolumeInfo,
+ const LARGE_INTEGER * Lcn,
+ LARGE_INTEGER * Lba
+ );
+
+/**
+ * Load some helper XP functions
+ *
+ * @v XpFuncs
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectLoadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs);
+
+/**
+ * Unload some helper XP functions
+ *
+ * @v XpFuncs
+ * @ret DWORD
+ */
+VOID M_NTFSSECT_API NtfsSectUnloadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs);
+
+/*** Object declarations */
+
+/**
+ * The last error message set by one of our functions.
+ * Obviously not per-thread
+ */
+extern CHAR * NtfsSectLastErrorMessage;
+
+/*** Struct/union definitions */
+struct S_NTFSSECT_EXTENT_ {
+ LARGE_INTEGER FirstVcn;
+ LARGE_INTEGER NextVcn;
+ LARGE_INTEGER FirstLcn;
+ };
+
+struct S_NTFSSECT_VOLINFO_ {
+ DWORD Size;
+ HANDLE Handle;
+ DWORD BytesPerSector;
+ DWORD SectorsPerCluster;
+ LARGE_INTEGER PartitionLba;
+ };
+
+struct S_NTFSSECT_XPFUNCS_ {
+ DWORD Size;
+ HMODULE Kernel32;
+ F_KERNEL32_GETVOLUMEPATHNAME * GetVolumePathName;
+ F_KERNEL32_GETDISKFREESPACE * GetDiskFreeSpace;
+ };
+
+#endif /* M_NTFSSECT_H_ */
diff --git a/win/ntfstest.c b/win/ntfstest.c
new file mode 100644
index 00000000..1fc27182
--- /dev/null
+++ b/win/ntfstest.c
@@ -0,0 +1,163 @@
+/* -------------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Shao Miller - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+/****
+ * ntfstest.c
+ *
+ * (C) Shao Miller, 2011
+ *
+ * Tests ntfssect.c functions
+ *
+ * With special thanks to Mark Roddy for his article:
+ * http://www.wd-3.com/archive/luserland.htm
+ */
+#include <windows.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntfssect.h"
+
+/*** Object types */
+
+/*** Function declarations */
+static void show_usage(void);
+static void show_last_err(void);
+static void show_err(DWORD);
+
+/*** Struct/union definitions */
+
+/*** Function definitions */
+
+/** Program entry-point */
+int main(int argc, char ** argv) {
+ int rc;
+ DWORD err;
+ S_NTFSSECT_VOLINFO vol_info;
+ HANDLE file;
+ LARGE_INTEGER vcn, lba;
+ S_NTFSSECT_EXTENT extent;
+ LONGLONG len;
+ BOOL ok;
+
+ if (argc != 2) {
+ rc = EXIT_FAILURE;
+ show_usage();
+ goto err_args;
+ }
+
+ /* Get volume info */
+ err = NtfsSectGetVolumeInfoFromFileName(argv[1], &vol_info);
+ if (err != ERROR_SUCCESS) {
+ show_err(err);
+ goto err_vol_info;
+ }
+ printf(
+ "Volume has %d bytes per sector, %d sectors per cluster\n",
+ vol_info.BytesPerSector,
+ vol_info.SectorsPerCluster
+ );
+
+ /* Open the file for reading */
+ file = CreateFile(
+ argv[1],
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+ if (file == INVALID_HANDLE_VALUE) {
+ rc = EXIT_FAILURE;
+ show_last_err();
+ goto err_file;
+ }
+
+ /* For each extent */
+ for (
+ vcn.QuadPart = 0;
+ NtfsSectGetFileVcnExtent(file, &vcn, &extent) == ERROR_SUCCESS;
+ vcn = extent.NextVcn
+ ) {
+ len = extent.NextVcn.QuadPart - extent.FirstVcn.QuadPart;
+ printf("Extent @ VCN #%lld,", extent.FirstVcn.QuadPart);
+ printf(" %lld clusters long:\n", len);
+ printf(" VCN #%lld -", extent.FirstVcn.QuadPart);
+ printf(" #%lld\n", extent.FirstVcn.QuadPart + len - 1);
+ printf(" LCN #%lld -", extent.FirstLcn.QuadPart);
+ printf(" #%lld\n", extent.FirstLcn.QuadPart + len - 1);
+ err = NtfsSectLcnToLba(
+ &vol_info,
+ &extent.FirstLcn,
+ &lba
+ );
+ if (err == ERROR_SUCCESS) {
+ printf(" LBA #%lld -", lba.QuadPart);
+ printf(
+ " #%lld\n",
+ lba.QuadPart + len * vol_info.SectorsPerCluster
+ );
+ }
+ continue;
+ }
+
+ rc = EXIT_SUCCESS;
+
+ CloseHandle(file);
+ err_file:
+
+ CloseHandle(vol_info.Handle);
+ err_vol_info:
+
+ err_args:
+
+ return rc;
+ }
+
+/** Display usage */
+static void show_usage(void) {
+ static const char usage_text[] = "\
+ File sector info . . . . . . . . . . . . . . . . . . . . Shao Miller, 2011\n\
+\n\
+ Usage: NTFSTEST.EXE <filename>\n\
+\n\
+ Attempts to dump cluster and sector info for <filename>.\n";
+
+ printf(usage_text);
+ return;
+ }
+
+static void show_last_err(void) {
+ show_err(GetLastError());
+ return;
+ }
+
+/** Display an error */
+static void show_err(DWORD err_code) {
+ void * buf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ err_code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &buf,
+ 0,
+ NULL
+ );
+ fprintf(stderr, "Error: %s\n", buf);
+ LocalFree(buf);
+ return;
+ }
+
diff --git a/win/ntfstest.rc b/win/ntfstest.rc
new file mode 100644
index 00000000..462d21f1
--- /dev/null
+++ b/win/ntfstest.rc
@@ -0,0 +1,26 @@
+
+1 VERSIONINFO
+FILEVERSION 0,0,0,1
+PRODUCTVERSION 0,0,0,1
+FILEOS 0x40004
+FILETYPE 0x1
+ {
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "Shao Miller"
+ VALUE "FileDescription", "NTFS File Sector Info"
+ VALUE "FileVersion", "0.0.0.1 (Aug-12-2011)"
+ VALUE "InternalName", "NTFSTest"
+ VALUE "LegalCopyright", "© 2011 Shao Miller. All rights reserved."
+ VALUE "OriginalFilename", "NTFSTEST.EXE"
+ VALUE "ProductName", "Utilities"
+ VALUE "ProductVersion", "0.0.0.1"
+ }
+ }
+ }
+
+#if 0
+1 ICON "ntfstest.ico"
+#endif
diff --git a/win/syslinux.c b/win/syslinux.c
index 0e833d8d..669450eb 100644
--- a/win/syslinux.c
+++ b/win/syslinux.c
@@ -27,6 +27,8 @@
#include "setadv.h"
#include "sysexits.h"
#include "syslxopt.h"
+#include "syslxfs.h"
+#include "ntfssect.h"
#ifdef __GNUC__
# define noreturn void __attribute__((noreturn))
@@ -48,16 +50,16 @@ void error(char *msg);
// The following struct should be in the ntddstor.h file, but I didn't have it.
// mingw32 has <ddk/ntddstor.h>, but including that file causes all kinds
// of other failures. mingw64 has it in <winioctl.h>.
-#ifndef __x86_64__
-typedef struct _STORAGE_DEVICE_NUMBER {
+// Thus, instead of STORAGE_DEVICE_NUMBER, use a lower-case private
+// definition...
+struct storage_device_number {
DEVICE_TYPE DeviceType;
ULONG DeviceNumber;
ULONG PartitionNumber;
-} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
-#endif
+};
BOOL GetStorageDeviceNumberByHandle(HANDLE handle,
- const STORAGE_DEVICE_NUMBER * sdn)
+ const struct storage_device_number *sdn)
{
BOOL result = FALSE;
DWORD count;
@@ -254,6 +256,7 @@ int main(int argc, char *argv[])
int ldlinux_sectors;
uint32_t ldlinux_cluster;
int nsectors;
+ int fs_type;
if (!checkver()) {
fprintf(stderr,
@@ -326,8 +329,10 @@ int main(int argc, char *argv[])
exit(1);
}
- /* Check to see that what we got was indeed an MS-DOS boot sector/superblock */
- if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+ /* Check to see that what we got was indeed an FAT/NTFS
+ * boot sector/superblock
+ */
+ if ((errmsg = syslinux_check_bootsect(sectbuf, &fs_type))) {
fprintf(stderr, "%s\n", errmsg);
exit(1);
}
@@ -379,6 +384,38 @@ int main(int argc, char *argv[])
ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE + SECTOR_SIZE - 1)
>> SECTOR_SHIFT;
sectors = calloc(ldlinux_sectors, sizeof *sectors);
+ if (fs_type == NTFS) {
+ DWORD err;
+ S_NTFSSECT_VOLINFO vol_info;
+ LARGE_INTEGER vcn, lba, len;
+ S_NTFSSECT_EXTENT extent;
+
+ err = NtfsSectGetVolumeInfo(drive_name + 4, &vol_info);
+ if (err != ERROR_SUCCESS) {
+ error("Could not fetch NTFS volume info");
+ exit(1);
+ }
+ secp = sectors;
+ nsectors = 0;
+ for (vcn.QuadPart = 0;
+ NtfsSectGetFileVcnExtent(f_handle, &vcn, &extent) == ERROR_SUCCESS;
+ vcn = extent.NextVcn) {
+ err = NtfsSectLcnToLba(&vol_info, &extent.FirstLcn, &lba);
+ if (err != ERROR_SUCCESS) {
+ error("Could not translate LDLINUX.SYS LCN to disk LBA");
+ exit(1);
+ }
+ lba.QuadPart -= vol_info.PartitionLba.QuadPart;
+ len.QuadPart = ((extent.NextVcn.QuadPart -
+ extent.FirstVcn.QuadPart) *
+ vol_info.SectorsPerCluster);
+ while (len.QuadPart-- && nsectors < ldlinux_sectors) {
+ *secp++ = lba.QuadPart++;
+ nsectors++;
+ }
+ }
+ goto map_done;
+ }
fs = libfat_open(libfat_readfile, (intptr_t) d_handle);
ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
secp = sectors;
@@ -390,6 +427,7 @@ int main(int argc, char *argv[])
s = libfat_nextsector(fs, s);
}
libfat_close(fs);
+map_done:
/*
* Patch ldlinux.sys and the boot sector
@@ -409,7 +447,7 @@ int main(int argc, char *argv[])
/* If desired, fix the MBR */
if (opt.install_mbr || opt.activate_partition) {
- STORAGE_DEVICE_NUMBER sdn;
+ struct storage_device_number sdn;
if (GetStorageDeviceNumberByHandle(d_handle, &sdn)) {
if (!FixMBR(sdn.DeviceNumber, sdn.PartitionNumber, opt.install_mbr, opt.activate_partition)) {
fprintf(stderr,
@@ -472,7 +510,7 @@ int main(int argc, char *argv[])
}
/* Make the syslinux boot sector */
- syslinux_make_bootsect(sectbuf);
+ syslinux_make_bootsect(sectbuf, fs_type);
/* Write the syslinux boot sector into the boot sector */
if (opt.bootsecfile) {