📄 dosfslib.c
字号:
{ dosFsBadBootMsg( 1, DOS_BOOT_BYTES_PER_SEC, work, NULL, __LINE__ ); ERR_MSG(1, "bytesPerSec = 0\n", 0,0,0,0,0,0 ); goto error; } if( work != cbioParams.bytesPerBlk ) { dosFsBadBootMsg( 1, DOS_BOOT_BYTES_PER_SEC, work, NULL, __LINE__ ); ERR_MSG(1, "cbioParams.bytesPerBlk %u != bytes-per-sec %u\n", cbioParams.bytesPerBlk, work, 0,0,0,0 ); goto error; } /* * bytes-per-sector must be a power-of-two per Microsoft FAT specification * and at least 32 bytes, so a shift is used instead of multiplication in * operations with this value. */ pVolDesc->secSizeShift = 0; for( work = 5; work < 16; work ++ ) { if( (1 << work) == pVolDesc->bytesPerSec ) { pVolDesc->secSizeShift = work; break; } } if( pVolDesc->secSizeShift == 0 ) { dosFsBadBootMsg( 1, DOS_BOOT_BYTES_PER_SEC, pVolDesc->bytesPerSec, NULL, __LINE__ ); goto error; } /* evaluate the total number of sectors on this volume */ work = DISK_TO_VX_16( bootSec + DOS_BOOT_NSECTORS ); /* * When the volume has at least 0x10000 sectors, the 16 bit field * DOS_BOOT_NSECTORS is zero, and the alternate 32bit field * DOS_BOOT_LONG_NSECTORS is used to determine the number of * sectors on the volume. */ if( work == 0 ) /* it is a large disk */ { work = DISK_TO_VX_32( bootSec + DOS_BOOT_LONG_NSECTORS ); if( work == 0 ) { dosFsBadBootMsg( 1, DOS_BOOT_LONG_NSECTORS, work, NULL, __LINE__ ); goto error; } } pVolDesc->totalSec = work; /* number of sectors can be greater than cbioParams.nBlocks */ if( work != cbioParams.nBlocks ) { /* * XXX - An error here may indicate a problem with representing * a partition size correctly in the underlying CBIO layer. * * Also, an off by one error may mean a driver bug. * cbioParams.nBlocks is the number of blocks on the * CBIO device. Using the "last addressable LBA value" * in nBlocks can produce an off by one error, this is * considered a driver problem. bd_nBlocks shall be the * number of blocks (1-xxx) not the last addressable block. * Rather the driver should set nBlocks to the * (last addressable block + 1). DOSFS1 did not make this * check. DOSFS2 does make this check to avoid overrun. */ if( work < cbioParams.nBlocks ) { ERR_MSG(10, "WARNING: num-sectors %u < cbioParams.nBlocks %u\n", work, cbioParams.nBlocks, 0,0,0,0 ); } else { dosFsBadBootMsg( 1, DOS_BOOT_LONG_NSECTORS, 0, NULL, __LINE__ ); ERR_MSG(1, "num-sectors %u > cbioParams.nBlocks %u\n", work, cbioParams.nBlocks, 0,0,0,0 ); goto error; } } /* evaluate the number of sectors per cluster */ pVolDesc->secPerClust = bootSec[ DOS_BOOT_SEC_PER_CLUST ]; if( pVolDesc->secPerClust == 0 ) { dosFsBadBootMsg( 1, DOS_BOOT_SEC_PER_CLUST, 0, NULL, __LINE__ ); goto error; } /* evaluate the number of FAT copies */ pVolDesc->nFats = bootSec[ DOS_BOOT_NFATS ]; if( pVolDesc->nFats == 0 ) { dosFsBadBootMsg( 1, DOS_BOOT_NFATS, 0, NULL, __LINE__ ); goto error; } /* get the number of hidden sectors */ pVolDesc->nHiddenSecs = DISK_TO_VX_16( bootSec + DOS_BOOT_NHIDDEN_SECS); /* evaluate the number of reserved sectors */ pVolDesc->nReservedSecs = DISK_TO_VX_16( bootSec + DOS_BOOT_NRESRVD_SECS); if( pVolDesc->nReservedSecs == 0 ) { dosFsBadBootMsg( 1, DOS_BOOT_NRESRVD_SECS, 0, NULL, __LINE__ ); goto error; } /* evaluate the number of sectors alloted to FAT table */ pVolDesc->secPerFat = DISK_TO_VX_16( bootSec + DOS_BOOT_SEC_PER_FAT ); /* * Now determine the volumes FAT type. FAT12, FAT16, and FAT32. * NOTE: The secPerFat field is zero on FAT32 DOSFS volumes. * This is how we determine if FAT32 will be used when mounting * this volume. If secPerFat is zero, it must be FAT32. * Else, we need to pick between FAT12 and FAT16. */ if( pVolDesc->secPerFat != 0 ) /* then using either FAT12 or FAT16 */ { /* * The maximum number of 16 bit FAT entries is 65536. * Anything greater is invalid. Check here. */ if( pVolDesc->secPerFat > (ULONG)0x10000*2 / pVolDesc->bytesPerSec) { dosFsBadBootMsg( 1, DOS_BOOT_SEC_PER_FAT, pVolDesc->secPerFat, NULL, __LINE__ ); ERR_MSG(1, "secPerFat 12/16 = %u, while BPS = %u\n", pVolDesc->secPerFat,pVolDesc->bytesPerSec,0,0,0,0 ); goto error; } /* * Now we must decide if our volume is using FAT12 or FAT16. * If we choose the wrong FAT type, volume mounting will fail, * and/or data corruption on the volume will occur when its exercised. * See also: SPR#34704. * We will also check the MS FSTYPE field (offset 0x36 in the * boot sector) when determining the FAT type. If either of the * Microsoft defined strings exist, then we honor the boot sectors * wisdom. This presumes that the formatter of the volume knew what * they were doing when writing out these strings. This may not * be the case, but its seems the most compatible approach. * The FSTYPE string field is also intentionaly being honored, so * that either FAT type can be forced in the field. In the event * of a bad mount occuring in the field, a hack of writing the correct * string to the BPB FSTYPE field would force the mount to the desired * type. Many DOS implementations do not set these strings and that * is just fine. Copy FSTYPE string to tmpType. */ bcopy ( (char *) bootSec + DOS_BOOT_FSTYPE_ID, (char *) tmpType, DOS_BOOT_FSTYPE_LEN); /* * Now calculate the FAT type (FAT12 vs. FAT16) per a formula * We warn the user when the FSTYPE string (if present) doesn't match * the calculation. */ work = dosFsVolIsFat12(bootSec); if (ERROR == work) { ERR_MSG(1, "dosFsVolIsFat12 returned ERROR\n", 0,0,0,0,0,0 ); goto error; } if (TRUE == work) /* then calculated FAT12 */ { /* * Check the FSTYPE field in the BPB to ensure the string * value matches our calculation. If not, the we assume * the formatter knew what they wanted, and we honor * the string value. We look for "FAT12 " or "FAT16 ". */ if ((strcmp ((char *)tmpType, DOS_BOOT_FSTYPE_FAT16)) == 0) { pVolDesc->fatType = FAT16; printf("WARNING: FAT16 indicated by BPB FSTYPE string, " "cluster calculation was FAT12. Honoring string.\n"); } else { pVolDesc->fatType = FAT12; } } else /* we calculated FAT 16 */ { /* * Check the FSTYPE field in the BPB to ensure the string * value matches our calculation. If not, the we assume * the formatter knew what they wanted, and we honor * the string value. We look for "FAT12 " or "FAT16 ". */ if ((strcmp ((char *)tmpType, DOS_BOOT_FSTYPE_FAT12)) == 0) { pVolDesc->fatType = FAT12; printf("WARNING: FAT12 indicated by BPB FSTYPE string, " "cluster calculation was FAT16. Honoring string.\n"); } else { pVolDesc->fatType = FAT16; } } /* volume Id and label */ pVolDesc->volIdOff = DOS_BOOT_VOL_ID; pVolDesc->volLabOff = DOS_BOOT_VOL_LABEL; } else /* Use FAT32 because (pVolDesc->secPerFat == 0) */ { pVolDesc->fatType = FAT32; /* sectors per fat copy */ pVolDesc->secPerFat = DISK_TO_VX_32( bootSec + DOS32_BOOT_SEC_PER_FAT ); if( pVolDesc->secPerFat == 0 ) { dosFsBadBootMsg( 1, DOS32_BOOT_SEC_PER_FAT, 0, "(FAT32)", __LINE__ ); goto error; } /* volume Id and label */ pVolDesc->volIdOff = DOS32_BOOT_VOL_ID; pVolDesc->volLabOff = DOS32_BOOT_VOL_LABEL; } /* * count sector number of data area start cluster. * This value can be corrected later by directory handler, if * root directory is not stored as regular directory * in clusters (FAT32), but instead resides contiguously * ahead first data cluster (FAT12/FAT16) */ pVolDesc->dataStartSec = pVolDesc->nReservedSecs + pVolDesc->secPerFat * pVolDesc->nFats; /* volume Id and label */ pVolDesc->volId = DISK_TO_VX_32( bootSec + pVolDesc->volIdOff ); bcopy( (char *)bootSec + pVolDesc->volLabOff, (char *)pVolDesc->bootVolLab, DOS_VOL_LABEL_LEN ); *(pVolDesc->bootVolLab + DOS_VOL_LABEL_LEN) = EOS; /* restore base version of boot sector */ if( pVolDesc->bootSecNum != DOS_BOOT_SEC_NUM ) { ERR_MSG( 1, "Try to reclaim original copy of boot sector\n", 0,0,0,0,0,0 ); if( (pass == 0) && (cbioBlkCopy(pVolDesc->pCbio, pVolDesc->bootSecNum, DOS_BOOT_SEC_NUM, 1 ) == OK) && (cbioIoctl(pVolDesc->pCbio, CBIO_CACHE_FLUSH, (void *)(-1) ) == OK)) { /* remount again */ pass ++; pVolDesc->bootSecNum = DOS_BOOT_SEC_NUM; goto boot_get; } } /* currently it is enough for starting */ return (OK); error: /* some data is inconsistent */ pVolDesc->bootSecNum ++; if( pVolDesc->bootSecNum < (u_int)DOS_BOOT_SEC_NUM + cbioParams.blocksPerTrack ) { /* try to find other boot block copy on next sector */ if( pVolDesc->bootSecNum == DOS_BOOT_SEC_NUM + 1 ) { ERR_MSG( 1, "Problem finding volume data, trying to " "use the next block as boot block.\n", 0,0,0,0,0,0 ); /* * SPR#69074 - only look at the next sector, this avoids * tons of error messages when mounting unformatted device * when we used to look at the remaining sectors in the track. */ goto boot_get; } ERR_MSG( 1, "Ensure this device is formatted and partitions are " "properly handled.\n", 0,0,0,0,0,0 ); } if( errnoGet() == OK ) errnoSet( S_dosFsLib_UNKNOWN_VOLUME_FORMAT ); return ERROR; } /* dosFsBootSecGet() *//********************************************************************************* dosFsVolIsFat12 - determine if a MSDOS volume is FAT12 or FAT16** This routine is the container for the logic which determines if a * dosFs volume is using FAT12 or FAT16. Two methods are implemented. * Both methods use information from the volumes boot parameter block* fields found in the boot sector.** The first FAT determination method follows the recommendations outlined* in the Microsoft document:** "Hardware White Paper* Designing Hardware for Microsoft
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -