static void _copy_keys_into(
	SG_context* pCtx,
    SG_vhash* pvh_list,
    SG_vhash* pvh_blobs
    )
{
    SG_uint32 count = 0;
    SG_uint32 i = 0;

    SG_ERR_CHECK(  SG_vhash__count(pCtx, pvh_list, &count)  );
    for (i=0; i<count; i++)
    {
        const char* psz = NULL;

        SG_ERR_CHECK(  SG_vhash__get_nth_pair(pCtx, pvh_list, i, &psz, NULL)  );
        SG_ERR_CHECK(  SG_vhash__update__null(pCtx, pvh_blobs, psz)  );
    }

fail:
    ;
}
Esempio n. 2
0
/**
 * Add to the fragball request vhash (see SG_server_prototypes.h for format).
 */
void SG_pull__add(
	SG_context* pCtx,
	SG_pull* pPull,
	SG_uint32 iDagnum,
	SG_rbtree* prbDagnodes,
	SG_rbtree* prbTags,
	SG_rbtree* prbDagnodePrefixes)
{
	_sg_pull* pMyPull = NULL;
	char bufDagnum[SG_DAGNUM__BUF_MAX__DEC];
	SG_bool found = SG_FALSE;
	SG_vhash* pvhDags = NULL; // Needs to be freed
	SG_vhash* pvhDagsRef = NULL; // Does not need to be freed, owned by parent vhash
	SG_vhash* pvhDagnum = NULL; // Needs to be freed
	SG_vhash* pvhDagnumRef = NULL; // Does not need to be freed, owned by parent vhash
	SG_rbtree_iterator* pit = NULL;

	SG_NULLARGCHECK_RETURN(pPull);
	SG_ARGCHECK_RETURN(iDagnum, iDagnum);
	pMyPull = (_sg_pull*)pPull;

	if (!pMyPull->pvhFragballRequest)
		SG_ERR_CHECK(  SG_VHASH__ALLOC(pCtx, &pMyPull->pvhFragballRequest)  );

	SG_ERR_CHECK(  SG_dagnum__to_sz__decimal(pCtx, iDagnum, bufDagnum, sizeof(bufDagnum))  );

	/* Get dagnum vhash, adding it if necessary. */
	SG_ERR_CHECK(  SG_vhash__has(pCtx, pMyPull->pvhFragballRequest, SG_SYNC_STATUS_KEY__DAGS, &found)  );
	if (found)
		SG_ERR_CHECK(  SG_vhash__get__vhash(pCtx, pMyPull->pvhFragballRequest, SG_SYNC_STATUS_KEY__DAGS, &pvhDagsRef)  );
	else
	{
		SG_ERR_CHECK(  SG_VHASH__ALLOC(pCtx, &pvhDags)  );
		pvhDagsRef = pvhDags;
		SG_ERR_CHECK(  SG_vhash__add__vhash(pCtx, pMyPull->pvhFragballRequest, SG_SYNC_STATUS_KEY__DAGS, &pvhDags)  );
	}
	
	SG_ERR_CHECK(  SG_vhash__has(pCtx, pvhDagsRef, bufDagnum, &found)  );
	if (found)
		SG_ERR_CHECK(  SG_vhash__get__vhash(pCtx, pvhDagsRef, bufDagnum, &pvhDagnumRef)  );
	
	if (!pvhDagnumRef)
	{
		SG_ERR_CHECK(  SG_VHASH__ALLOC(pCtx, &pvhDagnum)  );
		pvhDagnumRef = pvhDagnum;
		SG_ERR_CHECK(  SG_vhash__add__vhash(pCtx, pvhDagsRef, bufDagnum, &pvhDagnum)  );
	}

	/* If dagnodes were provided, add them to the dagnum vhash */
	if (prbDagnodes)
	{
		const char* pszHid;
		SG_ERR_CHECK(  SG_rbtree__iterator__first(pCtx, &pit, prbDagnodes, &found, &pszHid, NULL)  );
		while (found)
		{
			SG_ERR_CHECK(  SG_vhash__update__null(pCtx, pvhDagnumRef, pszHid)  );
			SG_ERR_CHECK(  SG_rbtree__iterator__next(pCtx, pit, &found, &pszHid, NULL)  );
		}
		SG_RBTREE_ITERATOR_NULLFREE(pCtx, pit);
	}	
	/* If tags were provided, add them to the dagnum vhash */
	if (prbTags)
	{
		const char* pszTag;
		SG_ERR_CHECK(  SG_rbtree__iterator__first(pCtx, &pit, prbTags, &found, &pszTag, NULL)  );
		while (found)
		{
			SG_ERR_CHECK(  SG_vhash__update__string__sz(pCtx, pvhDagnumRef, pszTag, SG_SYNC_REQUEST_VALUE_TAG)  );
			SG_ERR_CHECK(  SG_rbtree__iterator__next(pCtx, pit, &found, &pszTag, NULL)  );
		}
		SG_RBTREE_ITERATOR_NULLFREE(pCtx, pit);
	}	
	/* If dagnode hid prefixes were provided, add them to the dagnum vhash */
	if (prbDagnodePrefixes)
	{
		const char* pszHidPrefix;
		SG_ERR_CHECK(  SG_rbtree__iterator__first(pCtx, &pit, prbDagnodePrefixes, &found, &pszHidPrefix, NULL)  );
		while (found)
		{
			SG_ERR_CHECK(  SG_vhash__update__string__sz(pCtx, pvhDagnumRef, pszHidPrefix, SG_SYNC_REQUEST_VALUE_HID_PREFIX)  );
			SG_ERR_CHECK(  SG_rbtree__iterator__next(pCtx, pit, &found, &pszHidPrefix, NULL)  );
		}
		SG_RBTREE_ITERATOR_NULLFREE(pCtx, pit);
	}	

	return;

fail:
	SG_VHASH_NULLFREE(pCtx, pvhDagnum);
	SG_VHASH_NULLFREE(pCtx, pvhDags);
	SG_RBTREE_ITERATOR_NULLFREE(pCtx, pit);
}
static void _add_necessary_blobs(
	SG_context* pCtx,
    SG_changeset* pcs,
    SG_vhash* pvh_blobs
    )
{
    SG_uint64 dagnum = 0;

    SG_ERR_CHECK(  SG_changeset__get_dagnum(pCtx, pcs, &dagnum)  );
    if (SG_DAGNUM__IS_DB(dagnum))
    {
        SG_vhash* pvh_changes = NULL;
        SG_uint32 count_parents = 0;
        SG_uint32 i_parent = 0;

        SG_ERR_CHECK(  SG_changeset__db__get_changes(pCtx, pcs, &pvh_changes)  );
        SG_ERR_CHECK(  SG_vhash__count(pCtx, pvh_changes, &count_parents)  );
        for (i_parent=0; i_parent<count_parents; i_parent++)
        {
            SG_vhash* pvh_changes_for_one_parent = NULL;
            SG_vhash* pvh_add = NULL;

            SG_ERR_CHECK(  SG_vhash__get_nth_pair__vhash(pCtx, pvh_changes, i_parent, NULL, &pvh_changes_for_one_parent)  );
            SG_ERR_CHECK(  SG_vhash__check__vhash(pCtx, pvh_changes_for_one_parent, "add", &pvh_add)  );
            if (pvh_add)
            {
                SG_ERR_CHECK(  _copy_keys_into(pCtx, pvh_add, pvh_blobs)  );
            }

            pvh_add = NULL;
            SG_ERR_CHECK(  SG_vhash__check__vhash(pCtx, pvh_changes_for_one_parent, "attach_add", &pvh_add)  );
            if (pvh_add)
            {
                SG_ERR_CHECK(  _copy_keys_into(pCtx, pvh_add, pvh_blobs)  );
            }
        }
        if (!SG_DAGNUM__HAS_HARDWIRED_TEMPLATE(dagnum))
        {
            const char* psz_hid_template = NULL;

            SG_ERR_CHECK(  SG_changeset__db__get_template(pCtx, pcs, &psz_hid_template)  );

            SG_ERR_CHECK(  SG_vhash__update__null(pCtx, pvh_blobs, psz_hid_template)  );
        }
    }

    if (SG_DAGNUM__IS_TREE(dagnum))
    {
        SG_vhash* pvh_changes = NULL;
        const char* psz_root = NULL;
        SG_uint32 count_parents = 0;
        SG_uint32 i_parent = 0;

        SG_ERR_CHECK(  SG_changeset__tree__get_root(pCtx, pcs, &psz_root)  );
        SG_ERR_CHECK(  SG_vhash__update__null(pCtx, pvh_blobs, psz_root)  );

        SG_ERR_CHECK(  SG_changeset__tree__get_changes(pCtx, pcs, &pvh_changes)  );
        SG_ERR_CHECK(  SG_vhash__count(pCtx, pvh_changes, &count_parents)  );
        for (i_parent=0; i_parent<count_parents; i_parent++)
        {
            SG_vhash* pvh_changes_for_one_parent = NULL;
            SG_uint32 count_gids = 0;
            SG_uint32 i_gid = 0;

            SG_ERR_CHECK(  SG_vhash__get_nth_pair__vhash(pCtx, pvh_changes, i_parent, NULL, &pvh_changes_for_one_parent)  );

            SG_ERR_CHECK(  SG_vhash__count(pCtx, pvh_changes_for_one_parent, &count_gids)  );
            for (i_gid=0; i_gid<count_gids; i_gid++)
            {
                const char* psz_hid = NULL;
                const SG_variant* pv = NULL;

                SG_ERR_CHECK(  SG_vhash__get_nth_pair(pCtx, pvh_changes_for_one_parent, i_gid, NULL, &pv)  );
                if (SG_VARIANT_TYPE_VHASH == pv->type)
                {
                    SG_vhash* pvh_info = NULL;

                    SG_ERR_CHECK(  SG_variant__get__vhash(pCtx, pv, &pvh_info)  );
                    SG_ERR_CHECK(  SG_vhash__check__sz(pCtx, pvh_info, SG_CHANGEESET__TREE__CHANGES__HID, &psz_hid)  );
                    if (psz_hid)
                    {
                        SG_ERR_CHECK(  SG_vhash__update__null(pCtx, pvh_blobs, psz_hid)  );
                    }
                }
            }
        }
    }

fail:
    ;
}
static void loop_innards_make_delta(
    SG_context* pCtx,
    SG_repo* pRepo,
    SG_varray* pva_path,
    SG_uint32 i_path_step,
    SG_vhash* pvh_add,
    SG_vhash* pvh_remove
    )
{
    SG_changeset* pcs = NULL;

    const char* psz_csid_cur = NULL;
    const char* psz_csid_parent = NULL;
    SG_vhash* pvh_changes = NULL;
    SG_vhash* pvh_one_parent_changes = NULL;
    SG_vhash* pvh_cs_add = NULL;
    SG_vhash* pvh_cs_remove = NULL;

    SG_ERR_CHECK(  SG_varray__get__sz(pCtx, pva_path, i_path_step, &psz_csid_cur)  );
    SG_ERR_CHECK(  SG_varray__get__sz(pCtx, pva_path, i_path_step + 1, &psz_csid_parent)  );
    SG_ERR_CHECK(  SG_changeset__load_from_repo(pCtx, pRepo, psz_csid_cur, &pcs)  );

    SG_ERR_CHECK(  SG_changeset__db__get_changes(pCtx, pcs, &pvh_changes)  );

    SG_ERR_CHECK(  SG_vhash__get__vhash(pCtx, pvh_changes, psz_csid_parent, &pvh_one_parent_changes)  );

    SG_ERR_CHECK(  SG_vhash__check__vhash(pCtx, pvh_one_parent_changes, "add", &pvh_cs_remove)  );
    SG_ERR_CHECK(  SG_vhash__check__vhash(pCtx, pvh_one_parent_changes, "remove", &pvh_cs_add)  );

    if (pvh_cs_add)
    {
        SG_uint32 count = 0;
        SG_uint32 i = 0;

        SG_ERR_CHECK(  SG_vhash__count(pCtx, pvh_cs_add, &count)  );
        for (i=0; i<count; i++)
        {
            const char* psz_hid_rec = NULL;
            SG_bool b = SG_FALSE;

            SG_ERR_CHECK(  SG_vhash__get_nth_pair(pCtx, pvh_cs_add, i, &psz_hid_rec, NULL)  );
            SG_ERR_CHECK(  SG_vhash__remove_if_present(pCtx, pvh_remove, psz_hid_rec, &b)  );
            if (!b)
            {
                SG_ERR_CHECK(  SG_vhash__update__null(pCtx, pvh_add, psz_hid_rec)  );
            }
        }
    }

    if (pvh_cs_remove)
    {
        SG_uint32 count = 0;
        SG_uint32 i = 0;

        SG_ERR_CHECK(  SG_vhash__count(pCtx, pvh_cs_remove, &count)  );
        for (i=0; i<count; i++)
        {
            const char* psz_hid_rec = NULL;
            SG_bool b = SG_FALSE;

            SG_ERR_CHECK(  SG_vhash__get_nth_pair(pCtx, pvh_cs_remove, i, &psz_hid_rec, NULL)  );
            SG_ERR_CHECK(  SG_vhash__remove_if_present(pCtx, pvh_add, psz_hid_rec, &b)  );
            if (!b)
            {
                SG_ERR_CHECK(  SG_vhash__update__null(pCtx, pvh_remove, psz_hid_rec)  );
            }
        }
    }


fail:
    SG_CHANGESET_NULLFREE(pCtx, pcs);
}
/**
 * We get called once for each input in the stringarray
 * of files to unlock.
 *
 * Validate it and find the item's GID and add it to
 * the given VHASH.
 *
 * TODO 2012/03/02 This is a little different from the
 * TODO            version in sg_wc__lock.c.  Is this
 * TODO            really necessary.
 *
 */
