blob: 0c0918f8b8220cd2a182db0e289b8a541efb0c8a [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/* 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>
Matt Mower18794c82015-11-11 16:22:45 -06005 Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
bigbiff bigbiff9c754052013-01-09 09:09:08 -05006
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
Matt Mower18794c82015-11-11 16:22:45 -060020 The complete text of the GNU General Public License
bigbiff bigbiff9c754052013-01-09 09:09:08 -050021 can be found in /usr/share/common-licenses/GPL-3 file.
22*/
23
24/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
25 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
26
27#include <stdio.h>
Matt Mower18794c82015-11-11 16:22:45 -060028#include <stdint.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050029#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050030#include <stdlib.h>
31#include <time.h>
32
33#include "common.h"
Matt Mower18794c82015-11-11 16:22:45 -060034#include "fsck.fat.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050035#include "fat.h"
36#include "io.h"
37#include "boot.h"
Matt Mower18794c82015-11-11 16:22:45 -060038#include "check.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050039
40#define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
41 /* don't divide by zero */
42
43/* cut-over cluster counts for FAT12 and FAT16 */
44#define FAT12_THRESHOLD 4085
45#define FAT16_THRESHOLD 65525
46
47static struct {
Matt Mower18794c82015-11-11 16:22:45 -060048 uint8_t media;
49 const char *descr;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050050} mediabytes[] = {
51 {
52 0xf0, "5.25\" or 3.5\" HD floppy"}, {
53 0xf8, "hard disk"}, {
54 0xf9, "3,5\" 720k floppy 2s/80tr/9sec or "
55 "5.25\" 1.2M floppy 2s/80tr/15sec"}, {
56 0xfa, "5.25\" 320k floppy 1s/80tr/8sec"}, {
57 0xfb, "3.5\" 640k floppy 2s/80tr/8sec"}, {
58 0xfc, "5.25\" 180k floppy 1s/40tr/9sec"}, {
59 0xfd, "5.25\" 360k floppy 2s/40tr/9sec"}, {
60 0xfe, "5.25\" 160k floppy 1s/40tr/8sec"}, {
610xff, "5.25\" 320k floppy 2s/40tr/8sec"},};
62
Matt Mower18794c82015-11-11 16:22:45 -060063/* Unaligned fields must first be accessed byte-wise */
bigbiff bigbiff9c754052013-01-09 09:09:08 -050064#define GET_UNALIGNED_W(f) \
Matt Mower18794c82015-11-11 16:22:45 -060065 ( (uint16_t)f[0] | ((uint16_t)f[1]<<8) )
bigbiff bigbiff9c754052013-01-09 09:09:08 -050066
Matt Mower18794c82015-11-11 16:22:45 -060067static const char *get_media_descr(unsigned char media)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050068{
69 int i;
70
71 for (i = 0; i < sizeof(mediabytes) / sizeof(*mediabytes); ++i) {
72 if (mediabytes[i].media == media)
73 return (mediabytes[i].descr);
74 }
75 return ("undefined");
76}
77
78static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss)
79{
80 unsigned short sectors;
81
82 printf("Boot sector contents:\n");
83 if (!atari_format) {
84 char id[9];
85 strncpy(id, (const char *)b->system_id, 8);
86 id[8] = 0;
87 printf("System ID \"%s\"\n", id);
88 } else {
89 /* On Atari, a 24 bit serial number is stored at offset 8 of the boot
90 * sector */
91 printf("Serial number 0x%x\n",
Matt Mower18794c82015-11-11 16:22:45 -060092 b->system_id[5] | (b->system_id[6] << 8) | (b->
93 system_id[7] << 16));
bigbiff bigbiff9c754052013-01-09 09:09:08 -050094 }
95 printf("Media byte 0x%02x (%s)\n", b->media, get_media_descr(b->media));
96 printf("%10d bytes per logical sector\n", GET_UNALIGNED_W(b->sector_size));
97 printf("%10d bytes per cluster\n", fs->cluster_size);
Matt Mower18794c82015-11-11 16:22:45 -060098 printf("%10d reserved sector%s\n", le16toh(b->reserved),
99 le16toh(b->reserved) == 1 ? "" : "s");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500100 printf("First FAT starts at byte %llu (sector %llu)\n",
101 (unsigned long long)fs->fat_start,
102 (unsigned long long)fs->fat_start / lss);
103 printf("%10d FATs, %d bit entries\n", b->fats, fs->fat_bits);
104 printf("%10d bytes per FAT (= %u sectors)\n", fs->fat_size,
105 fs->fat_size / lss);
106 if (!fs->root_cluster) {
107 printf("Root directory starts at byte %llu (sector %llu)\n",
108 (unsigned long long)fs->root_start,
109 (unsigned long long)fs->root_start / lss);
110 printf("%10d root directory entries\n", fs->root_entries);
111 } else {
112 printf("Root directory start at cluster %lu (arbitrary size)\n",
Matt Mower18794c82015-11-11 16:22:45 -0600113 (unsigned long)fs->root_cluster);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500114 }
115 printf("Data area starts at byte %llu (sector %llu)\n",
116 (unsigned long long)fs->data_start,
117 (unsigned long long)fs->data_start / lss);
Matt Mower18794c82015-11-11 16:22:45 -0600118 printf("%10lu data clusters (%llu bytes)\n", (unsigned long)fs->clusters,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500119 (unsigned long long)fs->clusters * fs->cluster_size);
Matt Mower18794c82015-11-11 16:22:45 -0600120 printf("%u sectors/track, %u heads\n", le16toh(b->secs_track),
121 le16toh(b->heads));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500122 printf("%10u hidden sectors\n", atari_format ?
123 /* On Atari, the hidden field is only 16 bit wide and unused */
124 (((unsigned char *)&b->hidden)[0] |
Matt Mower18794c82015-11-11 16:22:45 -0600125 ((unsigned char *)&b->hidden)[1] << 8) : le32toh(b->hidden));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500126 sectors = GET_UNALIGNED_W(b->sectors);
Matt Mower18794c82015-11-11 16:22:45 -0600127 printf("%10u sectors total\n", sectors ? sectors : le32toh(b->total_sect));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500128}
129
130static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss)
131{
132 struct boot_sector b2;
133
134 if (!fs->backupboot_start) {
135 printf("There is no backup boot sector.\n");
Matt Mower18794c82015-11-11 16:22:45 -0600136 if (le16toh(b->reserved) < 3) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500137 printf("And there is no space for creating one!\n");
138 return;
139 }
140 if (interactive)
141 printf("1) Create one\n2) Do without a backup\n");
142 else
143 printf(" Auto-creating backup boot block.\n");
144 if (!interactive || get_key("12", "?") == '1') {
145 int bbs;
146 /* The usual place for the backup boot sector is sector 6. Choose
147 * that or the last reserved sector. */
Matt Mower18794c82015-11-11 16:22:45 -0600148 if (le16toh(b->reserved) >= 7 && le16toh(b->info_sector) != 6)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500149 bbs = 6;
150 else {
Matt Mower18794c82015-11-11 16:22:45 -0600151 bbs = le16toh(b->reserved) - 1;
152 if (bbs == le16toh(b->info_sector))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500153 --bbs; /* this is never 0, as we checked reserved >= 3! */
154 }
155 fs->backupboot_start = bbs * lss;
Matt Mower18794c82015-11-11 16:22:45 -0600156 b->backup_boot = htole16(bbs);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500157 fs_write(fs->backupboot_start, sizeof(*b), b);
158 fs_write((loff_t) offsetof(struct boot_sector, backup_boot),
159 sizeof(b->backup_boot), &b->backup_boot);
160 printf("Created backup of boot sector in sector %d\n", bbs);
161 return;
162 } else
163 return;
164 }
165
166 fs_read(fs->backupboot_start, sizeof(b2), &b2);
167 if (memcmp(b, &b2, sizeof(b2)) != 0) {
168 /* there are any differences */
Matt Mower18794c82015-11-11 16:22:45 -0600169 uint8_t *p, *q;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500170 int i, pos, first = 1;
171 char buf[20];
172
173 printf("There are differences between boot sector and its backup.\n");
Matt Mower18794c82015-11-11 16:22:45 -0600174 printf("This is mostly harmless. Differences: (offset:original/backup)\n ");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500175 pos = 2;
Matt Mower18794c82015-11-11 16:22:45 -0600176 for (p = (uint8_t *) b, q = (uint8_t *) & b2, i = 0; i < sizeof(b2);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500177 ++p, ++q, ++i) {
178 if (*p != *q) {
179 sprintf(buf, "%s%u:%02x/%02x", first ? "" : ", ",
Matt Mower18794c82015-11-11 16:22:45 -0600180 (unsigned)(p - (uint8_t *) b), *p, *q);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500181 if (pos + strlen(buf) > 78)
182 printf("\n "), pos = 2;
183 printf("%s", buf);
184 pos += strlen(buf);
185 first = 0;
186 }
187 }
188 printf("\n");
189
190 if (interactive)
191 printf("1) Copy original to backup\n"
192 "2) Copy backup to original\n" "3) No action\n");
193 else
194 printf(" Not automatically fixing this.\n");
195 switch (interactive ? get_key("123", "?") : '3') {
196 case '1':
197 fs_write(fs->backupboot_start, sizeof(*b), b);
198 break;
199 case '2':
200 fs_write(0, sizeof(b2), &b2);
201 break;
202 default:
203 break;
204 }
205 }
206}
207
208static void init_fsinfo(struct info_sector *i)
209{
Matt Mower18794c82015-11-11 16:22:45 -0600210 i->magic = htole32(0x41615252);
211 i->signature = htole32(0x61417272);
212 i->free_clusters = htole32(-1);
213 i->next_cluster = htole32(2);
214 i->boot_sign = htole16(0xaa55);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500215}
216
217static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, int lss)
218{
219 struct info_sector i;
220
221 if (!b->info_sector) {
222 printf("No FSINFO sector\n");
223 if (interactive)
224 printf("1) Create one\n2) Do without FSINFO\n");
225 else
226 printf(" Not automatically creating it.\n");
227 if (interactive && get_key("12", "?") == '1') {
228 /* search for a free reserved sector (not boot sector and not
229 * backup boot sector) */
Matt Mower18794c82015-11-11 16:22:45 -0600230 uint32_t s;
231 for (s = 1; s < le16toh(b->reserved); ++s)
232 if (s != le16toh(b->backup_boot))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500233 break;
Matt Mower18794c82015-11-11 16:22:45 -0600234 if (s > 0 && s < le16toh(b->reserved)) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500235 init_fsinfo(&i);
236 fs_write((loff_t) s * lss, sizeof(i), &i);
Matt Mower18794c82015-11-11 16:22:45 -0600237 b->info_sector = htole16(s);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500238 fs_write((loff_t) offsetof(struct boot_sector, info_sector),
239 sizeof(b->info_sector), &b->info_sector);
240 if (fs->backupboot_start)
241 fs_write(fs->backupboot_start +
242 offsetof(struct boot_sector, info_sector),
243 sizeof(b->info_sector), &b->info_sector);
244 } else {
245 printf("No free reserved sector found -- "
246 "no space for FSINFO sector!\n");
247 return;
248 }
249 } else
250 return;
251 }
252
Matt Mower18794c82015-11-11 16:22:45 -0600253 fs->fsinfo_start = le16toh(b->info_sector) * lss;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500254 fs_read(fs->fsinfo_start, sizeof(i), &i);
255
Matt Mower18794c82015-11-11 16:22:45 -0600256 if (i.magic != htole32(0x41615252) ||
257 i.signature != htole32(0x61417272) || i.boot_sign != htole16(0xaa55)) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500258 printf("FSINFO sector has bad magic number(s):\n");
Matt Mower18794c82015-11-11 16:22:45 -0600259 if (i.magic != htole32(0x41615252))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500260 printf(" Offset %llu: 0x%08x != expected 0x%08x\n",
261 (unsigned long long)offsetof(struct info_sector, magic),
Matt Mower18794c82015-11-11 16:22:45 -0600262 le32toh(i.magic), 0x41615252);
263 if (i.signature != htole32(0x61417272))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500264 printf(" Offset %llu: 0x%08x != expected 0x%08x\n",
265 (unsigned long long)offsetof(struct info_sector, signature),
Matt Mower18794c82015-11-11 16:22:45 -0600266 le32toh(i.signature), 0x61417272);
267 if (i.boot_sign != htole16(0xaa55))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500268 printf(" Offset %llu: 0x%04x != expected 0x%04x\n",
269 (unsigned long long)offsetof(struct info_sector, boot_sign),
Matt Mower18794c82015-11-11 16:22:45 -0600270 le16toh(i.boot_sign), 0xaa55);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500271 if (interactive)
272 printf("1) Correct\n2) Don't correct (FSINFO invalid then)\n");
273 else
274 printf(" Auto-correcting it.\n");
275 if (!interactive || get_key("12", "?") == '1') {
276 init_fsinfo(&i);
277 fs_write(fs->fsinfo_start, sizeof(i), &i);
278 } else
279 fs->fsinfo_start = 0;
280 }
281
282 if (fs->fsinfo_start)
Matt Mower18794c82015-11-11 16:22:45 -0600283 fs->free_clusters = le32toh(i.free_clusters);
284}
285
286static char print_fat_dirty_state(void)
287{
288 printf("Dirty bit is set. Fs was not properly unmounted and"
289 " some data may be corrupt.\n");
290
291 if (interactive) {
292 printf("1) Remove dirty bit\n" "2) No action\n");
293 return get_key("12", "?");
294 } else
295 printf(" Automatically removing dirty bit.\n");
296 return '1';
297}
298
299static void check_fat_state_bit(DOS_FS * fs, void *b)
300{
301 if (fs->fat_bits == 32) {
302 struct boot_sector *b32 = b;
303
304 if (b32->reserved3 & FAT_STATE_DIRTY) {
305 printf("0x41: ");
306 if (print_fat_dirty_state() == '1') {
307 b32->reserved3 &= ~FAT_STATE_DIRTY;
308 fs_write(0, sizeof(*b32), b32);
309 }
310 }
311 } else {
312 struct boot_sector_16 *b16 = b;
313
314 if (b16->reserved2 & FAT_STATE_DIRTY) {
315 printf("0x25: ");
316 if (print_fat_dirty_state() == '1') {
317 b16->reserved2 &= ~FAT_STATE_DIRTY;
318 fs_write(0, sizeof(*b16), b16);
319 }
320 }
321 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500322}
323
324void read_boot(DOS_FS * fs)
325{
326 struct boot_sector b;
327 unsigned total_sectors;
328 unsigned short logical_sector_size, sectors;
329 unsigned fat_length;
330 loff_t data_size;
331
332 fs_read(0, sizeof(b), &b);
333 logical_sector_size = GET_UNALIGNED_W(b.sector_size);
334 if (!logical_sector_size)
335 die("Logical sector size is zero.");
336
337 /* This was moved up because it's the first thing that will fail */
338 /* if the platform needs special handling of unaligned multibyte accesses */
339 /* but such handling isn't being provided. See GET_UNALIGNED_W() above. */
340 if (logical_sector_size & (SECTOR_SIZE - 1))
341 die("Logical sector size (%d bytes) is not a multiple of the physical "
342 "sector size.", logical_sector_size);
343
344 fs->cluster_size = b.cluster_size * logical_sector_size;
345 if (!fs->cluster_size)
346 die("Cluster size is zero.");
347 if (b.fats != 2 && b.fats != 1)
348 die("Currently, only 1 or 2 FATs are supported, not %d.\n", b.fats);
349 fs->nfats = b.fats;
350 sectors = GET_UNALIGNED_W(b.sectors);
Matt Mower18794c82015-11-11 16:22:45 -0600351 total_sectors = sectors ? sectors : le32toh(b.total_sect);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500352 if (verbose)
353 printf("Checking we can access the last sector of the filesystem\n");
354 /* Can't access last odd sector anyway, so round down */
355 fs_test((loff_t) ((total_sectors & ~1) - 1) * (loff_t) logical_sector_size,
356 logical_sector_size);
Matt Mower18794c82015-11-11 16:22:45 -0600357 fat_length = le16toh(b.fat_length) ?
358 le16toh(b.fat_length) : le32toh(b.fat32_length);
359 fs->fat_start = (loff_t) le16toh(b.reserved) * logical_sector_size;
360 fs->root_start = ((loff_t) le16toh(b.reserved) + b.fats * fat_length) *
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500361 logical_sector_size;
362 fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
363 fs->data_start = fs->root_start + ROUND_TO_MULTIPLE(fs->root_entries <<
364 MSDOS_DIR_BITS,
365 logical_sector_size);
366 data_size = (loff_t) total_sectors *logical_sector_size - fs->data_start;
367 fs->clusters = data_size / fs->cluster_size;
368 fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
369 fs->fsinfo_start = 0; /* no FSINFO structure */
370 fs->free_clusters = -1; /* unknown */
371 if (!b.fat_length && b.fat32_length) {
372 fs->fat_bits = 32;
Matt Mower18794c82015-11-11 16:22:45 -0600373 fs->root_cluster = le32toh(b.root_cluster);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500374 if (!fs->root_cluster && fs->root_entries)
375 /* M$ hasn't specified this, but it looks reasonable: If
376 * root_cluster is 0 but there is a separate root dir
377 * (root_entries != 0), we handle the root dir the old way. Give a
378 * warning, but convertig to a root dir in a cluster chain seems
379 * to complex for now... */
380 printf("Warning: FAT32 root dir not in cluster chain! "
381 "Compatibility mode...\n");
382 else if (!fs->root_cluster && !fs->root_entries)
383 die("No root directory!");
384 else if (fs->root_cluster && fs->root_entries)
385 printf("Warning: FAT32 root dir is in a cluster chain, but "
386 "a separate root dir\n"
387 " area is defined. Cannot fix this easily.\n");
388 if (fs->clusters < FAT16_THRESHOLD)
389 printf("Warning: Filesystem is FAT32 according to fat_length "
390 "and fat32_length fields,\n"
391 " but has only %lu clusters, less than the required "
392 "minimum of %d.\n"
393 " This may lead to problems on some systems.\n",
Matt Mower18794c82015-11-11 16:22:45 -0600394 (unsigned long)fs->clusters, FAT16_THRESHOLD);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500395
Matt Mower18794c82015-11-11 16:22:45 -0600396 check_fat_state_bit(fs, &b);
397 fs->backupboot_start = le16toh(b.backup_boot) * logical_sector_size;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500398 check_backup_boot(fs, &b, logical_sector_size);
399
400 read_fsinfo(fs, &b, logical_sector_size);
401 } else if (!atari_format) {
402 /* On real MS-DOS, a 16 bit FAT is used whenever there would be too
403 * much clusers otherwise. */
404 fs->fat_bits = (fs->clusters >= FAT12_THRESHOLD) ? 16 : 12;
405 if (fs->clusters >= FAT16_THRESHOLD)
406 die("Too many clusters (%lu) for FAT16 filesystem.", fs->clusters);
Matt Mower18794c82015-11-11 16:22:45 -0600407 check_fat_state_bit(fs, &b);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500408 } else {
409 /* On Atari, things are more difficult: GEMDOS always uses 12bit FATs
410 * on floppies, and always 16 bit on harddisks. */
411 fs->fat_bits = 16; /* assume 16 bit FAT for now */
412 /* If more clusters than fat entries in 16-bit fat, we assume
413 * it's a real MSDOS FS with 12-bit fat. */
414 if (fs->clusters + 2 > fat_length * logical_sector_size * 8 / 16 ||
415 /* if it's a floppy disk --> 12bit fat */
416 device_no == 2 ||
417 /* if it's a ramdisk or loopback device and has one of the usual
418 * floppy sizes -> 12bit FAT */
419 ((device_no == 1 || device_no == 7) &&
420 (total_sectors == 720 || total_sectors == 1440 ||
421 total_sectors == 2880)))
422 fs->fat_bits = 12;
423 }
424 /* On FAT32, the high 4 bits of a FAT entry are reserved */
425 fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits;
426 fs->fat_size = fat_length * logical_sector_size;
427
Matt Mower18794c82015-11-11 16:22:45 -0600428 fs->label = calloc(12, sizeof(uint8_t));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500429 if (fs->fat_bits == 12 || fs->fat_bits == 16) {
430 struct boot_sector_16 *b16 = (struct boot_sector_16 *)&b;
431 if (b16->extended_sig == 0x29)
432 memmove(fs->label, b16->label, 11);
433 else
434 fs->label = NULL;
435 } else if (fs->fat_bits == 32) {
436 if (b.extended_sig == 0x29)
437 memmove(fs->label, &b.label, 11);
438 else
439 fs->label = NULL;
440 }
441
442 if (fs->clusters >
Matt Mower18794c82015-11-11 16:22:45 -0600443 ((uint64_t)fs->fat_size * 8 / fs->fat_bits) - 2)
444 die("Filesystem has %d clusters but only space for %d FAT entries.",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500445 fs->clusters,
446 ((unsigned long long)fs->fat_size * 8 / fs->fat_bits) - 2);
447 if (!fs->root_entries && !fs->root_cluster)
448 die("Root directory has zero size.");
449 if (fs->root_entries & (MSDOS_DPS - 1))
450 die("Root directory (%d entries) doesn't span an integral number of "
451 "sectors.", fs->root_entries);
452 if (logical_sector_size & (SECTOR_SIZE - 1))
453 die("Logical sector size (%d bytes) is not a multiple of the physical "
454 "sector size.", logical_sector_size);
455#if 0 /* linux kernel doesn't check that either */
456 /* ++roman: On Atari, these two fields are often left uninitialized */
457 if (!atari_format && (!b.secs_track || !b.heads))
458 die("Invalid disk format in boot sector.");
459#endif
460 if (verbose)
461 dump_boot(fs, &b, logical_sector_size);
462}
463
464static void write_boot_label(DOS_FS * fs, char *label)
465{
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500466 if (fs->fat_bits == 12 || fs->fat_bits == 16) {
Matt Mower18794c82015-11-11 16:22:45 -0600467 struct boot_sector_16 b16;
468
469 fs_read(0, sizeof(b16), &b16);
470 if (b16.extended_sig != 0x29) {
471 b16.extended_sig = 0x29;
472 b16.serial = 0;
473 memmove(b16.fs_type, fs->fat_bits == 12 ? "FAT12 " : "FAT16 ",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500474 8);
475 }
Matt Mower18794c82015-11-11 16:22:45 -0600476 memmove(b16.label, label, 11);
477 fs_write(0, sizeof(b16), &b16);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500478 } else if (fs->fat_bits == 32) {
Matt Mower18794c82015-11-11 16:22:45 -0600479 struct boot_sector b;
480
481 fs_read(0, sizeof(b), &b);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500482 if (b.extended_sig != 0x29) {
483 b.extended_sig = 0x29;
484 b.serial = 0;
485 memmove(b.fs_type, "FAT32 ", 8);
486 }
487 memmove(b.label, label, 11);
Matt Mower18794c82015-11-11 16:22:45 -0600488 fs_write(0, sizeof(b), &b);
489 if (fs->backupboot_start)
490 fs_write(fs->backupboot_start, sizeof(b), &b);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500491 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500492}
493
Matt Mower18794c82015-11-11 16:22:45 -0600494loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500495{
Matt Mower18794c82015-11-11 16:22:45 -0600496 uint32_t cluster;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500497 loff_t offset;
498 int i;
499
500 if (fs->root_cluster) {
501 for (cluster = fs->root_cluster;
502 cluster != 0 && cluster != -1;
503 cluster = next_cluster(fs, cluster)) {
504 offset = cluster_start(fs, cluster);
505 for (i = 0; i * sizeof(DIR_ENT) < fs->cluster_size; i++) {
506 fs_read(offset, sizeof(DIR_ENT), de);
Matt Mower18794c82015-11-11 16:22:45 -0600507 if (de->attr != VFAT_LN_ATTR && de->attr & ATTR_VOLUME)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500508 return offset;
509 offset += sizeof(DIR_ENT);
510 }
511 }
512 } else {
513 for (i = 0; i < fs->root_entries; i++) {
514 offset = fs->root_start + i * sizeof(DIR_ENT);
515 fs_read(offset, sizeof(DIR_ENT), de);
Matt Mower18794c82015-11-11 16:22:45 -0600516 if (de->attr != VFAT_LN_ATTR && de->attr & ATTR_VOLUME)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500517 return offset;
518 }
519 }
520
521 return 0;
522}
523
524static void write_volume_label(DOS_FS * fs, char *label)
525{
526 time_t now = time(NULL);
527 struct tm *mtime = localtime(&now);
528 loff_t offset;
Matt Mower18794c82015-11-11 16:22:45 -0600529 int created;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500530 DIR_ENT de;
531
Matt Mower18794c82015-11-11 16:22:45 -0600532 created = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500533 offset = find_volume_de(fs, &de);
Matt Mower18794c82015-11-11 16:22:45 -0600534 if (offset == 0) {
535 created = 1;
536 offset = alloc_rootdir_entry(fs, &de, label);
537 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500538 memcpy(de.name, label, 11);
Matt Mower18794c82015-11-11 16:22:45 -0600539 de.time = htole16((unsigned short)((mtime->tm_sec >> 1) +
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500540 (mtime->tm_min << 5) +
541 (mtime->tm_hour << 11)));
Matt Mower18794c82015-11-11 16:22:45 -0600542 de.date = htole16((unsigned short)(mtime->tm_mday +
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500543 ((mtime->tm_mon + 1) << 5) +
544 ((mtime->tm_year - 80) << 9)));
Matt Mower18794c82015-11-11 16:22:45 -0600545 if (created) {
546 de.attr = ATTR_VOLUME;
547 de.ctime_ms = 0;
548 de.ctime = de.time;
549 de.cdate = de.date;
550 de.adate = de.date;
551 de.starthi = 0;
552 de.start = 0;
553 de.size = 0;
554 }
555
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500556 fs_write(offset, sizeof(DIR_ENT), &de);
557}
558
559void write_label(DOS_FS * fs, char *label)
560{
561 int l = strlen(label);
562
563 while (l < 11)
564 label[l++] = ' ';
565
566 write_boot_label(fs, label);
567 write_volume_label(fs, label);
568}