/**
 * Add the given "entryname" to the portability-collider and THROW
 * if there are any issues/problems.
 *
 * Since a PARTIAL COMMIT has the ability to include some changes
 * and not include other changes, we have to re-verify that the
 * set of items to be included in a TREENODE is well-defined.
 *
 * pszEntryname contains the item's entryname as we want it to
 * appear in the final TREENODE/TREENODEENTRY.
 *
 * pStringRepoPath contains the item's path for error messages.
 * the entryname in this path may be different from the given
 * entryname (such as when we want to test with the baseline
 * version of the entryname for a non-participating item, but
 * want to complain using the current pathname).
 * 
 */
void sg_wc_tx__commit__queue__utils__check_port(SG_context * pCtx,
												SG_wc_port * pPort,
												const char * pszEntryname,
												SG_treenode_entry_type tneType,
												const SG_string * pStringRepoPath)
{
	const SG_string * pStringItemLog = NULL;		// we don't own this
	SG_wc_port_flags portFlags;	
	SG_bool bIsDuplicate;

	SG_ERR_CHECK(  SG_wc_port__add_item(pCtx, pPort, NULL, pszEntryname, tneType,
										&bIsDuplicate)  );
	if (bIsDuplicate)
		SG_ERR_THROW2(  SG_ERR_PENDINGTREE_PARTIAL_CHANGE_COLLISION,
						(pCtx, "Partial commit would cause collision: '%s' (%s)",
						 pszEntryname,
						 SG_string__sz(pStringRepoPath))  );

	SG_ERR_CHECK(  SG_wc_port__get_item_result_flags(pCtx, pPort, pszEntryname,
													 &portFlags, &pStringItemLog)  );
	if (portFlags)
		SG_ERR_THROW2(  SG_ERR_WC_PORT_FLAGS,
						(pCtx, "Partial commit could (potentially) cause problems: '%s' (%s)\n%s",
						 pszEntryname,
						 SG_string__sz(pStringRepoPath),
						 SG_string__sz(pStringItemLog))  );

	// the item does not cause problems.

fail:
	return;
}
/**
 * Create a pathname in the per-file temp-dir for one
 * version of the file.
 *
 * We use the ancestor version of the entryname
 * to avoid issues with pending renames.
 * 
 */
void _sg_mrg__create_pathname_for_conflict_file(SG_context * pCtx,
												SG_mrg * pMrg,
												SG_mrg_cset_entry_conflict * pMrgCSetEntryConflict,
												const char * pszPrefix,
												SG_pathname ** ppPathReturned)
{
	SG_pathname * pPath = NULL;
	SG_string * pString = NULL;

	SG_ERR_CHECK(  _sg_mrg__ensure_temp_dir_for_file_conflict(pCtx, pMrg, pMrgCSetEntryConflict)  );

	// create something like: "<sgtemp>/<gid7>_YYYYMMDD_<k>/<prefix>~<entryname>"

	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pString)  );
	SG_ERR_CHECK(  SG_string__sprintf(pCtx, pString, "%s~%s",
									  pszPrefix,
									  SG_string__sz(pMrgCSetEntryConflict->pMrgCSetEntry_Ancestor->pStringEntryname))  );
	SG_ERR_CHECK(  SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPath,
												   pMrgCSetEntryConflict->pPathTempDirForFile,
												   SG_string__sz(pString))  );

	SG_STRING_NULLFREE(pCtx, pString);
	*ppPathReturned = pPath;
	return;

fail:
	SG_STRING_NULLFREE(pCtx, pString);
	SG_PATHNAME_NULLFREE(pCtx, pPath);
}
Пример #3
0
void SG_getopt__print_option(SG_context* pCtx, SG_console_stream cs, SG_getopt_option* opt, const char * overrideDesc)
{
	SG_string *opts;

	if (opt == NULL)
    {
		SG_ERR_IGNORE(  SG_console(pCtx, cs, "?")  );
		return;
    }

	SG_ERR_CHECK(  SG_string__alloc(pCtx, &opts)  );

	/* We have a valid option which may or may not have a "short
		name" (a single-character alias for the long option). */
	if (opt->optch <= 255)
		SG_ERR_CHECK(  SG_string__sprintf(pCtx, opts, "-%c [--%s]", opt->optch, opt->pStringName)  );
	else
		SG_ERR_CHECK(  SG_string__sprintf(pCtx, opts, "--%s", opt->pStringName)  );

	if (opt->has_arg)
		SG_ERR_CHECK(  SG_string__append__sz(pCtx, opts, " ARG")  );

	if (overrideDesc)
		SG_ERR_IGNORE(  SG_console(pCtx, cs, "%-20s :  %s\n", SG_string__sz(opts), overrideDesc)  );
	else
		SG_ERR_IGNORE(  SG_console(pCtx, cs, "%-20s :  %s\n", SG_string__sz(opts), opt->pStringDescription)  );


fail:
	SG_STRING_NULLFREE(pCtx, opts);
}
Пример #4
0
void SG_localsettings__varray__append(SG_context * pCtx, const char* psz_path, const char* pValue)
{
	SG_jsondb* p = NULL;
    SG_string* pstr = NULL;
    SG_varray* pva = NULL;
    SG_string* pstr_path_found = NULL;

	SG_ASSERT(pCtx);
	SG_NONEMPTYCHECK_RETURN(psz_path);

    SG_ERR_CHECK(  SG_closet__get_localsettings(pCtx, &p)  );
    SG_ERR_CHECK(  SG_localsettings__get__varray(pCtx, psz_path, NULL, &pva, &pstr_path_found)  );
    if (!pstr_path_found)
    {
        // this came from factory defaults.
        SG_ERR_CHECK(  SG_string__alloc(pCtx, &pstr_path_found)  );
        SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr_path_found, "%s/%s", SG_LOCALSETTING__SCOPE__MACHINE, psz_path)  );
        SG_ERR_CHECK(  SG_localsettings__update__varray(pCtx, SG_string__sz(pstr_path_found), pva)  );
    }

    SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr)  );
    SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr, "%s/#", SG_string__sz(pstr_path_found))  );
	SG_ERR_CHECK(  SG_jsondb__update__string__sz(pCtx, p, SG_string__sz(pstr), SG_TRUE, pValue)  );

