shithub: mapfs

Download patch

ref: adb6ddf2966e78f5a04135decfcd8058992b8aae
parent: e78b966c9df18dce119421db741881d94a549dfd
author: sirjofri <sirjofri@sirjofri.de>
date: Fri Mar 28 14:56:30 EDT 2025

do not use filetrees, don't show files below zoom level

--- a/cache.c
+++ b/cache.c
@@ -6,96 +6,41 @@
 #include "dat.h"
 #include "fns.h"
 
-Bundle*
-mkbundle(int z, int x, int y)
-{
-	Bundle *ret = mallocz(sizeof(Bundle), 1);
-	if (!ret)
-		sysfatal("%r");
-	ret->x = x;
-	ret->y = y;
-	ret->z = z;
-	return ret;
-}
-
 void
-filly(File *root, int z, int x, int m)
+download(Bundle b, char *file)
 {
-	int i;
-	File *f;
-	char buf[64];
-	Dir *d;
+	char *url;
 	
-	for (i = 0; i < m; i++) {
-		snprint(buf, sizeof buf, "%d", i);
-		f = createfile(root, buf, uid, 0444, mkbundle(z, x, i));
-		if (!f)
-			sysfatal("createfile img %r");
-		
-		snprint(buf, sizeof buf, "%s/%d/%d/%d", cache, z, x, i);
-		d = dirstat(buf);
-		if (!d)
-			continue;
-		f->length = d->length;
-		free(d);
-	}
-}
-
-void
-fillx(File *root, int z, int m)
-{
-	int i;
-	File *f;
-	char buf[5];
+	url = smprint("https://tile.openstreetmap.org/%d/%d/%d.png", b.z, b.x, b.y);
 	
-	for (i = 0; i < m; i++) {
-		snprint(buf, sizeof buf, "%d", i);
-		f = createfile(root, buf, uid, 0777|DMDIR, nil);
-		if (!f)
-			sysfatal("createfile dir %r");
-		
-		filly(f, z, i, m);
-	}
-}
-
-void
-inittree(File *root)
-{
-	File *f;
-	int m;
-	char buf[3];
+	putenv("tileurl", url);
+	free(url);
 	
-	for (int i = 0; i <= maxzoom; i++) {
-		snprint(buf, sizeof buf, "%d", i);
-		f = createfile(root, buf, uid, 0555|DMDIR, nil);
-		if (!f)
-			sysfatal("createfile zoomdir %r");
-		
-		m = 1;
-		for (int j = 0; j < i; j++)
-			m *= 2;
-		fillx(f, i, m);
-	}
-}
-
-void
-download(Bundle b, char *file)
-{
-	char *cmd = smprint(
-		"mkdir -p `{basename -d '%s'} && "
-		"hget https://tile.openstreetmap.org/%d/%d/%d.png | "
-		"png -t9 > '%s'",
-		file, b.z, b.x, b.y, file);
+	putenv("tilefile", file);
+	
+	char *cmd =
+		"mkdir -p `{basename -d $tilefile} && "
+		"hget $tileurl > /tmp/tmptile.png && "
+		"png -t9 /tmp/tmptile.png > $tilefile && "
+		"rm /tmp/tmptile.png";
+	
 	execl("/bin/rc", "rc", "-c", cmd, nil);
 }
 
 void
-requestfile(File *file, Bundle *b, char *dest)
+requestfile(Bundle b, char *dest)
 {
 	int p[2];
 	int pid;
-	Dir *d;
+	int mod;
 	
+	mod = 1;
+	for (int i = 0; i < b.z; i++)
+		mod *= 2;
+	
+	b.x = b.x % mod;
+	b.y = b.y % mod;
+	
 	switch (pid = fork()) {
 	case -1:
 		sysfatal("fork: %r");
@@ -103,16 +48,10 @@
 		close(p[1]);
 		break;
 	case 0:
-		download(*b, dest);
+		download(b, dest);
 		sysfatal("download: %r");
 	}
 	
 	while (waitpid() != pid)
 		;
-	
-	d = dirstat(dest);
-	if (d) {
-		file->length = d->length;
-		free(d);
-	}
 }
--- a/fns.h
+++ b/fns.h
@@ -1,2 +1,1 @@
-void inittree(File *root);
-void requestfile(File *file, Bundle *b, char *dest);
+void requestfile(Bundle b, char *dest);
--- a/mapfs.c
+++ b/mapfs.c
@@ -14,33 +14,307 @@
 	exits("usage");
 }
 
+char Ebadzoom[] = "bad zoom";
+char Enofile[] = "file not found";
+char Enotile[] = "invalid tile";
+
 char *mtpt = "/mnt/map";
 char *cache = "/tmp/mapcache";
 char *uid;
-int maxzoom = 8;
+int maxzoom = 19;
 
