Deleting a file from git repository using libgit2 - c++

Say you have a file in a git repository:
a.txt
What APIs should be used to create a commit that removes that file?
For example in this question the file is committed without creating it on disk. Is it now possible to remove that file without using the index (stage area)?
I was expecting a similar flow, maybe creating a git_tree_entry for the tree builder, but that does not seem to be the case. git_reference_list() does not list files, so there's a dead end. Also searching the sources for delete and remove got me no success.

Removing a file is similar to adding a file - you remove the index entry to stage the delete, then you can create a commit from the index.
You probably want to use git_index_remove_bypath, which will remove the file from the index and resolve any conflicts that file had.

Here is a copy-paste example; for getLastCommit() see this question.
bool commitStage (
git_repository * repo, git_signature * sign,
const char * message )
{
bool b = false;
int rc;
git_index * repo_idx; /* the stage area for our repository */
git_oid oid_idx_tree; /* the SHA1 for the tree generated from index */
git_oid oid_commit; /* the SHA1 for our commit */
git_tree * tree_cmt; /* tree generated from index */
git_commit * parent_commit;/* most recent commit in the head */
parent_commit = getLastCommit( repo );
if ( parent_commit != NULL )
{ /* we have the parent commit */
rc = git_repository_index( &repo_idx, repo );
if ( rc == 0 )
{ /* we now have the index (stage area) structure in repo_idx */
git_index_read(repo_idx);
/* the stage area may be altered here with functions like
git_index_add_bypath();
git_index_remove_bypath();
*/
/* by writing the index we get the SHA1 of the tree */
rc = git_index_write_tree( &oid_idx_tree, repo_idx );
if ( rc == 0 )
{
rc = git_tree_lookup(
&tree_cmt, repo, &oid_idx_tree );
if ( rc == 0 )
{ /* the actual tree structure; create a commit from it */
rc = git_commit_create(
&oid_commit, repo, "HEAD",
sign, sign, NULL,
message,
tree_cmt, 1, (const git_commit**)&parent_commit );
if ( rc == 0 )
{
b = true;
}
}
}
git_index_free( repo_idx );
}
git_commit_free( parent_commit );
}
return b;
}

Related

How to convert OID of a code-signing algorithm from CRYPT_ALGORITHM_IDENTIFIER to a human readable string?

When I'm retrieving a code signing signature from an executable file on Windows, the CERT_CONTEXT of the certificate points to the CERT_INFO, that has CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm member that contains the algorithm used for signing.
How do I convert that to a human readable form as such?
For instance, SignatureAlgorithm.pszObjId may be set to "1.2.840.113549.1.1.11" string, which is szOID_RSA_SHA256RSA according to this long list. I guess I can make a very long switch statement for it, and link it to "sha256", but I'd rather avoid it since I don't know what most of those values are. Is there an API that can do all that for me?
Use CryptFindOIDInfo to get information about a OID including the display name and the CNG algorithm identifier string:
void PrintSigAlgoName(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo)
{
if(pSigAlgo && pSigAlgo->pszObjId)
{
PCCRYPT_OID_INFO pCOI = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pSigAlgo->pszObjId, 0);
if(pCOI && pCOI->pwszName)
{
_tprintf(_T("%ls"), pCOI->pwszName);
}
else
{
_tprintf(_T("%hs"), pSigAlgo->pszObjId);
}
}
}
Expanding on the answer of Anders. You can also get this information from the result of a call to WinVerifyTrust(). It is deeply nested inside CRYPT_PROVIDER_DATA:
GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_DATA trustData;
// omitted: prepare trustData
DWORD lStatus = ::WinVerifyTrust( NULL, &policyGUID, &trustData );
if( lStatus == ERROR_SUCCESS )
{
CRYPT_PROVIDER_DATA* pData = ::WTHelperProvDataFromStateData( trustData.hWVTStateData );
if( pData && pData->pPDSip && pData->pPDSip->psIndirectData &&
pData->pPDSip->psIndirectData->DigestAlgorithm.pszObjId )
{
CRYPT_ALGORITHM_IDENTIFIER const& sigAlgo = pData->pPDSip->psIndirectData->DigestAlgorithm;
PCCRYPT_OID_INFO pCOI = ::CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY, sigAlgo.pszObjId, 0 );
if(pCOI && pCOI->pwszName)
{
_tprintf(_T("%ls"), pCOI->pwszName);
}
else
{
_tprintf(_T("%hs"), sigAlgo.pszObjId);
}
}
}
Note: Detailed error checking omitted for brevity!
Note2: From Win 8 onwards (and patched Win 7), WinVerifyTrust can be used to verify and get information about multiple signatures of a file, more info in this Q&A.

