source: bootcd/isolinux/syslinux-6.03/win/syslinux.c @ dd1be7c

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

bootstuff

  • Property mode set to 100644
File size: 15.3 KB
Line 
1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2003 Lars Munch Christensen - All Rights Reserved
4 *   Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
5 *
6 *   Based on the Linux installer program for SYSLINUX by H. Peter Anvin
7 *
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.
13 *
14 * ----------------------------------------------------------------------- */
15
16/*
17 * syslinux-mingw.c - Win2k/WinXP installer program for SYSLINUX
18 */
19
20#include <windows.h>
21#include <stdio.h>
22#include <ctype.h>
23#include <getopt.h>
24
25#include "syslinux.h"
26#include "libfat.h"
27#include "setadv.h"
28#include "sysexits.h"
29#include "syslxopt.h"
30#include "syslxfs.h"
31#include "ntfssect.h"
32
33#ifdef __GNUC__
34# define noreturn void __attribute__((noreturn))
35#else
36# define noreturn void
37#endif
38
39void error(char *msg);
40
41/* Begin stuff for MBR code */
42
43#include <winioctl.h>
44
45#define PART_TABLE  0x1be
46#define PART_SIZE   0x10
47#define PART_COUNT  4
48#define PART_ACTIVE 0x80
49
50// The following struct should be in the ntddstor.h file, but I didn't have it.
51// mingw32 has <ddk/ntddstor.h>, but including that file causes all kinds
52// of other failures.  mingw64 has it in <winioctl.h>.
53// Thus, instead of STORAGE_DEVICE_NUMBER, use a lower-case private
54// definition...
55struct storage_device_number {
56    DEVICE_TYPE DeviceType;
57    ULONG DeviceNumber;
58    ULONG PartitionNumber;
59};
60
61BOOL GetStorageDeviceNumberByHandle(HANDLE handle,
62                                    const struct storage_device_number *sdn)
63{
64    BOOL result = FALSE;
65    DWORD count;
66
67    if (DeviceIoControl(handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL,
68                        0, (LPVOID) sdn, sizeof(*sdn), &count, NULL)) {
69        result = TRUE;
70    } else {
71        error("GetDriveNumber: DeviceIoControl failed");
72    }
73
74    return (result);
75}
76
77int GetBytesPerSector(HANDLE drive)
78{
79    int result = 0;
80    DISK_GEOMETRY g;
81    DWORD count;
82
83    if (DeviceIoControl(drive, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
84                        &g, sizeof(g), &count, NULL)) {
85        result = g.BytesPerSector;
86    }
87
88    return (result);
89}
90
91BOOL FixMBR(int driveNum, int partitionNum, int write_mbr, int set_active)
92{
93    BOOL result = TRUE;
94    HANDLE drive;
95
96    char driveName[128];
97
98    sprintf(driveName, "\\\\.\\PHYSICALDRIVE%d", driveNum);
99
100    drive = CreateFile(driveName,
101                       GENERIC_READ | GENERIC_WRITE,
102                       FILE_SHARE_WRITE | FILE_SHARE_READ,
103                       NULL, OPEN_EXISTING, 0, NULL);
104
105    if (drive == INVALID_HANDLE_VALUE) {
106        error("Accessing physical drive");
107        result = FALSE;
108    }
109
110    if (result) {
111        unsigned char sector[SECTOR_SIZE];
112        DWORD howMany;
113
114        if (GetBytesPerSector(drive) != SECTOR_SIZE) {
115            fprintf(stderr,
116                    "Error: Sector size of this drive is %d; must be %d\n",
117                    GetBytesPerSector(drive), SECTOR_SIZE);
118            result = FALSE;
119        }
120
121        if (result) {
122            if (ReadFile(drive, sector, sizeof(sector), &howMany, NULL) == 0) {
123                error("Reading raw drive");
124                result = FALSE;
125            } else if (howMany != sizeof(sector)) {
126                fprintf(stderr,
127                        "Error: ReadFile on drive only got %d of %d bytes\n",
128                        (int)howMany, sizeof(sector));
129                result = FALSE;
130            }
131        }
132        // Copy over the MBR code if specified (-m)
133        if (write_mbr) {
134            if (result) {
135                if (syslinux_mbr_len >= PART_TABLE) {
136                    fprintf(stderr, "Error: MBR will not fit; not writing\n");
137                    result = FALSE;
138                } else {
139                    memcpy(sector, syslinux_mbr, syslinux_mbr_len);
140                }
141            }
142        }
143        // Check that our partition is active if specified (-a)
144        if (set_active) {
145            if (sector[PART_TABLE + (PART_SIZE * (partitionNum - 1))] != 0x80) {
146                int p;
147                for (p = 0; p < PART_COUNT; p++)
148                    sector[PART_TABLE + (PART_SIZE * p)] =
149                        (p == partitionNum - 1 ? 0x80 : 0);
150            }
151        }
152
153        if (result) {
154            SetFilePointer(drive, 0, NULL, FILE_BEGIN);
155
156            if (WriteFile(drive, sector, sizeof(sector), &howMany, NULL) == 0) {
157                error("Writing MBR");
158                result = FALSE;
159            } else if (howMany != sizeof(sector)) {
160                fprintf(stderr,
161                        "Error: WriteFile on drive only wrote %d of %d bytes\n",
162                        (int)howMany, sizeof(sector));
163                result = FALSE;
164            }
165        }
166
167        if (!CloseHandle(drive)) {
168            error("CloseFile on drive");
169            result = FALSE;
170        }
171    }
172
173    return (result);
174}
175
176/* End stuff for MBR code */
177
178const char *program;            /* Name of program */
179
180/*
181 * Check Windows version.
182 *
183 * On Windows Me/98/95 you cannot open a directory, physical disk, or
184 * volume using CreateFile.
185 */
186int checkver(void)
187{
188    OSVERSIONINFO osvi;
189
190    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
191    GetVersionEx(&osvi);
192
193    return (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
194        ((osvi.dwMajorVersion > 4) ||
195         ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)));
196}
197
198/*
199 * Windows error function
200 */
201void error(char *msg)
202{
203    LPVOID lpMsgBuf;
204
205    /* Format the Windows error message */
206    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
207                  (LPTSTR) & lpMsgBuf, 0, NULL);
208
209    /* Print it */
210    fprintf(stderr, "%s: %s", msg, (char *)lpMsgBuf);
211
212    /* Free the buffer */
213    LocalFree(lpMsgBuf);
214}
215
216/*
217 * Wrapper for ReadFile suitable for libfat
218 */
219int libfat_readfile(intptr_t pp, void *buf, size_t secsize,
220                    libfat_sector_t sector)
221{
222    uint64_t offset = (uint64_t) sector * secsize;
223    LONG loword = (LONG) offset;
224    LONG hiword = (LONG) (offset >> 32);
225    LONG hiwordx = hiword;
226    DWORD bytes_read;
227
228    if (SetFilePointer((HANDLE) pp, loword, &hiwordx, FILE_BEGIN) != loword ||
229        hiword != hiwordx ||
230        !ReadFile((HANDLE) pp, buf, secsize, &bytes_read, NULL) ||
231        bytes_read != secsize) {
232        fprintf(stderr, "Cannot read sector %u\n", sector);
233        exit(1);
234    }
235
236    return secsize;
237}
238
239static void move_file(char *pathname, char *filename)
240{
241    char new_name[strlen(opt.directory) + 16];
242    char *cp = new_name + 3;
243    const char *sd;
244    int slash = 1;
245
246    new_name[0] = opt.device[0];
247    new_name[1] = ':';
248    new_name[2] = '\\';
249
250    for (sd = opt.directory; *sd; sd++) {
251        char c = *sd;
252
253        if (c == '/' || c == '\\') {
254            if (slash)
255                continue;
256            c = '\\';
257            slash = 1;
258        } else {
259            slash = 0;
260        }
261
262        *cp++ = c;
263    }
264
265    /* Skip if subdirectory == root */
266    if (cp > new_name + 3) {
267        if (!slash)
268            *cp++ = '\\';
269
270        memcpy(cp, filename, 12);
271
272        /* Delete any previous file */
273        SetFileAttributes(new_name, FILE_ATTRIBUTE_NORMAL);
274        DeleteFile(new_name);
275        if (!MoveFile(pathname, new_name)) {
276            fprintf(stderr,
277                    "Failed to move %s to destination directory: %s\n",
278                    filename, opt.directory);
279
280            SetFileAttributes(pathname, FILE_ATTRIBUTE_READONLY |
281                              FILE_ATTRIBUTE_SYSTEM |
282                              FILE_ATTRIBUTE_HIDDEN);
283        } else
284            SetFileAttributes(new_name, FILE_ATTRIBUTE_READONLY |
285                              FILE_ATTRIBUTE_SYSTEM |
286                              FILE_ATTRIBUTE_HIDDEN);
287    }
288}
289
290int main(int argc, char *argv[])
291{
292    HANDLE f_handle, d_handle;
293    DWORD bytes_read;
294    DWORD bytes_written;
295    DWORD drives;
296    UINT drive_type;
297
298    static unsigned char sectbuf[SECTOR_SIZE];
299    char **argp;
300    static char drive_name[] = "\\\\.\\?:";
301    static char drive_root[] = "?:\\";
302    static char ldlinux_name[] = "?:\\ldlinux.sys";
303    static char ldlinuxc32_name[] = "?:\\ldlinux.c32";
304    const char *errmsg;
305    struct libfat_filesystem *fs;
306    libfat_sector_t s, *secp;
307    libfat_sector_t *sectors;
308    int ldlinux_sectors;
309    uint32_t ldlinux_cluster;
310    int nsectors;
311    int fs_type;
312
313    if (!checkver()) {
314        fprintf(stderr,
315                "You need to be running at least Windows NT; use syslinux.com instead.\n");
316        exit(1);
317    }
318
319    program = argv[0];
320
321    parse_options(argc, argv, MODE_SYSLINUX_DOSWIN);
322
323    if (!opt.device || !isalpha(opt.device[0]) || opt.device[1] != ':'
324        || opt.device[2])
325        usage(EX_USAGE, MODE_SYSLINUX_DOSWIN);
326
327    if (opt.sectors || opt.heads || opt.reset_adv || opt.set_once
328        || (opt.update_only > 0) || opt.menu_save || opt.offset) {
329        fprintf(stderr,
330                "At least one specified option not yet implemented"
331                " for this installer.\n");
332        exit(1);
333    }
334
335    /* Test if drive exists */
336    drives = GetLogicalDrives();
337    if (!(drives & (1 << (tolower(opt.device[0]) - 'a')))) {
338        fprintf(stderr, "No such drive %c:\n", opt.device[0]);
339        exit(1);
340    }
341
342    /* Determines the drive type */
343    drive_name[4] = opt.device[0];
344    ldlinux_name[0] = opt.device[0];
345    ldlinuxc32_name[0] = opt.device[0];
346    drive_root[0] = opt.device[0];
347    drive_type = GetDriveType(drive_root);
348
349    /* Test for removeable media */
350    if ((drive_type == DRIVE_FIXED) && (opt.force == 0)) {
351        fprintf(stderr, "Not a removable drive (use -f to override) \n");
352        exit(1);
353    }
354
355    /* Test for unsupported media */
356    if ((drive_type != DRIVE_FIXED) && (drive_type != DRIVE_REMOVABLE)) {
357        fprintf(stderr, "Unsupported media\n");
358        exit(1);
359    }
360
361    /*
362     * First open the drive
363     */
364    d_handle = CreateFile(drive_name, GENERIC_READ | GENERIC_WRITE,
365                          FILE_SHARE_READ | FILE_SHARE_WRITE,
366                          NULL, OPEN_EXISTING, 0, NULL);
367
368    if (d_handle == INVALID_HANDLE_VALUE) {
369        error("Could not open drive");
370        exit(1);
371    }
372
373    /*
374     * Make sure we can read the boot sector
375     */
376    if (!ReadFile(d_handle, sectbuf, SECTOR_SIZE, &bytes_read, NULL)) {
377        error("Reading boot sector");
378        exit(1);
379    }
380    if (bytes_read != SECTOR_SIZE) {
381        fprintf(stderr, "Could not read the whole boot sector\n");
382        exit(1);
383    }
384
385    /* Check to see that what we got was indeed an FAT/NTFS
386     * boot sector/superblock
387     */
388    if ((errmsg = syslinux_check_bootsect(sectbuf, &fs_type))) {
389        fprintf(stderr, "%s\n", errmsg);
390        exit(1);
391    }
392
393    /* Change to normal attributes to enable deletion */
394    /* Just ignore error if the file do not exists */
395    SetFileAttributes(ldlinux_name, FILE_ATTRIBUTE_NORMAL);
396    SetFileAttributes(ldlinuxc32_name, FILE_ATTRIBUTE_NORMAL);
397
398    /* Delete the file */
399    /* Just ignore error if the file do not exists */
400    DeleteFile(ldlinux_name);
401    DeleteFile(ldlinuxc32_name);
402
403    /* Initialize the ADV -- this should be smarter */
404    syslinux_reset_adv(syslinux_adv);
405
406    /* Create ldlinux.sys file */
407    f_handle = CreateFile(ldlinux_name, GENERIC_READ | GENERIC_WRITE,
408                          FILE_SHARE_READ | FILE_SHARE_WRITE,
409                          NULL, CREATE_ALWAYS,
410                          FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM |
411                          FILE_ATTRIBUTE_HIDDEN, NULL);
412
413    if (f_handle == INVALID_HANDLE_VALUE) {
414        error("Unable to create ldlinux.sys");
415        exit(1);
416    }
417
418    /* Write ldlinux.sys file */
419    if (!WriteFile(f_handle, (const char _force *)syslinux_ldlinux,
420                   syslinux_ldlinux_len, &bytes_written, NULL) ||
421        bytes_written != syslinux_ldlinux_len) {
422        error("Could not write ldlinux.sys");
423        exit(1);
424    }
425    if (!WriteFile(f_handle, syslinux_adv, 2 * ADV_SIZE,
426                   &bytes_written, NULL) ||
427        bytes_written != 2 * ADV_SIZE) {
428        error("Could not write ADV to ldlinux.sys");
429        exit(1);
430    }
431
432    /* Now flush the media */
433    if (!FlushFileBuffers(f_handle)) {
434        error("FlushFileBuffers failed");
435        exit(1);
436    }
437
438    /* Map the file (is there a better way to do this?) */
439    ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE + SECTOR_SIZE - 1)
440        >> SECTOR_SHIFT;
441    sectors = calloc(ldlinux_sectors, sizeof *sectors);
442    if (fs_type == NTFS) {
443        DWORD err;
444        S_NTFSSECT_VOLINFO vol_info;
445        LARGE_INTEGER vcn, lba, len;
446        S_NTFSSECT_EXTENT extent;
447
448        err = NtfsSectGetVolumeInfo(drive_name + 4, &vol_info);
449        if (err != ERROR_SUCCESS) {
450            error("Could not fetch NTFS volume info");
451            exit(1);
452        }
453        secp = sectors;
454        nsectors = 0;
455        for (vcn.QuadPart = 0;
456             NtfsSectGetFileVcnExtent(f_handle, &vcn, &extent) == ERROR_SUCCESS;
457             vcn = extent.NextVcn) {
458            err = NtfsSectLcnToLba(&vol_info, &extent.FirstLcn, &lba);
459            if (err != ERROR_SUCCESS) {
460                error("Could not translate LDLINUX.SYS LCN to disk LBA");
461                exit(1);
462            }
463            lba.QuadPart -= vol_info.PartitionLba.QuadPart;
464            len.QuadPart = ((extent.NextVcn.QuadPart -
465                             extent.FirstVcn.QuadPart) *
466                            vol_info.SectorsPerCluster);
467            while (len.QuadPart-- && nsectors < ldlinux_sectors) {
468                *secp++ = lba.QuadPart++;
469                nsectors++;
470            }
471        }
472        goto map_done;
473    }
474    fs = libfat_open(libfat_readfile, (intptr_t) d_handle);
475    ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
476    secp = sectors;
477    nsectors = 0;
478    s = libfat_clustertosector(fs, ldlinux_cluster);
479    while (s && nsectors < ldlinux_sectors) {
480        *secp++ = s;
481        nsectors++;
482        s = libfat_nextsector(fs, s);
483    }
484    libfat_close(fs);
485map_done:
486
487    /*
488     * Patch ldlinux.sys and the boot sector
489     */
490    syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL);
491
492    /*
493     * Rewrite the file
494     */
495    if (SetFilePointer(f_handle, 0, NULL, FILE_BEGIN) != 0 ||
496        !WriteFile(f_handle, syslinux_ldlinux, syslinux_ldlinux_len,
497                   &bytes_written, NULL)
498        || bytes_written != syslinux_ldlinux_len) {
499        error("Could not write ldlinux.sys");
500        exit(1);
501    }
502
503    /* If desired, fix the MBR */
504    if (opt.install_mbr || opt.activate_partition) {
505        struct storage_device_number sdn;
506        if (GetStorageDeviceNumberByHandle(d_handle, &sdn)) {
507            if (!FixMBR(sdn.DeviceNumber, sdn.PartitionNumber, opt.install_mbr, opt.activate_partition)) {
508                fprintf(stderr,
509                        "Did not successfully update the MBR; continuing...\n");
510            }
511        } else {
512            fprintf(stderr,
513                    "Could not find device number for updating MBR; continuing...\n");
514        }
515    }
516
517    /* Close file */
518    CloseHandle(f_handle);
519
520    /* Move the file to the desired location */
521    if (opt.directory)
522        move_file(ldlinux_name, "ldlinux.sys");
523
524    f_handle = CreateFile(ldlinuxc32_name, GENERIC_READ | GENERIC_WRITE,
525                          FILE_SHARE_READ | FILE_SHARE_WRITE,
526                          NULL, CREATE_ALWAYS,
527                          FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM |
528                          FILE_ATTRIBUTE_HIDDEN, NULL);
529
530    if (f_handle == INVALID_HANDLE_VALUE) {
531        error("Unable to create ldlinux.c32");
532        exit(1);
533    }
534
535    /* Write ldlinux.c32 file */
536    if (!WriteFile(f_handle, (const char _force *)syslinux_ldlinuxc32,
537                   syslinux_ldlinuxc32_len, &bytes_written, NULL) ||
538        bytes_written != syslinux_ldlinuxc32_len) {
539        error("Could not write ldlinux.c32");
540        exit(1);
541    }
542
543    /* Now flush the media */
544    if (!FlushFileBuffers(f_handle)) {
545        error("FlushFileBuffers failed");
546        exit(1);
547    }
548
549    CloseHandle(f_handle);
550
551    /* Move the file to the desired location */
552    if (opt.directory)
553        move_file(ldlinuxc32_name, "ldlinux.c32");
554
555    /* Make the syslinux boot sector */
556    syslinux_make_bootsect(sectbuf, fs_type);
557
558    /* Write the syslinux boot sector into the boot sector */
559    if (opt.bootsecfile) {
560        f_handle = CreateFile(opt.bootsecfile, GENERIC_READ | GENERIC_WRITE,
561                              FILE_SHARE_READ | FILE_SHARE_WRITE,
562                              NULL, CREATE_ALWAYS,
563                              FILE_ATTRIBUTE_ARCHIVE, NULL);
564        if (f_handle == INVALID_HANDLE_VALUE) {
565            error("Unable to create bootsector file");
566            exit(1);
567        }
568        if (!WriteFile(f_handle, sectbuf, SECTOR_SIZE, &bytes_written, NULL)) {
569            error("Could not write boot sector file");
570            exit(1);
571        }
572        CloseHandle(f_handle);
573    } else {
574        SetFilePointer(d_handle, 0, NULL, FILE_BEGIN);
575        WriteFile(d_handle, sectbuf, SECTOR_SIZE, &bytes_written, NULL);
576    }
577
578    if (bytes_written != SECTOR_SIZE) {
579        fprintf(stderr, "Could not write the whole boot sector\n");
580        exit(1);
581    }
582
583    /* Close file */
584    CloseHandle(d_handle);
585
586    /* Done! */
587    return 0;
588}
Note: See TracBrowser for help on using the repository browser.