shithub: union

Download patch

ref: 743124504e1558d594b2d9a3d0d329cc540435ed
author: kvik <kvik@a-b.xyz>
date: Tue Nov 17 02:41:34 EST 2020

init

--- /dev/null
+++ b/mkfile
@@ -1,0 +1,10 @@
+</$objtype/mkfile
+
+TARG=union
+OFILES=union.$O
+BIN=/$objtype/bin
+
+</sys/src/cmd/mkone
+
+uninstall:V:
+	rm -f $BIN/$TARG
--- /dev/null
+++ b/union.c
@@ -1,0 +1,121 @@
+#include <u.h>
+#include <libc.h>
+
+int fatal = 1;
+
+void
+usage(void)
+{
+	fprint(2, "%s: [-abcr] path [...] mtpt\n", argv0);
+	exits("usage");
+}
+
+void
+error(char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	vfprint(2, fmt, arg);
+	va_end(arg);
+	if(fatal)
+		exits("fatal");
+}
+
+int
+same(char *p, char *q)
+{
+	int r;
+	Dir *dp, *dq;
+
+	r = 0;
+	if((dp = dirstat(p)) == nil)
+		error("dirstat: %r\n");
+	if((dq = dirstat(q)) == nil)
+		error("dirstat: %r\n");
+	if(dp->type==dq->type
+	&& dp->dev==dq->dev
+	&& dp->qid.path==dq->qid.path
+	&& dp->qid.vers==dq->qid.vers
+	&& dp->qid.type==dq->qid.type)
+		r = 1;
+	free(dp);
+	free(dq);
+	return r;
+}
+
+void
+replace(char *p, char *q)
+{
+	if((bind(p, q, MREPL)) < 0)
+		error("bind %s %s: %r\n", p, q);
+}
+
+void
+after(char *p, char *q)
+{
+	int fd;
+	long n;
+	char np[1024], nq[1024];
+	Dir *dir, *d;
+
+	if(same(p, q) == 0)
+	if((bind(p, q, MAFTER)) < 0)
+		error("bind %s %s: %r\n", p, q);
+	if((fd = open(p, OREAD)) < 0)
+		sysfatal("open: %r");
+	if((n = dirreadall(fd, &dir)) < 0)
+		error("dirreadall: %r\n");
+	close(fd);
+	for(d = dir; n > 0; n--, d++){
+		if((d->mode&DMDIR) == 0)
+			continue;
+		snprint(np, sizeof np, "%s/%s", p, d->name);
+		snprint(nq, sizeof nq, "%s/%s", q, d->name);
+		after(np, nq);
+	}
+}
+
+void
+before(char *p, char *q)
+{
+	char *t;
+	
+	t = "/mnt/temp";
+	replace(p, t);
+	after(q, t);
+	replace(t, q);
+	unmount(nil, t);
+}
+
+void
+main(int argc, char *argv[])
+{
+	int i;
+	char *mtpt;
+	int op;
+
+	enum {After, Before, Replace};
+	op = After;
+	ARGBEGIN{
+	default: usage();
+	case 'a': op = After; break;
+	case 'b': op = Before; break;
+	case 'r': op = Replace; break;
+	case 'q': fatal = 0; break;
+	}ARGEND;
+	if(argc < 2)
+		usage();
+
+	mtpt = argv[argc-1];
+	for(i = 0; i < argc-1; i++)
+		switch(op){
+		default: usage();
+		case After:
+			after(argv[i], mtpt); break;
+		case Before:
+			before(argv[i], mtpt); break;
+		case Replace:
+			replace(argv[i], mtpt); break;
+		}
+}