AmendHub

Download:

jcs

/

amend

/

amendments

/

39

repo: Implement a backup mechanism, backup the repo before committing

Unfortunately some bug in Amend can cause a crash during/after a
commit which corrupts the resource file, making it unusable :(

jcs made amendment 39 over 2 years ago
--- committer.c Thu Dec 16 17:20:00 2021 +++ committer.c Thu Dec 30 14:54:00 2021 @@ -486,6 +486,10 @@ committer_commit(struct committer *committer) loglen = (*(committer->log_te))->teLength; SetCursor(*(GetCursor(watchCursor))); + + committer_status("Backing up repo..."); + repo_backup(committer->browser->repo); + committer_status("Committing changes..."); repo_commit(committer->browser->repo, committer->diffed_files, --- repo.c Wed Dec 15 21:27:04 2021 +++ repo.c Thu Dec 30 16:47:41 2021 @@ -870,7 +870,7 @@ repo_commit(struct repo *repo, short *files, short nfi time_t date; long fsize; short i, commit_id, id, error, frefnum; - + /* date (long) */ commit_len = sizeof(long); @@ -1005,6 +1005,10 @@ repo_commit(struct repo *repo, short *files, short nfi repo_sort_commits(repo); UpdateResFile(repo->fh); + + if (FlushVol(nil, repo->vrefnum)) + warn("Failed flushing filesystem after committing, " + "proceed with caution"); } short @@ -1032,6 +1036,9 @@ repo_migrate(struct repo *repo, short is_new) return -1; } + if (!is_new) + repo_backup(repo); + /* per-version migrations */ if (ver == 1) { /* version 1 had no file flags */ @@ -1080,4 +1087,38 @@ repo_migrate(struct repo *repo, short is_new) UpdateResFile(repo->fh); return 0; -} +} + +void +repo_backup(struct repo *repo) +{ + Str255 source_filename, dest_filename; + FInfo fi; + short error; + char *path = NULL; + short source_ref, dest_ref; + + sprintf((char *)&source_filename, "%s", repo->filename); + CtoPstr(source_filename); + if (getpath(repo->vrefnum, source_filename, &path, false) != 0) + err(1, "Failed resolving path of open repo"); + + sprintf((char *)&source_filename, "%s:%s", path, repo->filename); + sprintf((char *)&dest_filename, "%s (backup)", source_filename); + CtoPstr(source_filename); + CtoPstr(dest_filename); + free(path); + + /* + * Tell copy_file to keep source open, which is our current resource + * file. Even though it calls OpenRFPerm and is supposed to get a new + * filehandle, it gets the same one as our resource file so closing it + * causes problems for us after copying. + */ + error = copy_file(source_filename, dest_filename, true, true); + if (error) + err(1, "Failed backing up repo: %d", error); + + if (FlushVol(nil, repo->vrefnum)) + err(1, "Failed flushing filesystem after backup, aborting"); +} --- repo.h Wed Dec 15 21:27:28 2021 +++ repo.h Thu Dec 30 14:49:23 2021 @@ -97,5 +97,6 @@ void repo_export_patch(struct repo *repo, struct repo_ void repo_commit(struct repo *repo, short *files, short nfiles, short adds, short subs, char *author, Handle log, short loglen, Handle diff, unsigned long difflen); +void repo_backup(struct repo *repo); #endif --- util.c Thu Dec 16 17:04:39 2021 +++ util.c Thu Dec 30 16:39:45 2021 @@ -513,6 +513,115 @@ is_dir(char *path) return false; } +OSErr +copy_file(Str255 source, Str255 dest, bool overwrite, + bool keep_source_open) +{ + FInfo fi; + short error, source_ref, dest_ref; + + /* copy data fork */ + + error = GetFInfo(source, 0, &fi); + if (error) + return error; + + error = Create(dest, 0, fi.fdCreator, fi.fdType); + if (error == dupFNErr && overwrite) { + error = FSDelete(dest, 0); + if (error) + return error; + error = Create(dest, 0, fi.fdCreator, fi.fdType); + } + if (error) + return error; + + error = FSOpen(source, 0, &source_ref); + if (error) + return error; + + error = FSOpen(dest, 0, &dest_ref); + if (error) { + if (!keep_source_open) + FSClose(source_ref); + return error; + } + + error = copy_file_contents(source_ref, dest_ref); + + if (!keep_source_open) + FSClose(source_ref); + FSClose(dest_ref); + + if (error) + return error; + + /* + * Copy resource fork, open source as shared read/write in case it's + * an open resource file. + */ + source_ref = OpenRFPerm(source, 0, fsRdWrShPerm); + if (source_ref == -1) + return ResError(); + + CreateResFile(dest); + if (ResError()) { + if (!keep_source_open) + FSClose(source_ref); + return ResError(); + } + error = OpenRF(dest, 0, &dest_ref); + if (error) { + if (!keep_source_open) + FSClose(source_ref); + return error; + } + + error = copy_file_contents(source_ref, dest_ref); + + if (!keep_source_open) + FSClose(source_ref); + FSClose(dest_ref); + + return error; +} + +OSErr +copy_file_contents(short source_ref, short dest_ref) +{ + char buf[512]; + short error; + long source_size, count; + + GetEOF(source_ref, &source_size); + error = SetFPos(source_ref, fsFromStart, 0); + if (error) + return error; + error = SetEOF(dest_ref, source_size); + if (error) + return error; + error = SetFPos(dest_ref, fsFromStart, 0); + if (error) + return error; + while (source_size > 0) { + count = sizeof(buf); + if (count > source_size) + count = source_size; + error = FSRead(source_ref, &count, &buf); + if (error && error != eofErr) + break; + source_size -= count; + error = FSWrite(dest_ref, &count, &buf); + if (error && error != eofErr) + break; + } + + if (error && error != eofErr) + return error; + + return 0; +} + /* read a \r-terminated line or the final non-line bytes of an open file */ OSErr FSReadLine(short frefnum, char *buf, size_t buflen) --- util.h Fri Nov 19 13:34:19 2021 +++ util.h Thu Dec 30 16:24:50 2021 @@ -88,6 +88,9 @@ pascal Boolean open_dialog_filter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit); bool is_dir(char *path); short stat(const char *path, struct stat *sb); +OSErr copy_file(Str255 source, Str255 dest, bool overwrite, + bool keep_source_open); +OSErr copy_file_contents(short source_ref, short dest_ref); OSErr FSReadLine(short frefnum, char *buf, size_t buflen); Handle SetResSize(Handle res, size_t size);