Beispiel #1
0
void u0023_vcdiff__test_deltify_run(SG_context * pCtx)
{
	FILE* fp;
	SG_pathname* pPath_version1 = NULL;
	SG_pathname* pPath_version2 = NULL;
	int i;

	VERIFY_ERR_CHECK_DISCARD(  unittest__get_nonexistent_pathname(pCtx, &pPath_version1)  );
	VERIFY_ERR_CHECK_DISCARD(  unittest__get_nonexistent_pathname(pCtx, &pPath_version2)  );

	fp = fopen(SG_pathname__sz(pPath_version1), "w");
	fprintf(fp, "Ah, I should havq known it from thq vqry start This girl will lqavq mq with a brokqn hqart Now listqn pqoplq what I'm tqlling you A-kqqp away from-a Runaround Suq\n");
	fclose(fp);

	fp = fopen(SG_pathname__sz(pPath_version2), "w");
	for (i=0; i<500000; i++)
	{
		fputc('e', fp);
	}
	fclose(fp);

	VERIFY_ERR_CHECK_DISCARD(  u0023_vcdiff__do_test_deltify(pCtx, pPath_version1, pPath_version2)  );

	SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath_version1)  );
	SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath_version2)  );

	SG_PATHNAME_NULLFREE(pCtx, pPath_version1);
	SG_PATHNAME_NULLFREE(pCtx, pPath_version2);
}
Beispiel #2
0
void u0023_vcdiff__test_deltify(SG_context * pCtx)
{
	FILE* fp;
	SG_pathname* pPath_version1 = NULL;
	SG_pathname* pPath_version2 = NULL;
	int i;

	VERIFY_ERR_CHECK_DISCARD(  unittest__get_nonexistent_pathname(pCtx,&pPath_version1)  );
	VERIFY_ERR_CHECK_DISCARD(  unittest__get_nonexistent_pathname(pCtx,&pPath_version2)  );

	fp = fopen(SG_pathname__sz(pPath_version1), "w");
	for (i=0; i<500; i++)
	{
		fprintf(fp, "Ah, I should have known it from the very start This girl will leave me with a broken heart Now listen people what I'm telling you A-keep away from-a Runaround Sue\n");
	}
	fclose(fp);

	fp = fopen(SG_pathname__sz(pPath_version2), "w");
	for (i=0; i<100; i++)
	{
		fprintf(fp, "He rocks in the tree-top all a day long Hoppin' and a-boppin' and a-singin' the song All the little birds on J-Bird St. Love to hear the robin goin' tweet tweet tweet\n");
	}
	fclose(fp);

	VERIFY_ERR_CHECK_DISCARD(  u0023_vcdiff__do_test_deltify(pCtx, pPath_version1, pPath_version2)  );

	SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath_version1)  );
	SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath_version2)  );

	SG_PATHNAME_NULLFREE(pCtx, pPath_version1);
	SG_PATHNAME_NULLFREE(pCtx, pPath_version2);
}
Beispiel #3
0
void u0023_vcdiff__test_deltify_small_files(SG_context * pCtx)
{
	FILE* fp;
	SG_pathname* pPath_version1;
	SG_pathname* pPath_version2;

	VERIFY_ERR_CHECK_DISCARD(  unittest__get_nonexistent_pathname(pCtx, &pPath_version1)  );
	VERIFY_ERR_CHECK_DISCARD(  unittest__get_nonexistent_pathname(pCtx, &pPath_version2)  );

	fp = fopen(SG_pathname__sz(pPath_version1), "w");
	fprintf(fp, "e");
	fclose(fp);

	fp = fopen(SG_pathname__sz(pPath_version2), "w");
	fprintf(fp, "a");
	fclose(fp);

	VERIFY_ERR_CHECK_DISCARD(  u0023_vcdiff__do_test_deltify(pCtx, pPath_version1, pPath_version2)  );

	SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath_version1)  );
	SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath_version2)  );

	SG_PATHNAME_NULLFREE(pCtx, pPath_version1);
	SG_PATHNAME_NULLFREE(pCtx, pPath_version2);
}
Beispiel #4
0
void u0023_vcdiff__test_deltify_from_zerolength(SG_context * pCtx)
{
	FILE* fp;
	SG_pathname* pPath_version1 = NULL;
	SG_pathname* pPath_version2 = NULL;
	int i;

	VERIFY_ERR_CHECK_DISCARD(  unittest__get_nonexistent_pathname(pCtx, &pPath_version1)  );
	VERIFY_ERR_CHECK_DISCARD(  unittest__get_nonexistent_pathname(pCtx, &pPath_version2)  );

	fp = fopen(SG_pathname__sz(pPath_version1), "w");
	fclose(fp);

	fp = fopen(SG_pathname__sz(pPath_version2), "w");
	for (i=0; i<500000; i++)
	{
		fputc(i % 256, fp);
	}
	fclose(fp);

	VERIFY_ERR_CHECK_DISCARD(  u0023_vcdiff__do_test_deltify(pCtx, pPath_version1, pPath_version2)  );

	SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath_version1)  );
	SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath_version2)  );

	SG_PATHNAME_NULLFREE(pCtx, pPath_version1);
	SG_PATHNAME_NULLFREE(pCtx, pPath_version2);
}
STDMETHODIMP CVeracityOverlay_Ignored::IsMemberOf(LPCWSTR pwszPath, DWORD dwAttrib)
{
	pwszPath;
	dwAttrib;
	HRESULT returnVal = S_FALSE;
	//return returnVal;
	SG_context* pCtx = GetAContext();
	
	SG_pathname * pPathCwd = NULL;
	SG_pathname * pPathTop = NULL;
	if (InAWorkingFolder(pCtx, pwszPath, &pPathCwd, &pPathTop) )
	{
		SG_wc_status_flags status =  GetStatus(pCtx, SG_pathname__sz(pPathCwd), SG_pathname__sz(pPathTop), NULL);

		if (StatusHas(status, SG_WC_STATUS_FLAGS__U__IGNORED) || StatusHas(status, SG_WC_STATUS_FLAGS__R__RESERVED) )
			returnVal = S_OK;
		else
			returnVal = S_FALSE;
	}
	else
		returnVal = S_FALSE;
	SG_PATHNAME_NULLFREE(pCtx, pPathCwd);
	SG_PATHNAME_NULLFREE(pCtx, pPathTop);
	SG_CONTEXT_NULLFREE(pCtx);
	return returnVal;
}
void _sg_mrg__copy_wc_to_temp_file(SG_context * pCtx, SG_mrg * pMrg,
								   SG_mrg_cset_entry * pMrgCSetEntry,
								   const SG_pathname * pPathTempFile)
{
	sg_wc_liveview_item * pLVI;
	SG_string * pStringRepoPath = NULL;
	SG_pathname * pPathInWC = NULL;
	SG_bool bExists;
	SG_bool bKnown;

	SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx,pPathTempFile,&bExists,NULL,NULL)  );
	if (bExists)
	{
#if TRACE_WC_MERGE
		SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,
								   "Skipping copy of WC version to [%s]\n",
								   SG_pathname__sz(pPathTempFile))  );
#endif
		return;
	}

	// Find the absolute path of the WD version of the file.
	SG_ERR_CHECK(  sg_wc_tx__liveview__fetch_random_item(pCtx, pMrg->pWcTx,
														 pMrgCSetEntry->uiAliasGid,
														 &bKnown, &pLVI)  );
	SG_ASSERT_RELEASE_FAIL(  (bKnown)  );
	SG_ERR_CHECK(  sg_wc_tx__liveview__compute_live_repo_path(pCtx, pMrg->pWcTx, pLVI,
															  &pStringRepoPath)  );
	SG_ERR_CHECK(  sg_wc_db__path__repopath_to_absolute(pCtx, pMrg->pWcTx->pDb,
														pStringRepoPath,
														&pPathInWC)  );

#if TRACE_WC_MERGE
	SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,
							   "Copying WC version [%s] to [%s]\n",
							   SG_string__sz(pStringRepoPath),
							   SG_pathname__sz(pPathTempFile))  );
