shithub: front

Download patch

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
--