Changeset 66689 in vbox
- Timestamp:
- Apr 27, 2017 2:39:50 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 3 edited
-
include/iprt/formats/fat.h (modified) (2 diffs)
-
include/iprt/fsvfs.h (added)
-
include/iprt/mangling.h (modified) (1 diff)
-
src/VBox/Runtime/common/filesystem/fatvfs.cpp (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/formats/fat.h
r66676 r66689 53 53 #define FAT_ID_IS_VALID(a_bFatId) ( (uint8_t)(a_bFatId) >= 0xf8 \ 54 54 || (uint8_t)(a_bFatId) == 0xf0 \ 55 || (uint8_t)(a_b Media) == 0xf4 /* obscure - msdos 2.11 */ \56 || (uint8_t)(a_b Media) == 0xf5 /* obscure - msdos 2.11 */ \55 || (uint8_t)(a_bFatId) == 0xf4 /* obscure - msdos 2.11 */ \ 56 || (uint8_t)(a_bFatId) == 0xf5 /* obscure - msdos 2.11 */ \ 57 57 || (uint8_t)(a_bFatId) == 0xed /* obscure, tandy 2000 */ \ 58 58 || (uint8_t)(a_bFatId) == 0xe5 /* obscure, tandy 2000 */ ) … … 503 503 * @{ */ 504 504 #define FAT_FIRST_DATA_CLUSTER 2 /**< The first data cluster. */ 505 506 #define FAT_MAX_FAT12_TOTAL_CLUSTERS UINT32_C(0x00000ff6) /**< Maximum number of clusters in a 12-bit FAT . */ 507 #define FAT_MAX_FAT16_TOTAL_CLUSTERS UINT32_C(0x0000fff6) /**< Maximum number of clusters in a 16-bit FAT . */ 508 #define FAT_MAX_FAT32_TOTAL_CLUSTERS UINT32_C(0x0ffffff6) /**< Maximum number of clusters in a 32-bit FAT . */ 509 505 510 #define FAT_LAST_FAT12_DATA_CLUSTER UINT32_C(0x00000ff5) /**< The last possible data cluster for FAT12. */ 506 511 #define FAT_LAST_FAT16_DATA_CLUSTER UINT32_C(0x0000fff5) /**< The last possible data cluster for FAT16. */ 507 512 #define FAT_LAST_FAT32_DATA_CLUSTER UINT32_C(0x0ffffff5) /**< The last possible data cluster for FAT32. */ 513 514 #define FAT_MAX_FAT12_DATA_CLUSTERS UINT32_C(0x00000ff4) /**< Maximum number of data clusters for FAT12. */ 515 #define FAT_MAX_FAT16_DATA_CLUSTERS UINT32_C(0x0000fff4) /**< Maximum number of data clusters for FAT16. */ 516 #define FAT_MAX_FAT32_DATA_CLUSTERS UINT32_C(0x0ffffff4) /**< Maximum number of data clusters for FAT32. */ 517 518 #define FAT_MIN_FAT12_DATA_CLUSTERS UINT32_C(0x00000001) /**< Maximum number of data clusters for FAT12. */ 519 #define FAT_MIN_FAT16_DATA_CLUSTERS UINT32_C(0x00000ff5) /**< Maximum number of data clusters for FAT16. */ 520 #define FAT_MIN_FAT32_DATA_CLUSTERS UINT32_C(0x0000fff5) /**< Maximum number of data clusters for FAT32. */ 508 521 509 522 #define FAT_FIRST_FAT12_EOC UINT32_C(0x00000ff8) /**< The first end-of-file-cluster number for FAT12. */ -
trunk/include/iprt/mangling.h
r66615 r66689 916 916 # define RTFsTypeName RT_MANGLER(RTFsTypeName) 917 917 # define RTFsFatVolOpen RT_MANGLER(RTFsFatVolOpen) 918 # define RTFsFatVolFormat RT_MANGLER(RTFsFatVolFormat) 919 # define RTFsFatVolFormat144 RT_MANGLER(RTFsFatVolFormat144) 918 920 # define RTGetOpt RT_MANGLER(RTGetOpt) 919 921 # define RTGetOptArgvFree RT_MANGLER(RTGetOptArgvFree) -
trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp
r66676 r66689 30 30 *********************************************************************************************************************************/ 31 31 #include "internal/iprt.h" 32 #include <iprt/fs .h>32 #include <iprt/fsvfs.h> 33 33 34 34 #include <iprt/asm.h> … … 39 39 #include <iprt/mem.h> 40 40 #include <iprt/poll.h> 41 #include <iprt/rand.h> 41 42 #include <iprt/string.h> 42 43 #include <iprt/sg.h> … … 45 46 #include <iprt/vfs.h> 46 47 #include <iprt/vfslowlevel.h> 48 #include <iprt/zero.h> 47 49 #include <iprt/formats/fat.h> 48 50 … … 263 265 /** Pointer to a FAT linear metadata cache. */ 264 266 typedef RTFSFATCLUSTERMAPCACHE *PRTFSFATCLUSTERMAPCACHE; 265 266 267 /**268 * FAT type (format).269 */270 typedef enum RTFSFATTYPE271 {272 RTFSFATTYPE_INVALID = 0,273 RTFSFATTYPE_FAT12,274 RTFSFATTYPE_FAT16,275 RTFSFATTYPE_FAT32,276 RTFSFATTYPE_END277 } RTFSFATTYPE;278 267 279 268 … … 3605 3594 pThis->cClusters = (pThis->cbTotalSize - cbSystemStuff) / pThis->cbCluster; 3606 3595 3607 if (pThis->cClusters >= FAT_ LAST_FAT16_DATA_CLUSTER)3608 { 3609 pThis->cClusters = FAT_ LAST_FAT16_DATA_CLUSTER + 1;3596 if (pThis->cClusters >= FAT_MAX_FAT16_DATA_CLUSTERS) 3597 { 3598 pThis->cClusters = FAT_MAX_FAT16_DATA_CLUSTERS; 3610 3599 pThis->enmFatType = RTFSFATTYPE_FAT16; 3611 3600 } 3612 else if (pThis->cClusters > FAT_LAST_FAT12_DATA_CLUSTER)3601 else if (pThis->cClusters >= FAT_MIN_FAT16_DATA_CLUSTERS) 3613 3602 pThis->enmFatType = RTFSFATTYPE_FAT16; 3614 3603 else … … 3720 3709 uint64_t cbFat = pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32 * (uint64_t)pThis->cbSector; 3721 3710 if ( cbFat == 0 3722 || cbFat >= (FAT_LAST_FAT32_DATA_CLUSTER + 1)* 4 + pThis->cbSector * 16)3711 || cbFat >= FAT_MAX_FAT32_TOTAL_CLUSTERS * 4 + pThis->cbSector * 16) 3723 3712 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 3724 3713 "Bogus 32-bit FAT size: %#RX32", pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32); … … 3741 3730 3742 3731 uint64_t cClusters = (pThis->cbTotalSize - (pThis->offFirstCluster - pThis->offBootSector)) / pThis->cbCluster; 3743 if (cClusters <= FAT_ LAST_FAT32_DATA_CLUSTER)3732 if (cClusters <= FAT_MAX_FAT32_DATA_CLUSTERS) 3744 3733 pThis->cClusters = (uint32_t)cClusters; 3745 3734 else 3746 pThis->cClusters = FAT_ LAST_FAT32_DATA_CLUSTER + 1;3747 if (pThis->cClusters > pThis->cbFat / 4)3748 pThis->cClusters = pThis->cbFat / 4;3735 pThis->cClusters = FAT_MAX_FAT32_DATA_CLUSTERS; 3736 if (pThis->cClusters > (pThis->cbFat / 4 - FAT_FIRST_DATA_CLUSTER)) 3737 pThis->cClusters = (pThis->cbFat / 4 - FAT_FIRST_DATA_CLUSTER); 3749 3738 3750 3739 /* … … 4139 4128 4140 4129 4130 /** 4131 * Opens a FAT file system volume. 4132 * 4133 * @returns IPRT status code. 4134 * @param hVfsFileIn The file or device backing the volume. 4135 * @param fReadOnly Whether to mount it read-only. 4136 * @param offBootSector The offset of the boot sector relative to the start 4137 * of @a hVfsFileIn. Pass 0 for floppies. 4138 * @param phVfs Where to return the virtual file system handle. 4139 * @param pErrInfo Where to return additional error information. 4140 */ 4141 4141 RTDECL(int) RTFsFatVolOpen(RTVFSFILE hVfsFileIn, bool fReadOnly, uint64_t offBootSector, PRTVFS phVfs, PRTERRINFO pErrInfo) 4142 4142 { … … 4167 4167 RTVfsFileRelease(hVfsFileIn); 4168 4168 return rc; 4169 } 4170 4171 4172 4173 4174 /** 4175 * Fills a range in the file with zeros in the most efficient manner. 4176 * 4177 * @returns IPRT status code. 4178 * @param hVfsFile The file to write to. 4179 * @param off Where to start filling with zeros. 4180 * @param cbZeros How many zero blocks to write. 4181 */ 4182 static int rtFsFatVolWriteZeros(RTVFSFILE hVfsFile, uint64_t off, uint32_t cbZeros) 4183 { 4184 while (cbZeros > 0) 4185 { 4186 uint32_t cbToWrite = sizeof(g_abRTZero64K); 4187 if (cbToWrite > cbZeros) 4188 cbToWrite = cbZeros; 4189 int rc = RTVfsFileWriteAt(hVfsFile, off, g_abRTZero64K, cbToWrite, NULL); 4190 if (RT_FAILURE(rc)) 4191 return rc; 4192 off += cbToWrite; 4193 cbZeros -= cbToWrite; 4194 } 4195 return VINF_SUCCESS; 4196 } 4197 4198 4199 /** 4200 * Formats a FAT volume. 4201 * 4202 * @returns IRPT status code. 4203 * @param hVfsFile The volume file. 4204 * @param offVol The offset into @a hVfsFile of the file. 4205 * Typically 0. 4206 * @param cbVol The size of the volume. Pass 0 if the rest of 4207 * hVfsFile should be used. 4208 * @param fFlags See RTFSFATVOL_FMT_F_XXX. 4209 * @param cbSector The logical sector size. Must be power of two. 4210 * Optional, pass zero to use 512. 4211 * @param cSectorsPerCluster Number of sectors per cluster. Power of two. 4212 * Optional, pass zero to auto detect. 4213 * @param enmFatType The FAT type (12, 16, 32) to use. 4214 * Optional, pass RTFSFATTYPE_INVALID for default. 4215 * @param cHeads The number of heads to report in the BPB. 4216 * Optional, pass zero to auto detect. 4217 * @param cSectorsPerTrack The number of sectors per track to put in the 4218 * BPB. Optional, pass zero to auto detect. 4219 * @param bMedia The media byte value and FAT ID to use. 4220 * Optional, pass zero to auto detect. 4221 * @param cRootDirEntries Number of root directory entries. 4222 * Optional, pass zero to auto detect. 4223 * @param cHiddenSectors Number of hidden sectors. Pass 0 for 4224 * unpartitioned media. 4225 * @param pErrInfo Additional error information, maybe. Optional. 4226 */ 4227 RTDECL(int) RTFsFatVolFormat(RTVFSFILE hVfsFile, uint64_t offVol, uint64_t cbVol, uint32_t fFlags, uint16_t cbSector, 4228 uint16_t cSectorsPerCluster, RTFSFATTYPE enmFatType, uint32_t cHeads, uint32_t cSectorsPerTrack, 4229 uint8_t bMedia, uint16_t cRootDirEntries, uint32_t cHiddenSectors, PRTERRINFO pErrInfo) 4230 { 4231 int rc; 4232 uint32_t cFats = 2; 4233 4234 /* 4235 * Validate input. 4236 */ 4237 if (!cbSector) 4238 cbSector = 512; 4239 else 4240 AssertMsgReturn( cbSector == 128 4241 || cbSector == 512 4242 || cbSector == 1024 4243 || cbSector == 4096, 4244 ("cbSector=%#x\n", cbSector), 4245 VERR_INVALID_PARAMETER); 4246 AssertMsgReturn(cSectorsPerCluster == 0 || (cSectorsPerCluster <= 128 && RT_IS_POWER_OF_TWO(cSectorsPerCluster)), 4247 ("cSectorsPerCluster=%#x\n", cSectorsPerCluster), VERR_INVALID_PARAMETER); 4248 AssertMsgReturn(bMedia == 0 || (FAT_ID_IS_VALID(bMedia) && FATBPB_MEDIA_IS_VALID(bMedia)), 4249 ("bMedia=%#x\n"), VERR_INVALID_PARAMETER); 4250 AssertReturn(!(fFlags & ~RTFSFATVOL_FMT_F_VALID_MASK), VERR_INVALID_FLAGS); 4251 AssertReturn(enmFatType >= RTFSFATTYPE_INVALID && enmFatType < RTFSFATTYPE_END, VERR_INVALID_PARAMETER); 4252 4253 if (!cbVol) 4254 { 4255 uint64_t cbFile; 4256 rc = RTVfsFileGetSize(hVfsFile, &cbFile); 4257 AssertRCReturn(rc, rc); 4258 AssertMsgReturn(cbFile > offVol, ("cbFile=%#RX64 offVol=%#RX64\n", cbFile, offVol), VERR_INVALID_PARAMETER); 4259 cbVol = cbFile - offVol; 4260 } 4261 uint64_t const cSectorsInVol = cbVol / cbSector; 4262 4263 /* 4264 * Guess defaults if necessary. 4265 */ 4266 if (!cSectorsPerCluster || !cHeads || !cSectorsPerTrack || !bMedia || !cRootDirEntries) 4267 { 4268 static struct 4269 { 4270 uint64_t cbVol; 4271 uint8_t bMedia; 4272 uint8_t cHeads; 4273 uint8_t cSectorsPerTrack; 4274 uint8_t cSectorsPerCluster; 4275 uint16_t cRootDirEntries; 4276 } s_aDefaults[] = 4277 { 4278 /* cbVol, bMedia, cHeads, cSectorsPTrk, cSectorsPClstr, cRootDirEntries */ 4279 { 163840, 0xfe, /* cyl: 40,*/ 1, 8, 1, 64 }, 4280 { 184320, 0xfc, /* cyl: 40,*/ 1, 9, 2, 64 }, 4281 { 327680, 0xff, /* cyl: 40,*/ 2, 8, 2, 112 }, 4282 { 368640, 0xfd, /* cyl: 40,*/ 2, 9, 2, 112 }, 4283 { 737280, 0xf9, /* cyl: 80,*/ 2, 9, 2, 112 }, 4284 { 1228800, 0xf9, /* cyl: 80,*/ 2, 15, 2, 112 }, 4285 { 1474560, 0xf0, /* cyl: 80,*/ 2, 18, 1, 224 }, 4286 { 2949120, 0xf0, /* cyl: 80,*/ 2, 36, 2, 224 }, 4287 { 528482304, 0xf8, /* cyl: 1024,*/ 16, 63, 0, 512 }, // 504MB limit 4288 { UINT64_C(7927234560), 0xf8, /* cyl: 1024,*/ 240, 63, 0, 512 }, // 7.3GB limit 4289 { UINT64_C(8422686720), 0xf8, /* cyl: 1024,*/ 255, 63, 0, 512 }, // 7.84GB limit 4290 4291 }; 4292 uint32_t iDefault = 0; 4293 while ( iDefault < RT_ELEMENTS(s_aDefaults) - 1U 4294 && cbVol > s_aDefaults[iDefault].cbVol) 4295 iDefault++; 4296 if (!cHeads) 4297 cHeads = s_aDefaults[iDefault].cHeads; 4298 if (!cSectorsPerTrack) 4299 cSectorsPerTrack = s_aDefaults[iDefault].cSectorsPerTrack; 4300 if (!bMedia) 4301 bMedia = s_aDefaults[iDefault].bMedia; 4302 if (!cRootDirEntries) 4303 cRootDirEntries = s_aDefaults[iDefault].cRootDirEntries; 4304 if (!cSectorsPerCluster) 4305 { 4306 cSectorsPerCluster = s_aDefaults[iDefault].cSectorsPerCluster; 4307 if (!cSectorsPerCluster) 4308 { 4309 uint32_t cbFat12Overhead = cbSector /* boot sector */ 4310 + RT_ALIGN_32(FAT_MAX_FAT12_TOTAL_CLUSTERS * 3 / 2, cbSector) * cFats /* FATs */ 4311 + RT_ALIGN_32(cRootDirEntries * sizeof(FATDIRENTRY), cbSector) /* root dir */; 4312 uint32_t cbFat16Overhead = cbSector /* boot sector */ 4313 + RT_ALIGN_32(FAT_MAX_FAT16_TOTAL_CLUSTERS * 2, cbSector) * cFats /* FATs */ 4314 + RT_ALIGN_32(cRootDirEntries * sizeof(FATDIRENTRY), cbSector) /* root dir */; 4315 4316 if ( enmFatType == RTFSFATTYPE_FAT12 4317 || cbVol <= cbFat12Overhead + FAT_MAX_FAT12_DATA_CLUSTERS * 4 * cbSector) 4318 { 4319 enmFatType = RTFSFATTYPE_FAT12; 4320 cSectorsPerCluster = 1; 4321 while ( cSectorsPerCluster < 128 4322 && cSectorsInVol 4323 > cbFat12Overhead / cbSector 4324 + (uint32_t)cSectorsPerCluster * FAT_MAX_FAT12_DATA_CLUSTERS 4325 + cSectorsPerCluster - 1) 4326 cSectorsPerCluster <<= 1; 4327 } 4328 else if ( enmFatType == RTFSFATTYPE_FAT16 4329 || cbVol <= cbFat16Overhead + FAT_MAX_FAT16_DATA_CLUSTERS * 128 * cbSector) 4330 { 4331 enmFatType = RTFSFATTYPE_FAT16; 4332 cSectorsPerCluster = 1; 4333 while ( cSectorsPerCluster < 128 4334 && cSectorsInVol 4335 > cbFat12Overhead / cbSector 4336 + (uint32_t)cSectorsPerCluster * FAT_MAX_FAT16_DATA_CLUSTERS 4337 + cSectorsPerCluster - 1) 4338 cSectorsPerCluster <<= 1; 4339 } 4340 else 4341 { 4342 /* The target here is keeping the FAT size below 8MB. Seems windows 4343 likes a minimum 4KB cluster size as wells as a max of 32KB (googling). */ 4344 enmFatType = RTFSFATTYPE_FAT32; 4345 uint32_t cbFat32Overhead = cbSector * 32 /* boot sector, info sector, boot sector copies, reserved sectors */ 4346 + _8M * cFats; 4347 if (cbSector >= _4K) 4348 cSectorsPerCluster = 1; 4349 else 4350 cSectorsPerCluster = _4K / cbSector; 4351 while ( cSectorsPerCluster < 128 4352 && cSectorsPerCluster * cbSector < _32K 4353 && cSectorsInVol > cbFat32Overhead / cbSector + (uint64_t)cSectorsPerCluster * _2M) 4354 cSectorsPerCluster <<= 1; 4355 } 4356 } 4357 } 4358 } 4359 Assert(cSectorsPerCluster); 4360 Assert(cRootDirEntries); 4361 uint32_t cbRootDir = RT_ALIGN_32(cRootDirEntries * sizeof(FATDIRENTRY), cbSector); 4362 uint32_t const cbCluster = cSectorsPerCluster * cbSector; 4363 4364 /* 4365 * If we haven't figured out the FAT type yet, do so. 4366 * The file system code determins the FAT based on cluster counts, 4367 * so we must do so here too. 4368 */ 4369 if (enmFatType == RTFSFATTYPE_INVALID) 4370 { 4371 uint32_t cbFat12Overhead = cbSector /* boot sector */ 4372 + RT_ALIGN_32(FAT_MAX_FAT12_TOTAL_CLUSTERS * 3 / 2, cbSector) * cFats /* FATs */ 4373 + RT_ALIGN_32(cRootDirEntries * sizeof(FATDIRENTRY), cbSector) /* root dir */; 4374 if ( cbVol <= cbFat12Overhead + cbCluster 4375 || (cbVol - cbFat12Overhead) / cbCluster <= FAT_MAX_FAT12_DATA_CLUSTERS) 4376 enmFatType = RTFSFATTYPE_FAT12; 4377 else 4378 { 4379 uint32_t cbFat16Overhead = cbSector /* boot sector */ 4380 + RT_ALIGN_32(FAT_MAX_FAT16_TOTAL_CLUSTERS * 2, cbSector) * cFats /* FATs */ 4381 + cbRootDir; 4382 if ( cbVol <= cbFat16Overhead + cbCluster 4383 || (cbVol - cbFat16Overhead) / cbCluster <= FAT_MAX_FAT16_DATA_CLUSTERS) 4384 enmFatType = RTFSFATTYPE_FAT16; 4385 else 4386 enmFatType = RTFSFATTYPE_FAT32; 4387 } 4388 } 4389 if (enmFatType == RTFSFATTYPE_FAT32) 4390 cbRootDir = cbCluster; 4391 4392 /* 4393 * Calculate the FAT size and number of data cluster. 4394 * 4395 * Since the FAT size depends on how many data clusters there are, we start 4396 * with a minimum FAT size and maximum clust count, then recalucate it. The 4397 * result isn't necessarily stable, so we will only retry stabalizing the 4398 * result a few times. 4399 */ 4400 uint32_t cbReservedFixed = enmFatType == RTFSFATTYPE_FAT32 ? 32 * cbSector : cbSector + cbRootDir; 4401 uint32_t cbFat = cbSector; 4402 if (cbReservedFixed + cbFat * cFats >= cbVol) 4403 return RTErrInfoSetF(pErrInfo, VERR_DISK_FULL, "volume is too small (cbVol=%#RX64 rsvd=%#x cbFat=%#x cFat=%#x)", 4404 cbVol, cbReservedFixed, cbFat, cFats); 4405 uint32_t cMaxClusters = enmFatType == RTFSFATTYPE_FAT12 ? FAT_MAX_FAT12_DATA_CLUSTERS 4406 : enmFatType == RTFSFATTYPE_FAT16 ? FAT_MAX_FAT16_DATA_CLUSTERS 4407 : FAT_MAX_FAT12_DATA_CLUSTERS; 4408 uint32_t cClusters = (uint32_t)RT_MIN((cbVol - cbReservedFixed - cbFat * cFats) / cbCluster, cMaxClusters); 4409 uint32_t cPrevClusters; 4410 uint32_t cTries = 4; 4411 do 4412 { 4413 cPrevClusters = cClusters; 4414 switch (enmFatType) 4415 { 4416 case RTFSFATTYPE_FAT12: 4417 cbFat = (uint32_t)RT_MIN(FAT_MAX_FAT12_TOTAL_CLUSTERS, cClusters) * 3 / 2; 4418 break; 4419 case RTFSFATTYPE_FAT16: 4420 cbFat = (uint32_t)RT_MIN(FAT_MAX_FAT16_TOTAL_CLUSTERS, cClusters) * 2; 4421 break; 4422 case RTFSFATTYPE_FAT32: 4423 cbFat = (uint32_t)RT_MIN(FAT_MAX_FAT32_TOTAL_CLUSTERS, cClusters) * 4; 4424 cbFat = RT_ALIGN_32(cbFat, _4K); 4425 break; 4426 default: 4427 AssertFailedReturn(VERR_INTERNAL_ERROR_2); 4428 } 4429 cbFat = RT_ALIGN_32(cbFat, cbSector); 4430 if (cbReservedFixed + cbFat * cFats >= cbVol) 4431 return RTErrInfoSetF(pErrInfo, VERR_DISK_FULL, "volume is too small (cbVol=%#RX64 rsvd=%#x cbFat=%#x cFat=%#x)", 4432 cbVol, cbReservedFixed, cbFat, cFats); 4433 cClusters = (uint32_t)RT_MIN((cbVol - cbReservedFixed - cbFat * cFats) / cbCluster, cMaxClusters); 4434 } while ( cClusters != cPrevClusters 4435 && cTries-- > 0); 4436 uint64_t const cTotalSectors = cClusters * (uint64_t)cSectorsPerCluster + (cbReservedFixed + cbFat * cFats) / cbSector; 4437 4438 /* 4439 * Check that the file system type and cluster count matches up. If they 4440 * don't the type will be misdetected. 4441 * 4442 * Note! These assertions could trigger if the above calculations are wrong. 4443 */ 4444 switch (enmFatType) 4445 { 4446 case RTFSFATTYPE_FAT12: 4447 AssertMsgReturn(cClusters >= FAT_MIN_FAT12_DATA_CLUSTERS && cClusters <= FAT_MAX_FAT12_DATA_CLUSTERS, 4448 ("cClusters=%#x\n", cClusters), VERR_OUT_OF_RANGE); 4449 break; 4450 case RTFSFATTYPE_FAT16: 4451 AssertMsgReturn(cClusters >= FAT_MIN_FAT16_DATA_CLUSTERS && cClusters <= FAT_MAX_FAT16_DATA_CLUSTERS, 4452 ("cClusters=%#x\n", cClusters), VERR_OUT_OF_RANGE); 4453 break; 4454 case RTFSFATTYPE_FAT32: 4455 AssertMsgReturn(cClusters >= FAT_MIN_FAT32_DATA_CLUSTERS && cClusters <= FAT_MAX_FAT32_DATA_CLUSTERS, 4456 ("cClusters=%#x\n", cClusters), VERR_OUT_OF_RANGE); 4457 default: 4458 AssertFailedReturn(VERR_INTERNAL_ERROR_2); 4459 } 4460 4461 /* 4462 * Okay, create the boot sector. 4463 */ 4464 size_t cbBuf = RT_MAX(RT_MAX(_64K, cbCluster), cbSector * 2U); 4465 uint8_t *pbBuf = (uint8_t *)RTMemTmpAllocZ(cbBuf); 4466 AssertReturn(pbBuf, VERR_NO_TMP_MEMORY); 4467 4468 const char *pszLastOp = "boot sector"; 4469 PFATBOOTSECTOR pBootSector = (PFATBOOTSECTOR)pbBuf; 4470 pBootSector->abJmp[0] = 0xeb; 4471 pBootSector->abJmp[1] = RT_UOFFSETOF(FATBOOTSECTOR, Bpb) 4472 + (enmFatType == RTFSFATTYPE_FAT32 ? sizeof(FAT32EBPB) : sizeof(FATEBPB)) - 2; 4473 pBootSector->abJmp[2] = 0x90; 4474 memcpy(pBootSector->achOemName, enmFatType == RTFSFATTYPE_FAT32 ? "FAT32 " : "IPRT 6.2", sizeof(pBootSector->achOemName)); 4475 pBootSector->Bpb.Bpb331.cbSector = (uint16_t)cbSector; 4476 pBootSector->Bpb.Bpb331.cSectorsPerCluster = (uint8_t)cSectorsPerCluster; 4477 pBootSector->Bpb.Bpb331.cReservedSectors = enmFatType == RTFSFATTYPE_FAT32 ? cbReservedFixed / cbSector : 1; 4478 pBootSector->Bpb.Bpb331.cFats = (uint8_t)cFats; 4479 pBootSector->Bpb.Bpb331.cMaxRootDirEntries = enmFatType == RTFSFATTYPE_FAT32 ? 0 : cRootDirEntries; 4480 pBootSector->Bpb.Bpb331.cTotalSectors16 = cTotalSectors <= UINT16_MAX ? (uint16_t)cTotalSectors : 0; 4481 pBootSector->Bpb.Bpb331.bMedia = bMedia; 4482 pBootSector->Bpb.Bpb331.cSectorsPerFat = enmFatType == RTFSFATTYPE_FAT32 ? 0 : cbFat / cbSector; 4483 pBootSector->Bpb.Bpb331.cSectorsPerTrack = cSectorsPerTrack; 4484 pBootSector->Bpb.Bpb331.cTracksPerCylinder = cHeads; 4485 pBootSector->Bpb.Bpb331.cHiddenSectors = cHiddenSectors; 4486 pBootSector->Bpb.Bpb331.cTotalSectors32 = cTotalSectors <= UINT32_MAX ? (uint32_t)cTotalSectors : 0; 4487 if (enmFatType != RTFSFATTYPE_FAT32) 4488 { 4489 pBootSector->Bpb.Ebpb.bInt13Drive = 0; 4490 pBootSector->Bpb.Ebpb.bReserved = 0; 4491 pBootSector->Bpb.Ebpb.bExtSignature = FATEBPB_SIGNATURE; 4492 pBootSector->Bpb.Ebpb.uSerialNumber = RTRandU32(); 4493 memset(pBootSector->Bpb.Ebpb.achLabel, ' ', sizeof(pBootSector->Bpb.Ebpb.achLabel)); 4494 memcpy(pBootSector->Bpb.Ebpb.achType, enmFatType == RTFSFATTYPE_FAT12 ? "FAT12 " : "FAT16 ", 4495 sizeof(pBootSector->Bpb.Ebpb.achType)); 4496 } 4497 else 4498 { 4499 pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32 = cbFat / cbSector; 4500 pBootSector->Bpb.Fat32Ebpb.fFlags = 0; 4501 pBootSector->Bpb.Fat32Ebpb.uVersion = FAT32EBPB_VERSION_0_0; 4502 pBootSector->Bpb.Fat32Ebpb.uRootDirCluster = FAT_FIRST_DATA_CLUSTER; 4503 pBootSector->Bpb.Fat32Ebpb.uInfoSectorNo = 1; 4504 pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo = 6; 4505 RT_ZERO(pBootSector->Bpb.Fat32Ebpb.abReserved); 4506 4507 pBootSector->Bpb.Fat32Ebpb.bInt13Drive = 0; 4508 pBootSector->Bpb.Fat32Ebpb.bReserved = 0; 4509 pBootSector->Bpb.Fat32Ebpb.bExtSignature = FATEBPB_SIGNATURE; 4510 pBootSector->Bpb.Fat32Ebpb.uSerialNumber = RTRandU32(); 4511 memset(pBootSector->Bpb.Fat32Ebpb.achLabel, ' ', sizeof(pBootSector->Bpb.Fat32Ebpb.achLabel)); 4512 if (cTotalSectors > UINT32_MAX) 4513 pBootSector->Bpb.Fat32Ebpb.u.cTotalSectors64 = cTotalSectors; 4514 else 4515 memcpy(pBootSector->Bpb.Fat32Ebpb.u.achType, "FAT32 ", sizeof(pBootSector->Bpb.Fat32Ebpb.u.achType)); 4516 } 4517 pbBuf[pBootSector->abJmp[1] + 2 + 0] = 0xcd; /* int 19h */ 4518 pbBuf[pBootSector->abJmp[1] + 2 + 1] = 0x19; 4519 pbBuf[pBootSector->abJmp[1] + 2 + 2] = 0xcc; /* int3 */ 4520 pbBuf[pBootSector->abJmp[1] + 2 + 3] = 0xcc; 4521 4522 pBootSector->uSignature = FATBOOTSECTOR_SIGNATURE; 4523 if (cbSector != sizeof(*pBootSector)) 4524 *(uint16_t *)&pbBuf[cbSector - 2] = FATBOOTSECTOR_SIGNATURE; /** @todo figure out how disks with non-512 byte sectors work! */ 4525 4526 rc = RTVfsFileWriteAt(hVfsFile, offVol, pBootSector, cbSector, NULL); 4527 uint32_t const offFirstFat = pBootSector->Bpb.Bpb331.cReservedSectors * cbSector; 4528 4529 /* 4530 * Write the FAT32 info sector, 3 boot sector copies, and zero fill 4531 * the other reserved sectors. 4532 */ 4533 if (RT_SUCCESS(rc) && enmFatType == RTFSFATTYPE_FAT32) 4534 { 4535 pszLastOp = "fat32 info sector"; 4536 PFAT32INFOSECTOR pInfoSector = (PFAT32INFOSECTOR)&pbBuf[cbSector]; /* preserve the boot sector. */ 4537 RT_ZERO(*pInfoSector); 4538 pInfoSector->uSignature1 = FAT32INFOSECTOR_SIGNATURE_1; 4539 pInfoSector->uSignature2 = FAT32INFOSECTOR_SIGNATURE_2; 4540 pInfoSector->uSignature3 = FAT32INFOSECTOR_SIGNATURE_3; 4541 pInfoSector->cFreeClusters = cClusters - 1; /* ASSUMES 1 cluster for the root dir. */ 4542 pInfoSector->cLastAllocatedCluster = FAT_FIRST_DATA_CLUSTER; 4543 rc = RTVfsFileWriteAt(hVfsFile, offVol + cbSector, pInfoSector, cbSector, NULL); 4544 4545 uint32_t iSector = 2; 4546 if (RT_SUCCESS(rc)) 4547 { 4548 pszLastOp = "fat32 unused reserved sectors"; 4549 rc = rtFsFatVolWriteZeros(hVfsFile, offVol + iSector * cbSector, 4550 (pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo - iSector) * cbSector); 4551 iSector = pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo; 4552 } 4553 4554 if (RT_SUCCESS(rc)) 4555 { 4556 pszLastOp = "boot sector copy"; 4557 for (uint32_t i = 0; i < 3 && RT_SUCCESS(rc); i++, iSector++) 4558 rc = RTVfsFileWriteAt(hVfsFile, offVol + iSector * cbSector, pBootSector, cbSector, NULL); 4559 } 4560 4561 if (RT_SUCCESS(rc)) 4562 { 4563 pszLastOp = "fat32 unused reserved sectors"; 4564 rc = rtFsFatVolWriteZeros(hVfsFile, offVol + iSector * cbSector, 4565 (pBootSector->Bpb.Bpb331.cReservedSectors - iSector) * cbSector); 4566 } 4567 } 4568 4569 /* 4570 * The FATs. 4571 */ 4572 if (RT_SUCCESS(rc)) 4573 { 4574 pszLastOp = "fat"; 4575 pBootSector = NULL; /* invalid */ 4576 RT_BZERO(pbBuf, cbSector); 4577 switch (enmFatType) 4578 { 4579 case RTFSFATTYPE_FAT32: 4580 pbBuf[11] = 0x0f; /* EOC for root dir*/ 4581 pbBuf[10] = 0xff; 4582 pbBuf[9] = 0xff; 4583 pbBuf[8] = 0xff; 4584 pbBuf[7] = 0x0f; /* Formatter's EOC, followed by signed extend FAT ID. */ 4585 pbBuf[6] = 0xff; 4586 pbBuf[5] = 0xff; 4587 pbBuf[4] = 0xff; 4588 /* fall thru */ 4589 case RTFSFATTYPE_FAT16: 4590 pbBuf[3] = 0xff; 4591 /* fall thru */ 4592 case RTFSFATTYPE_FAT12: 4593 pbBuf[2] = 0xff; 4594 pbBuf[1] = 0xff; 4595 pbBuf[0] = bMedia; /* FAT ID */ 4596 break; 4597 default: AssertFailed(); 4598 } 4599 for (uint32_t iFatCopy = 0; iFatCopy < cFats && RT_SUCCESS(rc); iFatCopy++) 4600 { 4601 rc = RTVfsFileWriteAt(hVfsFile, offVol + offFirstFat + cbFat * iFatCopy, pbBuf, cbSector, NULL); 4602 if (RT_SUCCESS(rc) && cbFat > cbSector) 4603 rc = rtFsFatVolWriteZeros(hVfsFile, offVol + offFirstFat + cbFat * iFatCopy + cbSector, cbFat - cbSector); 4604 } 4605 } 4606 4607 /* 4608 * The root directory. 4609 */ 4610 if (RT_SUCCESS(rc)) 4611 { 4612 /** @todo any mandatory directory entries we need to fill in here? */ 4613 pszLastOp = "root dir"; 4614 rc = rtFsFatVolWriteZeros(hVfsFile, offVol + offFirstFat + cbFat * cFats, cbRootDir); 4615 } 4616 4617 /* 4618 * If long format, fill the rest of the disk with 0xf6. 4619 */ 4620 AssertCompile(RTFSFATVOL_FMT_F_QUICK != 0); 4621 if (RT_SUCCESS(rc) && !(fFlags & RTFSFATVOL_FMT_F_QUICK)) 4622 { 4623 pszLastOp = "formatting data clusters"; 4624 uint64_t offCur = offFirstFat + cbFat * cFats + cbRootDir; 4625 uint64_t cbLeft = cTotalSectors * cbSector; 4626 if (cbLeft > offCur) 4627 { 4628 cbLeft -= offCur; 4629 offCur += offVol; 4630 4631 memset(pbBuf, 0xf6, cbBuf); 4632 while (cbLeft > 0) 4633 { 4634 size_t cbToWrite = cbLeft >= cbBuf ? cbBuf : (size_t)cbLeft; 4635 rc = RTVfsFileWriteAt(hVfsFile, offCur, pbBuf, cbToWrite, NULL); 4636 if (RT_SUCCESS(rc)) 4637 { 4638 offCur += cbToWrite; 4639 cbLeft -= cbToWrite; 4640 } 4641 else 4642 break; 4643 } 4644 } 4645 } 4646 4647 /* 4648 * Done. 4649 */ 4650 RTMemTmpFree(pbBuf); 4651 if (RT_SUCCESS(rc)) 4652 return rc; 4653 return RTErrInfoSet(pErrInfo, rc, pszLastOp); 4654 } 4655 4656 4657 /** 4658 * Formats a 1.44MB floppy image. 4659 * 4660 * @returns IPRT status code. 4661 * @param hVfsFile The image. 4662 */ 4663 RTDECL(int) RTFsFatVolFormat144(RTVFSFILE hVfsFile, bool fQuick) 4664 { 4665 return RTFsFatVolFormat(hVfsFile, 0 /*offVol*/, 1474560, fQuick ? RTFSFATVOL_FMT_F_QUICK : RTFSFATVOL_FMT_F_FULL, 4666 512 /*cbSector*/, 2 /*cSectorsPerCluster*/, RTFSFATTYPE_FAT12, 2 /*cHeads*/, 18 /*cSectors*/, 4667 0xf0 /*bMedia*/, 0 /*cHiddenSectors*/, 224 /*cRootDirEntries*/, NULL /*pErrInfo*/); 4169 4668 } 4170 4669
Note:
See TracChangeset
for help on using the changeset viewer.

