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: ; }
/** * 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); }