ref: 30794bba756772ada85b7642beddb42ffc416203
parent: 8f109ae113215166746b150a5a09b96050e62e52
author: Ori Bernstein <ori@eigenstate.org>
date: Tue Aug 2 23:13:00 EDT 2022
patch: apply patches atomically When applying a patch, we used to write out the patch, rename the file, and then move to the next one. This meant that if a patch failed to apply cleanly, we would leave the patch half-applied. This sucked, so we now apply the patch as a whole unit, or not at all.
--- a/sys/src/cmd/patch.c
+++ b/sys/src/cmd/patch.c
@@ -6,6 +6,7 @@
typedef struct Patch Patch;
typedef struct Hunk Hunk;
typedef struct Fbuf Fbuf;
+typedef struct Fchg Fchg;
struct Patch {
char *name;
@@ -39,10 +40,18 @@
int len;
};
+struct Fchg {
+ char *tmp;
+ char *old;
+ char *new;
+};
+
int strip;
int reverse;
void (*addnew)(Hunk*, char*);
void (*addold)(Hunk*, char*);
+Fchg *changed;
+int nchanged;
char*
readline(Biobuf *f, int *lnum)
@@ -398,15 +407,49 @@
sysfatal("open %s: %r", tmp);
if(write(fd, o, len) != len)
sysfatal("write %s: %r", tmp);
- if(strcmp(old, new) == 0 && remove(old) == -1)
- sysfatal("remove %s: %r", old);
- if(rename(fd, new) == -1)
- sysfatal("create %s: %r", new);
- if(close(fd) == -1)
- sysfatal("close %s: %r", tmp);
- free(tmp);
+ if((changed = realloc(changed, (nchanged+1)*sizeof(Fchg))) == nil)
+ sysfatal("realloc: %r");
+ if((changed[nchanged].new = strdup(new)) == nil)
+ sysfatal("strdup: %r");
+ if((changed[nchanged].old = strdup(old)) == nil)
+ sysfatal("strdup: %r");
+ changed[nchanged].tmp = tmp;
+ nchanged++;
+ close(fd);
}
+void
+finish(int ok)
+{
+ Fchg *c;
+ int i, fd;
+
+ for(i = 0; i < nchanged; i++){
+ c = &changed[i];
+ if(!ok){
+ if(remove(c->tmp) == -1)
+ fprint(2, "remove %s: %r\n", c->tmp);
+ }else{
+ if((fd = open(c->tmp, ORDWR)) == -1)
+ sysfatal("open %s: %r", c->tmp);
+ if(strcmp(c->old, c->new) == 0 && remove(c->old) == -1)
+ sysfatal("remove %s: %r", c->old);
+ if(rename(fd, c->new) == -1)
+ sysfatal("create %s: %r", c->new);
+ if(close(fd) == -1)
+ sysfatal("close %s: %r", c->tmp);
+ if(strcmp(c->new, "/dev/null") == 0)
+ print("%s\n", c->old);
+ else
+ print("%s\n", c->new);
+ }
+ free(c->tmp);
+ free(c->old);
+ free(c->new);
+ }
+ free(changed);
+}
+
int
slurp(Fbuf *f, char *path)
{
@@ -530,10 +573,6 @@
if(i+1 == p->nhunk || strcmp(curfile, p->hunk[i+1].newpath) != 0){
o = append(o, &osz, e, f.buf + f.len);
blat(h->oldpath, h->newpath, o, osz);
- if(strcmp(h->newpath, "/dev/null") == 0)
- print("%s\n", h->oldpath);
- else
- print("%s\n", h->newpath);
osz = 0;
}
}
@@ -571,7 +610,7 @@
{
Biobuf *f;
Patch *p;
- int i;
+ int i, ok;
ARGBEGIN{
case 'p':
@@ -592,13 +631,16 @@
addnew = addnewfn;
addold = addoldfn;
}
+ ok = 1;
if(argc == 0){
if((f = Bfdopen(0, OREAD)) == nil)
sysfatal("open stdin: %r");
if((p = parse(f, "stdin")) == nil)
sysfatal("parse patch: %r");
- if(apply(p, "stdin") == -1)
- sysfatal("apply stdin: %r");
+ if(apply(p, "stdin") == -1){
+ fprint(2, "apply stdin: %r\n");
+ ok = 0;
+ }
freepatch(p);
Bterm(f);
}else{
@@ -607,11 +649,14 @@
sysfatal("open %s: %r", argv[i]);
if((p = parse(f, argv[i])) == nil)
sysfatal("parse patch: %r");
- if(apply(p, argv[i]) == -1)
- sysfatal("apply %s: %r", argv[i]);
+ if(apply(p, argv[i]) == -1){
+ fprint(2, "apply %s: %r\n", argv[i]);
+ ok = 0;
+ }
freepatch(p);
Bterm(f);
}
}
+ finish(ok);
exits(nil);
}