fail:
    SG_STRING_NULLFREE(pCtx, pstr);
	SG_JSONDB_NULLFREE(pCtx, p);
    SG_VARRAY_NULLFREE(pCtx, pva);
    SG_STRING_NULLFREE(pCtx, pstr_path_found);
}
Пример #5
0
void SG_sync__remember_sync_target(SG_context* pCtx, const char * pszLocalRepoDescriptor, const char * pszSyncTarget)
{
	SG_string * pString = NULL;
	SG_varray * pva_targets = NULL;
	SG_bool bFound = SG_FALSE;
	SG_uint32 nEntry = 0;

	//Save this destination to the local setting of previously used destinations.
	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pString)  );
	SG_ERR_CHECK(  SG_string__sprintf(pCtx, pString, "%s/%s/%s",
									SG_LOCALSETTING__SCOPE__INSTANCE,
									pszLocalRepoDescriptor,
									SG_LOCALSETTING__SYNC_TARGETS)  );
	SG_ERR_CHECK(  SG_localsettings__get__varray(pCtx, SG_string__sz(pString), NULL, &pva_targets, NULL)  );
	if (pva_targets)
		SG_ERR_CHECK(  SG_varray__find__sz(pCtx, pva_targets, pszSyncTarget, &bFound, &nEntry)  );
	else
		SG_VARRAY__ALLOC(pCtx, &pva_targets);
	if (!bFound)
	{
		SG_ERR_CHECK(  SG_varray__append__string__sz(pCtx, pva_targets, pszSyncTarget)  );
		SG_ERR_CHECK(  SG_localsettings__update__varray(pCtx, SG_string__sz(pString), pva_targets)  );
	}
fail:
	SG_STRING_NULLFREE(pCtx, pString);
	SG_VARRAY_NULLFREE(pCtx, pva_targets);
}
void sg_sync_client__http__get_dagnode_info(
    SG_context* pCtx,
    SG_sync_client* pSyncClient,
    SG_vhash* pvhRequest,
    SG_history_result** ppInfo)
{
    SG_string* pstrRequest = NULL;
    char* pszUrl = NULL;
    SG_string* pstr = NULL;

    SG_NULLARGCHECK_RETURN(pSyncClient);
    SG_NULLARGCHECK_RETURN(pvhRequest);
    SG_NULLARGCHECK_RETURN(ppInfo);

    SG_ERR_CHECK(  _get_sync_url(pCtx, pSyncClient->psz_remote_repo_spec, SYNC_URL_SUFFIX "/incoming" JSON_URL_SUFFIX, NULL, NULL, &pszUrl)  );


    SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstrRequest)  );
    SG_ERR_CHECK(  SG_vhash__to_json(pCtx, pvhRequest, pstrRequest)  );

    SG_ERR_CHECK(  do_url(pCtx, pszUrl, "GET", SG_string__sz(pstrRequest), pSyncClient->psz_username, pSyncClient->psz_password, &pstr, NULL, SG_TRUE)  );
    SG_ERR_CHECK(  SG_history_result__from_json(pCtx, SG_string__sz(pstr), ppInfo)  );

    /* fall through */
fail:
    SG_NULLFREE(pCtx, pszUrl);
    SG_STRING_NULLFREE(pCtx, pstrRequest);
    SG_STRING_NULLFREE(pCtx, pstr);
}
void SG_password__get(
	SG_context *pCtx,
	const char *szRepoSpec,
	const char *username,
	SG_string **pPassword)
{
	SG_byte *pwdata = NULL;
	SG_uint32 pwlen;
	SG_string *password = NULL;
	SG_string *path = NULL;
	SG_string *server = NULL;
	SecProtocolType proto;
	SG_uint32 port;
	SG_bool isValid = SG_FALSE;

	OSStatus findRes;

	SG_NULLARGCHECK_RETURN(pPassword);
	*pPassword = NULL;

	SG_NULLARGCHECK(username);
	SG_NULLARGCHECK(szRepoSpec);

	SG_ERR_CHECK(  _sg_password__parse_url(pCtx, szRepoSpec,
		&isValid, &proto, &server, &path, &port)  );

	if (! isValid)
		SG_ERR_THROW(SG_ERR_NOTIMPLEMENTED);

	findRes = SecKeychainFindInternetPassword(
		NULL,
		SG_STRLEN( SG_string__sz(server) ), SG_string__sz(server),
		0, NULL,
		SG_STRLEN(username), username,
		SG_STRLEN( SG_string__sz(path) ), SG_string__sz(path),
		port, proto, kSecAuthenticationTypeDefault,
		(UInt32 *)&pwlen, (void **)&pwdata,
		NULL);

	if (findRes == errSecItemNotFound ||
		findRes == errSecInteractionNotAllowed)
		goto fail;
	else if (findRes != errSecSuccess)
		_SG_THROW_MAC_SEC_ERROR(findRes);

	SG_ERR_CHECK(  SG_STRING__ALLOC__BUF_LEN(pCtx, &password, pwdata, pwlen)  );
	*pPassword = password;
	password = NULL;

fail:
	if (pwdata)
		SecKeychainItemFreeContent(NULL, pwdata);
	SG_STRING_NULLFREE(pCtx, path);
	SG_STRING_NULLFREE(pCtx, server);
	SG_STRING_NULLFREE(pCtx, password);
}
Пример #8
0
void SG_localsettings__varray__remove_first_match(SG_context * pCtx, const char* psz_path, const char* psz_val)
{
	SG_jsondb* p = NULL;
    SG_string* pstr_path_element = NULL;
    SG_varray* pva = NULL;
    SG_uint32 ndx = 0;
    SG_uint32 count = 0;
    SG_uint32 i = 0;
    SG_bool b_found = SG_FALSE;
    SG_string* pstr_path_found = NULL;

	SG_ASSERT(pCtx);
	SG_NONEMPTYCHECK_RETURN(psz_path);

    SG_ERR_CHECK(  SG_closet__get_localsettings(pCtx, &p)  );
    SG_ERR_CHECK(  SG_localsettings__get__varray(pCtx, psz_path, NULL, &pva, &pstr_path_found)  );
    if (pva)
    {
        if (!pstr_path_found)
        {
            // this came from factory defaults.
            SG_ERR_CHECK(  SG_string__alloc(pCtx, &pstr_path_found)  );
            SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr_path_found, "%s/%s", SG_LOCALSETTING__SCOPE__MACHINE, psz_path)  );
            SG_ERR_CHECK(  SG_localsettings__update__varray(pCtx, SG_string__sz(pstr_path_found), pva)  );
        }

        SG_ERR_CHECK(  SG_varray__count(pCtx, pva, &count)  );
        for (i=0; i<count; i++)
        {
            const char* psz = NULL;

            SG_ERR_CHECK(  SG_varray__get__sz(pCtx, pva, i, &psz)  );
            if (0 == strcmp(psz, psz_val))
            {
                b_found = SG_TRUE;
                ndx = i;
                break;
            }
        }
        if (b_found)
        {
            SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr_path_element)  );
            SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr_path_element, "%s/%d", SG_string__sz(pstr_path_found), ndx)  );
            SG_ERR_CHECK(  SG_jsondb__remove(pCtx, p, SG_string__sz(pstr_path_element))  );
        }
    }

