b7007a9a8bee3e3c84671d92b1ba3d7d03fca151
[reactos.git] / reactos / sdk / lib / fslib / vfatlib / check / boot.c
1 /* boot.c - Read and analyze ia PC/MS-DOS boot sector
2
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>
7
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.
12
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.
17
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/>.
20
21 The complete text of the GNU General Public License
22 can be found in /usr/share/common-licenses/GPL-3 file.
23 */
24
25 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
26 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
27
28 #include "vfatlib.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33
34 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
35 /* don't divide by zero */
36
37 /* cut-over cluster counts for FAT12 and FAT16 */
38 #define FAT12_THRESHOLD 4085
39 #define FAT16_THRESHOLD 65525
40
41 static struct {
42 uint8_t media;
43 const char *descr;
44 } mediabytes[] = {
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" },
55 };
56
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))
65 #else
66 #define GET_UNALIGNED_W(f) le16toh( *(unsigned short *)&f )
67 #endif
68
69 static const char *get_media_descr(unsigned char media)
70 {
71 int i;
72
73 for (i = 0; i < sizeof(mediabytes) / sizeof(*mediabytes); ++i) {
74 if (mediabytes[i].media == media)
75 return (mediabytes[i].descr);
76 }
77 return ("undefined");
78 }
79
80 static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss)
81 {
82 unsigned short sectors;
83
84 printf("Boot sector contents:\n");
85 if (!atari_format) {
86 char id[9];
87 strncpy(id, (const char *)b->system_id, 8);
88 id[8] = 0;
89 printf("System ID \"%s\"\n", id);
90 } else {
91 /* On Atari, a 24 bit serial number is stored at offset 8 of the boot
92 * sector */
93 printf("Serial number 0x%x\n",
94 b->system_id[5] | (b->system_id[6] << 8) | (b->
95 system_id[7] << 16));
96 }
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,
107 fs->fat_size / lss);
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);
113 } else {
114 printf("Root directory start at cluster %lu (arbitrary size)\n",
115 (unsigned long)fs->root_cluster);
116 }
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),
124 le16toh(b->heads));
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));
131 }
132
133 static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss)
134 {
135 struct boot_sector b2;
136
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");
141 return;
142 }
143 if (interactive)
144 printf("1) Create one\n2) Do without a backup\n");
145 else
146 printf(" Auto-creating backup boot block.\n");
147 if (!interactive || get_key("12", "?") == '1') {
148 int bbs;
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)
152 bbs = 6;
153 else {
154 bbs = le16toh(b->reserved) - 1;
155 if (bbs == le16toh(b->info_sector))
156 --bbs; /* this is never 0, as we checked reserved >= 3! */
157 }
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);
164 return;
165 } else
166 return;
167 }
168
169 fs_read(fs->backupboot_start, sizeof(b2), &b2);
170 if (memcmp(b, &b2, sizeof(b2)) != 0) {
171 /* there are any differences */
172 uint8_t *p, *q;
173 int i, pos, first = 1;
174 char buf[20];
175
176 printf("There are differences between boot sector and its backup.\n");
177 printf("This is mostly harmless. Differences: (offset:original/backup)\n ");
178 pos = 2;
179 for (p = (uint8_t *) b, q = (uint8_t *) & b2, i = 0; i < sizeof(b2);
180 ++p, ++q, ++i) {
181 if (*p != *q) {
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;
186 printf("%s", buf);
187 pos += strlen(buf);
188 first = 0;
189 }
190 }
191 printf("\n");
192
193 if (interactive)
194 printf("1) Copy original to backup\n"
195 "2) Copy backup to original\n" "3) No action\n");
196 else
197 printf(" Not automatically fixing this.\n");
198 switch (interactive ? get_key("123", "?") : '3') {
199 case '1':
200 fs_write(fs->backupboot_start, sizeof(*b), b);
201 break;
202 case '2':
203 fs_write(0, sizeof(b2), &b2);
204 break;
205 default:
206 break;
207 }
208 }
209 }
210
211 static void init_fsinfo(struct info_sector *i)
212 {
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);
218 }
219
220 static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, int lss)
221 {
222 struct info_sector i;
223
224 if (!b->info_sector) {
225 printf("No FSINFO sector\n");
226 if (interactive)
227 printf("1) Create one\n2) Do without FSINFO\n");
228 else
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) */
233 uint32_t s;
234 for (s = 1; s < le16toh(b->reserved); ++s)
235 if (s != le16toh(b->backup_boot))
236 break;
237 if (s > 0 && s < le16toh(b->reserved)) {
238 init_fsinfo(&i);
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);
247 } else {
248 printf("No free reserved sector found -- "
249 "no space for FSINFO sector!\n");
250 return;
251 }
252 } else
253 return;
254 }
255
256 fs->fsinfo_start = le16toh(b->info_sector) * lss;
257 fs_read(fs->fsinfo_start, sizeof(i), &i);
258
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);
274 if (interactive)
275 printf("1) Correct\n2) Don't correct (FSINFO invalid then)\n");
276 else
277 printf(" Auto-correcting it.\n");
278 if (!interactive || get_key("12", "?") == '1') {
279 init_fsinfo(&i);
280 fs_write(fs->fsinfo_start, sizeof(i), &i);
281 } else
282 fs->fsinfo_start = 0;
283 }
284
285 if (fs->fsinfo_start)
286 fs->free_clusters = le32toh(i.free_clusters);
287 }
288
289 static char print_fat_dirty_state(void)
290 {
291 printf("Dirty bit is set. Fs was not properly unmounted and"
292 " some data may be corrupt.\n");
293
294 if (interactive) {
295 printf("1) Remove dirty bit\n" "2) No action\n");
296 return get_key("12", "?");
297 } else
298 printf(" Automatically removing dirty bit.\n");
299 return '1';
300 }
301
302 static void check_fat_state_bit(DOS_FS * fs, void *b)
303 {
304 if (fs->fat_bits == 32) {
305 struct boot_sector *b32 = b;
306
307 if (b32->reserved3 & FAT_STATE_DIRTY) {
308 printf("0x41: ");
309 if (print_fat_dirty_state() == '1') {
310 b32->reserved3 &= ~FAT_STATE_DIRTY;
311 fs_write(0, sizeof(*b32), b32);
312 }
313 }
314 } else {
315 struct boot_sector_16 *b16 = b;
316
317 if (b16->reserved2 & FAT_STATE_DIRTY) {
318 printf("0x25: ");
319 if (print_fat_dirty_state() == '1') {
320 b16->reserved2 &= ~FAT_STATE_DIRTY;
321 fs_write(0, sizeof(*b16), b16);
322 }
323 }
324 }
325 }
326
327 void read_boot(DOS_FS * fs)
328 {
329 struct boot_sector b;
330 unsigned total_sectors;
331 unsigned short logical_sector_size, sectors;
332 unsigned fat_length;
333 off_t data_size;
334
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.");
339
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);
346
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);
352 fs->nfats = b.fats;
353 sectors = GET_UNALIGNED_W(b.sectors);
354 total_sectors = sectors ? sectors : le32toh(b.total_sect);
355 if (verbose)
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) *
364 logical_sector_size;
365 fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
366 fs->data_start = fs->root_start + ROUND_TO_MULTIPLE(fs->root_entries <<
367 MSDOS_DIR_BITS,
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) {
375 fs->fat_bits = 32;
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 "
395 "minimum of %d.\n"
396 " This may lead to problems on some systems.\n",
397 (unsigned long)fs->data_clusters, FAT16_THRESHOLD);
398
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);
402
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);
411 } else {
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))
421 fs->fat_bits = 12;
422 }
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;
426
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);
432 else
433 fs->label = NULL;
434 } else if (fs->fat_bits == 32) {
435 if (b.extended_sig == 0x29)
436 memmove(fs->label, &b.label, 11);
437 else
438 fs->label = NULL;
439 }
440
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.",
444 fs->data_clusters,
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.");
458 #endif
459 if (verbose)
460 dump_boot(fs, &b, logical_sector_size);
461 }