hdt: updating memtest to 4.10
[syslinux.git] / win32 / syslinux.c
blob297b97b5c63a1540246ef771e78553796cb499d6
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2003 Lars Munch Christensen - All Rights Reserved
4 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
6 * Based on the Linux installer program for SYSLINUX by H. Peter Anvin
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
11 * Boston MA 02111-1307, USA; either version 2 of the License, or
12 * (at your option) any later version; incorporated herein by reference.
14 * ----------------------------------------------------------------------- */
17 * syslinux-mingw.c - Win2k/WinXP installer program for SYSLINUX
20 #include <windows.h>
21 #include <stdio.h>
22 #include <ctype.h>
24 #include "syslinux.h"
25 #include "libfat.h"
27 #ifdef __GNUC__
28 # define noreturn void __attribute__((noreturn))
29 #else
30 # define noreturn void
31 #endif
33 void error(char *msg);
35 /* Begin stuff for MBR code */
37 #include <winioctl.h>
39 #define PART_TABLE 0x1be
40 #define PART_SIZE 0x10
41 #define PART_COUNT 4
42 #define PART_ACTIVE 0x80
44 // The following struct should be in the ntddstor.h file, but I didn't have it.
45 // TODO: Make this a conditional compilation
46 typedef struct _STORAGE_DEVICE_NUMBER {
47 DEVICE_TYPE DeviceType;
48 ULONG DeviceNumber;
49 ULONG PartitionNumber;
50 } STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
52 BOOL GetStorageDeviceNumberByHandle(HANDLE handle,
53 const STORAGE_DEVICE_NUMBER * sdn)
55 BOOL result = FALSE;
56 DWORD count;
58 if (DeviceIoControl(handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL,
59 0, (LPVOID) sdn, sizeof(*sdn), &count, NULL)) {
60 result = TRUE;
61 } else {
62 error("GetDriveNumber: DeviceIoControl failed");
65 return (result);
68 int GetBytesPerSector(HANDLE drive)
70 int result = 0;
71 DISK_GEOMETRY g;
72 DWORD count;
74 if (DeviceIoControl(drive, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
75 &g, sizeof(g), &count, NULL)) {
76 result = g.BytesPerSector;
79 return (result);
82 BOOL FixMBR(int driveNum, int partitionNum, int write_mbr, int set_active)
84 BOOL result = TRUE;
85 HANDLE drive;
87 char driveName[128];
89 sprintf(driveName, "\\\\.\\PHYSICALDRIVE%d", driveNum);
91 drive = CreateFile(driveName,
92 GENERIC_READ | GENERIC_WRITE,
93 FILE_SHARE_WRITE | FILE_SHARE_READ,
94 NULL, OPEN_EXISTING, 0, NULL);
96 if (drive == INVALID_HANDLE_VALUE) {
97 error("Accessing physical drive");
98 result = FALSE;
101 if (result) {
102 unsigned char sector[SECTOR_SIZE];
103 DWORD howMany;
105 if (GetBytesPerSector(drive) != SECTOR_SIZE) {
106 fprintf(stderr,
107 "Error: Sector size of this drive is %d; must be %d\n",
108 GetBytesPerSector(drive), SECTOR_SIZE);
109 result = FALSE;
112 if (result) {
113 if (ReadFile(drive, sector, sizeof(sector), &howMany, NULL) == 0) {
114 error("Reading raw drive");
115 result = FALSE;
116 } else if (howMany != sizeof(sector)) {
117 fprintf(stderr,
118 "Error: ReadFile on drive only got %d of %d bytes\n",
119 (int)howMany, sizeof(sector));
120 result = FALSE;
123 // Copy over the MBR code if specified (-m)
124 if (write_mbr) {
125 if (result) {
126 if (syslinux_mbr_len >= PART_TABLE) {
127 fprintf(stderr, "Error: MBR will not fit; not writing\n");
128 result = FALSE;
129 } else {
130 memcpy(sector, syslinux_mbr, syslinux_mbr_len);
134 // Check that our partition is active if specified (-a)
135 if (set_active) {
136 if (sector[PART_TABLE + (PART_SIZE * (partitionNum - 1))] != 0x80) {
137 int p;
138 for (p = 0; p < PART_COUNT; p++)
139 sector[PART_TABLE + (PART_SIZE * p)] =
140 (p == partitionNum - 1 ? 0x80 : 0);
144 if (result) {
145 SetFilePointer(drive, 0, NULL, FILE_BEGIN);
147 if (WriteFile(drive, sector, sizeof(sector), &howMany, NULL) == 0) {
148 error("Writing MBR");
149 result = FALSE;
150 } else if (howMany != sizeof(sector)) {
151 fprintf(stderr,
152 "Error: WriteFile on drive only wrote %d of %d bytes\n",
153 (int)howMany, sizeof(sector));
154 result = FALSE;
158 if (!CloseHandle(drive)) {
159 error("CloseFile on drive");
160 result = FALSE;
164 return (result);
167 /* End stuff for MBR code */
169 const char *program; /* Name of program */
170 const char *drive; /* Drive to install to */
173 * Check Windows version.
175 * On Windows Me/98/95 you cannot open a directory, physical disk, or
176 * volume using CreateFile.
178 int checkver(void)
180 OSVERSIONINFO osvi;
182 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
183 GetVersionEx(&osvi);
185 return (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
186 ((osvi.dwMajorVersion > 4) ||
187 ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)));
191 * Windows error function
193 void error(char *msg)
195 LPVOID lpMsgBuf;
197 /* Format the Windows error message */
198 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
199 (LPTSTR) & lpMsgBuf, 0, NULL);
201 /* Print it */
202 fprintf(stderr, "%s: %s", msg, (char *)lpMsgBuf);
204 /* Free the buffer */
205 LocalFree(lpMsgBuf);
209 * Wrapper for ReadFile suitable for libfat
211 int libfat_readfile(intptr_t pp, void *buf, size_t secsize,
212 libfat_sector_t sector)
214 uint64_t offset = (uint64_t) sector * secsize;
215 LONG loword = (LONG) offset;
216 LONG hiword = (LONG) (offset >> 32);
217 LONG hiwordx = hiword;
218 DWORD bytes_read;
220 if (SetFilePointer((HANDLE) pp, loword, &hiwordx, FILE_BEGIN) != loword ||
221 hiword != hiwordx ||
222 !ReadFile((HANDLE) pp, buf, secsize, &bytes_read, NULL) ||
223 bytes_read != secsize) {
224 fprintf(stderr, "Cannot read sector %u\n", sector);
225 exit(1);
228 return secsize;
231 noreturn usage(void)
233 fprintf(stderr,
234 "Usage: syslinux.exe [-sfmar][-d directory] <drive>: [bootsecfile]\n");
235 exit(1);
238 int main(int argc, char *argv[])
240 HANDLE f_handle, d_handle;
241 DWORD bytes_read;
242 DWORD bytes_written;
243 DWORD drives;
244 UINT drive_type;
246 static unsigned char sectbuf[SECTOR_SIZE];
247 char **argp, *opt;
248 static char drive_name[] = "\\\\.\\?:";
249 static char drive_root[] = "?:\\";
250 static char ldlinux_name[] = "?:\\ldlinux.sys";
251 const char *errmsg;
252 struct libfat_filesystem *fs;
253 libfat_sector_t s, *secp;
254 libfat_sector_t *sectors;
255 int ldlinux_sectors;
256 uint32_t ldlinux_cluster;
257 int nsectors;
258 const char *bootsecfile = NULL;
259 const char *subdir = NULL;
261 int force = 0; /* -f (force) option */
262 int mbr = 0; /* -m (MBR) option */
263 int setactive = 0; /* -a (set partition active) */
264 int stupid = 0; /* -s (stupid) option */
265 int raid_mode = 0; /* -r (RAID) option */
267 (void)argc;
269 if (!checkver()) {
270 fprintf(stderr,
271 "You need to be running at least Windows NT; use syslinux.com instead.\n");
272 exit(1);
275 program = argv[0];
276 drive = NULL;
278 for (argp = argv + 1; *argp; argp++) {
279 if (**argp == '-') {
280 opt = *argp + 1;
281 if (!*opt)
282 usage();
284 while (*opt) {
285 switch (*opt) {
286 case 's': /* Use "safe, slow and stupid" code */
287 stupid = 1;
288 break;
289 case 'r': /* RAID mode */
290 raid_mode = 1;
291 break;
292 case 'f': /* Force install */
293 force = 1;
294 break;
295 case 'm': /* Install MBR */
296 mbr = 1;
297 break;
298 case 'a': /* Mark this partition active */
299 setactive = 1;
300 break;
301 case 'd':
302 if (argp[1])
303 subdir = *++argp;
304 break;
305 default:
306 usage();
307 break;
309 opt++;
311 } else {
312 if (bootsecfile)
313 usage();
314 else if (drive)
315 bootsecfile = *argp;
316 else
317 drive = *argp;
321 if (!drive || !isalpha(drive[0]) || drive[1] != ':' || drive[2])
322 usage();
324 /* Test if drive exists */
325 drives = GetLogicalDrives();
326 if (!(drives & (1 << (tolower(drive[0]) - 'a')))) {
327 fprintf(stderr, "No such drive %c:\n", drive[0]);
328 exit(1);
331 /* Determines the drive type */
332 drive_name[4] = drive[0];
333 ldlinux_name[0] = drive[0];
334 drive_root[0] = drive[0];
335 drive_type = GetDriveType(drive_root);
337 /* Test for removeable media */
338 if ((drive_type == DRIVE_FIXED) && (force == 0)) {
339 fprintf(stderr, "Not a removable drive (use -f to override) \n");
340 exit(1);
343 /* Test for unsupported media */
344 if ((drive_type != DRIVE_FIXED) && (drive_type != DRIVE_REMOVABLE)) {
345 fprintf(stderr, "Unsupported media\n");
346 exit(1);
350 * First open the drive
352 d_handle = CreateFile(drive_name, GENERIC_READ | GENERIC_WRITE,
353 FILE_SHARE_READ | FILE_SHARE_WRITE,
354 NULL, OPEN_EXISTING, 0, NULL);
356 if (d_handle == INVALID_HANDLE_VALUE) {
357 error("Could not open drive");
358 exit(1);
362 * Make sure we can read the boot sector
364 if (!ReadFile(d_handle, sectbuf, SECTOR_SIZE, &bytes_read, NULL)) {
365 error("Reading boot sector");
366 exit(1);
368 if (bytes_read != SECTOR_SIZE) {
369 fprintf(stderr, "Could not read the whole boot sector\n");
370 exit(1);
373 /* Check to see that what we got was indeed an MS-DOS boot sector/superblock */
374 if ((errmsg = syslinux_check_bootsect(sectbuf))) {
375 fprintf(stderr, "%s\n", errmsg);
376 exit(1);
379 /* Change to normal attributes to enable deletion */
380 /* Just ignore error if the file do not exists */
381 SetFileAttributes(ldlinux_name, FILE_ATTRIBUTE_NORMAL);
383 /* Delete the file */
384 /* Just ignore error if the file do not exists */
385 DeleteFile(ldlinux_name);
387 /* Create ldlinux.sys file */
388 f_handle = CreateFile(ldlinux_name, GENERIC_READ | GENERIC_WRITE,
389 FILE_SHARE_READ | FILE_SHARE_WRITE,
390 NULL, CREATE_ALWAYS,
391 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM |
392 FILE_ATTRIBUTE_HIDDEN, NULL);
394 if (f_handle == INVALID_HANDLE_VALUE) {
395 error("Unable to create ldlinux.sys");
396 exit(1);
399 /* Write ldlinux.sys file */
400 if (!WriteFile
401 (f_handle, syslinux_ldlinux, syslinux_ldlinux_len, &bytes_written,
402 NULL)) {
403 error("Could not write ldlinux.sys");
404 exit(1);
407 if (bytes_written != syslinux_ldlinux_len) {
408 fprintf(stderr, "Could not write whole ldlinux.sys\n");
409 exit(1);
412 /* Now flush the media */
413 if (!FlushFileBuffers(f_handle)) {
414 error("FlushFileBuffers failed");
415 exit(1);
418 /* Map the file (is there a better way to do this?) */
419 ldlinux_sectors = (syslinux_ldlinux_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
420 sectors = calloc(ldlinux_sectors, sizeof *sectors);
421 fs = libfat_open(libfat_readfile, (intptr_t) d_handle);
422 ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
423 secp = sectors;
424 nsectors = 0;
425 s = libfat_clustertosector(fs, ldlinux_cluster);
426 while (s && nsectors < ldlinux_sectors) {
427 *secp++ = s;
428 nsectors++;
429 s = libfat_nextsector(fs, s);
431 libfat_close(fs);
434 * Patch ldlinux.sys and the boot sector
436 syslinux_patch(sectors, nsectors, stupid, raid_mode, subdir, NULL);
439 * Rewrite the file
441 if (SetFilePointer(f_handle, 0, NULL, FILE_BEGIN) != 0 ||
442 !WriteFile(f_handle, syslinux_ldlinux, syslinux_ldlinux_len,
443 &bytes_written, NULL)
444 || bytes_written != syslinux_ldlinux_len) {
445 error("Could not write ldlinux.sys");
446 exit(1);
449 /* If desired, fix the MBR */
450 if (mbr || setactive) {
451 STORAGE_DEVICE_NUMBER sdn;
452 if (GetStorageDeviceNumberByHandle(d_handle, &sdn)) {
453 if (!FixMBR(sdn.DeviceNumber, sdn.PartitionNumber, mbr, setactive)) {
454 fprintf(stderr,
455 "Did not successfully update the MBR; continuing...\n");
457 } else {
458 fprintf(stderr,
459 "Could not find device number for updating MBR; continuing...\n");
463 /* Close file */
464 CloseHandle(f_handle);
466 /* Move the file to the desired location */
467 if (subdir) {
468 char new_ldlinux_name[strlen(subdir) + 16];
469 char *cp = new_ldlinux_name + 3;
470 const char *sd;
471 int slash = 1;
473 new_ldlinux_name[0] = drive[0];
474 new_ldlinux_name[1] = ':';
475 new_ldlinux_name[2] = '\\';
477 for (sd = subdir; *sd; sd++) {
478 char c = *sd;
480 if (c == '/' || c == '\\') {
481 if (slash)
482 continue;
483 c = '\\';
484 slash = 1;
485 } else {
486 slash = 0;
489 *cp++ = c;
492 /* Skip if subdirectory == root */
493 if (cp > new_ldlinux_name + 3) {
494 if (!slash)
495 *cp++ = '\\';
497 memcpy(cp, "ldlinux.sys", 12);
499 /* Delete any previous file */
500 SetFileAttributes(new_ldlinux_name, FILE_ATTRIBUTE_NORMAL);
501 DeleteFile(new_ldlinux_name);
502 if (!MoveFile(ldlinux_name, new_ldlinux_name))
503 SetFileAttributes(ldlinux_name, FILE_ATTRIBUTE_READONLY |
504 FILE_ATTRIBUTE_SYSTEM |
505 FILE_ATTRIBUTE_HIDDEN);
506 else
507 SetFileAttributes(new_ldlinux_name, FILE_ATTRIBUTE_READONLY |
508 FILE_ATTRIBUTE_SYSTEM |
509 FILE_ATTRIBUTE_HIDDEN);
513 /* Make the syslinux boot sector */
514 syslinux_make_bootsect(sectbuf);
516 /* Write the syslinux boot sector into the boot sector */
517 if (bootsecfile) {
518 f_handle = CreateFile(bootsecfile, GENERIC_READ | GENERIC_WRITE,
519 FILE_SHARE_READ | FILE_SHARE_WRITE,
520 NULL, CREATE_ALWAYS,
521 FILE_ATTRIBUTE_ARCHIVE, NULL);
522 if (f_handle == INVALID_HANDLE_VALUE) {
523 error("Unable to create bootsector file");
524 exit(1);
526 if (!WriteFile(f_handle, sectbuf, SECTOR_SIZE, &bytes_written, NULL)) {
527 error("Could not write boot sector file");
528 exit(1);
530 CloseHandle(f_handle);
531 } else {
532 SetFilePointer(d_handle, 0, NULL, FILE_BEGIN);
533 WriteFile(d_handle, sectbuf, SECTOR_SIZE, &bytes_written, NULL);
536 if (bytes_written != SECTOR_SIZE) {
537 fprintf(stderr, "Could not write the whole boot sector\n");
538 exit(1);
541 /* Close file */
542 CloseHandle(d_handle);
544 /* Done! */
545 return 0;