"Fossies" - the Fresh Open Source Software Archive 
Member "dosfstools-4.2/src/boot.c" (31 Jan 2021, 24197 Bytes) of package /linux/misc/dosfstools-4.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "boot.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
4.1_vs_4.2.
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-2017 Andreas Bombe <aeb@debian.org>
7 Copyright (C) 2018-2021 Pali Rohár <pali.rohar@gmail.com>
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 The complete text of the GNU General Public License
23 can be found in /usr/share/common-licenses/GPL-3 file.
24 */
25
26 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
27 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
28
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <time.h>
36
37 #include "common.h"
38 #include "fsck.fat.h"
39 #include "fat.h"
40 #include "io.h"
41 #include "boot.h"
42 #include "check.h"
43 #include "charconv.h"
44
45 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
46 /* don't divide by zero */
47
48 /* cut-over cluster counts for FAT12 and FAT16 */
49 #define FAT12_THRESHOLD 4085
50 #define FAT16_THRESHOLD 65525
51
52 off_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern, int gen_name)
53 {
54 static int curr_num = 0;
55 off_t offset;
56
57 if (fs->root_cluster) {
58 DIR_ENT d2;
59 int i = 0, got = 0;
60 uint32_t clu_num, prev = 0;
61 off_t offset2;
62
63 clu_num = fs->root_cluster;
64 offset = cluster_start(fs, clu_num);
65 while (clu_num > 0 && clu_num != -1) {
66 fs_read(offset, sizeof(DIR_ENT), &d2);
67 if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) {
68 got = 1;
69 break;
70 }
71 i += sizeof(DIR_ENT);
72 offset += sizeof(DIR_ENT);
73 if ((i % fs->cluster_size) == 0) {
74 prev = clu_num;
75 if ((clu_num = next_cluster(fs, clu_num)) == 0 || clu_num == -1)
76 break;
77 offset = cluster_start(fs, clu_num);
78 }
79 }
80 if (!got) {
81 /* no free slot, need to extend root dir: alloc next free cluster
82 * after previous one */
83 if (!prev)
84 die("Root directory has no cluster allocated!");
85 for (clu_num = prev + 1; clu_num != prev; clu_num++) {
86 FAT_ENTRY entry;
87
88 if (clu_num >= fs->data_clusters + 2)
89 clu_num = 2;
90 get_fat(&entry, fs->fat, clu_num, fs);
91 if (!entry.value)
92 break;
93 }
94 if (clu_num == prev)
95 die("Root directory full and no free cluster");
96 set_fat(fs, prev, clu_num);
97 set_fat(fs, clu_num, -1);
98 set_owner(fs, clu_num, get_owner(fs, fs->root_cluster));
99 /* clear new cluster */
100 memset(&d2, 0, sizeof(d2));
101 offset = cluster_start(fs, clu_num);
102 for (i = 0; i < fs->cluster_size; i += sizeof(DIR_ENT))
103 fs_write(offset + i, sizeof(d2), &d2);
104 }
105 memset(de, 0, sizeof(DIR_ENT));
106 if (gen_name) {
107 while (1) {
108 char expanded[12];
109 sprintf(expanded, pattern, curr_num);
110 memcpy(de->name, expanded, MSDOS_NAME);
111 clu_num = fs->root_cluster;
112 i = 0;
113 offset2 = cluster_start(fs, clu_num);
114 while (clu_num > 0 && clu_num != -1) {
115 fs_read(offset2, sizeof(DIR_ENT), &d2);
116 if (offset2 != offset &&
117 !strncmp((const char *)d2.name, (const char *)de->name,
118 MSDOS_NAME))
119 break;
120 i += sizeof(DIR_ENT);
121 offset2 += sizeof(DIR_ENT);
122 if ((i % fs->cluster_size) == 0) {
123 if ((clu_num = next_cluster(fs, clu_num)) == 0 ||
124 clu_num == -1)
125 break;
126 offset2 = cluster_start(fs, clu_num);
127 }
128 }
129 if (clu_num == 0 || clu_num == -1)
130 break;
131 if (++curr_num >= 10000)
132 die("Unable to create unique name");
133 }
134 } else {
135 memcpy(de->name, pattern, MSDOS_NAME);
136 }
137 } else {
138 DIR_ENT *root;
139 int next_free = 0, scan;
140
141 root = alloc(fs->root_entries * sizeof(DIR_ENT));
142 fs_read(fs->root_start, fs->root_entries * sizeof(DIR_ENT), root);
143
144 while (next_free < fs->root_entries)
145 if (IS_FREE(root[next_free].name) &&
146 root[next_free].attr != VFAT_LN_ATTR)
147 break;
148 else
149 next_free++;
150 if (next_free == fs->root_entries)
151 die("Root directory is full.");
152 offset = fs->root_start + next_free * sizeof(DIR_ENT);
153 memset(de, 0, sizeof(DIR_ENT));
154 if (gen_name) {
155 while (1) {
156 char expanded[12];
157 sprintf(expanded, pattern, curr_num);
158 memcpy(de->name, expanded, MSDOS_NAME);
159 for (scan = 0; scan < fs->root_entries; scan++)
160 if (scan != next_free &&
161 !strncmp((const char *)root[scan].name,
162 (const char *)de->name, MSDOS_NAME))
163 break;
164 if (scan == fs->root_entries)
165 break;
166 if (++curr_num >= 10000)
167 die("Unable to create unique name");
168 }
169 } else {
170 memcpy(de->name, pattern, MSDOS_NAME);
171 }
172 free(root);
173 }
174 ++n_files;
175 return offset;
176 }
177
178 static struct {
179 uint8_t media;
180 const char *descr;
181 } mediabytes[] = {
182 {
183 0xf0, "5.25\" or 3.5\" HD floppy"}, {
184 0xf8, "hard disk"}, {
185 0xf9, "3,5\" 720k floppy 2s/80tr/9sec or "
186 "5.25\" 1.2M floppy 2s/80tr/15sec"}, {
187 0xfa, "5.25\" 320k floppy 1s/80tr/8sec"}, {
188 0xfb, "3.5\" 640k floppy 2s/80tr/8sec"}, {
189 0xfc, "5.25\" 180k floppy 1s/40tr/9sec"}, {
190 0xfd, "5.25\" 360k floppy 2s/40tr/9sec"}, {
191 0xfe, "5.25\" 160k floppy 1s/40tr/8sec"}, {
192 0xff, "5.25\" 320k floppy 2s/40tr/8sec"},};
193
194 /* Unaligned fields must first be accessed byte-wise */
195 #define GET_UNALIGNED_W(f) \
196 ( (uint16_t)f[0] | ((uint16_t)f[1]<<8) )
197
198 static const char *get_media_descr(unsigned char media)
199 {
200 int i;
201
202 for (i = 0; i < sizeof(mediabytes) / sizeof(*mediabytes); ++i) {
203 if (mediabytes[i].media == media)
204 return (mediabytes[i].descr);
205 }
206 return ("undefined");
207 }
208
209 static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss)
210 {
211 unsigned short sectors;
212
213 printf("Boot sector contents:\n");
214 if (!atari_format) {
215 char id[9];
216 strncpy(id, (const char *)b->system_id, 8);
217 id[8] = 0;
218 printf("System ID \"%s\"\n", id);
219 } else {
220 /* On Atari, a 24 bit serial number is stored at offset 8 of the boot
221 * sector */
222 printf("Serial number 0x%x\n",
223 b->system_id[5] | (b->system_id[6] << 8) | (b->
224 system_id[7] << 16));
225 }
226 printf("Media byte 0x%02x (%s)\n", b->media, get_media_descr(b->media));
227 printf("%10d bytes per logical sector\n", GET_UNALIGNED_W(b->sector_size));
228 printf("%10d bytes per cluster\n", fs->cluster_size);
229 printf("%10d reserved sector%s\n", le16toh(b->reserved),
230 le16toh(b->reserved) == 1 ? "" : "s");
231 printf("First FAT starts at byte %llu (sector %llu)\n",
232 (unsigned long long)fs->fat_start,
233 (unsigned long long)fs->fat_start / lss);
234 printf("%10d FATs, %d bit entries\n", b->fats, fs->fat_bits);
235 printf("%10u bytes per FAT (= %u sectors)\n", fs->fat_size,
236 fs->fat_size / lss);
237 if (!fs->root_cluster) {
238 printf("Root directory starts at byte %llu (sector %llu)\n",
239 (unsigned long long)fs->root_start,
240 (unsigned long long)fs->root_start / lss);
241 printf("%10d root directory entries\n", fs->root_entries);
242 } else {
243 printf("Root directory start at cluster %lu (arbitrary size)\n",
244 (unsigned long)fs->root_cluster);
245 }
246 printf("Data area starts at byte %llu (sector %llu)\n",
247 (unsigned long long)fs->data_start,
248 (unsigned long long)fs->data_start / lss);
249 printf("%10lu data clusters (%llu bytes)\n",
250 (unsigned long)fs->data_clusters,
251 (unsigned long long)fs->data_clusters * fs->cluster_size);
252 printf("%u sectors/track, %u heads\n", le16toh(b->secs_track),
253 le16toh(b->heads));
254 printf("%10u hidden sectors\n", atari_format ?
255 /* On Atari, the hidden field is only 16 bit wide and unused */
256 (((unsigned char *)&b->hidden)[0] |
257 ((unsigned char *)&b->hidden)[1] << 8) : le32toh(b->hidden));
258 sectors = GET_UNALIGNED_W(b->sectors);
259 printf("%10u sectors total\n", sectors ? sectors : le32toh(b->total_sect));
260 }
261
262 static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, unsigned int lss)
263 {
264 struct boot_sector b2;
265
266 if (!fs->backupboot_start) {
267 printf("There is no backup boot sector.\n");
268 if (le16toh(b->reserved) < 3) {
269 printf("And there is no space for creating one!\n");
270 return;
271 }
272 if (get_choice(1, " Auto-creating backup boot block.",
273 2,
274 1, "Create one",
275 2, "Do without a backup") == 1) {
276 unsigned int bbs;
277 /* The usual place for the backup boot sector is sector 6. Choose
278 * that or the last reserved sector. */
279 if (le16toh(b->reserved) >= 7 && le16toh(b->info_sector) != 6)
280 bbs = 6;
281 else {
282 bbs = le16toh(b->reserved) - 1;
283 if (bbs == le16toh(b->info_sector))
284 --bbs; /* this is never 0, as we checked reserved >= 3! */
285 }
286 fs->backupboot_start = bbs * lss;
287 b->backup_boot = htole16(bbs);
288 fs_write(fs->backupboot_start, sizeof(*b), b);
289 fs_write(offsetof(struct boot_sector, backup_boot),
290 sizeof(b->backup_boot), &b->backup_boot);
291 printf("Created backup of boot sector in sector %d\n", bbs);
292 return;
293 } else
294 return;
295 }
296
297 fs_read(fs->backupboot_start, sizeof(b2), &b2);
298 if (memcmp(b, &b2, sizeof(b2)) != 0) {
299 /* there are any differences */
300 uint8_t *p, *q;
301 int i, pos, first = 1;
302 char buf[32];
303
304 printf("There are differences between boot sector and its backup.\n");
305 printf("This is mostly harmless. Differences: (offset:original/backup)\n ");
306 pos = 2;
307 for (p = (uint8_t *) b, q = (uint8_t *) & b2, i = 0; i < sizeof(b2);
308 ++p, ++q, ++i) {
309 if (*p != *q) {
310 sprintf(buf, "%s%u:%02x/%02x", first ? "" : ", ",
311 (unsigned)(p - (uint8_t *) b), *p, *q);
312 if (pos + strlen(buf) > 78)
313 printf("\n "), pos = 2;
314 printf("%s", buf);
315 pos += strlen(buf);
316 first = 0;
317 }
318 }
319 printf("\n");
320
321 switch (get_choice(3, " Not automatically fixing this.",
322 3,
323 1, "Copy original to backup",
324 2, "Copy backup to original",
325 3, "No action")) {
326 case 1:
327 fs_write(fs->backupboot_start, sizeof(*b), b);
328 break;
329 case 2:
330 fs_write(0, sizeof(b2), &b2);
331 break;
332 default:
333 break;
334 }
335 }
336 }
337
338 static void init_fsinfo_except_reserved(struct info_sector *i)
339 {
340 i->magic = htole32(0x41615252);
341 i->signature = htole32(0x61417272);
342 i->free_clusters = htole32(-1);
343 i->next_cluster = htole32(2);
344 i->boot_sign = htole32(0xaa550000);
345 }
346
347 static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, unsigned int lss)
348 {
349 struct info_sector i;
350
351 if (!b->info_sector) {
352 printf("No FSINFO sector\n");
353 if (get_choice(2, " Not automatically creating it.",
354 2,
355 1, "Create one",
356 2, "Do without FSINFO") == 1) {
357 /* search for a free reserved sector (not boot sector and not
358 * backup boot sector) */
359 uint32_t s;
360 for (s = 1; s < le16toh(b->reserved); ++s)
361 if (s != le16toh(b->backup_boot))
362 break;
363 if (s > 0 && s < le16toh(b->reserved)) {
364 memset(&i, 0, sizeof (struct info_sector));
365 init_fsinfo_except_reserved(&i);
366 fs_write((off_t)s * lss, sizeof(i), &i);
367 b->info_sector = htole16(s);
368 fs_write(offsetof(struct boot_sector, info_sector),
369 sizeof(b->info_sector), &b->info_sector);
370 if (fs->backupboot_start)
371 fs_write(fs->backupboot_start +
372 offsetof(struct boot_sector, info_sector),
373 sizeof(b->info_sector), &b->info_sector);
374 } else {
375 printf("No free reserved sector found -- "
376 "no space for FSINFO sector!\n");
377 return;
378 }
379 } else
380 return;
381 }
382
383 fs->fsinfo_start = le16toh(b->info_sector) * lss;
384 fs_read(fs->fsinfo_start, sizeof(i), &i);
385
386 if (i.magic != htole32(0x41615252) ||
387 i.signature != htole32(0x61417272) || i.boot_sign != htole32(0xaa550000)) {
388 printf("FSINFO sector has bad magic number(s):\n");
389 if (i.magic != htole32(0x41615252))
390 printf(" Offset %llu: 0x%08x != expected 0x%08x\n",
391 (unsigned long long)offsetof(struct info_sector, magic),
392 le32toh(i.magic), 0x41615252);
393 if (i.signature != htole32(0x61417272))
394 printf(" Offset %llu: 0x%08x != expected 0x%08x\n",
395 (unsigned long long)offsetof(struct info_sector, signature),
396 le32toh(i.signature), 0x61417272);
397 if (i.boot_sign != htole32(0xaa550000))
398 printf(" Offset %llu: 0x%08x != expected 0x%08x\n",
399 (unsigned long long)offsetof(struct info_sector, boot_sign),
400 le32toh(i.boot_sign), 0xaa550000);
401 if (get_choice(1, " Auto-correcting it.",
402 2,
403 1, "Correct",
404 2, "Don't correct (FSINFO invalid then)") == 1) {
405 init_fsinfo_except_reserved(&i);
406 fs_write(fs->fsinfo_start, sizeof(i), &i);
407 } else
408 fs->fsinfo_start = 0;
409 }
410
411 if (fs->fsinfo_start)
412 fs->free_clusters = le32toh(i.free_clusters);
413 }
414
415 void read_boot(DOS_FS * fs)
416 {
417 struct boot_sector b;
418 unsigned total_sectors;
419 unsigned int logical_sector_size, sectors;
420 long long fat_length;
421 unsigned total_fat_entries;
422 off_t data_size;
423 long long position;
424
425 fs_read(0, sizeof(b), &b);
426 logical_sector_size = GET_UNALIGNED_W(b.sector_size);
427 if (!logical_sector_size)
428 die("Logical sector size is zero.");
429
430 /* This was moved up because it's the first thing that will fail */
431 /* if the platform needs special handling of unaligned multibyte accesses */
432 /* but such handling isn't being provided. See GET_UNALIGNED_W() above. */
433 if (logical_sector_size & (SECTOR_SIZE - 1))
434 die("Logical sector size (%u bytes) is not a multiple of the physical "
435 "sector size.", logical_sector_size);
436
437 fs->cluster_size = b.cluster_size * logical_sector_size;
438 if (!fs->cluster_size)
439 die("Cluster size is zero.");
440 if (b.fats != 2 && b.fats != 1)
441 die("Currently, only 1 or 2 FATs are supported, not %d.\n", b.fats);
442 fs->nfats = b.fats;
443 sectors = GET_UNALIGNED_W(b.sectors);
444 total_sectors = sectors ? sectors : le32toh(b.total_sect);
445 if (verbose)
446 printf("Checking we can access the last sector of the filesystem\n");
447 /* Can't access last odd sector anyway, so round down */
448 position = (long long)((total_sectors & ~1) - 1) * logical_sector_size;
449 if (position > OFF_MAX)
450 die("Filesystem is too large.");
451 if (!fs_test(position, logical_sector_size))
452 die("Failed to read sector %u.", (total_sectors & ~1) - 1);
453
454 fat_length = le16toh(b.fat_length) ?
455 le16toh(b.fat_length) : le32toh(b.fat32_length);
456 if (!fat_length)
457 die("FAT size is zero.");
458
459 fs->fat_start = (off_t)le16toh(b.reserved) * logical_sector_size;
460 position = (le16toh(b.reserved) + b.fats * fat_length) *
461 logical_sector_size;
462 if (position > OFF_MAX)
463 die("Filesystem is too large.");
464 fs->root_start = position;
465 fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
466 position = (long long)fs->root_start +
467 ROUND_TO_MULTIPLE(fs->root_entries << MSDOS_DIR_BITS,
468 logical_sector_size);
469 if (position > OFF_MAX)
470 die("Filesystem is too large.");
471 fs->data_start = position;
472 position = (long long)total_sectors * logical_sector_size - fs->data_start;
473 if (position > OFF_MAX)
474 die("Filesystem is too large.");
475 data_size = position;
476 if (data_size < fs->cluster_size)
477 die("Filesystem has no space for any data clusters");
478
479 fs->data_clusters = data_size / fs->cluster_size;
480 fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
481 fs->fsinfo_start = 0; /* no FSINFO structure */
482 fs->free_clusters = -1; /* unknown */
483 if (!b.fat_length && b.fat32_length) {
484 fs->fat_bits = 32;
485 fs->root_cluster = le32toh(b.root_cluster);
486 if (!fs->root_cluster && fs->root_entries)
487 /* M$ hasn't specified this, but it looks reasonable: If
488 * root_cluster is 0 but there is a separate root dir
489 * (root_entries != 0), we handle the root dir the old way. Give a
490 * warning, but convertig to a root dir in a cluster chain seems
491 * to complex for now... */
492 fprintf(stderr, "Warning: FAT32 root dir not in cluster chain! "
493 "Compatibility mode...\n");
494 else if (!fs->root_cluster && !fs->root_entries)
495 die("No root directory!");
496 else if (fs->root_cluster && fs->root_entries)
497 fprintf(stderr, "Warning: FAT32 root dir is in a cluster chain, but "
498 "a separate root dir\n"
499 " area is defined. Cannot fix this easily.\n");
500 if (fs->data_clusters < FAT16_THRESHOLD)
501 fprintf(stderr, "Warning: Filesystem is FAT32 according to fat_length "
502 "and fat32_length fields,\n"
503 " but has only %lu clusters, less than the required "
504 "minimum of %d.\n"
505 " This may lead to problems on some systems.\n",
506 (unsigned long)fs->data_clusters, FAT16_THRESHOLD);
507
508 fs->backupboot_start = le16toh(b.backup_boot) * logical_sector_size;
509 check_backup_boot(fs, &b, logical_sector_size);
510
511 read_fsinfo(fs, &b, logical_sector_size);
512 } else if (!atari_format) {
513 /* On real MS-DOS, a 16 bit FAT is used whenever there would be too
514 * much clusers otherwise. */
515 fs->fat_bits = (fs->data_clusters >= FAT12_THRESHOLD) ? 16 : 12;
516 if (fs->data_clusters >= FAT16_THRESHOLD)
517 die("Too many clusters (%lu) for FAT16 filesystem.",
518 (unsigned long)fs->data_clusters);
519 } else {
520 /* On Atari, things are more difficult: GEMDOS always uses 12bit FATs
521 * on floppies, and always 16 bit on harddisks. */
522 fs->fat_bits = 16; /* assume 16 bit FAT for now */
523 /* If more clusters than fat entries in 16-bit fat, we assume
524 * it's a real MSDOS FS with 12-bit fat. */
525 if (fs->data_clusters + 2 > fat_length * logical_sector_size * 8 / 16 ||
526 /* if it has one of the usual floppy sizes -> 12bit FAT */
527 (total_sectors == 720 || total_sectors == 1440 ||
528 total_sectors == 2880))
529 fs->fat_bits = 12;
530 }
531 /* On FAT32, the high 4 bits of a FAT entry are reserved */
532 fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits;
533 position = fat_length * logical_sector_size;
534 if (position > OFF_MAX)
535 die("Filesystem is too large.");
536 fs->fat_size = position;
537
538 fs->label[0] = 0;
539 if (fs->fat_bits == 12 || fs->fat_bits == 16) {
540 struct boot_sector_16 *b16 = (struct boot_sector_16 *)&b;
541 if (b16->extended_sig == 0x29) {
542 memmove(fs->label, b16->label, 11);
543 fs->serial = b16->serial;
544 }
545 } else if (fs->fat_bits == 32) {
546 if (b.extended_sig == 0x29) {
547 memmove(fs->label, &b.label, 11);
548 fs->serial = b.serial;
549 }
550 }
551
552 position = (long long)fs->fat_size * 8 / fs->fat_bits;
553 if (position > UINT_MAX)
554 die("FAT has space for too many entries (%lld).", (long long)position);
555 total_fat_entries = position;
556 if (fs->data_clusters > total_fat_entries - 2)
557 die("Filesystem has %u clusters but only space for %u FAT entries.",
558 fs->data_clusters, total_fat_entries - 2);
559 if (!fs->root_entries && !fs->root_cluster)
560 die("Root directory has zero size.");
561 if (fs->root_entries & (MSDOS_DPS - 1))
562 die("Root directory (%d entries) doesn't span an integral number of "
563 "sectors.", fs->root_entries);
564 if (logical_sector_size & (SECTOR_SIZE - 1))
565 die("Logical sector size (%u bytes) is not a multiple of the physical "
566 "sector size.", logical_sector_size);
567 #if 0 /* linux kernel doesn't check that either */
568 /* ++roman: On Atari, these two fields are often left uninitialized */
569 if (!atari_format && (!b.secs_track || !b.heads))
570 die("Invalid disk format in boot sector.");
571 #endif
572 if (verbose)
573 dump_boot(fs, &b, logical_sector_size);
574 }
575
576 static void write_boot_label_or_serial(int label_mode, DOS_FS * fs,
577 const char *label, uint32_t serial)
578 {
579 if (fs->fat_bits == 12 || fs->fat_bits == 16) {
580 struct boot_sector_16 b16;
581
582 fs_read(0, sizeof(b16), &b16);
583 if (b16.extended_sig != 0x29) {
584 b16.extended_sig = 0x29;
585 b16.serial = 0;
586 memmove(b16.label, "NO NAME ", 11);
587 memmove(b16.fs_type, fs->fat_bits == 12 ? "FAT12 " : "FAT16 ",
588 8);
589 }
590
591 if (label_mode)
592 memmove(b16.label, label, 11);
593 else
594 b16.serial = serial;
595
596 fs_write(0, sizeof(b16), &b16);
597 } else if (fs->fat_bits == 32) {
598 struct boot_sector b;
599
600 fs_read(0, sizeof(b), &b);
601 if (b.extended_sig != 0x29) {
602 b.extended_sig = 0x29;
603 b.serial = 0;
604 memmove(b.label, "NO NAME ", 11);
605 memmove(b.fs_type, "FAT32 ", 8);
606 }
607
608 if (label_mode)
609 memmove(b.label, label, 11);
610 else
611 b.serial = serial;
612
613 fs_write(0, sizeof(b), &b);
614 if (fs->backupboot_start)
615 fs_write(fs->backupboot_start, sizeof(b), &b);
616 }
617 }
618
619 void write_boot_label(DOS_FS * fs, const char *label)
620 {
621 write_boot_label_or_serial(1, fs, label, 0);
622 }
623
624 void write_serial(DOS_FS * fs, uint32_t serial)
625 {
626 write_boot_label_or_serial(0, fs, NULL, serial);
627 }
628
629 off_t find_volume_de(DOS_FS * fs, DIR_ENT * de)
630 {
631 uint32_t cluster;
632 off_t offset;
633 int i;
634
635 if (fs->root_cluster) {
636 for (cluster = fs->root_cluster;
637 cluster != 0 && cluster != -1;
638 cluster = next_cluster(fs, cluster)) {
639 offset = cluster_start(fs, cluster);
640 for (i = 0; i * sizeof(DIR_ENT) < fs->cluster_size; i++) {
641 fs_read(offset, sizeof(DIR_ENT), de);
642
643 /* no point in scanning after end of directory marker */
644 if (!de->name[0])
645 return 0;
646
647 if (!IS_FREE(de->name) &&
648 de->attr != VFAT_LN_ATTR && de->attr & ATTR_VOLUME)
649 return offset;
650 offset += sizeof(DIR_ENT);
651 }
652 }
653 } else {
654 for (i = 0; i < fs->root_entries; i++) {
655 offset = fs->root_start + i * sizeof(DIR_ENT);
656 fs_read(offset, sizeof(DIR_ENT), de);
657
658 /* no point in scanning after end of directory marker */
659 if (!de->name[0])
660 return 0;
661
662 if (!IS_FREE(de->name) &&
663 de->attr != VFAT_LN_ATTR && de->attr & ATTR_VOLUME)
664 return offset;
665 }
666 }
667
668 return 0;
669 }
670
671 void write_volume_label(DOS_FS * fs, char *label)
672 {
673 time_t now;
674 struct tm *mtime;
675 off_t offset;
676 int created;
677 DIR_ENT de;
678
679 created = 0;
680 offset = find_volume_de(fs, &de);
681 if (offset == 0) {
682 created = 1;
683 offset = alloc_rootdir_entry(fs, &de, label, 0);
684 }
685
686 memcpy(de.name, label, 11);
687 if (de.name[0] == 0xe5)
688 de.name[0] = 0x05;
689
690 now = time(NULL);
691 mtime = (now != (time_t)-1) ? localtime(&now) : NULL;
692 if (mtime && mtime->tm_year >= 80 && mtime->tm_year <= 207) {
693 de.time = htole16((unsigned short)((mtime->tm_sec >> 1) +
694 (mtime->tm_min << 5) +
695 (mtime->tm_hour << 11)));
696 de.date = htole16((unsigned short)(mtime->tm_mday +
697 ((mtime->tm_mon + 1) << 5) +
698 ((mtime->tm_year - 80) << 9)));
699 } else {
700 /* fallback to 1.1.1980 00:00:00 */
701 de.time = htole16(0);
702 de.date = htole16(1 + (1 << 5));
703 }
704 if (created) {
705 de.attr = ATTR_VOLUME;
706 de.ctime_ms = 0;
707 de.ctime = de.time;
708 de.cdate = de.date;
709 de.adate = de.date;
710 de.starthi = 0;
711 de.start = 0;
712 de.size = 0;
713 }
714
715 fs_write(offset, sizeof(DIR_ENT), &de);
716 }
717
718 void write_label(DOS_FS * fs, char *label)
719 {
720 int l = strlen(label);
721
722 while (l < 11)
723 label[l++] = ' ';
724
725 write_boot_label(fs, label);
726 write_volume_label(fs, label);
727 }
728
729 void remove_label(DOS_FS *fs)
730 {
731 off_t offset;
732 DIR_ENT de;
733
734 write_boot_label(fs, "NO NAME ");
735
736 offset = find_volume_de(fs, &de);
737 if (offset) {
738 /* mark entry as deleted */
739 de.name[0] = 0xe5;
740 /* remove ATTR_VOLUME for compatibility with older fatlabel version
741 * which ignores above deletion mark for entries with ATTR_VOLUME */
742 de.attr = 0;
743 fs_write(offset, sizeof(DIR_ENT), &de);
744 }
745 }
746
747 const char *pretty_label(const char *label)
748 {
749 static char buffer[256];
750 char *p;
751 int i;
752 int last;
753
754 for (last = 10; last >= 0; last--) {
755 if (label[last] != ' ')
756 break;
757 }
758
759 p = buffer;
760 for (i = 0; i <= last && label[i] && p < buffer + sizeof(buffer) - 1; ++i) {
761 if (!dos_char_to_printable(&p, label[i], buffer + sizeof(buffer) - 1 - p))
762 *p++ = '_';
763 }
764 *p = 0;
765
766 return buffer;
767 }