jcs
/amend
/amendments
/87
repo: Factor out amendment marshalling
I wish I could use bile's marshalling for this, but the current
on-disk format of things is weird in Amend and would require a
database upgrade to convert to bile's way of storing variable-length
fields.
Start on renaming commit to amendment.
jcs made amendment 87 over 2 years ago
--- repo.c Tue Aug 16 14:38:02 2022
+++ repo.c Wed Aug 17 14:23:09 2022
@@ -26,12 +26,12 @@
struct repo * repo_init(struct bile *bile, short is_new);
void repo_sort_files(struct repo *repo);
-void repo_sort_commits(struct repo *repo);
+void repo_sort_amendments(struct repo *repo);
short repo_get_file_attrs(struct repo *repo, Str255 filename,
struct repo_file_attrs *attrs);
short repo_file_update(struct repo *repo, struct repo_file *file);
unsigned short repo_diff_header(struct repo *repo,
- struct repo_commit *commit, char **ret);
+ struct repo_amendment *amendment, char **ret);
short repo_migrate(struct repo *repo, short is_new);
pascal Boolean repo_add_file_filter(struct FileParam *pbp);
@@ -103,6 +103,7 @@ repo_init(struct bile *bile, short is_new)
Str255 buf;
struct bile_object *bob;
struct repo *repo;
+ struct repo_file *file;
size_t size;
char *data;
short error, fh;
@@ -111,7 +112,7 @@ repo_init(struct bile *bile, short is_new)
repo = xmalloczero(sizeof(struct repo));
repo->bile = bile;
repo->next_file_id = 1;
- repo->next_commit_id = 1;
+ repo->next_amendment_id = 1;
if (repo_migrate(repo, is_new) != 0) {
free(repo);
@@ -129,36 +130,37 @@ repo_init(struct bile *bile, short is_new)
size = bile_read_alloc(bile, REPO_FILE_RTYPE, bob->id, &data);
if (size == 0)
panic("failed fetching file %ld", bob->id);
+ repo->files[i] = xmalloczero(sizeof(struct repo_file));
repo->files[i] = repo_parse_file(bob->id, (unsigned char *)data,
size);
- if (repo->files[i]->id >= repo->next_file_id)
- repo->next_file_id = repo->files[i]->id + 1;
+ if (repo->files[i]->id >= repo->next_file_id)
+ repo->next_file_id = repo->files[i]->id + 1;
free(data);
}
}
repo_sort_files(repo);
- /* fill in commit info */
- repo->ncommits = bile_count_by_type(bile, REPO_COMMIT_RTYPE);
- if (repo->ncommits) {
- repo->commits = xmalloc(repo->ncommits * sizeof(Ptr));
- for (i = 0; i < repo->ncommits; i++) {
- bob = bile_get_nth_of_type(bile, i, REPO_COMMIT_RTYPE);
+ /* fill in amendment info */
+ repo->namendments = bile_count_by_type(bile, REPO_AMENDMENT_RTYPE);
+ if (repo->namendments) {
+ repo->amendments = xmalloc(repo->namendments * sizeof(Ptr));
+ for (i = 0; i < repo->namendments; i++) {
+ bob = bile_get_nth_of_type(bile, i, REPO_AMENDMENT_RTYPE);
if (bob == NULL)
- panic("no %ld commit, but count said it should be there",
+ panic("no %ld amendment, but count said it should be there",
i);
- size = bile_read_alloc(bile, REPO_COMMIT_RTYPE, bob->id,
+ size = bile_read_alloc(bile, REPO_AMENDMENT_RTYPE, bob->id,
&data);
if (size == 0)
- panic("failed fetching commit %ld", bob->id);
- repo->commits[i] = repo_parse_commit(bob->id,
+ panic("failed fetching amendment %ld", bob->id);
+ repo->amendments[i] = repo_parse_amendment(bob->id,
(unsigned char *)data, size);
- if (repo->commits[i]->id >= repo->next_commit_id)
- repo->next_commit_id = repo->commits[i]->id + 1;
+ if (repo->amendments[i]->id >= repo->next_amendment_id)
+ repo->next_amendment_id = repo->amendments[i]->id + 1;
free(data);
}
}
- repo_sort_commits(repo);
+ repo_sort_amendments(repo);
return repo;
}
@@ -167,24 +169,24 @@ void
repo_close(struct repo *repo)
{
struct repo_file *file;
- struct repo_commit *commit;
+ struct repo_amendment *amendment;
Handle h;
short i;
- for (i = 0; i < repo->ncommits; i++) {
- commit = repo->commits[i];
- if (commit == NULL)
+ for (i = 0; i < repo->namendments; i++) {
+ amendment = repo->amendments[i];
+ if (amendment == NULL)
continue;
- if (commit->log != NULL)
- DisposHandle(commit->log);
+ if (amendment->log != NULL)
+ DisposHandle(amendment->log);
- if (commit->file_ids != NULL)
- free(commit->file_ids);
+ if (amendment->file_ids != NULL)
+ free(amendment->file_ids);
- free(commit);
+ free(amendment);
}
- free(repo->commits);
+ free(repo->amendments);
for (i = 0; i < repo->nfiles; i++) {
file = repo->files[i];
@@ -248,18 +250,18 @@ repo_parse_file(unsigned long id, unsigned char *data,
return file;
}
-struct repo_commit *
-repo_parse_commit(unsigned long id, unsigned char *data, size_t size)
+struct repo_amendment *
+repo_parse_amendment(unsigned long id, unsigned char *data, size_t size)
{
- struct repo_commit *commit;
+ struct repo_amendment *amendment;
unsigned short len, i;
short datapos;
- commit = xmalloczero(sizeof(struct repo_commit));
- commit->id = id;
+ amendment = xmalloczero(sizeof(struct repo_amendment));
+ amendment->id = id;
/* date */
- commit->date = ((unsigned long)data[0] << 24) |
+ amendment->date = ((unsigned long)data[0] << 24) |
((unsigned long)data[1] << 16) |
((unsigned long)data[2] << 8) |
((unsigned long)data[3]);
@@ -267,46 +269,46 @@ repo_parse_commit(unsigned long id, unsigned char *dat
/* author, pstr */
len = data[0];
- if (len > sizeof(commit->author) - 1)
- len = sizeof(commit->author) - 1;
- memcpy(commit->author, data + 1, len);
- commit->author[len] = '\0';
+ if (len > sizeof(amendment->author) - 1)
+ len = sizeof(amendment->author) - 1;
+ memcpy(amendment->author, data + 1, len);
+ amendment->author[len] = '\0';
data += (data[0] + 1);
/* files, short */
- commit->nfiles = (data[0] << 8) | data[1];
+ amendment->nfiles = (data[0] << 8) | data[1];
data += 2;
- if (commit->nfiles) {
- commit->file_ids = xmalloc(sizeof(short) * commit->nfiles);
- for (i = 0; i < commit->nfiles; i++) {
- commit->file_ids[i] = (data[0] << 8) | data[1];
+ if (amendment->nfiles) {
+ amendment->file_ids = xmalloc(sizeof(short) * amendment->nfiles);
+ for (i = 0; i < amendment->nfiles; i++) {
+ amendment->file_ids[i] = (data[0] << 8) | data[1];
data += 2;
}
}
/* additions, short */
- commit->adds = (data[0] << 8) | data[1];
+ amendment->adds = (data[0] << 8) | data[1];
data += 2;
/* subs, short */
- commit->subs = (data[0] << 8) | data[1];
+ amendment->subs = (data[0] << 8) | data[1];
data += 2;
/* log message, word-length */
len = (data[0] << 8) | data[1];
data += 2;
- commit->log = xNewHandle(len + 1);
- commit->log_len = len;
- HLock(commit->log);
- memcpy(*(commit->log), data, len);
- (*(commit->log))[len] = '\0';
- HUnlock(commit->log);
+ amendment->log = xNewHandle(len + 1);
+ amendment->log_len = len;
+ HLock(amendment->log);
+ memcpy(*(amendment->log), data, len);
+ (*(amendment->log))[len] = '\0';
+ HUnlock(amendment->log);
data += len;
/* TODO: use datapos and check against size like repo_parse_file */
- return commit;
+ return amendment;
}
struct repo_file *
@@ -322,34 +324,34 @@ repo_file_with_id(struct repo *repo, short id)
}
unsigned short
-repo_diff_header(struct repo *repo, struct repo_commit *commit,
+repo_diff_header(struct repo *repo, struct repo_amendment *amendment,
char **ret)
{
struct tm *ttm = NULL;
unsigned short header_len;
short i;
- *ret = xmalloc(128 + commit->log_len);
- ttm = localtime(&commit->date);
+ *ret = xmalloc(128 + amendment->log_len);
+ ttm = localtime(&amendment->date);
header_len = sprintf(*ret,
"Author: %s\r"
"Date: %04d-%02d-%02d %02d:%02d:%02d\r"
"\r ",
- commit->author,
+ amendment->author,
ttm->tm_year + 1900, ttm->tm_mon + 1, ttm->tm_mday,
ttm->tm_hour, ttm->tm_min, ttm->tm_sec);
/* copy log, indenting each line */
- HLock(commit->log);
- for (i = 0; i < commit->log_len; i++) {
- *(*ret + header_len++) = (*(commit->log))[i];
+ HLock(amendment->log);
+ for (i = 0; i < amendment->log_len; i++) {
+ *(*ret + header_len++) = (*(amendment->log))[i];
- if ((*(commit->log))[i] == '\r' && i < commit->log_len - 1) {
+ if ((*(amendment->log))[i] == '\r' && i < amendment->log_len - 1) {
*(*ret + header_len++) = ' ';
*(*ret + header_len++) = ' ';
}
}
- HUnlock(commit->log);
+ HUnlock(amendment->log);
*(*ret + header_len++) = '\r';
*(*ret + header_len++) = '\r';
@@ -357,7 +359,7 @@ repo_diff_header(struct repo *repo, struct repo_commit
}
void
-repo_show_diff_text(struct repo *repo, struct repo_commit *commit,
+repo_show_diff_text(struct repo *repo, struct repo_amendment *amendment,
TEHandle te)
{
char truncbuf[64];
@@ -372,9 +374,9 @@ repo_show_diff_text(struct repo *repo, struct repo_com
TESetText("", 0, te);
- bob = bile_find(repo->bile, REPO_DIFF_RTYPE, commit->id);
+ bob = bile_find(repo->bile, REPO_DIFF_RTYPE, amendment->id);
if (bob == NULL) {
- warn("Failed finding DIFF %d, corrupted repo?", commit->id);
+ warn("Failed finding DIFF %d, corrupted repo?", amendment->id);
return;
}
@@ -382,7 +384,7 @@ repo_show_diff_text(struct repo *repo, struct repo_com
if (diff_len == 0)
panic("diff zero bytes");
- header_len = repo_diff_header(repo, commit, &buf);
+ header_len = repo_diff_header(repo, amendment, &buf);
all_len = header_len + diff_len;
if (all_len >= MAX_TEXTEDIT_SIZE) {
@@ -397,7 +399,7 @@ repo_show_diff_text(struct repo *repo, struct repo_com
size = bile_read_object(repo->bile, bob, dtext + header_len,
all_len - header_len);
if (size == 0)
- panic("failed reading diff %lu: %d", commit->id,
+ panic("failed reading diff %lu: %d", amendment->id,
bile_error(repo->bile));
if (trunc) {
@@ -698,18 +700,18 @@ repo_sort_files(struct repo *repo)
}
void
-repo_sort_commits(struct repo *repo)
+repo_sort_amendments(struct repo *repo)
{
- struct repo_commit *commit;
+ struct repo_amendment *amendment;
short i, j;
- /* reverse order, newest commit first */
- for (i = 0; i < repo->ncommits; i++) {
- for (j = 0; j < repo->ncommits - i - 1; j++) {
- if (repo->commits[j]->id < repo->commits[j + 1]->id) {
- commit = repo->commits[j];
- repo->commits[j] = repo->commits[j + 1];
- repo->commits[j + 1] = commit;
+ /* reverse order, newest amendment first */
+ for (i = 0; i < repo->namendments; i++) {
+ for (j = 0; j < repo->namendments - i - 1; j++) {
+ if (repo->amendments[j]->id < repo->amendments[j + 1]->id) {
+ amendment = repo->amendments[j];
+ repo->amendments[j] = repo->amendments[j + 1];
+ repo->amendments[j + 1] = amendment;
}
}
}
@@ -872,7 +874,7 @@ repo_file_changed(struct repo *repo, struct repo_file
}
void
-repo_export_patch(struct repo *repo, struct repo_commit *commit,
+repo_export_patch(struct repo *repo, struct repo_amendment *amendment,
short vrefnum, Str255 filename)
{
struct bile_object *bob;
@@ -880,9 +882,9 @@ repo_export_patch(struct repo *repo, struct repo_commi
char *buf = NULL;
short error, frefnum, header_len;
- bob = bile_find(repo->bile, REPO_DIFF_RTYPE, commit->id);
+ bob = bile_find(repo->bile, REPO_DIFF_RTYPE, amendment->id);
if (bob == NULL)
- panic("failed finding DIFF %d", commit->id);
+ panic("failed finding DIFF %d", amendment->id);
/*
* Don't use our creator here because we don't want finder opening us
@@ -904,7 +906,7 @@ repo_export_patch(struct repo *repo, struct repo_commi
panic("Failed to truncate file %s: %d", PtoCstr(filename),
error);
- size = repo_diff_header(repo, commit, &buf);
+ size = repo_diff_header(repo, amendment, &buf);
error = FSWrite(frefnum, &size, buf);
if (error)
panic("Failed to write diff header to %s: %d", PtoCstr(filename),
@@ -923,105 +925,70 @@ repo_export_patch(struct repo *repo, struct repo_commi
}
void
-repo_commit(struct repo *repo, struct diffed_file *diffed_files,
+repo_amend(struct repo *repo, struct diffed_file *diffed_files,
short nfiles, short adds, short subs, char *author, Handle log,
short loglen, Handle diff, unsigned long difflen)
{
Str255 tfilename;
- unsigned char *commit, *tdata, *fdata;
+ struct repo_amendment *amendment;
+ unsigned long datalen, fsize;
+ unsigned char *tdata, *fdata;
+ char *amendment_data;
FInfo finfo;
size_t size;
- short commit_len, pos = 0, len;
- short i, commit_id, id, error, frefnum, actual_nfiles;
- time_t date;
- long fsize;
+ short i, id, error, frefnum;
- /* date (long) */
- commit_len = sizeof(long);
-
- /* author (pstr) */
- commit_len += 1 + strlen(author);
+ amendment = xmalloczero(sizeof(struct repo_amendment));
+ amendment->id = repo->next_amendment_id;
+ amendment->date = Time;
/* find files with actual data changes */
- actual_nfiles = 0;
+ amendment->nfiles = 0;
+ amendment->file_ids = xcalloc(sizeof(short), nfiles);
for (i = 0; i < nfiles; i++) {
- if (diffed_files[i].flags & DIFFED_FILE_TEXT)
- actual_nfiles++;
+ if (diffed_files[i].flags & DIFFED_FILE_TEXT) {
+ amendment->file_ids[amendment->nfiles] =
+ diffed_files[i].file->id;
+ amendment->nfiles++;
+ }
}
- if (actual_nfiles == 0)
- panic("repo_commit passed nfiles %d but actual files is 0", nfiles);
+ if (amendment->nfiles == 0)
+ panic("repo_amendment passed nfiles %d but actual files is 0",
+ nfiles);
- /* nfiles (short) */
- commit_len += sizeof(short) + (actual_nfiles * sizeof(short));
+ strlcpy(amendment->author, author, sizeof(amendment->author));
+ amendment->adds = adds;
+ amendment->subs = subs;
- /* adds (short) */
- commit_len += sizeof(short);
-
- /* deletions (short) */
- commit_len += sizeof(short);
-
- /* log (wstr) */
- commit_len += sizeof(short) + loglen;
-
- commit = xmalloc(commit_len);
-
- date = Time;
- commit[pos++] = (date >> 24) & 0xff;
- commit[pos++] = (date >> 16) & 0xff;
- commit[pos++] = (date >> 8) & 0xff;
- commit[pos++] = date & 0xff;
-
- commit[pos++] = strlen(author);
- for (i = 0; i < strlen(author); i++)
- commit[pos++] = author[i];
-
- commit[pos++] = (actual_nfiles >> 8) & 0xff;
- commit[pos++] = actual_nfiles & 0xff;
- for (i = 0; i < nfiles; i++) {
- if (!(diffed_files[i].flags & DIFFED_FILE_TEXT))
- continue;
-
- commit[pos++] = (diffed_files[i].file->id >> 8) & 0xff;
- commit[pos++] = diffed_files[i].file->id & 0xff;
- }
-
- commit[pos++] = (adds >> 8) & 0xff;
- commit[pos++] = adds & 0xff;
-
- commit[pos++] = (subs >> 8) & 0xff;
- commit[pos++] = subs & 0xff;
-
+ /* caller expects to be able to free their version, so make our own */
+ amendment->log_len = loglen;
+ amendment->log = xNewHandle(loglen);
HLock(log);
- commit[pos++] = (loglen >> 8) & 0xff;
- commit[pos++] = loglen & 0xff;
- memcpy(commit + pos, *log, loglen);
- pos += loglen;
+ HLock(amendment->log);
+ memcpy(*(amendment->log), *log, loglen);
+ HUnlock(amendment->log);
HUnlock(log);
- if (pos != commit_len)
- panic("repo_commit: accumulated len %d != expected %d", pos,
- commit_len);
+ repo_marshall_amendment(amendment, &amendment_data, &datalen);
- commit_id = repo->next_commit_id;
-
/* store diff */
HLock(diff);
progress("Storing diff...");
- size = bile_write(repo->bile, REPO_DIFF_RTYPE, commit_id, *diff,
+ size = bile_write(repo->bile, REPO_DIFF_RTYPE, amendment->id, *diff,
difflen);
if (size != difflen)
panic("Failed storing diff in repo file: %d",
bile_error(repo->bile));
HUnlock(diff);
- /* store commit */
- progress("Storing commit metadata...");
- size = bile_write(repo->bile, REPO_COMMIT_RTYPE, commit_id, commit,
- commit_len);
- if (size != commit_len)
- panic("Failed storing commit in repo file: %d",
+ /* store amendment */
+ progress("Storing amendment metadata...");
+ size = bile_write(repo->bile, REPO_AMENDMENT_RTYPE, amendment->id,
+ amendment_data, datalen);
+ if (size != datalen)
+ panic("Failed storing amendment in repo file: %d",
bile_error(repo->bile));
- /* used later, don't free yet */
+ free(amendment_data);
/* store new versions of each file */
for (i = 0; i < nfiles; i++) {
@@ -1072,18 +1039,82 @@ repo_commit(struct repo *repo, struct diffed_file *dif
/* flush volume */
bile_flush(repo->bile, 1);
- repo->next_commit_id = commit_id + 1;
+ repo->next_amendment_id = amendment->id + 1;
- /* update commit list */
- repo->ncommits++;
- repo->commits = xreallocarray(repo->commits, repo->ncommits,
+ /* update amendment list */
+ repo->namendments++;
+ repo->amendments = xreallocarray(repo->amendments, repo->namendments,
sizeof(Ptr));
- repo->commits[repo->ncommits - 1] = repo_parse_commit(commit_id,
- commit, commit_len);
+ repo->amendments[repo->namendments - 1] = amendment;
- free(commit);
+ repo_sort_amendments(repo);
+}
- repo_sort_commits(repo);
+void
+repo_marshall_amendment(struct repo_amendment *amendment, char **retdata,
+ unsigned long *retlen)
+{
+ unsigned short len, pos = 0;
+ char *data;
+ short i;
+ char clen;
+
+ /* date (long) */
+ len = sizeof(long);
+
+ /* author (pstr) */
+ len += 1 + strlen(amendment->author);
+
+ /* nfiles (short) */
+ len += sizeof(short) + (amendment->nfiles * sizeof(short));
+
+ /* adds (short) */
+ len += sizeof(short);
+
+ /* deletions (short) */
+ len += sizeof(short);
+
+ /* log (wstr) */
+ len += sizeof(short) + amendment->log_len;
+
+ *retdata = xmalloc(len);
+ data = *retdata;
+
+ data[pos++] = (amendment->date >> 24) & 0xff;
+ data[pos++] = (amendment->date >> 16) & 0xff;
+ data[pos++] = (amendment->date >> 8) & 0xff;
+ data[pos++] = amendment->date & 0xff;
+
+ clen = strlen(amendment->author);
+ data[pos++] = clen;
+ for (i = 0; i < clen; i++)
+ data[pos++] = amendment->author[i];
+
+ data[pos++] = (amendment->nfiles >> 8) & 0xff;
+ data[pos++] = amendment->nfiles & 0xff;
+ for (i = 0; i < amendment->nfiles; i++) {
+ data[pos++] = (amendment->file_ids[i] >> 8) & 0xff;
+ data[pos++] = amendment->file_ids[i] & 0xff;
+ }
+
+ data[pos++] = (amendment->adds >> 8) & 0xff;
+ data[pos++] = amendment->adds & 0xff;
+
+ data[pos++] = (amendment->subs >> 8) & 0xff;
+ data[pos++] = amendment->subs & 0xff;
+
+ HLock(amendment->log);
+ data[pos++] = (amendment->log_len >> 8) & 0xff;
+ data[pos++] = amendment->log_len & 0xff;
+ memcpy(data + pos, *(amendment->log), amendment->log_len);
+ pos += amendment->log_len;
+ HUnlock(amendment->log);
+
+ if (pos != len)
+ panic("repo_marshall_amendment: accumulated len %d != expected %d",
+ pos, len);
+
+ *retlen = len;
}
short
--- repo.h Wed Jun 15 10:39:56 2022
+++ repo.h Wed Aug 17 13:42:43 2022
@@ -25,7 +25,7 @@
#define REPO_TYPE 'AMRP'
#define REPO_FILE_RTYPE 'AFIL'
-#define REPO_COMMIT_RTYPE 'CMMT'
+#define REPO_AMENDMENT_RTYPE 'CMMT'
#define REPO_DIFF_RTYPE 'DIFF'
#define REPO_TEXT_RTYPE 'TEXT'
#define REPO_VERS_RTYPE 'RVER'
@@ -61,7 +61,7 @@ struct diffed_file {
#define DIFFED_FILE_METADATA (1 << 1)
};
-struct repo_commit {
+struct repo_amendment {
short id;
time_t date;
char author[32];
@@ -78,20 +78,20 @@ struct repo {
short nfiles;
struct repo_file **files;
short next_file_id;
- short ncommits;
- struct repo_commit **commits;
- short next_commit_id;
+ short namendments;
+ struct repo_amendment **amendments;
+ short next_amendment_id;
};
struct repo *repo_open(AppFile *file);
struct repo *repo_create(void);
void repo_close(struct repo *repo);
-struct repo_commit *repo_parse_commit(unsigned long id, unsigned char *data,
+struct repo_amendment *repo_parse_amendment(unsigned long id, unsigned char *data,
size_t size);
struct repo_file * repo_parse_file(unsigned long id, unsigned char *data,
size_t size);
struct repo_file *repo_file_with_id(struct repo *repo, short id);
-void repo_show_diff_text(struct repo *repo, struct repo_commit *commit,
+void repo_show_diff_text(struct repo *repo, struct repo_amendment *amendment,
TEHandle te);
struct repo_file *repo_add_file(struct repo *repo);
void repo_file_mark_for_deletion(struct repo *repo, struct repo_file *file);
@@ -99,11 +99,13 @@ short repo_diff_file(struct repo *repo, struct repo_fi
short repo_file_changed(struct repo *repo, struct repo_file *file);
short repo_checkout_file(struct repo *repo, struct repo_file *file,
short vrefnum, Str255 filename);
-void repo_export_patch(struct repo *repo, struct repo_commit *commit,
+void repo_export_patch(struct repo *repo, struct repo_amendment *amendment,
short vrefnum, Str255 filename);
-void repo_commit(struct repo *repo, struct diffed_file *diffed_files,
+void repo_amend(struct repo *repo, struct diffed_file *diffed_files,
short nfiles, short adds, short subs, char *author, Handle log,
short loglen, Handle diff, unsigned long difflen);
+void repo_marshall_amendment(struct repo_amendment *amendment,
+ char **retdata, unsigned long *retlen);
void repo_backup(struct repo *repo);
#endif