#endif

	// Ideally, when we create this TEMP file it should be read-only.
	// Afterall, it does represent a historical version of the file and
	// it should only be used as INPUT to whatever merge tool the user
	// has configured.  So it should be read-only.  This might allow
	// a GUI merge tool to show locks/whatever and/or prevent accidental
	// editing of these files.
	//
	// However, this can cause an "Access is Denied" error on Windows
	// when we get ready to delete the contents of the TEMP directory.
	// We'll deal with that there rather than here.

	SG_ERR_CHECK(  SG_fsobj__copy_file(pCtx, pPathInWC, pPathTempFile, 0400)  );

fail:
	SG_STRING_NULLFREE(pCtx, pStringRepoPath);
	SG_PATHNAME_NULLFREE(pCtx, pPathInWC);
}
void sg_treediff_cache::GetStatusForPath(SG_context * pCtx, SG_bool bIsRetry, const SG_pathname * pPathName, SG_wc_status_flags * pStatusFlags, SG_bool * pbDirChanged)
{
	wxCriticalSectionLocker lock(m_wc_transaction_lock);
	SG_wc_status_flags statusFlags = SG_WC_STATUS_FLAGS__U__FOUND;
	SG_string * psgstr_statusFlagsDetails = NULL;
	if (m_pwc_tx == NULL)
	{
		//Start a read-only transaction.
		SG_ERR_CHECK(  SG_WC_TX__ALLOC__BEGIN(pCtx, &m_pwc_tx, ((pPathName)), SG_TRUE)  );
	}

	SG_ERR_CHECK(  SG_wc_tx__get_item_status_flags(pCtx, m_pwc_tx, SG_pathname__sz(pPathName), SG_FALSE, SG_FALSE, &statusFlags, NULL)  );
	if (pbDirChanged != NULL && (statusFlags & SG_WC_STATUS_FLAGS__T__DIRECTORY))
	{
		//It's a directory, so we need to check to see if there are modifications under it.
		SG_wc_status_flags dirStatusFlags = SG_WC_STATUS_FLAGS__U__FOUND;
		SG_ERR_CHECK(  SG_wc_tx__get_item_dirstatus_flags(pCtx, m_pwc_tx, SG_pathname__sz(pPathName), &dirStatusFlags, NULL, pbDirChanged)   );
	}
#if DEBUG
	SG_ERR_CHECK(  SG_wc_debug__status__dump_flags(pCtx, statusFlags, "status flags", &psgstr_statusFlagsDetails)  );
	SG_ERR_CHECK(  SG_log__report_verbose(pCtx, "%s", SG_string__sz(psgstr_statusFlagsDetails))  );
#endif
	//Don't recurse if this is our second try. 
	if ((bIsRetry == SG_FALSE) 
		&& ((statusFlags & SG_WC_STATUS_FLAGS__T__BOGUS) == SG_WC_STATUS_FLAGS__T__BOGUS) )
	{
		//This is a item that is new in the directory since we started
		//our transaction.  Close the transaction, and start a new one.
		SG_ERR_CHECK(  SG_log__report_verbose(pCtx, "Got a bogus status.  Restarting transaction")  );
		clearCache(pCtx);
		GetStatusForPath(pCtx, SG_TRUE, pPathName, &statusFlags, pbDirChanged);
	}
	
	SG_ERR_CHECK(  SG_time__get_milliseconds_since_1970_utc(pCtx, &m_timeLastRequest)  );
	*pStatusFlags = statusFlags;
fail:
	SG_STRING_NULLFREE(pCtx, psgstr_statusFlagsDetails);
	//Log and reset any errors on the context.
	//Any error condition should report the status as
	//Found and still send a message back to the client.
	if (SG_context__has_err(pCtx) == SG_TRUE)
	{
		if (!SG_context__err_equals(pCtx, SG_ERR_WC_DB_BUSY))
		{
			SG_log__report_error__current_error(pCtx);
		}
		SG_context__err_reset(pCtx);
	}
}
/**
 * Create a per-tx temp-dir if we don't already have one.
 *
 */
void sg_wc_tx__create_session_temp_dir(SG_context * pCtx,
									   SG_wc_tx * pWcTx)
{
	char bufTidSession[SG_TID_MAX_BUFFER_LENGTH];
	SG_uint32 nrDigits = 10;

	if (pWcTx->pPathSessionTempDir)
		return;

	// pick a space in /tmp for exporting temporary copies of the files
	// so that internal and/or external tools can compare them.
	//
	// TODO 2012/05/02 Investigate the use of SG_workingdir__get_temp_path() (which
	// TODO            creates things in .sgdrawer rather than /tmp).
	// TODO            (see also sg_mrg__private_file_mrg.h)
	// TODO            See also sg_vv2__diff__create_session_temp_dir().

	SG_ERR_CHECK(  SG_PATHNAME__ALLOC__USER_TEMP_DIRECTORY(pCtx, &pWcTx->pPathSessionTempDir)  );
	SG_ERR_CHECK(  SG_tid__generate2(pCtx, bufTidSession, sizeof(bufTidSession), nrDigits)  );
	SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, pWcTx->pPathSessionTempDir, bufTidSession)  );

	SG_ERR_TRY(  SG_fsobj__mkdir_recursive__pathname(pCtx, pWcTx->pPathSessionTempDir)  );
	SG_ERR_CATCH_IGNORE(  SG_ERR_DIR_ALREADY_EXISTS  );
	SG_ERR_CATCH_END;

#if 0 && defined(DEBUG)
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "CreateSessionTempDir: %s\n",
							   SG_pathname__sz(pWcTx->pPathSessionTempDir))  );
#endif

fail:
	return;
}
/**
 * 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);
}
/**
 * Export the contents of the given file entry (which reflects a specific version)
 * into a temp file so that an external tool can use it.
 *
 * You own the returned pathname and the file on disk.
 */
void _sg_mrg__export_to_temp_file(SG_context * pCtx, SG_mrg * pMrg,
								  const char * pszHidBlob,
								  const SG_pathname * pPathTempFile)
{
	SG_file * pFile = NULL;
	SG_bool bExists;

	SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx,pPathTempFile,&bExists,NULL,NULL)  );
	if (bExists)
	{
#if TRACE_WC_MERGE
		SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,
								   "Skipping export of [blob %s] to [%s]\n",pszHidBlob,SG_pathname__sz(pPathTempFile))  );
#endif
	}
	else
	{
#if TRACE_WC_MERGE
		SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,
								   "Exporting          [blob %s] to [%s]\n",pszHidBlob,SG_pathname__sz(pPathTempFile))  );
#endif

		// Ideally, when we create this TEMP file it should be read-only.
		// Afterall, it does represent a historical version of the file and
		// it should only be used as INPUT to whatever merge tool the user
		// has configured.  So it should be read-only.  This might allow
		// a GUI merge tool to show locks/whatever and/or prevent accidental
		// editing of these files.
		//
		// However, this can cause an "Access is Denied" error on Windows
		// when we get ready to delete the contents of the TEMP directory.
		// We'll deal with that there rather than here.

		SG_ERR_CHECK(  SG_file__open__pathname(pCtx,pPathTempFile,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0400,&pFile)  );
		SG_ERR_CHECK(  SG_repo__fetch_blob_into_file(pCtx, pMrg->pWcTx->pDb->pRepo, pszHidBlob,pFile,NULL)  );
		SG_FILE_NULLCLOSE(pCtx,pFile);
	}

	return;

fail:
	if (pFile)			// only if **WE** created the file, do we try to delete it on error.
	{
		SG_FILE_NULLCLOSE(pCtx,pFile);
		SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx,pPathTempFile)  );
	}
}
void _set_curl_options(SG_context* pCtx, CURL* pCurl)
{
	char * szServerFiles = NULL;
	char * szVerifyCerts = NULL;
	SG_pathname *pServerFiles = NULL;
	CURLcode rc = CURLE_OK;
#ifdef WINDOWS
	SG_bool bExists = SG_FALSE;
	SG_bool bVerifyCerts = SG_TRUE;
#endif
	SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__VERIFY_SSL_CERTS, NULL, &szVerifyCerts, NULL)  );
	if (szVerifyCerts != NULL && (SG_strcmp__null(szVerifyCerts, "false") == 0 || SG_strcmp__null(szVerifyCerts, "FALSE")  == 0))
	{
#ifdef WINDOWS
		bVerifyCerts = SG_FALSE;
#endif
		rc = curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, SG_FALSE);		
	}

	if (rc)
		SG_ERR_THROW(SG_ERR_LIBCURL(rc));


