void SG_user__get_email_for_repo(SG_context * pCtx, SG_repo* pRepo, const char ** ppsz_email) { char * psz_admin_id = NULL; char * psz_userid = NULL; const char * psz_email_temp = NULL; SG_string * pstr_path = NULL; SG_vhash * pvh_userhash = NULL; if (pRepo) { SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &psz_admin_id) ); // we store this userid under the admin scope of the repo we were given SG_ERR_CHECK( SG_string__alloc__format(pCtx, &pstr_path, "%s/%s/%s", SG_LOCALSETTING__SCOPE__ADMIN, psz_admin_id, SG_LOCALSETTING__USERID ) ); SG_ERR_CHECK( SG_localsettings__get__sz(pCtx, SG_string__sz(pstr_path), pRepo, &psz_userid, NULL) ); if (psz_userid == NULL || *psz_userid == 0) SG_ERR_THROW(SG_ERR_USER_NOT_FOUND); SG_ERR_CHECK( SG_user__lookup_by_userid(pCtx, pRepo, psz_userid, &pvh_userhash) ); SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_userhash, "email", &psz_email_temp) ); SG_ERR_CHECK( SG_STRDUP(pCtx, psz_email_temp, (char**)ppsz_email) ); } fail: SG_VHASH_NULLFREE(pCtx, pvh_userhash); SG_NULLFREE(pCtx, psz_admin_id); SG_NULLFREE(pCtx, psz_userid); SG_STRING_NULLFREE(pCtx, pstr_path); }
void SG_sync_remote__heartbeat( SG_context* pCtx, SG_repo* pRepo, SG_vhash** ppvh) { SG_vhash* pvh = NULL; char* pszRepoId = NULL; char* pszAdminId = NULL; char* pszHashMethod = NULL; SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvh) ); SG_ERR_CHECK( SG_repo__get_repo_id(pCtx, pRepo, &pszRepoId) ); SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &pszAdminId) ); SG_ERR_CHECK( SG_repo__get_hash_method(pCtx, pRepo, &pszHashMethod) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh, SG_SYNC_REPO_INFO_KEY__REPO_ID, pszRepoId) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh, SG_SYNC_REPO_INFO_KEY__ADMIN_ID, pszAdminId) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh, SG_SYNC_REPO_INFO_KEY__HASH_METHOD, pszHashMethod) ); *ppvh = pvh; pvh = NULL; /* fall through */ fail: SG_VHASH_NULLFREE(pCtx, pvh); SG_NULLFREE(pCtx, pszRepoId); SG_NULLFREE(pCtx, pszAdminId); SG_NULLFREE(pCtx, pszHashMethod); }
void SG_user__set_user__repo( SG_context* pCtx, SG_repo* pRepo, const char* psz_email ) { SG_vhash* pvh_user = NULL; char* psz_admin_id = NULL; const char* psz_userid = NULL; SG_string* pstr_path = NULL; SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pstr_path) ); if (pRepo) { SG_ERR_CHECK( SG_user__lookup_by_email(pCtx, pRepo, psz_email, &pvh_user) ); if (!pvh_user) { SG_ERR_THROW( SG_ERR_USER_NOT_FOUND ); } SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_user, SG_ZING_FIELD__RECID, &psz_userid) ); SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &psz_admin_id) ); // we store this userid under the admin scope of the repo we were given SG_ERR_CHECK( SG_string__sprintf(pCtx, pstr_path, "%s/%s/%s", SG_LOCALSETTING__SCOPE__ADMIN, psz_admin_id, SG_LOCALSETTING__USERID ) ); SG_ERR_CHECK( SG_localsettings__update__sz(pCtx, SG_string__sz(pstr_path), psz_userid) ); } // AND we store this email address in machine scope for fallback lookups SG_ERR_CHECK( SG_string__sprintf(pCtx, pstr_path, "%s/%s", SG_LOCALSETTING__SCOPE__MACHINE, SG_LOCALSETTING__USEREMAIL ) ); SG_ERR_CHECK( SG_localsettings__update__sz(pCtx, SG_string__sz(pstr_path), psz_email) ); fail: SG_STRING_NULLFREE(pCtx, pstr_path); SG_NULLFREE(pCtx, psz_admin_id); SG_VHASH_NULLFREE(pCtx, pvh_user); }
void SG_server__get_repo_info(SG_context* pCtx, SG_repo* pRepo, char** ppszRepoId, char** ppszAdminId, char** ppszHashMethod) { char* pszRepoId = NULL; char* pszAdminId = NULL; char* pszHashMethod = NULL; SG_NULLARGCHECK_RETURN(pRepo); if (ppszRepoId) SG_ERR_CHECK( SG_repo__get_repo_id(pCtx, pRepo, &pszRepoId) ); if (ppszAdminId) SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &pszAdminId) ); if (ppszHashMethod) SG_ERR_CHECK( SG_repo__get_hash_method(pCtx, pRepo, &pszHashMethod) ); if (ppszRepoId) { *ppszRepoId = pszRepoId; pszRepoId = NULL; } if (ppszAdminId) { *ppszAdminId = pszAdminId; pszAdminId = NULL; } if (ppszHashMethod) { *ppszHashMethod = pszHashMethod; pszHashMethod = NULL; } /* fall through */ fail: SG_NULLFREE(pCtx, pszRepoId); SG_NULLFREE(pCtx, pszAdminId); SG_NULLFREE(pCtx, pszHashMethod); }
/** * Create a new repo in the closet. */ static void _vv_verbs__init_new_repo__do_init(SG_context * pCtx, const char * pszRepoName, const char * pszStorage, const char * pszHashMethod, const char * psz_shared_users, SG_bool bFromUserMaster, char ** ppszGidRepoId, char ** ppszHidCSetFirst) { SG_repo * pRepo = NULL; SG_repo * pRepoUserMaster = NULL; char * pszUserMasterAdminId = NULL; SG_changeset * pCSetFirst = NULL; const char * pszHidCSetFirst_ref; char * pszHidCSetFirst = NULL; char * pszGidRepoId = NULL; char bufAdminId[SG_GID_BUFFER_LENGTH]; // create a completely new repo in the closet. SG_NULLARGCHECK_RETURN( pszRepoName ); // pszStorage is optional // pszHashMethod is optional SG_ASSERT(SG_FALSE == (psz_shared_users && bFromUserMaster)); // checked in SG_vv_verbs__init_new_repo if (psz_shared_users) { SG_ERR_CHECK( _vv_verbs__init_new_repo__get_admin_id(pCtx, psz_shared_users, bufAdminId) ); } else if (bFromUserMaster) { SG_ERR_CHECK( SG_REPO__USER_MASTER__OPEN(pCtx, &pRepoUserMaster) ); SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepoUserMaster, &pszUserMasterAdminId) ); memcpy(bufAdminId, pszUserMasterAdminId, sizeof(bufAdminId)); //SG_memcpy2(pszUserMasterAdminId, bufAdminId); SG_NULLFREE(pCtx, pszUserMasterAdminId); } else { SG_ERR_CHECK( SG_gid__generate(pCtx, bufAdminId, sizeof(bufAdminId)) ); } SG_ERR_CHECK( SG_repo__create__completely_new__empty__closet(pCtx, bufAdminId, pszStorage, pszHashMethod, pszRepoName) ); SG_ERR_CHECK( SG_REPO__OPEN_REPO_INSTANCE(pCtx, pszRepoName, &pRepo) ); if (!psz_shared_users && !bFromUserMaster) { SG_ERR_CHECK( SG_user__create_nobody(pCtx, pRepo) ); } SG_ERR_CHECK( SG_repo__setup_basic_stuff(pCtx, pRepo, &pCSetFirst, NULL) ); if (psz_shared_users) { SG_ERR_CHECK( SG_pull__admin(pCtx, pRepo, psz_shared_users, NULL, NULL, NULL, NULL) ); } else if (bFromUserMaster) { SG_ERR_CHECK( SG_pull__admin__local(pCtx, pRepo, pRepoUserMaster, NULL) ); } SG_ERR_CHECK( SG_changeset__get_id_ref(pCtx, pCSetFirst, &pszHidCSetFirst_ref) ); SG_ERR_CHECK( SG_STRDUP(pCtx, pszHidCSetFirst_ref, &pszHidCSetFirst) ); SG_ERR_CHECK( SG_repo__get_repo_id(pCtx, pRepo, &pszGidRepoId) ); *ppszGidRepoId = pszGidRepoId; *ppszHidCSetFirst = pszHidCSetFirst; SG_REPO_NULLFREE(pCtx, pRepo); SG_REPO_NULLFREE(pCtx, pRepoUserMaster); SG_CHANGESET_NULLFREE(pCtx, pCSetFirst); return; fail: /* If we fail to pull the admin dags after the repo's been created, delete it. */ if (pRepo) { SG_REPO_NULLFREE(pCtx, pRepo); if (pszRepoName) SG_ERR_IGNORE( _vv_verbs__init_new_repo__delete_new_repo(pCtx, pszRepoName) ); } SG_REPO_NULLFREE(pCtx, pRepoUserMaster); SG_CHANGESET_NULLFREE(pCtx, pCSetFirst); SG_NULLFREE(pCtx, pszGidRepoId); SG_NULLFREE(pCtx, pszHidCSetFirst); }
void SG_sync_remote__get_repo_info( SG_context* pCtx, SG_repo* pRepo, SG_bool bIncludeBranches, SG_bool b_include_areas, SG_vhash** ppvh) { SG_vhash* pvh = NULL; char* pszRepoId = NULL; char* pszAdminId = NULL; char* pszHashMethod = NULL; SG_uint32 count_dagnums = 0; SG_uint64* paDagNums = NULL; SG_uint32 i = 0; SG_vhash* pvh_dags = NULL; SG_vhash* pvh_areas = NULL; SG_vhash* pvhBranchPile = NULL; SG_bool bHasBranchDag = SG_FALSE; SG_NULLARGCHECK_RETURN(pRepo); SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvh) ); /* Protocol version */ SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pvh, SG_SYNC_REPO_INFO_KEY__PROTOCOL_VERSION, 1) ); /* Basic repository info */ SG_ERR_CHECK( SG_repo__get_repo_id(pCtx, pRepo, &pszRepoId) ); SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &pszAdminId) ); SG_ERR_CHECK( SG_repo__get_hash_method(pCtx, pRepo, &pszHashMethod) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh, SG_SYNC_REPO_INFO_KEY__REPO_ID, pszRepoId) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh, SG_SYNC_REPO_INFO_KEY__ADMIN_ID, pszAdminId) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh, SG_SYNC_REPO_INFO_KEY__HASH_METHOD, pszHashMethod) ); /* All DAGs in the repository */ SG_ERR_CHECK( SG_repo__list_dags(pCtx, pRepo, &count_dagnums, &paDagNums) ); SG_ERR_CHECK( SG_vhash__addnew__vhash(pCtx, pvh, "dags", &pvh_dags) ); for (i=0; i<count_dagnums; i++) { char buf_dagnum[SG_DAGNUM__BUF_MAX__HEX]; SG_ERR_CHECK_RETURN( SG_dagnum__to_sz__hex(pCtx, paDagNums[i], buf_dagnum, sizeof(buf_dagnum)) ); SG_ERR_CHECK( SG_vhash__add__null(pCtx, pvh_dags, buf_dagnum) ); /* Asking for a DAG for the first time in a repo will create that DAG. * When pushing into an empty repo, we don't want this initial query to create * empty new DAGs, so we make sure they exist before we query them. */ if (paDagNums[i] == SG_DAGNUM__VC_BRANCHES) bHasBranchDag = SG_TRUE; } // TODO the following code is a problem, because it requires that this repo // instance have indexes, and we would prefer to preserve the ability of // an index-free instance to support push, pull, and clone. /* All areas in the repository */ if (b_include_areas) { SG_ERR_CHECK( SG_area__list(pCtx, pRepo, &pvh_areas) ); if (pvh_areas) { SG_ERR_CHECK( SG_vhash__add__vhash(pCtx, pvh, "areas", &pvh_areas) ); } } /* Branches */ if (bIncludeBranches && bHasBranchDag) { SG_ERR_CHECK( SG_vc_branches__cleanup(pCtx, pRepo, &pvhBranchPile) ); if (pvhBranchPile) { SG_bool bHasBranches; SG_ERR_CHECK( SG_vhash__has(pCtx, pvhBranchPile, "branches", &bHasBranches) ); if (bHasBranches) SG_ERR_CHECK( SG_vhash__add__vhash(pCtx, pvh, "branches", &pvhBranchPile) ); } } *ppvh = pvh; pvh = NULL; /* fall through */ fail: SG_NULLFREE(pCtx, paDagNums); SG_VHASH_NULLFREE(pCtx, pvh); SG_NULLFREE(pCtx, pszRepoId); SG_NULLFREE(pCtx, pszAdminId); SG_NULLFREE(pCtx, pszHashMethod); SG_VHASH_NULLFREE(pCtx, pvh_areas); SG_VHASH_NULLFREE(pCtx, pvhBranchPile); }
void SG_sync_remote__request_fragball( SG_context* pCtx, SG_repo* pRepo, const SG_pathname* pFragballDirPathname, SG_vhash* pvhRequest, char** ppszFragballName) { SG_pathname* pFragballPathname = NULL; SG_uint64* paDagNums = NULL; SG_string* pstrFragballName = NULL; SG_rbtree* prbDagnodes = NULL; SG_rbtree_iterator* pit = NULL; SG_rev_spec* pRevSpec = NULL; SG_stringarray* psaFullHids = NULL; SG_rbtree* prbDagnums = NULL; SG_dagfrag* pFrag = NULL; char* pszRepoId = NULL; char* pszAdminId = NULL; SG_fragball_writer* pfb = NULL; SG_NULLARGCHECK_RETURN(pRepo); SG_NULLARGCHECK_RETURN(pFragballDirPathname); { char buf_filename[SG_TID_MAX_BUFFER_LENGTH]; SG_ERR_CHECK( SG_tid__generate(pCtx, buf_filename, sizeof(buf_filename)) ); SG_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pFragballPathname, pFragballDirPathname, buf_filename) ); } if (!pvhRequest) { // Add leaves from every dag to the fragball. SG_uint32 count_dagnums; SG_uint32 i; SG_ERR_CHECK( SG_fragball_writer__alloc(pCtx, pRepo, pFragballPathname, SG_TRUE, 2, &pfb) ); SG_ERR_CHECK( SG_repo__list_dags(pCtx, pRepo, &count_dagnums, &paDagNums) ); for (i=0; i<count_dagnums; i++) { SG_ERR_CHECK( SG_repo__fetch_dag_leaves(pCtx, pRepo, paDagNums[i], &prbDagnodes) ); SG_ERR_CHECK( SG_fragball__write__dagnodes(pCtx, pfb, paDagNums[i], prbDagnodes) ); SG_RBTREE_NULLFREE(pCtx, prbDagnodes); } SG_ERR_CHECK( SG_pathname__get_last(pCtx, pFragballPathname, &pstrFragballName) ); SG_ERR_CHECK( SG_STRDUP(pCtx, SG_string__sz(pstrFragballName), ppszFragballName) ); SG_ERR_CHECK( SG_fragball_writer__close(pCtx, pfb) ); } else { // Specific dags/nodes were requested. Build that fragball. SG_bool found; #if TRACE_SYNC_REMOTE && 0 SG_ERR_CHECK( SG_vhash_debug__dump_to_console__named(pCtx, pvhRequest, "fragball request") ); #endif SG_ERR_CHECK( SG_vhash__has(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__CLONE, &found) ); if (found) { // SG_SYNC_STATUS_KEY__CLONE_REQUEST is currently ignored SG_ERR_CHECK( SG_repo__fetch_repo__fragball(pCtx, pRepo, 3, pFragballDirPathname, ppszFragballName) ); } else { // Not a full clone. SG_ERR_CHECK( SG_fragball_writer__alloc(pCtx, pRepo, pFragballPathname, SG_TRUE, 2, &pfb) ); SG_ERR_CHECK( SG_vhash__has(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__SINCE, &found) ); if (found) { SG_vhash* pvh_since = NULL; SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__SINCE, &pvh_since) ); SG_ERR_CHECK( _do_since(pCtx, pRepo, pvh_since, pfb) ); } SG_ERR_CHECK( SG_vhash__has(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__DAGS, &found) ); if (found) { // Specific Dagnodes were requested. Add just those nodes to our "start from" rbtree. SG_vhash* pvhDags; SG_uint32 count_requested_dagnums; SG_uint32 i; const SG_variant* pvRevSpecs = NULL; SG_vhash* pvhRevSpec = NULL; // For each requested dag, get rev spec request. SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__DAGS, &pvhDags) ); SG_ERR_CHECK( SG_vhash__count(pCtx, pvhDags, &count_requested_dagnums) ); if (count_requested_dagnums) SG_ERR_CHECK( SG_repo__list_dags__rbtree(pCtx, pRepo, &prbDagnums) ); for (i=0; i<count_requested_dagnums; i++) { SG_bool isValidDagnum = SG_FALSE; SG_bool bSpecificNodesRequested = SG_FALSE; const char* pszRefDagNum = NULL; SG_uint64 iDagnum; // Get the dag's missing node vhash. SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvhDags, i, &pszRefDagNum, &pvRevSpecs) ); // Verify that requested dagnum exists SG_ERR_CHECK( SG_rbtree__find(pCtx, prbDagnums, pszRefDagNum, &isValidDagnum, NULL) ); if (!isValidDagnum) continue; SG_ERR_CHECK( SG_dagnum__from_sz__hex(pCtx, pszRefDagNum, &iDagnum) ); if (pvRevSpecs && pvRevSpecs->type != SG_VARIANT_TYPE_NULL) { SG_uint32 countRevSpecs = 0; SG_ERR_CHECK( SG_variant__get__vhash(pCtx, pvRevSpecs, &pvhRevSpec) ); SG_ERR_CHECK( SG_rev_spec__from_vash(pCtx, pvhRevSpec, &pRevSpec) ); // Process the rev spec for each dag SG_ERR_CHECK( SG_rev_spec__count(pCtx, pRevSpec, &countRevSpecs) ); if (countRevSpecs > 0) { bSpecificNodesRequested = SG_TRUE; SG_ERR_CHECK( SG_rev_spec__get_all__repo(pCtx, pRepo, pRevSpec, SG_TRUE, &psaFullHids, NULL) ); SG_ERR_CHECK( SG_stringarray__to_rbtree_keys(pCtx, psaFullHids, &prbDagnodes) ); SG_STRINGARRAY_NULLFREE(pCtx, psaFullHids); } SG_REV_SPEC_NULLFREE(pCtx, pRevSpec); } if (!bSpecificNodesRequested) { // When no specific nodes are in the request, add all leaves. SG_ERR_CHECK( SG_repo__fetch_dag_leaves(pCtx, pRepo, iDagnum, &prbDagnodes) ); } if (prbDagnodes) // can be null when leaves of an empty dag are requested { // Get the leaves of the other repo, which we need to connect to. SG_ERR_CHECK( SG_vhash__has(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__LEAVES, &found) ); if (found) { SG_vhash* pvhRefAllLeaves; SG_vhash* pvhRefDagLeaves; SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__LEAVES, &pvhRefAllLeaves) ); SG_ERR_CHECK( SG_vhash__has(pCtx, pvhRequest, pszRefDagNum, &found) ); { SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvhRefAllLeaves, pszRefDagNum, &pvhRefDagLeaves) ); SG_ERR_CHECK( SG_sync__build_best_guess_dagfrag(pCtx, pRepo, iDagnum, prbDagnodes, pvhRefDagLeaves, &pFrag) ); } } else { // The other repo's leaves weren't provided: add just the requested nodes, make no attempt to connect. SG_ERR_CHECK( SG_repo__get_repo_id(pCtx, pRepo, &pszRepoId) ); SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &pszAdminId) ); SG_ERR_CHECK( SG_dagfrag__alloc(pCtx, &pFrag, pszRepoId, pszAdminId, iDagnum) ); SG_ERR_CHECK( SG_dagfrag__load_from_repo__simple(pCtx, pFrag, pRepo, prbDagnodes) ); SG_NULLFREE(pCtx, pszRepoId); SG_NULLFREE(pCtx, pszAdminId); } SG_ERR_CHECK( SG_fragball__write__frag(pCtx, pfb, pFrag) ); SG_RBTREE_NULLFREE(pCtx, prbDagnodes); SG_DAGFRAG_NULLFREE(pCtx, pFrag); } } // dagnum loop } // if "dags" exists /* Add requested blobs to the fragball */ SG_ERR_CHECK( SG_vhash__has(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__BLOBS, &found) ); if (found) { // Blobs were requested. SG_vhash* pvhBlobs; SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__BLOBS, &pvhBlobs) ); SG_ERR_CHECK( SG_sync__add_blobs_to_fragball(pCtx, pfb, pvhBlobs) ); } SG_ERR_CHECK( SG_pathname__get_last(pCtx, pFragballPathname, &pstrFragballName) ); SG_ERR_CHECK( SG_STRDUP(pCtx, SG_string__sz(pstrFragballName), ppszFragballName) ); } SG_ERR_CHECK( SG_fragball_writer__close(pCtx, pfb) ); } /* fallthru */ fail: // If we had an error, delete the half-baked fragball. if (pFragballPathname && SG_context__has_err(pCtx)) { SG_ERR_IGNORE( SG_fsobj__remove__pathname(pCtx, pFragballPathname) ); } SG_PATHNAME_NULLFREE(pCtx, pFragballPathname); SG_NULLFREE(pCtx, paDagNums); SG_STRING_NULLFREE(pCtx, pstrFragballName); SG_RBTREE_NULLFREE(pCtx, prbDagnodes); SG_RBTREE_ITERATOR_NULLFREE(pCtx, pit); SG_RBTREE_NULLFREE(pCtx, prbDagnums); SG_REV_SPEC_NULLFREE(pCtx, pRevSpec); SG_STRINGARRAY_NULLFREE(pCtx, psaFullHids); SG_DAGFRAG_NULLFREE(pCtx, pFrag); SG_NULLFREE(pCtx, pszRepoId); SG_NULLFREE(pCtx, pszAdminId); SG_FRAGBALL_WRITER_NULLFREE(pCtx, pfb); }
void SG_vc_hooks__BROADCAST__AFTER_COMMIT( SG_context* pCtx, SG_repo* pRepo, SG_changeset* pcs, const char* psz_tied_branch_name, const SG_audit* pq, const char* psz_comment, const char* const* paszAssocs, SG_uint32 count_assocs, const SG_stringarray* psa_stamps ) { SG_varray* pva_hooks = NULL; SG_vhash* pvh_params = NULL; char* psz_repo_id = NULL; char* psz_admin_id = NULL; SG_ERR_CHECK( SG_vc_hooks__lookup_by_interface( pCtx, pRepo, SG_VC_HOOK__INTERFACE__BROADCAST__AFTER_COMMIT, &pva_hooks ) ); if (pva_hooks) { SG_uint32 count_hooks = 0; SG_uint32 i_hook = 0; const char* psz_descriptor_name = NULL; SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &psz_admin_id) ); SG_ERR_CHECK( SG_repo__get_repo_id( pCtx, pRepo, &psz_repo_id ) ); SG_ERR_CHECK( SG_repo__get_descriptor_name(pCtx, pRepo, &psz_descriptor_name) ); SG_ERR_CHECK( SG_varray__count(pCtx, pva_hooks, &count_hooks) ); for (i_hook=0; i_hook<count_hooks; i_hook++) { SG_vhash* pvh_hook = NULL; const char* psz_js = NULL; const char* psz_csid = NULL; SG_vhash* pvh_changeset = NULL; SG_ERR_CHECK( SG_varray__get__vhash(pCtx, pva_hooks, i_hook, &pvh_hook) ); SG_ERR_CHECK( SG_changeset__get_id_ref(pCtx, pcs, &psz_csid) ); SG_ERR_CHECK( SG_changeset__get_vhash_ref(pCtx, pcs, &pvh_changeset) ); SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_hook, "js", &psz_js) ); SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvh_params) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "csid", psz_csid) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "repo_id", psz_repo_id) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "admin_id", psz_admin_id) ); if (psz_descriptor_name) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "descriptor_name", psz_descriptor_name) ); } if (pq) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "userid", pq->who_szUserId) ); } if (psz_comment) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "comment", psz_comment) ); } if (psz_tied_branch_name) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "branch", psz_tied_branch_name) ); } SG_ERR_CHECK( SG_vhash__addcopy__vhash(pCtx, pvh_params, "changeset", pvh_changeset) ); if (paszAssocs && count_assocs) { SG_uint32 i = 0; SG_varray* pva_ids = NULL; SG_ERR_CHECK( SG_vhash__addnew__varray(pCtx, pvh_params, "wit_ids", &pva_ids) ); for (i=0; i<count_assocs; i++) { SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_ids, paszAssocs[i]) ); } } if (psa_stamps) { SG_uint32 count = 0; SG_uint32 i = 0; SG_varray* pva_stamps = NULL; SG_ERR_CHECK( SG_vhash__addnew__varray(pCtx, pvh_params, "stamps", &pva_stamps) ); SG_ERR_CHECK( SG_stringarray__count(pCtx, psa_stamps, &count) ); for (i=0; i<count; i++) { const char* psz_stamp = NULL; SG_ERR_CHECK( SG_stringarray__get_nth(pCtx, psa_stamps, i, &psz_stamp) ); SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_stamps, psz_stamp) ); } } SG_ERR_CHECK( SG_vc_hooks__execute(pCtx, psz_js, pvh_params, NULL) ); SG_VHASH_NULLFREE(pCtx, pvh_params); } } fail: SG_VHASH_NULLFREE(pCtx, pvh_params); SG_VARRAY_NULLFREE(pCtx, pva_hooks); SG_NULLFREE(pCtx, psz_repo_id); SG_NULLFREE(pCtx, psz_admin_id); }
// TODO not sure we really want to pass this much stuff to this interface void SG_vc_hooks__ASK__WIT__VALIDATE_ASSOCIATIONS( SG_context* pCtx, SG_repo* pRepo, const char* const* paszAssocs, SG_uint32 count_assocs, SG_varray *pBugs ) { SG_vhash* pvh_params = NULL; SG_vhash* pvh_result = NULL; char* psz_repo_id = NULL; char* psz_admin_id = NULL; SG_vhash* pvh_hook = NULL; const char* psz_js = NULL; SG_uint32 i = 0; SG_varray* pva_ids = NULL; const char* psz_descriptor_name = NULL; SG_ERR_CHECK( sg_vc_hooks__lookup_by_interface__single_result( pCtx, pRepo, SG_VC_HOOK__INTERFACE__ASK__WIT__VALIDATE_ASSOCIATIONS, &pvh_hook ) ); if (!pvh_hook) return; SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &psz_admin_id) ); SG_ERR_CHECK( SG_repo__get_repo_id( pCtx, pRepo, &psz_repo_id ) ); SG_ERR_CHECK( SG_repo__get_descriptor_name(pCtx, pRepo, &psz_descriptor_name) ); SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_hook, "js", &psz_js) ); SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvh_params) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "repo_id", psz_repo_id) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "admin_id", psz_admin_id) ); if (psz_descriptor_name) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "descriptor_name", psz_descriptor_name) ); } SG_ERR_CHECK( SG_vhash__addnew__varray(pCtx, pvh_params, "wit_ids", &pva_ids) ); for (i=0; i<count_assocs; i++) { SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_ids, paszAssocs[i]) ); } SG_ERR_CHECK( SG_vc_hooks__execute(pCtx, psz_js, pvh_params, &pvh_result) ); // TODO process the result if (pvh_result) { SG_bool hasErrors = SG_FALSE; SG_bool hasBugs = SG_FALSE; SG_ERR_CHECK( SG_vhash__has(pCtx, pvh_result, "error", &hasErrors) ); if (hasErrors) { const char *emsg = NULL; SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_result, "error", &emsg) ); SG_ERR_THROW2( SG_ERR_VC_HOOK_REFUSED, (pCtx, "%s", emsg) ); } SG_ERR_CHECK( SG_vhash__has(pCtx, pvh_result, "bugs", &hasBugs) ); if (hasBugs && pBugs) { SG_varray *bugs = NULL; SG_ERR_CHECK( SG_vhash__get__varray(pCtx, pvh_result, "bugs", &bugs) ); SG_ERR_CHECK( SG_varray__copy_items(pCtx, bugs, pBugs) ); } } fail: SG_VHASH_NULLFREE(pCtx, pvh_params); SG_VHASH_NULLFREE(pCtx, pvh_result); SG_VHASH_NULLFREE(pCtx, pvh_hook); SG_NULLFREE(pCtx, psz_repo_id); SG_NULLFREE(pCtx, psz_admin_id); }
// TODO not sure we really want to pass this much stuff to this interface void SG_vc_hooks__ASK__WIT__ADD_ASSOCIATIONS( SG_context* pCtx, SG_repo* pRepo, SG_changeset* pcs, const char* psz_tied_branch_name, const SG_audit* pq, const char* psz_comment, const char* const* paszAssocs, SG_uint32 count_assocs, const SG_stringarray* psa_stamps ) { SG_vhash* pvh_hook = NULL; SG_vhash* pvh_params = NULL; SG_vhash* pvh_result = NULL; char* psz_repo_id = NULL; char* psz_admin_id = NULL; SG_ERR_CHECK( sg_vc_hooks__lookup_by_interface__single_result( pCtx, pRepo, SG_VC_HOOK__INTERFACE__ASK__WIT__ADD_ASSOCIATIONS, &pvh_hook ) ); if (pvh_hook) { const char* psz_js = NULL; SG_uint32 i = 0; SG_varray* pva_ids = NULL; const char* psz_descriptor_name = NULL; const char* psz_csid = NULL; SG_vhash* pvh_changeset = NULL; SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &psz_admin_id) ); SG_ERR_CHECK( SG_repo__get_repo_id( pCtx, pRepo, &psz_repo_id ) ); SG_ERR_CHECK( SG_repo__get_descriptor_name(pCtx, pRepo, &psz_descriptor_name) ); SG_ERR_CHECK( SG_changeset__get_id_ref(pCtx, pcs, &psz_csid) ); SG_ERR_CHECK( SG_changeset__get_vhash_ref(pCtx, pcs, &pvh_changeset) ); SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_hook, "js", &psz_js) ); SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvh_params) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "csid", psz_csid) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "repo_id", psz_repo_id) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "admin_id", psz_admin_id) ); if (psz_descriptor_name) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "descriptor_name", psz_descriptor_name) ); } if (pq) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "userid", pq->who_szUserId) ); } if (psz_comment) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "comment", psz_comment) ); } if (psz_tied_branch_name) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvh_params, "branch", psz_tied_branch_name) ); } SG_ERR_CHECK( SG_vhash__addcopy__vhash(pCtx, pvh_params, "changeset", pvh_changeset) ); SG_ERR_CHECK( SG_vhash__addnew__varray(pCtx, pvh_params, "wit_ids", &pva_ids) ); for (i=0; i<count_assocs; i++) { SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_ids, paszAssocs[i]) ); } if (psa_stamps) { SG_uint32 count = 0; SG_uint32 i = 0; SG_varray* pva_stamps = NULL; SG_ERR_CHECK( SG_vhash__addnew__varray(pCtx, pvh_params, "stamps", &pva_stamps) ); SG_ERR_CHECK( SG_stringarray__count(pCtx, psa_stamps, &count) ); for (i=0; i<count; i++) { const char* psz_stamp = NULL; SG_ERR_CHECK( SG_stringarray__get_nth(pCtx, psa_stamps, i, &psz_stamp) ); SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_stamps, psz_stamp) ); } } SG_ERR_CHECK( SG_vc_hooks__execute(pCtx, psz_js, pvh_params, &pvh_result) ); // TODO process the result if (pvh_result) { SG_bool hasErrors = SG_FALSE; SG_ERR_CHECK( SG_vhash__has(pCtx, pvh_result, "error", &hasErrors) ); if (hasErrors) { const char *emsg = NULL; SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_result, "error", &emsg) ); SG_ERR_THROW2( SG_ERR_VC_HOOK_REFUSED, (pCtx, "\n:%s: %s", SG_VC_HOOK__INTERFACE__ASK__WIT__ADD_ASSOCIATIONS, emsg) ); } } } fail: SG_VHASH_NULLFREE(pCtx, pvh_params); SG_VHASH_NULLFREE(pCtx, pvh_result); SG_VHASH_NULLFREE(pCtx, pvh_hook); SG_NULLFREE(pCtx, psz_repo_id); SG_NULLFREE(pCtx, psz_admin_id); }
void SG_sync__closet_user_dags( SG_context* pCtx, SG_repo* pRepoSrcNotMine, const char* pszRefHidLeafSrc, SG_varray** ppvaSyncedUserList) { char* pszSrcAdminId = NULL; char* pszHidLeafSrc = NULL; char* pszHidLeafDest = NULL; SG_vhash* pvhDescriptors = NULL; SG_repo* pRepoDest = NULL; SG_repo* pRepoSrcMine = NULL; char* pszDestAdminId = NULL; /* Using disallowed characters to ensure no collision with an actual repo name. * Not that this isn't actually stored anywhere--we just use it as a key in the * vhash below where the /real/ repos have descriptor names. */ const char* pszRefUserMasterFakeName = "\\/USER_MASTER\\/"; /* The repo routines do a null arg check of pRepoSrcNotMine. The other args are optional. */ if (!pszRefHidLeafSrc) { SG_ERR_CHECK( SG_zing__get_leaf(pCtx, pRepoSrcNotMine, NULL, SG_DAGNUM__USERS, &pszHidLeafSrc) ); pszRefHidLeafSrc = pszHidLeafSrc; } /* Add all repositories in "normal" status, to the list we'll iterate over. */ SG_ERR_CHECK( SG_closet__descriptors__list(pCtx, &pvhDescriptors) ); /* If it exists, add the user master repo to the list. */ { SG_bool bExists = SG_FALSE; SG_ERR_CHECK( SG_repo__user_master__exists(pCtx, &bExists) ); if (bExists) SG_ERR_CHECK( SG_vhash__add__null(pCtx, pvhDescriptors, pszRefUserMasterFakeName) ); } /* Iterate over the repositories, syncing the user database. */ { SG_int32 i = 0; SG_uint32 numDescriptors = 0; SG_ERR_CHECK( SG_vhash__count(pCtx, pvhDescriptors, &numDescriptors) ); for(i = 0; i < (SG_int32)numDescriptors; i++) { const char* pszRefNameDest = NULL; SG_bool bAdminIdsMatch = SG_TRUE; const SG_variant* pvRefDest = NULL; /* Note that the source repo will be in this loop, too, but we don't need to check for * it, adding another strcmp, because the leaf hid comparison below will effectively * skip it. So we do one extra leaf fetch and comparison, total, rather than an extra * strcmp for every repo in the closet. */ SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvhDescriptors, i, &pszRefNameDest, &pvRefDest) ); if (SG_VARIANT_TYPE_NULL == pvRefDest->type) SG_ERR_CHECK( SG_REPO__USER_MASTER__OPEN(pCtx, &pRepoDest) ); else SG_ERR_CHECK( SG_REPO__OPEN_REPO_INSTANCE(pCtx, pszRefNameDest, &pRepoDest) ); SG_ERR_CHECK( SG_zing__get_leaf(pCtx, pRepoDest, NULL, SG_DAGNUM__USERS, &pszHidLeafDest) ); if (strcmp(pszRefHidLeafSrc, pszHidLeafDest)) { /* Pull from source to dest. * Pull is generally faster than push, so we're using it on purpose. */ SG_pull__admin__local(pCtx, pRepoDest, pRepoSrcNotMine, NULL); if (SG_context__has_err(pCtx)) { /* If there's an admin id mismatch, don't die. Log a warning and move on. */ if (SG_context__err_equals(pCtx, SG_ERR_ADMIN_ID_MISMATCH)) { const char* pszRefNameSrc = NULL; SG_ERR_DISCARD; SG_ERR_CHECK( SG_repo__get_descriptor_name(pCtx, pRepoSrcNotMine, &pszRefNameSrc) ); if (!pszRefNameSrc) pszRefNameSrc = pszRefUserMasterFakeName; SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepoSrcNotMine, &pszSrcAdminId) ); SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepoDest, &pszDestAdminId) ); SG_ERR_CHECK( SG_log__report_warning(pCtx, "admin-id mismatch when syncing users: source repo %s has %s, dest repo %s has %s", pszRefNameSrc, pszSrcAdminId, pszRefNameDest, pszDestAdminId) ); bAdminIdsMatch = SG_FALSE; SG_NULLFREE(pCtx, pszDestAdminId); SG_NULLFREE(pCtx, pszSrcAdminId); } else SG_ERR_RETHROW; } if (bAdminIdsMatch) { SG_NULLFREE(pCtx, pszHidLeafDest); SG_ERR_CHECK( SG_zing__get_leaf(pCtx, pRepoDest, NULL, SG_DAGNUM__USERS, &pszHidLeafDest) ); if (strcmp(pszRefHidLeafSrc, pszHidLeafDest)) { /* The pull from source to dest resulted in a new leaf. * Use the new leaf and restart the loop. */ SG_NULLFREE(pCtx, pszHidLeafSrc); pszRefHidLeafSrc = pszHidLeafSrc = pszHidLeafDest; pszHidLeafDest = NULL; SG_REPO_NULLFREE(pCtx, pRepoSrcMine); pRepoSrcNotMine = pRepoSrcMine = pRepoDest; pRepoDest = NULL; i = -1; /* start again at the first descriptor */ } } } SG_NULLFREE(pCtx, pszHidLeafDest); SG_REPO_NULLFREE(pCtx, pRepoDest); } } if (ppvaSyncedUserList) SG_ERR_CHECK( SG_user__list_all(pCtx, pRepoSrcNotMine, ppvaSyncedUserList) ); /* fall through */ fail: SG_NULLFREE(pCtx, pszSrcAdminId); SG_NULLFREE(pCtx, pszHidLeafSrc); SG_NULLFREE(pCtx, pszHidLeafDest); SG_VHASH_NULLFREE(pCtx, pvhDescriptors); SG_REPO_NULLFREE(pCtx, pRepoDest); SG_REPO_NULLFREE(pCtx, pRepoSrcMine); SG_NULLFREE(pCtx, pszDestAdminId); }
void SG_sync__build_best_guess_dagfrag( SG_context* pCtx, SG_repo* pRepo, SG_uint64 iDagNum, SG_rbtree* prbStartFromHids, SG_vhash* pvhConnectToHidsAndGens, SG_dagfrag** ppFrag) { SG_uint32 i, countConnectTo; SG_rbtree_iterator* pit = NULL; SG_dagnode* pdn = NULL; SG_dagfrag* pFrag = NULL; SG_repo_fetch_dagnodes_handle* pdh = NULL; SG_int32 minGen = SG_INT32_MAX; SG_int32 maxGen = 0; SG_uint32 gensToFetch = 0; char* psz_repo_id = NULL; char* psz_admin_id = NULL; SG_bool bNextHid; const char* pszRefHid; SG_int32 gen; #if TRACE_SYNC SG_int64 startTime; SG_int64 endTime; #endif SG_NULLARGCHECK_RETURN(prbStartFromHids); /* Find the minimum generation in pertinent "connect to" nodes. */ if (pvhConnectToHidsAndGens) { SG_ERR_CHECK( SG_vhash__count(pCtx, pvhConnectToHidsAndGens, &countConnectTo) ); for (i = 0; i < countConnectTo; i++) { SG_int32 gen; SG_ERR_CHECK( SG_vhash__get_nth_pair__int32(pCtx, pvhConnectToHidsAndGens, i, &pszRefHid, &gen) ); if (gen < minGen) minGen = gen; } } /* Happens when pulling into an empty repo, or when an entire dag is specifically requested. */ if (minGen == SG_INT32_MAX) minGen = -1; SG_ERR_CHECK( SG_repo__fetch_dagnodes__begin(pCtx, pRepo, iDagNum, &pdh) ); /* Find the maximum generation in pertinent "start from" nodes. */ SG_ERR_CHECK( SG_rbtree__iterator__first(pCtx, &pit, prbStartFromHids, &bNextHid, &pszRefHid, NULL) ); while (bNextHid) { SG_ERR_CHECK( SG_repo__fetch_dagnodes__one(pCtx, pRepo, pdh, pszRefHid, &pdn) ); SG_ERR_CHECK( SG_dagnode__get_generation(pCtx, pdn, &gen) ); if (gen > maxGen) maxGen = gen; SG_DAGNODE_NULLFREE(pCtx, pdn); SG_ERR_CHECK( SG_rbtree__iterator__next(pCtx, pit, &bNextHid, &pszRefHid, NULL) ); } SG_RBTREE_ITERATOR_NULLFREE(pCtx, pit); if (maxGen <= minGen) gensToFetch = FALLBACK_GENS_PER_ROUNDTRIP; else gensToFetch = maxGen - minGen; #if TRACE_SYNC { char buf_dagnum[SG_DAGNUM__BUF_MAX__HEX]; SG_uint32 count; SG_ERR_CHECK( SG_dagnum__to_sz__hex(pCtx, iDagNum, buf_dagnum, sizeof(buf_dagnum)) ); SG_ERR_CHECK( SG_console(pCtx, SG_CS_STDERR, "Building best guess dagfrag for dag %s...\n", buf_dagnum) ); SG_ERR_CHECK( SG_console(pCtx, SG_CS_STDERR, "Starting from nodes:\n") ); SG_ERR_CHECK( SG_rbtree_debug__dump_keys_to_console(pCtx, prbStartFromHids) ); SG_ERR_CHECK( SG_vhash_debug__dump_to_console__named(pCtx, pvhConnectToHidsAndGens, "Connecting to nodes") ); SG_ERR_CHECK( SG_rbtree__count(pCtx, prbStartFromHids, &count) ); SG_ERR_CHECK( SG_console(pCtx, SG_CS_STDERR, "result has %d generations from %u starting nodes.\n", gensToFetch, count) ); SG_ERR_CHECK( SG_console__flush(pCtx, SG_CS_STDERR) ); SG_ERR_CHECK( SG_time__get_milliseconds_since_1970_utc(pCtx, &startTime) ); } #endif /* Return a frag with the corresponding generations filled in. */ SG_ERR_CHECK( SG_repo__get_repo_id(pCtx, pRepo, &psz_repo_id) ); SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &psz_admin_id) ); SG_ERR_CHECK( SG_dagfrag__alloc(pCtx, &pFrag, psz_repo_id, psz_admin_id, iDagNum) ); SG_ERR_CHECK( SG_dagfrag__load_from_repo__multi(pCtx, pFrag, pRepo, prbStartFromHids, gensToFetch) ); #if TRACE_SYNC SG_ERR_CHECK( SG_time__get_milliseconds_since_1970_utc(pCtx, &endTime) ); { SG_uint32 dagnodeCount; double seconds = ((double)endTime-(double)startTime)/1000; SG_ERR_CHECK( SG_dagfrag__dagnode_count(pCtx, pFrag, &dagnodeCount) ); SG_ERR_CHECK( SG_console(pCtx, SG_CS_STDERR, " - %u nodes in frag, built in %1.3f seconds\n", dagnodeCount, seconds) ); SG_ERR_CHECK( SG_dagfrag_debug__dump__console(pCtx, pFrag, "best-guess dagfrag", 0, SG_CS_STDERR) ); } #endif *ppFrag = pFrag; pFrag = NULL; /* Common cleanup */ fail: SG_NULLFREE(pCtx, psz_repo_id); SG_NULLFREE(pCtx, psz_admin_id); SG_RBTREE_ITERATOR_NULLFREE(pCtx, pit); SG_DAGNODE_NULLFREE(pCtx, pdn); SG_DAGFRAG_NULLFREE(pCtx, pFrag); SG_ERR_IGNORE( SG_repo__fetch_dagnodes__end(pCtx, pRepo, &pdh) ); }
void SG_localsettings__get__variant(SG_context * pCtx, const char * psz_path, SG_repo* pRepo, SG_variant** ppv, SG_string** ppstr_where_found) { SG_jsondb* p = NULL; SG_string* pstr_path = NULL; SG_variant* pv = NULL; char* psz_repo_id = NULL; char* psz_admin_id = NULL; const char* psz_ref_descriptor_name = NULL; SG_ASSERT(pCtx); SG_NONEMPTYCHECK_RETURN(psz_path); SG_ERR_CHECK( SG_closet__get_localsettings(pCtx, &p) ); SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pstr_path) ); if ('/' == psz_path[0]) { SG_bool b = SG_FALSE; SG_ERR_CHECK( SG_string__sprintf(pCtx, pstr_path, "%s", psz_path) ); SG_ERR_CHECK( SG_jsondb__has(pCtx, p, SG_string__sz(pstr_path), &b) ); if (b) { SG_ERR_CHECK( SG_jsondb__get__variant(pCtx, p, SG_string__sz(pstr_path), &pv) ); } } else { SG_bool b_has_val = SG_FALSE; // try the instance of the repo if (!b_has_val && pRepo) { SG_ERR_CHECK( SG_repo__get_descriptor_name(pCtx, pRepo, &psz_ref_descriptor_name) ); SG_ERR_CHECK( SG_string__sprintf(pCtx, pstr_path, "%s/%s/%s", SG_LOCALSETTING__SCOPE__INSTANCE, psz_ref_descriptor_name, psz_path ) ); SG_ERR_CHECK( SG_jsondb__has(pCtx, p, SG_string__sz(pstr_path), &b_has_val) ); if (b_has_val) { SG_ERR_CHECK( SG_jsondb__get__variant(pCtx, p, SG_string__sz(pstr_path), &pv) ); } } // then the repo if (!b_has_val && pRepo) { SG_ERR_CHECK( SG_repo__get_repo_id(pCtx, pRepo, &psz_repo_id) ); SG_ERR_CHECK( SG_string__sprintf(pCtx, pstr_path, "%s/%s/%s", SG_LOCALSETTING__SCOPE__REPO, psz_repo_id, psz_path ) ); SG_ERR_CHECK( SG_jsondb__has(pCtx, p, SG_string__sz(pstr_path), &b_has_val) ); if (b_has_val) { SG_ERR_CHECK( SG_jsondb__get__variant(pCtx, p, SG_string__sz(pstr_path), &pv) ); } } // then the admin group of repos if (!b_has_val && pRepo) { SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepo, &psz_admin_id) ); SG_ERR_CHECK( SG_string__sprintf(pCtx, pstr_path, "%s/%s/%s", SG_LOCALSETTING__SCOPE__ADMIN, psz_admin_id, psz_path ) ); SG_ERR_CHECK( SG_jsondb__has(pCtx, p, SG_string__sz(pstr_path), &b_has_val) ); if (b_has_val) { SG_ERR_CHECK( SG_jsondb__get__variant(pCtx, p, SG_string__sz(pstr_path), &pv) ); } } // then the machine if (!b_has_val) { SG_ERR_CHECK( SG_string__sprintf(pCtx, pstr_path, "%s/%s", SG_LOCALSETTING__SCOPE__MACHINE, psz_path) ); SG_ERR_CHECK( SG_jsondb__has(pCtx, p, SG_string__sz(pstr_path), &b_has_val) ); if (b_has_val) { SG_ERR_CHECK( SG_jsondb__get__variant(pCtx, p, SG_string__sz(pstr_path), &pv) ); } } // then the factory default if (!b_has_val) { SG_STRING_NULLFREE(pCtx, pstr_path); SG_ERR_CHECK( SG_localsettings__factory__get__variant(pCtx, psz_path, &pv) ); } } *ppv = pv; pv = NULL; if (ppstr_where_found) { *ppstr_where_found = pstr_path; pstr_path = NULL; } fail: SG_NULLFREE(pCtx, psz_repo_id); SG_NULLFREE(pCtx, psz_admin_id); SG_VARIANT_NULLFREE(pCtx, pv); SG_STRING_NULLFREE(pCtx, pstr_path); SG_JSONDB_NULLFREE(pCtx, p); }