void u0038_test_version(SG_context * pCtx) { /* This test pokes around in closet internals in ways normal closet callers shouldn't. */ SG_string* pstrEnv = NULL; SG_uint32 len; SG_pathname* pPathCloset = NULL; SG_pathname* pPathClosetVersion = NULL; SG_pathname* pPathClosetVersionBackup = NULL; SG_file* pFile = NULL; SG_vhash* pvh = NULL; /* Deliberately making this break for closet version 3 -- current is version 2. */ SG_byte buf[3]; VERIFY_ERR_CHECK( SG_environment__get__str(pCtx, "SGCLOSET", &pstrEnv, &len) ); if (len) { VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPathCloset, SG_string__sz(pstrEnv)) ); } else { VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__USER_APPDATA_DIRECTORY(pCtx, &pPathCloset) ); VERIFY_ERR_CHECK( SG_pathname__append__from_sz(pCtx, pPathCloset, ".sgcloset") ); } VERIFY_ERR_CHECK( SG_pathname__alloc__pathname_sz(pCtx, &pPathClosetVersion, pPathCloset, "version") ); VERIFY_ERR_CHECK( SG_pathname__alloc__pathname_sz(pCtx, &pPathClosetVersionBackup, pPathCloset, "version.bak") ); VERIFY_ERR_CHECK( SG_fsobj__move__pathname_pathname(pCtx, pPathClosetVersion, pPathClosetVersionBackup) ); VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx, pPathClosetVersion, SG_FILE_OPEN_OR_CREATE|SG_FILE_WRONLY|SG_FILE_TRUNC, 0644, &pFile) ); VERIFY_ERR_CHECK( SG_file__write(pCtx, pFile, sizeof(buf), buf, NULL) ); VERIFY_ERR_CHECK( SG_file__close(pCtx, &pFile) ); SG_closet__descriptors__list(pCtx, &pvh); VERIFY_COND("", SG_context__err_equals(pCtx, SG_ERR_UNSUPPORTED_CLOSET_VERSION)); SG_ERR_DISCARD; VERIFY_ERR_CHECK( SG_fsobj__remove__pathname(pCtx, pPathClosetVersion) ); VERIFY_ERR_CHECK( SG_fsobj__move__pathname_pathname(pCtx, pPathClosetVersionBackup, pPathClosetVersion) ); /* Common cleanup */ fail: SG_STRING_NULLFREE(pCtx, pstrEnv); SG_PATHNAME_NULLFREE(pCtx, pPathCloset); SG_PATHNAME_NULLFREE(pCtx, pPathClosetVersion); SG_PATHNAME_NULLFREE(pCtx, pPathClosetVersionBackup); SG_FILE_NULLCLOSE(pCtx, pFile); SG_VHASH_NULLFREE(pCtx, pvh); }
void u0038_test_ridesc(SG_context * pCtx) { SG_closet_descriptor_handle* ph = NULL; SG_vhash* pvh = NULL; SG_vhash* pvh_all = NULL; SG_uint32 count = 0; SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "1") ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add_begin(pCtx, "1", NULL, NULL, NULL, NULL, &pvh, &ph) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add_commit(pCtx, &ph, pvh, SG_REPO_STATUS__NORMAL)); SG_VHASH_NULLFREE(pCtx, pvh); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__remove(pCtx, "1") ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "2") ); /* This may or may not be an error */ /* delete one that is not there should be an error */ VERIFY_ERR_CHECK_HAS_ERR_DISCARD( SG_closet__descriptors__remove(pCtx, "2") ); /* fetch one that is not there should be an error */ VERIFY_ERR_CHECK_HAS_ERR_DISCARD( SG_closet__descriptors__get(pCtx, "2", NULL, &pvh) ); VERIFY_COND("", pvh==NULL); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "3") ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "4") ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add_begin(pCtx, "3", NULL, NULL, NULL, NULL, &pvh, &ph) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add_commit(pCtx, &ph, pvh, SG_REPO_STATUS__NORMAL) ); SG_VHASH_NULLFREE(pCtx, pvh); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add_begin(pCtx, "4", NULL, NULL, NULL, NULL, &pvh, &ph) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add_commit(pCtx, &ph, pvh, SG_REPO_STATUS__NORMAL) ); SG_VHASH_NULLFREE(pCtx, pvh); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__get(pCtx, "3", NULL, &pvh) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__list(pCtx, &pvh_all) ); VERIFY_ERR_CHECK_DISCARD( SG_vhash__count(pCtx, pvh_all, &count) ); /* adding a duplicate name should be an error */ VERIFY_ERR_CHECK_ERR_EQUALS_DISCARD( SG_closet__descriptors__add_begin(pCtx, "3", NULL, NULL, NULL, NULL, NULL, &ph), SG_ERR_REPO_ALREADY_EXISTS); VERIFY_COND("count", (count >= 2)); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "3") ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "4") ); SG_VHASH_NULLFREE(pCtx, pvh_all); SG_VHASH_NULLFREE(pCtx, pvh); }
void u0038_test_ridesc(SG_context * pCtx) { SG_vhash* pvh = NULL; SG_vhash* pvh2 = NULL; SG_vhash* pvh_all = NULL; SG_uint32 count = 0; VERIFY_ERR_CHECK_DISCARD( SG_VHASH__ALLOC(pCtx, &pvh) ); VERIFY_ERR_CHECK_DISCARD( SG_vhash__add__string__sz(pCtx, pvh, "hello", "world") ); VERIFY_ERR_CHECK_DISCARD( SG_vhash__add__string__sz(pCtx, pvh, "hola", "mundo") ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "1") ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add(pCtx, "1", pvh) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__remove(pCtx, "1") ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "2") ); /* This may or may not be an error */ /* delete one that is not there should be an error */ VERIFY_ERR_CHECK_HAS_ERR_DISCARD( SG_closet__descriptors__remove(pCtx, "2") ); /* fetch one that is not there should be an error */ VERIFY_ERR_CHECK_HAS_ERR_DISCARD( SG_closet__descriptors__get(pCtx, "2", &pvh2) ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "3") ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "4") ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add(pCtx, "3", pvh) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add(pCtx, "4", pvh) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__get(pCtx, "3", &pvh2) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__list(pCtx, &pvh_all) ); VERIFY_ERR_CHECK_DISCARD( SG_vhash__count(pCtx, pvh_all, &count) ); VERIFY_COND("count", (count >= 2)); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "3") ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "4") ); SG_VHASH_NULLFREE(pCtx, pvh_all); SG_VHASH_NULLFREE(pCtx, pvh); SG_VHASH_NULLFREE(pCtx, pvh2); }
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); }