#ifdef WINDOWS
	if (bVerifyCerts)
	{
		SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__SERVER_FILES, NULL, &szServerFiles, NULL)  );
		if (szServerFiles)
		{
			SG_ERR_CHECK(  SG_pathname__alloc__sz(pCtx, &pServerFiles, szServerFiles)  );
			SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, pServerFiles, "ssl") );
			SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, pServerFiles, "curl-ca-bundle.crt") );
			SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx, pServerFiles, &bExists, NULL, NULL)  );
		}

		if (bExists)
		{
			rc = curl_easy_setopt(pCurl, CURLOPT_CAINFO, SG_pathname__sz(pServerFiles));	
			if (rc)
				SG_ERR_THROW(SG_ERR_LIBCURL(rc));
		}
		else
		{
			if (pServerFiles)
				SG_ERR_CHECK(  SG_log__report_warning(pCtx, "Could not find root certificate file. Looked for it at: %s. SSL connections will not work.", SG_pathname__sz(pServerFiles))  );
			else
				SG_ERR_CHECK(  SG_log__report_warning(pCtx, "Could not find root certificate file: no server/files path is configured. SSL connections will not work.")  );
		}
	}
#endif

fail:
	SG_PATHNAME_NULLFREE(pCtx, pServerFiles);
	SG_NULLFREE(pCtx, szServerFiles);
	SG_NULLFREE(pCtx, szVerifyCerts);
}
/**
 * Convert absolute path to a wd-top-relative string.
 * 
 * This is just pathname/string parsing; we DO NOT confirm
 * that the path exists.  We only confirm that the result
 * is properly contained within the working directory.
 *
 */
void sg_wc_db__path__absolute_to_repopath(SG_context * pCtx,
										  const sg_wc_db * pDb,
										  const SG_pathname * pPathItem,
										  SG_string ** ppStringRepoPath)
{
	SG_string * pString = NULL;
	const char * psz;

	SG_workingdir__wdpath_to_repopath(pCtx,
									  pDb->pPathWorkingDirectoryTop,
									  pPathItem,
									  SG_FALSE,
									  &pString);
	if (SG_CONTEXT__HAS_ERR(pCtx))
	{
		if (SG_context__err_equals(pCtx, SG_ERR_CANNOT_MAKE_RELATIVE_PATH))
			goto throw_not_in_working_copy;
		if (SG_context__err_equals(pCtx, SG_ERR_ITEM_NOT_UNDER_VERSION_CONTROL))
			goto throw_not_in_working_copy;
		if (SG_context__err_equals(pCtx, SG_ERR_PATH_NOT_IN_WORKING_COPY))
			goto throw_not_in_working_copy;
		SG_ERR_RETHROW;
	}
	
	psz = SG_string__sz(pString);
	if ((psz[0] == '.') && (psz[1] == '.') && ((psz[2] == '/') || (psz[2] == 0)))
		goto throw_not_in_working_copy;

	*ppStringRepoPath = pString;
	return;

throw_not_in_working_copy:
	SG_context__err_reset(pCtx);
	SG_ERR_THROW2(  SG_ERR_PATH_NOT_IN_WORKING_COPY,
					(pCtx, "The path '%s' is not inside the working copy rooted at '%s'.",
					 SG_pathname__sz(pPathItem),
					 SG_pathname__sz(pDb->pPathWorkingDirectoryTop))  );

fail:
	SG_STRING_NULLFREE(pCtx, pString);
}
/**
 * For MODIFIED or DELETED items we need to populate the left side
 * of the diff.  This should be called after _pick_tool().
 * 
 * put the various fields that we need to use in the call to SG_difftool__run()
 * into the pvhDiffItem for later.
 *
 */
static void _get_left_side_details(SG_context * pCtx,
								   sg_wc6diff__setup_data * pData,
								   const SG_vhash * pvhItem,
								   SG_vhash * pvhDiffItem)
{
	SG_string * pStringLabel_left  = NULL;
	SG_pathname * pPathAbsolute_left = NULL;
	SG_vhash * pvhSubsection_left = NULL;		// we do not own this
	const char * pszRepoPath_left;
	const char * pszGid;
	const char * pszHid_left;
	const char * pszToolName = NULL;
	const char * pszName_left;

	// get the repo-path for the left side *AS IT EXISTED IN THE LEFT CSET*.
	SG_ERR_CHECK(  SG_vhash__get__vhash(pCtx, pvhItem, pData->pszSubsectionLeft, &pvhSubsection_left)  );
	SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvhSubsection_left, "hid", &pszHid_left)  );
	SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvhSubsection_left, "path", &pszRepoPath_left)  );
	SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvhSubsection_left, "name", &pszName_left)  );

	// left label is "<left_repo-path> <hid>" (we have an HID and since no date makes sense)
	SG_ERR_CHECK(  sg_wc_diff_utils__make_label(pCtx, pszRepoPath_left, pszHid_left, NULL, &pStringLabel_left)  );
	SG_ERR_CHECK(  SG_vhash__add__string__sz(pCtx, pvhDiffItem, "left_label",    SG_string__sz(pStringLabel_left))  );

	SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvhDiffItem, "tool", &pszToolName)  );
	if (strcmp(pszToolName, SG_DIFFTOOL__INTERNAL__SKIP) == 0)
	{
		// There's no point in exporting a binary file into TEMP so
		// that we can invoke a no-op difftool.
		// See W5937.
	}
	else
	{
		// fetch the baseline version of the file into a temp file.
		// the left side should be read-only because it refers to a
		// historical version (regardless of whether or not we are
		// interactive).

		SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvhItem, "gid", &pszGid)  );
		SG_ERR_CHECK(  sg_wc_diff_utils__export_to_temp_file(pCtx, pData->pWcTx, pData->pszSubsectionLeft,
															 pszGid, pszHid_left,
															 pszName_left,
															 &pPathAbsolute_left)  );
		SG_ERR_CHECK(  SG_fsobj__chmod__pathname(pCtx, pPathAbsolute_left, 0400)  );

		SG_ERR_CHECK(  SG_vhash__add__string__sz(pCtx, pvhDiffItem, "left_abs_path", SG_pathname__sz(pPathAbsolute_left))  );
	}

fail:
	SG_PATHNAME_NULLFREE(pCtx, pPathAbsolute_left);
	SG_STRING_NULLFREE(pCtx, pStringLabel_left);
}
Beispiel #14
0
int u0020_utf8pathnames__create_file(SG_context * pCtx, const SG_pathname * pPathnameTmpDir, _tableitem * pti)
{
	// create a file in the given tmp dir using the given filename.

	SG_pathname * pPathnameNewFile;
	char * pBufUtf8;
	SG_uint32 lenUtf8;
	SG_file * pFile;
	int iResult;
	SG_bool bTest;

	// convert the utf32 string into utf8.

	VERIFY_ERR_CHECK_DISCARD(  SG_utf8__from_utf32(pCtx, pti->pa32,&pBufUtf8,&lenUtf8)  );	// we have to free pBufUtf8

	// verify that the computed utf8 string matches what we thought it should be.
	// (this hopefully guards against the conversion layer playing NFC/NFD tricks.)

	iResult = SG_utf8__compare(pBufUtf8,(char *)pti->pa8);
	VERIFYP_COND("u0020_utf8pathnames",(iResult==0),("Compare failed [%s][%s]",pBufUtf8,pti->pa8));

	// create full pathname to the file to create.

	VERIFY_ERR_CHECK_DISCARD(  SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx,
															   &pPathnameNewFile,
															   pPathnameTmpDir,pBufUtf8)  );

	// create the file and close it.
	// on Linux when our locale is set to something other than UTF-8, we may
	// get an ICU(10) == U_INVALID_CHAR_FOUND error because the test data is
	// not necessarily friendly to any one locale and there are some NFD
	// cases too.   we map ICU(10) to SG_ERR_UNMAPPABLE_UNICODE_CHAR

	SG_file__open__pathname(pCtx,pPathnameNewFile,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0755,&pFile);
#if defined(LINUX)
	bTest = (  (!SG_context__has_err(pCtx))  ||  (SG_context__err_equals(pCtx,SG_ERR_UNMAPPABLE_UNICODE_CHAR))  );
#else
	bTest = (  (!SG_context__has_err(pCtx))  );
