ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

boot.c
Go to the documentation of this file.
00001 /* boot.c  -  Read and analyze ia PC/MS-DOS boot sector */
00002 
00003 /* Written 1993 by Werner Almesberger */
00004 
00005 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
00006  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
00007 
00008 #include "vfatlib.h"
00009 
00010 #define NDEBUG
00011 #include <debug.h>
00012 
00013 
00014 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
00015     /* don't divide by zero */
00016 
00017 static struct {
00018     __u8 media;
00019     char *descr;
00020 } mediabytes[] = {
00021     { 0xf0, "5.25\" or 3.5\" HD floppy" },
00022     { 0xf8, "hard disk" },
00023     { 0xf9, "3,5\" 720k floppy 2s/80tr/9sec or "
00024             "5.25\" 1.2M floppy 2s/80tr/15sec" },
00025     { 0xfa, "5.25\" 320k floppy 1s/80tr/8sec" },
00026     { 0xfb, "3.5\" 640k floppy 2s/80tr/8sec" },
00027     { 0xfc, "5.25\" 180k floppy 1s/40tr/9sec" },
00028     { 0xfd, "5.25\" 360k floppy 2s/40tr/9sec" },
00029     { 0xfe, "5.25\" 160k floppy 1s/40tr/8sec" },
00030     { 0xff, "5.25\" 320k floppy 2s/40tr/8sec" },
00031 };
00032 
00033 #if defined __alpha || defined __ia64__ || defined __x86_64__ || defined __ppc64__
00034 /* Unaligned fields must first be copied byte-wise (little endian) */
00035 #define GET_UNALIGNED_W(u) \
00036     (((unsigned char*)(&u))[0] | (((unsigned char*)&(u))[1] << 8))
00037 #elif defined __s390x__
00038 /* Unaligned fields must first be copied byte-wise (big endian) */
00039 #define GET_UNALIGNED_W(pu) \
00040     (((unsigned char*)&(u))[1] | (((unsigned char*)&(u))[0] << 8))
00041 #else
00042 #define GET_UNALIGNED_W(f) CF_LE_W( *(unsigned short *)&f )
00043 #endif
00044 
00045 static char *get_media_descr( unsigned char media )
00046 {
00047     int i;
00048 
00049     for( i = 0; i < sizeof(mediabytes)/sizeof(*mediabytes); ++i ) {
00050     if (mediabytes[i].media == media)
00051         return( mediabytes[i].descr );
00052     }
00053     return( "undefined" );
00054 }
00055 
00056 static void dump_boot(DOS_FS *fs,struct boot_sector *b,unsigned lss)
00057 {
00058     unsigned short sectors;
00059     char id[9];
00060 
00061     VfatPrint("Boot sector contents:\n");
00062 
00063     strncpy(id,(char*)b->system_id,8);
00064     id[8] = 0;
00065     VfatPrint("System ID \"%s\"\n",id);
00066 
00067     VfatPrint("Media byte 0x%02x (%s)\n",b->media,get_media_descr(b->media));
00068     VfatPrint("%10d bytes per logical sector\n",GET_UNALIGNED_W(b->sector_size));
00069     VfatPrint("%10d bytes per cluster\n",fs->cluster_size);
00070     VfatPrint("%10d reserved sector%s\n",CF_LE_W(b->reserved),
00071        CF_LE_W(b->reserved) == 1 ? "" : "s");
00072     VfatPrint("First FAT starts at byte %llu (sector %llu)\n",
00073        (__u64)fs->fat_start,
00074        (__u64)fs->fat_start/lss);
00075     VfatPrint("%10d FATs, %d bit entries\n",b->fats,fs->fat_bits);
00076     VfatPrint("%10d bytes per FAT (= %u sectors)\n",fs->fat_size,
00077        fs->fat_size/lss);
00078     if (!fs->root_cluster) {
00079     VfatPrint("Root directory starts at byte %llu (sector %llu)\n",
00080            (__u64)fs->root_start,
00081            (__u64)fs->root_start/lss);
00082     VfatPrint("%10d root directory entries\n",fs->root_entries);
00083     }
00084     else {
00085     VfatPrint( "Root directory start at cluster %lu (arbitrary size)\n",
00086         fs->root_cluster);
00087     }
00088     VfatPrint("Data area starts at byte %llu (sector %llu)\n",
00089        (__u64)fs->data_start,
00090        (__u64)fs->data_start/lss);
00091     VfatPrint("%10lu data clusters (%llu bytes)\n",fs->clusters,
00092        (__u64)fs->clusters*fs->cluster_size);
00093     VfatPrint("%u sectors/track, %u heads\n",CF_LE_W(b->secs_track),
00094        CF_LE_W(b->heads));
00095     VfatPrint("%10u hidden sectors\n", CF_LE_L(b->hidden));
00096     sectors = GET_UNALIGNED_W( b->sectors );
00097     VfatPrint("%10u sectors total\n", sectors ? sectors : CF_LE_L(b->total_sect));
00098 }
00099 
00100 static void check_backup_boot(DOS_FS *fs, struct boot_sector *b, int lss)
00101 {
00102     struct boot_sector b2;
00103 
00104     if (!fs->backupboot_start) {
00105     VfatPrint( "There is no backup boot sector.\n" );
00106     if (CF_LE_W(b->reserved) < 3) {
00107         VfatPrint( "And there is no space for creating one!\n" );
00108         return;
00109     }
00110     if (FsCheckFlags & FSCHECK_INTERACTIVE)
00111         VfatPrint( "1) Create one\n2) Do without a backup\n" );
00112     else VfatPrint( "  Auto-creating backup boot block.\n" );
00113     if (!(FsCheckFlags & FSCHECK_INTERACTIVE) || get_key("12","?") == '1') {
00114         int bbs;
00115         /* The usual place for the backup boot sector is sector 6. Choose
00116          * that or the last reserved sector. */
00117         if (CF_LE_W(b->reserved) >= 7 && CF_LE_W(b->info_sector) != 6)
00118         bbs = 6;
00119         else {
00120         bbs = CF_LE_W(b->reserved) - 1;
00121         if (bbs == CF_LE_W(b->info_sector))
00122             --bbs; /* this is never 0, as we checked reserved >= 3! */
00123         }
00124         fs->backupboot_start = bbs*lss;
00125         b->backup_boot = CT_LE_W(bbs);
00126         fs_write(fs->backupboot_start,sizeof(*b),b);
00127         fs_write((off_t)offsetof(struct boot_sector,backup_boot),
00128              sizeof(b->backup_boot),&b->backup_boot);
00129         VfatPrint( "Created backup of boot sector in sector %d\n", bbs );
00130         return;
00131     }
00132     else return;
00133     }
00134 
00135     fs_read(fs->backupboot_start,sizeof(b2),&b2);
00136     if (memcmp(b,&b2,sizeof(b2)) != 0) {
00137     /* there are any differences */
00138     __u8 *p, *q;
00139     int i, pos, first = 1;
00140     char buf[20];
00141 
00142     VfatPrint( "There are differences between boot sector and its backup.\n" );
00143     VfatPrint( "Differences: (offset:original/backup)\n  " );
00144     pos = 2;
00145     for( p = (__u8 *)b, q = (__u8 *)&b2, i = 0; i < sizeof(b2);
00146          ++p, ++q, ++i ) {
00147         if (*p != *q) {
00148         sprintf( buf, "%s%u:%02x/%02x", first ? "" : ", ",
00149              (unsigned)(p-(__u8 *)b), *p, *q );
00150         if (pos + strlen(buf) > 78) VfatPrint( "\n  " ), pos = 2;
00151         VfatPrint( "%s", buf );
00152         pos += strlen(buf);
00153         first = 0;
00154         }
00155     }
00156     VfatPrint( "\n" );
00157 
00158     if (FsCheckFlags & FSCHECK_INTERACTIVE)
00159         VfatPrint( "1) Copy original to backup\n"
00160             "2) Copy backup to original\n"
00161             "3) No action\n" );
00162     else VfatPrint( "  Not automatically fixing this.\n" );
00163     switch ((FsCheckFlags & FSCHECK_INTERACTIVE) ? get_key("123","?") : '3') {
00164       case '1':
00165         fs_write(fs->backupboot_start,sizeof(*b),b);
00166         break;
00167       case '2':
00168         fs_write(0,sizeof(b2),&b2);
00169         break;
00170       default:
00171         break;
00172     }
00173     }
00174 }
00175 
00176 static void init_fsinfo(struct info_sector *i)
00177 {
00178     i->magic = CT_LE_L(0x41615252);
00179     i->signature = CT_LE_L(0x61417272);
00180     i->free_clusters = CT_LE_L(-1);
00181     i->next_cluster = CT_LE_L(2);
00182     i->boot_sign = CT_LE_W(0xaa55);
00183 }
00184 
00185 static void read_fsinfo(DOS_FS *fs, struct boot_sector *b,int lss)
00186 {
00187     struct info_sector i;
00188 
00189     if (!b->info_sector) {
00190     VfatPrint( "No FSINFO sector\n" );
00191     if (FsCheckFlags & FSCHECK_INTERACTIVE)
00192         VfatPrint( "1) Create one\n2) Do without FSINFO\n" );
00193     else VfatPrint( "  Not automatically creating it.\n" );
00194     if ((FsCheckFlags & FSCHECK_INTERACTIVE) && get_key("12","?") == '1') {
00195         /* search for a free reserved sector (not boot sector and not
00196          * backup boot sector) */
00197         __u32 s;
00198         for( s = 1; s < CF_LE_W(b->reserved); ++s )
00199         if (s != CF_LE_W(b->backup_boot)) break;
00200         if (s > 0 && s < CF_LE_W(b->reserved)) {
00201         init_fsinfo(&i);
00202         fs_write((off_t)s*lss,sizeof(i),&i);
00203         b->info_sector = CT_LE_W(s);
00204         fs_write((off_t)offsetof(struct boot_sector,info_sector),
00205              sizeof(b->info_sector),&b->info_sector);
00206         if (fs->backupboot_start)
00207             fs_write(fs->backupboot_start+
00208                  offsetof(struct boot_sector,info_sector),
00209                  sizeof(b->info_sector),&b->info_sector);
00210         }
00211         else {
00212         VfatPrint( "No free reserved sector found -- "
00213             "no space for FSINFO sector!\n" );
00214         return;
00215         }
00216     }
00217     else return;
00218     }
00219 
00220     fs->fsinfo_start = CF_LE_W(b->info_sector)*lss;
00221     fs_read(fs->fsinfo_start,sizeof(i),&i);
00222 
00223     if (i.magic != CT_LE_L(0x41615252) ||
00224     i.signature != CT_LE_L(0x61417272) ||
00225     i.boot_sign != CT_LE_W(0xaa55)) {
00226     VfatPrint( "FSINFO sector has bad magic number(s):\n" );
00227     if (i.magic != CT_LE_L(0x41615252))
00228         VfatPrint( "  Offset %llu: 0x%08x != expected 0x%08x\n",
00229             (__u64)offsetof(struct info_sector,magic),
00230             CF_LE_L(i.magic),0x41615252);
00231     if (i.signature != CT_LE_L(0x61417272))
00232         VfatPrint( "  Offset %llu: 0x%08x != expected 0x%08x\n",
00233             (__u64)offsetof(struct info_sector,signature),
00234             CF_LE_L(i.signature),0x61417272);
00235     if (i.boot_sign != CT_LE_W(0xaa55))
00236         VfatPrint( "  Offset %llu: 0x%04x != expected 0x%04x\n",
00237             (__u64)offsetof(struct info_sector,boot_sign),
00238             CF_LE_W(i.boot_sign),0xaa55);
00239     if (FsCheckFlags & FSCHECK_INTERACTIVE)
00240         VfatPrint( "1) Correct\n2) Don't correct (FSINFO invalid then)\n" );
00241     else VfatPrint( "  Auto-correcting it.\n" );
00242     if (!(FsCheckFlags & FSCHECK_INTERACTIVE) || get_key("12","?") == '1') {
00243         init_fsinfo(&i);
00244         fs_write(fs->fsinfo_start,sizeof(i),&i);
00245     }
00246     else fs->fsinfo_start = 0;
00247     }
00248 
00249     if (fs->fsinfo_start)
00250     fs->free_clusters = CF_LE_L(i.free_clusters);
00251 }
00252 
00253 void read_boot(DOS_FS *fs)
00254 {
00255     struct boot_sector b;
00256     unsigned total_sectors;
00257     unsigned short logical_sector_size, sectors;
00258     unsigned fat_length;
00259     loff_t data_size;
00260 
00261     fs_read(0,sizeof(b),&b);
00262     logical_sector_size = GET_UNALIGNED_W(b.sector_size);
00263     if (!logical_sector_size) die("Logical sector size is zero.");
00264     fs->cluster_size = b.cluster_size*logical_sector_size;
00265     if (!fs->cluster_size) die("Cluster size is zero.");
00266     if (b.fats != 2 && b.fats != 1)
00267     die("Currently, only 1 or 2 FATs are supported, not %d.\n",b.fats);
00268     fs->nfats = b.fats;
00269     sectors = GET_UNALIGNED_W(b.sectors);
00270     total_sectors = sectors ? sectors : CF_LE_L(b.total_sect);
00271     if (FsCheckFlags & FSCHECK_VERBOSE) VfatPrint("Checking we can access the last sector of the filesystem\n");
00272     /* Can't access last odd sector anyway, so round down */
00273     fs_test((loff_t)((total_sectors & ~1)-1)*(loff_t)logical_sector_size,
00274         logical_sector_size);
00275     fat_length = CF_LE_W(b.fat_length) ?
00276          CF_LE_W(b.fat_length) : CF_LE_L(b.fat32_length);
00277     fs->fat_start = (off_t)CF_LE_W(b.reserved)*logical_sector_size;
00278     fs->root_start = ((off_t)CF_LE_W(b.reserved)+b.fats*fat_length)*
00279       logical_sector_size;
00280     fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
00281     fs->data_start = fs->root_start+ROUND_TO_MULTIPLE(fs->root_entries <<
00282       MSDOS_DIR_BITS,logical_sector_size);
00283     data_size = (loff_t)total_sectors*logical_sector_size-fs->data_start;
00284     fs->clusters = data_size/fs->cluster_size;
00285     fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
00286     fs->fsinfo_start = 0; /* no FSINFO structure */
00287     fs->free_clusters = -1; /* unknown */
00288     if (!b.fat_length && b.fat32_length) {
00289     fs->fat_bits = 32;
00290     fs->root_cluster = CF_LE_L(b.root_cluster);
00291     if (!fs->root_cluster && fs->root_entries)
00292         /* M$ hasn't specified this, but it looks reasonable: If
00293          * root_cluster is 0 but there is a separate root dir
00294          * (root_entries != 0), we handle the root dir the old way. Give a
00295          * warning, but convertig to a root dir in a cluster chain seems
00296          * to complex for now... */
00297         VfatPrint( "Warning: FAT32 root dir not in cluster chain! "
00298             "Compability mode...\n" );
00299     else if (!fs->root_cluster && !fs->root_entries)
00300         die("No root directory!");
00301     else if (fs->root_cluster && fs->root_entries)
00302         VfatPrint( "Warning: FAT32 root dir is in a cluster chain, but "
00303             "a separate root dir\n"
00304             "  area is defined. Cannot fix this easily.\n" );
00305 
00306     fs->backupboot_start = CF_LE_W(b.backup_boot)*logical_sector_size;
00307     check_backup_boot(fs,&b,logical_sector_size);
00308 
00309     read_fsinfo(fs,&b,logical_sector_size);
00310     }
00311     else {
00312     /* On real MS-DOS, a 16 bit FAT is used whenever there would be too
00313      * much clusters otherwise. */
00314     fs->fat_bits = (fs->clusters > MSDOS_FAT12) ? 16 : 12;
00315     }
00316 
00317     /* On FAT32, the high 4 bits of a FAT entry are reserved */
00318     fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits;
00319     fs->fat_size = fat_length*logical_sector_size;
00320     if (fs->clusters > ((__u64)fs->fat_size*8/fs->fat_bits)-2)
00321     die("File system has %d clusters but only space for %d FAT entries.",
00322       fs->clusters,((__u64)fs->fat_size*8/fs->fat_bits)-2);
00323     if (!fs->root_entries && !fs->root_cluster)
00324     die("Root directory has zero size.");
00325     if (fs->root_entries & (MSDOS_DPS-1))
00326     die("Root directory (%d entries) doesn't span an integral number of "
00327       "sectors.",fs->root_entries);
00328     if (logical_sector_size & (SECTOR_SIZE-1))
00329     die("Logical sector size (%d bytes) is not a multiple of the physical "
00330       "sector size.",logical_sector_size);
00331     /* ++roman: On Atari, these two fields are often left uninitialized */
00332     if ((!b.secs_track || !b.heads))
00333     die("Invalid disk format in boot sector.");
00334     if (FsCheckFlags & FSCHECK_VERBOSE) dump_boot(fs,&b,logical_sector_size);
00335 }
00336 
00337 /* Local Variables: */
00338 /* tab-width: 8     */
00339 /* End:             */

Generated on Sat May 26 2012 04:35:04 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.