win: Add further NTFS support to Windows installers
authorShao Miller <shao.miller@yrdsb.edu.on.ca>
Sun, 14 Aug 2011 23:41:24 +0000 (19:41 -0400)
committerPaulo Alcantara <pcacjr@gmail.com>
Sun, 11 Sep 2011 04:09:59 +0000 (04:09 +0000)
We have a way of building a map of the LDLINUX.SYS sectors
on an NTFS filesystem, now.

Signed-off-by: Paulo Alcantara <pcacjr@gmail.com>
Signed-off-by: Shao Miller <shao.miller@yrdsb.edu.on.ca>
win/ntfssect.c [new file with mode: 0644]
win/ntfssect.h [new file with mode: 0644]
win/ntfstest.c [new file with mode: 0644]
win/ntfstest.rc [new file with mode: 0644]
win/syslinux.c
win32/Makefile
win32/ntfstest/Makefile [new file with mode: 0644]
win64/Makefile
win64/ntfstest/Makefile [new file with mode: 0644]

diff --git a/win/ntfssect.c b/win/ntfssect.c
new file mode 100644 (file)
index 0000000..8c2bcca
--- /dev/null
@@ -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 (file)
index 0000000..246c26d
--- /dev/null
@@ -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 (file)
index 0000000..1fc2718
--- /dev/null
@@ -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 (file)
index 0000000..462d21f
--- /dev/null
@@ -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
index 4e4435e..13f25b6 100644 (file)
@@ -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))
@@ -382,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--) {
+               *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;
@@ -393,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
index cdb18f2..f960998 100644 (file)
@@ -47,7 +47,7 @@ WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
 
 .SUFFIXES: .c .obj .lib .exe .i .s .S
 
-SRCS     = ../win/syslinux.c
+SRCS     = ../win/syslinux.c ../win/ntfssect.c
 OBJS     = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
 LIBSRC   = ../libinstaller/fs.c \
           ../libinstaller/syslxmod.c \
diff --git a/win32/ntfstest/Makefile b/win32/ntfstest/Makefile
new file mode 100644 (file)
index 0000000..00e89cf
--- /dev/null
@@ -0,0 +1,87 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+##   Copyright 2010 Intel Corporation; author: H. Peter Anvin
+##
+##   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.
+##
+## -----------------------------------------------------------------------
+
+#
+# Makefile for Win32 NTFS file cluster test
+#
+# This is separated out mostly so we can have a different set of Makefile
+# variables.
+#
+
+OSTYPE   = $(shell uname -msr)
+ifeq ($(findstring CYGWIN,$(OSTYPE)),CYGWIN)
+## Compiling on Cygwin
+WINPREFIX  :=
+WINCFLAGS  := -mno-cygwin $(GCCWARN) -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64
+WINLDFLAGS := -mno-cygwin -Os -s
+else
+## Compiling on some variant of MinGW
+ifeq ($(findstring MINGW32,$(OSTYPE)),MINGW32)
+WINPREFIX  :=
+else
+WINPREFIX  := $(shell ../find-mingw32.sh gcc)
+endif
+WINCFLAGS  := $(GCCWARN) -Wno-sign-compare -Os -fomit-frame-pointer \
+             -D_FILE_OFFSET_BITS=64
+WINLDFLAGS := -Os -s
+endif
+WINCFLAGS += -I. -I../../win
+
+WINCC      := $(WINPREFIX)gcc
+WINAR     := $(WINPREFIX)ar
+WINRANLIB  := $(WINPREFIX)ranlib
+WINDRES    := $(WINPREFIX)windres
+
+WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
+       -o hello.exe ../../win/hello.c >/dev/null 2>&1 ; echo $$?)
+
+.SUFFIXES: .c .obj .lib .exe .i .s .S .rc .res
+
+SRCS     = ../../win/ntfstest.c ../../win/ntfssect.c 
+RCS      = ../../win/ntfstest.rc 
+OBJS     = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
+RESS     = $(patsubst %.rc,%.res,$(notdir $(RCS)))
+
+VPATH = .:../../win
+
+TARGETS = ntfstest.exe
+
+ifeq ($(WINCC_IS_GOOD),0)
+all: $(TARGETS)
+else
+all:
+       rm -f $(TARGETS)
+endif
+
+tidy dist:
+       -rm -f *.o *.obj *.lib *.i *.s *.a .*.d *.tmp *_bin.c hello.exe
+
+clean: tidy
+
+spotless: clean
+       -rm -f *~ $(TARGETS)
+
+ntfstest.exe: $(OBJS) $(RESS)
+       $(WINCC) $(WINLDFLAGS) -o $@ $^
+
+
+%.obj: %.c
+       $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -c -o $@ $<
+%.i: %.c
+       $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -E -o $@ $<
+%.s: %.c
+       $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -S -o $@ $<
+%.res: %.rc
+       $(WINDRES) -O COFF $< $@
+
+-include .*.d *.tmp
index 6853fb2..fe60793 100644 (file)
@@ -37,7 +37,7 @@ WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
 
 .SUFFIXES: .c .obj .lib .exe .i .s .S
 
