ref: d6229fafff96c77ff8d5c2758fd8436950559fe4
parent: 440d87f85823350dedd0accaa9c90f425436064d
parent: 906f8f188f86e09b7f93445dd20571ad83790fed
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat May 31 10:09:47 EDT 2025
merge
--- a/sys/man/1/patch
+++ b/sys/man/1/patch
@@ -4,7 +4,10 @@
.SH SYNOPSIS
.B patch
[
-.B -R
+.B -nR
+[
+.B -d
+.I rdir
]
[
.B -p
--- a/sys/src/cmd/gefs/cons.c
+++ b/sys/src/cmd/gefs/cons.c
@@ -173,7 +173,9 @@
for(i = 0; i < fs->nusers; i++){
u = &fs->users[i];
fprint(fd, "%d:%s:", u->id, u->name);
- if((v = uid2user(u->lead)) == nil)
+ if(u->lead == noneid)
+ fprint(fd, ":");
+ else if((v = uid2user(u->lead)) == nil)
fprint(fd, "???:");
else
fprint(fd, "%s:", v->name);
--- a/sys/src/cmd/gefs/dat.h
+++ b/sys/src/cmd/gefs/dat.h
@@ -533,7 +533,7 @@
QLock synclk;
Rendez syncrz;
- QLock mountlk;
+ RWLock mountlk;
Mount *mounts;
Mount *snapmnt;
Lock connlk;
--- a/sys/src/cmd/gefs/fs.c
+++ b/sys/src/cmd/gefs/fs.c
@@ -114,8 +114,16 @@
nexterror();
}
tracem("packb");
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next)
+
+ rlock(&fs->mountlk);
+ if(waserror()){
+ runlock(&fs->mountlk);
+ nexterror();
+ }
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next)
updatesnap(&mnt->root, mnt->root, mnt->name, mnt->flag);
+ runlock(&fs->mountlk);
+ poperror();
/*
* Now that we've updated the snaps, we can sync the
* dlist; the snap tree will not change from here.
@@ -204,16 +212,18 @@
static void
snapfs(Amsg *a, Tree **tp)
{
- Tree *t, *s;
+ Tree *t, *s, *r;
Mount *mnt;
+ t = nil;
+ r = nil;
+ *tp = nil;
+ rlock(&fs->mountlk);
if(waserror()){
- *tp = nil;
+ runlock(&fs->mountlk);
nexterror();
}
- t = nil;
- *tp = nil;
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next){
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next){
if(strcmp(a->old, mnt->name) == 0){
updatesnap(&mnt->root, mnt->root, mnt->name, mnt->flag);
t = agetp(&mnt->root);
@@ -224,6 +234,7 @@
if(t == nil && (t = opensnap(a->old, nil)) == nil){
if(a->fd != -1)
fprint(a->fd, "snap: open '%s': does not exist\n", a->old);
+ runlock(&fs->mountlk);
poperror();
return;
}
@@ -231,12 +242,13 @@
if(mnt != nil) {
if(a->fd != -1)
fprint(a->fd, "snap: snap is mounted: '%s'\n", a->old);
+ runlock(&fs->mountlk);
poperror();
return;
}
if(t->nlbl == 1 && t->nref <= 1 && t->succ == -1){
ainc(&t->memref);
- *tp = t;
+ r = t;
}
delsnap(t, t->succ, a->old);
}else{
@@ -244,6 +256,7 @@
if(a->fd != -1)
fprint(a->fd, "snap: already exists '%s'\n", a->new);
closesnap(s);
+ runlock(&fs->mountlk);
poperror();
return;
}
@@ -250,7 +263,9 @@
tagsnap(t, a->new, a->flag);
}
closesnap(t);
+ runlock(&fs->mountlk);
poperror();
+ *tp = r;
if(a->fd != -1){
if(a->delete)
fprint(a->fd, "deleted: %s\n", a->old);
@@ -415,8 +430,16 @@
{
if(!(mnt->flag & Lmut))
error(Erdonly);
- if(mnt->root->nlbl != 1 || mnt->root->nref != 0)
+ if(mnt->root->nlbl != 1 || mnt->root->nref != 0){
+ rlock(&fs->mountlk);
+ if(waserror()){
+ runlock(&fs->mountlk);
+ nexterror();
+ }
updatesnap(&mnt->root, mnt->root, mnt->name, mnt->flag);
+ poperror();
+ runlock(&fs->mountlk);
+ }
btupsert(mnt->root, m, nm);
}
@@ -679,22 +702,19 @@
return fs->snapmnt;
}
- qlock(&fs->mountlk);
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next){
+ wlock(&fs->mountlk);
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next){
if(strcmp(name, mnt->name) == 0){
ainc(&mnt->ref);
goto Out;
}
}
- if((mnt = mallocz(sizeof(*mnt), 1)) == nil){
- qunlock(&fs->mountlk);
- error(Enomem);
- }
if(waserror()){
- qunlock(&fs->mountlk);
+ wunlock(&fs->mountlk);
free(mnt);
nexterror();
}
+ mnt = emalloc(sizeof(*mnt), 1);
mnt->ref = 1;
snprint(mnt->name, sizeof(mnt->name), "%s", name);
if((t = opensnap(name, &flg)) == nil)
@@ -703,11 +723,11 @@
mnt->root = t;
mnt->next = fs->mounts;
loadautos(mnt);
- asetp(&fs->mounts, mnt);
+ fs->mounts = mnt;
poperror();
Out:
- qunlock(&fs->mountlk);
+ wunlock(&fs->mountlk);
return mnt;
}
@@ -718,8 +738,8 @@
if(mnt == nil)
return;
+ wlock(&fs->mountlk);
if(adec(&mnt->ref) == 0){
- qlock(&fs->mountlk);
for(p = &fs->mounts; (me = *p) != nil; p = &me->next){
if(me == mnt)
break;
@@ -727,8 +747,8 @@
assert(me != nil);
*p = me->next;
limbo(DFmnt, me);
- qunlock(&fs->mountlk);
}
+ wunlock(&fs->mountlk);
}
static void
@@ -1914,6 +1934,8 @@
}
if(f->dent->gone)
error(Ephase);
+ if((f->dent->qid.type & QTEXCL) && f->dent->ref != 1)
+ error(Elocked);
/*
* we need a double check that the file is in the tree
* here, because the walk to the fid is done in a reader
@@ -2005,8 +2027,7 @@
}
if(f->dent->gone)
error(Ephase);
- if(f->dent->qid.type & QTEXCL)
- if(f->dent->ref != 1)
+ if((f->dent->qid.type & QTEXCL) && f->dent->ref != 1)
error(Elocked);
if(m->mode & ORCLOSE)
if((e = candelete(f)) != nil)
@@ -3031,12 +3052,14 @@
tmnow(&tm, nil);
now = tmnorm(&tm);
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next){
+ rlock(&fs->mountlk);
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next){
if(!(mnt->flag & Lmut))
continue;
for(i = 0; i < nelem(mnt->cron); i++)
cronsync(mnt->name, &mnt->cron[i], &tm, now);
}
+ runlock(&fs->mountlk);
poperror();
}
}
--- a/sys/src/cmd/gefs/snap.c
+++ b/sys/src/cmd/gefs/snap.c
@@ -310,6 +310,8 @@
*
* If it has one successor and no label, then
* it will be merged with that successor.
+ *
+ * Must be called with mntlock held for r
*/
void
delsnap(Tree *t, vlong succ, char *name)
@@ -360,7 +362,8 @@
btupsert(&fs->snap, m, nm);
if(deltree){
reclaimblocks(t->gen, succ, t->pred);
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next){
+ assert(!canwlock(&fs->mountlk));
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next){
if(mnt->root->gen == t->succ)
mnt->root->pred = t->pred;
if(mnt->root->gen == t->pred)
--- a/sys/src/cmd/gefs/user.c
+++ b/sys/src/cmd/gefs/user.c
@@ -133,6 +133,7 @@
goto Error;
}
snprint(u->name, sizeof(u->name), "%s", f);
+ u->lead = noneid;
u->memb = nil;
u->nmemb = 0;
i++;
@@ -162,6 +163,11 @@
if(u == nil){
fprint(fd, "/adm/users:%d: leader %s does not exist\n", lnum, f);
err = Enouser;
+ goto Error;
+ }
+ if(u->id == noneid){
+ fprint(fd, "/adm/users:%d: group leader may not be none\n", lnum);
+ err = Esyntax;
goto Error;
}
users[i].lead = u->id;
--- a/sys/src/cmd/git/branch
+++ b/sys/src/cmd/git/branch
@@ -16,7 +16,7 @@
if(~ $#listall 0)
awk '$1=="branch"{print $2}' < $gitfs/ctl
if not
- cd .git/refs/ && walk -f heads remotes
+ cd .git/refs/ && walk -f heads remotes | sort
exit
}
if(! ~ $#* 1)
@@ -31,6 +31,7 @@
new=refs/heads/$branch
orig=`{git/query HEAD}
+origbranch=refs/`{awk '$1=="branch"{print $2}' < $gitfs/ctl}
if (~ $#baseref 1)
base=`{git/query $baseref} || exit 'bad base'
if not if(~ $#newbr 0)
@@ -50,7 +51,7 @@
deleted=`$nl{git/query -c HEAD $base | grep '^-' | subst '^..'}
# if we remove the current branch without switching, bad things happen
-if(~ $remove 1 && ~ `{git/query HEAD} `{git/query $branch})
+if(~ $remove 1 && ~ $origbranch $new)
die 'cannot remove current branch'
# if we're not merging, don't clobber existing changes.
if(~ $#merge 0 && ~ $#remove 0){
--- a/sys/src/cmd/git/test/mkfile
+++ b/sys/src/cmd/git/test/mkfile
@@ -9,7 +9,8 @@
lca\
merge\
noam\
- range
+ range\
+ rebase
</sys/src/cmd/mktest
--- /dev/null
+++ b/sys/src/cmd/git/test/rebase.rc
@@ -1,0 +1,26 @@
+#!/bin/rc
+
+. ./util.rc
+
+rm -fr scratch
+mkdir scratch
+
+echo @@ rebase test @@
+@{
+ cd scratch
+ q git/init
+ q echo a >a; git/add a; git/commit -m a a
+
+ q git/branch -n front-test
+ echo c >c;
+ q git/add c
+ q git/commit -m c c
+
+ q git/branch front
+ echo b >b;
+ q git/add b
+ q git/commit -m b b
+
+ q git/branch front-test
+ q git/rebase front
+}
--- a/sys/src/cmd/git/walk.c
+++ b/sys/src/cmd/git/walk.c
@@ -77,31 +77,53 @@
return r == 0;
}
+/*
+ * Tricky; we want to know if a file or dir is indexed,
+ * but a dir is only indexed if we have a file with dir/
+ * listed in the index.
+ *
+ * as a result, we need to add a virtual '/' at the end
+ * of the path if we're doing it, so if we have:
+ * foo.bar/x
+ * foo/y
+ * and we want to find out if foo is a directory we should
+ * descend into, we need to compare as though foo/ ended
+ * with a '/', or we'll bsearch down do foo.bar, not foo.
+ *
+ * this code resembles entcmp() in util.c, but differs
+ * because we're comparing whole paths.
+ */
int
-pathcmp(char *s, char *path, int dir, int len)
+pathcmp(char *sa, char *sb, int sadir)
{
- int r;
+ unsigned a, b;
- r = strncmp(s, path, len);
- if(r != 0)
- return r;
- if(path[len] == 0 || dir && path[len] == '/')
- return 0;
- return -1;
+ while(1){
+ a = *sa++;
+ b = *sb++;
+ if(a != b){
+ if(a == 0 && sadir)
+ a = '/';
+ if(a == '/' && b == '/')
+ return 0;
+ return (a > b) ? 1 : -1;
+ }
+ if(a == 0)
+ return 0;
+ }
}
int
indexed(char *path, int dir)
{
- int lo, hi, mid, r, len;
+ int lo, hi, mid, r;
r = -1;
lo = 0;
hi = nidx-1;
- len = strlen(path);
while(lo <= hi){
mid = (hi + lo) / 2;
- r = pathcmp(path, idx[mid].path, dir, len);
+ r = pathcmp(path, idx[mid].path, dir);
if(r < 0)
hi = mid-1;
else if(r > 0)
--- a/sys/src/cmd/patch.c
+++ b/sys/src/cmd/patch.c
@@ -17,6 +17,10 @@
struct Hunk {
int lnum;
+ char *orig;
+ int origlen;
+ int origsz;
+
char *oldpath;
int oldln;
int oldcnt;
@@ -50,6 +54,8 @@
int strip;
int reverse;
+int rejfd = -1;
+char *rejfile;
char *workdir;
Fchg *changed;
int nchanged;
@@ -136,6 +142,9 @@
h->lnum = lnum;
h->oldpath = strdup(oldpath);
h->newpath = strdup(newpath);
+ h->origlen = 0;
+ h->origsz = 32;
+ h->orig = emalloc(h->origsz);
h->oldlen = 0;
h->oldsz = 32;
h->old = emalloc(h->oldsz);
@@ -142,6 +151,8 @@
h->newlen = 0;
h->newsz = 32;
h->new = emalloc(h->newsz);
+ cleanname(h->oldpath);
+ cleanname(h->newpath);
if(strncmp(s, "@@ -", 4) != 0)
return -1;
e = s + 4;
@@ -182,6 +193,20 @@
}
void
+addorig(Hunk *h, char *ln)
+{
+ int n;
+
+ n = strlen(ln);
+ while(h->origlen + n >= h->origsz){
+ h->origsz *= 2;
+ h->orig = erealloc(h->orig, h->origsz);
+ }
+ memcpy(h->orig + h->origlen, ln, n);
+ h->origlen += n;
+}
+
+void
addnew(Hunk *h, char *ln)
{
int n;
@@ -331,6 +356,7 @@
break;
}
c = ln[0];
+ addorig(&h, ln);
switch(ln[0]){
default:
sysfatal("%s:%d: malformed hunk: leading junk", name, lnum);
@@ -575,7 +601,7 @@
}
char*
-search(Fbuf *f, Hunk *h, char *fname)
+search(Fbuf *f, Hunk *h)
{
int ln, oldln, fuzz, scanning;
char *p;
@@ -599,9 +625,19 @@
return p;
}
}
- sysfatal("%s:%d: unable to find hunk offset near %s:%d", fname, h->lnum, h->oldpath, h->oldln);
+ return nil;
}
+void
+rejected(Hunk *h, char *fname)
+{
+ fprint(2, "%s:%d: skipping failed hunk %s:%d\n", fname, h->lnum, h->oldpath, h->oldln);
+ fprint(rejfd, "--- %s:%d \n", h->oldpath, h->oldln);
+ fprint(rejfd, "+++ %s:%d \n", h->newpath, h->newln);
+ fprint(rejfd, "@@ -%d,%d +%d,%d @@\n", h->oldln, h->oldcnt, h->newln, h->newcnt);
+ write(rejfd, h->orig, h->origlen);
+}
+
char*
append(char *o, int *sz, char *s, char *e)
{
@@ -617,12 +653,12 @@
int
apply(Patch *p, char *fname)
{
- char *o, *s, *e, *curfile, *nextfile;
+ char *o, *s, *n, *curfile, *nextfile;
int i, osz;
Hunk *h, *prevh;
Fbuf f;
- e = nil;
+ n = nil;
o = nil;
osz = 0;
curfile = nil;
@@ -639,28 +675,38 @@
if(curfile == nil || strcmp(curfile, nextfile) != 0){
if(curfile != nil){
if(!dryrun)
- o = append(o, &osz, e, f.buf + f.len);
+ o = append(o, &osz, n, f.buf + f.len);
blat(prevh->oldpath, prevh->newpath, o, osz, f.mode);
osz = 0;
}
if(!dryrun){
slurp(&f, h->oldpath);
- e = f.buf;
+ n = f.buf;
}
curfile = nextfile;
}
if(!dryrun){
- s = e;
- e = search(&f, h, fname);
+ char *e;
+ s = n;
+ 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);
+ else{
+ rejected(h, fname);
+ goto Next;
+ }
+ }
o = append(o, &osz, s, e);
o = append(o, &osz, h->new, h->new + h->newlen);
- e += h->oldlen;
+ n = e + h->oldlen;
}
+Next:
prevh = h;
}
if(curfile != nil){
if(!dryrun)
- o = append(o, &osz, e, f.buf + f.len);
+ o = append(o, &osz, n, f.buf + f.len);
blat(h->oldpath, h->newpath, o, osz, f.mode);
}
free(o);
@@ -688,7 +734,7 @@
void
usage(void)
{
- fprint(2, "usage: %s [-nR] [-p nstrip] [patch...]\n", argv0);
+ fprint(2, "usage: %s [-nR] [-p nstrip] [-r rejfile] [patch...]\n", argv0);
exits("usage");
}
@@ -703,6 +749,9 @@
case 'd':
workdir = EARGF(usage());
break;
+ case 'r':
+ rejfile = EARGF(usage());
+ break;
case 'p':
strip = atoi(EARGF(usage()));
break;
@@ -718,11 +767,18 @@
}ARGEND;
ok = 1;
+ if(rejfile != nil){
+ rejfd = create(rejfile, OWRITE, 0644);
+ if(rejfd == -1)
+ sysfatal("open %s: %r", rejfile);
+ }
if(argc == 0){
if((f = Bfdopen(0, OREAD)) == nil)
sysfatal("open stdin: %r");
if((p = parse(f, "stdin")) == nil)
sysfatal("parse patch: %r");
+ if(workdir != nil && chdir(workdir) == -1)
+ sysfatal("chdir %s: %r", workdir);
if(apply(p, "stdin") == -1){
fprint(2, "apply stdin: %r\n");
ok = 0;
--- a/sys/src/cmd/test/patch/patch.rc
+++ b/sys/src/cmd/test/patch/patch.rc
@@ -11,13 +11,20 @@
fn checkpatch{
rm -f $1.out
- ../../$O.patch $1.patch
+ ../../$O.patch $*(2-) $1.patch
check $1.out $1.expected
}
+fn checkrej {
+ rm -f $1.rout
+ checkpatch $1 -r $1.rout
+ check $1.rout $1.rexpected
+}
+
checkpatch basic
checkpatch header
checkpatch create
+checkrej rej
seq 12 > delete.out
../../$O.patch delete.patch
--- /dev/null
+++ b/sys/src/cmd/test/patch/rej.expected
@@ -1,0 +1,98 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+16
+12
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+96
--- /dev/null
+++ b/sys/src/cmd/test/patch/rej.in
@@ -1,0 +1,93 @@
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+16
+12
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+96
--- /dev/null
+++ b/sys/src/cmd/test/patch/rej.patch
@@ -1,0 +1,42 @@
+--- rej.in
++++ rej.out
+@@ -1,3 +1,5 @@
++1
++2
+ 3
+ 4
+ 5
+@@ -10,8 +12,8 @@
+ 12
+ 13
+ 14
+-13
+-12
++15
++16
+ 17
+ 18
+ 19
+@@ -35,6 +37,8 @@
+ 37
+ 38
+ 39
++40
++41
+ 42
+ 43
+ 44
+@@ -80,6 +84,7 @@
+ 84
+ 85
+ 86
++87
+ 88
+ 89
+ 90
+@@ -91,3 +96,5 @@
+ 96
+ 97
+ 98
++99
++100
--- /dev/null
+++ b/sys/src/cmd/test/patch/rej.rexpected
@@ -1,0 +1,21 @@
+--- rej.in:9
++++ rej.out:11
+@@ -9,8 +11,8 @@
+ 12
+ 13
+ 14
+-13
+-12
++15
++16
+ 17
+ 18
+ 19
+--- rej.in:90
++++ rej.out:95
+@@ -90,3 +95,5 @@
+ 96
+ 97
+ 98
++99
++100
--
⑨