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);
}
--
⑨