Esempio n. 1
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);
}
Esempio n. 2
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);
}
/**
 * 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);
}
Esempio n. 4
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);
}
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 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);
}
/**
 * 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);
}
Esempio n. 8
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);
}
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);
}
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);
}
Esempio n. 11
0
void SG_vfile__end(
	SG_context* pCtx,
	SG_vfile** ppvf,
	const SG_vhash* pvh
	)
{
	SG_string* pstr = NULL;
	SG_vfile* pvf = NULL;

	SG_NULLARGCHECK_RETURN(ppvf);

	pvf = *ppvf;

	if (pvh)
	{
		SG_ARGCHECK_RETURN( !(pvf->mode & SG_FILE_RDONLY) , pvh );

		SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr)  );

		SG_ERR_CHECK(  SG_vhash__to_json(pCtx, pvh,pstr)  );

		SG_ERR_CHECK(  SG_file__seek(pCtx, pvf->pFile, 0)  );

		SG_ERR_CHECK(  SG_file__truncate(pCtx, pvf->pFile)  );

#if TRACE_VFILE
		SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR, "VFileEnd: Writing %d bytes to file.\n",
								   SG_string__length_in_bytes(pstr))  );
#endif

		SG_ERR_CHECK(  SG_file__write(pCtx, pvf->pFile, SG_string__length_in_bytes(pstr), (const SG_byte *)SG_string__sz(pstr), NULL)  );
		SG_STRING_NULLFREE(pCtx, pstr);
	}
	else
	{
		if (!(pvf->mode & SG_FILE_RDONLY))
		{
			SG_ERR_CHECK(  SG_file__seek(pCtx, pvf->pFile, 0)  );

			SG_ERR_CHECK(  SG_file__truncate(pCtx, pvf->pFile)  );

#if TRACE_VFILE
			SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR, "VFileEnd: Truncating file.\n")  );
#endif
		}
	}

	SG_FILE_NULLCLOSE(pCtx, pvf->pFile);

	SG_NULLFREE(pCtx, pvf);
	*ppvf = NULL;

	return;
fail:
	SG_STRING_NULLFREE(pCtx, pstr);
}
void SG_curl__free(SG_context* pCtx, SG_curl* pCurl)
{
	_sg_curl* p = (_sg_curl*)pCurl;

	if (p)
	{
		SG_STRING_NULLFREE(pCtx, p->pstrErr);
		SG_STRING_NULLFREE(pCtx, p->pstrRawHeaders);
		curl_easy_cleanup(p->pCurl);
		SG_NULLFREE(pCtx, p);
	}
}
Esempio n. 13
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);
}
Esempio n. 14
0
void SG_getopt__free(SG_context * pCtx, SG_getopt * pGetopt)
{
	if (!pGetopt)
		return;

	SG_STRING_NULLFREE(pCtx, pGetopt->pStringAppName);
	SG_STRING_NULLFREE(pCtx, pGetopt->pStringCommandName);

	if (pGetopt->paszArgs)
	{
		SG_ERR_CHECK_RETURN(  SG_freeStringList(pCtx, (const char ***)&pGetopt->paszArgs, pGetopt->count_args)  );
	}

	SG_NULLFREE(pCtx, pGetopt);
}
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);
}
Esempio n. 16
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);
}
Esempio n. 17
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);
}
Esempio n. 18
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);

}
Esempio n. 19
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);
}
Esempio n. 20
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);
}
Esempio n. 21
0
void SG_group__list(
	SG_context* pCtx,
    SG_repo* pRepo,
    SG_varray** ppva
    )
{
    SG_string* pstr_where = NULL;
    SG_stringarray* psa_results = NULL;
    char* psz_hid_cs_leaf = NULL;
    SG_vhash* pvh_group = NULL;
    SG_varray* pva_result = NULL;
    SG_stringarray* psa_fields = NULL;

    SG_ERR_CHECK(  SG_zing__get_leaf__fail_if_needs_merge(pCtx, pRepo, SG_DAGNUM__USERS, &psz_hid_cs_leaf)  );

    SG_ERR_CHECK(  SG_STRINGARRAY__ALLOC(pCtx, &psa_fields, 2)  );
    SG_ERR_CHECK(  SG_stringarray__add(pCtx, psa_fields, "recid")  );
    SG_ERR_CHECK(  SG_stringarray__add(pCtx, psa_fields, "name")  );
    SG_ERR_CHECK(  SG_zing__query(pCtx, pRepo, SG_DAGNUM__USERS, psz_hid_cs_leaf, "group", NULL, "name #ASC", 0, 0, psa_fields, &pva_result)  );

    *ppva = pva_result;
    pva_result = NULL;

fail:
    SG_VHASH_NULLFREE(pCtx, pvh_group);
    SG_NULLFREE(pCtx, psz_hid_cs_leaf);
    SG_VARRAY_NULLFREE(pCtx, pva_result);
    SG_STRINGARRAY_NULLFREE(pCtx, psa_results);
    SG_STRING_NULLFREE(pCtx, pstr_where);
    SG_STRINGARRAY_NULLFREE(pCtx, psa_fields);
}
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);
}
Esempio n. 23
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;
}
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);
}
static void _get_sync_url(SG_context* pCtx, const char* pszBaseUrl, const char* pszUrlSuffix, const char* pszPushId, const char* pszQueryString, char** ppszUrl)
{
    SG_string* pstrUrl = NULL;

    SG_ERR_CHECK(  SG_STRING__ALLOC__RESERVE(pCtx, &pstrUrl, 1024)  );
    SG_ERR_CHECK(  SG_string__append__sz(pCtx, pstrUrl, pszBaseUrl)  );

    if (pszUrlSuffix)
        SG_ERR_CHECK(  SG_string__append__sz(pCtx, pstrUrl, pszUrlSuffix)  );

    if (pszPushId)
    {
        SG_ERR_CHECK(  SG_string__append__sz(pCtx, pstrUrl, "/")  );
        SG_ERR_CHECK(  SG_string__append__sz(pCtx, pstrUrl, pszPushId)  );
    }
    if (pszQueryString)
    {
        SG_ERR_CHECK(  SG_string__append__sz(pCtx, pstrUrl, "?")  );
        SG_ERR_CHECK(  SG_string__append__sz(pCtx, pstrUrl, pszQueryString)  );
    }

    SG_ERR_CHECK(  SG_string__sizzle(pCtx, &pstrUrl, (SG_byte**)ppszUrl, NULL)  );

    return;

fail:
    SG_STRING_NULLFREE(pCtx, pstrUrl);
}
Esempio n. 26
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);
}
static void _get_host(SG_context* pCtx, const char* szRepoSpec, SG_string** ppstrHost)
{
	LPWSTR pwszRepoSpec = NULL;
	SG_uint32 len = 0;
	URL_COMPONENTSW UrlComponents;
	SG_string* pstrHost = NULL;
	WCHAR buf[260];

	SG_zero(UrlComponents);
	UrlComponents.dwStructSize = sizeof(URL_COMPONENTS);
	UrlComponents.dwHostNameLength = sizeof(buf);
	UrlComponents.lpszHostName = buf;

	SG_ERR_CHECK(  SG_utf8__extern_to_os_buffer__wchar(pCtx, szRepoSpec, &pwszRepoSpec, &len)  );

	if ( !InternetCrackUrlW(pwszRepoSpec, len, ICU_DECODE, &UrlComponents) )
		SG_ERR_THROW2(  SG_ERR_GETLASTERROR(GetLastError()), (pCtx, "unable to parse host from URL")  );

	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstrHost)  );
	SG_ERR_CHECK(  SG_utf8__intern_from_os_buffer__wchar(pCtx, pstrHost, UrlComponents.lpszHostName)  );

	SG_RETURN_AND_NULL(pstrHost, ppstrHost);

	/* fall through */
