/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h" #include "io.h" enum { Slop = 256, /* room at the start of a message buf for proto hdrs */ }; Filsys* fsstr(char *p) { Filsys *fs; for(fs=filsys; fs->name; fs++) if(strcmp(fs->name, p) == 0) return fs; return 0; } Filsys* dev2fs(Device *dev) { Filsys *fs; for(fs=filsys; fs->name; fs++) if(fs->dev == dev) return fs; return 0; } /* * allocate 'count' contiguous channels * of type 'type' and return pointer to base */ Chan* fs_chaninit(int type, int count, int data) { uint8_t *p; Chan *cp, *icp; int i; p = malloc(count * (sizeof(Chan)+data)); icp = (Chan*)p; for(i = 0; i < count; i++) { cp = (Chan*)p; cp->next = chans; chans = cp; cp->type = type; cp->chan = cons.chano; cons.chano++; strncpy(cp->whoname, "", sizeof cp->whoname); wlock(&cp->reflock); wunlock(&cp->reflock); rlock(&cp->reflock); runlock(&cp->reflock); p += sizeof(Chan); if(data){ cp->pdata = p; p += data; } } return icp; } void fileinit(Chan *cp) { File *f, *prev; Tlock *t; int h; loop: lock(&flock); for (h=0; h < nelem(flist); h++) for (prev=0, f = flist[h]; f; prev=f, f=f->next) { if(f->cp != cp) continue; if(prev) { prev->next = f->next; f->next = flist[h]; flist[h] = f; } flist[h] = f->next; unlock(&flock); qlock(f); if(t = f->tlock) { if(t->file == f) t->time = 0; /* free the lock */ f->tlock = 0; } if(f->open & FREMOV) doremove(f, 0); freewp(f->wpath); f->open = 0; authfree(f->auth); f->auth = 0; f->cp = 0; qunlock(f); goto loop; } unlock(&flock); } enum { NOFID = (uint32_t)~0 }; /* * returns a locked file structure */ File* filep(Chan *cp, uint32_t fid, int flag) { File *f; int h; if(fid == NOFID) return 0; h = (int32_t)(uintptr)cp + fid; if(h < 0) h = ~h; h %= nelem(flist); loop: lock(&flock); for(f=flist[h]; f; f=f->next) if(f->fid == fid && f->cp == cp){ /* * Already in use is an error * when called from attach or clone (walk * in 9P2000). The console uses FID[12] and * never clunks them so catch that case. */ if(flag == 0 || cp == cons.chan) goto out; unlock(&flock); return 0; } if(flag) { f = newfp(); if(f) { f->fid = fid; f->cp = cp; f->wpath = 0; f->tlock = 0; f->doffset = 0; f->dslot = 0; f->auth = 0; f->next = flist[h]; flist[h] = f; goto out; } } unlock(&flock); return 0; out: unlock(&flock); qlock(f); if(f->fid == fid && f->cp == cp) return f; qunlock(f); goto loop; } /* * always called with flock locked */ File* newfp(void) { static int first; File *f; int start, i; i = first; start = i; do { f = &files[i]; i++; if(i >= conf.nfile) i = 0; if(f->cp) continue; first = i; return f; } while(i != start); print("out of files\n"); return 0; } void freefp(File *fp) { Chan *cp; File *f, *prev; int h; if(!fp || !(cp = fp->cp)) return; h = (int32_t)(uintptr)cp + fp->fid; if(h < 0) h = ~h; h %= nelem(flist); lock(&flock); for(prev=0,f=flist[h]; f; prev=f,f=f->next) if(f == fp) { if(prev) prev->next = f->next; else flist[h] = f->next; break; } fp->cp = 0; unlock(&flock); } int iaccess(File *f, Dentry *d, int m) { /* uid none gets only other permissions */ if(f->uid != 0) { /* * owner */ if(f->uid == d->uid) if((m<<6) & d->mode) return 0; /* * group membership */ if(ingroup(f->uid, d->gid)) if((m<<3) & d->mode) return 0; } /* * other */ if(m & d->mode) { if((d->mode & DDIR) && (m == DEXEC)) return 0; if(!ingroup(f->uid, 9999)) return 0; } /* * various forms of superuser */ if(wstatallow) return 0; if(duallow != 0 && duallow == f->uid) if((d->mode & DDIR) && (m == DREAD || m == DEXEC)) return 0; return 1; } Tlock* tlocked(Iobuf *p, Dentry *d) { Tlock *t, *t1; Off qpath; Timet tim; Device *dev; tim = toytime(); qpath = d->qid.path; dev = p->dev; again: t1 = 0; for(t=tlocks+NTLOCK-1; t>=tlocks; t--) { if(t->qpath == qpath) if(t->time >= tim) if(t->dev == dev) return nil; /* its locked */ if(t1 != nil && t->time == 0) t1 = t; /* remember free lock */ } if(t1 == 0) { // reclaim old locks lock(&tlocklock); for(t=tlocks+NTLOCK-1; t>=tlocks; t--) if(t->time < tim) { t->time = 0; t1 = t; } unlock(&tlocklock); } if(t1) { lock(&tlocklock); if(t1->time != 0) { unlock(&tlocklock); goto again; } t1->dev = dev; t1->qpath = qpath; t1->time = tim + TLOCK; unlock(&tlocklock); } /* botch * out of tlock nodes simulates * a locked file */ return t1; } Wpath* newwp(void) { static int si = 0; int i; Wpath *w, *sw, *ew; i = si + 1; if(i < 0 || i >= conf.nwpath) i = 0; si = i; sw = &wpaths[i]; ew = &wpaths[conf.nwpath]; for(w=sw;;) { w++; if(w >= ew) w = &wpaths[0]; if(w == sw) { print("out of wpaths\n"); return 0; } if(w->refs) continue; lock(&wpathlock); if(w->refs) { unlock(&wpathlock); continue; } w->refs = 1; w->up = 0; unlock(&wpathlock); return w; } } void freewp(Wpath *w) { lock(&wpathlock); for(; w; w=w->up) w->refs--; unlock(&wpathlock); } Off qidpathgen(Device *dev) { Iobuf *p; Superb *sb; Off path; p = getbuf(dev, superaddr(dev), Brd|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("newqid: super block"); sb = (Superb*)p->iobuf; sb->qidgen++; path = sb->qidgen; putbuf(p); return path; } /* truncating to length > 0 */ static void truncfree(Truncstate *ts, Device *dev, int d, Iobuf *p, int i) { int pastlast; Off a; pastlast = ts->pastlast; a = ((Off *)p->iobuf)[i]; if (d > 0 || pastlast) buffree(dev, a, d, ts); if (pastlast) { ((Off *)p->iobuf)[i] = 0; p->flags |= Bmod|Bimm; } else if (d == 0 && ts->relblk == ts->lastblk) ts->pastlast = 1; if (d == 0) ts->relblk++; } /* * free the block at `addr' on dev. * if it's an indirect block (d [depth] > 0), * first recursively free all the blocks it names. * * ts->relblk is the block number within the file of this * block (or the first data block eventually pointed to via * this indirect block). */ void buffree(Device *dev, Off addr, int d, Truncstate *ts) { Iobuf *p; Off a; int i, pastlast; if(!addr) return; pastlast = (ts == nil? 1: ts->pastlast); /* * if this is an indirect block, recurse and free any * suitable blocks within it (possibly via further indirect blocks). */ if(d > 0) { d--; p = getbuf(dev, addr, Brd); if(p) { if (ts == nil) /* common case: create */ for(i=INDPERBUF-1; i>=0; i--) { a = ((Off *)p->iobuf)[i]; buffree(dev, a, d, nil); } else /* wstat truncation */ for (i = 0; i < INDPERBUF; i++) truncfree(ts, dev, d, p, i); putbuf(p); } } if (!pastlast) return; /* * having zeroed the pointer to this block, add it to the free list. * stop outstanding i/o */ p = getbuf(dev, addr, Bprobe); if(p) { p->flags &= ~(Bmod|Bimm); putbuf(p); } /* * dont put written worm * blocks into free list */ if(dev->type == Devcw) { i = cwfree(dev, addr); if(i) return; } p = getbuf(dev, superaddr(dev), Brd|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("buffree: super block"); addfree(dev, addr, (Superb*)p->iobuf); putbuf(p); } Off bufalloc(Device *dev, int tag, int32_t qid, int uid) { Iobuf *bp, *p; Superb *sb; Off a, n; p = getbuf(dev, superaddr(dev), Brd|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) { print("bufalloc: super block\n"); if(p) putbuf(p); return 0; } sb = (Superb*)p->iobuf; loop: n = --sb->fbuf.nfree; sb->tfree--; if(n < 0 || n >= FEPERBUF) { print("bufalloc: %Z: bad freelist\n", dev); n = 0; sb->fbuf.free[0] = 0; } a = sb->fbuf.free[n]; if(n <= 0) { if(a == 0) { sb->tfree = 0; sb->fbuf.nfree = 1; if(dev->type == Devcw) { n = uid; if(n < 0 || n >= nelem(growacct)) n = 0; growacct[n]++; if(cwgrow(dev, sb, uid)) goto loop; } putbuf(p); print("fs %Z full uid=%d\n", dev, uid); return 0; } bp = getbuf(dev, a, Brd); if(!bp || checktag(bp, Tfree, QPNONE)) { if(bp) putbuf(bp); putbuf(p); return 0; } sb->fbuf = *(Fbuf*)bp->iobuf; putbuf(bp); } bp = getbuf(dev, a, Bmod); memset(bp->iobuf, 0, RBUFSIZE); settag(bp, tag, qid); if(tag == Tind1 || tag == Tind2 || #ifndef COMPAT32 tag == Tind3 || tag == Tind4 || /* add more Tind tags here ... */ #endif tag == Tdir) bp->flags |= Bimm; putbuf(bp); putbuf(p); return a; } /* * what are legal characters in a name? * only disallow control characters. * a) utf avoids control characters. * b) '/' may not be the separator */ int checkname(char *n) { int i, c; for(i=0; ifbuf.nfree; if(n < 0 || n > FEPERBUF) panic("addfree: bad freelist"); if(n >= FEPERBUF) { p = getbuf(dev, addr, Bmod|Bimm); if(p == 0) panic("addfree: getbuf"); *(Fbuf*)p->iobuf = sb->fbuf; settag(p, Tfree, QPNONE); putbuf(p); n = 0; } sb->fbuf.free[n++] = addr; sb->fbuf.nfree = n; sb->tfree++; if(addr >= sb->fsize) sb->fsize = addr+1; } /* static int Yfmt(Fmt* fmt) { Chan *cp; char s[20]; cp = va_arg(fmt->args, Chan*); sprint(s, "C%d.%.3d", cp->type, cp->chan); return fmtstrcpy(fmt, s); } */ static int Zfmt(Fmt* fmt) { Device *d; int c, c1; char s[100]; d = va_arg(fmt->args, Device*); if(d == nil) { sprint(s, "Z***"); goto out; } c = c1 = '\0'; switch(d->type) { default: sprint(s, "D%d", d->type); break; case Devwren: c = 'w'; /* fallthrough */ case Devworm: if (c == '\0') c = 'r'; /* fallthrough */ case Devlworm: if (c == '\0') c = 'l'; if(d->wren.ctrl == 0 && d->wren.lun == 0) sprint(s, "%c%d", c, d->wren.targ); else sprint(s, "%c%d.%d.%d", c, d->wren.ctrl, d->wren.targ, d->wren.lun); break; case Devmcat: c = '('; c1 = ')'; /* fallthrough */ case Devmlev: if (c == '\0') { c = '['; c1 = ']'; } /* fallthrough */ case Devmirr: if (c == '\0') { c = '{'; c1 = '}'; } if(d->cat.first == d->cat.last) sprint(s, "%c%Z%c", c, d->cat.first, c1); else if(d->cat.first->link == d->cat.last) sprint(s, "%c%Z%Z%c", c, d->cat.first, d->cat.last, c1); else sprint(s, "%c%Z-%Z%c", c, d->cat.first, d->cat.last, c1); break; case Devro: sprint(s, "o%Z%Z", d->ro.parent->cw.c, d->ro.parent->cw.w); break; case Devcw: sprint(s, "c%Z%Z", d->cw.c, d->cw.w); break; case Devjuke: sprint(s, "j%Z%Z", d->j.j, d->j.m); break; case Devfworm: sprint(s, "f%Z", d->fw.fw); break; case Devpart: sprint(s, "p(%Z)%ld.%ld", d->part.d, d->part.base, d->part.size); break; case Devswab: sprint(s, "x%Z", d->swab.d); break; case Devnone: sprint(s, "n"); break; } out: return fmtstrcpy(fmt, s); } static int Gfmt(Fmt* fmt) { int t; char *s; t = va_arg(fmt->args, int); s = ""; if(t >= 0 && t < MAXTAG) s = tagnames[t]; return fmtstrcpy(fmt, s); } void formatinit(void) { quotefmtinstall(); // fmtinstall('Y', Yfmt); /* print channels */ fmtinstall('Z', Zfmt); /* print devices */ fmtinstall('G', Gfmt); /* print tags */ fmtinstall('T', Tfmt); /* print times */ // fmtinstall('E', eipfmt); /* print ether addresses */ fmtinstall('I', eipfmt); /* print ip addresses */ } void rootream(Device *dev, Off addr) { Iobuf *p; Dentry *d; p = getbuf(dev, addr, Bmod|Bimm); memset(p->iobuf, 0, RBUFSIZE); settag(p, Tdir, QPROOT); d = getdir(p, 0); strcpy(d->name, "/"); d->uid = -1; d->gid = -1; d->mode = DALLOC | DDIR | ((DREAD|DEXEC) << 6) | ((DREAD|DEXEC) << 3) | ((DREAD|DEXEC) << 0); d->qid = QID9P1(QPROOT|QPDIR,0); d->atime = time(nil); d->mtime = d->atime; d->muid = 0; putbuf(p); } void superream(Device *dev, Off addr) { Iobuf *p; Superb *s; Off i; p = getbuf(dev, addr, Bmod|Bimm); memset(p->iobuf, 0, RBUFSIZE); settag(p, Tsuper, QPSUPER); s = (Superb*)p->iobuf; s->fstart = 2; s->fsize = devsize(dev); s->fbuf.nfree = 1; s->qidgen = 10; for(i = s->fsize-1; i >= addr+2; i--) addfree(dev, i, s); putbuf(p); } struct { Lock; Msgbuf *smsgbuf; Msgbuf *lmsgbuf; } msgalloc; /* * pre-allocate some message buffers at boot time. * if this supply is exhausted, more will be allocated as needed. */ void mbinit(void) { Msgbuf *mb; Rabuf *rb; int i; lock(&msgalloc); unlock(&msgalloc); msgalloc.lmsgbuf = 0; msgalloc.smsgbuf = 0; for(i=0; imagic = Mbmagic; mb->xdata = malloc(LARGEBUF+Slop); mb->flags = LARGE; mbfree(mb); cons.nlarge++; } for(i=0; imagic = Mbmagic; mb->xdata = malloc(SMALLBUF+Slop); mb->flags = 0; mbfree(mb); cons.nsmall++; } memset(mballocs, 0, sizeof(mballocs)); lock(&rabuflock); unlock(&rabuflock); rabuffree = 0; for(i=0; i<1000; i++) { rb = malloc(sizeof(*rb)); rb->link = rabuffree; rabuffree = rb; } } Msgbuf* mballoc(int count, Chan *cp, int category) { Msgbuf *mb; lock(&msgalloc); if(count > SMALLBUF) { if(count > LARGEBUF) panic("msgbuf count"); mb = msgalloc.lmsgbuf; if(mb == nil) { mb = malloc(sizeof(Msgbuf)); mb->xdata = malloc(LARGEBUF+Slop); cons.nlarge++; } else msgalloc.lmsgbuf = mb->next; mb->flags = LARGE; } else { mb = msgalloc.smsgbuf; if(mb == nil) { mb = malloc(sizeof(Msgbuf)); mb->xdata = malloc(SMALLBUF+Slop); cons.nsmall++; } else msgalloc.smsgbuf = mb->next; mb->flags = 0; } mballocs[category]++; unlock(&msgalloc); mb->magic = Mbmagic; mb->count = count; mb->chan = cp; mb->next = 0; mb->param = 0; mb->category = category; mb->data = mb->xdata+Slop; return mb; } void mbfree(Msgbuf *mb) { if(mb == nil) return; assert(mb->magic == Mbmagic); if (mb->magic != Mbmagic) panic("mbfree: bad magic 0x%lx", mb->magic); if(mb->flags & BTRACE) print("mbfree: BTRACE cat=%d flags=%x, caller %#p\n", mb->category, mb->flags, getcallerpc()); if(mb->flags & FREE) panic("mbfree already free"); lock(&msgalloc); mballocs[mb->category]--; mb->flags |= FREE; if(mb->flags & LARGE) { mb->next = msgalloc.lmsgbuf; msgalloc.lmsgbuf = mb; } else { mb->next = msgalloc.smsgbuf; msgalloc.smsgbuf = mb; } mb->data = 0; mb->magic = 0; unlock(&msgalloc); } /* * returns 1 if n is prime * used for adjusting lengths * of hashing things. * there is no need to be clever */ int prime(int64_t n) { int32_t i; if((n%2) == 0) return 0; for(i=3;; i+=2) { if((n%i) == 0) return 0; if((int64_t)i*i >= n) return 1; } } char* getwrd(char *word, char *line) { int c, n; while(isascii(*line) && isspace(*line) && *line != '\n') line++; for(n = 0; n < Maxword; n++) { c = *line; if(c == '\0' || isascii(c) && isspace(c)) break; line++; *word++ = c; } *word = 0; return line; } void hexdump(void *a, int n) { char s1[30], s2[4]; uint8_t *p; int i; p = a; s1[0] = 0; for(i = 0; i < n; i++) { sprint(s2, " %.2ux", p[i]); strcat(s1, s2); if((i&7) == 7) { print("%s\n", s1); s1[0] = 0; } } if(s1[0]) print("%s\n", s1); } void* fs_recv(Queue *q, int) { void *a; int i, c; if(q == nil) panic("recv null q"); qlock(q); q->waitedfor = 1; while((c = q->count) <= 0) rsleep(&q->empty); i = q->loc; a = q->args[i]; i++; if(i >= q->size) i = 0; q->loc = i; q->count = c-1; rwakeup(&q->full); /* no longer full */ qunlock(q); return a; } void fs_send(Queue *q, void *a) { int i, c; if(q == nil) panic("send null q"); if(!q->waitedfor) { for (i = 0; i < 5 && !q->waitedfor; i++) sleep(1000); if(!q->waitedfor) { /* likely a bug; don't wait forever */ print("no readers yet for %s q\n", q->name); abort(); } } qlock(q); while((c = q->count) >= q->size) rsleep(&q->full); i = q->loc + c; if(i >= q->size) i -= q->size; q->args[i] = a; q->count = c+1; rwakeup(&q->empty); /* no longer empty */ qunlock(q); } Queue* newqueue(int size, char *name) { Queue *q; q = malloc(sizeof(Queue) + (size-1)*sizeof(void*)); q->size = size; q->full.l = q->empty.l = &q->QLock; q->name = name; return q; } int devread(Device *d, Off b, void *c) { int e; for (;;) switch(d->type) { case Devcw: return cwread(d, b, c); case Devjuke: d = d->j.m; break; case Devro: return roread(d, b, c); case Devwren: return wrenread(d, b, c); case Devworm: case Devlworm: return wormread(d, b, c); case Devfworm: return fwormread(d, b, c); case Devmcat: return mcatread(d, b, c); case Devmlev: return mlevread(d, b, c); case Devmirr: return mirrread(d, b, c); case Devpart: return partread(d, b, c); case Devswab: e = devread(d->swab.d, b, c); if(e == 0) swab(c, 0); return e; case Devnone: print("read from device none(%lld)\n", (Wideoff)b); return 1; default: panic("illegal device in devread: %Z %lld", d, (Wideoff)b); return 1; } } int devwrite(Device *d, Off b, void *c) { int e; /* * set readonly to non-0 to prevent all writes; * mainly for trying dangerous experiments. */ if (readonly) return 0; for (;;) switch(d->type) { case Devcw: return cwwrite(d, b, c); case Devjuke: d = d->j.m; break; case Devro: print("write to ro device %Z(%lld)\n", d, (Wideoff)b); return 1; case Devwren: return wrenwrite(d, b, c); case Devworm: case Devlworm: return wormwrite(d, b, c); case Devfworm: return fwormwrite(d, b, c); case Devmcat: return mcatwrite(d, b, c); case Devmlev: return mlevwrite(d, b, c); case Devmirr: return mirrwrite(d, b, c); case Devpart: return partwrite(d, b, c); case Devswab: swab(c, 1); e = devwrite(d->swab.d, b, c); swab(c, 0); return e; case Devnone: /* checktag() can generate blocks with type devnone */ return 0; default: panic("illegal device in devwrite: %Z %lld", d, (Wideoff)b); return 1; } } Devsize devsize(Device *d) { for (;;) switch(d->type) { case Devcw: case Devro: return cwsize(d); case Devjuke: d = d->j.m; break; case Devwren: return wrensize(d); case Devworm: case Devlworm: return wormsize(d); case Devfworm: return fwormsize(d); case Devmcat: return mcatsize(d); case Devmlev: return mlevsize(d); case Devmirr: return mirrsize(d); case Devpart: return partsize(d); case Devswab: d = d->swab.d; break; default: panic("illegal device in devsize: %Z", d); return 0; } } /* result is malloced */ char * sdof(Device *d) { static char name[256]; for (;;) switch(d->type) { case Devjuke: d = d->j.j; /* robotics */ break; case Devwren: snprint(name, sizeof name, "/dev/sd%d%d", d->wren.ctrl, d->wren.targ); return strdup(name); case Devswab: d = d->swab.d; break; default: panic("illegal device in sdof: %Z", d); return nil; } } Off superaddr(Device *d) { for (;;) switch(d->type) { default: return SUPER_ADDR; case Devcw: case Devro: return cwsaddr(d); case Devswab: d = d->swab.d; break; } } Off getraddr(Device *d) { for (;;) switch(d->type) { default: return ROOT_ADDR; case Devcw: case Devro: return cwraddr(d); case Devswab: d = d->swab.d; break; } } void devream(Device *d, int top) { Device *l; loop: print("\tdevream: %Z %d\n", d, top); switch(d->type) { default: print("ream: unknown dev type %Z\n", d); return; case Devcw: devream(d->cw.w, 0); devream(d->cw.c, 0); if(top) { wlock(&mainlock); cwream(d); wunlock(&mainlock); } devinit(d); return; case Devfworm: devream(d->fw.fw, 0); fwormream(d); break; case Devpart: devream(d->part.d, 0); break; case Devmlev: case Devmcat: case Devmirr: for(l=d->cat.first; l; l=l->link) devream(l, 0); break; case Devjuke: case Devworm: case Devlworm: case Devwren: break; case Devswab: d = d->swab.d; goto loop; } devinit(d); if(top) { wlock(&mainlock); rootream(d, ROOT_ADDR); superream(d, SUPER_ADDR); wunlock(&mainlock); } } void devrecover(Device *d) { for (;;) { print("recover: %Z\n", d); switch(d->type) { default: print("recover: unknown dev type %Z\n", d); return; case Devcw: wlock(&mainlock); /* recover */ cwrecover(d); wunlock(&mainlock); return; case Devswab: d = d->swab.d; break; } } } void devinit(Device *d) { for (;;) { if(d->init) return; d->init = 1; print("\tdevinit %Z\n", d); switch(d->type) { default: print("devinit unknown device %Z\n", d); return; case Devro: cwinit(d->ro.parent); return; case Devcw: cwinit(d); return; case Devjuke: jukeinit(d); return; case Devwren: wreninit(d); return; case Devworm: case Devlworm: return; case Devfworm: fworminit(d); return; case Devmcat: mcatinit(d); return; case Devmlev: mlevinit(d); return; case Devmirr: mirrinit(d); return; case Devpart: partinit(d); return; case Devswab: d = d->swab.d; break; case Devnone: print("devinit of Devnone\n"); return; } } } void swab2(void *c) { uint8_t *p; int t; p = c; t = p[0]; p[0] = p[1]; p[1] = t; } void swab4(void *c) { uint8_t *p; int t; p = c; t = p[0]; p[0] = p[3]; p[3] = t; t = p[1]; p[1] = p[2]; p[2] = t; } void swab8(void *c) { uint8_t *p; int t; p = c; t = p[0]; p[0] = p[7]; p[7] = t; t = p[1]; p[1] = p[6]; p[6] = t; t = p[2]; p[2] = p[5]; p[5] = t; t = p[3]; p[3] = p[4]; p[4] = t; } /* * swab a block * flag = 0 -- convert from foreign to native * flag = 1 -- convert from native to foreign */ void swab(void *c, int flag) { uint8_t *p; Tag *t; int i, j; Dentry *d; Cache *h; Bucket *b; Superb *s; Fbuf *f; Off *l; /* swab the tag */ p = (uint8_t*)c; t = (Tag*)(p + BUFSIZE); if(!flag) { swab2(&t->pad); swab2(&t->tag); swaboff(&t->path); } /* swab each block type */ switch(t->tag) { default: print("no swab for tag=%G rw=%d\n", t->tag, flag); for(j=0; j<16; j++) print(" %.2x", p[BUFSIZE+j]); print("\n"); for(i=0; i<16; i++) { print("%.4x", i*16); for(j=0; j<16; j++) print(" %.2x", p[i*16+j]); print("\n"); } panic("swab"); break; case Tsuper: s = (Superb*)p; swaboff(&s->fbuf.nfree); for(i=0; ifbuf.free[i]); swaboff(&s->fstart); swaboff(&s->fsize); swaboff(&s->tfree); swaboff(&s->qidgen); swaboff(&s->cwraddr); swaboff(&s->roraddr); swaboff(&s->last); swaboff(&s->next); break; case Tdir: for(i=0; iuid); swab2(&d->gid); swab2(&d->mode); swab2(&d->muid); swaboff(&d->qid.path); swab4(&d->qid.version); swaboff(&d->size); for(j=0; jdblock[j]); for (j = 0; j < NIBLOCK; j++) swaboff(&d->iblocks[j]); swab4(&d->atime); swab4(&d->mtime); } break; case Tind1: case Tind2: #ifndef COMPAT32 case Tind3: case Tind4: /* add more Tind tags here ... */ #endif l = (Off *)p; for(i=0; infree); for(i=0; ifree[i]); break; case Tbuck: for(i=0; iagegen); for(j=0; jentry[j].age); swab2(&b->entry[j].state); swaboff(&b->entry[j].waddr); } } break; case Tcache: h = (Cache*)p; swaboff(&h->maddr); swaboff(&h->msize); swaboff(&h->caddr); swaboff(&h->csize); swaboff(&h->fsize); swaboff(&h->wsize); swaboff(&h->wmax); swaboff(&h->sbaddr); swaboff(&h->cwraddr); swaboff(&h->roraddr); swab4(&h->toytime); swab4(&h->time); break; case Tnone: // unitialized case Tfile: // someone elses problem case Tvirgo: // bit map -- all bytes case Tconfig: // configuration string -- all bytes break; } /* swab the tag */ if(flag) { swab2(&t->pad); swab2(&t->tag); swaboff(&t->path); } }