Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenboot.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
1.7.6.1
|