static void _fetch_size_of_blob(SG_context * pCtx,
								SG_wc_tx * pWcTx,
								const char * pszHidContent,
								SG_uint64 * pSize)
{
    SG_uint64 len = 0;

	SG_ERR_CHECK_RETURN(  SG_repo__fetch_blob__begin(pCtx, pWcTx->pDb->pRepo, pszHidContent,
													 SG_TRUE, NULL, NULL, NULL, &len, NULL)  );
	*pSize = len;
}
Esempio n. 2
0
void MyFn(create_blob_from_bytes)(SG_context * pCtx,
								  SG_repo * pRepo,
								  SG_uint32 lenBuf1,
								  const char * szSrc)
{
	// create a large buffer containing some known data.
	// use it to create a blob directly from the buffer.
	// read it back from the repo and verify it.

	char* pszidTidRandom1 = NULL;
	char* pszidTidRandom2 = NULL;
	SG_uint32 lenSrc;
	char* pszidHidBlob1 = NULL;
	char* pszidHidBlob1Dup = NULL;
	char* pszidHidBlob2 = NULL;
	char* pszidHidVerify1 = NULL;
	char* pszidHidVerify2 = NULL;
	SG_bool bEqual;
	char * pbuf1 = NULL;
	char * pbuf2 = NULL;
	char * pbuf1End;
	char * p1;
	SG_uint64 lenBuf2;
	SG_repo_tx_handle* pTx = NULL;
	SG_repo_fetch_blob_handle* pFetchHandle = NULL;

	SG_uint64 lenAbortedBlob;
	SG_uint32 lenGotAbortedBlob;
    SG_bool b_done = SG_FALSE;

	//////////////////////////////////////////////////////////////////

	SG_ERR_IGNORE(  SG_tid__alloc2(pCtx, &pszidTidRandom1, 32)  );
	SG_ERR_IGNORE(  SG_tid__alloc2(pCtx, &pszidTidRandom2, 32)  );

	if (lenBuf1 < 100)
		lenBuf1 += 100;

	pbuf1 = (char *)SG_calloc(1,lenBuf1+1);
	pbuf1End = pbuf1+lenBuf1;
	p1 = pbuf1;

	// write random gid at the beginning of the buffer
	// so that we won't get collisions if we are called
	// multiple times.

	memcpy(p1,pszidTidRandom1,strlen(pszidTidRandom1));
	p1 += strlen(pszidTidRandom1);
	*p1++ = '\n';

	// generate lots of data in the file so that we'll cause the
	// blob routines to exercise the chunking stuff.

	lenSrc = (SG_uint32)strlen(szSrc);
	while (p1+lenSrc < pbuf1End)
	{
		memcpy(p1,szSrc,lenSrc);
		p1 += lenSrc;
	}

	// use the buffer to create a blob in the repo.  we use lenBuf1 as the
	// length rather than (p1-pbuf1) so we may have some nulls at the end.
	// hope this is ok???  i guess we'll find out...

	VERIFY_ERR_CHECK_DISCARD(  SG_repo__begin_tx(pCtx, pRepo, &pTx)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_repo__store_blob_from_memory(pCtx, pRepo,pTx,NULL,SG_FALSE,(SG_byte *)pbuf1,lenBuf1,&pszidHidBlob1)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_repo__commit_tx(pCtx, pRepo, &pTx)  );

	INFOP("create_blob_from_bytes",("Created blob [%s]",(pszidHidBlob1)));

	//////////////////////////////////////////////////////////////////
	// try to create blob again and verify we get an duplicate-hid error.

	// Ian TODO: Put this back when SG_ERR_BLOBFILEALREADYEXISTS is replaced.
//	VERIFY_ERR_CHECK_DISCARD(  SG_repo__begin_tx(pCtx, pRepo, &pTx)  );
// 	err = SG_repo__store_blob_from_memory(pRepo,pTx,SG_FALSE,(SG_byte *)pbuf1,lenBuf1,&pszidHidBlob1Dup);
// 	VERIFYP_CTX_ERR_IS("create_blob_from_bytes(duplicate)", pCtx, SG_ERR_BLOBFILEALREADYEXISTS, ("Duplicate create failed [%s][%s]",pszidHidBlob1,pszidHidBlob1Dup));
//	VERIFY_ERR_CHECK_DISCARD(  SG_repo__commit_tx(pCtx, pRepo, SG_DAGNUM__NONE, NULL, &pTx)  );

	//////////////////////////////////////////////////////////////////
	// abort a fetch, ensure it doesn't interfere with subsequent complete fetch

	VERIFY_ERR_CHECK_DISCARD(  SG_repo__fetch_blob__begin(pCtx, pRepo, pszidHidBlob1, SG_TRUE, NULL, NULL, NULL, NULL, &lenAbortedBlob, &pFetchHandle)  );

	// We want to abort mid-blob, so we set an arbitrary (but small) chunk size, and verify that the blob is
	// bigger than it.
	VERIFY_ERR_CHECK_DISCARD(  SG_repo__fetch_blob__chunk(pCtx, pRepo, pFetchHandle, 64, (SG_byte*)pbuf1, &lenGotAbortedBlob, &b_done)  );
	VERIFY_COND("create_blob_from_bytes(fetch abort sufficient length)", lenAbortedBlob > lenGotAbortedBlob);

	VERIFY_ERR_CHECK_DISCARD(  SG_repo__fetch_blob__abort(pCtx, pRepo, &pFetchHandle)  );
	VERIFY_COND("create_blob_from_bytes(fetch abort freed handle)", !pFetchHandle);

	//////////////////////////////////////////////////////////////////
	// fetch blob into a new buffer and verify that it matches.

	VERIFY_ERR_CHECK_DISCARD(  SG_repo__fetch_blob_into_memory(pCtx, pRepo,pszidHidBlob1,(SG_byte **)&pbuf2,&lenBuf2)  );
	VERIFY_COND("create_blob_from_bytes(fetch blob)",(lenBuf2 == (SG_uint64)lenBuf1));

	//////////////////////////////////////////////////////////////////
	// verify that the contents of buf-2 is identical to the contents of buf-1.
	// (we already know that the HIDs match and was verified during the fetch,
	// but there are times when the HID is just being used as a key -- it
	// doesn't mean that what we actually restored is correct.

	VERIFY_ERR_CHECK_DISCARD(  SG_repo__alloc_compute_hash__from_bytes(pCtx, pRepo, lenBuf1, (SG_byte *)pbuf1, &pszidHidVerify1)  );

	VERIFY_ERR_CHECK_DISCARD(  SG_repo__alloc_compute_hash__from_bytes(pCtx, pRepo, (SG_uint32)lenBuf2, (SG_byte *)pbuf2, &pszidHidVerify2)  );

	bEqual = (0 == (strcmp(pszidHidVerify1,pszidHidVerify2)));
	VERIFY_COND("create_blob_from_bytes(verify v1==v2)",bEqual);

	bEqual = (0 == (strcmp(pszidHidVerify1,pszidHidBlob1)));
	VERIFY_COND("create_blob_from_bytes(verify v1==id)",bEqual);

	VERIFY_COND("creata_blob_from_bytes(memcmp)",(memcmp(pbuf1,pbuf2,lenBuf1)==0));

	//////////////////////////////////////////////////////////////////
	// cleanup

	SG_NULLFREE(pCtx, pbuf1);
	SG_NULLFREE(pCtx, pbuf2);
	SG_NULLFREE(pCtx, pszidTidRandom1);
	SG_NULLFREE(pCtx, pszidTidRandom2);
	SG_NULLFREE(pCtx, pszidHidBlob1);
	SG_NULLFREE(pCtx, pszidHidBlob1Dup);
	SG_NULLFREE(pCtx, pszidHidBlob2);
	SG_NULLFREE(pCtx, pszidHidVerify1);
	SG_NULLFREE(pCtx, pszidHidVerify2);
}
void sg_wc_tx__apply__store_symlink(SG_context * pCtx,
									SG_wc_tx * pWcTx,
									const SG_vhash * pvh)
{
	SG_pathname * pPath = NULL;
	SG_string * pStringSymlink = NULL;
	const char * pszRepoPath;		// we do not own this
	const char * pszHidExpected;	// we do not own this
	char * pszHidObserved = NULL;
	sg_wc_liveview_item * pLVI;		// we do not own this
	SG_int64 alias;
	SG_bool bKnown;
	SG_bool bDontBother_BlobEncoding;
	SG_bool bSrcIsSparse;

	SG_ERR_CHECK(  SG_vhash__get__sz(   pCtx, pvh, "src",   &pszRepoPath)  );
	SG_ERR_CHECK(  SG_vhash__get__int64(pCtx, pvh, "alias", &alias)  );
	SG_ERR_CHECK(  SG_vhash__get__sz(   pCtx, pvh, "hid",   &pszHidExpected)  );
	SG_ERR_CHECK(  SG_vhash__get__bool( pCtx, pvh, "src_sparse",     &bSrcIsSparse)  );

#if TRACE_WC_TX_APPLY
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   ("sg_wc_tx__apply__store_symlink: '%s' [src-sparse %d]\n"),
							   pszRepoPath, bSrcIsSparse)  );