static void _map_input(SG_context * pCtx,
                       SG_wc_tx * pWcTx,
                       SG_vhash * pvh_gids,
                       const char * pszInput)
{
    SG_string * pStringRepoPath = NULL;
    char * pszGid = NULL;
    sg_wc_liveview_item * pLVI;		// we do not own this
    SG_wc_status_flags statusFlags;
    SG_bool bKnown;
    char cDomain;

    SG_NONEMPTYCHECK_RETURN( pszInput );	// throw if omitted, do not assume "@/".

    SG_ERR_CHECK(  sg_wc_db__path__anything_to_repopath(pCtx, pWcTx->pDb, pszInput,
                   SG_WC_DB__PATH__IMPORT_FLAGS__TREAT_NULL_AS_ERROR,
                   &pStringRepoPath, &cDomain)  );
#if TRACE_WC_LOCK
    SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
                               "SG_wc__unlock: '%s' normalized to [domain %c] '%s'\n",
                               pszInput, cDomain, SG_string__sz(pStringRepoPath))  );
#endif

    // find the GID/alias of the named item while taking
    // account whatever domain component.  (that is, they
    // could have said "@g12345...." or "@b/....." rather
    // than a live path.)
    //
    // Fetch the LVI for this item.  This may implicitly
    // cause a SCANDIR/READIR and/or sync up with the DB.
    // This is good because it also means we will get the
    // exact-match stuff on each component within the
    // pathname.

    SG_ERR_CHECK(  sg_wc_tx__liveview__fetch_item__domain(pCtx, pWcTx, pStringRepoPath,
                   &bKnown, &pLVI)  );
    if (!bKnown)
    {
        // We only get this if the path is completely bogus and
        // took us off into the weeds (as opposed to reporting
        // something just not-controlled).
        SG_ERR_THROW2(  SG_ERR_NOT_FOUND,
                        (pCtx, "Unknown item '%s'.", SG_string__sz(pStringRepoPath))  );
    }

    if (pLVI->tneType != SG_TREENODEENTRY_TYPE_REGULAR_FILE)
        SG_ERR_THROW2(  SG_ERR_VC_LOCK_FILES_ONLY,
                        (pCtx, "%s", pszInput)  );

    SG_ERR_CHECK(  sg_wc__status__compute_flags(pCtx, pWcTx, pLVI,
                   SG_TRUE,	// --no-ignores (faster)
                   SG_FALSE,	// trust TSC
                   &statusFlags)  );
    if (statusFlags & (SG_WC_STATUS_FLAGS__U__FOUND
                       |SG_WC_STATUS_FLAGS__U__IGNORED))
        SG_ERR_THROW2(  SG_ERR_ITEM_NOT_UNDER_VERSION_CONTROL,
                        (pCtx, "%s", pszInput)  );
    // TODO 2012/03/02 Not sure checking for __S__ADDED is needed on an unlock.
    if (statusFlags & SG_WC_STATUS_FLAGS__S__ADDED)
        SG_ERR_THROW2(  SG_ERR_VC_LOCK_NOT_COMMITTED_YET,
                        (pCtx, "%s", pszInput)  );

    SG_ERR_CHECK(  sg_wc_db__gid__get_gid_from_alias(pCtx, pWcTx->pDb, pLVI->uiAliasGid, &pszGid)  );
    SG_ASSERT_RELEASE_FAIL2(  (pszGid[0] == 'g'),	// we get 't' domain IDs for uncontrolled items
                              (pCtx, "%s has temp id %s", pszInput, pszGid)  );

    // TODO 2012/03/02 The original PendingTree version of the
    // TODO            code did a SG_vhash__add__null() which
    // TODO            will throw on duplicates.  I'm going to
    // TODO            soften that.

    SG_ERR_CHECK(  SG_vhash__update__null(pCtx, pvh_gids, pszGid)  );

fail:
    SG_STRING_NULLFREE(pCtx, pStringRepoPath);
    SG_NULLFREE(pCtx, pszGid);
}