fail:
	SG_NULLFREE(pCtx, pwszRepoSpec);
	SG_STRING_NULLFREE(pCtx, pstrHost);
}
/**
 * Queue a request to resolve (or partially resolve) an issue.
 * We assume that the caller has already
 * queued any necessary WD operations
 * (such as moves/renamed) and now just
 * needs to mark the item resolved (or
 * partially resolved).
 *
 * Since an item may have multiple conflict
 * bits set, you can use this to mark the
 * specific choices made in the pvhSavedResolutions
 * and only mark it fully resolved when
 * everything has been chosen.
 *
 * We steal the optional/given pvhSavedResolutions.
 *
 */
void sg_wc_tx__queue__resolve_issue__sr(SG_context * pCtx,
										SG_wc_tx * pWcTx,
										sg_wc_liveview_item * pLVI,
										SG_wc_status_flags statusFlags_x_xr_xu,
										SG_vhash ** ppvhSavedResolutions)
{
	SG_string * pStringResolveData = NULL;

	SG_NULLARGCHECK_RETURN( pWcTx );
	SG_NULLARGCHECK_RETURN( pLVI );
	// ppvhSavedResolutions is optional.

	if (ppvhSavedResolutions && *ppvhSavedResolutions)
	{
		SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pStringResolveData)  );
		SG_ERR_CHECK(  SG_vhash__to_json(pCtx, (*ppvhSavedResolutions), pStringResolveData)  );
	}

	SG_ERR_CHECK(  sg_wc_tx__journal__resolve_issue__sr(pCtx, pWcTx,
														pLVI->uiAliasGid,
														statusFlags_x_xr_xu,
														pStringResolveData)  );

	pLVI->statusFlags_x_xr_xu = statusFlags_x_xr_xu;

	SG_VHASH_NULLFREE(pCtx, pLVI->pvhSavedResolutions);
	if (ppvhSavedResolutions && *ppvhSavedResolutions)
	{
		pLVI->pvhSavedResolutions = *ppvhSavedResolutions;
		*ppvhSavedResolutions = NULL;
	}

