VirtualBox

Changeset 69598 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Nov 6, 2017 3:03:05 PM (7 years ago)
Author:
vboxsync
Message:

fatvfs.cpp: Implemented directory listing and opening.

File:
1 edited

Legend:

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

    r69596 r69598  
    36673667static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)
    36683668{
    3669     RT_NOREF(pvThis, pszSubDir, fFlags, phVfsDir);
    3670 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSubDir);
     3669    PRTFSFATDIR     pThis   = (PRTFSFATDIR)pvThis;
     3670    PRTFSFATDIRSHRD pShared = pThis->pShared;
     3671    AssertReturn(!fFlags, VERR_INVALID_FLAGS);
     3672
     3673    /*
     3674     * Try open directory.
     3675     */
     3676    uint32_t    offEntryInDir;
     3677    bool        fLong;
     3678    FATDIRENTRY DirEntry;
     3679    int rc = rtFsFatDirShrd_FindEntry(pShared, pszSubDir, &offEntryInDir, &fLong, &DirEntry);
     3680    LogFlow(("rtFsFatDir_OpenDir: FindEntry(,%s,,,) -> %Rrc fLong=%d offEntryInDir=%#RX32\n", rc, fLong, offEntryInDir));
     3681    if (RT_SUCCESS(rc))
     3682    {
     3683        switch (DirEntry.fAttrib & (FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME))
     3684        {
     3685            case FAT_ATTR_DIRECTORY:
     3686                rc = rtFsFatDir_New(pShared->Core.pVol, pShared, &DirEntry, offEntryInDir,
     3687                                    RTFSFAT_GET_CLUSTER(&DirEntry, pShared->Core.pVol), UINT64_MAX /*offDisk*/,
     3688                                    DirEntry.cbFile, phVfsDir);
     3689                break;
     3690
     3691            case 0:
     3692                rc = VERR_NOT_A_DIRECTORY;
     3693                break;
     3694
     3695            default:
     3696                rc = VERR_PATH_NOT_FOUND;
     3697                break;
     3698        }
     3699    }
     3700    return rc;
     3701}
     3702
     3703
     3704/**
     3705 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
     3706 */
     3707static DECLCALLBACK(int) rtFsFatDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
     3708{
     3709    RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
    36713710    return VERR_NOT_IMPLEMENTED;
    36723711}
     
    36743713
    36753714/**
    3676  * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
    3677  */
    3678 static DECLCALLBACK(int) rtFsFatDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
    3679 {
    3680     RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
    3681 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSubDir);
    3682     return VERR_NOT_IMPLEMENTED;
    3683 }
    3684 
    3685 
    3686 /**
    36873715 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
    36883716 */
     
    36903718{
    36913719    RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
    3692 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSymlink);
    36933720    return VERR_NOT_SUPPORTED;
    36943721}
     
    37023729{
    37033730    RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
    3704 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSymlink);
    37053731    return VERR_NOT_SUPPORTED;
    37063732}
     
    37443770{
    37453771    RT_NOREF(pvThis, pszEntry, fType);
    3746 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszEntry);
    37473772    return VERR_NOT_IMPLEMENTED;
    37483773}
     
    37553780{
    37563781    RT_NOREF(pvThis, pszEntry, fType, pszNewName);
    3757 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszEntry);
    37583782    return VERR_NOT_IMPLEMENTED;
    37593783}
     
    37653789static DECLCALLBACK(int) rtFsFatDir_RewindDir(void *pvThis)
    37663790{
    3767     RT_NOREF(pvThis);
    3768 RTAssertMsg2("%s\n", __FUNCTION__);
    3769     return VERR_NOT_IMPLEMENTED;
     3791    PRTFSFATDIR pThis = (PRTFSFATDIR)pvThis;
     3792    pThis->offDir = 0;
     3793    return VINF_SUCCESS;
     3794}
     3795
     3796
     3797/**
     3798 * Calculates the UTF-8 length of the name in the given directory entry.
     3799 *
     3800 * @returns The length in characters (bytes), excluding terminator.
     3801 * @param   pShared     The shared directory structure (for codepage).
     3802 * @param   pEntry      The directory entry.
     3803 */
     3804static size_t rtFsFatDir_CalcUtf8LengthForDirEntry(PRTFSFATDIRSHRD pShared, PCFATDIRENTRY pEntry)
     3805{
     3806    RT_NOREF(pShared);
     3807    PCRTUTF16 g_pawcMap = &g_awchFatCp437Chars[0];
     3808
     3809    /* The base name (this won't work with DBCS, but that's not a concern at the moment). */
     3810    size_t offSrc = 8;
     3811    while (offSrc > 1 && RTUniCpIsSpace(g_pawcMap[pEntry->achName[offSrc - 1]]))
     3812        offSrc--;
     3813
     3814    size_t cchRet = 0;
     3815    while (offSrc-- > 0)
     3816        cchRet += RTStrCpSize(g_pawcMap[pEntry->achName[offSrc]]);
     3817
     3818    /* Extension. */
     3819    offSrc = 11;
     3820    while (offSrc > 8 && RTUniCpIsSpace(g_pawcMap[pEntry->achName[offSrc - 1]]))
     3821        offSrc--;
     3822    if (offSrc > 8)
     3823    {
     3824        cchRet += 1; /* '.' */
     3825        while (offSrc-- > 8)
     3826            cchRet += RTStrCpSize(g_pawcMap[pEntry->achName[offSrc]]);
     3827    }
     3828
     3829    return cchRet;
     3830}
     3831
     3832
     3833/**
     3834 * Copies the name from the directory entry into a UTF-16 buffer.
     3835 *
     3836 * @returns Number of UTF-16 items written (excluding terminator).
     3837 * @param   pShared     The shared directory structure (for codepage).
     3838 * @param   pEntry      The directory entry.
     3839 * @param   pwszDst     The destination buffer.
     3840 * @param   cwcDst      The destination buffer size.
     3841 */
     3842static uint16_t rtFsFatDir_CopyDirEntryToUtf16(PRTFSFATDIRSHRD pShared, PCFATDIRENTRY pEntry, PRTUTF16 pwszDst, size_t cwcDst)
     3843{
     3844    Assert(cwcDst > 0);
     3845
     3846    RT_NOREF(pShared);
     3847    PCRTUTF16 g_pawcMap = &g_awchFatCp437Chars[0];
     3848
     3849    /* The base name (this won't work with DBCS, but that's not a concern at the moment). */
     3850    size_t cchSrc = 8;
     3851    while (cchSrc > 1 && RTUniCpIsSpace(g_pawcMap[pEntry->achName[cchSrc - 1]]))
     3852        cchSrc--;
     3853
     3854    size_t offDst = 0;
     3855    for (size_t offSrc = 0; offSrc < cchSrc; offSrc++)
     3856    {
     3857        AssertReturnStmt(offDst + 1 < cwcDst, pwszDst[cwcDst - 1] = '\0', (uint16_t)cwcDst);
     3858        pwszDst[offDst++] = g_pawcMap[pEntry->achName[offSrc]];
     3859    }
     3860
     3861    /* Extension. */
     3862    cchSrc = 3;
     3863    while (cchSrc > 0 && RTUniCpIsSpace(g_pawcMap[pEntry->achName[8 + cchSrc - 1]]))
     3864        cchSrc--;
     3865    if (cchSrc > 0)
     3866    {
     3867        AssertReturnStmt(offDst + 1 < cwcDst, pwszDst[cwcDst - 1] = '\0', (uint16_t)cwcDst);
     3868        pwszDst[offDst++] = '.';
     3869
     3870        for (size_t offSrc = 0; offSrc < cchSrc; offSrc++)
     3871        {
     3872            AssertReturnStmt(offDst + 1 < cwcDst, pwszDst[cwcDst - 1] = '\0', (uint16_t)cwcDst);
     3873            pwszDst[offDst++] = g_pawcMap[pEntry->achName[8 + offSrc]];
     3874        }
     3875    }
     3876
     3877    pwszDst[offDst] = '\0';
     3878    return (uint16_t)offDst;
     3879}
     3880
     3881
     3882/**
     3883 * Copies the name from the directory entry into a UTF-8 buffer.
     3884 *
     3885 * @returns Number of UTF-16 items written (excluding terminator).
     3886 * @param   pShared     The shared directory structure (for codepage).
     3887 * @param   pEntry      The directory entry.
     3888 * @param   pszDst      The destination buffer.
     3889 * @param   cbDst       The destination buffer size.
     3890 */
     3891static uint16_t rtFsFatDir_CopyDirEntryToUtf8(PRTFSFATDIRSHRD pShared, PCFATDIRENTRY pEntry, char *pszDst, size_t cbDst)
     3892{
     3893    Assert(cbDst > 0);
     3894
     3895    RT_NOREF(pShared);
     3896    PCRTUTF16 g_pawcMap = &g_awchFatCp437Chars[0];
     3897
     3898    /* The base name (this won't work with DBCS, but that's not a concern at the moment). */
     3899    size_t cchSrc = 8;
     3900    while (cchSrc > 1 && RTUniCpIsSpace(g_pawcMap[pEntry->achName[cchSrc - 1]]))
     3901        cchSrc--;
     3902
     3903    char * const pszDstEnd = pszDst + cbDst;
     3904    char *pszCurDst = pszDst;
     3905    for (size_t offSrc = 0; offSrc < cchSrc; offSrc++)
     3906    {
     3907        RTUNICP const uc = g_pawcMap[pEntry->achName[offSrc]];
     3908        size_t        cbCp = RTStrCpSize(uc);
     3909        AssertReturnStmt(cbCp < (size_t)(pszDstEnd - pszCurDst), *pszCurDst = '\0', (uint16_t)(pszDstEnd - pszCurDst));
     3910        pszCurDst = RTStrPutCp(pszCurDst, uc);
     3911    }
     3912
     3913    /* Extension. */
     3914    cchSrc = 3;
     3915    while (cchSrc > 0 && RTUniCpIsSpace(g_pawcMap[pEntry->achName[8 + cchSrc - 1]]))
     3916        cchSrc--;
     3917    if (cchSrc > 0)
     3918    {
     3919        AssertReturnStmt(1U < (size_t)(pszDstEnd - pszCurDst), *pszCurDst = '\0', (uint16_t)(pszDstEnd - pszCurDst));
     3920        *pszCurDst++ = '.';
     3921
     3922        for (size_t offSrc = 0; offSrc < cchSrc; offSrc++)
     3923        {
     3924            RTUNICP const uc = g_pawcMap[pEntry->achName[8 + offSrc]];
     3925            size_t        cbCp = RTStrCpSize(uc);
     3926            AssertReturnStmt(cbCp < (size_t)(pszDstEnd - pszCurDst), *pszCurDst = '\0', (uint16_t)(pszDstEnd - pszCurDst));
     3927            pszCurDst = RTStrPutCp(pszCurDst, uc);
     3928        }
     3929    }
     3930
     3931    *pszCurDst = '\0';
     3932    return (uint16_t)(pszDstEnd - pszCurDst);
    37703933}
    37713934
     
    37773940                                            RTFSOBJATTRADD enmAddAttr)
    37783941{
    3779     RT_NOREF(pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
    3780 RTAssertMsg2("%s\n", __FUNCTION__);
    3781     return VERR_NOT_IMPLEMENTED;
     3942    PRTFSFATDIR     pThis   = (PRTFSFATDIR)pvThis;
     3943    PRTFSFATDIRSHRD pShared = pThis->pShared;
     3944
     3945    /*
     3946     * Fake '.' and '..' entries.
     3947     */
     3948    if (pThis->offDir < 2)
     3949    {
     3950        size_t cbNeeded = RT_OFFSETOF(RTDIRENTRYEX, szName[pThis->offDir + 2]);
     3951        if (cbNeeded < *pcbDirEntry)
     3952            *pcbDirEntry = cbNeeded;
     3953        else
     3954        {
     3955            *pcbDirEntry = cbNeeded;
     3956            return VERR_BUFFER_OVERFLOW;
     3957        }
     3958
     3959        int rc;
     3960        if (   pThis->offDir == 0
     3961            || pShared->Core.pParentDir == NULL)
     3962            rc = rtFsFatObj_QueryInfo(&pShared->Core, &pDirEntry->Info, enmAddAttr);
     3963        else
     3964            rc = rtFsFatObj_QueryInfo(&pShared->Core.pParentDir->Core, &pDirEntry->Info, enmAddAttr);
     3965
     3966        pDirEntry->cwcShortName = 0;
     3967        pDirEntry->wszShortName[0] = '\0';
     3968        pDirEntry->szName[0] = '.';
     3969        pDirEntry->szName[1] = '.';
     3970        pDirEntry->szName[++pThis->offDir] = '\0';
     3971        pDirEntry->cbName = pThis->offDir;
     3972        return rc;
     3973    }
     3974
     3975    /*
     3976     * Scan the directory buffer by buffer.
     3977     */
     3978    RTUTF16             wszName[260+1];
     3979    uint8_t             bChecksum       = UINT8_MAX;
     3980    uint8_t             idNextSlot      = UINT8_MAX;
     3981    size_t              cwcName         = 0;
     3982    uint32_t            offEntryInDir   = pThis->offDir - 2;
     3983    uint32_t const      cbDir           = pShared->Core.cbObject;
     3984    Assert(RT_ALIGN_32(cbDir, sizeof(*pDirEntry)) == cbDir);
     3985    AssertCompile(FATDIRNAMESLOT_MAX_SLOTS * FATDIRNAMESLOT_CHARS_PER_SLOT < RT_ELEMENTS(wszName));
     3986    wszName[260] = '\0';
     3987
     3988    while (offEntryInDir < cbDir)
     3989    {
     3990        /* Get chunk of entries starting at offEntryInDir. */
     3991        uint32_t            uBufferLock = UINT32_MAX;
     3992        uint32_t            cEntries    = 0;
     3993        PCFATDIRENTRYUNION  paEntries   = NULL;
     3994        int rc = rtFsFatDirShrd_GetEntriesAt(pShared, offEntryInDir, &paEntries, &cEntries, &uBufferLock);
     3995        if (RT_FAILURE(rc))
     3996            return rc;
     3997
     3998        /*
     3999         * Now work thru each of the entries.
     4000         */
     4001        for (uint32_t iEntry = 0; iEntry < cEntries; iEntry++, offEntryInDir += sizeof(FATDIRENTRY))
     4002        {
     4003            switch ((uint8_t)paEntries[iEntry].Entry.achName[0])
     4004            {
     4005                default:
     4006                    break;
     4007                case FATDIRENTRY_CH0_DELETED:
     4008                    cwcName = 0;
     4009                    continue;
     4010                case FATDIRENTRY_CH0_END_OF_DIR:
     4011                    if (pShared->Core.pVol->enmBpbVersion >= RTFSFATBPBVER_DOS_2_0)
     4012                    {
     4013                        pThis->offDir = cbDir + 2;
     4014                        rtFsFatDirShrd_ReleaseBufferAfterReading(pShared, uBufferLock);
     4015                        return VERR_NO_MORE_FILES;
     4016                    }
     4017                    cwcName = 0;
     4018                    break; /* Technically a valid entry before DOS 2.0, or so some claim. */
     4019            }
     4020
     4021            /*
     4022             * Check for long filename slot.
     4023             */
     4024            if (   paEntries[iEntry].Slot.fAttrib == FAT_ATTR_NAME_SLOT
     4025                && paEntries[iEntry].Slot.idxZero == 0
     4026                && paEntries[iEntry].Slot.fZero   == 0
     4027                && (paEntries[iEntry].Slot.idSlot & ~FATDIRNAMESLOT_FIRST_SLOT_FLAG) <= FATDIRNAMESLOT_HIGHEST_SLOT_ID
     4028                && (paEntries[iEntry].Slot.idSlot & ~FATDIRNAMESLOT_FIRST_SLOT_FLAG) != 0)
     4029            {
     4030                /* New slot? */
     4031                if (paEntries[iEntry].Slot.idSlot & FATDIRNAMESLOT_FIRST_SLOT_FLAG)
     4032                {
     4033                    idNextSlot = paEntries[iEntry].Slot.idSlot & ~FATDIRNAMESLOT_FIRST_SLOT_FLAG;
     4034                    bChecksum  = paEntries[iEntry].Slot.bChecksum;
     4035                    cwcName    = idNextSlot * FATDIRNAMESLOT_CHARS_PER_SLOT;
     4036                    wszName[cwcName] = '\0';
     4037                }
     4038                /* Is valid next entry? */
     4039                else if (   paEntries[iEntry].Slot.idSlot    == idNextSlot
     4040                         && paEntries[iEntry].Slot.bChecksum == bChecksum)
     4041                { /* likely */ }
     4042                else
     4043                    cwcName = 0;
     4044                if (cwcName)
     4045                {
     4046                    idNextSlot--;
     4047                    size_t offName = idNextSlot * FATDIRNAMESLOT_CHARS_PER_SLOT;
     4048                    memcpy(&wszName[offName],         paEntries[iEntry].Slot.awcName0, sizeof(paEntries[iEntry].Slot.awcName0));
     4049                    memcpy(&wszName[offName + 5],     paEntries[iEntry].Slot.awcName1, sizeof(paEntries[iEntry].Slot.awcName1));
     4050                    memcpy(&wszName[offName + 5 + 6], paEntries[iEntry].Slot.awcName2, sizeof(paEntries[iEntry].Slot.awcName2));
     4051                }
     4052            }
     4053            /*
     4054             * Got a regular directory entry.  Try return it to the caller.
     4055             */
     4056            else
     4057            {
     4058                /* Do the length calc and check for overflows. */
     4059                bool   fLongName = false;
     4060                size_t cchName = 0;
     4061                if (   cwcName != 0
     4062                    && idNextSlot == 0
     4063                    && rtFsFatDir_CalcChecksum(&paEntries[iEntry].Entry) == bChecksum)
     4064                {
     4065                    rc = RTUtf16CalcUtf8LenEx(wszName, cwcName, &cchName);
     4066                    if (RT_FAILURE(rc))
     4067                    {
     4068                        fLongName = false;
     4069                        cwcName = 0;
     4070                    }
     4071                }
     4072                if (!fLongName)
     4073                    cchName = rtFsFatDir_CalcUtf8LengthForDirEntry(pShared, &paEntries[iEntry].Entry);
     4074                size_t cbNeeded = RT_OFFSETOF(RTDIRENTRYEX, szName[cchName + 1]);
     4075                if (cbNeeded <= *pcbDirEntry)
     4076                    *pcbDirEntry = cbNeeded;
     4077                else
     4078                {
     4079                    *pcbDirEntry = cbNeeded;
     4080                    return VERR_BUFFER_OVERFLOW;
     4081                }
     4082
     4083                /* To avoid duplicating code in rtFsFatObj_InitFromDirRec and
     4084                   rtFsFatObj_QueryInfo, we create a dummy RTFSFATOBJ on the stack. */
     4085                RTFSFATOBJ TmpObj;
     4086                RT_ZERO(TmpObj);
     4087                rtFsFatObj_InitFromDirEntry(&TmpObj, &paEntries[iEntry].Entry, offEntryInDir, pShared->Core.pVol);
     4088
     4089                rtFsFatDirShrd_ReleaseBufferAfterReading(pShared, uBufferLock);
     4090
     4091                rc = rtFsFatObj_QueryInfo(&TmpObj, &pDirEntry->Info, enmAddAttr);
     4092
     4093                /* Copy out the names. */
     4094                pDirEntry->cbName = (uint16_t)cchName;
     4095                if (fLongName)
     4096                {
     4097                    char *pszDst = &pDirEntry->szName[0];
     4098                    int rc2 = RTUtf16ToUtf8Ex(wszName, cwcName, &pszDst, cchName + 1, NULL);
     4099                    AssertRC(rc2);
     4100
     4101                    pDirEntry->cwcShortName = rtFsFatDir_CopyDirEntryToUtf16(pShared, &paEntries[iEntry].Entry,
     4102                                                                             pDirEntry->wszShortName,
     4103                                                                             RT_ELEMENTS(pDirEntry->wszShortName));
     4104                }
     4105                else
     4106                {
     4107                    rtFsFatDir_CopyDirEntryToUtf8(pShared, &paEntries[iEntry].Entry, &pDirEntry->szName[0], cchName + 1);
     4108                    pDirEntry->wszShortName[0] = '\0';
     4109                    pDirEntry->cwcShortName = 0;
     4110                }
     4111
     4112                if (RT_SUCCESS(rc))
     4113                    pThis->offDir = offEntryInDir + sizeof(paEntries[iEntry]) + 2;
     4114                return rc;
     4115            }
     4116        }
     4117
     4118        rtFsFatDirShrd_ReleaseBufferAfterReading(pShared, uBufferLock);
     4119    }
     4120
     4121    pThis->offDir = cbDir + 2;
     4122    return VERR_NO_MORE_FILES;
    37824123}
    37834124
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