b7007a9a8bee3e3c84671d92b1ba3d7d03fca151
1 /* boot.c - Read and analyze ia PC/MS-DOS boot sector
3 Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
4 Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
5 Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
6 Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
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, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 The complete text of the GNU General Public License
22 can be found in /usr/share/common-licenses/GPL-3 file.
25 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
26 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
34 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
35 /* don't divide by zero */
37 /* cut-over cluster counts for FAT12 and FAT16 */
38 #define FAT12_THRESHOLD 4085
39 #define FAT16_THRESHOLD 65525
45 { 0xf0, "5.25\" or 3.5\" HD floppy" },
46 { 0xf8, "hard disk" },
47 { 0xf9, "3.5\" 720k floppy 2s/80tr/9sec or "
48 "5.25\" 1.2M floppy 2s/80tr/15sec" },
49 { 0xfa, "5.25\" 320k floppy 1s/80tr/8sec" },
50 { 0xfb, "3.5\" 640k floppy 2s/80tr/8sec" },
51 { 0xfc, "5.25\" 180k floppy 1s/40tr/9sec" },
52 { 0xfd, "5.25\" 360k floppy 2s/40tr/9sec" },
53 { 0xfe, "5.25\" 160k floppy 1s/40tr/8sec" },
54 { 0xff, "5.25\" 320k floppy 2s/40tr/8sec" },
57 #if defined __alpha || defined __ia64__ || defined __x86_64__ || defined __ppc64__
58 /* Unaligned fields must first be copied byte-wise (little endian) */
59 #define GET_UNALIGNED_W(u) \
60 (((unsigned char*)(&u))[0] | (((unsigned char*)&(u))[1] << 8))
61 #elif defined __s390x__
62 /* Unaligned fields must first be copied byte-wise (big endian) */
63 #define GET_UNALIGNED_W(pu) \
64 (((unsigned char*)&(u))[1] | (((unsigned char*)&(u))[0] << 8))
66 #define GET_UNALIGNED_W(f) le16toh( *(unsigned short *)&f )
69 static const char *get_media_descr(unsigned char media
)
73 for (i
= 0; i
< sizeof(mediabytes
) / sizeof(*mediabytes
); ++i
) {
74 if (mediabytes
[i
].media
== media
)
75 return (mediabytes
[i
].descr
);
80 static void dump_boot(DOS_FS
* fs
, struct boot_sector
*b
, unsigned lss
)
82 unsigned short sectors
;
84 printf("Boot sector contents:\n");
87 strncpy(id
, (const char *)b
->system_id
, 8);
89 printf("System ID \"%s\"\n", id
);
91 /* On Atari, a 24 bit serial number is stored at offset 8 of the boot
93 printf("Serial number 0x%x\n",
94 b
->system_id
[5] | (b
->system_id
[6] << 8) | (b
->
97 printf("Media byte 0x%02x (%s)\n", b
->media
, get_media_descr(b
->media
));
98 printf("%10d bytes per logical sector\n", GET_UNALIGNED_W(b
->sector_size
));
99 printf("%10d bytes per cluster\n", fs
->cluster_size
);
100 printf("%10d reserved sector%s\n", le16toh(b
->reserved
),
101 le16toh(b
->reserved
) == 1 ? "" : "s");
102 printf("First FAT starts at byte %llu (sector %llu)\n",
103 (unsigned long long)fs
->fat_start
,
104 (unsigned long long)fs
->fat_start
/ lss
);
105 printf("%10d FATs, %d bit entries\n", b
->fats
, fs
->fat_bits
);
106 printf("%10d bytes per FAT (= %u sectors)\n", fs
->fat_size
,
108 if (!fs
->root_cluster
) {
109 printf("Root directory starts at byte %llu (sector %llu)\n",
110 (unsigned long long)fs
->root_start
,
111 (unsigned long long)fs
->root_start
/ lss
);
112 printf("%10d root directory entries\n", fs
->root_entries
);
114 printf("Root directory start at cluster %lu (arbitrary size)\n",
115 (unsigned long)fs
->root_cluster
);
117 printf("Data area starts at byte %llu (sector %llu)\n",
118 (unsigned long long)fs
->data_start
,
119 (unsigned long long)fs
->data_start
/ lss
);
120 printf("%10lu data clusters (%llu bytes)\n",
121 (unsigned long)fs
->data_clusters
,
122 (unsigned long long)fs
->data_clusters
* fs
->cluster_size
);
123 printf("%u sectors/track, %u heads\n", le16toh(b
->secs_track
),
125 printf("%10u hidden sectors\n", atari_format
?
126 /* On Atari, the hidden field is only 16 bit wide and unused */
127 (((unsigned char *)&b
->hidden
)[0] |
128 ((unsigned char *)&b
->hidden
)[1] << 8) : le32toh(b
->hidden
));
129 sectors
= GET_UNALIGNED_W(b
->sectors
);
130 printf("%10u sectors total\n", sectors
? sectors
: le32toh(b
->total_sect
));
133 static void check_backup_boot(DOS_FS
* fs
, struct boot_sector
*b
, int lss
)
135 struct boot_sector b2
;
137 if (!fs
->backupboot_start
) {
138 printf("There is no backup boot sector.\n");
139 if (le16toh(b
->reserved
) < 3) {
140 printf("And there is no space for creating one!\n");
144 printf("1) Create one\n2) Do without a backup\n");
146 printf(" Auto-creating backup boot block.\n");
147 if (!interactive
|| get_key("12", "?") == '1') {
149 /* The usual place for the backup boot sector is sector 6. Choose
150 * that or the last reserved sector. */
151 if (le16toh(b
->reserved
) >= 7 && le16toh(b
->info_sector
) != 6)
154 bbs
= le16toh(b
->reserved
) - 1;
155 if (bbs
== le16toh(b
->info_sector
))
156 --bbs
; /* this is never 0, as we checked reserved >= 3! */
158 fs
->backupboot_start
= bbs
* lss
;
159 b
->backup_boot
= htole16(bbs
);
160 fs_write(fs
->backupboot_start
, sizeof(*b
), b
);
161 fs_write(offsetof(struct boot_sector
, backup_boot
),
162 sizeof(b
->backup_boot
), &b
->backup_boot
);
163 printf("Created backup of boot sector in sector %d\n", bbs
);
169 fs_read(fs
->backupboot_start
, sizeof(b2
), &b2
);
170 if (memcmp(b
, &b2
, sizeof(b2
)) != 0) {
171 /* there are any differences */
173 int i
, pos
, first
= 1;
176 printf("There are differences between boot sector and its backup.\n");
177 printf("This is mostly harmless. Differences: (offset:original/backup)\n ");
179 for (p
= (uint8_t *) b
, q
= (uint8_t *) & b2
, i
= 0; i
< sizeof(b2
);
182 sprintf(buf
, "%s%u:%02x/%02x", first
? "" : ", ",
183 (unsigned)(p
- (uint8_t *) b
), *p
, *q
);
184 if (pos
+ strlen(buf
) > 78)
185 printf("\n "), pos
= 2;
194 printf("1) Copy original to backup\n"
195 "2) Copy backup to original\n" "3) No action\n");
197 printf(" Not automatically fixing this.\n");
198 switch (interactive
? get_key("123", "?") : '3') {
200 fs_write(fs
->backupboot_start
, sizeof(*b
), b
);
203 fs_write(0, sizeof(b2
), &b2
);
211 static void init_fsinfo(struct info_sector
*i
)
213 i
->magic
= htole32(0x41615252);
214 i
->signature
= htole32(0x61417272);
215 i
->free_clusters
= htole32(-1);
216 i
->next_cluster
= htole32(2);
217 i
->boot_sign
= htole16(0xaa55);
220 static void read_fsinfo(DOS_FS
* fs
, struct boot_sector
*b
, int lss
)
222 struct info_sector i
;
224 if (!b
->info_sector
) {
225 printf("No FSINFO sector\n");
227 printf("1) Create one\n2) Do without FSINFO\n");
229 printf(" Not automatically creating it.\n");
230 if (interactive
&& get_key("12", "?") == '1') {
231 /* search for a free reserved sector (not boot sector and not
232 * backup boot sector) */
234 for (s
= 1; s
< le16toh(b
->reserved
); ++s
)
235 if (s
!= le16toh(b
->backup_boot
))
237 if (s
> 0 && s
< le16toh(b
->reserved
)) {
239 fs_write((off_t
)s
* lss
, sizeof(i
), &i
);
240 b
->info_sector
= htole16(s
);
241 fs_write(offsetof(struct boot_sector
, info_sector
),
242 sizeof(b
->info_sector
), &b
->info_sector
);
243 if (fs
->backupboot_start
)
244 fs_write(fs
->backupboot_start
+
245 offsetof(struct boot_sector
, info_sector
),
246 sizeof(b
->info_sector
), &b
->info_sector
);
248 printf("No free reserved sector found -- "
249 "no space for FSINFO sector!\n");
256 fs
->fsinfo_start
= le16toh(b
->info_sector
) * lss
;
257 fs_read(fs
->fsinfo_start
, sizeof(i
), &i
);
259 if (i
.magic
!= htole32(0x41615252) ||
260 i
.signature
!= htole32(0x61417272) || i
.boot_sign
!= htole16(0xaa55)) {
261 printf("FSINFO sector has bad magic number(s):\n");
262 if (i
.magic
!= htole32(0x41615252))
263 printf(" Offset %llu: 0x%08x != expected 0x%08x\n",
264 (unsigned long long)offsetof(struct info_sector
, magic
),
265 le32toh(i
.magic
), 0x41615252);
266 if (i
.signature
!= htole32(0x61417272))
267 printf(" Offset %llu: 0x%08x != expected 0x%08x\n",
268 (unsigned long long)offsetof(struct info_sector
, signature
),
269 le32toh(i
.signature
), 0x61417272);
270 if (i
.boot_sign
!= htole16(0xaa55))
271 printf(" Offset %llu: 0x%04x != expected 0x%04x\n",
272 (unsigned long long)offsetof(struct info_sector
, boot_sign
),
273 le16toh(i
.boot_sign
), 0xaa55);
275 printf("1) Correct\n2) Don't correct (FSINFO invalid then)\n");
277 printf(" Auto-correcting it.\n");
278 if (!interactive
|| get_key("12", "?") == '1') {
280 fs_write(fs
->fsinfo_start
, sizeof(i
), &i
);
282 fs
->fsinfo_start
= 0;
285 if (fs
->fsinfo_start
)
286 fs
->free_clusters
= le32toh(i
.free_clusters
);
289 static char print_fat_dirty_state(void)
291 printf("Dirty bit is set. Fs was not properly unmounted and"
292 " some data may be corrupt.\n");
295 printf("1) Remove dirty bit\n" "2) No action\n");
296 return get_key("12", "?");
298 printf(" Automatically removing dirty bit.\n");
302 static void check_fat_state_bit(DOS_FS
* fs
, void *b
)
304 if (fs
->fat_bits
== 32) {
305 struct boot_sector
*b32
= b
;
307 if (b32
->reserved3
& FAT_STATE_DIRTY
) {
309 if (print_fat_dirty_state() == '1') {
310 b32
->reserved3
&= ~FAT_STATE_DIRTY
;
311 fs_write(0, sizeof(*b32
), b32
);
315 struct boot_sector_16
*b16
= b
;
317 if (b16
->reserved2
& FAT_STATE_DIRTY
) {
319 if (print_fat_dirty_state() == '1') {
320 b16
->reserved2
&= ~FAT_STATE_DIRTY
;
321 fs_write(0, sizeof(*b16
), b16
);
327 void read_boot(DOS_FS
* fs
)
329 struct boot_sector b
;
330 unsigned total_sectors
;
331 unsigned short logical_sector_size
, sectors
;
335 fs_read(0, sizeof(b
), &b
);
336 logical_sector_size
= GET_UNALIGNED_W(b
.sector_size
);
337 if (!logical_sector_size
)
338 die("Logical sector size is zero.");
340 /* This was moved up because it's the first thing that will fail */
341 /* if the platform needs special handling of unaligned multibyte accesses */
342 /* but such handling isn't being provided. See GET_UNALIGNED_W() above. */
343 if (logical_sector_size
& (SECTOR_SIZE
- 1))
344 die("Logical sector size (%d bytes) is not a multiple of the physical "
345 "sector size.", logical_sector_size
);
347 fs
->cluster_size
= b
.cluster_size
* logical_sector_size
;
348 if (!fs
->cluster_size
)
349 die("Cluster size is zero.");
350 if (b
.fats
!= 2 && b
.fats
!= 1)
351 die("Currently, only 1 or 2 FATs are supported, not %d.\n", b
.fats
);
353 sectors
= GET_UNALIGNED_W(b
.sectors
);
354 total_sectors
= sectors
? sectors
: le32toh(b
.total_sect
);
356 printf("Checking we can access the last sector of the filesystem\n");
357 /* Can't access last odd sector anyway, so round down */
358 fs_test((off_t
)((total_sectors
& ~1) - 1) * logical_sector_size
,
359 logical_sector_size
);
360 fat_length
= le16toh(b
.fat_length
) ?
361 le16toh(b
.fat_length
) : le32toh(b
.fat32_length
);
362 fs
->fat_start
= (off_t
)le16toh(b
.reserved
) * logical_sector_size
;
363 fs
->root_start
= ((off_t
)le16toh(b
.reserved
) + b
.fats
* fat_length
) *
365 fs
->root_entries
= GET_UNALIGNED_W(b
.dir_entries
);
366 fs
->data_start
= fs
->root_start
+ ROUND_TO_MULTIPLE(fs
->root_entries
<<
368 logical_sector_size
);
369 data_size
= (off_t
)total_sectors
* logical_sector_size
- fs
->data_start
;
370 fs
->data_clusters
= data_size
/ fs
->cluster_size
;
371 fs
->root_cluster
= 0; /* indicates standard, pre-FAT32 root dir */
372 fs
->fsinfo_start
= 0; /* no FSINFO structure */
373 fs
->free_clusters
= -1; /* unknown */
374 if (!b
.fat_length
&& b
.fat32_length
) {
376 fs
->root_cluster
= le32toh(b
.root_cluster
);
377 if (!fs
->root_cluster
&& fs
->root_entries
)
378 /* M$ hasn't specified this, but it looks reasonable: If
379 * root_cluster is 0 but there is a separate root dir
380 * (root_entries != 0), we handle the root dir the old way. Give a
381 * warning, but convertig to a root dir in a cluster chain seems
382 * to complex for now... */
383 printf("Warning: FAT32 root dir not in cluster chain! "
384 "Compatibility mode...\n");
385 else if (!fs
->root_cluster
&& !fs
->root_entries
)
386 die("No root directory!");
387 else if (fs
->root_cluster
&& fs
->root_entries
)
388 printf("Warning: FAT32 root dir is in a cluster chain, but "
389 "a separate root dir\n"
390 " area is defined. Cannot fix this easily.\n");
391 if (fs
->data_clusters
< FAT16_THRESHOLD
)
392 printf("Warning: Filesystem is FAT32 according to fat_length "
393 "and fat32_length fields,\n"
394 " but has only %lu clusters, less than the required "
396 " This may lead to problems on some systems.\n",
397 (unsigned long)fs
->data_clusters
, FAT16_THRESHOLD
);
399 check_fat_state_bit(fs
, &b
);
400 fs
->backupboot_start
= le16toh(b
.backup_boot
) * logical_sector_size
;
401 check_backup_boot(fs
, &b
, logical_sector_size
);
403 read_fsinfo(fs
, &b
, logical_sector_size
);
404 } else if (!atari_format
) {
405 /* On real MS-DOS, a 16 bit FAT is used whenever there would be too
406 * much clusers otherwise. */
407 fs
->fat_bits
= (fs
->data_clusters
>= FAT12_THRESHOLD
) ? 16 : 12;
408 if (fs
->data_clusters
>= FAT16_THRESHOLD
)
409 die("Too many clusters (%lu) for FAT16 filesystem.", fs
->data_clusters
);
410 check_fat_state_bit(fs
, &b
);
412 /* On Atari, things are more difficult: GEMDOS always uses 12bit FATs
413 * on floppies, and always 16 bit on harddisks. */
414 fs
->fat_bits
= 16; /* assume 16 bit FAT for now */
415 /* If more clusters than fat entries in 16-bit fat, we assume
416 * it's a real MSDOS FS with 12-bit fat. */
417 if (fs
->data_clusters
+ 2 > fat_length
* logical_sector_size
* 8 / 16 ||
418 /* if it has one of the usual floppy sizes -> 12bit FAT */
419 (total_sectors
== 720 || total_sectors
== 1440 ||
420 total_sectors
== 2880))
423 /* On FAT32, the high 4 bits of a FAT entry are reserved */
424 fs
->eff_fat_bits
= (fs
->fat_bits
== 32) ? 28 : fs
->fat_bits
;
425 fs
->fat_size
= fat_length
* logical_sector_size
;
427 fs
->label
= calloc(12, sizeof(uint8_t));
428 if (fs
->fat_bits
== 12 || fs
->fat_bits
== 16) {
429 struct boot_sector_16
*b16
= (struct boot_sector_16
*)&b
;
430 if (b16
->extended_sig
== 0x29)
431 memmove(fs
->label
, b16
->label
, 11);
434 } else if (fs
->fat_bits
== 32) {
435 if (b
.extended_sig
== 0x29)
436 memmove(fs
->label
, &b
.label
, 11);
441 if (fs
->data_clusters
>
442 ((uint64_t)fs
->fat_size
* 8 / fs
->fat_bits
) - 2)
443 die("Filesystem has %d clusters but only space for %d FAT entries.",
445 ((unsigned long long)fs
->fat_size
* 8 / fs
->fat_bits
) - 2);
446 if (!fs
->root_entries
&& !fs
->root_cluster
)
447 die("Root directory has zero size.");
448 if (fs
->root_entries
& (MSDOS_DPS
- 1))
449 die("Root directory (%d entries) doesn't span an integral number of "
450 "sectors.", fs
->root_entries
);
451 if (logical_sector_size
& (SECTOR_SIZE
- 1))
452 die("Logical sector size (%d bytes) is not a multiple of the physical "
453 "sector size.", logical_sector_size
);
454 #if 0 /* linux kernel doesn't check that either */
455 /* ++roman: On Atari, these two fields are often left uninitialized */
456 if (!atari_format
&& (!b
.secs_track
|| !b
.heads
))
457 die("Invalid disk format in boot sector.");
460 dump_boot(fs
, &b
, logical_sector_size
);