#endif

	SG_ERR_CHECK(  sg_wc_tx__liveview__fetch_random_item(pCtx, pWcTx, alias, &bKnown, &pLVI)  );

	SG_ASSERT( (bSrcIsSparse == SG_WC_PRESCAN_FLAGS__IS_CONTROLLED_SPARSE(pLVI->scan_flags_Live)) );
	if (bSrcIsSparse)
	{
		// We've been asked to store the target of the symlink ***during a COMMIT***
		// and are given the *Expected-HID* (and we need to get the actual target
		// from the WD) and it is assumed that that will generate the same HID
		// that we were given.
		//
		// However, if the symlink is sparse (not populated) we can't do __readlink()
		// to get the (current) target.  So we have to
		// assume that we already have a blob in the repo for it.
		//
		// Since sparse items now have p_d_sparse dynamic data in tbl_PC, we assume
		// that whoever last modified the content of the symlink and set p_d_sparse->pszHid
		// also recorded the blob we need to be present now. (See __apply__overwrite_symlink())
		//
		// for sanity's sake verify that we already have this blob in the repo.

		SG_uint64 len = 0;
		SG_ERR_CHECK(  SG_repo__fetch_blob__begin(pCtx, pWcTx->pDb->pRepo, pszHidExpected,
												  SG_TRUE, NULL, NULL, NULL, &len, NULL)  );

		// so we don't need to do anything because we already
		// have a copy of this blob in the repo.
		return;
	}

	// We never bother compressing/encoding the symlink content
	// since it is so short.
	bDontBother_BlobEncoding = SG_TRUE;

	SG_ERR_CHECK(  sg_wc_db__path__sz_repopath_to_absolute(pCtx,
														   pWcTx->pDb,
														   pszRepoPath,
														   &pPath)  );

	SG_ERR_CHECK(  SG_fsobj__readlink(pCtx, pPath, &pStringSymlink)  );
	SG_ERR_CHECK(  SG_committing__add_bytes__string(pCtx,
													pWcTx->pCommittingInProgress,
													pStringSymlink,
													bDontBother_BlobEncoding,
													&pszHidObserved)  );

	// See note in __apply__store_file() about race condition.
	// If the HID computed now differs from what we thought
	// it should be, we lost the race.

	if (strcmp(pszHidObserved, pszHidExpected) != 0)
		SG_ERR_THROW2(  SG_ERR_ASSERT,
						(pCtx, "The symlink '%s' changed during the commit.",
						 pszRepoPath)  );

fail:
	SG_PATHNAME_NULLFREE(pCtx, pPath);
	SG_STRING_NULLFREE(pCtx, pStringSymlink);
	SG_NULLFREE(pCtx, pszHidObserved);
}