VirtualBox

Changeset 66708 in vbox


Ignore:
Timestamp:
Apr 27, 2017 10:01:52 PM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
115107
Message:

fatvfs: Quick implementation of a long filename generator.

File:
1 edited

Legend:

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

    r66699 r66708  
    3838#include <iprt/err.h>
    3939#include <iprt/mem.h>
     40#include <iprt/path.h>
    4041#include <iprt/poll.h>
    4142#include <iprt/rand.h>
     
    7172 */
    7273#define RTFSFAT_ROT_R1_U8(a_bValue) (((a_bValue) >> 1) | (uint8_t)((a_bValue) << 7))
     74
     75
     76/** Maximum number of characters we will create in a long file name. */
     77#define RTFSFAT_MAX_LFN_CHARS   255
    7378
    7479
     
    23442349 * @returns true if 8.3 formattable name, false if not.
    23452350 * @param   pszName8Dot3    Where to return the 8-dot-3 name when returning
    2346  *                          @c true.  Filled with zero on false.  12+1 bytes.
     2351 *                          @c true.  Filled with zero on false.  8+3+1 bytes.
    23472352 * @param   pszName         The filename to convert.
    23482353 */
     
    24342439 *
    24352440 * @returns IPRT status code.
     2441 * @retval  VERR_FILE_NOT_FOUND if not found.
    24362442 * @param   pThis           The directory to search.
    24372443 * @param   pszEntry        The entry to look for.
     
    24512457     * Turn pszEntry into a 8.3 filename, if possible.
    24522458     */
    2453     char    szName8Dot3[12+1];
     2459    char    szName8Dot3[8+3+1];
    24542460    bool    fIs8Dot3Name = rtFsFatDir_StringTo8Dot3(szName8Dot3, pszEntry);
    24552461
     
    26082614
    26092615/**
     2616 * Checks if we need to generate a long name for @a pszEntry.
     2617 *
     2618 * @returns true if we need to, false if we don't.
     2619 * @param   pszEntry        The UTF-8 directory entry entry name.
     2620 * @param   fIs8Dot3Name    Whether we've managed to create a 8-dot-3 name.
     2621 * @param   pDirEntry       The directory entry with the 8-dot-3 name when
     2622 *                          fIs8Dot3Name is set.
     2623 */
     2624static bool rtFsFatDir_NeedLongName(const char *pszEntry, bool fIs8Dot3Name, PCFATDIRENTRY pDirEntry)
     2625{
     2626    if (!fIs8Dot3Name)
     2627        return true;
     2628
     2629    /** @todo check case here. */
     2630    RT_NOREF(pszEntry, pDirEntry);
     2631    return false;
     2632}
     2633
     2634
     2635/**
     2636 * Checks if the given long name is valid for a long file name or not.
     2637 *
     2638 * Encoding, length and character set limitations are checked.
     2639 *
     2640 * @returns IRPT status code.
     2641 * @param   pwszEntry       The long filename.
     2642 * @param   cwc             The length of the filename in UTF-16 chars.
     2643 */
     2644static int rtFsFatDir_ValidateLongName(PCRTUTF16 pwszEntry, size_t cwc)
     2645{
     2646    if (cwc <= RTFSFAT_MAX_LFN_CHARS)
     2647    {
     2648        RT_NOREF(pwszEntry);
     2649        /** @todo check for invalid characters. */
     2650        return VINF_SUCCESS;
     2651    }
     2652    return VERR_FILENAME_TOO_LONG;
     2653}
     2654
     2655
     2656static void rtFsFatDir_CopyShortName(char *pszDst, uint32_t cchDst, const char *pszSrc, size_t cchSrc, char chPad)
     2657{
     2658    /* Copy from source. */
     2659    if (cchSrc > 0)
     2660    {
     2661        const char *pszSrcEnd = &pszSrc[cchSrc];
     2662        while (cchDst > 0 && pszSrc != pszSrcEnd)
     2663        {
     2664            RTUNICP uc;
     2665            int rc = RTStrGetCpEx(&pszSrc, &uc);
     2666            if (RT_SUCCESS(rc))
     2667            {
     2668                if (uc < 128)
     2669                {
     2670                    if (g_awchFatCp437Chars[uc] != uc)
     2671                    {
     2672                        if (uc)
     2673                        {
     2674                            uc = RTUniCpToUpper(uc);
     2675                            if (g_awchFatCp437Chars[uc] != uc)
     2676                                uc = '_';
     2677                        }
     2678                        else
     2679                            break;
     2680                    }
     2681                }
     2682                else
     2683                    uc = '_';
     2684            }
     2685            else
     2686                uc = '_';
     2687
     2688            *pszDst++ = (char)uc;
     2689            cchDst--;
     2690        }
     2691    }
     2692
     2693    /* Pad the remaining space. */
     2694    while (cchDst-- > 0)
     2695        *pszDst++ = chPad;
     2696}
     2697
     2698
     2699/**
     2700 * Generates a short filename.
     2701 *
     2702 * @returns IPRT status code.
     2703 * @param   pThis           The directory.
     2704 * @param   pszEntry        The long name (UTF-8).
     2705 * @param   pDirEntry       Where to put the short name.
     2706 */
     2707static int rtFsFatDir_GenerateShortName(PRTFSFATDIR pThis, const char *pszEntry, PFATDIRENTRY pDirEntry)
     2708{
     2709    FATDIRENTRY DirEntryIgn;
     2710    bool        fLongIgn;
     2711    uint32_t    offEntryInDirIgn;
     2712
     2713    /* Do some input parsing. */
     2714    const char  *pszExt      = RTPathSuffix(pszEntry);
     2715    size_t const cchBasename = pszExt ? pszExt - pszEntry : strlen(pszEntry);
     2716    size_t const cchExt      = pszExt ? strlen(++pszExt)  : 0;
     2717
     2718    /* Fill in the extension first. It stays the same. */
     2719    char szShortName[8+3+1];
     2720    rtFsFatDir_CopyShortName(&szShortName[8], 3, pszExt, cchExt, ' ');
     2721    szShortName[8+3] = '\0';
     2722
     2723    /*
     2724     * First try single digit 1..9.
     2725     */
     2726    rtFsFatDir_CopyShortName(szShortName, 6, pszEntry, cchBasename, '_');
     2727    szShortName[6] = '~';
     2728    for (uint32_t iLastDigit = 1; iLastDigit < 10; iLastDigit++)
     2729    {
     2730        szShortName[7] = iLastDigit + '0';
     2731        int rc = rtFsFatDir_FindEntry(pThis, szShortName, &offEntryInDirIgn, &fLongIgn, &DirEntryIgn);
     2732        if (rc == VERR_FILE_NOT_FOUND)
     2733        {
     2734            memcpy(pDirEntry->achName, szShortName, sizeof(pDirEntry->achName));
     2735            return VINF_SUCCESS;
     2736        }
     2737        if (RT_FAILURE(rc))
     2738            return rc;
     2739    }
     2740
     2741    /*
     2742     * First try two digits 10..99.
     2743     */
     2744    szShortName[5] = '~';
     2745    for (uint32_t iFirstDigit = 1; iFirstDigit < 10; iFirstDigit++)
     2746        for (uint32_t iLastDigit = 0; iLastDigit < 10; iLastDigit++)
     2747        {
     2748            szShortName[6] = iFirstDigit + '0';
     2749            szShortName[7] = iLastDigit  + '0';
     2750            int rc = rtFsFatDir_FindEntry(pThis, szShortName, &offEntryInDirIgn, &fLongIgn, &DirEntryIgn);
     2751            if (rc == VERR_FILE_NOT_FOUND)
     2752            {
     2753                memcpy(pDirEntry->achName, szShortName, sizeof(pDirEntry->achName));
     2754                return VINF_SUCCESS;
     2755            }
     2756            if (RT_FAILURE(rc))
     2757                return rc;
     2758        }
     2759
     2760    /*
     2761     * Okay, do random numbers then.
     2762     */
     2763    szShortName[2] = '~';
     2764    for (uint32_t i = 0; i < 8192; i++)
     2765    {
     2766        char    szHex[68];
     2767        ssize_t cchHex = RTStrFormatU32(szHex, sizeof(szHex), RTRandU32(), 16, 5, 0, RTSTR_F_CAPITAL | RTSTR_F_WIDTH);
     2768        AssertReturn(cchHex >= 5, VERR_NET_NOT_UNIQUE_NAME);
     2769        szShortName[7] = szHex[cchHex];
     2770        szShortName[6] = szHex[cchHex - 1];
     2771        szShortName[5] = szHex[cchHex - 2];
     2772        szShortName[4] = szHex[cchHex - 3];
     2773        szShortName[3] = szHex[cchHex - 4];
     2774        int rc = rtFsFatDir_FindEntry(pThis, szShortName, &offEntryInDirIgn, &fLongIgn, &DirEntryIgn);
     2775        if (rc == VERR_FILE_NOT_FOUND)
     2776        {
     2777            memcpy(pDirEntry->achName, szShortName, sizeof(pDirEntry->achName));
     2778            return VINF_SUCCESS;
     2779        }
     2780        if (RT_FAILURE(rc))
     2781            return rc;
     2782    }
     2783
     2784    return VERR_NET_NOT_UNIQUE_NAME;
     2785}
     2786
     2787
     2788/**
    26102789 * Considers whether we need to create a long name or not.
    26112790 *
     
    26262805{
    26272806    RT_NOREF(pThis, pDirEntry, paSlots, pszEntry);
    2628     if (fIs8Dot3Name)
     2807
     2808    /*
     2809     * If we don't need to create a long name, return immediately.
     2810     */
     2811    if (!rtFsFatDir_NeedLongName(pszEntry, fIs8Dot3Name, pDirEntry))
    26292812    {
    26302813        *pcSlots = 0;
    26312814        return VINF_SUCCESS;
    26322815    }
     2816
     2817    /*
     2818     * Convert the name to UTF-16 and figure it's length (this validates the
     2819     * input encoding).  Then do long name validation (length, charset limitation).
     2820     */
     2821    RTUTF16     wszEntry[FATDIRNAMESLOT_MAX_SLOTS * FATDIRNAMESLOT_CHARS_PER_SLOT + 4];
     2822    PRTUTF16    pwszEntry = wszEntry;
     2823    size_t      cwcEntry;
     2824    int rc = RTStrToUtf16Ex(pszEntry, RTSTR_MAX, &pwszEntry, RT_ELEMENTS(wszEntry), &cwcEntry);
     2825    if (RT_SUCCESS(rc))
     2826        rc = rtFsFatDir_ValidateLongName(pwszEntry, cwcEntry);
     2827    if (RT_SUCCESS(rc))
     2828    {
     2829        /*
     2830         * Generate a short name if we need to.
     2831         */
     2832        if (!fIs8Dot3Name)
     2833            rc = rtFsFatDir_GenerateShortName(pThis, pszEntry, pDirEntry);
     2834        if (RT_SUCCESS(rc))
     2835        {
     2836            /*
     2837             * Fill in the long name slots.  First we pad the wszEntry with 0xffff
     2838             * until it is a multiple of of the slot count.  That way we can copy
     2839             * the name straight into the entry without constaints.
     2840             */
     2841            memset(&wszEntry[cwcEntry + 1], 0xff,
     2842                   RT_MIN(sizeof(wszEntry) - (cwcEntry + 1) * sizeof(RTUTF16), FATDIRNAMESLOT_CHARS_PER_SLOT));
     2843
     2844            uint8_t const   bChecksum = rtFsFatDir_CalcChecksum(pDirEntry);
     2845            size_t const    cSlots    = (cwcEntry + FATDIRNAMESLOT_CHARS_PER_SLOT - 1) / FATDIRNAMESLOT_CHARS_PER_SLOT;
     2846            size_t          iSlot     = cSlots;
     2847            PCRTUTF16       pwszSrc   = wszEntry;
     2848            while (iSlot-- > 0)
     2849            {
     2850                memcpy(paSlots[iSlot].awcName0, pwszSrc, sizeof(paSlots[iSlot].awcName0));
     2851                pwszSrc += RT_ELEMENTS(paSlots[iSlot].awcName0);
     2852                memcpy(paSlots[iSlot].awcName1, pwszSrc, sizeof(paSlots[iSlot].awcName1));
     2853                pwszSrc += RT_ELEMENTS(paSlots[iSlot].awcName1);
     2854                memcpy(paSlots[iSlot].awcName2, pwszSrc, sizeof(paSlots[iSlot].awcName2));
     2855                pwszSrc += RT_ELEMENTS(paSlots[iSlot].awcName2);
     2856
     2857                paSlots[iSlot].idSlot    = (uint8_t)(cSlots - iSlot);
     2858                paSlots[iSlot].fAttrib   = FAT_ATTR_NAME_SLOT;
     2859                paSlots[iSlot].fZero     = 0;
     2860                paSlots[iSlot].idxZero   = 0;
     2861                paSlots[iSlot].bChecksum = bChecksum;
     2862            }
     2863            paSlots[0].idSlot |= FATDIRNAMESLOT_FIRST_SLOT_FLAG;
     2864            *pcSlots = (uint32_t)cSlots;
     2865            return VINF_SUCCESS;
     2866        }
     2867    }
    26332868    *pcSlots = UINT32_MAX;
    2634     return VERR_INVALID_NAME;
     2869    return rc;
    26352870}
    26362871
     
    28803115    uint32_t        cSlots = UINT32_MAX;
    28813116    FATDIRNAMESLOT  aSlots[FATDIRNAMESLOT_MAX_SLOTS];
     3117    AssertCompile(RTFSFAT_MAX_LFN_CHARS < RT_ELEMENTS(aSlots) * FATDIRNAMESLOT_CHARS_PER_SLOT);
    28823118    int rc = rtFsFatDir_MaybeCreateLongNameAndShortAlias(pThis, pszEntry, fIs8Dot3Name, pDirEntry, aSlots, &cSlots);
    28833119    if (RT_SUCCESS(rc))
Note: See TracChangeset for help on using the changeset viewer.

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