fail:
    SG_VARRAY_NULLFREE(pCtx, pva);
    SG_STRING_NULLFREE(pCtx, pstr_path_found);
    SG_STRING_NULLFREE(pCtx, pstr_path_element);
	SG_JSONDB_NULLFREE(pCtx, p);
}
Пример #9
0
static void _default_replacer(
	SG_context * pCtx,
	const _request_headers *pRequestHeaders,
	SG_string *keyword,
	SG_string *replacement,
	SG_bool *needEncoding)
{
	SG_string *pstrRepoDescriptorName = NULL;
	SG_repo *repo = NULL;

	SG_UNUSED(pRequestHeaders);

	if (seq(keyword, "WFREPO"))
	{
		SG_ERR_CHECK(  _getDescriptorName(pCtx, pRequestHeaders, &pstrRepoDescriptorName)  );
		SG_ERR_CHECK(  SG_string__set__string(pCtx, replacement, pstrRepoDescriptorName)  );
	}
	else if (seq(keyword, "USERNAME"))
	{
		SG_ERR_CHECK(  _getDescriptorName(pCtx, pRequestHeaders, &pstrRepoDescriptorName)  );

		if (pstrRepoDescriptorName != NULL)
		{
			SG_ERR_CHECK(  SG_repo__open_repo_instance(pCtx, SG_string__sz(pstrRepoDescriptorName), &repo)  );
		}

		SG_ERR_CHECK(  _getUserId(pCtx, repo, replacement)  );
	}
	else if (seq(keyword, "EMAIL"))
	{
		SG_ERR_CHECK(  _getDescriptorName(pCtx, pRequestHeaders, &pstrRepoDescriptorName)  );

		if (pstrRepoDescriptorName != NULL)
		{
			SG_ERR_CHECK(  SG_repo__open_repo_instance(pCtx, SG_string__sz(pstrRepoDescriptorName), &repo)  );
		}

		SG_ERR_CHECK( _getUserEmail(pCtx, repo, replacement)  );
	}
	else if (seq(keyword, "USERSELECTION"))
	{
		SG_ERR_CHECK(  _getDescriptorName(pCtx, pRequestHeaders, &pstrRepoDescriptorName)  );
		SG_ERR_CHECK(  _fillInUserSelection(pCtx, pstrRepoDescriptorName, replacement)  );
		*needEncoding = SG_FALSE;
	}

fail:
	SG_STRING_NULLFREE(pCtx, pstrRepoDescriptorName);
	SG_REPO_NULLFREE(pCtx, repo);
}
Пример #10
0
void SG_dbrecord__save_to_repo(SG_context* pCtx, SG_dbrecord * pRecord, SG_repo * pRepo, SG_repo_tx_handle* pRepoTx, SG_uint64* iBlobFullLength)
{
	SG_string * pString = NULL;
	char* pszHidComputed = NULL;
    SG_uint32 iLength = 0;

	SG_NULLARGCHECK_RETURN(pRepo);
	SG_NULLARGCHECK_RETURN(pRecord);

	// serialize the dbrecord into JSON string.

	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pString)  );
	SG_ERR_CHECK(  SG_dbrecord__to_json(pCtx, pRecord,pString)  );

#if 0
    printf("%s\n", SG_string__sz(pString)); // TODO remove this
#endif

	// remember the length of the blob
    iLength = SG_string__length_in_bytes(pString);
	*iBlobFullLength = (SG_uint64) iLength;

	// create a blob in the repository using the JSON string.  this computes the HID and returns it.

	SG_repo__store_blob_from_memory(pCtx,
		pRepo,pRepoTx,
        NULL, // TODO pass the record id into here
        SG_FALSE,
		(const SG_byte *)SG_string__sz(pString),
		iLength,
		&pszHidComputed);
	if (!SG_context__has_err(pCtx) || SG_context__err_equals(pCtx, SG_ERR_BLOBFILEALREADYEXISTS))
	{
		// freeeze the dbrecord memory-object and effectively make it read-only
		// from this point forward.  we give up our ownership of the HID.

		SG_ASSERT(  pszHidComputed  );
		_sg_dbrecord__freeze(pCtx, pRecord, pszHidComputed);
		pszHidComputed = NULL;

		SG_STRING_NULLFREE(pCtx, pString);
		return;  // return _OK or __BLOBFILEALREADYEXISTS
	}