#endif
	SG_context__err_reset(pCtx);

	VERIFYP_COND("u0020_utf8pathnames",bTest,
			 ("Error Creating file [%s]",SG_pathname__sz(pPathnameNewFile)));

	VERIFY_ERR_CHECK_DISCARD(  SG_file__close(pCtx, &pFile)  );

	SG_PATHNAME_NULLFREE(pCtx, pPathnameNewFile);
	SG_NULLFREE(pCtx, pBufUtf8);

	return 1;
}
Beispiel #15
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);
}
Beispiel #16
0
SG_bool compare_files_are_identical(const SG_pathname* pPath1, const SG_pathname* pPath2)
{
	SG_bool bResult;
	FILE* fp1;
	FILE* fp2;

	fp1 = fopen(SG_pathname__sz(pPath1), "r");
	if (!fp1)
    {
		return SG_FALSE;
    }
	fp2 = fopen(SG_pathname__sz(pPath2), "r");
	if (!fp2)
    {
		fclose(fp1);
		return SG_FALSE;
    }

	bResult = SG_TRUE;
	while (SG_TRUE)
    {
		int c1 = fgetc(fp1);
		int c2 = fgetc(fp2);
		if (c1 != c2)
		{
			bResult = SG_FALSE;
			break;
		}
		if (c1 == EOF)
		{
			break;
		}
    }
	fclose(fp1);
	fclose(fp2);
	return bResult;
}
Beispiel #17
0
void MyFn(create_tmp_src_dir)(SG_context * pCtx, SG_pathname ** ppPathnameTempDir)
{
	// create a temp directory in the current directory to be the
	// home of some userfiles.
	// caller must free returned value.

	SG_pathname * pPathnameTempDir = NULL;

	VERIFY_ERR_CHECK(  unittest__alloc_unique_pathname_in_cwd(pCtx,&pPathnameTempDir)  );
	VERIFY_ERR_CHECK(  SG_fsobj__mkdir_recursive__pathname(pCtx, pPathnameTempDir)  );

	INFOP("mktmpdir",("Temp Src Dir is [%s]",SG_pathname__sz(pPathnameTempDir)));

	*ppPathnameTempDir = pPathnameTempDir;
	return;

fail:
	SG_PATHNAME_NULLFREE(pCtx, pPathnameTempDir);
}
void SG_jscore__check_module_dags(SG_context *pCtx, JSContext *cx, JSObject *glob, const char *reponame)
{
	jsval args[2];
	JSBool js_ok;
	jsval rval;
	JSString *pjs;
	jsval fo = JSVAL_VOID;

	if (gpJSCoreGlobalState->bSkipModules || (! gpJSCoreGlobalState->pPathToModules))
		return;

	SG_ERR_CHECK(  _sg_jscore__install_modules(pCtx, cx, glob, NULL)  );

	SG_JS_NULL_CHECK(  (pjs = JS_NewStringCopyZ(cx, reponame))  );

	args[0] = STRING_TO_JSVAL(pjs);

	SG_JS_NULL_CHECK(  (pjs = JS_NewStringCopyZ(cx, SG_pathname__sz(gpJSCoreGlobalState->pPathToModules)))  );

	args[1] = STRING_TO_JSVAL(pjs);

	if (! JS_LookupProperty(cx, glob, "checkModuleDags", &fo))
	{
		SG_ERR_CHECK_CURRENT;
		SG_ERR_THROW2(SG_ERR_JS, (pCtx, "lookup of checkModuleDags failed"));
	}

	if (!JSVAL_IS_VOID(fo))
	{
		js_ok = JS_CallFunctionName(cx, glob, "checkModuleDags", SG_NrElements(args), args, &rval);
		SG_ERR_CHECK_CURRENT;
		if(!js_ok)
			SG_ERR_THROW2(SG_ERR_JS, (pCtx, "An error occurred initializing modules: call to JavaScript checkModuleDags() failed"));
	}

 fail:
	;
}
/**
 * For MODIFIED or ADDED items we need to populate the right side
 * of the diff.
 *
 * See footnote 1 above for bIsTmp_right.
 * 
 */
static void _get_right_side_details(SG_context * pCtx,
									sg_wc6diff__setup_data * pData,
									const SG_vhash * pvhItem,
									sg_wc_liveview_item * pLVI,
									SG_vhash * pvhDiffItem)
{
	SG_string * pStringLabel_right  = NULL;
	SG_pathname * pPathAbsolute_right = NULL;
	SG_vhash * pvhSubsection_right = NULL;		// we do not own this
	const char * pszRepoPath_right;
	char bufDate[SG_TIME_FORMAT_LENGTH+1];
	SG_bool bIsTmp_right;
	SG_fsobj_stat st_right;

	// get the repo-path for the right side *AS IT EXISTED IN THE RIGHT CSET*.
	SG_ERR_CHECK(  SG_vhash__get__vhash(pCtx, pvhItem, pData->pszSubsectionRight, &pvhSubsection_right)  );
	SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvhSubsection_right, "path", &pszRepoPath_right)  );

	SG_ERR_CHECK(  sg_wc_liveview_item__get_proxy_file_path(pCtx, pLVI, pData->pWcTx, &pPathAbsolute_right, &bIsTmp_right)  );
	SG_ERR_CHECK(  SG_fsobj__stat__pathname(pCtx, pPathAbsolute_right, &st_right)  );
	SG_ERR_CHECK(  SG_time__format_utc__i64(pCtx, st_right.mtime_ms, bufDate, SG_NrElements(bufDate))  );

	// the right label is "<right_repo_path> <datestamp>"
	SG_ERR_CHECK(  SG_fsobj__stat__pathname(pCtx, pPathAbsolute_right, &st_right)  );
	SG_ERR_CHECK(  sg_wc_diff_utils__make_label(pCtx, pszRepoPath_right, NULL, bufDate, &pStringLabel_right)  );

	// put the various fields that we need to use in the call to SG_difftool__run()
	// into the pvhDiffItem for later.

	SG_ERR_CHECK(  SG_vhash__add__string__sz(pCtx, pvhDiffItem, "right_label",    SG_string__sz(pStringLabel_right))  );
	SG_ERR_CHECK(  SG_vhash__add__string__sz(pCtx, pvhDiffItem, "right_abs_path", SG_pathname__sz(pPathAbsolute_right))  );
	SG_ERR_CHECK(  SG_vhash__add__bool(      pCtx, pvhDiffItem, "right_is_tmp",   bIsTmp_right)  );

