123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- /*
- * SRMbootFAT - SRM boot block composer for FAT filesystems.
- * Copyright (C) 1998 Nikita Schmidt <cetus@snowball.ucd.ie>
- * msdos.h is Copyright (C) 1995 Alain Knaff.
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include "msdos.h"
- /* This should test for little-endianness, but why bother,
- the whole thing is Alpha-specific anyway. */
- #ifdef __alpha__ /* Little endian */
- #define WORD(x) (*(u_int16_t *)(x))
- #define DWORD(x) (*(u_int32_t *)(x))
- #else /* Big endian; in fact, generic stuff */
- #define WORD _WORD
- #define DWORD _DWORD
- #endif
- union full_bootsector {
- struct bootsector dos;
- struct {
- unsigned char textlabel[64];
- unsigned char disklabel[276];
- unsigned char unused[140];
- u_int64_t count, start, flags;
- u_int64_t checksum;
- } srm;
- struct {
- u_int64_t contents[63];
- u_int64_t checksum;
- } check;
- };
- #ifdef __alpha__ /* Should be test for little endian */
- unsigned int get_fat_entry (unsigned char *fat, int fatbits, unsigned entry)
- {
- unsigned i, a, b;
- /* No check for fat boundaries... */
- switch (fatbits) {
- case 12:
- i = ((entry *= 3) & 7) << 2; /* Number of bits to shift */
- a = ((u_int32_t *)fat)[entry >>= 3];
- b = ((u_int32_t *)fat)[entry + 1]; /* May be outside FAT */
- return ((a >> i) | (b << (32 - i))) & 0xFFF;
- case 16:
- return ((u_int16_t *)fat)[entry];
- }
- fprintf (stderr, "Unknown FAT type - FAT-%d\n", fatbits);
- exit (3);
- }
- #else
- // Portable Version from Falk Hueffner <falk.hueffner@student.uni-tuebingen.de>
- unsigned int get_fat_entry (unsigned char *fat, int fatbits, unsigned entry)
- {
- unsigned i, a, b;
- /* No check for fat boundaries... */
- switch (fatbits) {
- case 12:
- i = ((entry *= 3) & 7) << 2; /* Number of bits to shift */
- entry >>= 3;
- a = DWORD(fat + 4 * entry);
- b = DWORD(fat + 4 * entry + 4);
- return ((a >> i) | (b << (32 - i))) & 0xFFF;
- case 16:
- return WORD(fat + 2 * entry);
- }
- fprintf (stderr, "Unknown FAT type - FAT-%d\n", fatbits);
- exit (3);
- }
- #endif
- int main (int argc, char *argv[])
- {
- int f;
- int i;
- char *p;
- union full_bootsector boot;
- unsigned secsize; /* Bytes per sector, hopefully 512 */
- unsigned clusize; /* Cluster size in sectors */
- unsigned fatstart; /* Number of reserved (boot) sectors */
- unsigned nfat; /* Number of FAT tables, hopefully 2 */
- unsigned dirents; /* Number of directory slots */
- unsigned psect; /* Total sectors on disk */
- unsigned media; /* Media descriptor=first byte of FAT */
- unsigned fatsize; /* Sectors in FAT */
- unsigned fatbits; /* FAT type (bits per entry) */
- unsigned char *fat;
- struct directory *rootdir;
- unsigned start; /* Starting cluster of the boot file */
- unsigned size; /* Boot file size */
- unsigned fat_end;
- unsigned j;
- u_int64_t checksum;
- char dosname[12];
- if (argc != 3)
- return printf ("Usage: srmbootfat <filesystem image file> <boot file>\n"), 1;
- if ((f = open (argv[1], O_RDWR)) < 0)
- return perror (argv[1]), 2;
- if (read (f, &boot, sizeof boot) != sizeof boot)
- return fprintf (stderr, "Can't read boot sector from %s\n", argv[1]), 2;
- secsize = _WORD (boot.dos.secsiz);
- clusize = boot.dos.clsiz;
- fatstart = WORD (boot.dos.nrsvsect);
- nfat = boot.dos.nfat;
- dirents = _WORD (boot.dos.dirents);
- psect = _WORD (boot.dos.psect);
- media = boot.dos.descr;
- fatsize = WORD (boot.dos.fatlen);
- if ((media & ~7) == 0xf8) {
- i = media & 3;
- clusize = old_dos[i].cluster_size;
- fatstart = 1;
- fatsize = old_dos[i].fat_len;
- dirents = old_dos[i].dir_len * (512 / MDIR_SIZE);
- nfat = 2;
- fatbits = 12;
- } else if (strncmp (boot.dos.ext.old.fat_type, "FAT12", 5) == 0)
- fatbits = 12;
- else if (strncmp (boot.dos.ext.old.fat_type, "FAT16", 5) == 0)
- fatbits = 16;
- else return fprintf (stderr, "%s: unrecognisable FAT type\n", argv[1]),
- 3;
- #ifdef DEBUG
- printf ("%s: filesystem type is FAT-%d\n", argv[1], fatbits);
- #endif
- if (secsize != 512)
- return fprintf (stderr, "%s: sector size is %d; "
- "unfortunately, this is not supported\n",
- argv[1], secsize),
- 3;
- if (nfat != 1 && nfat != 2)
- fprintf (stderr,
- "%s: warning: weird number of FAT tables (%d)\n",
- argv[1], nfat);
- fat = malloc (i = fatsize * secsize);
- rootdir = malloc (dirents * MDIR_SIZE);
- if (!fat || !rootdir)
- return fprintf (stderr, "Not enough memory\n"), 2;
- if (lseek (f, fatstart * secsize, SEEK_SET) == -1
- || read (f, fat, i) != i
- || lseek (f, (nfat - 1) * i, SEEK_CUR) == -1
- || read (f, rootdir, dirents * MDIR_SIZE) != dirents * MDIR_SIZE)
- return perror (argv[1]), 2;
- memset (dosname, ' ', sizeof dosname);
- i = 0;
- for (p = argv[2]; *p; p++)
- if (*p == '.')
- i = 8;
- else if (i < sizeof dosname)
- dosname[i++] = toupper (*p);
- for (i = 0; i < dirents; i++)
- if (memcmp (rootdir[i].name, dosname, 11) == 0
- && (rootdir[i].attr & (8 | 16)) == 0)
- break;
- if (i == dirents)
- return fprintf (stderr,
- "Can't find %s in the root directory in %s\n",
- argv[2], argv[1]), 4;
- start = WORD (rootdir[i].start);
- size = DWORD (rootdir[i].size);
- if (start * fatbits > fatsize * secsize * 8)
- return fprintf (stderr,
- "%s: first cluster (%u) is beyond the end of FAT",
- argv[2], start), 3;
- /* Fill in the bootstrap information */
- size = (size + secsize - 1) / secsize; /* Size is now in sectors */
- boot.srm.start = (start - 2) * clusize + fatstart + nfat * fatsize
- + dirents / (512 / MDIR_SIZE);
- boot.srm.count = size;
- boot.srm.flags = 0;
- /* Check that the image is contiguous */
- i = 1;
- fat_end = (1 << fatbits) - 9; /* 0xFF7, 0xFFF7 or whatever */
- while ((j = get_fat_entry (fat, fatbits, start)) < fat_end) {
- if (j != start + 1)
- return fprintf (stderr,
- "Unfortunately, %s is not contiguous\n",
- argv[2]), 4;
- start = j;
- i++;
- }
- if ((size + clusize - 1) / clusize != i)
- return fprintf (stderr, "Inconsistency: file size contradicts "
- "with the number of clusters allocated\n"), 3;
- /* Put the checksum and write the boot sector. */
- checksum = 0;
- for (i = 0; i < 63; i++)
- checksum += boot.check.contents[i];
- boot.check.checksum = checksum;
- printf ("Writing SRM boot block: starting sector %u, block count %u\n",
- (unsigned)boot.srm.start, (unsigned)boot.srm.count);
- if (lseek (f, 0, SEEK_SET) == -1
- || write (f, &boot, sizeof boot) != sizeof boot)
- return perror (argv[2]), 2;
- close (f);
- return 0;
- }
- struct OldDos_t old_dos[]={
- { 40, 9, 1, 4, 1, 2, 0xfc },
- { 40, 9, 2, 7, 2, 2, 0xfd },
- { 40, 8, 1, 4, 1, 1, 0xfe },
- { 40, 8, 2, 7, 2, 1, 0xff },
- { 80, 9, 2, 7, 2, 3, 0xf9 },
- { 80, 15, 2,14, 1, 7, 0xf9 },
- { 80, 18, 2,14, 1, 9, 0xf0 },
- { 80, 36, 2,15, 2, 9, 0xf0 },
- { 1, 8, 1, 1, 1, 1, 0xf0 }
- };
|