fail:
	SG_STRING_NULLFREE(pCtx, pString);
	SG_NULLFREE(pCtx, pszHidComputed);
}
void SG_password__set(
	SG_context* pCtx,
	const char *szRepoSpec,
	SG_string *pUserName,
	SG_string *pPassword)
{
	const char *username;
	const char *password;
	SG_string *path = NULL;
	SG_string *server = NULL;
	SG_string *proto = NULL;
	SG_uint32 port;
	SG_bool isValid = SG_FALSE;
	GnomeKeyringResult saveRes = 0;
	guint32 itemid = 0;

	if (! SG_password__supported())
		goto fail;

	SG_NULLARGCHECK(pUserName);
	SG_NULLARGCHECK(pPassword);
	SG_NULLARGCHECK(szRepoSpec);

	username = SG_string__sz(pUserName);
	password = SG_string__sz(pPassword);

	SG_ERR_CHECK(  _sg_password__parse_url(pCtx, szRepoSpec,
		&isValid, &proto, &server, &path, &port)  );

	if (! isValid)
		SG_ERR_THROW(SG_ERR_NOTIMPLEMENTED);

	saveRes = gnome_keyring_set_network_password_sync(
		NULL,
		username, NULL,
		SG_string__sz(server), SG_string__sz(path),
		SG_string__sz(proto), NULL, (guint32)port,
		password,
		&itemid);

	if ((saveRes != GNOME_KEYRING_RESULT_OK) && (saveRes != GNOME_KEYRING_RESULT_NO_MATCH) && (saveRes != GNOME_KEYRING_RESULT_CANCELLED))
		_SG_THROW_LINUX_SEC_ERROR(saveRes);

fail:
	SG_STRING_NULLFREE(pCtx, path);
	SG_STRING_NULLFREE(pCtx, server);
	SG_STRING_NULLFREE(pCtx, proto);
}
Пример #12
0
void SG_workingdir__generate_and_create_temp_dir_for_purpose(SG_context * pCtx,
															 const SG_pathname * pPathWorkingDirectoryTop,
															 const char * pszPurpose,
															 SG_pathname ** ppPathTempDir)
{
	SG_pathname * pPathTempRoot = NULL;
	SG_pathname * pPath = NULL;
	SG_string * pString = NULL;
	SG_int64 iTimeUTC;
	SG_time tmLocal;
	SG_uint32 kAttempt = 0;

	SG_NONEMPTYCHECK_RETURN(pszPurpose);
	SG_NULLARGCHECK_RETURN(ppPathTempDir);

	// get path to "<wd-top>/.sgtemp".
	SG_ERR_CHECK(  SG_workingdir__get_temp_path(pCtx,pPathWorkingDirectoryTop,&pPathTempRoot)  );

	SG_ERR_CHECK(  SG_time__get_milliseconds_since_1970_utc(pCtx,&iTimeUTC)  );
	SG_ERR_CHECK(  SG_time__decode__local(pCtx,iTimeUTC,&tmLocal)  );

	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx,&pString)  );

	while (1)
	{
		// build path "<wd-top>/.sgtemp/<purpose>_20091201_0".
		// where <purpose> is something like "revert" or "merge".

		SG_ERR_CHECK(  SG_string__sprintf(pCtx,pString,"%s_%04d%02d%02d_%d",
										  pszPurpose,
										  tmLocal.year,tmLocal.month,tmLocal.mday,
										  kAttempt++)  );
		SG_ERR_CHECK(  SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx,&pPath,pPathTempRoot,SG_string__sz(pString))  );

		// try to create a NEW temp directory.  if this path already exists on disk,
		// loop and try again.  if we have a hard errors, just give up.

		SG_fsobj__mkdir_recursive__pathname(pCtx,pPath);
		if (SG_context__has_err(pCtx) == SG_FALSE)
			goto success;

		if (SG_context__err_equals(pCtx,SG_ERR_DIR_ALREADY_EXISTS) == SG_FALSE)
			SG_ERR_RETHROW;

		SG_context__err_reset(pCtx);
		SG_PATHNAME_NULLFREE(pCtx,pPath);
	}

success:
	*ppPathTempDir = pPath;

	SG_STRING_NULLFREE(pCtx, pString);
	SG_PATHNAME_NULLFREE(pCtx, pPathTempRoot);
	return;

fail:
	SG_STRING_NULLFREE(pCtx, pString);
	SG_PATHNAME_NULLFREE(pCtx, pPathTempRoot);
	SG_PATHNAME_NULLFREE(pCtx, pPath);
}
/**
 * This is a special case of __get_original_content_hid() that
 * basically doest that and then fetches the blob and returns
 * the actual symlink target.
 *
 * This is a convenience for STATUS that can report 'target'
 * fields rather than (or in addition to) 'hid' for symlinks.
 *
 */
void sg_wc_liveview_item__get_original_symlink_target(SG_context * pCtx,
													  sg_wc_liveview_item * pLVI,
													  SG_wc_tx * pWcTx,
													  SG_string ** ppStringTarget)
{
	const char * pszHidContent;
	SG_string * pStringTarget = NULL;
	SG_byte*    pBuffer   = NULL;
	SG_uint64   uSize     = 0u;

	if (pLVI->tneType != SG_TREENODEENTRY_TYPE_SYMLINK)
		SG_ERR_THROW2_RETURN(  SG_ERR_INVALIDARG,
							   (pCtx, "GetOriginalSymlinkTarget: '%s' is not a symlink.",
								SG_string__sz(pLVI->pStringEntryname))  );

	SG_ERR_CHECK(  sg_wc_liveview_item__get_original_content_hid(pCtx, pLVI, pWcTx,
																 SG_FALSE,
																 &pszHidContent)  );
	SG_ERR_CHECK(  SG_repo__fetch_blob_into_memory(pCtx, pWcTx->pDb->pRepo,
												   pszHidContent,
												   &pBuffer, &uSize)  );
	SG_ERR_CHECK(  SG_STRING__ALLOC__BUF_LEN(pCtx, &pStringTarget, pBuffer, (SG_uint32)uSize)  );

	*ppStringTarget = pStringTarget;
	pStringTarget = NULL;

fail:
	SG_STRING_NULLFREE(pCtx, pStringTarget);
	SG_NULLFREE(pCtx, pBuffer);
}
void u0026_jsonparser__test_jsonparser_vhash_2(SG_context * pCtx)
{
	SG_string* pstr1 = NULL;
	SG_string* pstr2 = NULL;
	SG_vhash* pvh = NULL;

	VERIFY_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr1)  );
	VERIFY_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr2)  );

	VERIFY_ERR_CHECK(  u0026_jsonparser__create_2(pCtx, pstr1)  );

	SG_VHASH__ALLOC__FROM_JSON__SZ(pCtx, &pvh, SG_string__sz(pstr1));
	VERIFY_COND("from_json", !SG_context__has_err(pCtx));
	VERIFY_COND("from_json", pvh);

	SG_context__err_reset(pCtx);
	SG_vhash__to_json(pCtx, pvh, pstr2);
	VERIFY_COND("from_json", !SG_context__has_err(pCtx));

	// TODO do some checks

