ref: 5390510d0ae960fae9a0a9039bb9da3d1f4f969c
dir: /mapfs.c/
#include <u.h> #include <libc.h> #include <auth.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include "dat.h" #include "fns.h" void usage(void) { fprint(2, "usage: %s [-s srvname] [-m mtpt] [-c cachedir] [-z maxzoom]\n", argv0); exits("usage"); } char *copyright = "© OpenStreetMap Contributors (ODbL)"; int copyrightlen; 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 = 19; 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, Qcopy, 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; } if (strcmp(name, "copyright") == 0) { fid->qid = *qid = mkqid(Qcopy, 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 Qcopy: dir->qid = mkqid(Qcopy, QTFILE); dir->mode = 0444; dir->name = estrdup9p("copyright"); dir->length = copyrightlen; goto ugdefs; 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; ugdefs: 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 + 2) { return -1; } if (n == maxzoom + 1) { fillstat(Qctl, dir, nil); return 0; } if (n == maxzoom + 2) { fillstat(Qcopy, dir, nil); return 0; } path.z = n; fillstat(Qz, dir, &path); return 0; } static void fsread(Req *r) { Bundle b; Qpath path; int fd; char buf[128]; if (QID(r->fid->qid.path) == Qroot) { dirread9p(r, rootgen, nil); respond(r, nil); return; } if (QID(r->fid->qid.path) == Qctl) { snprint(buf, sizeof buf, "%d\n", maxzoom); readstr(r, buf); respond(r, nil); return; } if (QID(r->fid->qid.path) == Qcopy) { readstr(r, copyright); respond(r, nil); return; } if (QID(r->fid->qid.path) == Qz) { respond(r, nil); return; } 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; } r->ofcall.count = pread(fd, r->ofcall.data, r->ifcall.count, r->ifcall.offset); close(fd); respond(r, nil); } static void fsremove(Req *r) { Qpath p; Bundle b; char buf[128]; if (QID(r->fid->qid.path) != Qy) { respond(r, nil); return; } p = unpackqpath(r->fid->qid.path); b.z = p.z; b.x = p.x; b.y = p.y; 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(buf); respond(r, nil); return; } Srv fs = { .attach = fsattach, .walk1 = fswalk, .stat = fsstat, .read = fsread, .remove = fsremove, }; void main(int argc, char **argv) { char *srv = nil; int fd; ARGBEGIN{ case 's': srv = EARGF(usage()); break; case 'm': mtpt = EARGF(usage()); break; case 'c': cache = EARGF(usage()); break; case 'z': maxzoom = atoi(EARGF(usage())); break; case 'D': chatty9p++; break; }ARGEND; if (access(cache, AEXIST) < 0) { fd = create(cache, OREAD, 0777|DMDIR); if (fd < 0) sysfatal("unable to create cache directory: %r"); close(fd); } initnumtiles(); uid = getuser(); copyrightlen = strlen(copyright); postmountsrv(&fs, srv, mtpt, MREPL|MCREATE); }