fail:
	SG_PATHNAME_NULLFREE(pCtx, pPathAbsolute_right);
	SG_STRING_NULLFREE(pCtx, pStringLabel_right);
}
Beispiel #20
0
int u0020_utf8pathnames__test(SG_context * pCtx)
{
	SG_pathname * pPathnameTmpDir;
	int k, kLimit;

	// create a temporary directory.

	VERIFY_ERR_CHECK_RETURN(  u0020_utf8pathnames__mkdir_tmp_dir(pCtx, &pPathnameTmpDir)  );

	INFOP("u0020_utf8pathnames",("Creating directory [%s]",SG_pathname__sz(pPathnameTmpDir)));

	// create a series of files in the temporary directory that have
	// various unicode characters in their names.

	kLimit = SG_NrElements(table);
	for (k=0; k<kLimit; k++)
	{
		_tableitem * pti = &table[k];

		INFOP("u0020_utf8pathnames",("[%d] starts with [%c]",k,pti->pa8[0]));
		VERIFY_ERR_CHECK_DISCARD(  u0020_utf8pathnames__create_file(pCtx,pPathnameTmpDir,pti)  );
	}

	// open the tmp dir for reading and read the filename of each file in it.
	// compare these with the version of the filename that we used to create
	// the file.

	VERIFY_ERR_CHECK_DISCARD(  u0020_utf8pathnames__readdir(pCtx, pPathnameTmpDir)  );

	// clean up our mess

	VERIFY_ERR_CHECK_DISCARD(  SG_fsobj__rmdir_recursive__pathname(pCtx, pPathnameTmpDir)  );

	SG_PATHNAME_NULLFREE(pCtx, pPathnameTmpDir);
	return 1;
}
Beispiel #21
0
void MyFn(create_some_blobs_from_files)(SG_context * pCtx,
										SG_repo * pRepo,
										const SG_pathname * pPathnameTempDir)
{
	SG_uint64 k;
	char * szRepoId;

    VERIFY_ERR_CHECK_DISCARD(  SG_repo__get_repo_id(pCtx, pRepo, &szRepoId)  );

	INFOP("create_some_blobs_from_files",("RepoID[%s] TempDir[%s] ",
										  szRepoId,
										  SG_pathname__sz(pPathnameTempDir)
										  ));
    SG_NULLFREE(pCtx, szRepoId);

	//////////////////////////////////////////////////////////////////
	// create a series of blobs of various known lengths and contents.

	for (k=1; k <= MyMaxFile; k+= MyStepFile)
	{
		SG_ERR_IGNORE(  MyFn(create_blob_from_file)(pCtx, pRepo,pPathnameTempDir,k,"Hello World!\nThis is line 2.\n")  );
		SG_ERR_IGNORE(  MyFn(create_blob_from_file)(pCtx, pRepo,pPathnameTempDir,k,"Welcome to the middle of the film!\n")  );
	}
}
Beispiel #22
0
void SG_vfile__begin(
	SG_context* pCtx,
	const SG_pathname* pPath, /**< The path of the file containing the JSON text */
	SG_file_flags mode,
	SG_vhash** ppvh, /**< If there are no errors, the resulting vhash table will be returned here. */
	SG_vfile** ppvf
	)
{
	SG_vfile* pvf = NULL;
	SG_vhash* pvh = NULL;
	SG_uint32 len32;
	SG_fsobj_type t;
	SG_byte* p = NULL;
	SG_bool bExists;
	SG_fsobj_type FsObjType;
	SG_fsobj_perms FsObjPerms;

	SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx, pPath, &bExists, &FsObjType, &FsObjPerms)  );

	if (
		bExists
		&& (SG_FSOBJ_TYPE__REGULAR != FsObjType)
		)
	{
		SG_ERR_THROW_RETURN(SG_ERR_NOTAFILE);
	}

	if (bExists)
	{
		SG_uint64 len64;
		SG_ERR_CHECK(  SG_fsobj__length__pathname(pCtx, pPath, &len64, &t)  );

		// TODO "len" is uint64 because we can have huge files, but
		// TODO our buffer is limited to uint32 (on 32bit systems).
		// TODO verify that len will fit in uint32.
		len32 = (SG_uint32)len64;
	}
	else
	{
		len32 = 0;
	}

	SG_ERR_CHECK_RETURN(  SG_alloc1(pCtx, pvf)  );

	SG_ERR_CHECK(  SG_file__open__pathname(pCtx, pPath, mode | SG_FILE_LOCK, SG_FSOBJ_PERMS__UNUSED, &pvf->pFile)  );

	pvf->mode = mode;

#if TRACE_VFILE
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR, "VFileBegin: Reading %d bytes from %s\n", len32, SG_pathname__sz(pPath))  );
#endif

	if (len32 > 0)
	{
		SG_ERR_CHECK(  SG_alloc(pCtx, 1,len32+1,&p)  );
		SG_ERR_CHECK(  SG_file__read(pCtx, pvf->pFile, len32, p, NULL)  );

		p[len32] = 0;

		SG_ERR_CHECK(  SG_VHASH__ALLOC__FROM_JSON(pCtx, &pvh, (const char*) p)  );

		SG_NULLFREE(pCtx, p);
		p = NULL;
	}
	else
	{
		pvh = NULL;
	}

	*ppvf = pvf;
	*ppvh = pvh;

	return;

fail:
	SG_FILE_NULLCLOSE(pCtx, pvf->pFile);
	SG_NULLFREE(pCtx, p);
	SG_NULLFREE(pCtx, pvf);
}
void MyFn(create_repo)(SG_context * pCtx, SG_repo** ppRepo)
{
	SG_repo* pRepo = NULL;
	SG_pathname* pPath_repo = NULL;
	char buf_repo_id[SG_GID_BUFFER_LENGTH];
	char buf_admin_id[SG_GID_BUFFER_LENGTH];
	SG_vhash* pvhPartialDescriptor = NULL;
	char* pszRepoImpl = NULL;

	VERIFY_ERR_CHECK(  SG_gid__generate(pCtx, buf_repo_id, sizeof(buf_repo_id))  );
	VERIFY_ERR_CHECK(  SG_gid__generate(pCtx, buf_admin_id, sizeof(buf_admin_id))  );

	/* Get our paths fixed up */
	VERIFY_ERR_CHECK(  SG_PATHNAME__ALLOC(pCtx, &pPath_repo)  );
	VERIFY_ERR_CHECK(  SG_pathname__set__from_cwd(pCtx, pPath_repo)  );
	VERIFY_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, pPath_repo, "repo")  );

	SG_fsobj__mkdir__pathname(pCtx, pPath_repo);
	SG_context__err_reset(pCtx);

	// Create the repo
	VERIFY_ERR_CHECK(  SG_VHASH__ALLOC(pCtx, &pvhPartialDescriptor)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__NEWREPO_DRIVER, NULL, &pszRepoImpl, NULL)  );
    if (pszRepoImpl)
    {
        VERIFY_ERR_CHECK_DISCARD(  SG_vhash__add__string__sz(pCtx, pvhPartialDescriptor, SG_RIDESC_KEY__STORAGE, pszRepoImpl)  );
    }

	VERIFY_ERR_CHECK(  SG_vhash__add__string__sz(pCtx, pvhPartialDescriptor, SG_RIDESC_FSLOCAL__PATH_PARENT_DIR, SG_pathname__sz(pPath_repo))  );
	VERIFY_ERR_CHECK(  SG_repo__create_repo_instance(pCtx,NULL,pvhPartialDescriptor,SG_TRUE,NULL,buf_repo_id,buf_admin_id,&pRepo)  );

	*ppRepo = pRepo;

	// Fall through to common cleanup

fail:
	SG_VHASH_NULLFREE(pCtx, pvhPartialDescriptor);
	SG_PATHNAME_NULLFREE(pCtx, pPath_repo);

    SG_NULLFREE(pCtx, pszRepoImpl);
}
static void sg_read_entire_file(
	SG_context* pCtx,
	const SG_pathname* pPath,
	char** ppbuf,
	SG_uint32* plen
	)
{
	SG_uint32 len32;
	SG_fsobj_type t;
	SG_byte* p = NULL;
	SG_bool bExists;
	SG_fsobj_type FsObjType;
	SG_fsobj_perms FsObjPerms;
	SG_file* pFile = NULL;

	SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx, pPath, &bExists, &FsObjType, &FsObjPerms)  );

	if (
		bExists
		&& (SG_FSOBJ_TYPE__REGULAR != FsObjType)
		)
	{
		SG_ERR_IGNORE(  SG_log__report_error(pCtx, "Unable to open file: %s.", SG_pathname__sz(pPath))  );
		
		SG_ERR_THROW_RETURN(SG_ERR_NOTAFILE);
	}

	if (bExists)
	{
		SG_uint64 len64;
		SG_ERR_CHECK(  SG_fsobj__length__pathname(pCtx, pPath, &len64, &t)  );

		// TODO "len" is uint64 because we can have huge files, but
		// TODO our buffer is limited to uint32 (on 32bit systems).
		// TODO verify that len will fit in uint32.
		len32 = (SG_uint32)len64;

		SG_ERR_CHECK(  SG_file__open__pathname(pCtx, pPath, SG_FILE_RDONLY | SG_FILE_OPEN_EXISTING, SG_FSOBJ_PERMS__UNUSED, &pFile)  );
	}
	else
	{
		SG_ERR_THROW_RETURN(SG_ERR_NOTAFILE);
		//len32 = 0;
	}

	if (len32 > 0)
	{
		SG_ERR_CHECK(  SG_alloc(pCtx, 1,len32+1,&p)  );
		SG_ERR_CHECK(  SG_file__read(pCtx, pFile, len32, p, NULL)  );

		p[len32] = 0;

		*ppbuf = (char*) p;
		p = NULL;
		*plen = len32;
	}
	else
	{
		*ppbuf = NULL;
		*plen = 0;
	}

