- Timestamp:
- Nov 12, 2017 2:53:17 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/fs/fatvfs.cpp
r69659 r69660 311 311 /** The FAT size. */ 312 312 uint32_t cbFat; 313 /** Cluster allocation search hint. */ 314 uint32_t idxAllocHint; 313 315 /** Pointer to the volume (for disk access). */ 314 316 PRTFSFATVOL pVol; … … 1090 1092 1091 1093 1094 /** 1095 * Gets a pointer to a FAT entry, extended version. 1096 * 1097 * @returns IPRT status code. On failure, we're currently kind of screwed. 1098 * @param pCache The FAT cache. 1099 * @param pThis The FAT volume instance. 1100 * @param offFat The FAT byte offset to get the entry off. 1101 * @param ppbEntry Where to return the pointer to the entry. 1102 * @param pidxEntry Where to return the entry index. 1103 */ 1104 static int rtFsFatClusterMap_GetEntryEx(PRTFSFATCLUSTERMAPCACHE pCache, PRTFSFATVOL pThis, uint32_t offFat, 1105 uint8_t **ppbEntry, uint32_t *pidxEntry) 1106 { 1107 int rc; 1108 if (offFat < pThis->cbFat) 1109 { 1110 uint32_t const iEntry = (offFat >> pCache->cEntryIndexShift) & pCache->fEntryIndexMask; 1111 uint32_t const offInEntry = offFat & pCache->fEntryOffsetMask; 1112 uint32_t const offFatEntry = offFat - offInEntry; 1113 1114 *ppbEntry = pCache->aEntries[iEntry].pbData + offInEntry; 1115 *pidxEntry = iEntry; 1116 1117 /* If it's already ready, return immediately. */ 1118 if (pCache->aEntries[iEntry].offFat == offFatEntry) 1119 { 1120 Log3(("rtFsFatClusterMap_GetEntryEx: Hit entry %u for offFat=%#RX32\n", iEntry, offFat)); 1121 return VINF_SUCCESS; 1122 } 1123 1124 /* Do we need to flush it? */ 1125 rc = VINF_SUCCESS; 1126 if ( pCache->aEntries[iEntry].bmDirty != 0 1127 && pCache->aEntries[iEntry].offFat != UINT32_MAX) 1128 { 1129 Log3(("rtFsFatClusterMap_GetEntryEx: Flushing entry %u for offFat=%#RX32\n", iEntry, offFat)); 1130 rc = rtFsFatClusterMap_FlushEntry(pThis, iEntry); 1131 } 1132 if (RT_SUCCESS(rc)) 1133 { 1134 pCache->aEntries[iEntry].bmDirty = 0; 1135 1136 /* Read in the entry from disk */ 1137 rc = RTVfsFileReadAt(pThis->hVfsBacking, pThis->aoffFats[0] + offFatEntry, pCache->aEntries[iEntry].pbData, 1138 pCache->cbEntry, NULL); 1139 if (RT_SUCCESS(rc)) 1140 { 1141 Log3(("rtFsFatClusterMap_GetEntryEx: Loaded entry %u for offFat=%#RX32\n", iEntry, offFat)); 1142 pCache->aEntries[iEntry].offFat = offFatEntry; 1143 return VINF_SUCCESS; 1144 } 1145 /** @todo We can try other FAT copies here... */ 1146 LogRel(("rtFsFatClusterMap_GetEntryEx: Error loading entry %u for offFat=%#RX32 (%#64RX32 LB %#x): %Rrc\n", 1147 iEntry, offFat, pThis->aoffFats[0] + offFatEntry, pCache->cbEntry, rc)); 1148 pCache->aEntries[iEntry].offFat = UINT32_MAX; 1149 } 1150 } 1151 else 1152 rc = VERR_OUT_OF_RANGE; 1153 *ppbEntry = NULL; 1154 *pidxEntry = UINT32_MAX; 1155 return rc; 1156 } 1157 1092 1158 1093 1159 /** … … 1289 1355 } 1290 1356 1357 /** 1358 * Sets bmDirty for entry @a iEntry. 1359 * 1360 * @param pFatCache The FAT cache. 1361 * @param iEntry The cache entry. 1362 * @param pbIntoEntry Pointer into the cache entry that was dirtied. 1363 */ 1364 DECLINLINE(void) rtFsFatClusterMap_SetDirtyByteByPtr(PRTFSFATCLUSTERMAPCACHE pFatCache, uint32_t iEntry, uint8_t *pbIntoEntry) 1365 { 1366 uintptr_t offEntry = pbIntoEntry - pFatCache->aEntries[iEntry].pbData; 1367 Assert(offEntry < pFatCache->cbEntry); 1368 rtFsFatClusterMap_SetDirtyByte(pFatCache, iEntry, (uint32_t)offEntry); 1369 } 1370 1291 1371 1292 1372 /** Sets a FAT12 cluster value. */ … … 1327 1407 uint32_t idxCluster, uint32_t uValue) 1328 1408 { 1409 /* ASSUME that for FAT16 we cache the whole FAT in a single entry. */ 1410 AssertReturn(pFatCache->cEntries == 1, VERR_INTERNAL_ERROR_4); 1411 AssertReturn(pFatCache->cbEntry == pVol->cbFat, VERR_INTERNAL_ERROR_4); 1412 AssertReturn(pFatCache->aEntries[0].offFat == 0, VERR_INTERNAL_ERROR_4); 1329 1413 AssertReturn(uValue < 0x10000, VERR_INTERNAL_ERROR_2); 1330 RT_NOREF(pFatCache, pVol, idxCluster, uValue); 1331 return VERR_NOT_IMPLEMENTED; 1414 1415 /* Make the change. */ 1416 uint8_t *pbFat = pFatCache->aEntries[0].pbData; 1417 uint32_t offFat = idxCluster * 2; 1418 pbFat[offFat] = (uint8_t)idxCluster; 1419 pbFat[offFat + 1] = (uint8_t)(idxCluster >> 8); 1420 1421 /* Update the dirty bits. */ 1422 rtFsFatClusterMap_SetDirtyByte(pFatCache, 0, offFat); 1423 1424 return VINF_SUCCESS; 1332 1425 } 1333 1426 … … 1338 1431 { 1339 1432 AssertReturn(uValue < 0x10000000, VERR_INTERNAL_ERROR_2); 1340 RT_NOREF(pFatCache, pVol, idxCluster, uValue); 1341 return VERR_NOT_IMPLEMENTED; 1433 1434 /* Get the fat cache entry. */ 1435 uint8_t *pbEntry; 1436 uint32_t idxEntry; 1437 int rc = rtFsFatClusterMap_GetEntryEx(pFatCache, pVol, idxCluster * 4, &pbEntry, &idxEntry); 1438 if (RT_SUCCESS(rc)) 1439 { 1440 /* Make the change. */ 1441 pbEntry[0] = (uint8_t)idxCluster; 1442 pbEntry[1] = (uint8_t)(idxCluster >> 8); 1443 pbEntry[2] = (uint8_t)(idxCluster >> 16); 1444 pbEntry[3] = (uint8_t)(idxCluster >> 24); 1445 1446 /* Update the dirty bits. */ 1447 rtFsFatClusterMap_SetDirtyByteByPtr(pFatCache, idxEntry, pbEntry); 1448 } 1449 1450 return rc; 1342 1451 } 1343 1452 … … 1405 1514 { 1406 1515 offFatPrev = idxPrevCluster * 3 / 2; 1516 AssertReturn(offFatPrev + 1 < pFatCache->cbFat, VERR_INTERNAL_ERROR_3); 1407 1517 uint32_t idxPrevValue; 1408 1518 if (idxPrevCluster & 1) … … 1456 1566 rtFsFatClusterMap_SetDirtyByte(pFatCache, 0, offFat + 1); 1457 1567 1458 /* Chain it on the previous cluster. */1568 /* Chain it onto the previous cluster. */ 1459 1569 if (idxPrevCluster != UINT32_MAX) 1460 1570 { … … 1487 1597 uint32_t idxPrevCluster, uint32_t *pidxCluster) 1488 1598 { 1489 RT_NOREF(pFatCache, pVol, idxPrevCluster, pidxCluster); 1490 return VERR_NOT_IMPLEMENTED; 1599 /* ASSUME that for FAT16 we cache the whole FAT in a single entry. */ 1600 AssertReturn(pFatCache->cEntries == 1, VERR_INTERNAL_ERROR_4); 1601 AssertReturn(pFatCache->cbEntry == pVol->cbFat, VERR_INTERNAL_ERROR_4); 1602 AssertReturn(pFatCache->aEntries[0].offFat == 0, VERR_INTERNAL_ERROR_4); 1603 1604 /* 1605 * Check that the previous cluster is a valid chain end. 1606 */ 1607 uint8_t *pbFat = pFatCache->aEntries[0].pbData; 1608 uint32_t offFatPrev; 1609 if (idxPrevCluster != UINT32_MAX) 1610 { 1611 offFatPrev = idxPrevCluster * 2; 1612 AssertReturn(offFatPrev + 1 < pFatCache->cbFat, VERR_INTERNAL_ERROR_3); 1613 uint32_t idxPrevValue = RT_MAKE_U16(pbFat[offFatPrev], pbFat[offFatPrev + 1]); 1614 AssertReturn(idxPrevValue >= FAT_FIRST_FAT16_EOC, VERR_VFS_BOGUS_OFFSET); 1615 } 1616 else 1617 offFatPrev = UINT32_MAX; 1618 1619 /* 1620 * We start searching at idxAllocHint and continues to the end. The next 1621 * iteration starts searching from the start and up to idxAllocHint. 1622 */ 1623 uint32_t idxCluster = RT_MIN(pFatCache->idxAllocHint, FAT_FIRST_DATA_CLUSTER); 1624 uint32_t offFat = idxCluster * 2; 1625 uint32_t cClusters = pVol->cClusters; 1626 for (uint32_t i = 0; i < 2; i++) 1627 { 1628 while (idxCluster < pVol->cClusters) 1629 { 1630 if ( pbFat[offFat + 0] != 0x00 1631 || pbFat[offFat + 1] != 0x00) 1632 { 1633 /* In use - advance to the next one. */ 1634 offFat += 2; 1635 idxCluster++; 1636 } 1637 else 1638 { 1639 /* 1640 * Found one. Grab it. 1641 */ 1642 /* Set EOC. */ 1643 pbFat[offFat + 0] = 0xff; 1644 pbFat[offFat + 1] = 0xff; 1645 rtFsFatClusterMap_SetDirtyByte(pFatCache, 0, offFat); 1646 1647 /* Chain it onto the previous cluster (if any). */ 1648 if (idxPrevCluster != UINT32_MAX) 1649 { 1650 pbFat[offFatPrev + 0] = (uint8_t)idxCluster; 1651 pbFat[offFatPrev + 1] = (uint8_t)(idxCluster >> 8); 1652 rtFsFatClusterMap_SetDirtyByte(pFatCache, 0, offFatPrev); 1653 } 1654 1655 /* Update the allocation hint. */ 1656 pFatCache->idxAllocHint = idxCluster + 1; 1657 1658 /* Done. */ 1659 *pidxCluster = idxCluster; 1660 return VINF_SUCCESS; 1661 } 1662 } 1663 1664 /* Wrap around to the start of the map. */ 1665 cClusters = RT_MIN(pFatCache->idxAllocHint, pVol->cClusters); 1666 idxCluster = FAT_FIRST_DATA_CLUSTER; 1667 offFat = 4; 1668 } 1669 1670 return VERR_DISK_FULL; 1491 1671 } 1492 1672 … … 1498 1678 uint32_t idxPrevCluster, uint32_t *pidxCluster) 1499 1679 { 1500 RT_NOREF(pFatCache, pVol, idxPrevCluster, pidxCluster); 1501 return VERR_NOT_IMPLEMENTED; 1680 /* 1681 * Check that the previous cluster is a valid chain end. 1682 */ 1683 int rc; 1684 uint8_t *pbEntry; 1685 if (idxPrevCluster != UINT32_MAX) 1686 { 1687 rc = rtFsFatClusterMap_GetEntry(pFatCache, pVol, idxPrevCluster * 4, &pbEntry); 1688 if (RT_SUCCESS(rc)) 1689 { 1690 uint32_t idxPrevValue = RT_MAKE_U32_FROM_U8(pbEntry[0], pbEntry[1], pbEntry[2], pbEntry[3]); 1691 AssertReturn(idxPrevValue >= FAT_FIRST_FAT32_EOC, VERR_VFS_BOGUS_OFFSET); 1692 } 1693 else 1694 return rc; 1695 } 1696 1697 /* 1698 * We start searching at idxAllocHint and continues to the end. The next 1699 * iteration starts searching from the start and up to idxAllocHint. 1700 */ 1701 uint32_t idxCluster = RT_MIN(pFatCache->idxAllocHint, FAT_FIRST_DATA_CLUSTER); 1702 uint32_t offFat = idxCluster * 4; 1703 uint32_t cClusters = pVol->cClusters; 1704 for (uint32_t i = 0; i < 2; i++) 1705 { 1706 while (idxCluster < pVol->cClusters) 1707 { 1708 /* Note! This could be done in cache entry chunks. */ 1709 uint32_t idxEntry; 1710 rc = rtFsFatClusterMap_GetEntryEx(pFatCache, pVol, offFat, &pbEntry, &idxEntry); 1711 if (RT_SUCCESS(rc)) 1712 { 1713 if ( pbEntry[0] != 0x00 1714 || pbEntry[1] != 0x00 1715 || pbEntry[2] != 0x00 1716 || pbEntry[3] != 0x00) 1717 { 1718 /* In use - advance to the next one. */ 1719 offFat += 4; 1720 idxCluster++; 1721 } 1722 else 1723 { 1724 /* 1725 * Found one. Grab it. 1726 */ 1727 /* Set EOC. */ 1728 pbEntry[0] = 0xff; 1729 pbEntry[1] = 0xff; 1730 pbEntry[2] = 0xff; 1731 pbEntry[3] = 0x0f; 1732 rtFsFatClusterMap_SetDirtyByteByPtr(pFatCache, idxEntry, pbEntry); 1733 1734 /* Chain it on the previous cluster (if any). */ 1735 if (idxPrevCluster != UINT32_MAX) 1736 { 1737 rc = rtFsFatClusterMap_GetEntryEx(pFatCache, pVol, idxPrevCluster * 4, &pbEntry, &idxEntry); 1738 if (RT_SUCCESS(rc)) 1739 { 1740 pbEntry[0] = (uint8_t)idxCluster; 1741 pbEntry[1] = (uint8_t)(idxCluster >> 8); 1742 pbEntry[2] = (uint8_t)(idxCluster >> 16); 1743 pbEntry[3] = (uint8_t)(idxCluster >> 24); 1744 rtFsFatClusterMap_SetDirtyByteByPtr(pFatCache, idxEntry, pbEntry); 1745 } 1746 else 1747 { 1748 /* Try free the cluster. */ 1749 int rc2 = rtFsFatClusterMap_GetEntryEx(pFatCache, pVol, offFat, &pbEntry, &idxEntry); 1750 if (RT_SUCCESS(rc2)) 1751 { 1752 pbEntry[0] = 0; 1753 pbEntry[1] = 0; 1754 pbEntry[2] = 0; 1755 pbEntry[3] = 0; 1756 rtFsFatClusterMap_SetDirtyByteByPtr(pFatCache, idxEntry, pbEntry); 1757 } 1758 return rc; 1759 } 1760 } 1761 1762 /* Update the allocation hint. */ 1763 pFatCache->idxAllocHint = idxCluster + 1; 1764 1765 /* Done. */ 1766 *pidxCluster = idxCluster; 1767 return VINF_SUCCESS; 1768 } 1769 } 1770 } 1771 1772 /* Wrap around to the start of the map. */ 1773 cClusters = RT_MIN(pFatCache->idxAllocHint, pVol->cClusters); 1774 idxCluster = FAT_FIRST_DATA_CLUSTER; 1775 offFat = 4; 1776 } 1777 1778 return VERR_DISK_FULL; 1502 1779 } 1503 1780
Note:
See TracChangeset
for help on using the changeset viewer.