ref: 00f5c30ebc7c56b0deb6e0e3bc139f356174feff
parent: 37f8f8e3e43a4ac6ae65609b8ae7805a04ffe6e7
author: Ori Bernstein <ori@eigenstate.org>
date: Tue Jul 1 19:28:55 EDT 2025
patch: improve behavior when a patch has rejected hunks When we had removed files in misapplied hunks, we would bail out early and leave temp files lying around. Now, we keep trying to apply rejected hunks, and clean up the temp files correctly on patch failure.
--- a/sys/src/cmd/patch.c
+++ b/sys/src/cmd/patch.c
@@ -52,6 +52,9 @@
char *new;
};
+int finish(int);
+void fail(char*, ...);
+
int strip;
int reverse;
int rejfd = -1;
@@ -79,7 +82,7 @@
v = mallocz(n, 1);
if(v == nil)
- sysfatal("malloc: %r");
+ fail("malloc: %r");
setmalloctag(v, getcallerpc(&n));
return v;
}
@@ -91,11 +94,25 @@
n++;
v = realloc(v, n);
if(v == nil)
- sysfatal("malloc: %r");
+ fail("malloc: %r");
setmalloctag(v, getcallerpc(&n));
return v;
}
+void
+fail(char *fmt, ...)
+{
+ char msg[ERRMAX];
+ va_list ap;
+
+ finish(0);
+ va_start(ap, fmt);
+ vsnprint(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ fprint(2, "%s\n", msg);
+ exits(msg);
+}
+
int
fileheader(char *s, char *pfx, char **name)
{
@@ -125,7 +142,7 @@
while(*s == '/')
s++;
if(*s == '\0')
- sysfatal("too many components stripped");
+ fail("too many components stripped");
}
len = (e - s) + 1;
*name = emalloc(len);
@@ -188,7 +205,7 @@
if(h->newln > 0)
h->newln--;
if(h->oldln < 0 || h->newln < 0 || h->oldcnt < 0 || h->newcnt < 0)
- sysfatal("malformed hunk %s", s);
+ fail("malformed hunk %s", s);
return 0;
}
@@ -323,7 +340,7 @@
free(ln);
}
if(p->nhunk == 0)
- sysfatal("%s: could not find start of patch", name);
+ fail("%s: could not find start of patch", name);
goto out;
patch:
@@ -349,9 +366,9 @@
while(1){
if((ln = readline(f, &lnum)) == nil){
if(oldcnt != h.oldcnt)
- sysfatal("%s:%d: malformed hunk: mismatched -hunk size %d != %d", name, lnum, oldcnt, h.oldcnt);
+ fail("%s:%d: malformed hunk: mismatched -hunk size %d != %d", name, lnum, oldcnt, h.oldcnt);
if(newcnt != h.newcnt)
- sysfatal("%s:%d: malformed hunk: mismatched +hunk size %d != %d", name, lnum, newcnt, h.newcnt);
+ fail("%s:%d: malformed hunk: mismatched +hunk size %d != %d", name, lnum, newcnt, h.newcnt);
addhunk(p, &h);
break;
}
@@ -359,7 +376,7 @@
addorig(&h, ln);
switch(ln[0]){
default:
- sysfatal("%s:%d: malformed hunk: leading junk", name, lnum);
+ fail("%s:%d: malformed hunk: leading junk", name, lnum);
case '\\':
if(strncmp(ln, "\\ No newline", nelem("\\ No newline")-1) == 0)
trimhunk(c, &h);
@@ -388,7 +405,7 @@
}
free(ln);
if(oldcnt > h.oldcnt || newcnt > h.newcnt)
- sysfatal("%s:%d: malformed hunk: oversized hunk", name, lnum);
+ fail("%s:%d: malformed hunk: oversized hunk", name, lnum);
if(oldcnt < h.oldcnt || newcnt < h.newcnt)
continue;
@@ -467,51 +484,57 @@
int fd;
tmp = nil;
- if(strcmp(new, "/dev/null") == 0){
- if(len != 0)
- sysfatal("diff modifies removed file");
- }else if(!dryrun){
+ if(strcmp(new, "/dev/null") != 0 && !dryrun){
if(mkpath(new) == -1)
- sysfatal("mkpath %s: %r", new);
+ fail("mkpath %s: %r", new);
if((tmp = smprint("%s.tmp%d", new, getpid())) == nil)
- sysfatal("smprint: %r");
+ fail("smprint: %r");
if((fd = create(tmp, OWRITE, mode|0200)) == -1)
- sysfatal("open %s: %r", tmp);
+ fail("open %s: %r", tmp);
if(write(fd, o, len) != len)
- sysfatal("write %s: %r", tmp);
+ fail("write %s: %r", tmp);
close(fd);
}
if((changed = realloc(changed, (nchanged+1)*sizeof(Fchg))) == nil)
- sysfatal("realloc: %r");
+ fail("realloc: %r");
if((changed[nchanged].new = strdup(new)) == nil)
- sysfatal("strdup: %r");
+ fail("strdup: %r");
if((changed[nchanged].old = strdup(old)) == nil)
- sysfatal("strdup: %r");
+ fail("strdup: %r");
changed[nchanged].tmp = tmp;
nchanged++;
}
-void
+int
finish(int ok)
{
Fchg *c;
- int i, fd;
+ int i, fd, r;
+ r = 1;
for(i = 0; i < nchanged; i++){
c = &changed[i];
if(!ok){
- if(c->tmp != nil && remove(c->tmp) == -1)
+ if(c->tmp != nil && remove(c->tmp) == -1){
+ r = 0;
fprint(2, "remove %s: %r\n", c->tmp);
+ }
goto Free;
}
if(!dryrun){
if(strcmp(c->new, "/dev/null") == 0){
- if(remove(c->old) == -1)
- sysfatal("remove %s: %r", c->old);
+ if(remove(c->old) == -1){
+ r = 0;
+ fprint(2, "remove %s: %r\n", c->old);
+ goto Free;
+ }
goto Print;
}
- if((fd = open(c->tmp, ORDWR)) == -1)
- sysfatal("open %s: %r", c->tmp);
+ if((fd = open(c->tmp, ORDWR)) == -1){
+ r = 0;
+ fprint(2, "open %s: %r\n", c->tmp);
+ goto Free;
+ }
if(strcmp(c->old, c->new) == 0 && remove(c->old) == -1)
sysfatal("remove %s: %r", c->old);
if(rename(fd, c->new) == -1)
@@ -530,9 +553,10 @@
free(c->new);
}
free(changed);
+ return r;
}
-void
+int
slurp(Fbuf *f, char *path)
{
int n, i, fd, sz, len, nlines, linesz;
@@ -540,10 +564,12 @@
int *lines;
Dir *d;
- if((fd = open(path, OREAD)) == -1)
- sysfatal("open %s: %r", path);
+ if((fd = open(path, OREAD)) == -1){
+ fprint(2, "open %s: %r", path);
+ return -1;
+ }
if((d = dirfstat(fd)) == nil)
- sysfatal("stat %s: %r", path);
+ fail("stat %s: %r", path);
sz = 8192;
len = 0;
buf = emalloc(sz);
@@ -556,7 +582,7 @@
if(n == 0)
break;
if(n == -1)
- sysfatal("read %s: %r", path);
+ fail("read %s: %r", path);
len += n;
}
@@ -583,6 +609,7 @@
f->mode = d->mode;
free(d);
close(fd);
+ return 0;
}
char*
@@ -680,7 +707,10 @@
osz = 0;
}
if(!dryrun){
- slurp(&f, h->oldpath);
+ if(slurp(&f, h->oldpath) == -1){
+ rejected(h, fname);
+ goto Next;
+ }
n = f.buf;
}
curfile = nextfile;
@@ -691,7 +721,7 @@
e = search(&f, h);
if(e == nil){
if(rejfd == -1)
- sysfatal("%s:%d: unable to find hunk offset near %s:%d", fname, h->lnum, h->oldpath, h->oldln);
+ fail("%s:%d: unable to find hunk offset near %s:%d", fname, h->lnum, h->oldpath, h->oldln);
else{
rejected(h, fname);
goto Next;
@@ -770,15 +800,15 @@
if(rejfile != nil){
rejfd = create(rejfile, OWRITE, 0644);
if(rejfd == -1)
- sysfatal("open %s: %r", rejfile);
+ fail("open %s: %r", rejfile);
}
if(argc == 0){
if((f = Bfdopen(0, OREAD)) == nil)
- sysfatal("open stdin: %r");
+ fail("open stdin: %r");
if((p = parse(f, "stdin")) == nil)
- sysfatal("parse patch: %r");
+ fail("parse patch: %r");
if(workdir != nil && chdir(workdir) == -1)
- sysfatal("chdir %s: %r", workdir);
+ fail("chdir %s: %r", workdir);
if(apply(p, "stdin") == -1){
fprint(2, "apply stdin: %r\n");
ok = 0;
@@ -785,15 +815,15 @@
}
freepatch(p);
Bterm(f);
- finish(ok);
+ ok = finish(ok);
}else{
for(i = 0; ok && i < argc; i++){
if((f = Bopen(argv[i], OREAD)) == nil)
- sysfatal("open %s: %r", argv[i]);
+ fail("open %s: %r", argv[i]);
if((p = parse(f, argv[i])) == nil)
- sysfatal("parse patch: %r");
+ fail("parse patch: %r");
if(workdir != nil && chdir(workdir) == -1)
- sysfatal("chdir %s: %r", workdir);
+ fail("chdir %s: %r", workdir);
if(apply(p, argv[i]) == -1){
fprint(2, "apply %s: %r\n", argv[i]);
ok = 0;
@@ -800,8 +830,8 @@
}
freepatch(p);
Bterm(f);
- finish(ok);
+ ok = finish(ok);
}
}
- exits(nil);
+ exits(ok ? nil : "failed");
}
--
⑨