fail:
	SG_FILE_NULLCLOSE(pCtx, pFile);
	SG_NULLFREE(pCtx, p);
}
/**
 * Return a pathname (live or temp) to a file that contains
 * the CURRENTLY QUEUED content that this item **SHOULD** have
 * at this point in the TX.
 *
 * That is, the caller could be in the middle of a TX and have
 * overwritten the file once or twice and then may now be
 * requesting the path to show a diff.  Or the file content may
 * be unchanged, but we have queued one or more moves/renames to
 * it or parent directories.
 *
 * As a good player INSIDE THE TX, we need to give them a path
 * to a CURRENT IN-TX COPY OF THE ***CONTENT*** (wherever it
 * may be).
 *
 * So the path we return may be to a temp file that was created
 * as a source for a QUEUED overwrite.  Or it may be a path to
 * the unmodified content in the WD -- WHERE IT WAS BEFORE THE
 * TX -- because until APPLY is called, the WD hasn't been
 * changed yet.
 *
 * Regardless of whether the result is a temp file or not, the
 * caller should be careful to not let the user modify the file
 * without participating in the TX.  That is, if we return the
 * actual non-temp working copy of a file and they use it in a
 * DIFF and the user's difftool is interactive and they alter
 * it and then we cancel the TX, what should the WD version of
 * the file contain?
 * 
 * See also:
 * __overwrite_file_from_file()
 * __overwrite_file_from_repo()
 * __add_special()
 * __undo_delete()
 *
 *
 * We return an indication of whether the file is a TEMP file
 * and shouldn't be written to.  It DOES NOT indicate that you
 * can delete it -- it indicates that you should not edit it because
 * *WE* will probably delete the file if the TX is rolled-back and so
 * the user would lose their edits.
 * 
 */
void sg_wc_liveview_item__get_proxy_file_path(SG_context * pCtx,
											  sg_wc_liveview_item * pLVI,
											  SG_wc_tx * pWcTx,
											  SG_pathname ** ppPath,
											  SG_bool * pbIsTmp)
{
	SG_string * pStringRepoPath = NULL;
	SG_pathname * pPathAbsolute = NULL;
	char * pszGid = NULL;
	const char * psz;
	SG_bool bIsTmp = SG_TRUE;

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

	if (pLVI->queuedOverwrites.pvhContent == NULL)
	{
		// No changes to the content yet in this TX.  Return the PRE-TX
		// pathname of this file.  (We may have QUEUED moves/renames on
		// the file or a parent directory, but they haven't been applied
		// yet.)

		SG_ASSERT(  pLVI->pPrescanRow  );
		SG_ASSERT(  pLVI->pPrescanRow->pStringEntryname  );
		SG_ASSERT(  pLVI->pPrescanRow->pPrescanDir_Ref  );
		SG_ASSERT(  pLVI->pPrescanRow->pPrescanDir_Ref->pStringRefRepoPath  );

		SG_ERR_CHECK(  SG_STRING__ALLOC__COPY(pCtx,
											  &pStringRepoPath,
											  pLVI->pPrescanRow->pPrescanDir_Ref->pStringRefRepoPath)  );
		SG_ERR_CHECK(  SG_repopath__append_entryname(pCtx,
													 pStringRepoPath,
													 SG_string__sz(pLVI->pPrescanRow->pStringEntryname),
													 SG_FALSE)  );
		SG_ERR_CHECK(  sg_wc_db__path__repopath_to_absolute(pCtx, pWcTx->pDb,
															pStringRepoPath,
															&pPathAbsolute)  );
		bIsTmp = SG_FALSE;	// path is to actual WC file
		goto done;
	}

	SG_ERR_CHECK_RETURN(  SG_vhash__check__sz(pCtx, pLVI->queuedOverwrites.pvhContent, "file", &psz)  );
	if (psz)
	{
		// return path to existing TEMP file.  someone else owns the file.

		SG_ERR_CHECK(  SG_PATHNAME__ALLOC__SZ(pCtx, &pPathAbsolute, psz)  );
		bIsTmp = SG_TRUE;	// path is to a TEMP file (for which an overwrite-from-file has already been scheduled).
		goto done;
	}

	SG_ERR_CHECK_RETURN(  SG_vhash__check__sz(pCtx, pLVI->queuedOverwrites.pvhContent, "hid", &psz)  );
	if (psz)
	{
		// synthesize a TEMP file for this.  caller owns the new temp file.

		SG_ERR_CHECK(  sg_wc_db__gid__get_gid_from_alias(pCtx, pWcTx->pDb, pLVI->uiAliasGid, &pszGid)  );
		SG_ERR_CHECK(  sg_wc_diff_utils__export_to_temp_file(pCtx, pWcTx, "ref", pszGid, psz,
															 SG_string__sz(pLVI->pStringEntryname),	// for suffix only
															 &pPathAbsolute)  );
		bIsTmp = SG_TRUE;	// path is to a TEMP file that we just created.
		goto done;
	}

	SG_ERR_THROW2_RETURN(  SG_ERR_NOTIMPLEMENTED,
						   (pCtx,
							"GetProxyFilePath: required field missing from vhash for: %s",
							SG_string__sz(pLVI->pStringEntryname))  );

done:
#if TRACE_WC_LIE
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "GetProxyFilePath: '%s' ==> '%s' [bIsTmp %d]\n",
							   SG_string__sz(pLVI->pStringEntryname),
							   SG_pathname__sz(pPathAbsolute),
							   bIsTmp)  );
#endif
	*ppPath = pPathAbsolute;
	pPathAbsolute = NULL;
	*pbIsTmp = bIsTmp;

fail:
	SG_PATHNAME_NULLFREE(pCtx, pPathAbsolute);
	SG_STRING_NULLFREE(pCtx, pStringRepoPath);
	SG_NULLFREE(pCtx, pszGid);
}
Beispiel #26
0
int u0040_unc__stat_dir(SG_context * pCtx, const char * szDir)
{
	SG_pathname * pPathname = NULL;
	SG_pathname * pPathnameFile = NULL;
	SG_file * pf = NULL;
	SG_fsobj_stat fsobjStat;
	SG_bool bFileExists;
	SG_int_to_string_buffer bufSize;
	char bufDate[100];

	SG_context__err_reset(pCtx);

	//////////////////////////////////////////////////////////////////
	// stat the given directory.
	//////////////////////////////////////////////////////////////////

	INFOP("u0040_unc",("Inspecting [%s]",szDir));

	VERIFY_ERR_CHECK_RETURN(  SG_PATHNAME__ALLOC__SZ(pCtx,&pPathname,szDir)  );

	VERIFY_ERR_CHECK(  SG_fsobj__stat__pathname(pCtx,pPathname,&fsobjStat)  );
	VERIFY_COND("u0040_unc",(fsobjStat.type == SG_FSOBJ_TYPE__DIRECTORY));

	// TODO should we verify length == 0 ?
	// TODO should we verify modtime ?

	SG_uint64_to_sz(fsobjStat.size, bufSize);
	VERIFY_ERR_CHECK_DISCARD(  SG_time__format_utc__i64(pCtx,fsobjStat.mtime_ms,bufDate,SG_NrElements(bufDate))  );

	INFOP("u0040_unc",("Result: [perms %04o][type %d][size %s][mtime %s]",
					   fsobjStat.perms,fsobjStat.type,
					   bufSize,bufDate));

	//////////////////////////////////////////////////////////////////
	// create a unique file in the directory and stat it.
	//////////////////////////////////////////////////////////////////

	VERIFY_ERR_CHECK(  unittest__alloc_unique_pathname(pCtx,szDir,&pPathnameFile)  );

	INFOP("u0040_unc",("    Creating file [%s]",SG_pathname__sz(pPathnameFile)));

	VERIFY_ERR_CHECK(  SG_file__open__pathname(pCtx,pPathnameFile,SG_FILE_CREATE_NEW | SG_FILE_RDWR,0777,&pf)  );

	VERIFY_ERR_CHECK(  SG_fsobj__stat__pathname(pCtx,pPathnameFile,&fsobjStat)  );
	VERIFY_COND("u0040_unc",(fsobjStat.type == SG_FSOBJ_TYPE__REGULAR));
	VERIFY_COND("u0040_unc",(fsobjStat.size == 0));
	VERIFY_COND("u0040_unc",(SG_fsobj__equivalent_perms(fsobjStat.perms,0777)));
	// TODO should we verify modtime ?

	SG_uint64_to_sz(fsobjStat.size, bufSize);
	VERIFY_ERR_CHECK_DISCARD(  SG_time__format_utc__i64(pCtx,fsobjStat.mtime_ms,bufDate,SG_NrElements(bufDate))  );

	INFOP("u0040_unc",("    Result: [perms %04o][type %d][size %s][mtime %s]",
					   fsobjStat.perms,fsobjStat.type,
					   bufSize,bufDate));

	VERIFY_ERR_CHECK_DISCARD(  SG_file__close(pCtx, &pf)  );

	// delete the file and stat it again

	VERIFY_ERR_CHECK_DISCARD(  SG_fsobj__remove__pathname(pCtx,pPathnameFile)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_fsobj__exists__pathname(pCtx,pPathnameFile,&bFileExists,NULL,NULL)  );
	VERIFY_COND("u0040_unc",(!bFileExists));

	//////////////////////////////////////////////////////////////////
	// clean up
	//////////////////////////////////////////////////////////////////

	SG_PATHNAME_NULLFREE(pCtx, pPathnameFile);
	SG_PATHNAME_NULLFREE(pCtx, pPathname);
	return 1;

fail:
	SG_FILE_NULLCLOSE(pCtx, pf);
	SG_PATHNAME_NULLFREE(pCtx, pPathnameFile);
	SG_PATHNAME_NULLFREE(pCtx, pPathname);
	return 0;
}
Beispiel #27
0
/**
 * Assuming that we have something of the form:
 * 
 *     vv resolve [--foo] <arg_0> [<arg_1> [<arg_2> ...]]
 *
 * where each <arg_x> is an absolute or relative path in the WD
 * (probably not a repo-path).
 *
 * Use the PENDINGTREE to lookup each path and get the entry's GID.
 * Use the GID to search for an ISSUE in the list of issues.  If we
 * find it, add the GID to the stringarray we are building.  If not,
 * throw an error.
 */