fail:
	SG_STRING_NULLFREE(pCtx, pstr1);
	SG_STRING_NULLFREE(pCtx, pstr2);
	SG_VHASH_NULLFREE(pCtx, pvh);
}
/**
 * The values for RENAME, MOVE, ATTRBITS, SYMLINKS, and SUBMODULES are collapsable.  (see below)
 * In the corresponding rbUnique's we only need to remember the set of unique values for the
 * field.  THESE ARE THE KEYS IN THE prbUnique.
 *
 * As a convenience, we associate a vector of entries with each key.  These form a many-to-one
 * thing so that we can report all of the entries that have this value.
 *
 * TODO since we should only process a cset once, we should not get any
 * TODO duplicates in the vector, but it might be possible.  i'm not going
 * TODO to worry about it now.  if this becomes a problem, consider doing
 * TODO a unique-insert into the vector -or- making the vector a sub-rbtree.
 *
 */
static void _update_1_rbUnique(SG_context * pCtx, SG_rbtree * prbUnique, const char * pszKey, SG_mrg_cset_entry * pMrgCSetEntry_Leaf_k)
{
	SG_vector * pVec_Allocated = NULL;
	SG_vector * pVec;
	SG_bool bFound;

	SG_ERR_CHECK(  SG_rbtree__find(pCtx,prbUnique,pszKey,&bFound,(void **)&pVec)  );
	if (!bFound)
	{
		SG_ERR_CHECK(  SG_VECTOR__ALLOC(pCtx,&pVec_Allocated,3)  );
		SG_ERR_CHECK(  SG_rbtree__add__with_assoc(pCtx,prbUnique,pszKey,pVec_Allocated)  );
		pVec = pVec_Allocated;
		pVec_Allocated = NULL;			// rbtree owns this now
	}

	SG_ERR_CHECK(  SG_vector__append(pCtx,pVec,pMrgCSetEntry_Leaf_k,NULL)  );

#if TRACE_WC_MERGE
	SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,"_update_1_rbUnique: [%s][%s]\n",
									   pszKey,
									   SG_string__sz(pMrgCSetEntry_Leaf_k->pMrgCSet->pStringCSetLabel))  );
#endif

	return;

fail:
	SG_VECTOR_NULLFREE(pCtx, pVec_Allocated);
}
Пример #16
0
void SG_localsettings__descriptor__update__sz(
	SG_context * pCtx,
	const char * psz_descriptor_name,
	const char * psz_path,
	const char * pValue)
{
	SG_jsondb* p = NULL;
	SG_string* pstr_path = NULL;

	SG_ASSERT(pCtx);
	SG_NONEMPTYCHECK_RETURN(psz_descriptor_name);
	SG_NONEMPTYCHECK_RETURN(psz_path);
	SG_ARGCHECK_RETURN('/' != psz_path[0], psz_path);

	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr_path)  );
	SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr_path, "%s/%s/%s",
		SG_LOCALSETTING__SCOPE__INSTANCE, psz_descriptor_name, psz_path)  );

	SG_ERR_CHECK(  SG_closet__get_localsettings(pCtx, &p)  );
	SG_ERR_CHECK(  SG_jsondb__update__string__sz(pCtx, p, SG_string__sz(pstr_path), SG_TRUE, pValue)  );

fail:
	SG_STRING_NULLFREE(pCtx, pstr_path);
	SG_JSONDB_NULLFREE(pCtx, p);
}
Пример #17
0
void u0038_test_wdmapping(SG_context * pCtx)
{
	SG_vhash* pvh = NULL;
	SG_pathname* pPath = NULL;
	SG_pathname* pMappedPath = NULL;
	SG_string* pstrRepoDescriptorName = NULL;
	char* pszidGid = NULL;

	VERIFY_ERR_CHECK_DISCARD(  SG_PATHNAME__ALLOC(pCtx, &pPath)  );

	VERIFY_ERR_CHECK_DISCARD(  SG_pathname__set__from_cwd(pCtx, pPath)  );
	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, "r1")  );
	VERIFY_ERR_CHECK_DISCARD(  SG_closet__descriptors__add(pCtx, "r1", pvh)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_workingdir__set_mapping(pCtx, pPath, "r1", NULL)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_workingdir__find_mapping(pCtx, pPath, &pMappedPath, &pstrRepoDescriptorName, &pszidGid)  );
	VERIFY_COND("ridesc match", (0 == strcmp("r1", SG_string__sz(pstrRepoDescriptorName))));
	VERIFY_ERR_CHECK_DISCARD(  SG_pathname__append__from_sz(pCtx, pPath, "foo")  );
	VERIFY_ERR_CHECK_DISCARD(  SG_pathname__append__from_sz(pCtx, pPath, "bar")  );
	VERIFY_ERR_CHECK_DISCARD(  SG_pathname__append__from_sz(pCtx, pPath, "plok")  );

	SG_STRING_NULLFREE(pCtx, pstrRepoDescriptorName);
	SG_PATHNAME_NULLFREE(pCtx, pMappedPath);

	VERIFY_ERR_CHECK_DISCARD(  SG_workingdir__find_mapping(pCtx, pPath, &pMappedPath, &pstrRepoDescriptorName, &pszidGid)  );

	SG_STRING_NULLFREE(pCtx, pstrRepoDescriptorName);
	SG_PATHNAME_NULLFREE(pCtx, pMappedPath);
	SG_PATHNAME_NULLFREE(pCtx, pPath);

	SG_VHASH_NULLFREE(pCtx, pvh);
}
Пример #18
0
void SG_localsettings__update__varray(SG_context * pCtx, const char * psz_path, const SG_varray * pValue)
{
	SG_jsondb* p = NULL;
    SG_string* pstr_path = NULL;

    SG_ASSERT(pCtx);
    SG_NONEMPTYCHECK_RETURN(psz_path);
    SG_NULLARGCHECK_RETURN(pValue);

    SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr_path)  );
    if ('/' == psz_path[0])
    {
        SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr_path, "%s", psz_path)  );
    }
    else
    {
        SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr_path, "%s/%s", SG_LOCALSETTING__SCOPE__MACHINE, psz_path)  );
    }

    SG_ERR_CHECK(  SG_closet__get_localsettings(pCtx, &p)  );

	SG_ERR_CHECK(  SG_jsondb__update__varray(pCtx, p, SG_string__sz(pstr_path), SG_TRUE, pValue)  );

