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);
}
Beispiel #3
0
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);
}