"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "dosfstools-2.11/dosfsck/boot.c" of archive dosfstools-2.11.src.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /* boot.c  -  Read and analyze ia PC/MS-DOS boot sector */
    2 
    3 /* Written 1993 by Werner Almesberger */
    4 
    5 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
    6  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
    7 
    8 #include <stdio.h>
    9 #include <string.h>
   10 #include <sys/types.h>
   11 
   12 #include "common.h"
   13 #include "dosfsck.h"
   14 #include "io.h"
   15 #include "boot.h"
   16 
   17 
   18 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
   19     /* don't divide by zero */
   20 
   21 static struct {
   22     __u8 media;
   23     char *descr;
   24 } mediabytes[] = {
   25     { 0xf0, "5.25\" or 3.5\" HD floppy" },
   26     { 0xf8, "hard disk" },
   27     { 0xf9, "3,5\" 720k floppy 2s/80tr/9sec or "
   28             "5.25\" 1.2M floppy 2s/80tr/15sec" },
   29     { 0xfa, "5.25\" 320k floppy 1s/80tr/8sec" },
   30     { 0xfb, "3.5\" 640k floppy 2s/80tr/8sec" },
   31     { 0xfc, "5.25\" 180k floppy 1s/40tr/9sec" },
   32     { 0xfd, "5.25\" 360k floppy 2s/40tr/9sec" },
   33     { 0xfe, "5.25\" 160k floppy 1s/40tr/8sec" },
   34     { 0xff, "5.25\" 320k floppy 2s/40tr/8sec" },
   35 };
   36 
   37 #if defined __alpha || defined __ia64__ || defined __s390x__ || defined __x86_64__ || defined __ppc64__
   38 /* Unaligned fields must first be copied byte-wise */
   39 #define GET_UNALIGNED_W(f)			\
   40     ({						\
   41 	unsigned short __v;			\
   42 	memcpy( &__v, &f, sizeof(__v) );	\
   43 	CF_LE_W( *(unsigned short *)&f );	\
   44     })
   45 #else
   46 #define GET_UNALIGNED_W(f) CF_LE_W( *(unsigned short *)&f )
   47 #endif
   48 
   49 
   50 static char *get_media_descr( unsigned char media )
   51 {
   52     int i;
   53 
   54     for( i = 0; i < sizeof(mediabytes)/sizeof(*mediabytes); ++i ) {
   55 	if (mediabytes[i].media == media)
   56 	    return( mediabytes[i].descr );
   57     }
   58     return( "undefined" );
   59 }
   60 
   61 static void dump_boot(DOS_FS *fs,struct boot_sector *b,unsigned lss)
   62 {
   63     unsigned short sectors;
   64 
   65     printf("Boot sector contents:\n");
   66     if (!atari_format) {
   67 	char id[9];
   68 	strncpy(id,b->system_id,8);
   69 	id[8] = 0;
   70 	printf("System ID \"%s\"\n",id);
   71     }
   72     else {
   73 	/* On Atari, a 24 bit serial number is stored at offset 8 of the boot
   74 	 * sector */
   75 	printf("Serial number 0x%x\n",
   76 	       b->system_id[5] | (b->system_id[6]<<8) | (b->system_id[7]<<16));
   77     }
   78     printf("Media byte 0x%02x (%s)\n",b->media,get_media_descr(b->media));
   79     printf("%10d bytes per logical sector\n",GET_UNALIGNED_W(b->sector_size));
   80     printf("%10d bytes per cluster\n",fs->cluster_size);
   81     printf("%10d reserved sector%s\n",CF_LE_W(b->reserved),
   82 	   CF_LE_W(b->reserved) == 1 ? "" : "s");
   83     printf("First FAT starts at byte %llu (sector %llu)\n",
   84 	   (unsigned long long)fs->fat_start,
   85 	   (unsigned long long)fs->fat_start/lss);
   86     printf("%10d FATs, %d bit entries\n",b->fats,fs->fat_bits);
   87     printf("%10d bytes per FAT (= %u sectors)\n",fs->fat_size,
   88 	   fs->fat_size/lss);
   89     if (!fs->root_cluster) {
   90 	printf("Root directory starts at byte %llu (sector %llu)\n",
   91 	       (unsigned long long)fs->root_start,
   92 	       (unsigned long long)fs->root_start/lss);
   93 	printf("%10d root directory entries\n",fs->root_entries);
   94     }
   95     else {
   96 	printf( "Root directory start at cluster %lu (arbitrary size)\n",
   97 		fs->root_cluster);
   98     }
   99     printf("Data area starts at byte %llu (sector %llu)\n",
  100 	   (unsigned long long)fs->data_start,
  101 	   (unsigned long long)fs->data_start/lss);
  102     printf("%10lu data clusters (%llu bytes)\n",fs->clusters,
  103 	   (unsigned long long)fs->clusters*fs->cluster_size);
  104     printf("%u sectors/track, %u heads\n",CF_LE_W(b->secs_track),
  105 	   CF_LE_W(b->heads));
  106     printf("%10u hidden sectors\n",
  107 	   atari_format ?
  108 	   /* On Atari, the hidden field is only 16 bit wide and unused */
  109 	   (((unsigned char *)&b->hidden)[0] |
  110 	    ((unsigned char *)&b->hidden)[1] << 8) :
  111 	   CF_LE_L(b->hidden));
  112     sectors = GET_UNALIGNED_W( b->sectors );
  113     printf("%10u sectors total\n", sectors ? sectors : CF_LE_L(b->total_sect));
  114 }
  115 
  116 static void check_backup_boot(DOS_FS *fs, struct boot_sector *b, int lss)
  117 {
  118     struct boot_sector b2;
  119 
  120     if (!fs->backupboot_start) {
  121 	printf( "There is no backup boot sector.\n" );
  122 	if (CF_LE_W(b->reserved) < 3) {
  123 	    printf( "And there is no space for creating one!\n" );
  124 	    return;
  125 	}
  126 	if (interactive)
  127 	    printf( "1) Create one\n2) Do without a backup\n" );
  128 	else printf( "  Auto-creating backup boot block.\n" );
  129 	if (!interactive || get_key("12","?") == '1') {
  130 	    int bbs;
  131 	    /* The usual place for the backup boot sector is sector 6. Choose
  132 	     * that or the last reserved sector. */
  133 	    if (CF_LE_W(b->reserved) >= 7 && CF_LE_W(b->info_sector) != 6)
  134 		bbs = 6;
  135 	    else {
  136 		bbs = CF_LE_W(b->reserved) - 1;
  137 		if (bbs == CF_LE_W(b->info_sector))
  138 		    --bbs; /* this is never 0, as we checked reserved >= 3! */
  139 	    }
  140 	    fs->backupboot_start = bbs*lss;
  141 	    b->backup_boot = CT_LE_W(bbs);
  142 	    fs_write(fs->backupboot_start,sizeof(*b),b);
  143 	    fs_write((off_t)offsetof(struct boot_sector,backup_boot),
  144 		     sizeof(b->backup_boot),&b->backup_boot);
  145 	    printf( "Created backup of boot sector in sector %d\n", bbs );
  146 	    return;
  147 	}
  148 	else return;
  149     }
  150 
  151     fs_read(fs->backupboot_start,sizeof(b2),&b2);
  152     if (memcmp(b,&b2,sizeof(b2)) != 0) {
  153 	/* there are any differences */
  154 	__u8 *p, *q;
  155 	int i, pos, first = 1;
  156 	char buf[20];
  157 
  158 	printf( "There are differences between boot sector and its backup.\n" );
  159 	printf( "Differences: (offset:original/backup)\n  " );
  160 	pos = 2;
  161 	for( p = (__u8 *)b, q = (__u8 *)&b2, i = 0; i < sizeof(b2);
  162 	     ++p, ++q, ++i ) {
  163 	    if (*p != *q) {
  164 		sprintf( buf, "%s%u:%02x/%02x", first ? "" : ", ",
  165 			 (unsigned)(p-(__u8 *)b), *p, *q );
  166 		if (pos + strlen(buf) > 78) printf( "\n  " ), pos = 2;
  167 		printf( "%s", buf );
  168 		pos += strlen(buf);
  169 		first = 0;
  170 	    }
  171 	}
  172 	printf( "\n" );
  173 
  174 	if (interactive)
  175 	    printf( "1) Copy original to backup\n"
  176 		    "2) Copy backup to original\n"
  177 		    "3) No action\n" );
  178 	else printf( "  Not automatically fixing this.\n" );
  179 	switch (interactive ? get_key("123","?") : '3') {
  180 	  case '1':
  181 	    fs_write(fs->backupboot_start,sizeof(*b),b);
  182 	    break;
  183 	  case '2':
  184 	    fs_write(0,sizeof(b2),&b2);
  185 	    break;
  186 	  default:
  187 	    break;
  188 	}
  189     }
  190 }
  191 
  192 static void init_fsinfo(struct info_sector *i)
  193 {
  194     i->magic = CT_LE_L(0x41615252);
  195     i->signature = CT_LE_L(0x61417272);
  196     i->free_clusters = CT_LE_L(-1);
  197     i->next_cluster = CT_LE_L(2);
  198     i->boot_sign = CT_LE_W(0xaa55);
  199 }
  200 
  201 static void read_fsinfo(DOS_FS *fs, struct boot_sector *b,int lss)
  202 {
  203     struct info_sector i;
  204 
  205     if (!b->info_sector) {
  206 	printf( "No FSINFO sector\n" );
  207 	if (interactive)
  208 	    printf( "1) Create one\n2) Do without FSINFO\n" );
  209 	else printf( "  Not automatically creating it.\n" );
  210 	if (interactive && get_key("12","?") == '1') {
  211 	    /* search for a free reserved sector (not boot sector and not
  212 	     * backup boot sector) */
  213 	    __u32 s;
  214 	    for( s = 1; s < CF_LE_W(b->reserved); ++s )
  215 		if (s != CF_LE_W(b->backup_boot)) break;
  216 	    if (s > 0 && s < CF_LE_W(b->reserved)) {
  217 		init_fsinfo(&i);
  218 		fs_write((off_t)s*lss,sizeof(i),&i);
  219 		b->info_sector = CT_LE_W(s);
  220 		fs_write((off_t)offsetof(struct boot_sector,info_sector),
  221 			 sizeof(b->info_sector),&b->info_sector);
  222 		if (fs->backupboot_start)
  223 		    fs_write(fs->backupboot_start+
  224 			     offsetof(struct boot_sector,info_sector),
  225 			     sizeof(b->info_sector),&b->info_sector);
  226 	    }
  227 	    else {
  228 		printf( "No free reserved sector found -- "
  229 			"no space for FSINFO sector!\n" );
  230 		return;
  231 	    }
  232 	}
  233 	else return;
  234     }
  235 
  236     fs->fsinfo_start = CF_LE_W(b->info_sector)*lss;
  237     fs_read(fs->fsinfo_start,sizeof(i),&i);
  238 
  239     if (i.magic != CT_LE_L(0x41615252) ||
  240 	i.signature != CT_LE_L(0x61417272) ||
  241 	i.boot_sign != CT_LE_W(0xaa55)) {
  242 	printf( "FSINFO sector has bad magic number(s):\n" );
  243 	if (i.magic != CT_LE_L(0x41615252))
  244 	    printf( "  Offset %llu: 0x%08x != expected 0x%08x\n",
  245 		    (unsigned long long)offsetof(struct info_sector,magic),
  246 		    CF_LE_L(i.magic),0x41615252);
  247 	if (i.signature != CT_LE_L(0x61417272))
  248 	    printf( "  Offset %llu: 0x%08x != expected 0x%08x\n",
  249 		    (unsigned long long)offsetof(struct info_sector,signature),
  250 		    CF_LE_L(i.signature),0x61417272);
  251 	if (i.boot_sign != CT_LE_W(0xaa55))
  252 	    printf( "  Offset %llu: 0x%04x != expected 0x%04x\n",
  253 		    (unsigned long long)offsetof(struct info_sector,boot_sign),
  254 		    CF_LE_W(i.boot_sign),0xaa55);
  255 	if (interactive)
  256 	    printf( "1) Correct\n2) Don't correct (FSINFO invalid then)\n" );
  257 	else printf( "  Auto-correcting it.\n" );
  258 	if (!interactive || get_key("12","?") == '1') {
  259 	    init_fsinfo(&i);
  260 	    fs_write(fs->fsinfo_start,sizeof(i),&i);
  261 	}
  262 	else fs->fsinfo_start = 0;
  263     }
  264 
  265     if (fs->fsinfo_start)
  266 	fs->free_clusters = CF_LE_L(i.free_clusters);
  267 }
  268 
  269 void read_boot(DOS_FS *fs)
  270 {
  271     struct boot_sector b;
  272     unsigned total_sectors;
  273     unsigned short logical_sector_size, sectors;
  274     unsigned fat_length;
  275     off_t data_size;
  276 
  277     fs_read(0,sizeof(b),&b);
  278     logical_sector_size = GET_UNALIGNED_W(b.sector_size);
  279     if (!logical_sector_size) die("Logical sector size is zero.");
  280     fs->cluster_size = b.cluster_size*logical_sector_size;
  281     if (!fs->cluster_size) die("Cluster size is zero.");
  282     if (b.fats != 2 && b.fats != 1)
  283 	die("Currently, only 1 or 2 FATs are supported, not %d.\n",b.fats);
  284     fs->nfats = b.fats;
  285     sectors = GET_UNALIGNED_W(b.sectors);
  286     total_sectors = sectors ? sectors : CF_LE_L(b.total_sect);
  287     if (verbose) printf("Checking we can access the last sector of the filesystem\n");
  288     /* Can't access last odd sector anyway, so round down */
  289     fs_test((off_t)((total_sectors & ~1)-1)*(off_t)logical_sector_size,
  290 	    logical_sector_size);
  291     fat_length = CF_LE_W(b.fat_length) ?
  292 		 CF_LE_W(b.fat_length) : CF_LE_L(b.fat32_length);
  293     fs->fat_start = (off_t)CF_LE_W(b.reserved)*logical_sector_size;
  294     fs->root_start = ((off_t)CF_LE_W(b.reserved)+b.fats*fat_length)*
  295       logical_sector_size;
  296     fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
  297     fs->data_start = fs->root_start+ROUND_TO_MULTIPLE(fs->root_entries <<
  298       MSDOS_DIR_BITS,logical_sector_size);
  299     data_size = (off_t)total_sectors*logical_sector_size-fs->data_start;
  300     fs->clusters = data_size/fs->cluster_size;
  301     fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
  302     fs->fsinfo_start = 0; /* no FSINFO structure */
  303     fs->free_clusters = -1; /* unknown */
  304     if (!b.fat_length && b.fat32_length) {
  305 	fs->fat_bits = 32;
  306 	fs->root_cluster = CF_LE_L(b.root_cluster);
  307 	if (!fs->root_cluster && fs->root_entries)
  308 	    /* M$ hasn't specified this, but it looks reasonable: If
  309 	     * root_cluster is 0 but there is a separate root dir
  310 	     * (root_entries != 0), we handle the root dir the old way. Give a
  311 	     * warning, but convertig to a root dir in a cluster chain seems
  312 	     * to complex for now... */
  313 	    printf( "Warning: FAT32 root dir not in cluster chain! "
  314 		    "Compability mode...\n" );
  315 	else if (!fs->root_cluster && !fs->root_entries)
  316 	    die("No root directory!");
  317 	else if (fs->root_cluster && fs->root_entries)
  318 	    printf( "Warning: FAT32 root dir is in a cluster chain, but "
  319 		    "a separate root dir\n"
  320 		    "  area is defined. Cannot fix this easily.\n" );
  321 
  322 	fs->backupboot_start = CF_LE_W(b.backup_boot)*logical_sector_size;
  323 	check_backup_boot(fs,&b,logical_sector_size);
  324 
  325 	read_fsinfo(fs,&b,logical_sector_size);
  326     }
  327     else if (!atari_format) {
  328 	/* On real MS-DOS, a 16 bit FAT is used whenever there would be too
  329 	 * much clusers otherwise. */
  330 	fs->fat_bits = (fs->clusters > MSDOS_FAT12) ? 16 : 12;
  331     }
  332     else {
  333 	/* On Atari, things are more difficult: GEMDOS always uses 12bit FATs
  334 	 * on floppies, and always 16 bit on harddisks. */
  335 	fs->fat_bits = 16; /* assume 16 bit FAT for now */
  336 	/* If more clusters than fat entries in 16-bit fat, we assume
  337 	 * it's a real MSDOS FS with 12-bit fat. */
  338 	if (fs->clusters+2 > fat_length*logical_sector_size*8/16 ||
  339 	    /* if it's a floppy disk --> 12bit fat */
  340 	    device_no == 2 ||
  341 	    /* if it's a ramdisk or loopback device and has one of the usual
  342 	     * floppy sizes -> 12bit FAT  */
  343 	    ((device_no == 1 || device_no == 7) &&
  344 	     (total_sectors == 720 || total_sectors == 1440 ||
  345 	      total_sectors == 2880)))
  346 	    fs->fat_bits = 12;
  347     }
  348     /* On FAT32, the high 4 bits of a FAT entry are reserved */
  349     fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits;
  350     fs->fat_size = fat_length*logical_sector_size;
  351     if (fs->clusters > ((unsigned long long)fs->fat_size*8/fs->fat_bits)-2)
  352 	die("File system has %d clusters but only space for %d FAT entries.",
  353 	  fs->clusters,((unsigned long long)fs->fat_size*8/fs->fat_bits)-2);
  354     if (!fs->root_entries && !fs->root_cluster)
  355 	die("Root directory has zero size.");
  356     if (fs->root_entries & (MSDOS_DPS-1))
  357 	die("Root directory (%d entries) doesn't span an integral number of "
  358 	  "sectors.",fs->root_entries);
  359     if (logical_sector_size & (SECTOR_SIZE-1))
  360 	die("Logical sector size (%d bytes) is not a multiple of the physical "
  361 	  "sector size.",logical_sector_size);
  362     /* ++roman: On Atari, these two fields are often left uninitialized */
  363     if (!atari_format && (!b.secs_track || !b.heads))
  364 	die("Invalid disk format in boot sector.");
  365     if (verbose) dump_boot(fs,&b,logical_sector_size);
  366 }
  367 
  368 /* Local Variables: */
  369 /* tab-width: 8     */
  370 /* End:             */