Getting digital signature from mmc.exe at windows 8

I have an application that tries to verify the mmc.exe (services) signature. (the context of the application I think is irrelevant) I am trying with winapi function which both fails with
WinVerifyTrust. I get TRUST_E_BAD_DIGEST when I am trying with verification from catalog, and
TRUST_E_NOSIGNATURE when trying from file info. it is very important to mention that my function succeeds on win7, XP but fails on win8.
this is the code snippet for the function
CATALOG_INFO InfoStruct = {0};
InfoStruct.cbStruct = sizeof(CATALOG_INFO);
WINTRUST_CATALOG_INFO WintrustCatalogStructure = {0};
WintrustCatalogStructure.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
WINTRUST_FILE_INFO WintrustFileStructure = {0};
WintrustFileStructure.cbStruct = sizeof(WINTRUST_FILE_INFO);
GUID ActionGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
//Get a context for signature verification.
HCATADMIN Context = NULL;
if(!::CryptCATAdminAcquireContext(&Context, NULL, 0) ){
return false;
}
//Open file.
cx_handle hFile(::CreateFileW(filename_.c_str(), GENERIC_READ, 7, NULL, OPEN_EXISTING, 0, NULL));
if( INVALID_HANDLE_VALUE == (HANDLE)hFile )
{
CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Get the size we need for our hash.
DWORD HashSize = 0;
::CryptCATAdminCalcHashFromFileHandle(hFile, &HashSize, NULL, 0);
if( HashSize == 0 )
{
//0-sized has means error!
::CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Allocate memory.
buffer hashbuf(HashSize);
//Actually calculate the hash
if( !CryptCATAdminCalcHashFromFileHandle(hFile, &HashSize, hashbuf.data, 0) )
{
CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Convert the hash to a string.
buffer MemberTag(((HashSize * 2) + 1) * sizeof(wchar_t));
for( unsigned int i = 0; i < HashSize; i++ ){
swprintf(&((PWCHAR)MemberTag.data)[i * 2], L"%02X", hashbuf.data[i ]);
}
//Get catalog for our context.
HCATINFO CatalogContext = CryptCATAdminEnumCatalogFromHash(Context, hashbuf, HashSize, 0, NULL);
if ( CatalogContext )
{
//If we couldn't get information
if ( !CryptCATCatalogInfoFromContext(CatalogContext, &InfoStruct, 0) )
{
//Release the context and set the context to null so it gets picked up below.
CryptCATAdminReleaseCatalogContext(Context, CatalogContext, 0);
CatalogContext = NULL;
}
}
//If we have a valid context, we got our info.
//Otherwise, we attempt to verify the internal signature.
WINTRUST_DATA WintrustStructure = {0};
WintrustStructure.cbStruct = sizeof(WINTRUST_DATA);
if( !CatalogContext )
{
load_signature_verification_from_file_info(WintrustFileStructure, WintrustStructure);
}
else
{
load_signature_verification_from_catalog(WintrustStructure, WintrustCatalogStructure, InfoStruct, MemberTag);
}
//Call our verification function.
long verification_res = ::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
//Check return.
bool is_success = SUCCEEDED(verification_res) ? true : false;
// if failed with CatalogContext, try with FILE_INFO
if(!is_success && CatalogContext && verification_res != TRUST_E_NOSIGNATURE)
{
//warning2(L"Failed verification with Catalog Context: 0x%x %s ; Retrying with FILE_INFO.", verification_res, (const wchar_t*)format_last_error(verification_res));
load_signature_verification_from_file_info(WintrustFileStructure, WintrustStructure);
verification_res = ::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
is_success = SUCCEEDED(verification_res) ? true : false;
}
if(perr && !is_success && verification_res != TRUST_E_NOSIGNATURE)
{
perr->code = verification_res;
perr->description = format_last_error(verification_res);
}
//Free context.
if( CatalogContext ){
::CryptCATAdminReleaseCatalogContext(Context, CatalogContext, 0);
}
//If we successfully verified, we need to free.
if( is_success )
{
WintrustStructure.dwStateAction = WTD_STATEACTION_CLOSE;
::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
}
::CryptCATAdminReleaseContext(Context, 0);
return is_success;
I don't think any thing had changed in this function from win7 to win 8 so what could possibly go wrong?
UPDATE
I did notice that my function does work for task manager at win 8.
but again for the mmc it does not work.
It appears that your general approach is correct and the functions themselves haven't changed. However there are subtle changes; namely the data on which they operate has changed. The hashes stored for files on Windows 8, according to comments on CryptCATAdminCalcHashFromFileHandle, are calculated using SHA-256 hashes.
The SHA-256 hashing algorithm is not supported by CryptCATAdminCalcHashFromFileHandle, so you must update the code to use CryptCATAdminAcquireContext2 and CryptCATAdminCalcHashFromFileHandle2 on Windows 8; the former allows you to acquire a HCATADMIN with a specified hash algorithm, and the latter allows using that HCATADMIN.
(Interestingly, WINTRUST_CATALOG_INFO also points this direction with its HCATADMIN hCatAdmin member, documented as "Windows 8 and Windows Server 2012: Support for this member begins.")

How to commit to a git repository using libgit2?

Since there is no copy-paste example for creating a commit without using files on disk with libgit2 as far as I can tell I thought I should add one.
Don't forget that libgit2 is in full development at this time (March 2013) so have a look at official documentation and source code, as new features are added daily:
libgit2 API
headers are very well commented - here's an example
extensive tests may be a source of inspiration
there are some official examples, general.c is a good place to start
inspiration may be found in LibGit2Sharp - here are some tests
bool addGitCommit (
git_repository * repo, git_signature * sign,
const char * content, int content_sz,
const char * message )
{
int rc; /* return code for git_ functions */
git_oid oid_blob; /* the SHA1 for our blob in the tree */
git_oid oid_tree; /* the SHA1 for our tree in the commit */
git_oid oid_commit; /* the SHA1 for our initial commit */
git_blob * blob; /* our blob in the tree */
git_tree * tree_cmt; /* our tree in the commit */
git_treebuilder * tree_bld; /* tree builder */
bool b = false;
/* create a blob from our buffer */
rc = git_blob_create_frombuffer(
&oid_blob,
repo,
content,
content_sz );
if ( rc == 0 ) { /* blob created */
rc = git_blob_lookup( &blob, repo, &oid_blob );
if ( rc == 0 ) { /* blob created and found */
rc = git_treebuilder_create( &tree_bld, NULL );
if ( rc == 0 ) { /* a new tree builder created */
rc = git_treebuilder_insert(
NULL,
tree_bld,
"name-of-the-file.txt",
&oid_blob,
GIT_FILEMODE_BLOB );
if ( rc == 0 ) { /* blob inserted in tree */
rc = git_treebuilder_write(
&oid_tree,
repo,
tree_bld );
if ( rc == 0 ) { /* the tree was written to the database */
rc = git_tree_lookup(
&tree_cmt, repo, &oid_tree );
if ( rc == 0 ) { /*we've got the tree pointer */
rc = git_commit_create(
&oid_commit, repo, "HEAD",
sign, sign, /* same author and commiter */
NULL, /* default UTF-8 encoding */
message,
tree_cmt, 0, NULL );
if ( rc == 0 ) {
b = true;
}
git_tree_free( tree_cmt );
}
}
}
git_treebuilder_free( tree_bld );
}
git_blob_free( blob );
}
}
return b;
}
The repository comes from git_repository_init() or git_repository_open().
The signature comes from git_signature_now() or git_signature_new().
The function updates the HEAD for current branch.
If you do a git status after the function executes you will notice that the file name-of-the-file.txt appears as being deleted. That is because the function does not create an actual file, only an entry in the git database.
Also, note the last arguments of git_commit_create(). 0 and NULL means that this is the first (root) commit. For all other there should be at least a parent commit specified, maybe obtained using git_commit_lookup().
I'm just learning these things. Please improve this answer if you know better.

HDF5 :Create a Dataset with string

I am using HDF5 API and I am trying to create a dataset with variable-length string.
The struct is
struct dataX
{
std::string data;
};
I was using char[256] with a static hard coded size.
But I want it to be dynamic so after reading the HDF5 Doc, I found H5T_VARIABLE and used it as follows but it still fails.
H5Dcreate returns a negative value (means error).
hid_t mem_type;
mem_type = H5Tcopy( H5T_C_S1 );
H5Tset_size(mem_type,H5T_VARIABLE);
/* Create the memory data type. */
if ((mem_type_id = H5Tcreate (H5T_COMPOUND, mem_type )) < 0 ) {
return -1;
}
/* Insert fields. */
if ( H5Tinsert(mem_type_id, "field", 0, mem_type_id ) < 0 ) {
return -1;
}
/* Create a simple data space with unlimited size */
// hsize_t dims[1]={0};
// hsize_t maxdimsk[1]={ H5S_UNLIMITED };
if ( (sid = H5Screate_simple( 1, dims, maxdims )) < 0 ){
return -1;
}
/* Modify dataset creation properties, i.e. enable chunking */
plist_id = H5Pcreate (H5P_DATASET_CREATE);
//chunk==1
if ( H5Pset_chunk ( plist_id, 1, chunk ) < 0 ){
return -1;
}
H5Pset_alloc_time( plist_id, H5D_ALLOC_TIME_EARLY )
/* Set the fill value using a struct as the data type. */
// fill_data=0
if ( fill_data )
{
if ( H5Pset_fill_value( plist_id, mem_type_id, fill_data ) < 0 ){
LOG_ERROR << "cannot fill value " << LOG_ENDL;
return -1;
}
}
else {
if ( H5Pset_fill_time( plist_id, H5D_FILL_TIME_NEVER ) < 0 ) {
LOG_ERROR << "error" << LOG_ENDL;
}
}
/* Create the dataset. */
did = H5Dcreate( loc_id, dset_name, mem_type_id, sid, plist_id )
I tried H5D_ALLOC_TIME_LATE, thinking that maybe if it allocated the memory just before writing it would work but ... it didn't.
Now I'm stuck and I don't know what to do.
Did I miss something ?
Your mem_type_id doubly invalid:
the second argument of H5Tcreate should be the size of the compound datatype
in H5Tinsert, the last argument should be the datatype of the inserted field. Here I guess you meant mem_type instead of mem_type_id.
I don't know anything about what you are doing in particular, but to write variable length string, you do not need to create a compound type nor to set any special property lists. Basically your 3 first line are enough to create a valid variable-length string datatype (mem_type). Then you create the simple dataspace, then the dataset.
Have a look at this example, you will see it's pretty simple.

Why would GLU crash at this spot?

I have found that my application crashes with a null reference exception right here in sweep.c in GLU source code:
static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
/*
* Purpose: connect a "left" vertex (one where both edges go right)
* to the processed portion of the mesh. Let R be the active region
* containing vEvent, and let U and L be the upper and lower edge
* chains of R. There are two possibilities:
*
* - the normal case: split R into two regions, by connecting vEvent to
* the rightmost vertex of U or L lying to the left of the sweep line
*
* - the degenerate case: if vEvent is close enough to U or L, we
* merge vEvent into that edge chain. The subcases are:
* - merging with the rightmost vertex of U or L
* - merging with the active edge of U or L
* - merging with an already-processed portion of U or L
*/
{
ActiveRegion *regUp, *regLo, *reg;
GLUhalfEdge *eUp, *eLo, *eNew;
ActiveRegion tmp;
/* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */
/* Get a pointer to the active region containing vEvent */
tmp.eUp = vEvent->anEdge->Sym;
/* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
regLo = RegionBelow( regUp );
eUp = regUp->eUp;
eLo = regLo->eUp; //CRASHES RIGHT HERE SINCE RegLo is = 0x000000 FOR SOME REASON
/* Try merging with U or L first */
if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
ConnectLeftDegenerate( tess, regUp, vEvent );
return;
}
/* Connect vEvent to rightmost processed vertex of either chain.
* e->Dst is the vertex that we will connect to vEvent.
*/
reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
if( regUp->inside || reg->fixUpperEdge) {
if( reg == regUp ) {
eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
if (eNew == NULL) longjmp(tess->env,1);
} else {
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
if (tempHalfEdge == NULL) longjmp(tess->env,1);
eNew = tempHalfEdge->Sym;
}
if( reg->fixUpperEdge ) {
if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
} else {
ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
}
SweepEvent( tess, vEvent );
} else {
/* The new vertex is in a region which does not belong to the polygon.
* We don''t need to connect this vertex to the rest of the mesh.
*/
AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
}
}
It seems as though eRegLo is a NULL pointer sometimes which causes my application to crash. How could I modify the source to prevent it from crashing my application?
Thanks
You will have to look into the source for RegionBelow and see if and when it can return a NULL pointer. Between your call to RegionBelow and your de-reference of regLo, perform a regLo == NULL check. You can do this with an assert or by throwing an exception (in C++). Most likely, if RegionBelow can return NULL on error, there will be some other method that you can use to determine what the error was and how to handle it. You will have to consult the source code or documentation for RegionBelow to find that information.