VirtualBox

Ignore:
Timestamp:
Nov 30, 2010 5:46:14 PM (14 years ago)
Author:
vboxsync
Message:

Manifest comparison.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/checksum/manifest2.cpp

    r34464 r34535  
    6262    /** The attribute type if applicable, RTMANIFEST_ATTR_UNKNOWN if not. */
    6363    uint32_t            fType;
     64    /** Whether it was visited by the equals operation or not. */
     65    bool                fVisited;
    6466    /** The normalized property name that StrCore::pszString points at. */
    6567    char                szName[1];
     
    7981     *  RTMANIFESTATTR. */
    8082    RTSTRSPACE          Attributes;
     83    /** The number of attributes. */
     84    uint32_t            cAttributes;
     85    /** Whether it was visited by the equals operation or not. */
     86    bool                fVisited;
    8187    /** The normalized entry name that StrCore::pszString points at. */
    8288    char                szName[1];
     
    95101    /** The number of references to this manifest. */
    96102    uint32_t volatile   cRefs;
    97     /** Manifest attributes - RTMANIFESTATTR. */
    98     RTSTRSPACE          Attributes;
    99103    /** String space of the entries covered by this manifest -
    100104     *  RTMANIFESTENTRY. */
    101105    RTSTRSPACE          Entries;
     106    /** The number of entries. */
     107    uint32_t            cEntries;
     108    /** The entry for the manifest itself. */
     109    RTMANIFESTENTRY     SelfEntry;
    102110} RTMANIFESTINT;
    103111
     
    119127
    120128/**
     129 * Argument package used by RTManifestEqualsEx to pass it's arguments to the
     130 * enumeration callback functions.
     131 */
     132typedef struct RTMANIFESTEQUALS
     133{
     134    /** Name of entries to ignore. */
     135    const char * const *papszIgnoreEntries;
     136    /** Name of attributes to ignore. */
     137    const char * const *papszIgnoreAttr;
     138    /** Flags governing the comparision. */
     139    uint32_t            fFlags;
     140    /** Where to return an error message (++) on failure.  Can be NULL. */
     141    char               *pszError;
     142    /** The size of the buffer pszError points to.  Can be 0. */
     143    size_t              cbError;
     144
     145    /** Pointer to the 2nd manifest. */
     146    RTMANIFESTINT      *pThis2;
     147
     148    /** The number of ignored entries from the 1st manifest. */
     149    uint32_t            cIgnoredEntries2;
     150    /** The number of entries processed from the 2nd manifest. */
     151    uint32_t            cEntries2;
     152
     153    /** The number of ignored attributes from the 1st manifest. */
     154    uint32_t            cIgnoredAttributes1;
     155    /** The number of ignored attributes from the 1st manifest. */
     156    uint32_t            cIgnoredAttributes2;
     157    /** The number of attributes processed from the 2nd manifest. */
     158    uint32_t            cAttributes2;
     159    /** Pointer to the string space to get matching attributes from. */
     160    PRTSTRSPACE         pAttributes2;
     161    /** The name of the current entry.
     162     * Points to an empty string it's the manifest attributes. */
     163    const char         *pszCurEntry;
     164} RTMANIFESTEQUALS;
     165/** Pointer to an RTManifestEqualEx argument packet. */
     166typedef RTMANIFESTEQUALS *PRTMANIFESTEQUALS;
     167
     168
     169/**
    121170 * Creates an empty manifest.
    122171 *
     
    136185    pThis->u32Magic     = RTMANIFEST_MAGIC;
    137186    pThis->cRefs        = 1;
    138     pThis->Attributes   = NULL;
    139187    pThis->Entries      = NULL;
     188    pThis->cEntries     = 0;
     189    pThis->SelfEntry.StrCore.pszString = "main";
     190    pThis->SelfEntry.StrCore.cchString = 4;
     191    pThis->SelfEntry.Attributes        = 0;
     192    pThis->SelfEntry.cAttributes       = NULL;
     193    pThis->SelfEntry.fVisited          = false;
     194    pThis->SelfEntry.szName[0]         = '\0';
    140195
    141196    *phManifest = pThis;
     
    208263    {
    209264        ASMAtomicWriteU32(&pThis->u32Magic, ~RTMANIFEST_MAGIC);
    210         RTStrSpaceDestroy(&pThis->Attributes, rtManifestDestroyAttribute, pThis);
    211         RTStrSpaceDestroy(&pThis->Entries,    rtManifestDestroyEntry,    pThis);
     265        RTStrSpaceDestroy(&pThis->Entries, rtManifestDestroyEntry,pThis);
     266        RTStrSpaceDestroy(&pThis->SelfEntry.Attributes, rtManifestDestroyAttribute, pThis);
    212267        RTMemFree(pThis);
    213268    }
     
    238293
    239294
     295/**
     296 * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation.}
     297 */
     298static DECLCALLBACK(int) rtManifestAttributeClearVisited(PRTSTRSPACECORE pStr, void *pvUser)
     299{
     300    PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
     301    pAttr->fVisited = false;
     302    return 0;
     303}
     304
     305
     306/**
     307 * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation.}
     308 */
     309static DECLCALLBACK(int) rtManifestEntryClearVisited(PRTSTRSPACECORE pStr, void *pvUser)
     310{
     311    PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
     312    RTStrSpaceEnumerate(&pEntry->Attributes, rtManifestAttributeClearVisited, NULL);
     313    pEntry->fVisited = false;
     314    return 0;
     315}
     316
     317
     318/**
     319 * @callback_method_impl{FNRTSTRSPACECALLBACK, Finds the first missing.}
     320 */
     321static DECLCALLBACK(int) rtManifestAttributeFindMissing2(PRTSTRSPACECORE pStr, void *pvUser)
     322{
     323    PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
     324    PRTMANIFESTATTR   pAttr   = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
     325
     326    /*
     327     * Already visited?
     328     */
     329    if (pAttr->fVisited)
     330        return 0;
     331
     332    /*
     333     * Ignore this entry?
     334     */
     335    char const * const *ppsz = pEquals->papszIgnoreAttr;
     336    if (ppsz)
     337    {
     338        while (*ppsz)
     339        {
     340            if (!strcmp(*ppsz, pAttr->szName))
     341                return 0;
     342            ppsz++;
     343        }
     344    }
     345
     346    /*
     347     * Gotcha!
     348     */
     349    if (*pEquals->pszCurEntry)
     350        RTStrPrintf(pEquals->pszError, pEquals->cbError,
     351                    "Attribute '%s' on '%s' was not found in the 1st manifest",
     352                    pAttr->szName, pEquals->pszCurEntry);
     353    else
     354        RTStrPrintf(pEquals->pszError, pEquals->cbError, "Attribute '%s' was not found in the 1st manifest", pAttr->szName);
     355    return VERR_NOT_EQUAL;
     356}
     357
     358
     359/**
     360 * @callback_method_impl{FNRTSTRSPACECALLBACK, Finds the first missing.}
     361 */
     362static DECLCALLBACK(int) rtManifestEntryFindMissing2(PRTSTRSPACECORE pStr, void *pvUser)
     363{
     364    PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
     365    PRTMANIFESTENTRY  pEntry  = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
     366
     367    /*
     368     * Already visited?
     369     */
     370    if (pEntry->fVisited)
     371        return 0;
     372
     373    /*
     374     * Ignore this entry?
     375     */
     376    char const * const *ppsz = pEquals->papszIgnoreEntries;
     377    if (ppsz)
     378    {
     379        while (*ppsz)
     380        {
     381            if (!strcmp(*ppsz, pEntry->StrCore.pszString))
     382                return 0;
     383            ppsz++;
     384        }
     385    }
     386
     387    /*
     388     * Gotcha!
     389     */
     390    RTStrPrintf(pEquals->pszError, pEquals->cbError, "'%s' was not found in the 1st manifest", pEntry->StrCore.pszString);
     391    return VERR_NOT_EQUAL;
     392}
     393
     394
     395/**
     396 * @callback_method_impl{FNRTSTRSPACECALLBACK, Compares attributes.}
     397 */
     398static DECLCALLBACK(int) rtManifestAttributeCompare(PRTSTRSPACECORE pStr, void *pvUser)
     399{
     400    PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
     401    PRTMANIFESTATTR   pAttr1  = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
     402    PRTMANIFESTATTR   pAttr2;
     403
     404    Assert(!pAttr1->fVisited);
     405    pAttr1->fVisited = true;
     406
     407    /*
     408     * Ignore this entry?
     409     */
     410    char const * const *ppsz = pEquals->papszIgnoreAttr;
     411    if (ppsz)
     412    {
     413        while (*ppsz)
     414        {
     415            if (!strcmp(*ppsz, pAttr1->szName))
     416            {
     417                pAttr2 = (PRTMANIFESTATTR)RTStrSpaceGet(pEquals->pAttributes2, pAttr1->szName);
     418                if (pAttr2)
     419                {
     420                    Assert(!pAttr2->fVisited);
     421                    pAttr2->fVisited = true;
     422                    pEquals->cIgnoredAttributes2++;
     423                }
     424                pEquals->cIgnoredAttributes1++;
     425                return 0;
     426            }
     427            ppsz++;
     428        }
     429    }
     430
     431    /*
     432     * Find the matching attribute.
     433     */
     434    pAttr2 = (PRTMANIFESTATTR)RTStrSpaceGet(pEquals->pAttributes2, pAttr1->szName);
     435    if (!pAttr2)
     436    {
     437        if (pEquals->fFlags & RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)
     438            return 0;
     439
     440        if (*pEquals->pszCurEntry)
     441            RTStrPrintf(pEquals->pszError, pEquals->cbError,
     442                        "Attribute '%s' on '%s' was not found in the 2nd manifest",
     443                        pAttr1->szName, pEquals->pszCurEntry);
     444        else
     445            RTStrPrintf(pEquals->pszError, pEquals->cbError, "Attribute '%s' was not found in the 2nd manifest", pAttr1->szName);
     446        return VERR_NOT_EQUAL;
     447    }
     448
     449    Assert(!pAttr2->fVisited);
     450    pAttr2->fVisited = true;
     451    pEquals->cAttributes2++;
     452
     453    /*
     454     * Compare them.
     455     */
     456    if (strcmp(pAttr1->pszValue, pAttr2->pszValue))
     457    {
     458        if (*pEquals->pszCurEntry)
     459            RTStrPrintf(pEquals->pszError, pEquals->cbError,
     460                        "Attribute '%s' on '%s' does not match ('%s' vs. '%s')",
     461                        pAttr1->szName, pEquals->pszCurEntry, pAttr1->pszValue, pAttr2->pszValue);
     462        else
     463            RTStrPrintf(pEquals->pszError, pEquals->cbError,
     464                        "Attribute '%s' does not match ('%s' vs. '%s')",
     465                        pAttr1->szName, pAttr1->pszValue, pAttr2->pszValue);
     466        return VERR_NOT_EQUAL;
     467    }
     468
     469    return 0;
     470}
     471
     472
     473/**
     474 * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation.}
     475 */
     476DECLINLINE (int) rtManifestEntryCompare2(PRTMANIFESTEQUALS pEquals, PRTMANIFESTENTRY pEntry1, PRTMANIFESTENTRY pEntry2)
     477{
     478    /*
     479     * Compare the attributes.  It's a bit ugly with all this counting, but
     480     * how else to efficiently implement RTMANIFEST_EQUALS_IGN_MISSING_ATTRS?
     481     */
     482    pEquals->cIgnoredAttributes1 = 0;
     483    pEquals->cIgnoredAttributes2 = 0;
     484    pEquals->cAttributes2        = 0;
     485    pEquals->pszCurEntry         = &pEntry2->szName[0];
     486    pEquals->pAttributes2        = &pEntry2->Attributes;
     487    int rc = RTStrSpaceEnumerate(&pEntry1->Attributes, rtManifestAttributeCompare, pEquals);
     488    if (RT_SUCCESS(rc))
     489    {
     490        /*
     491         * Check that we matched all that is required.
     492         */
     493        if (   pEquals->cAttributes2 + pEquals->cIgnoredAttributes2 != pEntry2->cAttributes
     494            && (  !(pEquals->fFlags & RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)
     495                || pEquals->cIgnoredAttributes1 == pEntry1->cAttributes))
     496            rc = RTStrSpaceEnumerate(&pEntry2->Attributes, rtManifestAttributeFindMissing2, pEquals);
     497    }
     498    return rc;
     499}
     500
     501
     502/**
     503 * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation.}
     504 */
     505static DECLCALLBACK(int) rtManifestEntryCompare(PRTSTRSPACECORE pStr, void *pvUser)
     506{
     507    PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
     508    PRTMANIFESTENTRY  pEntry1 = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
     509    PRTMANIFESTENTRY  pEntry2;
     510
     511    /*
     512     * Ignore this entry.
     513     */
     514    char const * const *ppsz = pEquals->papszIgnoreEntries;
     515    if (ppsz)
     516    {
     517        while (*ppsz)
     518        {
     519            if (!strcmp(*ppsz, pStr->pszString))
     520            {
     521                pEntry2 = (PRTMANIFESTENTRY)RTStrSpaceGet(&pEquals->pThis2->Entries, pStr->pszString);
     522                if (pEntry2)
     523                {
     524                    pEntry2->fVisited = true;
     525                    pEquals->cIgnoredEntries2++;
     526                }
     527                pEntry1->fVisited = true;
     528                return 0;
     529            }
     530            ppsz++;
     531        }
     532    }
     533
     534    /*
     535     * Try find the entry in the other manifest.
     536     */
     537    pEntry2 = (PRTMANIFESTENTRY)RTStrSpaceGet(&pEquals->pThis2->Entries, pEntry1->StrCore.pszString);
     538    if (!pEntry2)
     539    {
     540        RTStrPrintf(pEquals->pszError, pEquals->cbError, "'%s' not found in the 2nd manifest", pEntry1->StrCore.pszString);
     541        return VERR_NOT_EQUAL;
     542    }
     543
     544    Assert(!pEntry1->fVisited);
     545    Assert(!pEntry2->fVisited);
     546    pEntry1->fVisited = true;
     547    pEntry2->fVisited = true;
     548    pEquals->cEntries2++;
     549
     550    return rtManifestEntryCompare2(pEquals, pEntry1, pEntry2);
     551}
     552
     553
     554
    240555RTDECL(int) RTManifestEqualsEx(RTMANIFEST hManifest1, RTMANIFEST hManifest2, const char * const *papszIgnoreEntries,
    241                                const char * const *papszIgnoreAttr, char *pszEntry, size_t cbEntry)
     556                               const char * const *papszIgnoreAttr, uint32_t fFlags, char *pszError, size_t cbError)
    242557{
    243558    /*
    244559     * Validate input.
    245560     */
    246     AssertPtrNullReturn(pszEntry, VERR_INVALID_POINTER);
    247     if (pszEntry && cbEntry)
    248         *pszEntry = '\0';
     561    AssertPtrNullReturn(pszError, VERR_INVALID_POINTER);
     562    if (pszError && cbError)
     563        *pszError = '\0';
    249564    RTMANIFESTINT *pThis1 = hManifest1;
    250     RTMANIFESTINT *pThis2 = hManifest1;
     565    RTMANIFESTINT *pThis2 = hManifest2;
    251566    if (pThis1 != NIL_RTMANIFEST)
    252567    {
     
    259574        AssertReturn(pThis2->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
    260575    }
     576    AssertReturn(!(fFlags & ~(RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)), VERR_INVALID_PARAMETER);
    261577
    262578    /*
     
    269585
    270586    /*
    271      *
    272      */
    273 
    274 
    275     /** @todo implement comparing. */
    276 
    277     return VERR_NOT_IMPLEMENTED;
     587     * Since we have to use callback style enumeration, we have to mark the
     588     * entries and attributes to make sure we've covered them all.
     589     */
     590    RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryClearVisited, NULL);
     591    RTStrSpaceEnumerate(&pThis2->Entries, rtManifestEntryClearVisited, NULL);
     592    RTStrSpaceEnumerate(&pThis1->SelfEntry.Attributes, rtManifestAttributeClearVisited, NULL);
     593    RTStrSpaceEnumerate(&pThis2->SelfEntry.Attributes, rtManifestAttributeClearVisited, NULL);
     594
     595    RTMANIFESTEQUALS Equals;
     596    Equals.pThis2               = pThis2;
     597    Equals.fFlags               = fFlags;
     598    Equals.papszIgnoreEntries   = papszIgnoreEntries;
     599    Equals.papszIgnoreAttr      = papszIgnoreAttr;
     600    Equals.pszError             = pszError;
     601    Equals.cbError              = cbError;
     602
     603    Equals.cIgnoredEntries2     = 0;
     604    Equals.cEntries2            = 0;
     605    Equals.cIgnoredAttributes1  = 0;
     606    Equals.cIgnoredAttributes2  = 0;
     607    Equals.cAttributes2         = 0;
     608    Equals.pAttributes2         = NULL;
     609    Equals.pszCurEntry          = NULL;
     610
     611    int rc = rtManifestEntryCompare2(&Equals, &pThis1->SelfEntry, &pThis2->SelfEntry);
     612    if (RT_SUCCESS(rc))
     613        rc = RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryCompare, &Equals);
     614    if (RT_SUCCESS(rc))
     615    {
     616        /*
     617         * Did we cover all entries of the 2nd manifest?
     618         */
     619        if (Equals.cEntries2 + Equals.cIgnoredEntries2 != pThis2->cEntries)
     620            rc = RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryFindMissing2, &Equals);
     621    }
     622
     623    return rc;
    278624}
    279625
     
    281627RTDECL(int) RTManifestEquals(RTMANIFEST hManifest1, RTMANIFEST hManifest2)
    282628{
    283     return RTManifestEqualsEx(hManifest1, hManifest2, NULL /*papszIgnoreEntries*/, NULL /*papszIgnoreAttrs*/, NULL, 0);
     629    return RTManifestEqualsEx(hManifest1, hManifest2,
     630                              NULL /*papszIgnoreEntries*/, NULL /*papszIgnoreAttrs*/,
     631                              0 /*fFlags*/, NULL, 0);
    284632}
    285633
     
    289637 *
    290638 * @returns IPRT status code.
    291  * @param   pAttributes         The attribute container.
     639 * @param   pEntry              Pointer to the entry.
    292640 * @param   pszAttr             The name of the attribute to add.
    293641 * @param   pszValue            The value string.
    294642 * @param   fType               The attribute type type.
    295643 */
    296 static int rtManifestSetAttrWorker(PRTSTRSPACE pAttributes, const char *pszAttr, const char *pszValue, uint32_t fType)
     644static int rtManifestSetAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr, const char *pszValue, uint32_t fType)
    297645{
    298646    char *pszValueCopy;
     
    305653     */
    306654    AssertCompileMemberOffset(RTMANIFESTATTR, StrCore, 0);
    307     PRTMANIFESTATTR pAttr = (PRTMANIFESTATTR)RTStrSpaceGet(pAttributes, pszAttr);
     655    PRTMANIFESTATTR pAttr = (PRTMANIFESTATTR)RTStrSpaceGet(&pEntry->Attributes, pszAttr);
    308656    if (pAttr)
    309657    {
     
    326674        pAttr->pszValue = pszValueCopy;
    327675        pAttr->fType    = fType;
    328         if (RT_UNLIKELY(!RTStrSpaceInsert(pAttributes, &pAttr->StrCore)))
     676        if (RT_UNLIKELY(!RTStrSpaceInsert(&pEntry->Attributes, &pAttr->StrCore)))
    329677        {
    330678            AssertFailed();
     
    333681            return VERR_INTERNAL_ERROR_4;
    334682        }
     683        pEntry->cAttributes++;
    335684    }
    336685
     
    359708    AssertReturn(RT_IS_POWER_OF_TWO(fType) && fType < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
    360709
    361     return rtManifestSetAttrWorker(&pThis->Attributes, pszAttr, pszValue, fType);
     710    return rtManifestSetAttrWorker(&pThis->SelfEntry, pszAttr, pszValue, fType);
    362711}
    363712
     
    367716 *
    368717 * @returns IPRT status code.
    369  * @param   pAttributes         The attribute container.
     718 * @param   pEntry              Pointer to the entry.
    370719 * @param   pszAttr             The name of the attribute to remove.
    371720 */
    372 static int rtManifestUnsetAttrWorker(PRTSTRSPACE pAttributes, const char *pszAttr)
    373 {
    374     PRTSTRSPACECORE pStrCore = RTStrSpaceRemove(pAttributes, pszAttr);
     721static int rtManifestUnsetAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr)
     722{
     723    PRTSTRSPACECORE pStrCore = RTStrSpaceRemove(&pEntry->Attributes, pszAttr);
    375724    if (!pStrCore)
    376725        return VWRN_NOT_FOUND;
     726    pEntry->cAttributes--;
    377727    rtManifestDestroyAttribute(pStrCore, NULL);
    378728    return VINF_SUCCESS;
     
    396746    AssertPtr(pszAttr);
    397747
    398     return rtManifestUnsetAttrWorker(&pThis->Attributes, pszAttr);
     748    return rtManifestUnsetAttrWorker(&pThis->SelfEntry, pszAttr);
    399749}
    400750
     
    420770        rc = RTStrGetCpEx(&pszCur, &uc);
    421771        if (RT_FAILURE(rc))
    422             break;
     772            return rc;
    423773        if (!uc)
    424774            break;
     
    426776            fNeedNormalization = true;
    427777        else if (uc < 32 || uc == ':' || uc == '(' || uc == ')')
    428         {
    429             rc = VERR_INVALID_NAME;
    430             break;
    431         }
     778            return VERR_INVALID_NAME;
    432779    }
    433780
    434781    if (pfNeedNormalization)
    435782        *pfNeedNormalization = fNeedNormalization;
     783
     784    size_t cchEntry = pszCur - pszEntry - 1;
     785    if (!cchEntry)
     786        rc = VERR_INVALID_NAME;
    436787    if (pcchEntry)
    437         *pcchEntry = pszCur - pszEntry - 1;
     788        *pcchEntry = cchEntry;
     789
    438790    return rc;
    439791}
     
    547899            return VERR_INTERNAL_ERROR_4;
    548900        }
     901        pThis->cEntries++;
    549902    }
    550903    else if (RT_FAILURE(rc))
    551904        return rc;
    552905
    553     return rtManifestSetAttrWorker(&pEntry->Attributes, pszAttr, pszValue, fType);
     906    return rtManifestSetAttrWorker(pEntry, pszAttr, pszValue, fType);
    554907}
    555908
     
    584937    rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
    585938    if (RT_SUCCESS(rc))
    586         rc = rtManifestUnsetAttrWorker(&pEntry->Attributes, pszAttr);
     939        rc = rtManifestUnsetAttrWorker(pEntry, pszAttr);
    587940    return rc;
    588941}
     
    640993
    641994            if (RTStrSpaceInsert(&pThis->Entries, &pEntry->StrCore))
     995            {
     996                pThis->cEntries++;
    642997                rc = VINF_SUCCESS;
     998            }
    643999            else
    6441000            {
     
    6851041        PRTSTRSPACECORE pStrCore = RTStrSpaceRemove(&pThis->Entries, pEntry->StrCore.pszString);
    6861042        AssertReturn(pStrCore, VERR_INTERNAL_ERROR_3);
     1043        pThis->cEntries--;
    6871044        rtManifestDestroyEntry(pStrCore, pThis);
    6881045    }
     
    9611318    Args.hVfsIos  = hVfsIos;
    9621319    Args.pszEntry = "main";
    963     int rc = RTStrSpaceEnumerate(&pThis->Attributes, rtManifestWriteStdAttr, &Args);
     1320    int rc = RTStrSpaceEnumerate(&pThis->SelfEntry.Attributes, rtManifestWriteStdAttr, &Args);
    9641321    if (RT_SUCCESS(rc))
    9651322        rc = RTStrSpaceEnumerate(&pThis->Entries, rtManifestWriteStdEntry, hVfsIos);
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