ref: c34bf6a2892dbb1dde83c59be4e224defb09cdfe
dir: /grpfs.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <ctype.h> #include <fcall.h> #include <thread.h> #include <9p.h> typedef struct Tile Tile; typedef struct XFile XFile; typedef struct Grp Grp; enum { Qfile, Qtile, Qgrp }; struct XFile { char type; char name[12+1]; ushort x, y; ulong size; /* for Qtile size is of image(6) buffer */ ulong off; uchar *buf; }; struct Grp { int fd; int nf; XFile *f; int nt; XFile *tiles; uint pal[256]; }; #define GET16(p) ((u16int)(p)[0] | (u16int)(p)[1]<<8) #define GET32(p) ((u32int)(p)[0] | (u32int)(p)[1]<<8 | (u32int)(p)[2]<<16 | (u32int)(p)[3]<<24) #define PUT16(p, u) ((p)[1] = (u)>>8, (p)[0] = (u)) #define PUT32(p, u) ((p)[3] = (u)>>24, (p)[2] = (u)>>16, (p)[1] = (u)>>8, (p)[0] = (u)) static Grp ggrp; static char kens[] = "KenSilverman"; static void fsreadtile(Req *r, XFile *f) { static uchar buf[64*1024]; uint *dot; int i; f = r->fid->file->aux; if(f->buf != nil){ Service: readbuf(r, f->buf, f->size); respond(r, nil); return; } f->buf = mallocz((11 * 5) + 5 + (f->x * f->y * 4), 1); sprint((char*)f->buf, "%11s %11d %11d %11d %11d", "a8r8g8b8", 0, 0, f->x, f->y); dot = (uint*)(f->buf + (11 * 5) + 5); pread(ggrp.fd, buf, f->x * f->y, f->off); for(i = 0; i < f->x * f->y; i++) dot[i] = ggrp.pal[buf[i]]; f->size = (11 * 5) + 5 + (f->x * f->y * 4); goto Service; } static void fsreadfile(Req *r, XFile *f) { if(f->buf){ readbuf(r, f->buf, f->size); respond(r, nil); return; } r->ofcall.count = r->ifcall.count; if(r->ifcall.offset >= f->size){ r->ofcall.count = 0; respond(r, nil); return; } if(r->ifcall.offset+r->ofcall.count > f->size) r->ofcall.count = f->size - r->ifcall.offset; r->ofcall.count = pread(ggrp.fd, r->ofcall.data, r->ofcall.count, r->ifcall.offset+f->off); respond(r, nil); } static void fsreadgrp(Req *r, XFile*) { int i, j; XFile *f; vlong off; u32int count; uchar buf[8192]; uchar *p; off = r->ifcall.offset; count = r->ifcall.count; if(off < 12 + 4){ memcpy(buf, kens, 12); PUT32(buf+12, ggrp.nf); readbuf(r, buf, 16); respond(r, nil); return; } off -= 12 + 4; if(off < 16 * ggrp.nf){ assert(sizeof buf > 16*ggrp.nf); p = buf; for(i = 0; i < ggrp.nf; i++){ memcpy(p, ggrp.f[i].name, 12); for(j = 0; j < 12; j++) *p++ = toupper(*p); PUT32(p, ggrp.f[i].size); p+=4; } r->ifcall.offset = off; readbuf(r, buf, 16*ggrp.nf); respond(r, nil); return; } off -= 16*ggrp.nf; for(i = 0; i < ggrp.nf; i++){ f = ggrp.f+i; if(off >= f->size){ off -= f->size; continue; } if(count+off >= f->size) count = f->size-off; if(f->buf != nil){ r->ifcall.offset = off; r->ifcall.count = count; readbuf(r, f->buf, f->size); } else r->ofcall.count = pread(ggrp.fd, r->ofcall.data, count, off+f->off); respond(r, nil); return; } r->ofcall.count = 0; respond(r, nil); } void (*readftab[])(Req*,XFile*) = { [Qfile] fsreadfile, [Qtile] fsreadtile, [Qgrp] fsreadgrp, }; static void fsread(Req *r) { XFile *f; f = r->fid->file->aux; if(f->type >= nelem(readftab)) sysfatal("invalid type %d", f->type); readftab[f->type](r, f); } static void fswritefile(Req *r, XFile *f) { vlong i, n; if(f->buf == nil){ f->buf = malloc(f->size); for(n = 0; n != f->size;){ i = pread(ggrp.fd, f->buf + n, f->size - n, f->off + n); if(i < 0){ responderror(r); return; } n += i; } } if(r->ifcall.count + r->ifcall.offset > f->size){ f->size = r->ifcall.count + r->ifcall.offset; f->buf = realloc(f->buf, f->size); } memmove(f->buf + r->ifcall.offset, r->ifcall.data, r->ifcall.count); r->ofcall.count = r->ifcall.count; respond(r, nil); } void (*writeftab[])(Req*,XFile*) = { [Qfile] fswritefile, [Qtile] nil, [Qgrp] nil, }; static void fswrite(Req *r) { XFile *f; f = r->fid->file->aux; if(f->type >= nelem(writeftab)) sysfatal("invalid type %d", f->type); if(writeftab[f->type] == nil) respond(r, "not supported"); else writeftab[f->type](r, f); } Srv fs = { .read=fsread, .write=fswrite, }; void parseart(Biobuf *b, ulong off) { static short tilesx[1024]; static short tilesy[1024]; uchar buf[16]; XFile *f; int nt, i, n; Bseek(b, off, 0); n = Bread(b, buf, 16); off += n; nt = GET32(buf+12) - GET32(buf+8) + 1; for(i = 0; i < nt; i++){ Bread(b, buf, 2); tilesx[i] = GET16(buf); } for(i = 0; i < nt; i++){ Bread(b, buf, 2); tilesy[i] = GET16(buf); } off += (nt * 2) + (nt * 2) + (nt * 4); ggrp.tiles = realloc(ggrp.tiles, sizeof(XFile) * (ggrp.nt + nt)); memset(&ggrp.tiles[ggrp.nt], 0, nt * sizeof(XFile)); f = ggrp.tiles + ggrp.nt; for(i = 0; i < nt; i++,f++){ f->type = Qtile; f->x = tilesx[i]; f->y = tilesy[i]; f->off = off; off += tilesx[i] * tilesy[i]; } ggrp.nt += nt; } void parsepal(int fd, int off) { uchar buf[256 * 3]; int i; memset(ggrp.pal, 0, sizeof ggrp.pal); pread(fd, buf, sizeof buf, off); for(i = 0; i < sizeof buf; i += 3) ggrp.pal[i/3] = ((buf[i+2]*4)<<0) | ((buf[i+1]*4)<<8) | ((buf[i]*4)<<16); } void parsegrp(int fd) { uchar buf[64]; uchar *p; int i, n; ulong off; XFile *f; char *user; File *dir; Biobuf *b; b = Bfdopen(fd, OREAD); off = n = Bread(b, buf, strlen(kens)); if(n < 0 || memcmp(buf, kens, n) != 0) sysfatal("invalid file"); n = Bread(b, buf, 4); if(n != 4) sysfatal("failed to read number of files"); user = getenv("user"); fs.tree = alloctree(user, "sys", 0644, nil); f = mallocz(sizeof *f, 1); f->type = Qgrp; createfile(fs.tree->root, "GRP", user, 0444, f); off += n; ggrp.fd = fd; ggrp.nf = GET32((uchar*)buf); ggrp.f = f = mallocz(sizeof(XFile) * ggrp.nf, 1); for(i = 0; i < ggrp.nf; i++,f++){ n = Bread(b, buf, 12); buf[n+1] = 0; for(p = buf; p <= buf+n; p++) *p = tolower(*p); memcpy(f->name, buf, n); off += n; n = Bread(b, buf, 4); off += n; f->size = GET32((uchar*)buf); } ggrp.nt = 0; f = ggrp.f; for(i = 0; i < ggrp.nf; i++,f++){ f->off = off; if(strstr(f->name, ".art") != nil) parseart(b, off); else createfile(fs.tree->root, f->name, user, 0666, f); if(strcmp(f->name, "palette.dat") == 0) parsepal(fd, off); off = f->off + f->size; } dir = createfile(fs.tree->root, "art", user, 0644|DMDIR, nil); for(i = 0; i < ggrp.nt; i++) createfile(dir, smprint("%05d.tile", i), user, 0666, ggrp.tiles + i); free(user); } static void usage(void) { fprint(2, "usage: %s grpfile\n", argv0); exits("usage"); } void main(int argc, char **argv) { char *mtpt, *srvname; int fd; srvname = nil; mtpt = "/mnt/grp"; ARGBEGIN{ case 's': srvname = EARGF(usage()); break; case 'm': mtpt = EARGF(usage()); break; default: usage(); break; }ARGEND; if(argc < 1) usage(); fd = open(argv[0], OREAD); if(fd < 0) sysfatal("%r"); parsegrp(fd); postmountsrv(&fs, srvname, mtpt, MREPL); exits(nil); }