fail:
	SG_JSONDB_NULLFREE(pCtx, p);
    SG_STRING_NULLFREE(pCtx, pstr_path);
}
void sg_sync_client__http__push_commit(
    SG_context* pCtx,
    SG_sync_client * pSyncClient,
    SG_sync_client_push_handle* pPush,
    SG_vhash** ppResult)
{
    char* pszUrl = NULL;
    sg_sync_client_http_push_handle* pMyPush = (sg_sync_client_http_push_handle*)pPush;
    SG_string* pstr = NULL;

    SG_NULLARGCHECK_RETURN(pSyncClient);
    SG_NULLARGCHECK_RETURN(pPush);
    SG_NULLARGCHECK_RETURN(ppResult);

    SG_ERR_CHECK(  _get_sync_url(pCtx, pSyncClient->psz_remote_repo_spec, SYNC_URL_SUFFIX, pMyPush->pszPushId, NULL, &pszUrl)  );

    SG_ERR_CHECK(  do_url(
                       pCtx,
                       pszUrl,
                       "POST",
                       NULL,
                       pSyncClient->psz_username,
                       pSyncClient->psz_password,
                       &pstr,
                       NULL,
                       SG_TRUE)  );

    SG_ERR_CHECK(  SG_vhash__alloc__from_json__sz(pCtx, ppResult, SG_string__sz(pstr))  );

    /* fall through */
fail:
    SG_STRING_NULLFREE(pCtx, pstr);
    SG_NULLFREE(pCtx, pszUrl);
}
void SG_password__forget_all(SG_context *pCtx)
{
	SG_string* pstrFilter = NULL;
	WCHAR* pwszFilter = NULL;
	DWORD numCreds = 0;
	PCREDENTIAL* paCreds = NULL;
	SG_uint32 i;

	SG_ERR_CHECK(  SG_STRING__ALLOC__SZ(pCtx, &pstrFilter, KEY_PREFIX)  );
	SG_ERR_CHECK(  SG_string__append__sz(pCtx, pstrFilter, KEY_SEPARATOR)  );
	SG_ERR_CHECK(  SG_string__append__sz(pCtx, pstrFilter, "*")  );
	SG_ERR_CHECK(  SG_utf8__extern_to_os_buffer__wchar(pCtx, SG_string__sz(pstrFilter), &pwszFilter, NULL)  );

	if ( !CredEnumerateW( pwszFilter, 0, &numCreds, &paCreds) )
	{
		DWORD err = GetLastError();
		if ( ERROR_NOT_FOUND != err)
			SG_ERR_THROW2( SG_ERR_GETLASTERROR(err), (pCtx, "%s", "unable to enumerate saved credentials") );
	}

	for (i = 0; i < numCreds; i++)
	{
		if ( !CredDeleteW( paCreds[i]->TargetName, CRED_TYPE_GENERIC, 0) )
			SG_ERR_THROW2( SG_ERR_GETLASTERROR(GetLastError()), (pCtx, "%s", "unable to delete credential") );
	}

	/* fall through */
fail:
	SG_NULLFREE(pCtx, pwszFilter);
	SG_STRING_NULLFREE(pCtx, pstrFilter);
}
Пример #21
0
SG_error SG_context__err_to_console(SG_context* pCtx, SG_console_stream cs)
{
	SG_error err;
	SG_string* pErrStr = NULL;

	SG_ASSERT( pCtx );
//	SG_ASSERT( pCtx->level < SG_CONTEXT_MAX_ERROR_LEVELS );

	if (pCtx->level > 0)		// when in an error-on-error (level > 0), there is NO error string.
		return SG_ERR_OK;		// so we don't need to do anything.

	// get the full error string about the error at the current level.

	err = SG_context__err_to_string(pCtx, &pErrStr);
	if (SG_IS_ERROR(err))		// an allocation/formatting error, just give up.
		return err;

	// write the error string/message to the console.  we push a new level
	// so that any problems converting the message to the user's locale or
	// writing to the console device don't trash the current error context.
	//
	// ***DO NOT JUMP OUT OF THIS PUSH..POP BLOCK.***

	SG_context__push_level(pCtx);
	{
		SG_console(pCtx, cs, SG_string__sz(pErrStr));

		err = pCtx->errValues[pCtx->level];		// we return the error value of the conversion/writing.
	}
	SG_context__pop_level(pCtx);

	SG_STRING_NULLFREE(pCtx, pErrStr);

	return err;
}
Пример #22
0
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);

}
Пример #23
0
static void do_one_template(
    SG_context* pCtx,
	SG_repo* pRepo,
    SG_uint32 iDagNum,
    SG_audit* pq,
    unsigned char* pjson
    )
{
    SG_vhash* pvh_template = NULL;
    SG_changeset* pcs = NULL;
    SG_dagnode* pdn = NULL;
    SG_zingtx* ptx = NULL;
    SG_string* pstr = NULL;

    // now the main dag
    SG_ERR_CHECK(  SG_zing__begin_tx(pCtx, pRepo, iDagNum, pq->who_szUserId, NULL, &ptx)  );

    SG_ERR_CHECK(  my_strip_comments(pCtx, (char*) pjson, &pstr)  );
    SG_ERR_CHECK(  SG_vhash__alloc__from_json(pCtx, &pvh_template, SG_string__sz(pstr)));

    SG_ERR_CHECK(  SG_zingtx__store_template(pCtx, ptx, &pvh_template)  );

    SG_ERR_CHECK(  SG_zing__commit_tx(pCtx, pq->when_int64, &ptx, &pcs, &pdn, NULL)  );
    SG_STRING_NULLFREE(pCtx, pstr);
    SG_CHANGESET_NULLFREE(pCtx, pcs);
    SG_DAGNODE_NULLFREE(pCtx, pdn);

    // fall thru

fail:
    SG_STRING_NULLFREE(pCtx, pstr);
    SG_CHANGESET_NULLFREE(pCtx, pcs);
    SG_DAGNODE_NULLFREE(pCtx, pdn);
}
void u0025_jsonwriter__verify(SG_context * pCtx, SG_string* pstr)
{
	const char *psz = SG_string__sz(pstr);
	SG_int32* putf32 = NULL;
	SG_uint32 len = 0;
	JSON_checker jc = new_JSON_checker(20);
	SG_uint32 i;
	int ok = 0;

	SG_utf8__to_utf32__sz(pCtx, psz, &putf32, &len);
	for (i=0; i<len; i++)
	{
		ok = JSON_checker_char(jc, putf32[i]);
		VERIFY_COND("JSON_checker_char", ok);
		if (!ok)
		{
			break;
		}
    }

	if (ok)
	{
		ok = JSON_checker_done(jc);
		VERIFY_COND("JSON_checker_done", ok);
	}


	SG_NULLFREE(pCtx, putf32);
}
Пример #25
0
void SG_localsettings__reset(SG_context * pCtx, const char* psz_path)
{
    SG_jsondb* p = NULL;
    SG_string* pstr_path = NULL;

    SG_ASSERT(pCtx);
    SG_NONEMPTYCHECK_RETURN(psz_path);

    SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr_path)  );
    if ('/' == psz_path[0])
    {
        SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr_path, "%s", psz_path)  );
    }
    else
    {
        SG_ERR_CHECK(  SG_string__sprintf(pCtx, pstr_path, "%s/%s", SG_LOCALSETTING__SCOPE__MACHINE, psz_path)  );
    }

    SG_ERR_CHECK(  SG_closet__get_localsettings(pCtx, &p)  );
	SG_jsondb__remove(pCtx, p, SG_string__sz(pstr_path));
    SG_ERR_CHECK_CURRENT_DISREGARD(SG_ERR_NOT_FOUND);

