srmbootfat.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * SRMbootFAT - SRM boot block composer for FAT filesystems.
  3. * Copyright (C) 1998 Nikita Schmidt <cetus@snowball.ucd.ie>
  4. * msdos.h is Copyright (C) 1995 Alain Knaff.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <stdio.h>
  17. #include <unistd.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <fcntl.h>
  21. #include <ctype.h>
  22. #include <sys/types.h>
  23. #include "msdos.h"
  24. /* This should test for little-endianness, but why bother,
  25. the whole thing is Alpha-specific anyway. */
  26. #ifdef __alpha__ /* Little endian */
  27. #define WORD(x) (*(u_int16_t *)(x))
  28. #define DWORD(x) (*(u_int32_t *)(x))
  29. #else /* Big endian; in fact, generic stuff */
  30. #define WORD _WORD
  31. #define DWORD _DWORD
  32. #endif
  33. union full_bootsector {
  34. struct bootsector dos;
  35. struct {
  36. unsigned char textlabel[64];
  37. unsigned char disklabel[276];
  38. unsigned char unused[140];
  39. u_int64_t count, start, flags;
  40. u_int64_t checksum;
  41. } srm;
  42. struct {
  43. u_int64_t contents[63];
  44. u_int64_t checksum;
  45. } check;
  46. };
  47. #ifdef __alpha__ /* Should be test for little endian */
  48. unsigned int get_fat_entry (unsigned char *fat, int fatbits, unsigned entry)
  49. {
  50. unsigned i, a, b;
  51. /* No check for fat boundaries... */
  52. switch (fatbits) {
  53. case 12:
  54. i = ((entry *= 3) & 7) << 2; /* Number of bits to shift */
  55. a = ((u_int32_t *)fat)[entry >>= 3];
  56. b = ((u_int32_t *)fat)[entry + 1]; /* May be outside FAT */
  57. return ((a >> i) | (b << (32 - i))) & 0xFFF;
  58. case 16:
  59. return ((u_int16_t *)fat)[entry];
  60. }
  61. fprintf (stderr, "Unknown FAT type - FAT-%d\n", fatbits);
  62. exit (3);
  63. }
  64. #else
  65. // Portable Version from Falk Hueffner <falk.hueffner@student.uni-tuebingen.de>
  66. unsigned int get_fat_entry (unsigned char *fat, int fatbits, unsigned entry)
  67. {
  68. unsigned i, a, b;
  69. /* No check for fat boundaries... */
  70. switch (fatbits) {
  71. case 12:
  72. i = ((entry *= 3) & 7) << 2; /* Number of bits to shift */
  73. entry >>= 3;
  74. a = DWORD(fat + 4 * entry);
  75. b = DWORD(fat + 4 * entry + 4);
  76. return ((a >> i) | (b << (32 - i))) & 0xFFF;
  77. case 16:
  78. return WORD(fat + 2 * entry);
  79. }
  80. fprintf (stderr, "Unknown FAT type - FAT-%d\n", fatbits);
  81. exit (3);
  82. }
  83. #endif
  84. int main (int argc, char *argv[])
  85. {
  86. int f;
  87. int i;
  88. char *p;
  89. union full_bootsector boot;
  90. unsigned secsize; /* Bytes per sector, hopefully 512 */
  91. unsigned clusize; /* Cluster size in sectors */
  92. unsigned fatstart; /* Number of reserved (boot) sectors */
  93. unsigned nfat; /* Number of FAT tables, hopefully 2 */
  94. unsigned dirents; /* Number of directory slots */
  95. unsigned psect; /* Total sectors on disk */
  96. unsigned media; /* Media descriptor=first byte of FAT */
  97. unsigned fatsize; /* Sectors in FAT */
  98. unsigned fatbits; /* FAT type (bits per entry) */
  99. unsigned char *fat;
  100. struct directory *rootdir;
  101. unsigned start; /* Starting cluster of the boot file */
  102. unsigned size; /* Boot file size */
  103. unsigned fat_end;
  104. unsigned j;
  105. u_int64_t checksum;
  106. char dosname[12];
  107. if (argc != 3)
  108. return printf ("Usage: srmbootfat <filesystem image file> <boot file>\n"), 1;
  109. if ((f = open (argv[1], O_RDWR)) < 0)
  110. return perror (argv[1]), 2;
  111. if (read (f, &boot, sizeof boot) != sizeof boot)
  112. return fprintf (stderr, "Can't read boot sector from %s\n", argv[1]), 2;
  113. secsize = _WORD (boot.dos.secsiz);
  114. clusize = boot.dos.clsiz;
  115. fatstart = WORD (boot.dos.nrsvsect);
  116. nfat = boot.dos.nfat;
  117. dirents = _WORD (boot.dos.dirents);
  118. psect = _WORD (boot.dos.psect);
  119. media = boot.dos.descr;
  120. fatsize = WORD (boot.dos.fatlen);
  121. if ((media & ~7) == 0xf8) {
  122. i = media & 3;
  123. clusize = old_dos[i].cluster_size;
  124. fatstart = 1;
  125. fatsize = old_dos[i].fat_len;
  126. dirents = old_dos[i].dir_len * (512 / MDIR_SIZE);
  127. nfat = 2;
  128. fatbits = 12;
  129. } else if (strncmp (boot.dos.ext.old.fat_type, "FAT12", 5) == 0)
  130. fatbits = 12;
  131. else if (strncmp (boot.dos.ext.old.fat_type, "FAT16", 5) == 0)
  132. fatbits = 16;
  133. else return fprintf (stderr, "%s: unrecognisable FAT type\n", argv[1]),
  134. 3;
  135. #ifdef DEBUG
  136. printf ("%s: filesystem type is FAT-%d\n", argv[1], fatbits);
  137. #endif
  138. if (secsize != 512)
  139. return fprintf (stderr, "%s: sector size is %d; "
  140. "unfortunately, this is not supported\n",
  141. argv[1], secsize),
  142. 3;
  143. if (nfat != 1 && nfat != 2)
  144. fprintf (stderr,
  145. "%s: warning: weird number of FAT tables (%d)\n",
  146. argv[1], nfat);
  147. fat = malloc (i = fatsize * secsize);
  148. rootdir = malloc (dirents * MDIR_SIZE);
  149. if (!fat || !rootdir)
  150. return fprintf (stderr, "Not enough memory\n"), 2;
  151. if (lseek (f, fatstart * secsize, SEEK_SET) == -1
  152. || read (f, fat, i) != i
  153. || lseek (f, (nfat - 1) * i, SEEK_CUR) == -1
  154. || read (f, rootdir, dirents * MDIR_SIZE) != dirents * MDIR_SIZE)
  155. return perror (argv[1]), 2;
  156. memset (dosname, ' ', sizeof dosname);
  157. i = 0;
  158. for (p = argv[2]; *p; p++)
  159. if (*p == '.')
  160. i = 8;
  161. else if (i < sizeof dosname)
  162. dosname[i++] = toupper (*p);
  163. for (i = 0; i < dirents; i++)
  164. if (memcmp (rootdir[i].name, dosname, 11) == 0
  165. && (rootdir[i].attr & (8 | 16)) == 0)
  166. break;
  167. if (i == dirents)
  168. return fprintf (stderr,
  169. "Can't find %s in the root directory in %s\n",
  170. argv[2], argv[1]), 4;
  171. start = WORD (rootdir[i].start);
  172. size = DWORD (rootdir[i].size);
  173. if (start * fatbits > fatsize * secsize * 8)
  174. return fprintf (stderr,
  175. "%s: first cluster (%u) is beyond the end of FAT",
  176. argv[2], start), 3;
  177. /* Fill in the bootstrap information */
  178. size = (size + secsize - 1) / secsize; /* Size is now in sectors */
  179. boot.srm.start = (start - 2) * clusize + fatstart + nfat * fatsize
  180. + dirents / (512 / MDIR_SIZE);
  181. boot.srm.count = size;
  182. boot.srm.flags = 0;
  183. /* Check that the image is contiguous */
  184. i = 1;
  185. fat_end = (1 << fatbits) - 9; /* 0xFF7, 0xFFF7 or whatever */
  186. while ((j = get_fat_entry (fat, fatbits, start)) < fat_end) {
  187. if (j != start + 1)
  188. return fprintf (stderr,
  189. "Unfortunately, %s is not contiguous\n",
  190. argv[2]), 4;
  191. start = j;
  192. i++;
  193. }
  194. if ((size + clusize - 1) / clusize != i)
  195. return fprintf (stderr, "Inconsistency: file size contradicts "
  196. "with the number of clusters allocated\n"), 3;
  197. /* Put the checksum and write the boot sector. */
  198. checksum = 0;
  199. for (i = 0; i < 63; i++)
  200. checksum += boot.check.contents[i];
  201. boot.check.checksum = checksum;
  202. printf ("Writing SRM boot block: starting sector %u, block count %u\n",
  203. (unsigned)boot.srm.start, (unsigned)boot.srm.count);
  204. if (lseek (f, 0, SEEK_SET) == -1
  205. || write (f, &boot, sizeof boot) != sizeof boot)
  206. return perror (argv[2]), 2;
  207. close (f);
  208. return 0;
  209. }
  210. struct OldDos_t old_dos[]={
  211. { 40, 9, 1, 4, 1, 2, 0xfc },
  212. { 40, 9, 2, 7, 2, 2, 0xfd },
  213. { 40, 8, 1, 4, 1, 1, 0xfe },
  214. { 40, 8, 2, 7, 2, 1, 0xff },
  215. { 80, 9, 2, 7, 2, 3, 0xf9 },
  216. { 80, 15, 2,14, 1, 7, 0xf9 },
  217. { 80, 18, 2,14, 1, 9, 0xf0 },
  218. { 80, 36, 2,15, 2, 9, 0xf0 },
  219. { 1, 8, 1, 1, 1, 1, 0xf0 }
  220. };