VirtualBox

Changeset 67278 in vbox for trunk


Ignore:
Timestamp:
Jun 6, 2017 4:49:24 PM (7 years ago)
Author:
vboxsync
Message:

isomaker: more code

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/formats/iso9660.h

    r66735 r67278  
    4040/** The (default) logical sectors size of ISO 9660. */
    4141#define ISO9660_SECTOR_SIZE                 2048
     42/** Maximum filename length (level 2 & 3). */
     43#define ISO9660_MAX_NAME_LEN                30
     44
    4245
    4346/** Accessor for ISO9660U16 and ISO9660U32 that retrievs the member value for
  • trunk/src/VBox/Runtime/common/fs/isomaker.cpp

    r67271 r67278  
    3636#include <iprt/assert.h>
    3737#include <iprt/err.h>
     38#include <iprt/ctype.h>
    3839#include <iprt/file.h>
    3940#include <iprt/list.h>
    4041#include <iprt/log.h>
    4142#include <iprt/mem.h>
     43#include <iprt/path.h>
    4244#include <iprt/string.h>
    4345#include <iprt/vfs.h>
     
    6062/** Maximum number of objects. */
    6163#define RTFSISOMAKER_MAX_OBJECTS            _16M
     64/** UTF-8 name buffer.  */
     65#define RTFSISOMAKER_MAX_NAME_BUF           768
     66
     67/** Tests if @a a_ch is in the set of d-characters. */
     68#define RTFSISOMAKER_IS_IN_D_CHARS(a_ch)        (RT_C_IS_UPPER(a_ch) || RT_C_IS_DIGIT(a_ch) || (a_ch) == '_')
     69
     70/** Tests if @a a_ch is in the set of d-characters when uppercased. */
     71#define RTFSISOMAKER_IS_UPPER_IN_D_CHARS(a_ch)  (RT_C_IS_ALNUM(a_ch) || (a_ch) == '_')
     72
    6273
    6374
     
    142153    /** Alternative TRANS.TBL name. */
    143154    char                   *pszTransNm;
     155    /** Length of pszSpecNm. */
     156    uint16_t                cchSpecNm;
    144157    /** Length of pszRockRidgeNm. */
    145158    uint16_t                cchRockRidgeNm;
     
    287300    /** The list of objects (RTFSISOMAKEROBJ). */
    288301    RTLISTANCHOR            ObjectHead;
    289 
    290     /** The total image size. */
     302    /** Number of objects in the image (ObjectHead).
     303     * This is used to number them, i.e. create RTFSISOMAKEROBJ::idxObj.  */
     304    uint32_t                cObjects;
     305
     306    /** Amount of file data. */
     307    uint64_t                cbData;
     308    /** The total image size.
     309     * @todo not sure if this is desirable.  */
    291310    uint64_t                cbTotal;
    292311
     
    554573
    555574
    556 DECL_NO_INLINE(static, PRTFSISOMAKEROBJ) rtFsIsoMakerIndexToObj(PRTFSISOMAKERINT pThis, uint32_t idxObj)
     575/**
     576 * Translates an object index number to an object pointer, slow path.
     577 *
     578 * @returns Pointer to object, NULL if not found.
     579 * @param   pThis               The ISO creator instance.
     580 * @param   idxObj              The object index too resolve.
     581 */
     582DECL_NO_INLINE(static, PRTFSISOMAKEROBJ) rtFsIsoMakerIndexToObjSlow(PRTFSISOMAKERINT pThis, uint32_t idxObj)
    557583{
    558584    PRTFSISOMAKEROBJ pObj;
     
    566592
    567593
     594/**
     595 * Translates an object index number to an object pointer.
     596 *
     597 * @returns Pointer to object, NULL if not found.
     598 * @param   pThis               The ISO creator instance.
     599 * @param   idxObj              The object index too resolve.
     600 */
    568601DECLINLINE(PRTFSISOMAKEROBJ) rtFsIsoMakerIndexToObj(PRTFSISOMAKERINT pThis, uint32_t idxObj)
    569602{
     
    571604    if (!pObj || RT_LIKELY(pObj->idxObj == idxObj))
    572605        return pObj;
    573     return rtFsIsoMakerIndexToObjSlow(pThis, idxObj)
    574 }
    575 
    576 
    577 static int rtTFsIsoMakerObjSetPathInOne(RTFSISOMAKER hIsoMaker, uint32_t idxEntry,
    578                                         uint32_t fNamespace, const char *pszPath)
    579 {
    580 
     606    return rtFsIsoMakerIndexToObjSlow(pThis, idxObj);
     607}
     608
     609
     610/**
     611 * Locates a child object by its namespace name.
     612 *
     613 * @returns Pointer to the child if found, NULL if not.
     614 * @param   pDirObj             The directory object to search.
     615 * @param   pszEntry            The (namespace) entry name.
     616 * @param   cchEntry            The length of the name.
     617 */
     618static PRTFSISOMAKERNAME rtFsIsoMakerFindObjInDir(PRTFSISOMAKERNAME pDirObj, const char *pszEntry, size_t cchEntry)
     619{
     620    if (pDirObj)
     621    {
     622        PRTFSISOMAKERNAMEDIR pDir = pDirObj->pDir;
     623        AssertReturn(pDir, NULL);
     624
     625        uint32_t i = pDir->cChildren;
     626        while (i-- > 0)
     627        {
     628            PRTFSISOMAKERNAME pChild = pDir->papChildren[i];
     629            if (   pChild->cchName == cchEntry
     630                && RTStrNICmp(pChild->szName, pszEntry, cchEntry) == 0)
     631                return pChild;
     632        }
     633    }
     634    return NULL;
     635}
     636
     637
     638/**
     639 * Locates a child object by its specified name.
     640 *
     641 * @returns Pointer to the child if found, NULL if not.
     642 * @param   pDirObj             The directory object to search.
     643 * @param   pszEntry            The (specified) entry name.
     644 * @param   cchEntry            The length of the name.
     645 */
     646static PRTFSISOMAKERNAME rtFsIsoMakerFindObjInDirBySpec(PRTFSISOMAKERNAME pDirObj, const char *pszEntry, size_t cchEntry)
     647{
     648    if (pDirObj)
     649    {
     650        PRTFSISOMAKERNAMEDIR pDir = pDirObj->pDir;
     651        AssertReturn(pDir, NULL);
     652
     653        uint32_t i = pDir->cChildren;
     654        while (i-- > 0)
     655        {
     656            PRTFSISOMAKERNAME pChild = pDir->papChildren[i];
     657            if (   pChild->cchSpecNm == cchEntry
     658                && RTStrNICmp(pChild->pszSpecNm, pszEntry, cchEntry) == 0)
     659                return pChild;
     660        }
     661    }
     662    return NULL;
     663}
     664
     665/**
     666 * Copy and convert a name to valid ISO-9660 (d-characters only).
     667 *
     668 * Worker for rtFsIsoMakerNormalizeNameForNamespace.  ASSUMES it deals with
     669 * dots.
     670 *
     671 * @returns Length of the resulting string.
     672 * @param   pszDst              The output buffer.
     673 * @param   cchDstMax           The maximum number of (d-chars) to put in the
     674 *                              output buffer .
     675 * @param   pszSrc              The UTF-8 source string.
     676 * @param   cchSrc              The maximum number of chars to copy from the
     677 *                              source string.
     678 */
     679static size_t rtFsIsoMakerCopyIso9660Name(char *pszDst, size_t cchDstMax, const char *pszSrc, size_t cchSrc)
     680{
     681    const char *pszSrcIn = pszSrc;
     682    size_t      offDst = 0;
     683    while ((size_t)(pszSrc - pszSrcIn) < cchSrc)
     684    {
     685        RTUNICP uc;
     686        int rc = RTStrGetCpEx(&pszSrc, &uc);
     687        if (RT_SUCCESS(rc))
     688        {
     689            if (   uc < 128
     690                && RTFSISOMAKER_IS_UPPER_IN_D_CHARS((char)uc))
     691            {
     692                pszDst[offDst++] = RT_C_TO_UPPER((char)uc);
     693                if (offDst >= cchDstMax)
     694                    break;
     695            }
     696        }
     697    }
     698    pszDst[offDst] = '\0';
     699    return offDst;
     700}
     701
     702
     703/**
     704 * Normalizes a name for the specified name space.
     705 *
     706 * @returns IPRT status code.
     707 * @param   pThis       The ISO maker instance.
     708 * @param   pParent     The parent directory.  NULL if root.
     709 * @param   pszSrc      The specified name to normalize.
     710 * @param   fNamespace  The namespace rulez to normalize it according to.
     711 * @param   fIsDir      Indicates whether it's a directory or file (like).
     712 * @param   pszDst      The output buffer.  Must be at least 32 bytes.
     713 * @param   cbDst       The size of the output buffer.
     714 * @param   pcchDst     Where to return the length of the returned string (i.e.
     715 *                      not counting the terminator).
     716 */
     717static int rtFsIsoMakerNormalizeNameForNamespace(PRTFSISOMAKERINT pThis, PRTFSISOMAKERNAME pParent, const char *pszSrc,
     718                                                 uint32_t fNamespace, bool fIsDir, char *pszDst, size_t cbDst, size_t *pcchDst)
     719{
     720    size_t cchSrc = strlen(pszSrc);
     721    if (cchSrc)
     722    {
     723        /*
     724         * Check that the object doesn't already exist.
     725         */
     726        AssertReturn(!rtFsIsoMakerFindObjInDirBySpec(pParent, pszSrc, cchSrc), VERR_ALREADY_EXISTS);
     727        switch (fNamespace)
     728        {
     729            /*
     730             * This one is fun. :)
     731             */
     732            case RTFSISOMAKERNAMESPACE_ISO_9660:
     733            {
     734                AssertReturn(cbDst > ISO9660_MAX_NAME_LEN, VERR_INTERNAL_ERROR_3);
     735
     736                /* Skip leading dots. */
     737                while (*pszSrc == '.')
     738                    pszSrc++, cchSrc--;
     739                if (!cchSrc)
     740                {
     741                    pszSrc = "DOTS";
     742                    cchSrc = 4;
     743                }
     744
     745                /*
     746                 * Produce a first name.
     747                 */
     748                size_t cchDst;
     749                size_t offDstDot;
     750                if (fIsDir)
     751                    offDstDot = cchDst = rtFsIsoMakerCopyIso9660Name(pszDst, pThis->uIsoLevel >= 2 ? ISO9660_MAX_NAME_LEN : 8,
     752                                                                     pszSrc, cchSrc);
     753                else
     754                {
     755                    /* Look for the last dot and try preserve the extension when doing the conversion. */
     756                    size_t offLastDot = cchSrc;
     757                    for (size_t off = 0; off < cchSrc; off++)
     758                        if (pszSrc[off] == '.')
     759                            offLastDot = off;
     760
     761                    if (offLastDot == cchSrc)
     762                        offDstDot = cchDst = rtFsIsoMakerCopyIso9660Name(pszDst, pThis->uIsoLevel >= 2 ? ISO9660_MAX_NAME_LEN : 8,
     763                                                                         pszSrc, cchSrc);
     764                    else
     765                    {
     766                        const char * const pszSrcExt = &pszSrc[offLastDot + 1];
     767                        size_t       const cchSrcExt = cchSrc - offLastDot - 1;
     768                        if (pThis->uIsoLevel < 2)
     769                        {
     770                            cchDst = rtFsIsoMakerCopyIso9660Name(pszDst, 8, pszSrc, cchSrc);
     771                            offDstDot = cchDst;
     772                            pszDst[cchDst++] = '.';
     773                            cchDst += rtFsIsoMakerCopyIso9660Name(&pszDst[cchDst], 3, pszSrcExt, cchSrcExt);
     774                        }
     775                        else
     776                        {
     777                            size_t cchDstExt = rtFsIsoMakerCopyIso9660Name(pszDst, ISO9660_MAX_NAME_LEN - 2, pszSrcExt, cchSrcExt);
     778                            if (cchDstExt > 0)
     779                            {
     780                                size_t cchBasename = rtFsIsoMakerCopyIso9660Name(pszDst, ISO9660_MAX_NAME_LEN - 2,
     781                                                                                 pszSrc, offLastDot);
     782                                if (cchBasename + 1 + cchDstExt <= ISO9660_MAX_NAME_LEN)
     783                                    cchDst = cchBasename;
     784                                else
     785                                    cchDst = ISO9660_MAX_NAME_LEN - 1 - RT_MIN(cchDstExt, 4);
     786                                offDstDot = cchDst;
     787                                pszDst[cchDst++] = '.';
     788                                cchDst += rtFsIsoMakerCopyIso9660Name(pszDst, ISO9660_MAX_NAME_LEN - 1 - cchDst,
     789                                                                      pszSrcExt, cchSrcExt);
     790                            }
     791                            else
     792                                offDstDot = cchDst = rtFsIsoMakerCopyIso9660Name(pszDst, ISO9660_MAX_NAME_LEN, pszSrc, cchSrc);
     793                        }
     794                    }
     795                }
     796
     797                /*
     798                 * Unique name?
     799                 */
     800                if (!rtFsIsoMakerFindObjInDir(pParent, pszDst, cchDst))
     801                {
     802                    *pcchDst = cchDst;
     803                    return VINF_SUCCESS;
     804                }
     805
     806                /*
     807                 * Mangle the name till we've got a unique one.
     808                 */
     809                size_t const cchMaxBasename = (pThis->uIsoLevel >= 2 ? ISO9660_MAX_NAME_LEN : 8) - (cchDst - offDstDot);
     810                size_t       cchInserted = 0;
     811                for (uint32_t i = 0; i < _32K; i++)
     812                {
     813                    /* Add a numberic infix. */
     814                    char szOrd[64];
     815                    size_t cchOrd = RTStrFormatU32(szOrd, sizeof(szOrd), i + 1, 10, -1, -1, 0 /*fFlags*/);
     816                    Assert((ssize_t)cchOrd > 0);
     817
     818                    /* Do we need to shuffle the suffix? */
     819                    if (cchOrd > cchInserted)
     820                    {
     821                        if (offDstDot < cchMaxBasename)
     822                        {
     823                            memmove(&pszDst[offDstDot + 1], &pszDst[offDstDot], cchDst + 1 - offDstDot);
     824                            cchDst++;
     825                            offDstDot++;
     826                        }
     827                        cchInserted = cchOrd;
     828                    }
     829
     830                    /* Insert the new infix and try again. */
     831                    memcpy(&pszDst[offDstDot - cchOrd], szOrd, cchOrd);
     832                    if (!rtFsIsoMakerFindObjInDir(pParent, pszDst, cchDst))
     833                    {
     834                        *pcchDst = cchDst;
     835                        return VINF_SUCCESS;
     836                    }
     837                }
     838                AssertFailed();
     839                return VERR_DUPLICATE;
     840            }
     841
     842            /*
     843             * At the moment we don't give darn about UCS-2 limitations here...
     844             */
     845            case RTFSISOMAKERNAMESPACE_JOLIET:
     846            {
     847                AssertReturn(cbDst > cchSrc, VERR_BUFFER_OVERFLOW);
     848                memcpy(pszDst, pszSrc, cchSrc);
     849                pszDst[cchSrc] = '\0';
     850                *pcchDst = cchSrc;
     851                return VINF_SUCCESS;
     852            }
     853
     854            case RTFSISOMAKERNAMESPACE_UDF:
     855            case RTFSISOMAKERNAMESPACE_HFS:
     856                AssertFailedReturn(VERR_NOT_IMPLEMENTED);
     857
     858            default:
     859                AssertFailedReturn(VERR_INTERNAL_ERROR_2);
     860        }
     861    }
     862    else
     863    {
     864        /*
     865         * Root special case.
     866         */
     867        AssertReturn(pParent, VERR_INTERNAL_ERROR_3);
     868        *pszDst = '\0';
     869        *pcchDst = 0;
     870        return VINF_SUCCESS;
     871    }
     872}
     873
     874
     875static int rtFsIsoMakerPathToParent(PRTFSISOMAKERINT pThis, PRTFSISOMAKERNAME *ppRoot, uint32_t fNamespace, const char *pszPath,
     876                                    PRTFSISOMAKERNAME *ppParent, const char **ppszEntry)
     877{
     878    RT_NOREF(pThis, ppRoot, fNamespace, pszPath, ppParent, ppszEntry);
     879    return -1;
     880}
     881
     882
     883static int rtFsIsoMakerObjSetPathInOne(PRTFSISOMAKERINT pThis, PRTFSISOMAKEROBJ pEntry, uint32_t fNamespace, const char *pszPath,
     884                                       PRTFSISOMAKERNAME *ppRoot, PRTFSISOMAKERNAME *ppName)
     885{
     886    AssertReturn(!*ppName, VERR_WRONG_ORDER);
     887
     888    /*
     889     * Figure out where the parent is.
     890     * This will create missing parent name space entries and directory nodes.
     891     */
     892    PRTFSISOMAKERNAME   pParent;
     893    const char         *pszEntry;
     894    int                 rc;
     895    if (pszPath[1] != '\0')
     896        rc = rtFsIsoMakerPathToParent(pThis, ppRoot, fNamespace, pszPath, &pParent, &pszEntry);
     897    else
     898    {
     899        /*
     900         * Special case for the root directory.
     901         */
     902        AssertReturn(!*ppRoot, VERR_WRONG_ORDER);
     903        pszEntry = &pszPath[1];
     904        pParent = NULL;
     905        rc = VINF_SUCCESS;
     906        Assert(pEntry->enmType == RTFSISOMAKEROBJTYPE_DIR);
     907    }
     908    if (RT_SUCCESS(rc))
     909    {
     910        /*
     911         * .
     912         */
     913        //size_t cchEntry = strlen(pszEntry);
     914        size_t cchName;
     915        char   szName[RTFSISOMAKER_MAX_NAME_BUF];
     916        rc = rtFsIsoMakerNormalizeNameForNamespace(pThis, pParent, pszEntry, fNamespace,
     917                                                   pEntry->enmType == RTFSISOMAKEROBJTYPE_DIR, szName, sizeof(szName), &cchName);
     918        if (RT_SUCCESS(rc))
     919        {
     920
     921            //PRTFSISOMAKERNAME pNameEntry = RTMemAllocZ()
     922        }
     923    }
     924
     925    return rc;
    581926}
    582927
     
    606951    AssertReturn(!(fNamespaces & ~RTFSISOMAKERNAMESPACE_VALID_MASK), VERR_INVALID_FLAGS);
    607952    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    608     AssertReturn(RTPATH_IS_SLASH(pszPath == '/'), VERR_INVALID_NAME);
     953    AssertReturn(RTPATH_IS_SLASH(*pszPath), VERR_INVALID_NAME);
    609954    PRTFSISOMAKEROBJ pObj = rtFsIsoMakerIndexToObj(pThis, idxObj);
    610955    AssertReturn(pObj, VERR_OUT_OF_RANGE);
     
    615960    int rc = VINF_SUCCESS;
    616961    for (uint32_t i = 0; i < RT_ELEMENTS(g_aRTFsIosNamespaces); i++)
    617         if (fNamespace & g_aRTFsIosNamespaces[i].fNamespace)
     962        if (fNamespaces & g_aRTFsIosNamespaces[i].fNamespace)
    618963        {
    619             int rc2 = rtTFsIsoMakerObjSetPathInOne(pThis, pEntry, g_aRTFsIosNamespaces[i].fNamespace, pszPath,
    620                                                    (PRTFSISOMAKERNAME *)((uintptr_t)pThis + g_aRTFsIosNamespaces[i].offRoot),
    621                                                    (PRTFSISOMAKERNAMESPACE *)((uintptr_t)pEntry + g_aRTFsIosNamespaces[i].offName));
     964            int rc2 = rtFsIsoMakerObjSetPathInOne(pThis, pObj, g_aRTFsIosNamespaces[i].fNamespace, pszPath,
     965                                                  (PRTFSISOMAKERNAME *)((uintptr_t)pThis + g_aRTFsIosNamespaces[i].offRoot),
     966                                                  (PRTFSISOMAKERNAME *)((uintptr_t)pObj + g_aRTFsIosNamespaces[i].offName));
    622967            if (RT_SUCCESS(rc2) || RT_FAILURE(rc))
    623968                continue;
     
    637982 * @param   enmType             The object type.
    638983 */
    639 static void rtFsIsoMakerInitCommonObj(PRTFSISOMAKERINT pThis, PRTFSISOMAKEROBJ pObj, RTFSISOMAKEROBJTYPE enmType)
     984static int rtFsIsoMakerInitCommonObj(PRTFSISOMAKERINT pThis, PRTFSISOMAKEROBJ pObj, RTFSISOMAKEROBJTYPE enmType)
    640985{
    641986    AssertReturn(pThis->cObjects < RTFSISOMAKER_MAX_OBJECTS, VERR_OUT_OF_RANGE);
     
    6701015    PRTFSISOMAKERDIR pDir = (PRTFSISOMAKERDIR)RTMemAllocZ(sizeof(*pDir));
    6711016    AssertReturn(pDir, VERR_NO_MEMORY);
    672     int rc = rtFsIsoMakerInitCommonObj(&pDir->Core, RTFSISOMAKEROBJTYPE_DIR);
     1017    int rc = rtFsIsoMakerInitCommonObj(pThis, &pDir->Core, RTFSISOMAKEROBJTYPE_DIR);
    6731018    if (RT_SUCCESS(rc))
    6741019    {
    675         *pidxObj = pObj->idxObj;
     1020        *pidxObj = pDir->Core.idxObj;
    6761021        return VINF_SUCCESS;
    6771022    }
     
    6971042    RTFSISOMAKER_ASSER_VALID_HANDLE_RET(pThis);
    6981043    AssertPtrReturn(pszDir, VERR_INVALID_POINTER);
    699     AssertReturn(RTPATH_IS_SLASH(pszPath == '/'), VERR_INVALID_NAME);
     1044    AssertReturn(RTPATH_IS_SLASH(*pszDir), VERR_INVALID_NAME);
    7001045
    7011046    uint32_t idxObj;
     
    7031048    if (RT_SUCCESS(rc))
    7041049    {
    705         rc = RTFsIsoMakerObjSetPath(hIsoMaker, idxObj, RTFSISOMAKERNAMESPACE_ALL);
     1050        rc = RTFsIsoMakerObjSetPath(hIsoMaker, idxObj, RTFSISOMAKERNAMESPACE_ALL, pszDir);
    7061051        if (RT_SUCCESS(rc))
    7071052        {
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