Changeset 66615 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Apr 19, 2017 7:29:36 PM (8 years ago)
- Location:
- trunk/src/VBox/Runtime/common
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp
r66602 r66615 30 30 *********************************************************************************************************************************/ 31 31 #include "internal/iprt.h" 32 //#include <iprt/???.h>32 #include <iprt/fs.h> 33 33 34 34 #include <iprt/asm.h> … … 37 37 #include <iprt/file.h> 38 38 #include <iprt/err.h> 39 #include <iprt/mem.h> 39 40 #include <iprt/poll.h> 40 41 #include <iprt/string.h> 42 #include <iprt/sg.h> 41 43 #include <iprt/thread.h> 42 44 #include <iprt/vfs.h> 43 45 #include <iprt/vfslowlevel.h> 46 #include <iprt/formats/fat.h> 44 47 45 48 … … 79 82 } RTFSFATCHAIN; 80 83 typedef RTFSFATCHAIN *PRTFSFATCHAIN; 84 typedef RTFSFATCHAIN const *PCRTFSFATCHAIN; 85 81 86 82 87 /** … … 85 90 typedef struct RTFSFATOBJ 86 91 { 92 /** The parent directory keeps a list of open objects (RTFSFATOBJ). */ 93 RTLISTNODE Entry; 87 94 /** The byte offset of the directory entry. 88 95 * This is set to UINT64_MAX if special FAT12/16 root directory. */ … … 103 110 struct RTFSFATVOL *pVol; 104 111 } RTFSFATOBJ; 112 typedef RTFSFATOBJ *PRTFSFATOBJ; 105 113 106 114 typedef struct RTFSFATFILE … … 113 121 typedef RTFSFATFILE *PRTFSFATFILE; 114 122 123 115 124 /** 116 125 * FAT directory. 126 * 127 * We work directories in one of two buffering modes. If there are few entries 128 * or if it's the FAT12/16 root directory, we map the whole thing into memory. 129 * If it's too large, we use an inefficient sector buffer for now. 130 * 131 * Directory entry updates happens exclusively via the directory, so any open 132 * files or subdirs have a parent reference for doing that. The parent OTOH, 133 * keeps a list of open children. 117 134 */ 118 135 typedef struct RTFSFATDIR 119 136 { 120 137 /** Core FAT object info. */ 121 RTFSFATOBJ Core; 138 RTFSFATOBJ Core; 139 /** Open child objects (RTFSFATOBJ). */ 140 RTLISTNODE OpenChildren; 141 142 /** Number of directory entries. */ 143 uint32_t cEntries; 144 145 /** If fully buffered. */ 146 bool fFullyBuffered; 147 /** Set if this is a linear root directory. */ 148 bool fIsFlatRootDir; 149 150 union 151 { 152 /** Data for the full buffered mode. 153 * No need to messing around with clusters here, as we only uses this for 154 * directories with a contiguous mapping on the disk. 155 * So, if we grow a directory in a non-contiguous manner, we have to switch 156 * to sector buffering on the fly. */ 157 struct 158 { 159 /** Directory offset. */ 160 uint64_t offDir; 161 /** Number of sectors mapped by paEntries and pbDirtySectors. */ 162 uint32_t cSectors; 163 /** Number of dirty sectors. */ 164 uint32_t cDirtySectors; 165 /** Pointer to the linear mapping of the directory entries. */ 166 PFATDIRENTRYUNION paEntries; 167 /** Dirty sector map. */ 168 uint8_t *pbDirtySectors; 169 } Full; 170 /** The simple sector buffering. 171 * This only works for clusters, so no FAT12/16 root directory fun. */ 172 struct 173 { 174 /** The disk offset of the current sector, UINT64_MAX if invalid. */ 175 uint64_t offOnDisk; 176 /** The directory offset, UINT32_MAX if invalid. */ 177 uint32_t offInDir; 178 uint32_t u32Reserved; /**< Puts pbSector and paEntries at the same location */ 179 /** Sector buffer. */ 180 PFATDIRENTRYUNION *paEntries; 181 /** Dirty flag. */ 182 bool fDirty; 183 } Simple; 184 } u; 122 185 } RTFSFATDIR; 186 /** Pointer to a FAT directory instance. */ 123 187 typedef RTFSFATDIR *PRTFSFATDIR; 188 189 190 /** 191 * File allocation table cache entry. 192 */ 193 typedef struct RTFSFATCLUSTERMAPENTRY 194 { 195 /** The byte offset into the fat, UINT32_MAX if invalid entry. */ 196 uint32_t offFat; 197 /** Pointer to the data. */ 198 uint8_t *pbData; 199 /** Dirty bitmap. Indexed by byte offset right shifted by 200 * RTFSFATCLUSTERMAPCACHE::cDirtyShift. */ 201 uint64_t bmDirty; 202 } RTFSFATCLUSTERMAPENTRY; 203 /** Pointer to a file allocation table cache entry. */ 204 typedef RTFSFATCLUSTERMAPENTRY *PRTFSFATCLUSTERMAPENTRY; 205 206 /** 207 * File allocation table cache. 208 */ 209 typedef struct RTFSFATCLUSTERMAPCACHE 210 { 211 /** Number of cache entries. */ 212 uint32_t cEntries; 213 /** The max size of data in a cache entry. */ 214 uint32_t cbEntry; 215 /** Dirty bitmap shift count. */ 216 uint32_t cDirtyShift; 217 /** The dirty cache line size (multiple of two). */ 218 uint32_t cbDirtyLine; 219 /** The cache name. */ 220 const char *pszName; 221 /** Cache entries. */ 222 RTFSFATCLUSTERMAPENTRY aEntries[RT_FLEXIBLE_ARRAY]; 223 } RTFSFATCLUSTERMAPCACHE; 224 /** Pointer to a FAT linear metadata cache. */ 225 typedef RTFSFATCLUSTERMAPCACHE *PRTFSFATCLUSTERMAPCACHE; 124 226 125 227 … … 141 243 typedef struct RTFSFATVOL 142 244 { 245 /** Handle to itself. */ 246 RTVFS hVfsSelf; 247 /** The file, partition, or whatever backing the FAT volume. */ 248 RTVFSFILE hVfsBacking; 249 /** The size of the backing thingy. */ 250 uint64_t cbBacking; 251 /** Byte offset of the bootsector relative to the start of the file. */ 252 uint64_t offBootSector; 143 253 /** Set if read-only mode. */ 144 bool fReadOnly; 145 254 bool fReadOnly; 255 /** Media byte. */ 256 uint8_t bMedia; 257 /** Reserved sectors. */ 258 uint32_t cReservedSectors; 259 260 /** Logical sector size. */ 261 uint32_t cbSector; 146 262 /** The cluster size in bytes. */ 147 uint32_t cbCluster;148 /** The number of data clusters . */149 uint32_t cClusters;263 uint32_t cbCluster; 264 /** The number of data clusters, including the two reserved ones. */ 265 uint32_t cClusters; 150 266 /** The offset of the first cluster. */ 151 uint64_t offFirstCluster; 267 uint64_t offFirstCluster; 268 /** The total size from the BPB, in bytes. */ 269 uint64_t cbTotalSize; 152 270 153 271 /** The FAT type. */ 154 RTFSFATTYPE enmFatType; 272 RTFSFATTYPE enmFatType; 273 155 274 /** Number of FAT entries (clusters). */ 156 uint32_t cFatEntries; 275 uint32_t cFatEntries; 276 /** The size of a FAT, in bytes. */ 277 uint32_t cbFat; 157 278 /** Number of FATs. */ 158 uint32_t cFats; 279 uint32_t cFats; 280 /** The end of chain marker used by the formatter (FAT entry \#2). */ 281 uint32_t idxEndOfChain; 282 /** The maximum last cluster supported by the FAT format. */ 283 uint32_t idxMaxLastCluster; 159 284 /** FAT byte offsets. */ 160 uint64_t aoffFats[8]; 285 uint64_t aoffFats[8]; 286 /** Pointer to the FAT (cluster map) cache. */ 287 PRTFSFATCLUSTERMAPCACHE pFatCache; 161 288 162 289 /** The root directory byte offset. */ 163 uint64_t offRootDir; 164 290 uint64_t offRootDir; 291 /** Root directory cluster, UINT32_MAX if not FAT32. */ 292 uint32_t idxRootDirCluster; 293 /** Number of root directory entries, if fixed. UINT32_MAX for FAT32. */ 294 uint32_t cRootDirEntries; 295 /** The size of the root directory, rounded up to the nearest sector size. */ 296 uint32_t cbRootDir; 297 /** The root directory handle. */ 298 RTVFSDIR hVfsRootDir; 299 /** The root directory instance data. */ 300 PRTFSFATDIR pRootDir; 301 302 /** Serial number. */ 303 uint32_t uSerialNo; 304 /** The stripped volume label, if included in EBPB. */ 305 char szLabel[12]; 306 /** The file system type from the EBPB (also stripped). */ 307 char szType[9]; 308 /** Number of FAT32 boot sector copies. */ 309 uint8_t cBootSectorCopies; 310 /** FAT32 flags. */ 311 uint16_t fFat32Flags; 312 /** Offset of the FAT32 boot sector copies, UINT64_MAX if none. */ 313 uint64_t offBootSectorCopies; 314 315 /** The FAT32 info sector byte offset, UINT64_MAX if not present. */ 316 uint64_t offFat32InfoSector; 317 /** The FAT32 info sector if offFat32InfoSector isn't UINT64_MAX. */ 318 FAT32INFOSECTOR Fat32InfoSector; 165 319 } RTFSFATVOL; 320 /** Pointer to a FAT volume (VFS instance data). */ 321 typedef RTFSFATVOL *PRTFSFATVOL; 322 323 324 325 /** 326 * Checks if the cluster chain is contiguous on the disk. 327 * 328 * @returns true / false. 329 * @param pChain The chain. 330 */ 331 static bool rtFsFatChain_IsContiguous(PCRTFSFATCHAIN pChain) 332 { 333 if (pChain->cClusters <= 1) 334 return true; 335 336 PRTFSFATCHAINPART pPart = RTListGetFirst(&pChain->ListParts, RTFSFATCHAINPART, ListEntry); 337 uint32_t idxNext = pPart->aEntries[0]; 338 uint32_t cLeft = pChain->cClusters; 339 for (;;) 340 { 341 uint32_t const cInPart = RT_MIN(cLeft, RT_ELEMENTS(pPart->aEntries)); 342 for (uint32_t iPart = 0; iPart < cInPart; iPart++) 343 if (pPart->aEntries[iPart] == idxNext) 344 idxNext++; 345 else 346 return false; 347 cLeft -= cInPart; 348 if (!cLeft) 349 return true; 350 pPart = RTListGetNext(&pChain->ListParts, pPart, RTFSFATCHAINPART, ListEntry); 351 } 352 } 353 354 355 356 /** 357 * Creates a cache for the file allocation table (cluster map). 358 * 359 * @returns Pointer to the cache. 360 * @param pThis The FAT volume instance. 361 * @param pbFirst512FatBytes The first 512 bytes of the first FAT. 362 */ 363 static int rtFsFatClusterMap_Create(PRTFSFATVOL pThis, uint8_t const *pbFirst512FatBytes, PRTERRINFO pErrInfo) 364 { 365 Assert(RT_ALIGN_32(pThis->cbFat, pThis->cbSector) == pThis->cbFat); 366 Assert(pThis->cbFat != 0); 367 368 /* 369 * Figure the cache size. Keeping it _very_ simple for now as we just need 370 * something that works, not anything the performs like crazy. 371 */ 372 uint32_t cEntries; 373 uint32_t cbEntry = pThis->cbFat; 374 if (cbEntry <= _512K) 375 cEntries = 1; 376 else 377 { 378 Assert(pThis->cbSector < _512K / 8); 379 cEntries = 8; 380 cbEntry = pThis->cbSector; 381 } 382 383 /* 384 * Allocate and initialize it all. 385 */ 386 PRTFSFATCLUSTERMAPCACHE pCache; 387 pThis->pFatCache = pCache = (PRTFSFATCLUSTERMAPCACHE)RTMemAllocZ(RT_OFFSETOF(RTFSFATCLUSTERMAPCACHE, aEntries[cEntries])); 388 if (!pCache) 389 return RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "Failed to allocate FAT cache"); 390 pCache->cEntries = cEntries; 391 pCache->cbEntry = cbEntry; 392 393 unsigned i = cEntries; 394 while (i-- > 0) 395 { 396 pCache->aEntries[i].pbData = (uint8_t *)RTMemAlloc(cbEntry); 397 if (pCache->aEntries[i].pbData == NULL) 398 { 399 for (i++; i < cEntries; i++) 400 RTMemFree(pCache->aEntries[i].pbData); 401 RTMemFree(pCache); 402 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate FAT cache entry (%#x bytes)", cbEntry); 403 } 404 405 pCache->aEntries[i].offFat = UINT32_MAX; 406 pCache->aEntries[i].bmDirty = 0; 407 } 408 409 /* 410 * Calc the dirty shift factor. 411 */ 412 cbEntry /= 64; 413 if (cbEntry < pThis->cbSector) 414 cbEntry = pThis->cbSector; 415 416 pCache->cDirtyShift = 1; 417 pCache->cbDirtyLine = 1; 418 while (pCache->cbDirtyLine < cbEntry) 419 { 420 pCache->cDirtyShift++; 421 pCache->cbDirtyLine <<= 1; 422 } 423 424 /* 425 * Fill the cache if single entry or entry size is 512. 426 */ 427 if (pCache->cEntries == 1 || pCache->cbEntry == 512) 428 { 429 memcpy(pCache->aEntries[0].pbData, pbFirst512FatBytes, RT_MIN(512, pCache->cbEntry)); 430 if (pCache->cbEntry > 512) 431 { 432 int rc = RTVfsFileReadAt(pThis->hVfsBacking, pThis->aoffFats[0] + 512, 433 &pCache->aEntries[0].pbData[512], pCache->cbEntry - 512, NULL); 434 if (RT_FAILURE(rc)) 435 return RTErrInfoSet(pErrInfo, rc, "Error reading FAT into memory"); 436 } 437 pCache->aEntries[0].offFat = 0; 438 pCache->aEntries[0].bmDirty = 0; 439 } 440 441 return VINF_SUCCESS; 442 } 443 444 445 /** 446 * Worker for rtFsFatClusterMap_Flush and rtFsFatClusterMap_FlushEntry. 447 * 448 * @returns IPRT status code. On failure, we're currently kind of screwed. 449 * @param pThis The FAT volume instance. 450 * @param iFirstEntry Entry to start flushing at. 451 * @param iLastEntry Last entry to flush. 452 */ 453 static int rtFsFatClusterMap_FlushWorker(PRTFSFATVOL pThis, uint32_t const iFirstEntry, uint32_t const iLastEntry) 454 { 455 PRTFSFATCLUSTERMAPCACHE pCache = pThis->pFatCache; 456 457 /* 458 * Walk the cache entries, accumulating segments to flush. 459 */ 460 int rc = VINF_SUCCESS; 461 uint64_t off = UINT64_MAX; 462 uint64_t offEdge = UINT64_MAX; 463 RTSGSEG aSgSegs[8]; 464 RTSGBUF SgBuf; 465 RTSgBufInit(&SgBuf, aSgSegs, RT_ELEMENTS(aSgSegs)); 466 SgBuf.cSegs = 0; /** @todo RTSgBuf API is stupid, make it smarter. */ 467 468 for (uint32_t iFatCopy = 0; iFatCopy < pThis->cFats; iFatCopy++) 469 { 470 for (uint32_t iEntry = iFirstEntry; iEntry <= iLastEntry; iEntry++) 471 { 472 uint64_t bmDirty = pCache->aEntries[iEntry].bmDirty; 473 if ( bmDirty != 0 474 && pCache->aEntries[iEntry].offFat != UINT32_MAX) 475 { 476 uint32_t offEntry = 0; 477 uint64_t iDirtyLine = 1; 478 while (offEntry < pCache->cbEntry) 479 { 480 if (pCache->aEntries[iEntry].bmDirty & iDirtyLine) 481 { 482 /* 483 * Found dirty cache line. 484 */ 485 uint64_t offDirtyLine = pThis->aoffFats[iFatCopy] + pCache->aEntries[iEntry].offFat + offEntry; 486 487 /* Can we simply extend the last segment? */ 488 if ( offDirtyLine == offEdge 489 && offEntry) 490 { 491 Assert( (uintptr_t)aSgSegs[SgBuf.cSegs - 1].pvSeg + aSgSegs[SgBuf.cSegs - 1].cbSeg 492 == (uintptr_t)&pCache->aEntries[iEntry].pbData[offEntry]); 493 aSgSegs[SgBuf.cSegs - 1].cbSeg += pCache->cbDirtyLine; 494 offEdge += pCache->cbDirtyLine; 495 } 496 else 497 { 498 /* flush if not adjacent or if we're out of segments. */ 499 if ( offDirtyLine != offEdge 500 || SgBuf.cSegs >= RT_ELEMENTS(aSgSegs)) 501 { 502 int rc2 = RTVfsFileSgWrite(pThis->hVfsBacking, off, &SgBuf, true /*fBlocking*/, NULL); 503 if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) 504 rc = rc2; 505 RTSgBufReset(&SgBuf); 506 SgBuf.cSegs = 0; 507 } 508 509 /* Append segment. */ 510 aSgSegs[SgBuf.cSegs].cbSeg = pCache->cbDirtyLine; 511 aSgSegs[SgBuf.cSegs].pvSeg = &pCache->aEntries[iEntry].pbData[offEntry]; 512 SgBuf.cSegs++; 513 offEdge = offDirtyLine + pCache->cbDirtyLine; 514 } 515 516 bmDirty &= ~iDirtyLine; 517 if (!bmDirty) 518 break; 519 } 520 } 521 iDirtyLine++; 522 offEntry += pCache->cbDirtyLine; 523 } 524 } 525 } 526 527 /* 528 * Final flush job. 529 */ 530 if (SgBuf.cSegs > 0) 531 { 532 int rc2 = RTVfsFileSgWrite(pThis->hVfsBacking, off, &SgBuf, true /*fBlocking*/, NULL); 533 if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) 534 rc = rc2; 535 } 536 537 /* 538 * Clear the dirty flags on success. 539 */ 540 if (RT_SUCCESS(rc)) 541 for (uint32_t iEntry = iFirstEntry; iEntry <= iLastEntry; iEntry++) 542 pCache->aEntries[iEntry].bmDirty = 0; 543 544 return rc; 545 } 546 547 548 /** 549 * Flushes out all dirty lines in the entire file allocation table cache. 550 * 551 * @returns IPRT status code. On failure, we're currently kind of screwed. 552 * @param pThis The FAT volume instance. 553 */ 554 static int rtFsFatClusterMap_Flush(PRTFSFATVOL pThis) 555 { 556 return rtFsFatClusterMap_FlushWorker(pThis, 0, pThis->pFatCache->cEntries - 1); 557 } 558 559 560 /** 561 * Flushes out all dirty lines in the file allocation table (cluster map) cache. 562 * 563 * This is typically called prior to reusing the cache entry. 564 * 565 * @returns IPRT status code. On failure, we're currently kind of screwed. 566 * @param pThis The FAT volume instance. 567 * @param iEntry The cache entry to flush. 568 */ 569 static int rtFsFatClusterMap_FlushEntry(PRTFSFATVOL pThis, uint32_t iEntry) 570 { 571 return rtFsFatClusterMap_FlushWorker(pThis, iEntry, iEntry); 572 } 573 574 575 /** 576 * Destroys the file allcation table cache, first flushing any dirty lines. 577 * 578 * @returns IRPT status code from flush (we've destroyed it regardless of the 579 * status code). 580 * @param pThis The FAT volume instance which cluster map shall be 581 * destroyed. 582 */ 583 static int rtFsFatClusterMap_Destroy(PRTFSFATVOL pThis) 584 { 585 int rc = VINF_SUCCESS; 586 PRTFSFATCLUSTERMAPCACHE pCache = pThis->pFatCache; 587 if (pCache) 588 { 589 /* flush stuff. */ 590 rc = rtFsFatClusterMap_Flush(pThis); 591 592 /* free everything. */ 593 uint32_t i = pCache->cEntries; 594 while (i-- > 0) 595 { 596 RTMemFree(pCache->aEntries[i].pbData); 597 pCache->aEntries[i].pbData = NULL; 598 } 599 pCache->cEntries = 0; 600 RTMemFree(pCache); 601 602 pThis->pFatCache = NULL; 603 } 604 605 return rc; 606 } 607 608 609 /** 610 * Reads a cluster chain into memory 611 * 612 * @returns IPRT status code. 613 * @param pThis The FAT volume instance. 614 * @param idxFirstCluster The first cluster. 615 * @param pChain The chain element to read into (and thereby 616 * initialize). 617 */ 618 static int rtFsFatClusterMap_ReadClusterChain(PRTFSFATVOL pThis, uint32_t idxFirstCluster, PRTFSFATCHAIN pChain) 619 { 620 pChain->cClusters = 0; 621 pChain->cbChain = 0; 622 RTListInit(&pChain->ListParts); 623 624 if ( idxFirstCluster >= pThis->cClusters 625 && idxFirstCluster >= FAT_FIRST_DATA_CLUSTER) 626 return VERR_VFS_BOGUS_OFFSET; 627 628 return VERR_NOT_IMPLEMENTED; 629 } 630 631 632 static void rtFsFatDosDateTimeToSpec(PRTTIMESPEC pTimeSpec, uint16_t uDate, uint16_t uTime, uint8_t cCentiseconds) 633 { 634 RTTIME Time; 635 Time.i32Year = 1980 + (uDate >> 9); 636 Time.u8Month = ((uDate >> 5) & 0xf); 637 Time.u8WeekDay = UINT8_MAX; 638 Time.u16YearDay = UINT16_MAX; 639 Time.u8MonthDay = RT_MAX(uDate & 0x1f, 1); 640 Time.u8Hour = uTime >> 11; 641 Time.u8Minute = (uTime >> 5) & 0x3f; 642 Time.u8Second = (uTime & 0x1f) << 1; 643 if (cCentiseconds > 0 && cCentiseconds < 200) /* screw complicated stuff for now. */ 644 { 645 if (cCentiseconds >= 100) 646 { 647 cCentiseconds -= 100; 648 Time.u8Second++; 649 } 650 Time.u32Nanosecond = cCentiseconds * UINT64_C(100000000); 651 } 652 653 RTTimeImplode(pTimeSpec, RTTimeNormalize(&Time)); 654 } 655 656 657 static void rtFsFatObj_InitFromDirEntry(PRTFSFATOBJ pObj, PCFATDIRENTRY pDirEntry, uint64_t offDirEntry, PRTFSFATVOL pThis) 658 { 659 RTListInit(&pObj->Entry); 660 pObj->pVol = pThis; 661 pObj->offDirEntry = offDirEntry; 662 pObj->fAttrib = ((RTFMODE)pDirEntry->fAttrib << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_OS2; 663 pObj->cbObject = pDirEntry->cbFile; 664 rtFsFatDosDateTimeToSpec(&pObj->ModificationTime, pDirEntry->uAccessDate, pDirEntry->uModifyTime, 0); 665 rtFsFatDosDateTimeToSpec(&pObj->BirthTime, pDirEntry->uBirthDate, pDirEntry->uBirthTime, pDirEntry->uBirthCentiseconds); 666 rtFsFatDosDateTimeToSpec(&pObj->AccessTime, pDirEntry->uAccessDate, 0, 0); 667 } 668 669 670 static void rtFsFatObj_InitDummy(PRTFSFATOBJ pObj, uint64_t offDirEntry, uint32_t cbObject, RTFMODE fAttrib, PRTFSFATVOL pThis) 671 { 672 RTListInit(&pObj->Entry); 673 pObj->pVol = pThis; 674 pObj->offDirEntry = offDirEntry; 675 pObj->fAttrib = fAttrib; 676 pObj->cbObject = cbObject; 677 RTTimeSpecSetDosSeconds(&pObj->AccessTime, 0); 678 RTTimeSpecSetDosSeconds(&pObj->ModificationTime, 0); 679 RTTimeSpecSetDosSeconds(&pObj->BirthTime, 0); 680 } 166 681 167 682 … … 569 1084 570 1085 /** 571 * @interface_method_impl{RTVFSOPS,pfnDestroy} 572 */ 573 static DECLCALLBACK(void) rtFsFatVol_Destroy(void *pvThis) 574 { 575 RT_NOREF(pvThis); 1086 * Instantiates a new directory. 1087 * 1088 * @returns IPRT status code. 1089 * @param pThis The FAT volume instance. 1090 * @param pParentDir The parent directory. This is NULL for the root 1091 * directory. 1092 * @param pDirEntry The parent directory entry. This is NULL for the root 1093 * directory. 1094 * @param offDirEntry The byte offset of the directory entry. UINT64_MAX if 1095 * root directory. 1096 * @param idxCluster The cluster where the directory content is to be found. 1097 * This can be UINT32_MAX if a root FAT12/16 directory. 1098 * @param offDisk The disk byte offset of the FAT12/16 root directory. 1099 * This is UINT64_MAX if idxCluster is given. 1100 * @param cbDir The size of the directory. 1101 * @param phVfsDir Where to return the directory handle. 1102 * @param ppDir Where to return the FAT directory instance data. 1103 */ 1104 static int rtFsFatDir_New(PRTFSFATVOL pThis, PRTFSFATDIR pParentDir, PCFATDIRENTRY pDirEntry, uint64_t offDirEntry, 1105 uint32_t idxCluster, uint64_t offDisk, uint32_t cbDir, PRTVFSDIR phVfsDir, PRTFSFATDIR *ppDir) 1106 { 1107 Assert((idxCluster == UINT32_MAX) != (offDisk == UINT64_MAX)); 1108 *ppDir = NULL; 1109 1110 PRTFSFATDIR pNewDir; 1111 int rc = RTVfsNewDir(&g_rtFsFatDirOps, sizeof(*pNewDir), 0 /*fFlags*/, pThis->hVfsSelf, 1112 NIL_RTVFSLOCK, phVfsDir, (void **)&pNewDir); 1113 if (RT_SUCCESS(rc)) 1114 { 1115 /* 1116 * Initialize it all so rtFsFatDir_Close doesn't trip up in anyway. 1117 */ 1118 RTListInit(&pNewDir->OpenChildren); 1119 if (pDirEntry) 1120 rtFsFatObj_InitFromDirEntry(&pNewDir->Core, pDirEntry, offDirEntry, pThis); 1121 else 1122 rtFsFatObj_InitDummy(&pNewDir->Core, offDirEntry, cbDir, RTFS_DOS_DIRECTORY, pThis); 1123 1124 pNewDir->cEntries = cbDir / sizeof(FATDIRENTRY); 1125 pNewDir->fIsFlatRootDir = idxCluster == UINT32_MAX; 1126 pNewDir->fFullyBuffered = pNewDir->fIsFlatRootDir; 1127 if (pNewDir->fFullyBuffered) 1128 { 1129 pNewDir->u.Full.offDir = UINT64_MAX; 1130 pNewDir->u.Full.cSectors = 0; 1131 pNewDir->u.Full.cDirtySectors = 0; 1132 pNewDir->u.Full.paEntries = NULL; 1133 pNewDir->u.Full.pbDirtySectors = NULL; 1134 } 1135 else 1136 { 1137 pNewDir->u.Simple.offOnDisk = UINT64_MAX; 1138 pNewDir->u.Simple.offInDir = UINT32_MAX; 1139 pNewDir->u.Simple.u32Reserved = 0; 1140 pNewDir->u.Simple.paEntries = NULL; 1141 pNewDir->u.Simple.fDirty = false; 1142 } 1143 1144 /* 1145 * If clustered backing, read the chain and see if we cannot still do the full buffering. 1146 */ 1147 if (idxCluster != UINT32_MAX) 1148 { 1149 rc = rtFsFatClusterMap_ReadClusterChain(pThis, idxCluster, &pNewDir->Core.Clusters); 1150 if (RT_SUCCESS(rc)) 1151 { 1152 if ( pNewDir->Core.Clusters.cClusters >= 1 1153 && pNewDir->Core.Clusters.cbChain <= _64K 1154 && rtFsFatChain_IsContiguous(&pNewDir->Core.Clusters)) 1155 pNewDir->fFullyBuffered = true; 1156 } 1157 } 1158 1159 if (RT_SUCCESS(rc)) 1160 { 1161 RT_NOREF(pParentDir); 1162 } 1163 1164 RTVfsDirRelease(*phVfsDir); 1165 } 1166 *phVfsDir = NIL_RTVFSDIR; 1167 *ppDir = NULL; 1168 return rc; 1169 } 1170 1171 1172 1173 1174 1175 /** 1176 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose} 1177 */ 1178 static DECLCALLBACK(int) rtFsFatVol_Close(void *pvThis) 1179 { 1180 PRTFSFATVOL pThis = (PRTFSFATVOL)pvThis; 1181 int rc = rtFsFatClusterMap_Destroy(pThis); 1182 1183 if (pThis->hVfsRootDir != NIL_RTVFSDIR) 1184 { 1185 Assert(RTListIsEmpty(&pThis->pRootDir->OpenChildren)); 1186 uint32_t cRefs = RTVfsDirRelease(pThis->hVfsRootDir); 1187 Assert(cRefs == 0); 1188 pThis->hVfsRootDir = NIL_RTVFSDIR; 1189 pThis->pRootDir = NULL; 1190 } 1191 1192 RTVfsFileRelease(pThis->hVfsBacking); 1193 pThis->hVfsBacking = NIL_RTVFSFILE; 1194 1195 return rc; 1196 } 1197 1198 1199 /** 1200 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo} 1201 */ 1202 static DECLCALLBACK(int) rtFsFatVol_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr) 1203 { 1204 RT_NOREF(pvThis, pObjInfo, enmAddAttr); 1205 return VERR_WRONG_TYPE; 576 1206 } 577 1207 … … 599 1229 DECL_HIDDEN_CONST(const RTVFSOPS) g_rtFsFatVolOps = 600 1230 { 1231 { /* Obj */ 1232 RTVFSOBJOPS_VERSION, 1233 RTVFSOBJTYPE_VFS, 1234 "FatVol", 1235 rtFsFatVol_Close, 1236 rtFsFatVol_QueryInfo, 1237 RTVFSOBJOPS_VERSION 1238 }, 601 1239 RTVFSOPS_VERSION, 602 1240 0 /* fFeatures */, 603 "FatVol",604 rtFsFatVol_Destroy,605 1241 rtFsFatVol_OpenRoot, 606 1242 rtFsFatVol_IsRangeInUse, … … 609 1245 610 1246 611 612 RTDECL(int) RTFsFatVolOpen(RTVFSFILE hVfsFileIn, bool fReadOnly, PRTVFS phVfs, PRTERRINFO pErrInfo) 613 { 614 RT_NOREF(hVfsFileIn, fReadOnly, pErrInfo, phVfs); 615 return VERR_NOT_IMPLEMENTED; 1247 /** 1248 * Tries to detect a DOS 1.x formatted image and fills in the BPB fields. 1249 * 1250 * There is no BPB here, but fortunately, there isn't much variety. 1251 * 1252 * @returns IPRT status code. 1253 * @param pThis The FAT volume instance, BPB derived fields are filled 1254 * in on success. 1255 * @param pBootSector The boot sector. 1256 * @param pbFatSector Points to the FAT sector, or whatever is 512 bytes after 1257 * the boot sector. 1258 * @param pErrInfo Where to return additional error information. 1259 */ 1260 static int rtFsFatVolTryInitDos1x(PRTFSFATVOL pThis, PCFATBOOTSECTOR pBootSector, uint8_t const *pbFatSector, 1261 PRTERRINFO pErrInfo) 1262 { 1263 /* 1264 * PC-DOS 1.0 does a 2fh byte short jump w/o any NOP following it. 1265 * Instead the following are three words and a 9 byte build date 1266 * string. The remaining space is zero filled. 1267 * 1268 * Note! No idea how this would look like for 8" floppies, only got 5"1/4'. 1269 * 1270 * ASSUME all non-BPB disks are using this format. 1271 */ 1272 if ( pBootSector->abJmp[0] != 0xeb /* jmp rel8 */ 1273 || pBootSector->abJmp[1] < 0x2f 1274 || pBootSector->abJmp[1] >= 0x80 1275 || pBootSector->abJmp[2] == 0x90 /* nop */) 1276 return RTErrInfoSetF(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, 1277 "No DOS v1.0 bootsector either - invalid jmp: %.3Rhxs", pBootSector->abJmp); 1278 uint32_t const offJump = 2 + pBootSector->abJmp[1]; 1279 uint32_t const offFirstZero = 2 /*jmp */ + 3 * 2 /* words */ + 9 /* date string */; 1280 Assert(offFirstZero >= RT_OFFSETOF(FATBOOTSECTOR, Bpb)); 1281 uint32_t const cbZeroPad = RT_MIN(offJump - offFirstZero, 1282 sizeof(pBootSector->Bpb.Bpb20) - (offFirstZero - RT_OFFSETOF(FATBOOTSECTOR, Bpb))); 1283 1284 if (!ASMMemIsAllU8((uint8_t const *)pBootSector + offFirstZero, cbZeroPad, 0)) 1285 return RTErrInfoSetF(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, 1286 "No DOS v1.0 bootsector either - expected zero padding %#x LB %#x: %.*Rhxs", 1287 offFirstZero, cbZeroPad, cbZeroPad, (uint8_t const *)pBootSector + offFirstZero); 1288 1289 /* 1290 * Check the FAT ID so we can tell if this is double or single sided, 1291 * as well as being a valid FAT12 start. 1292 */ 1293 if ( (pbFatSector[0] != 0xfe && pbFatSector[0] != 0xff) 1294 || pbFatSector[1] != 0xff 1295 || pbFatSector[2] != 0xff) 1296 return RTErrInfoSetF(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, 1297 "No DOS v1.0 bootsector either - unexpected start of FAT: %.3Rhxs", pbFatSector); 1298 1299 /* 1300 * Fixed DOS 1.0 config. 1301 */ 1302 pThis->enmFatType = RTFSFATTYPE_FAT12; 1303 pThis->bMedia = pbFatSector[0]; 1304 pThis->cReservedSectors = 1; 1305 pThis->cbSector = 512; 1306 pThis->cbCluster = pThis->bMedia == 0xfe ? 1024 : 512; 1307 pThis->cFats = 2; 1308 pThis->cbFat = 512; 1309 pThis->aoffFats[0] = pThis->offBootSector + pThis->cReservedSectors * 512; 1310 pThis->aoffFats[1] = pThis->aoffFats[0] + pThis->cbFat; 1311 pThis->offRootDir = pThis->aoffFats[1] + pThis->cbFat; 1312 pThis->cRootDirEntries = 512; 1313 pThis->offFirstCluster = pThis->offRootDir + RT_ALIGN_32(pThis->cRootDirEntries * sizeof(FATDIRENTRY), 1314 pThis->cbSector); 1315 pThis->cbTotalSize = pThis->bMedia == 0xfe ? 8 * 1 * 40 * 512 : 8 * 2 * 40 * 512; 1316 pThis->cClusters = (pThis->cbTotalSize - (pThis->offFirstCluster - pThis->offBootSector)) / pThis->cbCluster; 1317 return VINF_SUCCESS; 1318 } 1319 1320 1321 /** 1322 * Worker for rtFsFatVolTryInitDos2Plus that handles remaining BPB fields. 1323 * 1324 * @returns IPRT status code. 1325 * @param pThis The FAT volume instance, BPB derived fields are filled 1326 * in on success. 1327 * @param pBootSector The boot sector. 1328 * @param fMaybe331 Set if it could be a DOS v3.31 BPB. 1329 * @param pErrInfo Where to return additional error information. 1330 */ 1331 static int rtFsFatVolTryInitDos2PlusBpb(PRTFSFATVOL pThis, PCFATBOOTSECTOR pBootSector, bool fMaybe331, PRTERRINFO pErrInfo) 1332 { 1333 /* 1334 * Figure total sector count. Could both be zero, in which case we have to 1335 * fall back on the size of the backing stuff. 1336 */ 1337 if (pBootSector->Bpb.Bpb20.cTotalSectors16 != 0) 1338 pThis->cbTotalSize = pBootSector->Bpb.Bpb20.cTotalSectors16 * pThis->cbSector; 1339 else if ( pBootSector->Bpb.Bpb331.cTotalSectors32 != 0 1340 && fMaybe331) 1341 pThis->cbTotalSize = pBootSector->Bpb.Bpb331.cTotalSectors32 * (uint64_t)pThis->cbSector; 1342 else 1343 pThis->cbTotalSize = pThis->cbBacking - pThis->offBootSector; 1344 if (pThis->cReservedSectors * pThis->cbSector >= pThis->cbTotalSize) 1345 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1346 "Bogus FAT12/16 total or reserved sector count: %#x vs %#x", 1347 pThis->cReservedSectors, pThis->cbTotalSize / pThis->cbSector); 1348 1349 /* 1350 * The fat size. Complete FAT offsets. 1351 */ 1352 if ( pBootSector->Bpb.Bpb20.cSectorsPerFat == 0 1353 || ((uint32_t)pBootSector->Bpb.Bpb20.cSectorsPerFat * pThis->cFats + 1) * pThis->cbSector > pThis->cbTotalSize) 1354 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Bogus FAT12/16 sectors per FAT: %#x (total sectors %#RX64)", 1355 pBootSector->Bpb.Bpb20.cSectorsPerFat, pThis->cbTotalSize / pThis->cbSector); 1356 pThis->cbFat = pBootSector->Bpb.Bpb20.cSectorsPerFat * pThis->cbSector; 1357 1358 AssertReturn(pThis->cFats < RT_ELEMENTS(pThis->aoffFats), VERR_VFS_BOGUS_FORMAT); 1359 for (unsigned iFat = 1; iFat <= pThis->cFats; iFat++) 1360 pThis->aoffFats[iFat] = pThis->aoffFats[iFat - 1] + pThis->cbFat; 1361 1362 /* 1363 * Do root directory calculations. 1364 */ 1365 pThis->idxRootDirCluster = UINT32_MAX; 1366 pThis->offRootDir = pThis->aoffFats[pThis->cFats]; 1367 if (pThis->cRootDirEntries == 0) 1368 return RTErrInfoSet(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Zero FAT12/16 root directory size"); 1369 pThis->cbRootDir = pThis->cRootDirEntries * sizeof(FATDIRENTRY); 1370 pThis->cbRootDir = RT_ALIGN_32(pThis->cbRootDir, pThis->cbSector); 1371 1372 /* 1373 * First cluster and cluster count checks and calcs. Determin FAT type. 1374 */ 1375 pThis->offFirstCluster = pThis->offRootDir + pThis->cbRootDir; 1376 uint64_t cbSystemStuff = pThis->offFirstCluster - pThis->offBootSector; 1377 if (cbSystemStuff >= pThis->cbTotalSize) 1378 return RTErrInfoSet(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Bogus FAT12/16 total size, root dir, or fat size"); 1379 pThis->cClusters = (pThis->cbTotalSize - cbSystemStuff) / pThis->cbCluster; 1380 1381 if (pThis->cClusters >= FAT_LAST_FAT16_DATA_CLUSTER) 1382 { 1383 pThis->cClusters = FAT_LAST_FAT16_DATA_CLUSTER + 1; 1384 pThis->enmFatType = RTFSFATTYPE_FAT16; 1385 } 1386 else if (pThis->cClusters > FAT_LAST_FAT12_DATA_CLUSTER) 1387 pThis->enmFatType = RTFSFATTYPE_FAT16; 1388 else 1389 pThis->enmFatType = RTFSFATTYPE_FAT12; /** @todo Not sure if this is entirely the right way to go about it... */ 1390 1391 uint32_t cClustersPerFat; 1392 if (pThis->enmFatType == RTFSFATTYPE_FAT16) 1393 cClustersPerFat = pThis->cbFat / 2; 1394 else 1395 cClustersPerFat = pThis->cbFat * 2 / 3; 1396 if (pThis->cClusters > cClustersPerFat) 1397 pThis->cClusters = cClustersPerFat; 1398 1399 return VINF_SUCCESS; 1400 } 1401 1402 1403 /** 1404 * Worker for rtFsFatVolTryInitDos2Plus and rtFsFatVolTryInitDos2PlusFat32 that 1405 * handles common extended BPBs fields. 1406 * 1407 * @returns IPRT status code. 1408 * @param pThis The FAT volume instance. 1409 * @param bExtSignature The extended BPB signature. 1410 * @param uSerialNumber The serial number. 1411 * @param pachLabel Pointer to the volume label field. 1412 * @param pachType Pointer to the file system type field. 1413 */ 1414 static void rtFsFatVolInitCommonEbpbBits(PRTFSFATVOL pThis, uint8_t bExtSignature, uint32_t uSerialNumber, 1415 char const *pachLabel, char const *pachType) 1416 { 1417 pThis->uSerialNo = uSerialNumber; 1418 if (bExtSignature == FATEBPB_SIGNATURE) 1419 { 1420 memcpy(pThis->szLabel, pachLabel, RT_SIZEOFMEMB(FATEBPB, achLabel)); 1421 pThis->szLabel[RT_SIZEOFMEMB(FATEBPB, achLabel)] = '\0'; 1422 RTStrStrip(pThis->szLabel); 1423 1424 memcpy(pThis->szType, pachType, RT_SIZEOFMEMB(FATEBPB, achType)); 1425 pThis->szType[RT_SIZEOFMEMB(FATEBPB, achType)] = '\0'; 1426 RTStrStrip(pThis->szType); 1427 } 1428 else 1429 { 1430 pThis->szLabel[0] = '\0'; 1431 pThis->szType[0] = '\0'; 1432 } 1433 } 1434 1435 1436 /** 1437 * Worker for rtFsFatVolTryInitDos2Plus that deals with FAT32. 1438 * 1439 * @returns IPRT status code. 1440 * @param pThis The FAT volume instance, BPB derived fields are filled 1441 * in on success. 1442 * @param pBootSector The boot sector. 1443 * @param pErrInfo Where to return additional error information. 1444 */ 1445 static int rtFsFatVolTryInitDos2PlusFat32(PRTFSFATVOL pThis, PCFATBOOTSECTOR pBootSector, PRTERRINFO pErrInfo) 1446 { 1447 pThis->enmFatType = RTFSFATTYPE_FAT32; 1448 pThis->fFat32Flags = pBootSector->Bpb.Fat32Ebpb.fFlags; 1449 1450 if (pBootSector->Bpb.Fat32Ebpb.uVersion != FAT32EBPB_VERSION_0_0) 1451 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Unsupported FAT32 version: %d.%d (%#x)", 1452 RT_HI_U8(pBootSector->Bpb.Fat32Ebpb.uVersion), RT_LO_U8(pBootSector->Bpb.Fat32Ebpb.uVersion), 1453 pBootSector->Bpb.Fat32Ebpb.uVersion); 1454 1455 /* 1456 * Figure total sector count. We expected it to be filled in. 1457 */ 1458 bool fUsing64BitTotalSectorCount = false; 1459 if (pBootSector->Bpb.Fat32Ebpb.Bpb.cTotalSectors16 != 0) 1460 pThis->cbTotalSize = pBootSector->Bpb.Fat32Ebpb.Bpb.cTotalSectors16 * pThis->cbSector; 1461 else if (pBootSector->Bpb.Fat32Ebpb.Bpb.cTotalSectors32 != 0) 1462 pThis->cbTotalSize = pBootSector->Bpb.Fat32Ebpb.Bpb.cTotalSectors32 * (uint64_t)pThis->cbSector; 1463 else if ( pBootSector->Bpb.Fat32Ebpb.u.cTotalSectors64 <= UINT64_MAX / 512 1464 && pBootSector->Bpb.Fat32Ebpb.u.cTotalSectors64 > 3 1465 && pBootSector->Bpb.Fat32Ebpb.bExtSignature != FATEBPB_SIGNATURE_OLD) 1466 { 1467 pThis->cbTotalSize = pBootSector->Bpb.Fat32Ebpb.u.cTotalSectors64 * pThis->cbSector; 1468 fUsing64BitTotalSectorCount = true; 1469 } 1470 else 1471 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "FAT32 total sector count out of range: %#RX64", 1472 pBootSector->Bpb.Fat32Ebpb.u.cTotalSectors64); 1473 if (pThis->cReservedSectors * pThis->cbSector >= pThis->cbTotalSize) 1474 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1475 "Bogus FAT32 total or reserved sector count: %#x vs %#x", 1476 pThis->cReservedSectors, pThis->cbTotalSize / pThis->cbSector); 1477 1478 /* 1479 * Fat size. We check the 16-bit field even if it probably should be zero all the time. 1480 */ 1481 if (pBootSector->Bpb.Fat32Ebpb.Bpb.cSectorsPerFat != 0) 1482 { 1483 if ( pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32 != 0 1484 && pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32 != pBootSector->Bpb.Fat32Ebpb.Bpb.cSectorsPerFat) 1485 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1486 "Both 16-bit and 32-bit FAT size fields are set: %#RX16 vs %#RX32", 1487 pBootSector->Bpb.Fat32Ebpb.Bpb.cSectorsPerFat, pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32); 1488 pThis->cbFat = pBootSector->Bpb.Fat32Ebpb.Bpb.cSectorsPerFat * pThis->cbSector; 1489 } 1490 else 1491 { 1492 uint64_t cbFat = pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32 * (uint64_t)pThis->cbSector; 1493 if ( cbFat == 0 1494 || cbFat >= (FAT_LAST_FAT32_DATA_CLUSTER + 1) * 4 + pThis->cbSector * 16) 1495 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1496 "Bogus 32-bit FAT size: %#RX32", pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32); 1497 pThis->cbFat = (uint32_t)cbFat; 1498 } 1499 1500 /* 1501 * Complete the FAT offsets and first cluster offset, then calculate number 1502 * of data clusters. 1503 */ 1504 AssertReturn(pThis->cFats < RT_ELEMENTS(pThis->aoffFats), VERR_VFS_BOGUS_FORMAT); 1505 for (unsigned iFat = 1; iFat <= pThis->cFats; iFat++) 1506 pThis->aoffFats[iFat] = pThis->aoffFats[iFat - 1] + pThis->cbFat; 1507 pThis->offFirstCluster = pThis->aoffFats[pThis->cFats]; 1508 1509 if (pThis->offFirstCluster - pThis->offBootSector >= pThis->cbTotalSize) 1510 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1511 "Bogus 32-bit FAT size or total sector count: cFats=%d cbFat=%#x cbTotalSize=%#x", 1512 pThis->cFats, pThis->cbFat, pThis->cbTotalSize); 1513 1514 uint64_t cClusters = (pThis->cbTotalSize - (pThis->offFirstCluster - pThis->offBootSector)) / pThis->cbCluster; 1515 if (cClusters <= FAT_LAST_FAT32_DATA_CLUSTER) 1516 pThis->cClusters = (uint32_t)cClusters; 1517 else 1518 pThis->cClusters = FAT_LAST_FAT32_DATA_CLUSTER + 1; 1519 if (pThis->cClusters > pThis->cbFat / 4) 1520 pThis->cClusters = pThis->cbFat / 4; 1521 1522 /* 1523 * Root dir cluster. 1524 */ 1525 if ( pBootSector->Bpb.Fat32Ebpb.uRootDirCluster < FAT_FIRST_DATA_CLUSTER 1526 || pBootSector->Bpb.Fat32Ebpb.uRootDirCluster >= pThis->cClusters) 1527 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1528 "Bogus FAT32 root directory cluster: %#x", pBootSector->Bpb.Fat32Ebpb.uRootDirCluster); 1529 pThis->idxRootDirCluster = pBootSector->Bpb.Fat32Ebpb.uRootDirCluster; 1530 pThis->offRootDir = pThis->offFirstCluster 1531 + (pBootSector->Bpb.Fat32Ebpb.uRootDirCluster - FAT_FIRST_DATA_CLUSTER) * pThis->cbCluster; 1532 1533 /* 1534 * Info sector. 1535 */ 1536 if ( pBootSector->Bpb.Fat32Ebpb.uInfoSectorNo == 0 1537 || pBootSector->Bpb.Fat32Ebpb.uInfoSectorNo == UINT16_MAX) 1538 pThis->offFat32InfoSector = UINT64_MAX; 1539 else if (pBootSector->Bpb.Fat32Ebpb.uInfoSectorNo >= pThis->cReservedSectors) 1540 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1541 "Bogus FAT32 info sector number: %#x (reserved sectors %#x)", 1542 pBootSector->Bpb.Fat32Ebpb.uInfoSectorNo, pThis->cReservedSectors); 1543 else 1544 { 1545 pThis->offFat32InfoSector = pThis->cbSector * pBootSector->Bpb.Fat32Ebpb.uInfoSectorNo + pThis->offBootSector; 1546 int rc = RTVfsFileReadAt(pThis->hVfsBacking, pThis->offFat32InfoSector, 1547 &pThis->Fat32InfoSector, sizeof(pThis->Fat32InfoSector), NULL); 1548 if (RT_FAILURE(rc)) 1549 return RTErrInfoSetF(pErrInfo, rc, "Failed to read FAT32 info sector at offset %#RX64", pThis->offFat32InfoSector); 1550 if ( pThis->Fat32InfoSector.uSignature1 != FAT32INFOSECTOR_SIGNATURE_1 1551 || pThis->Fat32InfoSector.uSignature2 != FAT32INFOSECTOR_SIGNATURE_2 1552 || pThis->Fat32InfoSector.uSignature3 != FAT32INFOSECTOR_SIGNATURE_3) 1553 return RTErrInfoSetF(pErrInfo, rc, "FAT32 info sector signature mismatch: %#x %#x %#x", 1554 pThis->Fat32InfoSector.uSignature1, pThis->Fat32InfoSector.uSignature2, 1555 pThis->Fat32InfoSector.uSignature3); 1556 } 1557 1558 /* 1559 * Boot sector copy. 1560 */ 1561 if ( pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo == 0 1562 || pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo == UINT16_MAX) 1563 { 1564 pThis->cBootSectorCopies = 0; 1565 pThis->offBootSectorCopies = UINT64_MAX; 1566 } 1567 else if (pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo >= pThis->cReservedSectors) 1568 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1569 "Bogus FAT32 info boot sector copy location: %#x (reserved sectors %#x)", 1570 pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo, pThis->cReservedSectors); 1571 else 1572 { 1573 /** @todo not sure if cbSector is correct here. */ 1574 pThis->cBootSectorCopies = 3; 1575 if ( (uint32_t)pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo + pThis->cBootSectorCopies 1576 > pThis->cReservedSectors) 1577 pThis->cBootSectorCopies = (uint8_t)(pThis->cReservedSectors - pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo); 1578 pThis->offBootSectorCopies = pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo * pThis->cbSector + pThis->offBootSector; 1579 if ( pThis->offFat32InfoSector != UINT64_MAX 1580 && pThis->offFat32InfoSector - pThis->offBootSectorCopies < (uint64_t)(pThis->cBootSectorCopies * pThis->cbSector)) 1581 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "FAT32 info sector and boot sector copies overlap: %#x vs %#x", 1582 pBootSector->Bpb.Fat32Ebpb.uInfoSectorNo, pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo); 1583 } 1584 1585 /* 1586 * Serial number, label and type. 1587 */ 1588 rtFsFatVolInitCommonEbpbBits(pThis, pBootSector->Bpb.Fat32Ebpb.bExtSignature, pBootSector->Bpb.Fat32Ebpb.uSerialNumber, 1589 pBootSector->Bpb.Fat32Ebpb.achLabel, 1590 fUsing64BitTotalSectorCount ? pBootSector->achOemName : pBootSector->Bpb.Fat32Ebpb.achLabel); 1591 if (pThis->szType[0] == '\0') 1592 memcpy(pThis->szType, "FAT32", 6); 1593 1594 return VINF_SUCCESS; 1595 } 1596 1597 1598 /** 1599 * Tries to detect a DOS 2.0+ formatted image and fills in the BPB fields. 1600 * 1601 * We ASSUME BPB here, but need to figure out which version of the BPB it is, 1602 * which is lots of fun. 1603 * 1604 * @returns IPRT status code. 1605 * @param pThis The FAT volume instance, BPB derived fields are filled 1606 * in on success. 1607 * @param pBootSector The boot sector. 1608 * @param pbFatSector Points to the FAT sector, or whatever is 512 bytes after 1609 * the boot sector. On successful return it will contain 1610 * the first FAT sector. 1611 * @param pErrInfo Where to return additional error information. 1612 */ 1613 static int rtFsFatVolTryInitDos2Plus(PRTFSFATVOL pThis, PCFATBOOTSECTOR pBootSector, uint8_t *pbFatSector, PRTERRINFO pErrInfo) 1614 { 1615 /* 1616 * Check if we've got a known jump instruction first, because that will 1617 * give us a max (E)BPB size hint. 1618 */ 1619 uint8_t offJmp = UINT8_MAX; 1620 if ( pBootSector->abJmp[0] == 0xeb 1621 && pBootSector->abJmp[1] <= 0x7f) 1622 offJmp = pBootSector->abJmp[1] + 2; 1623 else if ( pBootSector->abJmp[0] == 0x90 1624 && pBootSector->abJmp[1] == 0xeb 1625 && pBootSector->abJmp[2] <= 0x7f) 1626 offJmp = pBootSector->abJmp[2] + 3; 1627 else if ( pBootSector->abJmp[0] == 0xe9 1628 && pBootSector->abJmp[2] <= 0x7f) 1629 offJmp = RT_MIN(127, RT_MAKE_U16(pBootSector->abJmp[1], pBootSector->abJmp[2])); 1630 uint8_t const cbMaxBpb = offJmp - RT_OFFSETOF(FATBOOTSECTOR, Bpb); 1631 1632 /* 1633 * Do the basic DOS v2.0 BPB fields. 1634 */ 1635 if (cbMaxBpb < sizeof(FATBPB20)) 1636 return RTErrInfoSetF(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, 1637 "DOS signature, but jmp too short for any BPB: %#x (max %#x BPB)", offJmp, cbMaxBpb); 1638 1639 if (pBootSector->Bpb.Bpb20.cFats == 0) 1640 return RTErrInfoSet(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, "DOS signature, number of FATs is zero, so not FAT file system"); 1641 if (pBootSector->Bpb.Bpb20.cFats > 4) 1642 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "DOS signature, too many FATs: %#x", pBootSector->Bpb.Bpb20.cFats); 1643 pThis->cFats = pBootSector->Bpb.Bpb20.cFats; 1644 1645 if (!FATBPB_MEDIA_IS_VALID(pBootSector->Bpb.Bpb20.bMedia)) 1646 return RTErrInfoSetF(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, 1647 "DOS signature, invalid media byte: %#x", pBootSector->Bpb.Bpb20.bMedia); 1648 pThis->bMedia = pBootSector->Bpb.Bpb20.bMedia; 1649 1650 if (!RT_IS_POWER_OF_TWO(pBootSector->Bpb.Bpb20.cbSector)) 1651 return RTErrInfoSetF(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, 1652 "DOS signature, sector size not power of two: %#x", pBootSector->Bpb.Bpb20.cbSector); 1653 if ( pBootSector->Bpb.Bpb20.cbSector != 512 1654 && pBootSector->Bpb.Bpb20.cbSector != 4096 1655 && pBootSector->Bpb.Bpb20.cbSector != 1024 1656 && pBootSector->Bpb.Bpb20.cbSector != 128) 1657 return RTErrInfoSetF(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, 1658 "DOS signature, unsupported sector size: %#x", pBootSector->Bpb.Bpb20.cbSector); 1659 pThis->cbSector = pBootSector->Bpb.Bpb20.cbSector; 1660 1661 if ( !RT_IS_POWER_OF_TWO(pBootSector->Bpb.Bpb20.cSectorsPerCluster) 1662 || !pBootSector->Bpb.Bpb20.cSectorsPerCluster) 1663 return RTErrInfoSetF(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, "DOS signature, cluster size not non-zero power of two: %#x", 1664 pBootSector->Bpb.Bpb20.cSectorsPerCluster); 1665 pThis->cbCluster = pBootSector->Bpb.Bpb20.cSectorsPerCluster * pThis->cbSector; 1666 1667 uint64_t const cMaxRoot = (pThis->cbBacking - pThis->offBootSector - 512) / sizeof(FATDIRENTRY); /* we'll check again later. */ 1668 if (pBootSector->Bpb.Bpb20.cMaxRootDirEntries >= cMaxRoot) 1669 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "DOS signature, too many root entries: %#x (max %#RX64)", 1670 pBootSector->Bpb.Bpb20.cSectorsPerCluster, cMaxRoot); 1671 pThis->cRootDirEntries = pBootSector->Bpb.Bpb20.cMaxRootDirEntries; 1672 1673 if ( pBootSector->Bpb.Bpb20.cReservedSectors == 0 1674 || pBootSector->Bpb.Bpb20.cReservedSectors >= _32K) 1675 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1676 "DOS signature, bogus reserved sector count: %#x", pBootSector->Bpb.Bpb20.cReservedSectors); 1677 pThis->cReservedSectors = pBootSector->Bpb.Bpb20.cReservedSectors; 1678 pThis->aoffFats[0] = pThis->offBootSector + pThis->cReservedSectors * pThis->cbSector; 1679 1680 /* 1681 * Jump ahead and check for FAT32 EBPB. 1682 * If found, we simply ASSUME it's a FAT32 file system. 1683 */ 1684 int rc; 1685 if ( ( sizeof(FAT32EBPB) <= cbMaxBpb 1686 && pBootSector->Bpb.Fat32Ebpb.bExtSignature == FATEBPB_SIGNATURE) 1687 || ( RT_OFFSETOF(FAT32EBPB, achLabel) <= cbMaxBpb 1688 && pBootSector->Bpb.Fat32Ebpb.bExtSignature == FATEBPB_SIGNATURE_OLD) ) 1689 { 1690 rc = rtFsFatVolTryInitDos2PlusFat32(pThis, pBootSector, pErrInfo); 1691 if (RT_FAILURE(rc)) 1692 return rc; 1693 } 1694 else 1695 { 1696 /* 1697 * Check for extended BPB, otherwise we'll have to make qualified guesses 1698 * about what kind of BPB we're up against based on jmp offset and zero fields. 1699 * ASSUMES either FAT16 or FAT12. 1700 */ 1701 if ( ( sizeof(FATEBPB) <= cbMaxBpb 1702 && pBootSector->Bpb.Ebpb.bExtSignature == FATEBPB_SIGNATURE) 1703 || ( RT_OFFSETOF(FATEBPB, achLabel) <= cbMaxBpb 1704 && pBootSector->Bpb.Ebpb.bExtSignature == FATEBPB_SIGNATURE_OLD) ) 1705 { 1706 rtFsFatVolInitCommonEbpbBits(pThis, pBootSector->Bpb.Ebpb.bExtSignature, pBootSector->Bpb.Ebpb.uSerialNumber, 1707 pBootSector->Bpb.Ebpb.achLabel, pBootSector->Bpb.Ebpb.achType); 1708 rc = rtFsFatVolTryInitDos2PlusBpb(pThis, pBootSector, true /*fMaybe331*/, pErrInfo); 1709 } 1710 else 1711 rc = rtFsFatVolTryInitDos2PlusBpb(pThis, pBootSector, cbMaxBpb >= sizeof(FATBPB331), pErrInfo); 1712 if (RT_FAILURE(rc)) 1713 return rc; 1714 if (pThis->szType[0] == '\0') 1715 memcpy(pThis->szType, pThis->enmFatType == RTFSFATTYPE_FAT12 ? "FAT12" : "FAT16", 6); 1716 } 1717 1718 /* 1719 * Check the FAT ID. May have to read a bit of the FAT into the buffer. 1720 */ 1721 if (pThis->aoffFats[0] != pThis->offBootSector + 512) 1722 { 1723 rc = RTVfsFileReadAt(pThis->hVfsBacking, pThis->aoffFats[0], pbFatSector, 512, NULL); 1724 if (RT_FAILURE(rc)) 1725 return RTErrInfoSet(pErrInfo, rc, "error reading first FAT sector"); 1726 } 1727 if (pbFatSector[0] != pThis->bMedia) 1728 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, 1729 "Media byte and FAT ID mismatch: %#x vs %#x (%.7Rhxs)", pbFatSector[0], pThis->bMedia, pbFatSector); 1730 switch (pThis->enmFatType) 1731 { 1732 case RTFSFATTYPE_FAT12: 1733 if ((pbFatSector[1] & 0xf) != 0xf) 1734 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Bogus FAT ID patting (FAT12): %.3Rhxs", pbFatSector); 1735 pThis->idxMaxLastCluster = FAT_LAST_FAT12_DATA_CLUSTER; 1736 pThis->idxEndOfChain = (pbFatSector[1] >> 4) | ((uint32_t)pbFatSector[2] << 4); 1737 break; 1738 1739 case RTFSFATTYPE_FAT16: 1740 if (pbFatSector[1] != 0xff) 1741 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Bogus FAT ID patting (FAT16): %.4Rhxs", pbFatSector); 1742 pThis->idxMaxLastCluster = FAT_LAST_FAT16_DATA_CLUSTER; 1743 pThis->idxEndOfChain = RT_MAKE_U16(pbFatSector[2], pbFatSector[3]); 1744 break; 1745 1746 case RTFSFATTYPE_FAT32: 1747 if ( pbFatSector[1] != 0xff 1748 || pbFatSector[2] != 0xff 1749 || (pbFatSector[3] & 0x0f) != 0x0f) 1750 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Bogus FAT ID patting (FAT32): %.8Rhxs", pbFatSector); 1751 pThis->idxMaxLastCluster = FAT_LAST_FAT32_DATA_CLUSTER; 1752 pThis->idxEndOfChain = RT_MAKE_U32_FROM_U8(pbFatSector[4], pbFatSector[5], pbFatSector[6], pbFatSector[7]); 1753 break; 1754 1755 default: AssertFailedReturn(VERR_INTERNAL_ERROR_2); 1756 } 1757 if (pThis->idxEndOfChain <= pThis->idxMaxLastCluster) 1758 return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Bogus formatter end-of-chain value: %#x, must be above %#x", 1759 pThis->idxEndOfChain, pThis->idxMaxLastCluster); 1760 1761 RT_NOREF(pbFatSector); 1762 return VINF_SUCCESS; 1763 } 1764 1765 1766 /** 1767 * Worker for RTFsFatVolOpen. 1768 * 1769 * @returns IPRT status code. 1770 * @param pThis The FAT VFS instance to initialize. 1771 * @param hVfsSelf The FAT VFS handle (no reference consumed). 1772 * @param hVfsBacking The file backing the alleged FAT file system. 1773 * Reference is consumed (via rtFsFatVol_Destroy). 1774 * @param fReadOnly Readonly or readwrite mount. 1775 * @param offBootSector The boot sector offset in bytes. 1776 * @param pErrInfo Where to return additional error info. Can be NULL. 1777 */ 1778 static int rtFsFatVolTryInit(PRTFSFATVOL pThis, RTVFS hVfsSelf, RTVFSFILE hVfsBacking, 1779 bool fReadOnly, uint64_t offBootSector, PRTERRINFO pErrInfo) 1780 { 1781 /* 1782 * First initialize the state so that rtFsFatVol_Destroy won't trip up. 1783 */ 1784 pThis->hVfsSelf = hVfsSelf; 1785 pThis->hVfsBacking = hVfsBacking; /* Caller referenced it for us, we consume it; rtFsFatVol_Destroy releases it. */ 1786 pThis->cbBacking = 0; 1787 pThis->offBootSector = offBootSector; 1788 pThis->fReadOnly = fReadOnly; 1789 pThis->cReservedSectors = 1; 1790 1791 pThis->cbSector = 512; 1792 pThis->cbCluster = 512; 1793 pThis->cClusters = 0; 1794 pThis->offFirstCluster = 0; 1795 pThis->cbTotalSize = 0; 1796 1797 pThis->enmFatType = RTFSFATTYPE_INVALID; 1798 pThis->cFatEntries = 0; 1799 pThis->cFats = 0; 1800 pThis->cbFat = 0; 1801 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aoffFats); i++) 1802 pThis->aoffFats[i] = UINT64_MAX; 1803 pThis->pFatCache = NULL; 1804 1805 pThis->offRootDir = UINT64_MAX; 1806 pThis->idxRootDirCluster = UINT32_MAX; 1807 pThis->cRootDirEntries = UINT32_MAX; 1808 pThis->cbRootDir = 0; 1809 pThis->hVfsRootDir = NIL_RTVFSDIR; 1810 pThis->pRootDir = NULL; 1811 1812 pThis->uSerialNo = 0; 1813 pThis->szLabel[0] = '\0'; 1814 pThis->szType[0] = '\0'; 1815 pThis->cBootSectorCopies = 0; 1816 pThis->fFat32Flags = 0; 1817 pThis->offBootSectorCopies = UINT64_MAX; 1818 pThis->offFat32InfoSector = UINT64_MAX; 1819 RT_ZERO(pThis->Fat32InfoSector); 1820 1821 /* 1822 * Get stuff that may fail. 1823 */ 1824 int rc = RTVfsFileGetSize(hVfsBacking, &pThis->cbBacking); 1825 if (RT_FAILURE(rc)) 1826 return rc; 1827 pThis->cbTotalSize = pThis->cbBacking - pThis->offBootSector; 1828 1829 /* 1830 * Read the boot sector and the following sector (start of the allocation 1831 * table unless it a FAT32 FS). We'll then validate the boot sector and 1832 * start of the FAT, expanding the BPB into the instance data. 1833 */ 1834 union 1835 { 1836 uint8_t ab[512*2]; 1837 uint16_t au16[512*2 / 2]; 1838 uint32_t au32[512*2 / 4]; 1839 FATBOOTSECTOR BootSector; 1840 FAT32INFOSECTOR InfoSector; 1841 } Buf; 1842 RT_ZERO(Buf); 1843 1844 rc = RTVfsFileReadAt(hVfsBacking, offBootSector, &Buf.BootSector, 512 * 2, NULL); 1845 if (RT_FAILURE(rc)) 1846 return RTErrInfoSet(pErrInfo, rc, "Unable to read bootsect"); 1847 1848 /* 1849 * Extract info from the BPB and validate the two special FAT entries. 1850 * 1851 * Check the DOS signature first. The PC-DOS 1.0 boot floppy does not have 1852 * a signature and we ASSUME this is the case for all flopies formated by it. 1853 */ 1854 if (Buf.BootSector.uSignature != FATBOOTSECTOR_SIGNATURE) 1855 { 1856 if (Buf.BootSector.uSignature != 0) 1857 return RTErrInfoSetF(pErrInfo, rc, "No DOS bootsector signature: %#06x", Buf.BootSector.uSignature); 1858 rc = rtFsFatVolTryInitDos1x(pThis, &Buf.BootSector, &Buf.ab[512], pErrInfo); 1859 } 1860 else 1861 rc = rtFsFatVolTryInitDos2Plus(pThis, &Buf.BootSector, &Buf.ab[512], pErrInfo); 1862 if (RT_FAILURE(rc)) 1863 return rc; 1864 1865 /* 1866 * Setup the FAT cache. 1867 */ 1868 rc = rtFsFatClusterMap_Create(pThis, &Buf.ab[512], pErrInfo); 1869 if (RT_FAILURE(rc)) 1870 return rc; 1871 1872 /* 1873 * Create the root directory fun. 1874 */ 1875 if (pThis->idxRootDirCluster == UINT32_MAX) 1876 rc = rtFsFatDir_New(pThis, NULL /*pParentDir*/, NULL /*pDirEntry*/, 0 /*offDirEntry*/, 1877 UINT32_MAX, pThis->offRootDir, pThis->cbRootDir, 1878 &pThis->hVfsRootDir, &pThis->pRootDir); 1879 else 1880 rc = rtFsFatDir_New(pThis, NULL /*pParentDir*/, NULL /*pDirEntry*/, 0 /*offDirEntry*/, 1881 pThis->idxRootDirCluster, UINT64_MAX, pThis->cbRootDir, 1882 &pThis->hVfsRootDir, &pThis->pRootDir); 1883 if (RT_FAILURE(rc)) 1884 return rc; 1885 1886 1887 return RTErrInfoSetF(pErrInfo, VERR_NOT_IMPLEMENTED, 1888 "cbSector=%#x cbCluster=%#x cReservedSectors=%#x\n" 1889 "cFats=%#x cbFat=%#x offFirstFat=%#RX64 offSecondFat=%#RX64\n" 1890 "cbRootDir=%#x offRootDir=%#RX64 offFirstCluster=%#RX64", 1891 pThis->cbSector, pThis->cbCluster, pThis->cReservedSectors, 1892 pThis->cFats, pThis->cbFat, pThis->aoffFats[0], pThis->aoffFats[1], 1893 pThis->cbRootDir, pThis->offRootDir, pThis->offFirstCluster); 1894 } 1895 1896 1897 RTDECL(int) RTFsFatVolOpen(RTVFSFILE hVfsFileIn, bool fReadOnly, uint64_t offBootSector, PRTVFS phVfs, PRTERRINFO pErrInfo) 1898 { 1899 /* 1900 * Quick input validation. 1901 */ 1902 AssertPtrReturn(phVfs, VERR_INVALID_POINTER); 1903 *phVfs = NIL_RTVFS; 1904 1905 uint32_t cRefs = RTVfsFileRetain(hVfsFileIn); 1906 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE); 1907 1908 /* 1909 * Create a new FAT VFS instance and try initialize it using the given input file. 1910 */ 1911 RTVFS hVfs = NIL_RTVFS; 1912 void *pvThis = NULL; 1913 int rc = RTVfsNew(&g_rtFsFatVolOps, sizeof(RTFSFATVOL), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, &pvThis); 1914 if (RT_SUCCESS(rc)) 1915 { 1916 rc = rtFsFatVolTryInit((PRTFSFATVOL)pvThis, hVfs, hVfsFileIn, fReadOnly, offBootSector, pErrInfo); 1917 if (RT_SUCCESS(rc)) 1918 *phVfs = hVfs; 1919 else 1920 RTVfsRelease(hVfs); 1921 } 1922 else 1923 RTVfsFileRelease(hVfsFileIn); 1924 return rc; 616 1925 } 617 1926 … … 676 1985 { 677 1986 RTVFS hVfs; 678 rc = RTFsFatVolOpen(hVfsFileIn, pElement->uProvider != false, &hVfs, pErrInfo);1987 rc = RTFsFatVolOpen(hVfsFileIn, pElement->uProvider != false, 0, &hVfs, pErrInfo); 679 1988 RTVfsFileRelease(hVfsFileIn); 680 1989 if (RT_SUCCESS(rc)) -
trunk/src/VBox/Runtime/common/filesystem/filesystemext.cpp
r63561 r66615 317 317 } 318 318 319 static DECLCALLBACK(void) rtFsExtDestroy(void *pvThis) 319 320 /** 321 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose} 322 */ 323 static DECLCALLBACK(int) rtFsExtVol_Close(void *pvThis) 320 324 { 321 325 PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis; … … 323 327 if (pThis->pBlkGrpDesc) 324 328 RTMemFree(pThis->pBlkGrpDesc); 325 } 329 330 return VINF_SUCCESS; 331 } 332 333 334 /** 335 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo} 336 */ 337 static DECLCALLBACK(int) rtFsExtVol_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr) 338 { 339 RT_NOREF(pvThis, pObjInfo, enmAddAttr); 340 return VERR_WRONG_TYPE; 341 } 342 326 343 327 344 static DECLCALLBACK(int) rtFsExtOpenRoot(void *pvThis, PRTVFSDIR phVfsDir) … … 376 393 } 377 394 395 378 396 DECL_HIDDEN_CONST(RTFILESYSTEMDESC) const g_rtFsExt = 379 397 { 380 /** cbFs */ 381 sizeof(RTFILESYSTEMEXT), 382 /** VfsOps */ 383 { 384 /** uVersion. */ 385 RTVFSOPS_VERSION, 386 /** fFeatures */ 387 0, 388 /** pszName */ 389 "ExtVfsOps", 390 /** pfnDestroy */ 391 rtFsExtDestroy, 392 /** pfnOpenRoot */ 393 rtFsExtOpenRoot, 394 /** pfnIsRangeInUse */ 395 rtFsExtIsRangeInUse, 396 /** uEndMarker */ 397 RTVFSOPS_VERSION 398 /* .cbFs = */ sizeof(RTFILESYSTEMEXT), 399 /* .VfsOps = */ 400 { 401 /* .Obj = */ 402 { 403 /* .uVersion = */ RTVFSOBJOPS_VERSION, 404 /* .enmType = */ RTVFSOBJTYPE_VFS, 405 /* .pszName = */ "ExtVol", 406 /* .pfnClose = */ rtFsExtVol_Close, 407 /* .pfnQueryInfo = */ rtFsExtVol_QueryInfo, 408 /* .uEndMarker = */ RTVFSOBJOPS_VERSION 409 }, 410 /* .uVersion = */ RTVFSOPS_VERSION, 411 /* .fFeatures = */ 0, 412 /* .pfnOpenRoot = */ rtFsExtOpenRoot, 413 /* .pfnIsRangeInUse = */ rtFsExtIsRangeInUse, 414 /* .uEndMarker = */ RTVFSOPS_VERSION 398 415 }, 399 /** pfnProbe */ 400 rtFsExtProbe, 401 /** pfnInit */ 402 rtFsExtInit 416 /* .pfnProbe = */ rtFsExtProbe, 417 /* .pfnInit = */ rtFsExtInit 403 418 }; 404 419 -
trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
r66601 r66615 80 80 AssertPtr((a_pSetOps)->pfnSetOwner); \ 81 81 Assert((a_pSetOps)->uEndMarker == RTVFSOBJSETOPS_VERSION); \ 82 } while (0) 83 84 /** Asserts that the VFS directory vtable is valid. */ 85 #define RTVFSDIR_ASSERT_OPS(pDirOps, a_enmType) \ 86 do { \ 87 RTVFSOBJ_ASSERT_OPS(&(pDirOps)->Obj, a_enmType); \ 88 RTVFSOBJSET_ASSERT_OPS(&(pDirOps)->ObjSet, RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet)); \ 89 Assert((pDirOps)->uVersion == RTVFSDIROPS_VERSION); \ 90 Assert(!(pDirOps)->fReserved); \ 91 AssertPtr((pDirOps)->pfnTraversalOpen); \ 92 AssertPtr((pDirOps)->pfnOpenFile); \ 93 AssertPtr((pDirOps)->pfnOpenDir); \ 94 AssertPtr((pDirOps)->pfnCreateDir); \ 95 AssertPtr((pDirOps)->pfnOpenSymlink); \ 96 AssertPtr((pDirOps)->pfnCreateSymlink); \ 97 AssertPtr((pDirOps)->pfnUnlinkEntry); \ 98 AssertPtr((pDirOps)->pfnRewindDir); \ 99 AssertPtr((pDirOps)->pfnReadDir); \ 100 Assert((pDirOps)->uEndMarker == RTVFSDIROPS_VERSION); \ 82 101 } while (0) 83 102 … … 1634 1653 AssertReturn(pVfsOps->uVersion == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH); 1635 1654 AssertReturn(pVfsOps->uEndMarker == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH); 1655 RTVFSOBJ_ASSERT_OPS(&pVfsOps->Obj, RTVFSOBJTYPE_VFS); 1636 1656 Assert(cbInstance > 0); 1637 1657 AssertPtr(ppvInstance); … … 1647 1667 return VERR_NO_MEMORY; 1648 1668 1649 int rc = rtVfsObjInitNewObject(&pThis->Base, NULL, hVfs, hLock,1669 int rc = rtVfsObjInitNewObject(&pThis->Base, &pVfsOps->Obj, hVfs, hLock, 1650 1670 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT)); 1651 1671 if (RT_FAILURE(rc)) … … 1660 1680 *phVfs = pThis; 1661 1681 *ppvInstance = pThis->Base.pvThis; 1682 1662 1683 return VINF_SUCCESS; 1663 1684 } … … 1832 1853 * 1833 1854 */ 1855 1856 1857 RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock, 1858 PRTVFSDIR phVfsDir, void **ppvInstance) 1859 { 1860 /* 1861 * Validate the input, be extra strict in strict builds. 1862 */ 1863 AssertPtr(pDirOps); 1864 AssertReturn(pDirOps->uVersion == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH); 1865 AssertReturn(pDirOps->uEndMarker == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH); 1866 Assert(!pDirOps->fReserved); 1867 RTVFSDIR_ASSERT_OPS(pDirOps, RTVFSOBJTYPE_DIR); 1868 Assert(cbInstance > 0); 1869 AssertReturn(!fFlags, VERR_INVALID_FLAGS); 1870 AssertPtr(ppvInstance); 1871 AssertPtr(phVfsDir); 1872 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE); 1873 1874 /* 1875 * Allocate the handle + instance data. 1876 */ 1877 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSDIRINTERNAL), RTVFS_INST_ALIGNMENT) 1878 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT); 1879 RTVFSDIRINTERNAL *pThis = (RTVFSDIRINTERNAL *)RTMemAllocZ(cbThis); 1880 if (!pThis) 1881 return VERR_NO_MEMORY; 1882 1883 int rc = rtVfsObjInitNewObject(&pThis->Base, &pDirOps->Obj, hVfs, hLock, 1884 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT)); 1885 if (RT_FAILURE(rc)) 1886 { 1887 RTMemFree(pThis); 1888 return rc; 1889 } 1890 1891 pThis->uMagic = RTVFSDIR_MAGIC; 1892 pThis->fReserved = 0; 1893 pThis->pOps = pDirOps; 1894 1895 *phVfsDir = pThis; 1896 *ppvInstance = pThis->Base.pvThis; 1897 return VINF_SUCCESS; 1898 } 1899 1834 1900 1835 1901 RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir) … … 2801 2867 2802 2868 2869 RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead) 2870 { 2871 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER); 2872 if (pcbRead) 2873 *pcbRead = 0; 2874 RTVFSFILEINTERNAL *pThis = hVfsFile; 2875 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 2876 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE); 2877 2878 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead); 2879 } 2880 2881 2882 RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten) 2883 { 2884 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER); 2885 if (pcbWritten) 2886 *pcbWritten = 0; 2887 RTVFSFILEINTERNAL *pThis = hVfsFile; 2888 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 2889 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE); 2890 2891 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten); 2892 } 2893 2894 2803 2895 RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile) 2804 2896 {
Note:
See TracChangeset
for help on using the changeset viewer.