/* ** Clearsign the given blob. Put the signed version in ** pOut. */ int clearsign(Blob *pIn, Blob *pOut){ char *zRand; char *zIn; char *zOut; char *zBase = db_get("pgp-command", "gpg --clearsign -o "); char *zCmd; int rc; if( is_false(zBase) ){ return 0; } zRand = db_text(0, "SELECT hex(randomblob(10))"); zOut = mprintf("out-%s", zRand); zIn = mprintf("in-%z", zRand); blob_write_to_file(pIn, zOut); zCmd = mprintf("%s %s %s", zBase, zIn, zOut); rc = fossil_system(zCmd); free(zCmd); if( rc==0 ){ if( pOut==pIn ){ blob_reset(pIn); } blob_zero(pOut); blob_read_from_file(pOut, zIn); }else{ if( pOut!=pIn ){ blob_copy(pOut, pIn); } } file_delete(zOut); file_delete(zIn); free(zOut); free(zIn); return rc; }
/* ** Extract the content for ID rid and put it into the ** uninitialized blob. Return 1 on success. If the record ** is a phantom, zero pBlob and return 0. */ int content_get(int rid, Blob *pBlob){ int rc; int i; int nextRid; assert( g.repositoryOpen ); blob_zero(pBlob); if( rid==0 ) return 0; /* Early out if we know the content is not available */ if( bag_find(&contentCache.missing, rid) ){ return 0; } /* Look for the artifact in the cache first */ if( bag_find(&contentCache.inCache, rid) ){ for(i=0; i<contentCache.n; i++){ if( contentCache.a[i].rid==rid ){ blob_copy(pBlob, &contentCache.a[i].content); contentCache.a[i].age = contentCache.nextAge++; return 1; } } } nextRid = findSrcid(rid); if( nextRid==0 ){ rc = content_of_blob(rid, pBlob); }else{ int n = 1; int nAlloc = 10; int *a = 0; int mx; Blob delta, next; a = fossil_malloc( sizeof(a[0])*nAlloc ); a[0] = rid; a[1] = nextRid; n = 1; while( !bag_find(&contentCache.inCache, nextRid) && (nextRid = findSrcid(nextRid))>0 ){ n++; if( n>=nAlloc ){ if( n>db_int(0, "SELECT max(rid) FROM blob") ){ fossil_panic("infinite loop in DELTA table"); } nAlloc = nAlloc*2 + 10; a = fossil_realloc(a, nAlloc*sizeof(a[0])); } a[n] = nextRid; } mx = n; rc = content_get(a[n], pBlob); n--; while( rc && n>=0 ){ rc = content_of_blob(a[n], &delta); if( rc ){ blob_delta_apply(pBlob, &delta, &next); blob_reset(&delta); if( (mx-n)%8==0 ){ content_cache_insert(a[n+1], pBlob); }else{ blob_reset(pBlob); } *pBlob = next; } n--; } free(a); if( !rc ) blob_reset(pBlob); } if( rc==0 ){ bag_insert(&contentCache.missing, rid); }else{ bag_insert(&contentCache.available, rid); } return rc; }
/* ** Rebuild cross-referencing information for the artifact ** rid with content pBase and all of its descendants. This ** routine clears the content buffer before returning. ** ** If the zFNameFormat variable is set, then this routine is ** called to run "fossil deconstruct" instead of the usual ** "fossil rebuild". In that case, instead of rebuilding the ** cross-referencing information, write the file content out ** to the appropriate directory. ** ** In both cases, this routine automatically recurses to process ** other artifacts that are deltas off of the current artifact. ** This is the most efficient way to extract all of the original ** artifact content from the Fossil repository. */ static void rebuild_step(int rid, int size, Blob *pBase){ static Stmt q1; Bag children; Blob copy; Blob *pUse; int nChild, i, cid; while( rid>0 ){ /* Fix up the "blob.size" field if needed. */ if( size!=blob_size(pBase) ){ db_multi_exec( "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid ); } /* Find all children of artifact rid */ db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid"); db_bind_int(&q1, ":rid", rid); bag_init(&children); while( db_step(&q1)==SQLITE_ROW ){ int cid = db_column_int(&q1, 0); if( !bag_find(&bagDone, cid) ){ bag_insert(&children, cid); } } nChild = bag_count(&children); db_reset(&q1); /* Crosslink the artifact */ if( nChild==0 ){ pUse = pBase; }else{ blob_copy(©, pBase); pUse = © } if( zFNameFormat==0 ){ /* We are doing "fossil rebuild" */ manifest_crosslink(rid, pUse, MC_NONE); }else{ /* We are doing "fossil deconstruct" */ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength); blob_write_to_file(pUse,zFile); free(zFile); free(zUuid); blob_reset(pUse); } assert( blob_is_reset(pUse) ); rebuild_step_done(rid); /* Call all children recursively */ rid = 0; for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ static Stmt q2; int sz; db_static_prepare(&q2, "SELECT content, size FROM blob WHERE rid=:rid"); db_bind_int(&q2, ":rid", cid); if( db_step(&q2)==SQLITE_ROW && (sz = db_column_int(&q2,1))>=0 ){ Blob delta, next; db_ephemeral_blob(&q2, 0, &delta); blob_uncompress(&delta, &delta); blob_delta_apply(pBase, &delta, &next); blob_reset(&delta); db_reset(&q2); if( i<nChild ){ rebuild_step(cid, sz, &next); }else{ /* Tail recursion */ rid = cid; size = sz; blob_reset(pBase); *pBase = next; } }else{ db_reset(&q2); blob_reset(pBase); } } bag_clear(&children); } }