-void
+ulong *numtiles;
+
+static void
+initnumtiles(void)
+{
+	numtiles = mallocz(sizeof(ulong) * (maxzoom + 1), 1);
+	if (!numtiles)
+		sysfatal("%r");
+	
+	for (int i = 0; i <= maxzoom; i++) {
+		numtiles[i] = 1;
+		for (int j = 0; j < i; j++)
+			numtiles[i] *= 2;
+	}
+}
+
+static int
+validtile(int z, int n)
+{
+	if (z < 0)
+		return 0;
+	if (z > maxzoom)
+		return 0;
+	
+	if (n < 0)
+		return 0;
+	if (n > numtiles[z])
+		return 0;
+	return 1;
+}
+
+/* path:
+
+	64 bits available
+	
+	3 - Q
+	5 - z
+	24 - x
+	24 - y
+
+*/
+
+typedef struct Qpath Qpath;
+struct Qpath {
+	int q;
+	int z;
+	uvlong x;
+	uvlong y;
+};
+
+static Qpath
+unpackqpath(uvlong path)
+{
+	Qpath q;
+	q.q = path & 0x7;
+	q.z = (path>>3) & 0x1f;
+	q.x = (path>>8) & 0xffffff;
+	q.y = (path>>32) & 0xffffff;
+	return q;
+}
+
+static uvlong
+packqpath(Qpath q)
+{
+	uvlong r;
+	r  = (q.y&0xffffff)<<32;
+	r |= (q.x&0xffffff)<<8;
+	r |= (q.z&0x1f)<<3;
+	r |= q.q&0x7;
+	return r;
+}
+
+#define QID(p) (p&0x7)
+
+enum {
+	Qroot,
+		Qctl,
+		Qz,
+			Qx,
+				Qy,
+};
+
+static Qid
+mkqid(uvlong q, int type)
+{
+	Qid id;
+	id.path = q;
+	id.vers = 0;
+	id.type = type;
+	return id;
+}
+
+static Qid
+mkzqid(int z)
+{
+	Qpath q;
+	q.z = z;
+	q.q = Qz;
+	return mkqid(packqpath(q), QTDIR);
+}
+
+static Qid
+mkxqid(int z, int x)
+{
+	Qpath q;
+	q.z = z;
+	q.x = x;
+	q.q = Qx;
+	return mkqid(packqpath(q), QTDIR);
+}
+
+static Qid
+mkyqid(int z, int x, int y)
+{
+	Qpath q;
+	q.z = z;
+	q.x = x;
+	q.y = y;
+	q.q = Qy;
+	return mkqid(packqpath(q), QTFILE);
+}
+
+static void
+fsattach(Req *r)
+{
+	r->fid->qid = r->ofcall.qid = mkqid(Qroot, QTDIR);
+	respond(r, nil);
+}
+
+static char*
+fswalk(Fid *fid, char *name, Qid *qid)
+{
+	int i;
+	Qpath path;
+	
+	if (QID(fid->qid.path) == Qroot) {
+		if (strcmp(name, "..") == 0) {
+			return nil;
+		}
+		if (strcmp(name, "ctl") == 0) {
+			fid->qid = *qid = mkqid(Qctl, QTFILE);
+			return nil;
+		}
+		i = atoi(name);
+		if (i < 0)
+			return Ebadzoom;
+		if (i > maxzoom)
+			return Ebadzoom;
+		fid->qid = *qid = mkzqid(i);
+		return nil;
+	}
+	
+	if (QID(fid->qid.path) == Qz) {
+		if (strcmp(name, "..") == 0) {
+			fid->qid = *qid = mkqid(Qroot, QTDIR);
+			return nil;
+		}
+		i = atoi(name);
+		path = unpackqpath(fid->qid.path);
+		if (!validtile(path.z, i))
+			return Enotile;
+		fid->qid = *qid = mkxqid(path.z, i);
+		return nil;
+	}
+	
+	if (QID(fid->qid.path) == Qx) {
+		path = unpackqpath(fid->qid.path);
+		if (strcmp(name, "..") == 0) {
+			fid->qid = *qid = mkxqid(path.z, path.x);
+			return nil;
+		}
+		i = atoi(name);
+		if (!validtile(path.z, i))
+			return Enotile;
+		fid->qid = *qid = mkyqid(path.z, path.x, i);
+		return nil;
+	}
+	
+	return Enofile;
+}
+
+static void
+fillstat(int type, Dir *dir, Qpath *p)
+{
+	char buf[12];
+	
+	switch (type) {
+	case Qroot:
+		dir->qid = mkqid(Qroot, QTDIR);
+		dir->name = estrdup9p(".");
+		dir->mode = 0777|DMDIR;
+		goto fulldefs;
+	case Qctl:
+		dir->qid = mkqid(Qctl, QTFILE);
+		dir->mode = 0444;
+		dir->name = estrdup9p("ctl");
+		goto fulldefs;
+	case Qz:
+		dir->qid = mkzqid(p->z);
+		snprint(buf, sizeof buf, "%d", p->z);
+		break;
+	case Qx:
+		dir->qid = mkxqid(p->z, p->x);
+		snprint(buf, sizeof buf, "%lld", p->x);
+		break;
+	case Qy:
+		dir->qid = mkyqid(p->z, p->x, p->y);
+		snprint(buf, sizeof buf, "%lld", p->y);
+		break;
+	}
+	dir->name = estrdup9p(buf);
+	dir->mode = 0777|DMDIR;
+fulldefs:
+	dir->length = 0;
+	dir->uid = estrdup9p(uid);
+	dir->gid = estrdup9p(uid);
+}
+
+static void
+fsstat(Req *r)
+{
+	Qpath path;
+	
+	path = unpackqpath(r->fid->qid.path);
+	fillstat(QID(r->fid->qid.path), &r->d, &path);
+	respond(r, nil);
+	return;
+}
+
+static int
+rootgen(int n, Dir *dir, void*)
+{
+	Qpath path;
+	if (n > maxzoom + 1) {
+		return -1;
+	}
+	if (n > maxzoom) {
+		fillstat(Qctl, dir, nil);
+		return 0;
+	}
+	path.z = n;
+	fillstat(Qz, dir, &path);
+	return 0;
+}
+
+static void
 fsread(Req *r)
 {
-	Bundle *b;
-	char *f;
+	Bundle b;
+	Qpath path;
 	int fd;
+	char buf[128];
 	
-	if (!r->fid->file->aux) {
-		respond(r, "invalid file");
+	if (QID(r->fid->qid.path) == Qroot) {
+		dirread9p(r, rootgen, nil);
+		respond(r, nil);
 		return;
 	}
-	b = (Bundle*)r->fid->file->aux;
 	
-	f = smprint("%s/%d/%d/%d", cache, b->z, b->x, b->y);
-	if (!f)
-		sysfatal("%r");
+	if (QID(r->fid->qid.path) == Qctl) {
+		snprint(buf, sizeof buf, "%d\n", maxzoom);
+		readstr(r, buf);
+		respond(r, nil);
+		return;
+	}
 	
-	if (access(f, AEXIST) < 0)
-		requestfile(r->fid->file, b, f);
+	if (QID(r->fid->qid.path) == Qz) {
+		respond(r, nil);
+		return;
+	}
 	
-	fd = open(f, OREAD);
-	free(f);
+	if (QID(r->fid->qid.path) == Qx) {
+		respond(r, nil);
+		return;
+	}
+	
+	if (QID(r->fid->qid.path) != Qy) {
+		respond(r, Enofile);
+		return;
+	}
+	
+	path = unpackqpath(r->fid->qid.path);
+	b.z = path.z;
+	b.x = path.x;
+	b.y = path.y;
+	
+	snprint(buf, sizeof buf, "%s/%d/%d/%d", cache, b.z, b.x, b.y);
+	
+	if (access(buf, AEXIST) < 0)
+		requestfile(b, buf);
+	
+	fd = open(buf, OREAD);
 	if (fd < 0) {
 		responderror(r);
 		return;
@@ -51,36 +325,39 @@
 	respond(r, nil);
 }
 
-void
+static void
 fsremove(Req *r)
 {
-	Bundle *b;
-	char *f;
+	Qpath p;
+	Bundle b;
+	char buf[128];
 	
-	if (!r->fid->file->aux) {
-		r->fid->file = nil;
+	if (QID(r->fid->qid.path) != Qy) {
 		respond(r, nil);
 		return;
 	}
-	b = (Bundle*)r->fid->file->aux;
 	
-	f = smprint("%s/%d/%d/%d", cache, b->z, b->x, b->y);
-	if (!f)
-		sysfatal("%r");
+	p = unpackqpath(r->fid->qid.path);
+	b.z = p.z;
+	b.x = p.x;
+	b.y = p.y;
 	
-	if (access(f, AEXIST) < 0) {
+	snprint(buf, sizeof buf, "%s/%d/%d/%d", cache, b.z, b.x, b.y);
+	
+	if (access(buf, AEXIST) < 0) {
 		respond(r, nil);
 		return;
 	}
 	
-	remove(f);
-	r->fid->file->length = 0;
-	r->fid->file = nil;
+	remove(buf);
 	respond(r, nil);
 	return;
 }
 
 Srv fs = {
+	.attach = fsattach,
+	.walk1 = fswalk,
+	.stat = fsstat,
 	.read = fsread,
 	.remove = fsremove,
 };
@@ -104,6 +381,9 @@
 	case 'z':
 		maxzoom = atoi(EARGF(usage()));
 		break;
+	case 'D':
+		chatty9p++;
+		break;
 	}ARGEND;
 	
 	if (access(cache, AEXIST) < 0) {
@@ -113,9 +393,8 @@
 		close(fd);
 	}
 	
+	initnumtiles();
 	uid = getuser();
 	
-	fs.tree = alloctree(nil, nil, DMDIR|0777, nil);
-	inittree(fs.tree->root);
 	postmountsrv(&fs, srv, mtpt, MREPL|MCREATE);
 }
--