1 /* boot.c - Read and analyze ia PC/MS-DOS boot sector */
3 /* Written 1993 by Werner Almesberger */
5 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
6 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
10 #include <sys/types.h>
18 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
19 /* don't divide by zero */
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" },
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) \
42 memcpy( &__v, &f, sizeof(__v) ); \
43 CF_LE_W( *(unsigned short *)&f ); \
46 #define GET_UNALIGNED_W(f) CF_LE_W( *(unsigned short *)&f )
50 static char *get_media_descr( unsigned char media
)
54 for( i
= 0; i
< sizeof(mediabytes
)/sizeof(*mediabytes
); ++i
) {
55 if (mediabytes
[i
].media
== media
)
56 return( mediabytes
[i
].descr
);
58 return( "undefined" );
61 static void dump_boot(DOS_FS
*fs
,struct boot_sector
*b
,unsigned lss
)
63 unsigned short sectors
;
65 printf("Boot sector contents:\n");
68 strncpy(id
,b
->system_id
,8);
70 printf("System ID \"%s\"\n",id
);
73 /* On Atari, a 24 bit serial number is stored at offset 8 of the boot
75 printf("Serial number 0x%x\n",
76 b
->system_id
[5] | (b
->system_id
[6]<<8) | (b
->system_id
[7]<<16));
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",
85 (__u64
)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
,
89 if (!fs
->root_cluster
) {
90 printf("Root directory starts at byte %llu (sector %llu)\n",
91 (__u64
)fs
->root_start
,
92 (__u64
)fs
->root_start
/lss
);
93 printf("%10d root directory entries\n",fs
->root_entries
);
96 printf( "Root directory start at cluster %lu (arbitrary size)\n",
99 printf("Data area starts at byte %llu (sector %llu)\n",
100 (__u64
)fs
->data_start
,
101 (__u64
)fs
->data_start
/lss
);
102 printf("%10lu data clusters (%llu bytes)\n",fs
->clusters
,
103 (__u64
)fs
->clusters
*fs
->cluster_size
);
104 printf("%u sectors/track, %u heads\n",CF_LE_W(b
->secs_track
),
106 printf("%10u hidden sectors\n",
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) :
112 sectors
= GET_UNALIGNED_W( b
->sectors
);
113 printf("%10u sectors total\n", sectors
? sectors
: CF_LE_L(b
->total_sect
));
116 static void check_backup_boot(DOS_FS
*fs
, struct boot_sector
*b
, int lss
)
118 struct boot_sector b2
;
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" );
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') {
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)
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! */
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
);
151 fs_read(fs
->backupboot_start
,sizeof(b2
),&b2
);
152 if (memcmp(b
,&b2
,sizeof(b2
)) != 0) {
153 /* there are any differences */
155 int i
, pos
, first
= 1;
158 printf( "There are differences between boot sector and its backup.\n" );
159 printf( "Differences: (offset:original/backup)\n " );
161 for( p
= (__u8
*)b
, q
= (__u8
*)&b2
, i
= 0; i
< sizeof(b2
);
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;
175 printf( "1) Copy original to backup\n"
176 "2) Copy backup to original\n"
178 else printf( " Not automatically fixing this.\n" );
179 switch (interactive
? get_key("123","?") : '3') {
181 fs_write(fs
->backupboot_start
,sizeof(*b
),b
);
184 fs_write(0,sizeof(b2
),&b2
);
192 static void init_fsinfo(struct info_sector
*i
)
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);
201 static void read_fsinfo(DOS_FS
*fs
, struct boot_sector
*b
,int lss
)
203 struct info_sector i
;
205 if (!b
->info_sector
) {
206 printf( "No FSINFO sector\n" );
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) */
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
)) {
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
);
228 printf( "No free reserved sector found -- "
229 "no space for FSINFO sector!\n" );
236 fs
->fsinfo_start
= CF_LE_W(b
->info_sector
)*lss
;
237 fs_read(fs
->fsinfo_start
,sizeof(i
),&i
);
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 (__u64
)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 (__u64
)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 (__u64
)offsetof(struct info_sector
,boot_sign
),
254 CF_LE_W(i
.boot_sign
),0xaa55);
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') {
260 fs_write(fs
->fsinfo_start
,sizeof(i
),&i
);
262 else fs
->fsinfo_start
= 0;
265 if (fs
->fsinfo_start
)
266 fs
->free_clusters
= CF_LE_L(i
.free_clusters
);
269 void read_boot(DOS_FS
*fs
)
271 struct boot_sector b
;
272 unsigned total_sectors
;
273 unsigned short logical_sector_size
, sectors
;
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
);
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((loff_t
)((total_sectors
& ~1)-1)*(loff_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
)*
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
= (loff_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
) {
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" );
322 fs
->backupboot_start
= CF_LE_W(b
.backup_boot
)*logical_sector_size
;
323 check_backup_boot(fs
,&b
,logical_sector_size
);
325 read_fsinfo(fs
,&b
,logical_sector_size
);
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;
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 */
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)))
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
> ((__u64
)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
,((__u64
)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
);
368 /* Local Variables: */