fail:
	SG_JSONDB_NULLFREE(pCtx, p);
    SG_STRING_NULLFREE(pCtx, pstr_path);
}
/**
 * Prompt user for what to do on an individual item.
 *
 */
static void _do_prompt(SG_context * pCtx,
                       const char * pszPrompt,
                       const char * pszChoices,
                       char chDefault,
                       char * pchChoice)
{
    SG_string * pStringInput = NULL;

    while (1)
    {
        const char * pszInput;
        const char * p;

        SG_ERR_CHECK(  SG_console(pCtx, SG_CS_STDOUT, "%s: ", pszPrompt)  );
        SG_ERR_CHECK(  SG_console__readline_stdin(pCtx, &pStringInput)  );
        pszInput = SG_string__sz(pStringInput);
        while ((*pszInput==' ') || (*pszInput=='\t'))
            pszInput++;
        if ((*pszInput==0) || (*pszInput=='\r') || (*pszInput=='\n'))
        {
            *pchChoice = chDefault;
            break;
        }
        p = strchr(pszChoices, *pszInput);
        if (p)
        {
            *pchChoice = *p;
            break;
        }
        SG_STRING_NULLFREE(pCtx, pStringInput);
    }

fail:
    SG_STRING_NULLFREE(pCtx, pStringInput);
}
void u0038_test_wdmapping(SG_context * pCtx)
{
	SG_vhash* pvh = NULL;
	SG_closet_descriptor_handle* ph = NULL;
	SG_pathname* pPath = NULL;
	SG_pathname* pMappedPath = NULL;
	SG_string* pstrRepoDescriptorName = NULL;
	char* pszidGid = NULL;
	char buf_tid[SG_TID_MAX_BUFFER_LENGTH];

	VERIFY_ERR_CHECK_DISCARD(  SG_tid__generate2__suffix(pCtx, buf_tid, sizeof(buf_tid), 32, "u0038")  );
	VERIFY_ERR_CHECK_DISCARD(  SG_PATHNAME__ALLOC__SZ(pCtx, &pPath, buf_tid)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_fsobj__mkdir__pathname(pCtx, pPath)  );

	SG_ERR_IGNORE(  SG_closet__descriptors__remove(pCtx, "r1")  );
	VERIFY_ERR_CHECK_DISCARD(  SG_closet__descriptors__add_begin(pCtx, "r1", 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_workingdir__set_mapping(pCtx, pPath, "r1", NULL)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_workingdir__find_mapping(pCtx, pPath, &pMappedPath, &pstrRepoDescriptorName, &pszidGid)  );
	VERIFY_COND("ridesc match", (0 == strcmp("r1", SG_string__sz(pstrRepoDescriptorName))));
	VERIFY_ERR_CHECK_DISCARD(  SG_pathname__append__from_sz(pCtx, pPath, "foo")  );
	VERIFY_ERR_CHECK_DISCARD(  SG_pathname__append__from_sz(pCtx, pPath, "bar")  );
	VERIFY_ERR_CHECK_DISCARD(  SG_pathname__append__from_sz(pCtx, pPath, "plok")  );

	SG_STRING_NULLFREE(pCtx, pstrRepoDescriptorName);
	SG_PATHNAME_NULLFREE(pCtx, pMappedPath);

	VERIFY_ERR_CHECK_DISCARD(  SG_workingdir__find_mapping(pCtx, pPath, &pMappedPath, &pstrRepoDescriptorName, &pszidGid)  );

	SG_STRING_NULLFREE(pCtx, pstrRepoDescriptorName);
	SG_PATHNAME_NULLFREE(pCtx, pMappedPath);
	SG_PATHNAME_NULLFREE(pCtx, pPath);
}
/**
 * Convert relative path to absolute, but make
 * sure that normalization doesn't take it outside
 * of the working directory.
 *
 * This is just pathname/string parsing; we DO NOT
 * confirm that the path exists or could exist.
 *
 */
void sg_wc_db__path__relative_to_absolute(SG_context * pCtx,
										  const sg_wc_db * pDb,
										  const SG_string * pStringRelativePath,
										  SG_pathname ** ppPathItem)
{
	SG_pathname * pPathWDT = NULL;
	SG_pathname * pPath = NULL;
	SG_uint32 lenWDT;

	// choke if they give us a repo-path.
	SG_ARGCHECK_RETURN(  (SG_string__sz(pStringRelativePath)[0] != '@'), pStringRelativePath  );

	// choke if this WC TX isn't cwd-based.
	SG_ERR_CHECK(  _check_if_relative_paths_allowed(pCtx, pDb)  );

	// clone WDT so that we can force a trailing slash.
	SG_ERR_CHECK(  SG_PATHNAME__ALLOC__COPY(pCtx,
											&pPathWDT,
											pDb->pPathWorkingDirectoryTop)  );
	SG_ERR_CHECK(  SG_pathname__add_final_slash(pCtx, pPathWDT)  );
	lenWDT = SG_pathname__length_in_bytes(pPathWDT);

	// allocate and normalize a new path with the net
	// result rather than writing on the clone (so that
	// we can do the following prefix test safely).
	SG_ERR_CHECK(  SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPath,
												   pPathWDT,
												   SG_string__sz(pStringRelativePath))  );

	if (strncmp(SG_pathname__sz(pPath),
				SG_pathname__sz(pPathWDT),
				lenWDT) != 0)
	{
		SG_ERR_THROW2(  SG_ERR_PATH_NOT_IN_WORKING_COPY,
						(pCtx, "The path '%s' is not inside the working copy rooted at '%s'.",
						 SG_string__sz(pStringRelativePath),
						 SG_pathname__sz(pDb->pPathWorkingDirectoryTop))  );
	}

	SG_PATHNAME_NULLFREE(pCtx, pPathWDT);
	*ppPathItem = pPath;
	return;

fail:
	SG_PATHNAME_NULLFREE(pCtx, pPathWDT);
	SG_PATHNAME_NULLFREE(pCtx, pPath);
}
Пример #29
0
static void _resolve__fix__run_external_file_merge_1(SG_context * pCtx,
													 struct _resolve_data * pData,
													 _resolve__external_tool * pET,
													 _resolve__step_pathnames * pStepPathnames,
													 SG_string * pStrRepoPath,
													 SG_bool * pbMergedText)
{
	SG_exec_argvec * pArgVec = NULL;
	SG_exit_status exitStatus;

	SG_UNUSED( pData );

#if 0 && defined(DEBUG)
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   ("RESOLVE File Merge: %s\n"
								"          Mine: %s\n"
								"         Other: %s\n"
								"      Ancestor: %s\n"
								"        Result: %s\n"),
							   SG_string__sz(pStrRepoPath),
							   SG_pathname__sz(pStepPathnames->pPath_Mine),
							   SG_pathname__sz(pStepPathnames->pPath_Other),
							   SG_pathname__sz(pStepPathnames->pPath_Ancestor),
							   SG_pathname__sz(pStepPathnames->pPath_Result))  );
