Introduce a changestore structure for keeping track of multiple changes.
The changestore is primarily needed to allow fetching contents from a change's dependencies (so we can print deleted lines). A changecontents() function is able to extract content bytes from dependent change files.
This change also begins the introduction of a lot of facilities for freeing resources in a more structured way. Using the changestore as an anchor point for all the allocated resources, we can navigate its structure and free everything that's been allocated at once.
5D2IYPL75HEP6JUEILEADSZRRSV72NECT6UQR3PORNDR35I2P5GQC WQSKMNHR73ZUU3FBTETABMO5F2KIKSDFICLJH7XEJXHUJ5HP3KXQC L3HKOF4WYZZLJJY2Q6YJ65WGAB74GQ2A7ICD23M5NQGBP4BXF6DQC LKIBESCNQSK63O7SARMBH4VPEXSIBT32TRPXPSC6Z7SMSOF73GMAC VXQYIOBXHTYEB62XSIAZGRNNIKXMDZLE5ANBGA7E7V3HOBVEMVSAC LPGHALLKCQRJUB7BNHABAG2VEEAFTUSN3WAPASM5B3V6JJ54GXJQC 7WA2F6RSQBGJJE5MZGQGAYJOWYEKQUWVI2MTZ4AMICEEQFENXANQC Y26WT3ZFN7KSVXOZ26B5Y2OR4M4VQYQLPMAHPC4O5VIT3ENBISXAC ZPNA2D42RFGGC45PLDYDGQUDPC7D4NBEH2HD4Y2L5P2CK3R52FAQC JVU3TTT5T776LB2UNT5DCISJDWOITRSJPRG3CDTX4NDQEHC5VI3QC JAGXXSR7DR5FG77VKBF62BW7Q3JMVHCLHF4VB2PSLIZF4RLE553QC QA7HY2THWTEZ2AQ4SINYGJKHHX4RFNZKA5LY4EDQCLVAVDZAZ2OQC YG4DZB3AW3Z3LB5CFBZZ4ORJOLZFN3G4CA2YTAMSUOQX3USVNVEAC XTVLIC243WZF52NVTNRA3SV3WLE2ZZ5GTFQOK45IOLMXYQMTLOSAC VKLGQREYOZDV46F672RFE5XJO3OEOP4EHTCWZYOJY24HVPQX3L6QC Q7TKZCJP2Z75EICZYKCEZDHKGERSOKZGMTSU3UXETBHTF663T66AC XTKRT6OQYN4LARQRDLI2KBSAJTOFZNT4AMBZ46CPUDZXD7IDYYWQC YDQLW2ZOAH7PZ7HHVTSFUO5IWE6O7FDNXVNIN7GG4TJ3P2B2BM4AC TGT4VSMEWWTFYILTXVZWA5WHB2RCZZYNGZJ3UUKZ5OPD6JQD4G5QC WFA5BBRFVUHJ53MOPZ2WDXZ4CEHKA32LDYERSYLVETIZTZDW22GAC NZNIG2ULNMS5Z3OWEKRVOPLFA6CWYNF47U7UMXNZFSX256F2ZZVAC NEORNIZEGPZAVZV2J6TTCWPZAQM3N7MH7SMS3NDT4WKTXI34NSUAC HKBM7HZGBH24UDVURTABIPF4P32AY6MDAZUDF3MWTXO7565BYWLQC N3PUHKQNA2Q5LRKTXHOZVG4LCDRKY5WAOEDSXS34KL27RZCSVHHAC QEFCNNVCEDFUV7O4ASWVI4QUTUFWLHAOTJMDCZ3DFJIUQWTAN3SAC RIWSVVASWLJQQTSVRHIIUPENOZWOMHQLZMTQVGJUS2ZUGDPSWWIQC 2U7P5SFQG3AVALKMPJF4WMZE6PXIXXZYOMZ3RZKILBUJ4UMFXVIAC DDLQMNGXZDIAK5ELYO5YYWKYKAZLH7FQ3L2J37MC2FOJEVDH6QDQC UPYQ5FMNFMZKEN5UZYE4TW5Y4CTJTKZD55NRVJP4CXU6MFDXT7VAC QYRJIOYPM7SAB3OHMALL67K44U5HPBRQ2AFNWUKATPXM6BUYRKBQC KDJUAAALIKZDRTVNUZKXYYA5UYMZNYBCI3CCRKS4YONBVRUADPXAC OBKF6SIIFFHHY7YWKPPX75N23NAVUD5662DKIHXSSIDPKKXQ5ZDQC 3FT3XTJMUAXQ257T5GB7YWWTI7QBKKVC7WA6DCH5UY26RLQO5PFQC WMFNGOYTKIZ7L25V3KMJPSWK23DTN6G3ESP6M55YIH6UTHFKL2XAC struct change {struct offsets offsets;struct hashed hashed;uint8_t *contents;};struct changeentry {size_t num;struct hash hash;struct change change;};/*** structure for keeping track of multiple changes*/struct changestore {size_t len;size_t cap;struct changeentry *entries;};void changestoreinit(struct changestore *, size_t cap);void changestorefree(struct changestore *);/*** either fetch a change that's already loaded, or load a change into* the changestore.*/struct change *changestoreget(struct changestore *, struct hash *);
}/*** Given an atom from a given change (by hash), extract the contents to return.** Returns a malloc()'ed buffer that must be free()'d, if there were* any contents to available. Returns NULL otherwise. The size of the* returned buffer is provided in the "n" parameter.*/static uint8_t *changecontents(struct changestore *changes, struct atom *change, uint8_t *contents,size_t *n){struct newvertex *v;struct edgemap *e;struct change *ch;uint8_t *buf = NULL;size_t sz = 0;switch (change->atomtype) {case NEW_VERTEX:v = &change->newvertex;sz = v->end - v->start;buf = xmalloc(sizeof(uint8_t) * sz);memcpy(buf, &contents[v->start], sz);break;case EDGE_MAP:e = &change->edgemap;if (e->edges.len == 0) {/* Technically an error */break;}if (!(e->edges.entries[0].flag & EDGE_FLAG_DELETED))break;for (size_t i = 0; i < e->edges.len; i++) {struct edge *edge = &e->edges.entries[i];// FIXME: need to keep track of current! see// /home/t/sources/pijul/pijul/libpijul/src/changestore/filesystem.rs (get_contents_ext)size_t z = edge->to.end - edge->to.start;/* TODO loop over the edges, extract relevant contents from the changestore */// keep track of current vertexch = changestoreget(changes, &edge->to.change);/* printf("changestoreget("); *//* hashprint(&edge->to.change); *//* printf(")"); *//* printf(" - %s\n", ch ? "ok" : "fail :-("); */// We find a change with some contents, and we// need to extract contents[start; end] we// then need to either xmalloc() buf, or// extend it to include more bytesif (ch) {if (buf) {buf = xrealloc(buf, sz + sizeof(uint8_t) * z);} else {buf = xmalloc(sizeof(uint8_t) * z);}memcpy(&buf[sz], &ch->contents[edge->to.start],z);sz += z;}}break;}*n = sz;return buf;
printf("edgemap {\n edges: [\n");for (i = 0; i < m->edges.len; i++) {struct edge *e = &m->edges.entries[i];printf(" edge { previous = %u, flag = ",e->previous);print_edgeflags(e->flag);printf(", from = Position { .. }, to = vertex { .. }, introducedby = ");hashprint(&e->introducedby);printf(" }\n");}printf(" ]\n}\n");
/* edgemap debugging *//* printf("edgemap {\n edges: [\n"); *//* for (i = 0; i < m->edges.len; i++) { *//* struct edge *e = &m->edges.entries[i]; *//* printf(" edge { previous = %u, flag = ", *//* e->previous); *//* print_edgeflags(e->flag); *//* printf(", from = position { change = "); *//* hashprint(&e->from.change); *//* printf(", pos = %lu }", e->from.pos); *//* printf(", to = vertex { change = "); *//* hashprint(&e->to.change); *//* printf(", start = %lu, end = %lu }, introducedby = ", *//* e->to.start, e->to.end); *//* hashprint(&e->introducedby); *//* printf(" }\n"); *//* } *//* printf(" ]\n}\n"); */res = changecontents(changes, a, contents, &n);if (res)printcontents(res, n, '-');
}}struct change *changestoreget(struct changestore *store, struct hash *hash){size_t i;for (i = 0; i < store->len; i++) {if (hasheq(hash, &store->entries[i].hash))return &store->entries[i].change;}return NULL;}voidchangestoreinit(struct changestore *s, size_t cap){s->entries = xmalloc(sizeof(struct changeentry) * cap);s->cap = cap;s->len = 0;}voidchangestorefree(struct changestore *s){size_t i;struct changeentry *e;struct change *c;/* Free all the entries first */for (i = 0; i < s->len; i++) {e = &s->entries[i];c = &e->change;hashedfree(&c->hashed);if (c->contents)free(c->contents);
int fd;int err;struct offsets off;uint8_t *contents;uint8_t contents_hash[32];char *h, *p;char chfile[PATH_MAX] = { 0 };struct hashed hashed;/* FIXME - make this a lot nicer... */
printf("Opening: %s\n", chfile);
static intloadchange(struct change *c, struct hash *hash, const char *repodir,const char *hashstr, int verbose){int fd, err;char chfile[PATH_MAX] = { 0 };struct offsets *off;struct hashed *hashed;uint8_t contents_hash[32];off = &c->offsets;hashed = &c->hashed;err = 0;printf("loading change %s\n", hashstr);formatchangepath(chfile, repodir, hashstr);
free(contents);out:close(fd);
/* FIXME consider that it might not only be blake3 bytes */base32_hashencode(hashstr, hash->bytes);return loadchange(c, h, repodir, hashstr, verbose);}/*** Takes an input hash, and tries to find a change file to open and read out.*/intchange(const char *hash, int verbose, const char *repodir){int err;struct changestore changestore = { 0 };struct changeentry *ch;size_t i, x;changestoreinit(&changestore, 32);ch = &changestore.entries[0];err = loadchange(&ch->change, &ch->hash, repodir, hash, verbose);if (err)return err;x = 1;changestore.len = 1;changestore.entries[0].num = 1;for (i = 0; i < ch->change.hashed.dependencies.len; i++) {err = loadchangeh(&changestore.entries[x].change,&changestore.entries[x].hash, repodir,&ch->change.hashed.dependencies.entries[i], verbose);if (err)goto changeout;changestore.len++;changestore.entries[x].num = ++x;}for (i = 0; i < ch->change.hashed.extraknown.len; i++) {err = loadchangeh(&changestore.entries[x].change,&changestore.entries[x].hash, repodir,&ch->change.hashed.extraknown.entries[i], verbose);if (err)goto changeout;changestore.len++;changestore.entries[x].num = ++x;}printf("x = %lu\n", x);print_change(&changestore, &ch->change.hashed, ch->change.contents);changeout:changestorefree(&changestore);