VirtualBox

Changeset 69660 in vbox for trunk


Ignore:
Timestamp:
Nov 12, 2017 2:53:17 PM (7 years ago)
Author:
vboxsync
Message:

fatvfs.cpp: Implemented FAT16 and FAT32 cluster map update functions - untested!

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/fs/fatvfs.cpp

    r69659 r69660  
    311311    /** The FAT size. */
    312312    uint32_t                cbFat;
     313    /** Cluster allocation search hint. */
     314    uint32_t                idxAllocHint;
    313315    /** Pointer to the volume (for disk access). */
    314316    PRTFSFATVOL             pVol;
     
    10901092
    10911093
     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 */
     1104static 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
    10921158
    10931159/**
     
    12891355}
    12901356
     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 */
     1364DECLINLINE(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
    12911371
    12921372/** Sets a FAT12 cluster value. */
     
    13271407                                          uint32_t idxCluster, uint32_t uValue)
    13281408{
     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);
    13291413    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;
    13321425}
    13331426
     
    13381431{
    13391432    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;
    13421451}
    13431452
     
    14051514    {
    14061515        offFatPrev = idxPrevCluster * 3 / 2;
     1516        AssertReturn(offFatPrev + 1 < pFatCache->cbFat, VERR_INTERNAL_ERROR_3);
    14071517        uint32_t idxPrevValue;
    14081518        if (idxPrevCluster & 1)
     
    14561566        rtFsFatClusterMap_SetDirtyByte(pFatCache, 0, offFat + 1);
    14571567
    1458         /* Chain it on the previous cluster. */
     1568        /* Chain it onto the previous cluster. */
    14591569        if (idxPrevCluster != UINT32_MAX)
    14601570        {
     
    14871597                                               uint32_t idxPrevCluster, uint32_t *pidxCluster)
    14881598{
    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;
    14911671}
    14921672
     
    14981678                                               uint32_t idxPrevCluster, uint32_t *pidxCluster)
    14991679{
    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;
    15021779}
    15031780
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette