176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* ----------------------------------------------------------------------- *
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2003 Lars Munch Christensen - All Rights Reserved
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Based on the Linux installer program for SYSLINUX by H. Peter Anvin
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   This program is free software; you can redistribute it and/or modify
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   it under the terms of the GNU General Public License as published by
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Boston MA 02111-1307, USA; either version 2 of the License, or
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   (at your option) any later version; incorporated herein by reference.
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ----------------------------------------------------------------------- */
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * syslinux-mingw.c - Win2k/WinXP installer program for SYSLINUX
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <windows.h>
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <ctype.h>
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <getopt.h>
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "syslinux.h"
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "libfat.h"
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "setadv.h"
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "sysexits.h"
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "syslxopt.h"
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "syslxfs.h"
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "ntfssect.h"
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef __GNUC__
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman# define noreturn void __attribute__((noreturn))
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman# define noreturn void
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid error(char *msg);
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Begin stuff for MBR code */
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <winioctl.h>
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define PART_TABLE  0x1be
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define PART_SIZE   0x10
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define PART_COUNT  4
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define PART_ACTIVE 0x80
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman// The following struct should be in the ntddstor.h file, but I didn't have it.
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman// mingw32 has <ddk/ntddstor.h>, but including that file causes all kinds
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman// of other failures.  mingw64 has it in <winioctl.h>.
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman// Thus, instead of STORAGE_DEVICE_NUMBER, use a lower-case private
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman// definition...
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct storage_device_number {
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DEVICE_TYPE DeviceType;
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ULONG DeviceNumber;
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ULONG PartitionNumber;
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanBOOL GetStorageDeviceNumberByHandle(HANDLE handle,
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				    const struct storage_device_number *sdn)
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    BOOL result = FALSE;
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DWORD count;
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (DeviceIoControl(handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL,
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			0, (LPVOID) sdn, sizeof(*sdn), &count, NULL)) {
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	result = TRUE;
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("GetDriveNumber: DeviceIoControl failed");
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (result);
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint GetBytesPerSector(HANDLE drive)
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int result = 0;
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DISK_GEOMETRY g;
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DWORD count;
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (DeviceIoControl(drive, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			&g, sizeof(g), &count, NULL)) {
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	result = g.BytesPerSector;
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (result);
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanBOOL FixMBR(int driveNum, int partitionNum, int write_mbr, int set_active)
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    BOOL result = TRUE;
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    HANDLE drive;
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char driveName[128];
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sprintf(driveName, "\\\\.\\PHYSICALDRIVE%d", driveNum);
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    drive = CreateFile(driveName,
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       GENERIC_READ | GENERIC_WRITE,
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       FILE_SHARE_WRITE | FILE_SHARE_READ,
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       NULL, OPEN_EXISTING, 0, NULL);
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (drive == INVALID_HANDLE_VALUE) {
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Accessing physical drive");
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	result = FALSE;
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (result) {
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned char sector[SECTOR_SIZE];
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DWORD howMany;
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (GetBytesPerSector(drive) != SECTOR_SIZE) {
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fprintf(stderr,
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    "Error: Sector size of this drive is %d; must be %d\n",
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    GetBytesPerSector(drive), SECTOR_SIZE);
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    result = FALSE;
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (result) {
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (ReadFile(drive, sector, sizeof(sector), &howMany, NULL) == 0) {
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		error("Reading raw drive");
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		result = FALSE;
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    } else if (howMany != sizeof(sector)) {
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		fprintf(stderr,
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			"Error: ReadFile on drive only got %d of %d bytes\n",
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			(int)howMany, sizeof(sector));
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		result = FALSE;
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	// Copy over the MBR code if specified (-m)
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (write_mbr) {
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (result) {
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (syslinux_mbr_len >= PART_TABLE) {
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    fprintf(stderr, "Error: MBR will not fit; not writing\n");
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    result = FALSE;
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else {
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    memcpy(sector, syslinux_mbr, syslinux_mbr_len);
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	// Check that our partition is active if specified (-a)
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (set_active) {
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (sector[PART_TABLE + (PART_SIZE * (partitionNum - 1))] != 0x80) {
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int p;
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		for (p = 0; p < PART_COUNT; p++)
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    sector[PART_TABLE + (PART_SIZE * p)] =
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			(p == partitionNum - 1 ? 0x80 : 0);
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (result) {
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    SetFilePointer(drive, 0, NULL, FILE_BEGIN);
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (WriteFile(drive, sector, sizeof(sector), &howMany, NULL) == 0) {
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		error("Writing MBR");
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		result = FALSE;
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    } else if (howMany != sizeof(sector)) {
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		fprintf(stderr,
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			"Error: WriteFile on drive only wrote %d of %d bytes\n",
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			(int)howMany, sizeof(sector));
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		result = FALSE;
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!CloseHandle(drive)) {
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    error("CloseFile on drive");
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    result = FALSE;
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (result);
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* End stuff for MBR code */
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst char *program;		/* Name of program */
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check Windows version.
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * On Windows Me/98/95 you cannot open a directory, physical disk, or
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * volume using CreateFile.
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint checkver(void)
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    OSVERSIONINFO osvi;
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    GetVersionEx(&osvi);
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	((osvi.dwMajorVersion > 4) ||
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)));
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Windows error function
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid error(char *msg)
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LPVOID lpMsgBuf;
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Format the Windows error message */
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),	// Default language
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  (LPTSTR) & lpMsgBuf, 0, NULL);
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Print it */
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    fprintf(stderr, "%s: %s", msg, (char *)lpMsgBuf);
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Free the buffer */
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LocalFree(lpMsgBuf);
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Wrapper for ReadFile suitable for libfat
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint libfat_readfile(intptr_t pp, void *buf, size_t secsize,
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    libfat_sector_t sector)
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint64_t offset = (uint64_t) sector * secsize;
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LONG loword = (LONG) offset;
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LONG hiword = (LONG) (offset >> 32);
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LONG hiwordx = hiword;
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DWORD bytes_read;
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (SetFilePointer((HANDLE) pp, loword, &hiwordx, FILE_BEGIN) != loword ||
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hiword != hiwordx ||
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	!ReadFile((HANDLE) pp, buf, secsize, &bytes_read, NULL) ||
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	bytes_read != secsize) {
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr, "Cannot read sector %u\n", sector);
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return secsize;
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void move_file(char *pathname, char *filename)
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char new_name[strlen(opt.directory) + 16];
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char *cp = new_name + 3;
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *sd;
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int slash = 1;
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    new_name[0] = opt.device[0];
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    new_name[1] = ':';
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    new_name[2] = '\\';
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (sd = opt.directory; *sd; sd++) {
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	char c = *sd;
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (c == '/' || c == '\\') {
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (slash)
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		continue;
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    c = '\\';
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    slash = 1;
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    slash = 0;
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*cp++ = c;
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Skip if subdirectory == root */
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (cp > new_name + 3) {
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!slash)
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *cp++ = '\\';
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(cp, filename, 12);
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Delete any previous file */
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	SetFileAttributes(new_name, FILE_ATTRIBUTE_NORMAL);
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DeleteFile(new_name);
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!MoveFile(pathname, new_name)) {
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fprintf(stderr,
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    "Failed to move %s to destination directory: %s\n",
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    filename, opt.directory);
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    SetFileAttributes(pathname, FILE_ATTRIBUTE_READONLY |
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      FILE_ATTRIBUTE_SYSTEM |
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      FILE_ATTRIBUTE_HIDDEN);
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    SetFileAttributes(new_name, FILE_ATTRIBUTE_READONLY |
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      FILE_ATTRIBUTE_SYSTEM |
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      FILE_ATTRIBUTE_HIDDEN);
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint main(int argc, char *argv[])
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    HANDLE f_handle, d_handle;
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DWORD bytes_read;
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DWORD bytes_written;
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DWORD drives;
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    UINT drive_type;
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static unsigned char sectbuf[SECTOR_SIZE];
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char **argp;
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static char drive_name[] = "\\\\.\\?:";
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static char drive_root[] = "?:\\";
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static char ldlinux_name[] = "?:\\ldlinux.sys";
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static char ldlinuxc32_name[] = "?:\\ldlinux.c32";
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *errmsg;
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct libfat_filesystem *fs;
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    libfat_sector_t s, *secp;
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    libfat_sector_t *sectors;
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int ldlinux_sectors;
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint32_t ldlinux_cluster;
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int nsectors;
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int fs_type;
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!checkver()) {
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr,
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		"You need to be running at least Windows NT; use syslinux.com instead.\n");
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    program = argv[0];
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    parse_options(argc, argv, MODE_SYSLINUX_DOSWIN);
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!opt.device || !isalpha(opt.device[0]) || opt.device[1] != ':'
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	|| opt.device[2])
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	usage(EX_USAGE, MODE_SYSLINUX_DOSWIN);
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.sectors || opt.heads || opt.reset_adv || opt.set_once
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	|| (opt.update_only > 0) || opt.menu_save || opt.offset) {
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr,
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		"At least one specified option not yet implemented"
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		" for this installer.\n");
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Test if drive exists */
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    drives = GetLogicalDrives();
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(drives & (1 << (tolower(opt.device[0]) - 'a')))) {
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr, "No such drive %c:\n", opt.device[0]);
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Determines the drive type */
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    drive_name[4] = opt.device[0];
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ldlinux_name[0] = opt.device[0];
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ldlinuxc32_name[0] = opt.device[0];
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    drive_root[0] = opt.device[0];
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    drive_type = GetDriveType(drive_root);
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Test for removeable media */
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((drive_type == DRIVE_FIXED) && (opt.force == 0)) {
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr, "Not a removable drive (use -f to override) \n");
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Test for unsupported media */
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((drive_type != DRIVE_FIXED) && (drive_type != DRIVE_REMOVABLE)) {
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr, "Unsupported media\n");
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * First open the drive
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    d_handle = CreateFile(drive_name, GENERIC_READ | GENERIC_WRITE,
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  FILE_SHARE_READ | FILE_SHARE_WRITE,
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  NULL, OPEN_EXISTING, 0, NULL);
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (d_handle == INVALID_HANDLE_VALUE) {
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Could not open drive");
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Make sure we can read the boot sector
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!ReadFile(d_handle, sectbuf, SECTOR_SIZE, &bytes_read, NULL)) {
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Reading boot sector");
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (bytes_read != SECTOR_SIZE) {
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr, "Could not read the whole boot sector\n");
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Check to see that what we got was indeed an FAT/NTFS
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * boot sector/superblock
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((errmsg = syslinux_check_bootsect(sectbuf, &fs_type))) {
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr, "%s\n", errmsg);
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Change to normal attributes to enable deletion */
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Just ignore error if the file do not exists */
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    SetFileAttributes(ldlinux_name, FILE_ATTRIBUTE_NORMAL);
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    SetFileAttributes(ldlinuxc32_name, FILE_ATTRIBUTE_NORMAL);
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Delete the file */
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Just ignore error if the file do not exists */
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DeleteFile(ldlinux_name);
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DeleteFile(ldlinuxc32_name);
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Initialize the ADV -- this should be smarter */
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    syslinux_reset_adv(syslinux_adv);
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Create ldlinux.sys file */
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    f_handle = CreateFile(ldlinux_name, GENERIC_READ | GENERIC_WRITE,
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  FILE_SHARE_READ | FILE_SHARE_WRITE,
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  NULL, CREATE_ALWAYS,
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM |
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  FILE_ATTRIBUTE_HIDDEN, NULL);
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (f_handle == INVALID_HANDLE_VALUE) {
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Unable to create ldlinux.sys");
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Write ldlinux.sys file */
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!WriteFile(f_handle, (const char _force *)syslinux_ldlinux,
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   syslinux_ldlinux_len, &bytes_written, NULL) ||
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	bytes_written != syslinux_ldlinux_len) {
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Could not write ldlinux.sys");
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!WriteFile(f_handle, syslinux_adv, 2 * ADV_SIZE,
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   &bytes_written, NULL) ||
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	bytes_written != 2 * ADV_SIZE) {
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Could not write ADV to ldlinux.sys");
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Now flush the media */
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!FlushFileBuffers(f_handle)) {
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("FlushFileBuffers failed");
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Map the file (is there a better way to do this?) */
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE + SECTOR_SIZE - 1)
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	>> SECTOR_SHIFT;
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sectors = calloc(ldlinux_sectors, sizeof *sectors);
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (fs_type == NTFS) {
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DWORD err;
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	S_NTFSSECT_VOLINFO vol_info;
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	LARGE_INTEGER vcn, lba, len;
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	S_NTFSSECT_EXTENT extent;
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	err = NtfsSectGetVolumeInfo(drive_name + 4, &vol_info);
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (err != ERROR_SUCCESS) {
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    error("Could not fetch NTFS volume info");
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    exit(1);
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	secp = sectors;
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nsectors = 0;
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (vcn.QuadPart = 0;
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	     NtfsSectGetFileVcnExtent(f_handle, &vcn, &extent) == ERROR_SUCCESS;
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	     vcn = extent.NextVcn) {
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    err = NtfsSectLcnToLba(&vol_info, &extent.FirstLcn, &lba);
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (err != ERROR_SUCCESS) {
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		error("Could not translate LDLINUX.SYS LCN to disk LBA");
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		exit(1);
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    lba.QuadPart -= vol_info.PartitionLba.QuadPart;
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    len.QuadPart = ((extent.NextVcn.QuadPart -
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     extent.FirstVcn.QuadPart) *
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    vol_info.SectorsPerCluster);
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (len.QuadPart-- && nsectors < ldlinux_sectors) {
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*secp++ = lba.QuadPart++;
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nsectors++;
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto map_done;
47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    fs = libfat_open(libfat_readfile, (intptr_t) d_handle);
47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    secp = sectors;
47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    nsectors = 0;
47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    s = libfat_clustertosector(fs, ldlinux_cluster);
47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (s && nsectors < ldlinux_sectors) {
48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*secp++ = s;
48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nsectors++;
48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	s = libfat_nextsector(fs, s);
48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    libfat_close(fs);
48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanmap_done:
48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Patch ldlinux.sys and the boot sector
48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL);
49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Rewrite the file
49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (SetFilePointer(f_handle, 0, NULL, FILE_BEGIN) != 0 ||
49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	!WriteFile(f_handle, syslinux_ldlinux, syslinux_ldlinux_len,
49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   &bytes_written, NULL)
49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	|| bytes_written != syslinux_ldlinux_len) {
49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Could not write ldlinux.sys");
50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* If desired, fix the MBR */
50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.install_mbr || opt.activate_partition) {
50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct storage_device_number sdn;
50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (GetStorageDeviceNumberByHandle(d_handle, &sdn)) {
50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (!FixMBR(sdn.DeviceNumber, sdn.PartitionNumber, opt.install_mbr, opt.activate_partition)) {
50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		fprintf(stderr,
50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			"Did not successfully update the MBR; continuing...\n");
51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fprintf(stderr,
51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    "Could not find device number for updating MBR; continuing...\n");
51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Close file */
51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    CloseHandle(f_handle);
51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Move the file to the desired location */
52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.directory)
52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	move_file(ldlinux_name, "ldlinux.sys");
52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    f_handle = CreateFile(ldlinuxc32_name, GENERIC_READ | GENERIC_WRITE,
52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  FILE_SHARE_READ | FILE_SHARE_WRITE,
52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  NULL, CREATE_ALWAYS,
52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM |
52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  FILE_ATTRIBUTE_HIDDEN, NULL);
52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (f_handle == INVALID_HANDLE_VALUE) {
53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Unable to create ldlinux.c32");
53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Write ldlinux.c32 file */
53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!WriteFile(f_handle, (const char _force *)syslinux_ldlinuxc32,
53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   syslinux_ldlinuxc32_len, &bytes_written, NULL) ||
53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	bytes_written != syslinux_ldlinuxc32_len) {
53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("Could not write ldlinux.c32");
54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Now flush the media */
54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!FlushFileBuffers(f_handle)) {
54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	error("FlushFileBuffers failed");
54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    CloseHandle(f_handle);
55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Move the file to the desired location */
55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.directory)
55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	move_file(ldlinuxc32_name, "ldlinux.c32");
55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Make the syslinux boot sector */
55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    syslinux_make_bootsect(sectbuf, fs_type);
55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Write the syslinux boot sector into the boot sector */
55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (opt.bootsecfile) {
56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	f_handle = CreateFile(opt.bootsecfile, GENERIC_READ | GENERIC_WRITE,
56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      FILE_SHARE_READ | FILE_SHARE_WRITE,
56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      NULL, CREATE_ALWAYS,
56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      FILE_ATTRIBUTE_ARCHIVE, NULL);
56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (f_handle == INVALID_HANDLE_VALUE) {
56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    error("Unable to create bootsector file");
56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    exit(1);
56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!WriteFile(f_handle, sectbuf, SECTOR_SIZE, &bytes_written, NULL)) {
56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    error("Could not write boot sector file");
57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    exit(1);
57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	CloseHandle(f_handle);
57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	SetFilePointer(d_handle, 0, NULL, FILE_BEGIN);
57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	WriteFile(d_handle, sectbuf, SECTOR_SIZE, &bytes_written, NULL);
57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (bytes_written != SECTOR_SIZE) {
57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fprintf(stderr, "Could not write the whole boot sector\n");
58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	exit(1);
58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Close file */
58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    CloseHandle(d_handle);
58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Done! */
58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
589