void SG_vfile__add__vhash( SG_context* pCtx, const SG_pathname* pPath, /**< The path of the file containing the JSON text */ const char* putf8Key, const SG_vhash* pHashValue ) { SG_vfile* pvf = NULL; SG_vhash* pvh = NULL; SG_vhash* pvhCopy = NULL; SG_ERR_CHECK( SG_vfile__begin(pCtx, pPath, SG_FILE_RDWR | SG_FILE_OPEN_OR_CREATE, &pvh, &pvf) ); if (!pvh) { SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvh) ); } SG_ERR_CHECK( SG_VHASH__ALLOC__COPY(pCtx, &pvhCopy, pHashValue) ); SG_ERR_CHECK( SG_vhash__add__vhash(pCtx, pvh, putf8Key, &pvhCopy) ); SG_ERR_CHECK( SG_vfile__end(pCtx, &pvf, pvh) ); SG_VHASH_NULLFREE(pCtx, pvh); return; fail: SG_ERR_IGNORE( sg_vfile__dispose(pCtx, pvf) ); SG_VHASH_NULLFREE(pCtx, pvhCopy); SG_VHASH_NULLFREE(pCtx, pvh); }
void SG_localsettings__foreach( SG_context* pCtx, const char* szPattern, SG_bool bIncludeDefaults, SG_localsettings_foreach_callback* pCallback, void* pCallerData ) { SG_vhash* pValues = NULL; SG_vhash* pDefaults = NULL; provide_matching_values__data ProvideMatchingValuesData = {NULL, NULL, NULL, NULL}; SG_UNUSED(pCallback); SG_UNUSED(pCallerData); // get the settings SG_ERR_CHECK( SG_localsettings__list__vhash(pCtx, &pValues) ); // if defaults were requested, get those too if (bIncludeDefaults) { SG_ERR_CHECK( SG_localsettings__factory__list__vhash(pCtx, &pDefaults) ); SG_ERR_CHECK( SG_vhash__add__vhash(pCtx, pValues, SG_LOCALSETTING__SCOPE__DEFAULT + 1, &pDefaults) ); // +1 to remove the slash at the beginning } // sort the settings SG_ERR_CHECK( SG_vhash__sort(pCtx, pValues, SG_TRUE, SG_vhash_sort_callback__increasing) ); // setup our callback data SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &(ProvideMatchingValuesData.pPrefix)) ); ProvideMatchingValuesData.szPattern = szPattern; ProvideMatchingValuesData.pCallback = pCallback; ProvideMatchingValuesData.pCallerData = pCallerData; // iterate through the vhash SG_ERR_CHECK( SG_vhash__foreach(pCtx, pValues, provide_matching_values, &ProvideMatchingValuesData) ); fail: SG_VHASH_NULLFREE(pCtx, pValues); SG_VHASH_NULLFREE(pCtx, pDefaults); SG_STRING_NULLFREE(pCtx, ProvideMatchingValuesData.pPrefix); }
static void _serialize_data_cb(SG_context * pCtx, const char * szHid, void * pAssocData, void * pVoidSerializeData) { struct _serialize_data * pSerializeData = (struct _serialize_data *)pVoidSerializeData; _my_data * pMyData = (_my_data *)pAssocData; SG_vhash * pvhMyData = NULL; SG_vhash * pvhDagnode = NULL; SG_ERR_CHECK( SG_VHASH__ALLOC__SHARED(pCtx,&pvhMyData,5,pSerializeData->pvhFrag) ); SG_ERR_CHECK( SG_vhash__add__int64(pCtx,pvhMyData,KEY_DFS_STATE,(SG_int64)pMyData->m_state) ); if (SG_DFS_END_FRINGE == pMyData->m_state) { SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx,pvhMyData,KEY_DAGNODE_ID,szHid) ); } else { SG_ERR_CHECK( SG_dagnode__to_vhash__shared(pCtx,pMyData->m_pDagnode,pvhMyData,&pvhDagnode) ); SG_ERR_CHECK( SG_vhash__add__vhash(pCtx,pvhMyData,KEY_ACTUAL_DAGNODE,&pvhDagnode) ); } #if DEBUG && TRACE_DAGFRAG && 0 SG_ERR_CHECK( SG_vhash_debug__dump_to_console(pCtx, pvhMyData) ); #endif SG_ERR_CHECK( SG_varray__append__vhash(pCtx,pSerializeData->pvaMyData,&pvhMyData) ); return; fail: SG_VHASH_NULLFREE(pCtx, pvhMyData); SG_VHASH_NULLFREE(pCtx, pvhDagnode); }
static void _tree__add_next_node_to_results(SG_context * pCtx, _tree_t * pTree, SG_varray * pResults, SG_uint32 * pCountResults, SG_bool * pbLastResultWasIndented) { SG_vhash * pResult = NULL; SG_varray * pChildren = NULL; SG_uint32 i; SG_varray * pTmp = NULL; // Add pTree->pNextResult to results list. SG_ERR_CHECK( SG_varray__appendnew__vhash(pCtx, pResults, &pResult) ); SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pResult, "revno", pTree->pNextResult->revno) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pResult, "changeset_id", pTree->pNextResult->pszHidRef) ); SG_ERR_CHECK( SG_vhash__add__vhash(pCtx, pResult, "parents", &pTree->pNextResult->pVcParents) ); SG_ERR_CHECK( SG_vhash__addnew__varray(pCtx, pResult, "displayChildren", &pChildren) ); for(i=0; i<pTree->pNextResult->displayChildren.count; ++i) SG_ERR_CHECK( SG_varray__append__int64(pCtx, pChildren, pTree->pNextResult->displayChildren.p[i]->revno) ); if(pTree->pNextResult->displayChildren.count>1 && pTree->indentLevel>0) { SG_varray * pContinuationToken = NULL; SG_ERR_CHECK( SG_vhash__addnew__varray(pCtx, pResult, "continuationToken", &pContinuationToken) ); SG_ERR_CHECK( _tree__generate_continuation_token(pCtx, pTree, pContinuationToken) ); } SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pResult, "indent", pTree->indentLevel) ); *pbLastResultWasIndented = (pTree->indentLevel > 0); if(pTree->pNextResult->pDisplayParent!=NULL) { SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pResult, "displayParent", pTree->pNextResult->pDisplayParent->revno) ); SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pResult, "indexInParent", pTree->pNextResult->pDisplayParent->displayChildren.count) ); SG_ASSERT(*pbLastResultWasIndented); } else { SG_ASSERT(!*pbLastResultWasIndented); } ++(*pCountResults); // Advance pTree->pNextResult pointer to next result. while(pTree->pNextResult->displayChildren.count==0 && pTree->pNextResult!=pTree->pRoot) { // We have already added this node and all children to the results. // Free the memory that will not be reused, and then put the node // on the "free list". _node__free_nonreusable_memory(pCtx, pTree->pNextResult); pTree->pNextResult->displayChildren.p[0] = pTree->pFreeList; pTree->pNextResult->displayChildren.count = 1; pTree->pFreeList = pTree->pNextResult; // Move back up up in the tree. pTree->pNextResult = pTree->pNextResult->pDisplayParent; if(pTree->pNextResult!=NULL) { // The node we just freed... Remove it from its display parent too. --pTree->pNextResult->displayChildren.count; // All children but the leftmost one are indented by 1 from the parent. if(pTree->pNextResult->displayChildren.count>0) --pTree->indentLevel; } } if(pTree->pNextResult->displayChildren.count>0) { SG_uint32 i = pTree->pNextResult->displayChildren.count-1; pTree->pNextResult = pTree->pNextResult->displayChildren.p[i]; if(i>=1) ++pTree->indentLevel; } else { pTree->pNextResult = NULL; } // If we advanced past root... if(pTree->pNextResult==NULL || pTree->pNextResult==pTree->pRoot->displayChildren.p[0]) { // Out with the old root, in with the new... _node__free_nonreusable_memory(pCtx, pTree->pRoot); pTree->pRoot->displayChildren.p[0] = pTree->pFreeList; pTree->pRoot->displayChildren.count = 1; pTree->pFreeList = pTree->pRoot; pTree->pRoot = pTree->pNextResult; if(pTree->pRoot!=NULL) pTree->pRoot->pDisplayParent = NULL; } return; fail: SG_VARRAY_NULLFREE(pCtx, pTmp); }
/** * 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); }
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); }
static void _sg_workingdir__get_entry2(SG_context * pCtx, SG_repo * pRepo, const SG_pathname * pPathSub, const char * pszGid, SG_treenode_entry_type type, const char * pszidHidContent, const char * pszidHidXattrs, SG_int64 iAttributeBits, SG_vhash * pvhTimestamps) { SG_file* pFile = NULL; SG_string* pstrLink = NULL; SG_byte* pBytes = NULL; SG_vhash * pvhGid = NULL; if (SG_TREENODEENTRY_TYPE_DIRECTORY == type) { /* create the directory and then recurse into it */ SG_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx, pPathSub) ); SG_ERR_CHECK( _sg_workingdir__get_dir(pCtx, pRepo, pPathSub, pszidHidContent, pvhTimestamps) ); } else if (SG_TREENODEENTRY_TYPE_REGULAR_FILE == type) { SG_ERR_CHECK( SG_file__open__pathname(pCtx, pPathSub, SG_FILE_RDWR | SG_FILE_CREATE_NEW, SG_FSOBJ_PERMS__MASK, &pFile) ); SG_ERR_CHECK( SG_repo__fetch_blob_into_file(pCtx, pRepo, pszidHidContent, pFile, NULL) ); SG_ERR_CHECK( SG_file__close(pCtx, &pFile) ); } else if (SG_TREENODEENTRY_TYPE_SYMLINK == type) { SG_uint64 iLenBytes = 0; SG_ERR_CHECK( SG_repo__fetch_blob_into_memory(pCtx, pRepo, pszidHidContent, &pBytes, &iLenBytes) ); SG_ERR_CHECK( SG_STRING__ALLOC__BUF_LEN(pCtx, &pstrLink, pBytes, (SG_uint32) iLenBytes) ); SG_ERR_CHECK( SG_fsobj__symlink(pCtx, pstrLink, pPathSub) ); SG_NULLFREE(pCtx, pBytes); SG_STRING_NULLFREE(pCtx, pstrLink); } else { SG_ERR_THROW(SG_ERR_NOTIMPLEMENTED); } if (pszidHidXattrs) { #ifdef SG_BUILD_FLAG_FEATURE_XATTR SG_ERR_CHECK( _sg_workingdir__set_xattrs(pCtx, pRepo, pPathSub, pszidHidXattrs) ); #else // TODO do we need to stuff something into the pendingtree to remind us // TODO that the entry originally had an XAttr and we just didn't restore // TODO it when we populated the WD on this Windows system? #endif } SG_ERR_CHECK( SG_attributes__bits__apply(pCtx, pPathSub, iAttributeBits) ); if (pvhTimestamps && (SG_TREENODEENTRY_TYPE_REGULAR_FILE == type)) { SG_fsobj_stat stat; SG_int64 iTimeNow; SG_ERR_CHECK( SG_fsobj__stat__pathname(pCtx, pPathSub, &stat) ); SG_ERR_CHECK( SG_time__get_milliseconds_since_1970_utc(pCtx, &iTimeNow) ); SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvhGid) ); SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pvhGid, "mtime_ms", stat.mtime_ms) ); SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pvhGid, "clock_ms", iTimeNow) ); SG_ERR_CHECK( SG_vhash__add__vhash(pCtx, pvhTimestamps, pszGid, &pvhGid) ); // this steals our vhash } fail: SG_VHASH_NULLFREE(pCtx, pvhGid); }