"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 }