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 vertex
ch = 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 bytes
if (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;
}
void
changestoreinit(struct changestore *s, size_t cap)
{
s->entries = xmalloc(sizeof(struct changeentry) * cap);
s->cap = cap;
s->len = 0;
}
void
changestorefree(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 int
loadchange(
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.
*/
int
change(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);