static void _resolve__map_args_to_gids(SG_context * pCtx,
									   struct _resolve_data * pData,
									   SG_uint32 count_args, const char ** paszArgs,
									   SG_bool bWantResolved,
									   SG_bool bWantUnresolved)
{
	SG_pathname * pPath_k = NULL;
	char * pszGid_k = NULL;
	SG_uint32 kArg;
	SG_bool bWantBoth = (bWantResolved && bWantUnresolved);

	SG_ERR_CHECK(  SG_STRINGARRAY__ALLOC(pCtx, &pData->psaGids, count_args)  );

	for (kArg=0; kArg<count_args; kArg++)
	{
		const SG_vhash * pvhIssue_k;
		SG_bool bFound;
		SG_bool bDuplicate;
		SG_bool bWantThisOne;

		// take each <arg_k> and get a full pathname for it and
		// search for it in the pendingtree and get its GID.
		// in theory, if an entry has an issue, it is dirty and
		// should have a ptnode.

		if (paszArgs[kArg][0] == '@')
			SG_ERR_CHECK(  SG_workingdir__construct_absolute_path_from_repo_path2(pCtx, pData->pPendingTree, paszArgs[kArg], &pPath_k)  );
		else
			SG_ERR_CHECK(  SG_PATHNAME__ALLOC__SZ(pCtx, &pPath_k, paszArgs[kArg])  );

		SG_ERR_CHECK(  SG_pendingtree__get_gid_from_local_path(pCtx, pData->pPendingTree, pPath_k, &pszGid_k)  );
#if 0 && defined(DEBUG)
		SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
								   ("Mapped arg[%d] '%s' to:\n"
									"\t%s\n"
									"\t[gid %s]\n"),
								   kArg, paszArgs[kArg],
								   SG_pathname__sz(pPath_k),
								   pszGid_k)  );
#endif

		// see if there is an ISSUE for this GID.

		SG_ERR_CHECK(  SG_pendingtree__find_wd_issue_by_gid(pCtx, pData->pPendingTree, pszGid_k, &bFound, &pvhIssue_k)  );
		if (!bFound)
			SG_ERR_THROW2(  SG_ERR_ISSUE_NOT_FOUND,
							(pCtx, "No issue found for '%s': %s",
							 paszArgs[kArg],
							 SG_pathname__sz(pPath_k))  );

		if (bWantBoth)
			bWantThisOne = SG_TRUE;
		else
		{
			SG_int64 s;
			SG_pendingtree_wd_issue_status status;
			SG_bool bResolved;

			SG_ERR_CHECK_RETURN(  SG_vhash__get__int64(pCtx, pvhIssue_k, "status", &s)  );
			status = (SG_pendingtree_wd_issue_status)s;
			bResolved = ((status & SG_ISSUE_STATUS__MARKED_RESOLVED) == SG_ISSUE_STATUS__MARKED_RESOLVED);

			bWantThisOne = ((bWantResolved && bResolved) || (bWantUnresolved && !bResolved));
		}

		if (bWantThisOne)
		{
			// check for duplicate args on command line. (or rather, args that
			// map to the same GID.)

			SG_ERR_CHECK(  SG_stringarray__find(pCtx, pData->psaGids, pszGid_k, 0, &bDuplicate, NULL)  );
			if (bDuplicate)
				SG_ERR_THROW2(  SG_ERR_DUPLICATE_ISSUE,
								(pCtx, "Argument '%s' maps to an issue already named.", paszArgs[kArg])  );

			SG_ERR_CHECK(  SG_stringarray__add(pCtx, pData->psaGids, pszGid_k)  );
		}

		SG_NULLFREE(pCtx, pszGid_k);
		SG_PATHNAME_NULLFREE(pCtx, pPath_k);
	}

	return;

fail:
	SG_NULLFREE(pCtx, pszGid_k);
	SG_PATHNAME_NULLFREE(pCtx, pPath_k);
}
static void perform_upload_request__string(
    SG_context* pCtx,
    CFHTTPMessageRef myRequest,
    SG_pathname* pPath,
    CFHTTPMessageRef* pmyResponse,
    SG_string** ppstr
)
{
    CFReadStreamRef myReadStream = NULL;
    CFHTTPMessageRef myResponse = NULL;
    SG_string* pstr = NULL;
    CFReadStreamRef upload = NULL;
    CFURLRef upload_file_url = NULL;

    // set the content-length header
    {
        SG_uint64 len = 0;
        SG_ERR_CHECK(  SG_fsobj__length__pathname(pCtx, pPath, &len, NULL)  );

        CFStringRef headerFieldName = CFSTR("Content-Length");
        CFStringRef headerFieldValue = CFStringCreateWithFormat (kCFAllocatorDefault, NULL,  CFSTR("%d"), len);
        CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
        CFRelease(headerFieldValue);
    }

    upload_file_url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*) SG_pathname__sz(pPath), SG_STRLEN(SG_pathname__sz(pPath)), SG_FALSE);
    upload = CFReadStreamCreateWithFile(kCFAllocatorDefault, upload_file_url);
    CFRelease(upload_file_url);
    if (!CFReadStreamOpen(upload))
    {
        CFStreamError myErr = CFReadStreamGetError(upload);

        if (myErr.domain == kCFStreamErrorDomainPOSIX)
        {
            // Interpret myErr.error as a UNIX errno.
            SG_ERR_THROW(  SG_ERR_ERRNO(myErr.error)  );
        }
        else if (myErr.domain == kCFStreamErrorDomainMacOSStatus)
        {
            // Interpret myErr.error as a MacOS error code.
            // TODO SG_ERR_THROW(  SG_ERR_MAC((OSStatus) myErr.error)  );
            SG_ERR_THROW(  SG_ERR_UNSPECIFIED  );
        }
    }

    SG_ERR_CHECK(  send_upload_request(pCtx, myRequest, upload, &myReadStream)  );
    SG_ERR_CHECK(  read_entire_stream__string(pCtx, myReadStream, &pstr, &myResponse)  );

    *ppstr = pstr;
    pstr = NULL;

    *pmyResponse = myResponse;
    myResponse = NULL;

