"SfR Fresh" - the SfR Freeware/Shareware Archive 
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /* boot.c - Read and analyze ia PC/MS-DOS boot sector */
2
3 /* Written 1993 by Werner Almesberger */
4
5 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
6 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <sys/types.h>
11
12 #include "common.h"
13 #include "dosfsck.h"
14 #include "io.h"
15 #include "boot.h"
16
17
18 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
19 /* don't divide by zero */
20
21 static struct {
22 __u8 media;
23 char *descr;
24 } mediabytes[] = {
25 { 0xf0, "5.25\" or 3.5\" HD floppy" },
26 { 0xf8, "hard disk" },
27 { 0xf9, "3,5\" 720k floppy 2s/80tr/9sec or "
28 "5.25\" 1.2M floppy 2s/80tr/15sec" },
29 { 0xfa, "5.25\" 320k floppy 1s/80tr/8sec" },
30 { 0xfb, "3.5\" 640k floppy 2s/80tr/8sec" },
31 { 0xfc, "5.25\" 180k floppy 1s/40tr/9sec" },
32 { 0xfd, "5.25\" 360k floppy 2s/40tr/9sec" },
33 { 0xfe, "5.25\" 160k floppy 1s/40tr/8sec" },
34 { 0xff, "5.25\" 320k floppy 2s/40tr/8sec" },
35 };
36
37 #if defined __alpha || defined __ia64__ || defined __s390x__ || defined __x86_64__ || defined __ppc64__
38 /* Unaligned fields must first be copied byte-wise */
39 #define GET_UNALIGNED_W(f) \
40 ({ \
41 unsigned short __v; \
42 memcpy( &__v, &f, sizeof(__v) ); \
43 CF_LE_W( *(unsigned short *)&f ); \
44 })
45 #else
46 #define GET_UNALIGNED_W(f) CF_LE_W( *(unsigned short *)&f )
47 #endif
48
49
50 static char *get_media_descr( unsigned char media )
51 {
52 int i;
53
54 for( i = 0; i < sizeof(mediabytes)/sizeof(*mediabytes); ++i ) {
55 if (mediabytes[i].media == media)
56 return( mediabytes[i].descr );
57 }
58 return( "undefined" );
59 }
60
61 static void dump_boot(DOS_FS *fs,struct boot_sector *b,unsigned lss)
62 {
63 unsigned short sectors;
64
65 printf("Boot sector contents:\n");
66 if (!atari_format) {
67 char id[9];
68 strncpy(id,b->system_id,8);
69 id[8] = 0;
70 printf("System ID \"%s\"\n",id);
71 }
72 else {
73 /* On Atari, a 24 bit serial number is stored at offset 8 of the boot
74 * sector */
75 printf("Serial number 0x%x\n",
76 b->system_id[5] | (b->system_id[6]<<8) | (b->system_id[7]<<16));
77 }
78 printf("Media byte 0x%02x (%s)\n",b->media,get_media_descr(b->media));
79 printf("%10d bytes per logical sector\n",GET_UNALIGNED_W(b->sector_size));
80 printf("%10d bytes per cluster\n",fs->cluster_size);
81 printf("%10d reserved sector%s\n",CF_LE_W(b->reserved),
82 CF_LE_W(b->reserved) == 1 ? "" : "s");
83 printf("First FAT starts at byte %llu (sector %llu)\n",
84 (unsigned long long)fs->fat_start,
85 (unsigned long long)fs->fat_start/lss);
86 printf("%10d FATs, %d bit entries\n",b->fats,fs->fat_bits);
87 printf("%10d bytes per FAT (= %u sectors)\n",fs->fat_size,
88 fs->fat_size/lss);
89 if (!fs->root_cluster) {
90 printf("Root directory starts at byte %llu (sector %llu)\n",
91 (unsigned long long)fs->root_start,
92 (unsigned long long)fs->root_start/lss);
93 printf("%10d root directory entries\n",fs->root_entries);
94 }
95 else {
96 printf( "Root directory start at cluster %lu (arbitrary size)\n",
97 fs->root_cluster);
98 }
99 printf("Data area starts at byte %llu (sector %llu)\n",
100 (unsigned long long)fs->data_start,
101 (unsigned long long)fs->data_start/lss);
102 printf("%10lu data clusters (%llu bytes)\n",fs->clusters,
103 (unsigned long long)fs->clusters*fs->cluster_size);
104 printf("%u sectors/track, %u heads\n",CF_LE_W(b->secs_track),
105 CF_LE_W(b->heads));
106 printf("%10u hidden sectors\n",
107 atari_format ?
108 /* On Atari, the hidden field is only 16 bit wide and unused */
109 (((unsigned char *)&b->hidden)[0] |
110 ((unsigned char *)&b->hidden)[1] << 8) :
111 CF_LE_L(b->hidden));
112 sectors = GET_UNALIGNED_W( b->sectors );
113 printf("%10u sectors total\n", sectors ? sectors : CF_LE_L(b->total_sect));
114 }
115
116 static void check_backup_boot(DOS_FS *fs, struct boot_sector *b, int lss)
117 {
118 struct boot_sector b2;
119
120 if (!fs->backupboot_start) {
121 printf( "There is no backup boot sector.\n" );
122 if (CF_LE_W(b->reserved) < 3) {
123 printf( "And there is no space for creating one!\n" );
124 return;
125 }
126 if (interactive)
127 printf( "1) Create one\n2) Do without a backup\n" );
128 else printf( " Auto-creating backup boot block.\n" );
129 if (!interactive || get_key("12","?") == '1') {
130 int bbs;
131 /* The usual place for the backup boot sector is sector 6. Choose
132 * that or the last reserved sector. */
133 if (CF_LE_W(b->reserved) >= 7 && CF_LE_W(b->info_sector) != 6)
134 bbs = 6;
135 else {
136 bbs = CF_LE_W(b->reserved) - 1;
137 if (bbs == CF_LE_W(b->info_sector))
138 --bbs; /* this is never 0, as we checked reserved >= 3! */
139 }
140 fs->backupboot_start = bbs*lss;
141 b->backup_boot = CT_LE_W(bbs);
142 fs_write(fs->backupboot_start,sizeof(*b),b);
143 fs_write((off_t)offsetof(struct boot_sector,backup_boot),
144 sizeof(b->backup_boot),&b->backup_boot);
145 printf( "Created backup of boot sector in sector %d\n", bbs );
146 return;
147 }
148 else return;
149 }
150
151 fs_read(fs->backupboot_start,sizeof(b2),&b2);
152 if (memcmp(b,&b2,sizeof(b2)) != 0) {
153 /* there are any differences */
154 __u8 *p, *q;
155 int i, pos, first = 1;
156 char buf[20];
157
158 printf( "There are differences between boot sector and its backup.\n" );
159 printf( "Differences: (offset:original/backup)\n " );
160 pos = 2;
161 for( p = (__u8 *)b, q = (__u8 *)&b2, i = 0; i < sizeof(b2);
162 ++p, ++q, ++i ) {
163 if (*p != *q) {
164 sprintf( buf, "%s%u:%02x/%02x", first ? "" : ", ",
165 (unsigned)(p-(__u8 *)b), *p, *q );
166 if (pos + strlen(buf) > 78) printf( "\n " ), pos = 2;
167 printf( "%s", buf );
168 pos += strlen(buf);
169 first = 0;
170 }
171 }
172 printf( "\n" );
173
174 if (interactive)
175 printf( "1) Copy original to backup\n"
176 "2) Copy backup to original\n"
177 "3) No action\n" );
178 else printf( " Not automatically fixing this.\n" );
179 switch (interactive ? get_key("123","?") : '3') {
180 case '1':
181 fs_write(fs->backupboot_start,sizeof(*b),b);
182 break;
183 case '2':
184 fs_write(0,sizeof(b2),&b2);
185 break;
186 default:
187 break;
188 }
189 }
190 }
191
192 static void init_fsinfo(struct info_sector *i)
193 {
194 i->magic = CT_LE_L(0x41615252);
195 i->signature = CT_LE_L(0x61417272);
196 i->free_clusters = CT_LE_L(-1);
197 i->next_cluster = CT_LE_L(2);
198 i->boot_sign = CT_LE_W(0xaa55);
199 }
200
201 static void read_fsinfo(DOS_FS *fs, struct boot_sector *b,int lss)
202 {
203 struct info_sector i;
204
205 if (!b->info_sector) {
206 printf( "No FSINFO sector\n" );
207 if (interactive)
208 printf( "1) Create one\n2) Do without FSINFO\n" );
209 else printf( " Not automatically creating it.\n" );
210 if (interactive && get_key("12","?") == '1') {
211 /* search for a free reserved sector (not boot sector and not
212 * backup boot sector) */
213 __u32 s;
214 for( s = 1; s < CF_LE_W(b->reserved); ++s )
215 if (s != CF_LE_W(b->backup_boot)) break;
216 if (s > 0 && s < CF_LE_W(b->reserved)) {
217 init_fsinfo(&i);
218 fs_write((off_t)s*lss,sizeof(i),&i);
219 b->info_sector = CT_LE_W(s);
220 fs_write((off_t)offsetof(struct boot_sector,info_sector),
221 sizeof(b->info_sector),&b->info_sector);
222 if (fs->backupboot_start)
223 fs_write(fs->backupboot_start+
224 offsetof(struct boot_sector,info_sector),
225 sizeof(b->info_sector),&b->info_sector);
226 }
227 else {
228 printf( "No free reserved sector found -- "
229 "no space for FSINFO sector!\n" );
230 return;
231 }
232 }
233 else return;
234 }
235
236 fs->fsinfo_start = CF_LE_W(b->info_sector)*lss;
237 fs_read(fs->fsinfo_start,sizeof(i),&i);
238
239 if (i.magic != CT_LE_L(0x41615252) ||
240 i.signature != CT_LE_L(0x61417272) ||
241 i.boot_sign != CT_LE_W(0xaa55)) {
242 printf( "FSINFO sector has bad magic number(s):\n" );
243 if (i.magic != CT_LE_L(0x41615252))
244 printf( " Offset %llu: 0x%08x != expected 0x%08x\n",
245 (unsigned long long)offsetof(struct info_sector,magic),
246 CF_LE_L(i.magic),0x41615252);
247 if (i.signature != CT_LE_L(0x61417272))
248 printf( " Offset %llu: 0x%08x != expected 0x%08x\n",
249 (unsigned long long)offsetof(struct info_sector,signature),
250 CF_LE_L(i.signature),0x61417272);
251 if (i.boot_sign != CT_LE_W(0xaa55))
252 printf( " Offset %llu: 0x%04x != expected 0x%04x\n",
253 (unsigned long long)offsetof(struct info_sector,boot_sign),
254 CF_LE_W(i.boot_sign),0xaa55);
255 if (interactive)
256 printf( "1) Correct\n2) Don't correct (FSINFO invalid then)\n" );
257 else printf( " Auto-correcting it.\n" );
258 if (!interactive || get_key("12","?") == '1') {
259 init_fsinfo(&i);
260 fs_write(fs->fsinfo_start,sizeof(i),&i);
261 }
262 else fs->fsinfo_start = 0;
263 }
264
265 if (fs->fsinfo_start)
266 fs->free_clusters = CF_LE_L(i.free_clusters);
267 }
268
269 void read_boot(DOS_FS *fs)
270 {
271 struct boot_sector b;
272 unsigned total_sectors;
273 unsigned short logical_sector_size, sectors;
274 unsigned fat_length;
275 off_t data_size;
276
277 fs_read(0,sizeof(b),&b);
278 logical_sector_size = GET_UNALIGNED_W(b.sector_size);
279 if (!logical_sector_size) die("Logical sector size is zero.");
280 fs->cluster_size = b.cluster_size*logical_sector_size;
281 if (!fs->cluster_size) die("Cluster size is zero.");
282 if (b.fats != 2 && b.fats != 1)
283 die("Currently, only 1 or 2 FATs are supported, not %d.\n",b.fats);
284 fs->nfats = b.fats;
285 sectors = GET_UNALIGNED_W(b.sectors);
286 total_sectors = sectors ? sectors : CF_LE_L(b.total_sect);
287 if (verbose) printf("Checking we can access the last sector of the filesystem\n");
288 /* Can't access last odd sector anyway, so round down */
289 fs_test((off_t)((total_sectors & ~1)-1)*(off_t)logical_sector_size,
290 logical_sector_size);
291 fat_length = CF_LE_W(b.fat_length) ?
292 CF_LE_W(b.fat_length) : CF_LE_L(b.fat32_length);
293 fs->fat_start = (off_t)CF_LE_W(b.reserved)*logical_sector_size;
294 fs->root_start = ((off_t)CF_LE_W(b.reserved)+b.fats*fat_length)*
295 logical_sector_size;
296 fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
297 fs->data_start = fs->root_start+ROUND_TO_MULTIPLE(fs->root_entries <<
298 MSDOS_DIR_BITS,logical_sector_size);
299 data_size = (off_t)total_sectors*logical_sector_size-fs->data_start;
300 fs->clusters = data_size/fs->cluster_size;
301 fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
302 fs->fsinfo_start = 0; /* no FSINFO structure */
303 fs->free_clusters = -1; /* unknown */
304 if (!b.fat_length && b.fat32_length) {
305 fs->fat_bits = 32;
306 fs->root_cluster = CF_LE_L(b.root_cluster);
307 if (!fs->root_cluster && fs->root_entries)
308 /* M$ hasn't specified this, but it looks reasonable: If
309 * root_cluster is 0 but there is a separate root dir
310 * (root_entries != 0), we handle the root dir the old way. Give a
311 * warning, but convertig to a root dir in a cluster chain seems
312 * to complex for now... */
313 printf( "Warning: FAT32 root dir not in cluster chain! "
314 "Compability mode...\n" );
315 else if (!fs->root_cluster && !fs->root_entries)
316 die("No root directory!");
317 else if (fs->root_cluster && fs->root_entries)
318 printf( "Warning: FAT32 root dir is in a cluster chain, but "
319 "a separate root dir\n"
320 " area is defined. Cannot fix this easily.\n" );
321
322 fs->backupboot_start = CF_LE_W(b.backup_boot)*logical_sector_size;
323 check_backup_boot(fs,&b,logical_sector_size);
324
325 read_fsinfo(fs,&b,logical_sector_size);
326 }
327 else if (!atari_format) {
328 /* On real MS-DOS, a 16 bit FAT is used whenever there would be too
329 * much clusers otherwise. */
330 fs->fat_bits = (fs->clusters > MSDOS_FAT12) ? 16 : 12;
331 }
332 else {
333 /* On Atari, things are more difficult: GEMDOS always uses 12bit FATs
334 * on floppies, and always 16 bit on harddisks. */
335 fs->fat_bits = 16; /* assume 16 bit FAT for now */
336 /* If more clusters than fat entries in 16-bit fat, we assume
337 * it's a real MSDOS FS with 12-bit fat. */
338 if (fs->clusters+2 > fat_length*logical_sector_size*8/16 ||
339 /* if it's a floppy disk --> 12bit fat */
340 device_no == 2 ||
341 /* if it's a ramdisk or loopback device and has one of the usual
342 * floppy sizes -> 12bit FAT */
343 ((device_no == 1 || device_no == 7) &&
344 (total_sectors == 720 || total_sectors == 1440 ||
345 total_sectors == 2880)))
346 fs->fat_bits = 12;
347 }
348 /* On FAT32, the high 4 bits of a FAT entry are reserved */
349 fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits;
350 fs->fat_size = fat_length*logical_sector_size;
351 if (fs->clusters > ((unsigned long long)fs->fat_size*8/fs->fat_bits)-2)
352 die("File system has %d clusters but only space for %d FAT entries.",
353 fs->clusters,((unsigned long long)fs->fat_size*8/fs->fat_bits)-2);
354 if (!fs->root_entries && !fs->root_cluster)
355 die("Root directory has zero size.");
356 if (fs->root_entries & (MSDOS_DPS-1))
357 die("Root directory (%d entries) doesn't span an integral number of "
358 "sectors.",fs->root_entries);
359 if (logical_sector_size & (SECTOR_SIZE-1))
360 die("Logical sector size (%d bytes) is not a multiple of the physical "
361 "sector size.",logical_sector_size);
362 /* ++roman: On Atari, these two fields are often left uninitialized */
363 if (!atari_format && (!b.secs_track || !b.heads))
364 die("Invalid disk format in boot sector.");
365 if (verbose) dump_boot(fs,&b,logical_sector_size);
366 }
367
368 /* Local Variables: */
369 /* tab-width: 8 */
370 /* End: */