VirtualBox

Changeset 66671 in vbox for trunk


Ignore:
Timestamp:
Apr 25, 2017 11:58:04 AM (7 years ago)
Author:
vboxsync
Message:

fatvfs: Updates.

File:
1 edited

Legend:

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

    r66670 r66671  
    415415*   Internal Functions                                                                                                           *
    416416*********************************************************************************************************************************/
     417static int rtFsFatFile_FlushMetaData(PRTFSFATFILE pThis);
    417418static void rtFsFatDir_AddOpenChild(PRTFSFATDIR pDir, PRTFSFATOBJ pChild);
    418419static void rtFsFatDir_RemoveOpenChild(PRTFSFATDIR pDir, PRTFSFATOBJ pChild);
     420static int  rtFsFatDir_GetEntryForUpdate(PRTFSFATDIR pThis, uint32_t offEntryInDir, PFATDIRENTRY *ppDirEntry, uint32_t *puWriteLock);
     421static int  rtFsFatDir_PutEntryAfterUpdate(PRTFSFATDIR pThis, PFATDIRENTRY pDirEntry, uint32_t uWriteLock);
    419422static int  rtFsFatDir_Flush(PRTFSFATDIR pThis);
    420423static int  rtFsFatDir_New(PRTFSFATVOL pThis, PRTFSFATDIR pParentDir, PCFATDIRENTRY pDirEntry, uint32_t offEntryInDir,
     
    808811    AssertReturn(pFatCache->aEntries[0].offFat == 0, VERR_INTERNAL_ERROR_4);
    809812
     813    /* Special case for empty files. */
     814    if (idxCluster == 0)
     815        return VINF_SUCCESS;
     816
     817    /* Work cluster by cluster. */
    810818    uint8_t const *pbFat = pFatCache->aEntries[0].pbData;
    811819    for (;;)
     
    882890        default:
    883891            AssertFailedReturn(VERR_INTERNAL_ERROR_2);
     892    }
     893}
     894
     895
     896/** Sets a FAT12 cluster value. */
     897static int rtFsFatClusterMap_SetCluster12(PRTFSFATCLUSTERMAPCACHE pFatCache, PRTFSFATVOL pVol,
     898                                          uint32_t idxCluster, uint32_t uValue)
     899{
     900    /* ASSUME that for FAT12 we cache the whole FAT in a single entry.  That
     901       way we don't need to deal with entries in different sectors and whatnot.  */
     902    AssertReturn(pFatCache->cEntries == 1, VERR_INTERNAL_ERROR_4);
     903    AssertReturn(pFatCache->cbEntry == pVol->cbFat, VERR_INTERNAL_ERROR_4);
     904    AssertReturn(pFatCache->aEntries[0].offFat == 0, VERR_INTERNAL_ERROR_4);
     905    AssertReturn(uValue < 0x1000, VERR_INTERNAL_ERROR_2);
     906
     907    /* Make the change. */
     908    uint8_t *pbFat  = pFatCache->aEntries[0].pbData;
     909    uint32_t offFat = idxCluster * 3 / 2;
     910    if (idxCluster & 1)
     911    {
     912        pbFat[offFat]     = (0x0f | pbFat[offFat]) | ((uValue & 0xf) << 4);
     913        pbFat[offFat + 1] = (uint8_t)(uValue >> 4);
     914    }
     915    else
     916    {
     917        pbFat[offFat]     = (uint8_t)uValue;
     918        pbFat[offFat + 1] = (0xf0 | pbFat[offFat + 1]) | ((uValue >> 8) | 0xf);
     919    }
     920
     921    /* Update the dirty bits. */
     922    pFatCache->aEntries[0].bmDirty |= RT_BIT_64(offFat >> pFatCache->cDirtyShift);
     923    pFatCache->aEntries[0].bmDirty |= RT_BIT_64((offFat + 1) >> pFatCache->cDirtyShift);
     924
     925    return VINF_SUCCESS;
     926}
     927
     928
     929/** Sets a FAT16 cluster value. */
     930static int rtFsFatClusterMap_SetCluster16(PRTFSFATCLUSTERMAPCACHE pFatCache, PRTFSFATVOL pVol,
     931                                          uint32_t idxCluster, uint32_t uValue)
     932{
     933    AssertReturn(uValue < 0x10000, VERR_INTERNAL_ERROR_2);
     934    RT_NOREF(pFatCache, pVol, idxCluster, uValue);
     935    return VERR_NOT_IMPLEMENTED;
     936}
     937
     938
     939/** Sets a FAT32 cluster value. */
     940static int rtFsFatClusterMap_SetCluster32(PRTFSFATCLUSTERMAPCACHE pFatCache, PRTFSFATVOL pVol,
     941                                          uint32_t idxCluster, uint32_t uValue)
     942{
     943    AssertReturn(uValue < 0x10000000, VERR_INTERNAL_ERROR_2);
     944    RT_NOREF(pFatCache, pVol, idxCluster, uValue);
     945    return VERR_NOT_IMPLEMENTED;
     946}
     947
     948
     949/**
     950 * Marks the cluster @a idxCluster as the end of the cluster chain.
     951 *
     952 * @returns IPRT status code
     953 * @param   pThis           The FAT volume instance.
     954 * @param   idxCluster      The cluster to end the chain with.
     955 */
     956static int rtFsFatClusterMap_SetEndOfChain(PRTFSFATVOL pThis, uint32_t idxCluster)
     957{
     958    AssertReturn(idxCluster >= FAT_FIRST_DATA_CLUSTER, VERR_VFS_BOGUS_OFFSET);
     959    AssertReturn(idxCluster < pThis->cClusters, VERR_VFS_BOGUS_OFFSET);
     960    switch (pThis->enmFatType)
     961    {
     962        case RTFSFATTYPE_FAT12: return rtFsFatClusterMap_SetCluster12(pThis->pFatCache, pThis, idxCluster, FAT_FIRST_FAT12_EOC);
     963        case RTFSFATTYPE_FAT16: return rtFsFatClusterMap_SetCluster16(pThis->pFatCache, pThis, idxCluster, FAT_FIRST_FAT16_EOC);
     964        case RTFSFATTYPE_FAT32: return rtFsFatClusterMap_SetCluster32(pThis->pFatCache, pThis, idxCluster, FAT_FIRST_FAT32_EOC);
     965        default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
     966    }
     967}
     968
     969
     970/**
     971 * Marks the cluster @a idxCluster as free.
     972 * @returns IPRT status code
     973 * @param   pThis           The FAT volume instance.
     974 * @param   idxCluster      The cluster to free.
     975 */
     976static int rtFsFatClusterMap_FreeCluster(PRTFSFATVOL pThis, uint32_t idxCluster)
     977{
     978    AssertReturn(idxCluster >= FAT_FIRST_DATA_CLUSTER, VERR_VFS_BOGUS_OFFSET);
     979    AssertReturn(idxCluster < pThis->cClusters, VERR_VFS_BOGUS_OFFSET);
     980    switch (pThis->enmFatType)
     981    {
     982        case RTFSFATTYPE_FAT12: return rtFsFatClusterMap_SetCluster12(pThis->pFatCache, pThis, idxCluster, 0);
     983        case RTFSFATTYPE_FAT16: return rtFsFatClusterMap_SetCluster16(pThis->pFatCache, pThis, idxCluster, 0);
     984        case RTFSFATTYPE_FAT32: return rtFsFatClusterMap_SetCluster32(pThis->pFatCache, pThis, idxCluster, 0);
     985        default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
    884986    }
    885987}
     
    9951097{
    9961098    PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
    997     return rtFsFatObj_Close(&pThis->Core);
     1099    int rc1 = rtFsFatFile_FlushMetaData(pThis);
     1100    int rc2 = rtFsFatObj_Close(&pThis->Core);
     1101    return RT_FAILURE(rc1) ? rc1 : rc2;
    9981102}
    9991103
     
    10711175
    10721176    /*
    1073      * Do the reading cluster by cluster (converge clusters later).
     1177     * Do the reading cluster by cluster.
    10741178     */
    10751179    int      rc         = VINF_SUCCESS;
     
    11081212        break;
    11091213    }
     1214
     1215    /* Update the offset and return. */
    11101216    pThis->offFile = off;
    11111217    if (pcbRead)
     
    11161222
    11171223/**
     1224 * Changes the size of a file or directory FAT object.
     1225 *
     1226 * @returns IPRT status code
     1227 * @param   pObj        The common object.
     1228 * @param   cbFile      The new file size.
     1229 */
     1230static int rtFsFatObj_SetSize(PRTFSFATOBJ pObj, uint32_t cbFile)
     1231{
     1232    AssertReturn((pObj->cbObject >> pObj->Clusters.cClusterByteShift) == pObj->Clusters.cClusters, VERR_INTERNAL_ERROR_3);
     1233
     1234    /*
     1235     * Do nothing if the size didn't change.
     1236     */
     1237    if (pObj->cbObject == cbFile)
     1238        return VINF_SUCCESS;
     1239
     1240    /*
     1241     * We need to at least update the directory entry, but quite likely allocate
     1242     * or release clusters.
     1243     */
     1244    int rc;
     1245    uint32_t const cClustersNew = (cbFile + pObj->Clusters.cbCluster - 1) >> pObj->Clusters.cClusterByteShift;
     1246    AssertReturn(pObj->pParentDir, VERR_INTERNAL_ERROR_2);
     1247    if (pObj->Clusters.cClusters == cClustersNew)
     1248    {
     1249        pObj->cbObject = cbFile;
     1250        rc = VINF_SUCCESS;
     1251    }
     1252    else if (pObj->cbObject < cbFile)
     1253    {
     1254        AssertFailed();
     1255    }
     1256    else
     1257    {
     1258        /* Free clusters we don't need any more. */
     1259        rc = rtFsFatClusterMap_SetEndOfChain(pObj->pVol, rtFsFatChain_GetCluster(&pObj->Clusters, cClustersNew - 1));
     1260        if (RT_SUCCESS(rc))
     1261        {
     1262            uint32_t iClusterToFree = cClustersNew;
     1263            while (iClusterToFree < pObj->Clusters.cClusters && RT_SUCCESS(rc))
     1264            {
     1265                rc = rtFsFatClusterMap_FreeCluster(pObj->pVol, rtFsFatChain_GetCluster(&pObj->Clusters, iClusterToFree));
     1266                iClusterToFree++;
     1267            }
     1268
     1269            /* Update the chain structure. */
     1270            pObj->Clusters.cClusters = cClustersNew;
     1271        }
     1272    }
     1273    if (RT_SUCCESS(rc))
     1274    {
     1275        /*
     1276         * Update the directory entry.
     1277         */
     1278        uint32_t     uWriteLock;
     1279        PFATDIRENTRY pDirEntry;
     1280        rc = rtFsFatDir_GetEntryForUpdate(pObj->pParentDir, pObj->offEntryInDir, &pDirEntry, &uWriteLock);
     1281        if (RT_SUCCESS(rc))
     1282        {
     1283            pDirEntry->cbFile = cbFile;
     1284            rc = rtFsFatDir_PutEntryAfterUpdate(pObj->pParentDir, pDirEntry, uWriteLock);
     1285        }
     1286    }
     1287    return rc;
     1288}
     1289
     1290
     1291/**
    11181292 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
    11191293 */
     
    11211295{
    11221296    PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
    1123     RT_NOREF(pThis, off, pSgBuf, fBlocking, pcbWritten);
    1124     return VERR_NOT_IMPLEMENTED;
    1125 }
    1126 
    1127 
    1128 /**
    1129  * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
    1130  */
    1131 static DECLCALLBACK(int) rtFsFatFile_Flush(void *pvThis)
    1132 {
    1133     PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
     1297    AssertReturn(pSgBuf->cSegs != 0, VERR_INTERNAL_ERROR_3);
     1298    RT_NOREF(fBlocking);
     1299
     1300    if (off == -1)
     1301        off = pThis->offFile;
     1302
     1303    /*
     1304     * Do the reading cluster by cluster.
     1305     */
     1306    int            rc         = VINF_SUCCESS;
     1307    uint32_t       cbWritten  = 0;
     1308    uint32_t       cbLeft     = pSgBuf->paSegs[0].cbSeg;
     1309    uint8_t const *pbSrc      = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
     1310    while (cbLeft > 0)
     1311    {
     1312        /* Figure out how much we can write.  Checking for max file size and such. */
     1313        uint32_t cbToWrite = pThis->Core.Clusters.cbCluster - ((uint32_t)off & (pThis->Core.Clusters.cbCluster - 1));
     1314        if (cbToWrite > cbLeft)
     1315            cbToWrite = cbLeft;
     1316        uint64_t offNew = (uint64_t)off + cbToWrite;
     1317        if (offNew < _4G)
     1318        { /*likely*/ }
     1319        else if ((uint64_t)off < _4G - 1U)
     1320            cbToWrite = _4G - 1U - off;
     1321        else
     1322        {
     1323            rc = VERR_FILE_TOO_BIG;
     1324            break;
     1325        }
     1326
     1327        /* Grow the file? */
     1328        if ((uint32_t)offNew > pThis->Core.cbObject)
     1329        {
     1330            rc = rtFsFatObj_SetSize(&pThis->Core, (uint32_t)offNew);
     1331            if (RT_SUCCESS(rc))
     1332            { /* likely */}
     1333            else
     1334                break;
     1335        }
     1336
     1337        /* Figure the disk offset. */
     1338        uint64_t offDisk = rtFsFatChain_FileOffsetToDiskOff(&pThis->Core.Clusters, (uint32_t)off, pThis->Core.pVol);
     1339        if (offDisk != UINT64_MAX)
     1340        {
     1341            rc = RTVfsFileWriteAt(pThis->Core.pVol->hVfsBacking, offDisk, pbSrc, cbToWrite, NULL);
     1342            if (RT_SUCCESS(rc))
     1343            {
     1344                off         += cbToWrite;
     1345                pbSrc       += cbToWrite;
     1346                cbWritten   += cbToWrite;
     1347                cbLeft      -= cbToWrite;
     1348            }
     1349            else
     1350                break;
     1351        }
     1352        else
     1353        {
     1354            rc = VERR_VFS_BOGUS_OFFSET;
     1355            break;
     1356        }
     1357    }
     1358
     1359    /* Update the offset and return. */
     1360    pThis->offFile = off;
     1361    if (pcbWritten)
     1362        *pcbWritten = cbWritten;
     1363    return VINF_SUCCESS;
     1364}
     1365
     1366
     1367/**
     1368 * Flushes file meta data.
     1369 *
     1370 * @returns IPRT status code
     1371 * @param   pThis           The file.
     1372 */
     1373static int rtFsFatFile_FlushMetaData(PRTFSFATFILE pThis)
     1374{
    11341375    int rc = VINF_SUCCESS;
    11351376    if (pThis->fMaybeDirtyFat)
     
    11411382            rc = rc2;
    11421383    }
    1143 
     1384    return rc;
     1385}
     1386
     1387/**
     1388 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
     1389 */
     1390static DECLCALLBACK(int) rtFsFatFile_Flush(void *pvThis)
     1391{
     1392    PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
     1393    int rc1 = rtFsFatFile_FlushMetaData(pThis);
    11441394    int rc2 = RTVfsFileFlush(pThis->Core.pVol->hVfsBacking);
    1145     if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    1146         rc = rc2;
    1147     return rc;
     1395    return RT_FAILURE(rc1) ? rc1 : rc2;
    11481396}
    11491397
     
    13581606             */
    13591607            rtFsFatDir_AddOpenChild(pParentDir, &pNewFile->Core);
    1360             return VINF_SUCCESS;
     1608
     1609            /*
     1610             * Should we truncate the file or anything of that sort?
     1611             */
     1612            if (   (fOpen & RTFILE_O_TRUNCATE)
     1613                || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
     1614                rc = rtFsFatObj_SetSize(&pNewFile->Core, 0);
     1615            if (RT_SUCCESS(rc))
     1616                return VINF_SUCCESS;
    13611617        }
    13621618
     
    13701626
    13711627
     1628/**
     1629 * Flush directory changes when having a fully buffered directory.
     1630 *
     1631 * @returns IPRT status code
     1632 * @param   pThis           The directory.
     1633 */
    13721634static int rtFsFatDir_FlushFullyBuffered(PRTFSFATDIR pThis)
    13731635{
    13741636    Assert(pThis->fFullyBuffered);
    1375     return VINF_SUCCESS;
    1376 }
    1377 
    1378 
     1637    uint32_t const  cbSector    = pThis->Core.pVol->cbSector;
     1638    RTVFSFILE const hVfsBacking = pThis->Core.pVol->hVfsBacking;
     1639    int             rc          = VINF_SUCCESS;
     1640    for (uint32_t i = 0; i < pThis->u.Full.cSectors; i++)
     1641        if (pThis->u.Full.pbDirtySectors[i])
     1642        {
     1643            int rc2 = RTVfsFileWriteAt(hVfsBacking, pThis->offEntriesOnDisk + i * cbSector,
     1644                                       (uint8_t *)pThis->paEntries + i * cbSector, cbSector, NULL);
     1645            if (RT_SUCCESS(rc2))
     1646                pThis->u.Full.pbDirtySectors[i] = false;
     1647            else if (RT_SUCCESS(rc))
     1648                rc = rc2;
     1649        }
     1650    return rc;
     1651}
     1652
     1653
     1654/**
     1655 * Flush directory changes when using simple buffering.
     1656 *
     1657 * @returns IPRT status code
     1658 * @param   pThis           The directory.
     1659 */
    13791660static int rtFsFatDir_FlushSimple(PRTFSFATDIR pThis)
    13801661{
     
    13961677
    13971678
     1679/**
     1680 * Flush directory changes.
     1681 *
     1682 * @returns IPRT status code
     1683 * @param   pThis           The directory.
     1684 */
    13981685static int rtFsFatDir_Flush(PRTFSFATDIR pThis)
    13991686{
     
    14041691
    14051692
    1406 static void rtFsFatDir_ReleaseBufferAfterReading(PRTFSFATDIR pThis, uint32_t uBufferReadLock)
    1407 {
    1408     RT_NOREF(pThis, uBufferReadLock);
    1409 }
    1410 
    1411 
    14121693/**
    14131694 * Gets one or more entires at @a offEntryInDir.
     1695 *
     1696 * Common worker for rtFsFatDir_GetEntriesAt and rtFsFatDir_GetEntryForUpdate
    14141697 *
    14151698 * @returns IPRT status code.
    14161699 * @param   pThis               The directory.
    14171700 * @param   offEntryInDir       The directory offset in bytes.
     1701 * @param   fForUpdate          Whether it's for updating.
    14181702 * @param   ppaEntries          Where to return pointer to the entry at
    14191703 *                              @a offEntryInDir.
     
    14241708 *                              done.
    14251709 */
    1426 static int rtFsFatDir_GetEntriesAt(PRTFSFATDIR pThis, uint32_t offEntryInDir,
    1427                                    PCFATDIRENTRYUNION *ppaEntries, uint32_t *pcEntries, uint32_t *puBufferReadLock)
    1428 {
    1429     *puBufferReadLock = UINT32_MAX;
     1710static int rtFsFatDir_GetEntriesAtCommon(PRTFSFATDIR pThis, uint32_t offEntryInDir, bool fForUpdate,
     1711                                         PFATDIRENTRYUNION *ppaEntries, uint32_t *pcEntries, uint32_t *puLock)
     1712{
     1713    *puLock = UINT32_MAX;
    14301714
    14311715    int rc;
     
    14401724             * Fully buffered: Return pointer to all the entires starting at offEntryInDir.
    14411725             */
    1442             *ppaEntries       = &pThis->paEntries[idxEntryInDir];
    1443             *pcEntries        = pThis->cEntries - idxEntryInDir;
    1444             *puBufferReadLock = 1;
     1726            *ppaEntries = &pThis->paEntries[idxEntryInDir];
     1727            *pcEntries  = pThis->cEntries - idxEntryInDir;
     1728            *puLock     = !fForUpdate ? 1 : UINT32_C(0x80000001);
    14451729            rc = VINF_SUCCESS;
    14461730        }
     
    14541738            if (off < pVol->cbSector)
    14551739            {
    1456                 *ppaEntries       = &pThis->paEntries[off / sizeof(FATDIRENTRY)];
    1457                 *pcEntries        = (pVol->cbSector - off) / sizeof(FATDIRENTRY);
    1458                 *puBufferReadLock = 1;
     1740                *ppaEntries = &pThis->paEntries[off / sizeof(FATDIRENTRY)];
     1741                *pcEntries  = (pVol->cbSector - off) / sizeof(FATDIRENTRY);
     1742                *puLock     = !fForUpdate ? 1 : UINT32_C(0x80000001);
    14591743                rc = VINF_SUCCESS;
    14601744            }
     
    14801764                    if (RT_SUCCESS(rc))
    14811765                    {
    1482                         *ppaEntries       = &pThis->paEntries[off / sizeof(FATDIRENTRY)];
    1483                         *pcEntries        = (pVol->cbSector - off) / sizeof(FATDIRENTRY);
    1484                         *puBufferReadLock = 1;
     1766                        *ppaEntries = &pThis->paEntries[off / sizeof(FATDIRENTRY)];
     1767                        *pcEntries  = (pVol->cbSector - off) / sizeof(FATDIRENTRY);
     1768                        *puLock     = !fForUpdate ? 1 : UINT32_C(0x80000001);
    14851769                        rc = VINF_SUCCESS;
    14861770                    }
     
    14971781        rc = VERR_FILE_NOT_FOUND;
    14981782    return rc;
     1783}
     1784
     1785
     1786/**
     1787 * Puts back a directory entry after updating it, releasing the write lock and
     1788 * marking it dirty.
     1789 *
     1790 * @returns IPRT status code
     1791 * @param   pThis           The directory.
     1792 * @param   pDirEntry       The directory entry.
     1793 * @param   uWriteLock      The write lock.
     1794 */
     1795static int rtFsFatDir_PutEntryAfterUpdate(PRTFSFATDIR pThis, PFATDIRENTRY pDirEntry, uint32_t uWriteLock)
     1796{
     1797    Assert(uWriteLock == UINT32_C(0x80000001));
     1798    if (pThis->fFullyBuffered)
     1799    {
     1800        uint32_t idxSector = ((uintptr_t)pDirEntry - (uintptr_t)pThis->paEntries) / pThis->Core.pVol->cbSector;
     1801        pThis->u.Full.pbDirtySectors[idxSector] = true;
     1802    }
     1803    else
     1804        pThis->u.Simple.fDirty = true;
     1805    return VINF_SUCCESS;
     1806}
     1807
     1808
     1809/**
     1810 * Gets the pointer to the given directory entry for the purpose of updating it.
     1811 *
     1812 * Call rtFsFatDir_PutEntryAfterUpdate afterwards.
     1813 *
     1814 * @returns IPRT status code.
     1815 * @param   pThis           The directory.
     1816 * @param   offEntryInDir   The byte offset of the directory entry, within the
     1817 *                          directory.
     1818 * @param   ppDirEntry      Where to return the pointer to the directory entry.
     1819 * @param   puWriteLock     Where to return the write lock.
     1820 */
     1821static int rtFsFatDir_GetEntryForUpdate(PRTFSFATDIR pThis, uint32_t offEntryInDir, PFATDIRENTRY *ppDirEntry,
     1822                                        uint32_t *puWriteLock)
     1823{
     1824    uint32_t cEntriesIgn;
     1825    return rtFsFatDir_GetEntriesAtCommon(pThis, offEntryInDir, true /*fForUpdate*/, (PFATDIRENTRYUNION *)ppDirEntry,
     1826                                         &cEntriesIgn, puWriteLock);
     1827}
     1828
     1829
     1830static void rtFsFatDir_ReleaseBufferAfterReading(PRTFSFATDIR pThis, uint32_t uBufferReadLock)
     1831{
     1832    RT_NOREF(pThis, uBufferReadLock);
     1833    Assert(uBufferReadLock == 1);
     1834}
     1835
     1836
     1837/**
     1838 * Gets one or more entires at @a offEntryInDir.
     1839 *
     1840 * @returns IPRT status code.
     1841 * @param   pThis               The directory.
     1842 * @param   offEntryInDir       The directory offset in bytes.
     1843 * @param   ppaEntries          Where to return pointer to the entry at
     1844 *                              @a offEntryInDir.
     1845 * @param   pcEntries           Where to return the number of entries
     1846 *                              @a *ppaEntries points to.
     1847 * @param   puBufferReadLock    Where to return the buffer read lock handle.
     1848 *                              Call rtFsFatDir_ReleaseBufferAfterReading when
     1849 *                              done.
     1850 */
     1851static int rtFsFatDir_GetEntriesAt(PRTFSFATDIR pThis, uint32_t offEntryInDir,
     1852                                   PCFATDIRENTRYUNION *ppaEntries, uint32_t *pcEntries, uint32_t *puBufferReadLock)
     1853{
     1854    return rtFsFatDir_GetEntriesAtCommon(pThis, offEntryInDir, false /*fForUpdate*/, (PFATDIRENTRYUNION *)ppaEntries,
     1855                                         pcEntries, puBufferReadLock);
    14991856}
    15001857
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