Changeset 69598 in vbox for trunk/src/VBox
- Timestamp:
- Nov 6, 2017 3:03:05 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/fs/fatvfs.cpp
r69596 r69598 3667 3667 static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir) 3668 3668 { 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 */ 3707 static DECLCALLBACK(int) rtFsFatDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir) 3708 { 3709 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir); 3671 3710 return VERR_NOT_IMPLEMENTED; 3672 3711 } … … 3674 3713 3675 3714 /** 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 /**3687 3715 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink} 3688 3716 */ … … 3690 3718 { 3691 3719 RT_NOREF(pvThis, pszSymlink, phVfsSymlink); 3692 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSymlink);3693 3720 return VERR_NOT_SUPPORTED; 3694 3721 } … … 3702 3729 { 3703 3730 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink); 3704 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSymlink);3705 3731 return VERR_NOT_SUPPORTED; 3706 3732 } … … 3744 3770 { 3745 3771 RT_NOREF(pvThis, pszEntry, fType); 3746 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszEntry);3747 3772 return VERR_NOT_IMPLEMENTED; 3748 3773 } … … 3755 3780 { 3756 3781 RT_NOREF(pvThis, pszEntry, fType, pszNewName); 3757 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszEntry);3758 3782 return VERR_NOT_IMPLEMENTED; 3759 3783 } … … 3765 3789 static DECLCALLBACK(int) rtFsFatDir_RewindDir(void *pvThis) 3766 3790 { 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 */ 3804 static 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 */ 3842 static 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 */ 3891 static 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); 3770 3933 } 3771 3934 … … 3777 3940 RTFSOBJATTRADD enmAddAttr) 3778 3941 { 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; 3782 4123 } 3783 4124
Note:
See TracChangeset
for help on using the changeset viewer.