-SRCS     = ../win/syslinux.c
+SRCS     = ../win/syslinux.c ../win/ntfssect.c
 OBJS     = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
 LIBSRC   = ../libinstaller/fs.c \
           ../libinstaller/syslxmod.c \
diff --git a/win64/ntfstest/Makefile b/win64/ntfstest/Makefile
new file mode 100644 (file)
index 0000000..5b975be
--- /dev/null
@@ -0,0 +1,76 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+##   Copyright 2010 Intel Corporation; author: H. Peter Anvin
+##
+##   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.
+##
+## -----------------------------------------------------------------------
+
+#
+# Makefile for Win64 NTFS file cluster test
+#
+# This is separated out mostly so we can have a different set of Makefile
+# variables.
+#
+
+OSTYPE   = $(shell uname -msr)
+# Don't know how to do a native compile here...
+WINPREFIX  := $(shell ../find-mingw64.sh gcc)
+WINCFLAGS  := $(GCCWARN) -Wno-sign-compare -Os -fomit-frame-pointer \
+             -D_FILE_OFFSET_BITS=64
+WINLDFLAGS := -Os -s
+WINCFLAGS += -I. -I../../win
+
+WINCC      := $(WINPREFIX)gcc
+WINAR     := $(WINPREFIX)ar
+WINRANLIB  := $(WINPREFIX)ranlib
+WINDRES    := $(WINPREFIX)windres
+
+WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
+       -o hello.exe ../../win/hello.c >/dev/null 2>&1 ; echo $$?)
+
+.SUFFIXES: .c .obj .lib .exe .i .s .S .rc .res
+
+SRCS     = ../../win/ntfstest.c ../../win/ntfssect.c
+RCS      = ../../win/ntfstest.rc
+OBJS     = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
+RESS     = $(patsubst %.rc,%.res,$(notdir $(RCS)))
+
+VPATH = .:../../win
+
+TARGETS = ntfstest64.exe
+
+ifeq ($(WINCC_IS_GOOD),0)
+all: $(TARGETS)
+else
+all:
+       rm -f $(TARGETS)
+endif
+
+tidy dist:
+       -rm -f *.o *.obj *.lib *.i *.s *.a .*.d *.tmp *_bin.c hello.exe
+
+clean: tidy
+
+spotless: clean
+       -rm -f *~ $(TARGETS)
+
+ntfstest64.exe: $(OBJS) $(RESS)
+       $(WINCC) $(WINLDFLAGS) -o $@ $^
+
+
+%.obj: %.c
+       $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -c -o $@ $<
+%.i: %.c
+       $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -E -o $@ $<
+%.s: %.c
+       $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -S -o $@ $<
+%.res: %.rc
+       $(WINDRES) -O COFF $< $@
+
+-include .*.d *.tmp