fail:
	SG_STRING_NULLFREE(pCtx, pStringResolveData);
}
void SG_mrg_cset_entry_conflict__free(SG_context * pCtx,
									  SG_mrg_cset_entry_conflict * pMrgCSetEntryConflict)
{
	if (!pMrgCSetEntryConflict)
		return;

	SG_VECTOR_I64_NULLFREE(pCtx, pMrgCSetEntryConflict->pVec_MrgCSetEntryNeq_Changes);
	SG_VECTOR_NULLFREE(pCtx, pMrgCSetEntryConflict->pVec_MrgCSetEntry_Changes);	// we do not own the pointers within
	SG_VECTOR_NULLFREE(pCtx, pMrgCSetEntryConflict->pVec_MrgCSet_Deletes);		// we do not own the pointers within

	// for the collapsable rbUnique's we own the vectors in the rbtree-values, but not the pointers within the vector
	SG_RBTREE_NULLFREE_WITH_ASSOC(pCtx, pMrgCSetEntryConflict->prbUnique_AttrBits,          (SG_free_callback *)SG_vector__free);
	SG_RBTREE_NULLFREE_WITH_ASSOC(pCtx, pMrgCSetEntryConflict->prbUnique_Entryname,         (SG_free_callback *)SG_vector__free);
	SG_RBTREE_NULLFREE_WITH_ASSOC(pCtx, pMrgCSetEntryConflict->prbUnique_GidParent,         (SG_free_callback *)SG_vector__free);
	SG_RBTREE_NULLFREE_WITH_ASSOC(pCtx, pMrgCSetEntryConflict->prbUnique_Symlink_HidBlob,   (SG_free_callback *)SG_vector__free);
	SG_RBTREE_NULLFREE_WITH_ASSOC(pCtx, pMrgCSetEntryConflict->prbUnique_Submodule_HidBlob, (SG_free_callback *)SG_vector__free);
	SG_RBTREE_NULLFREE_WITH_ASSOC(pCtx, pMrgCSetEntryConflict->prbUnique_File_HidBlob,      (SG_free_callback *)SG_vector__free);

	SG_VECTOR_NULLFREE(pCtx, pMrgCSetEntryConflict->pVec_MrgCSetEntry_OtherDirsInCycle);	// we do not own the pointers within
	SG_STRING_NULLFREE(pCtx, pMrgCSetEntryConflict->pStringPathCycleHint);

	SG_FILETOOL_NULLFREE(pCtx, pMrgCSetEntryConflict->pMergeTool);

	SG_PATHNAME_NULLFREE(pCtx, pMrgCSetEntryConflict->pPathTempDirForFile);
	SG_PATHNAME_NULLFREE(pCtx, pMrgCSetEntryConflict->pPathTempFile_Ancestor);
	SG_PATHNAME_NULLFREE(pCtx, pMrgCSetEntryConflict->pPathTempFile_Result);
	SG_PATHNAME_NULLFREE(pCtx, pMrgCSetEntryConflict->pPathTempFile_Baseline);
	SG_PATHNAME_NULLFREE(pCtx, pMrgCSetEntryConflict->pPathTempFile_Other);

	SG_NULLFREE(pCtx, pMrgCSetEntryConflict->pszHidDisposable);
	SG_NULLFREE(pCtx, pMrgCSetEntryConflict->pszHidGenerated);

	SG_NULLFREE(pCtx, pMrgCSetEntryConflict);
}
/**
 * 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);
}