fail:
    if (upload)
    {
        CFRelease(upload);
    }
    if (myReadStream)
    {
        CFReadStreamClose(myReadStream);
        CFRelease(myReadStream);
        myReadStream = NULL;
    }

    if (myResponse)
    {
        CFRelease(myResponse);
        myResponse = NULL;
    }

    SG_STRING_NULLFREE(pCtx, pstr);
}
Beispiel #29
0
void MyFn(create_repo)(SG_context * pCtx, SG_repo ** ppRepo)
{
	// caller must free returned value.

	SG_repo * pRepo;
	SG_pathname * pPathnameRepoDir = NULL;
	SG_vhash* pvhPartialDescriptor = NULL;
    char buf_repo_id[SG_GID_BUFFER_LENGTH];
    char buf_admin_id[SG_GID_BUFFER_LENGTH];
	char* pszRepoImpl = NULL;

	VERIFY_ERR_CHECK(  SG_gid__generate(pCtx, buf_repo_id, sizeof(buf_repo_id))  );
	VERIFY_ERR_CHECK(  SG_gid__generate(pCtx, buf_admin_id, sizeof(buf_admin_id))  );

	VERIFY_ERR_CHECK(  SG_PATHNAME__ALLOC(pCtx, &pPathnameRepoDir)  );
	VERIFY_ERR_CHECK(  SG_pathname__set__from_cwd(pCtx, pPathnameRepoDir)  );

	VERIFY_ERR_CHECK(  SG_VHASH__ALLOC(pCtx, &pvhPartialDescriptor)  );

	VERIFY_ERR_CHECK_DISCARD(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__NEWREPO_DRIVER, NULL, &pszRepoImpl, NULL)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_vhash__add__string__sz(pCtx, pvhPartialDescriptor, SG_RIDESC_KEY__STORAGE, pszRepoImpl)  );

	VERIFY_ERR_CHECK(  SG_vhash__add__string__sz(pCtx, pvhPartialDescriptor, SG_RIDESC_FSLOCAL__PATH_PARENT_DIR, SG_pathname__sz(pPathnameRepoDir))  );

	VERIFY_ERR_CHECK(  SG_repo__create_repo_instance(pCtx,pvhPartialDescriptor,SG_TRUE,NULL,buf_repo_id,buf_admin_id,&pRepo)  );

	SG_VHASH_NULLFREE(pCtx, pvhPartialDescriptor);

	{
		const SG_vhash * pvhRepoDescriptor = NULL;
		VERIFY_ERR_CHECK(  SG_repo__get_descriptor(pCtx, pRepo,&pvhRepoDescriptor)  );

		//INFOP("open_repo",("Repo is [%s]",SG_string__sz(pstrRepoDescriptor)));
	}

	*ppRepo = pRepo;

fail:
	SG_VHASH_NULLFREE(pCtx, pvhPartialDescriptor);
	SG_PATHNAME_NULLFREE(pCtx, pPathnameRepoDir);

    SG_NULLFREE(pCtx, pszRepoImpl);
}
/**
 * create 1 test file.
 * cat it to a second file using files bound to child's STDIN and STDOUT.
 * cat both files to third file using cl args for input and third bound to child's STDOUT.
 * cat all 3 files using cl args to OUR STDOUT.
 */
void MyFn(test1)(SG_context * pCtx)
{
	SG_exit_status exitStatusChild;
	SG_file * pFileF1 = NULL;
	SG_file * pFileF2 = NULL;
	SG_file * pFileF3 = NULL;
	SG_pathname * pPathTempDir = NULL;
	SG_pathname * pPathF1 = NULL;
	SG_pathname * pPathF2 = NULL;
	SG_pathname * pPathF3 = NULL;
	SG_exec_argvec * pArgVec = NULL;

	// create a GID temp directory in the current directory.

	VERIFY_ERR_CHECK(  unittest__alloc_unique_pathname_in_cwd(pCtx,&pPathTempDir)  );
	VERIFY_ERR_CHECK(  SG_fsobj__mkdir_recursive__pathname(pCtx,pPathTempDir)  );

	// create a couple of pathnames to test files in the temp directory.

	VERIFY_ERR_CHECK(  unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF1)  );
	INFOP("exec",("PathF1 is %s",SG_pathname__sz(pPathF1)));
	VERIFY_ERR_CHECK(  unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF2)  );
	INFOP("exec",("PathF2 is %s",SG_pathname__sz(pPathF2)));
	VERIFY_ERR_CHECK(  unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF3)  );
	INFOP("exec",("PathF3 is %s",SG_pathname__sz(pPathF3)));

	//////////////////////////////////////////////////////////////////
	// create F1 and write some data to it.

	VERIFY_ERR_CHECK(  SG_file__open__pathname(pCtx,pPathF1,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0644,&pFileF1)  );
	VERIFY_ERR_CHECK(  SG_file__write(pCtx,pFileF1,
									  SG_pathname__length_in_bytes(pPathF1),
									  (SG_byte *)SG_pathname__sz(pPathF1),
									  NULL)  );
	VERIFY_ERR_CHECK(  SG_file__write(pCtx,pFileF1,
									  1,
									  (SG_byte *)"\n",
									  NULL)  );
	VERIFY_ERR_CHECK(  SG_file__write(pCtx,pFileF1,
									  SG_pathname__length_in_bytes(pPathF1),
									  (SG_byte *)SG_pathname__sz(pPathF1),
									  NULL)  );
	VERIFY_ERR_CHECK(  SG_file__write(pCtx,pFileF1,
									  1,
									  (SG_byte *)"\n",
									  NULL)  );
	SG_FILE_NULLCLOSE(pCtx, pFileF1);

	//////////////////////////////////////////////////////////////////
	// re-open F1 for reading.
	// create F2 as a place for STDOUT of command.

	VERIFY_ERR_CHECK(  SG_file__open__pathname(pCtx,pPathF1,SG_FILE_RDONLY|SG_FILE_OPEN_EXISTING,0644,&pFileF1)  );
	VERIFY_ERR_CHECK(  SG_file__open__pathname(pCtx,pPathF2,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,   0644,&pFileF2)  );

	// exec: /bin/cat <f1 >f2

	VERIFY_ERR_CHECK(  SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,NULL,pFileF1,pFileF2,NULL,&exitStatusChild)  );
	VERIFY_COND("child status",(exitStatusChild == 0));

	INFOP("/bin/cat <f1 >f2",("Child exit status is [%d]",exitStatusChild));
	SG_FILE_NULLCLOSE(pCtx, pFileF1);
	SG_FILE_NULLCLOSE(pCtx, pFileF2);

	//////////////////////////////////////////////////////////////////
	// let F1 and F2 be given on the command line.
	// create F3 as a place for STDOUT of command.

	VERIFY_ERR_CHECK(  SG_file__open__pathname(pCtx,pPathF3,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,   0644,&pFileF3)  );

	// exec: /bin/cat -n f1 f2 >f3

	VERIFY_ERR_CHECK(  SG_exec_argvec__alloc(pCtx,&pArgVec)  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,"-n")  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF1))  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF2))  );

	VERIFY_ERR_CHECK(  SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,pFileF3,NULL,&exitStatusChild)  );
	VERIFY_COND("child status",(exitStatusChild == 0));

	INFOP("/bin/cat -n f1 f2 >f3",("Child exit status is [%d]",exitStatusChild));
	SG_FILE_NULLCLOSE(pCtx, pFileF3);
	SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec);

	//////////////////////////////////////////////////////////////////
	// exec: /bin/cat f1 f2 f3 (to our stdout)

	VERIFY_ERR_CHECK(  SG_exec_argvec__alloc(pCtx,&pArgVec)  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF1))  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF2))  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF3))  );

	VERIFY_ERR_CHECK(  SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,NULL,NULL,&exitStatusChild)  );
	VERIFY_COND("child status",(exitStatusChild == 0));

	INFOP("/bin/cat -n f1 f2 f3",("Child exit status is [%d]",exitStatusChild));
	SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec);

	//////////////////////////////////////////////////////////////////
	// exec: /bin/cat f3 f2 f1 (to our stdout)

	VERIFY_ERR_CHECK(  SG_exec_argvec__alloc(pCtx,&pArgVec)  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF3))  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF2))  );
	VERIFY_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF1))  );

	VERIFY_ERR_CHECK(  SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,NULL,NULL,&exitStatusChild)  );
	VERIFY_COND("child status",(exitStatusChild == 0));

	INFOP("/bin/cat -n f3 f2 f1",("Child exit status is [%d]",exitStatusChild));
	SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec);

	// fall through to common cleanup.

fail:
	SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec);
	SG_PATHNAME_NULLFREE(pCtx, pPathTempDir);
	SG_PATHNAME_NULLFREE(pCtx, pPathF1);
	SG_PATHNAME_NULLFREE(pCtx, pPathF2);
	SG_PATHNAME_NULLFREE(pCtx, pPathF3);
	SG_FILE_NULLCLOSE(pCtx, pFileF1);
	SG_FILE_NULLCLOSE(pCtx, pFileF2);
	SG_FILE_NULLCLOSE(pCtx, pFileF3);
}