#endif


	SG_ERR_CHECK(  SG_exec_argvec__alloc(pCtx, &pArgVec)  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "-r")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_pathname__sz(pStepPathnames->pPath_Result))  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "-t1")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "Mine")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "-t2")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_string__sz(pStrRepoPath))  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "-t3")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "Other")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_pathname__sz(pStepPathnames->pPath_Mine))  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_pathname__sz(pStepPathnames->pPath_Ancestor))  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_pathname__sz(pStepPathnames->pPath_Other))  );

	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDOUT, "RESOLVE: Preparing to launch external merge tool: %s\n", pET->pszName)  );
	SG_ERR_CHECK(  SG_exec__exec_sync__files(pCtx, pET->pszExe, pArgVec, NULL, NULL, NULL, &exitStatus)  );
	*pbMergedText = (exitStatus == 0);

fail:
	SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec);
}
void SG_curl__throw_on_non200(SG_context* pCtx, SG_curl* pCurl)
{
	SG_int32 httpResponseCode = 0;
	SG_vhash* pvhErr = NULL;
	_sg_curl* p = (_sg_curl*)pCurl;

	SG_NULLARGCHECK_RETURN(pCurl);

	SG_ERR_CHECK(  SG_curl__getinfo__int32(pCtx, pCurl, CURLINFO_RESPONSE_CODE, &httpResponseCode)  );
	if (httpResponseCode != 200)
	{
		if ((httpResponseCode == 500 || httpResponseCode == 410) && p->pstrErr)
		{
			SG_bool bHas = SG_FALSE;
			const char* szMsg = NULL;
			
			SG_VHASH__ALLOC__FROM_JSON__SZ(pCtx, &pvhErr, SG_string__sz(p->pstrErr));
			if (SG_context__err_equals(pCtx, SG_ERR_JSONPARSER_SYNTAX))
			{
				// The server didn't return a JSON-formatted response.
				if (httpResponseCode == 500)
					SG_ERR_RESET_THROW2(SG_ERR_EXTENDED_HTTP_500, (pCtx, "%s", SG_string__sz(p->pstrErr)));
				else
					SG_ERR_THROW2(SG_ERR_SERVER_HTTP_ERROR, (pCtx, "%d", httpResponseCode));
			}
			SG_ERR_CHECK_CURRENT;

			SG_ERR_CHECK(  SG_vhash__has(pCtx, pvhErr, "msg", &bHas)  );
			if (bHas)
				SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvhErr, "msg", &szMsg)  );
			if (szMsg)
				SG_ERR_THROW2(SG_ERR_EXTENDED_HTTP_500, (pCtx, "%s", szMsg));
			else
				SG_ERR_THROW2(SG_ERR_EXTENDED_HTTP_500, (pCtx, "%s", SG_string__sz(p->pstrErr)));
		}
		else if (httpResponseCode == 401)
		{
			SG_ERR_THROW(SG_ERR_AUTHORIZATION_REQUIRED);
		}
		else
			SG_ERR_THROW2(SG_ERR_SERVER_HTTP_ERROR, (pCtx, "%d", httpResponseCode));
	}

	/* common cleanup */
fail:
	SG_VHASH_NULLFREE(pCtx, pvhErr);
}