static int dirfixed(uchar *p, uchar *e, Dir *d) { int len; len = GBIT16(p)+BIT16SZ; if(p + len > e) return -1; p += BIT16SZ; /* ignore size */ d->type = devno(GBIT16(p), 1); p += BIT16SZ; d->dev = GBIT32(p); p += BIT32SZ; d->qid.type = GBIT8(p); p += BIT8SZ; d->qid.vers = GBIT32(p); p += BIT32SZ; d->qid.path = GBIT64(p); p += BIT64SZ; d->mode = GBIT32(p); p += BIT32SZ; d->atime = GBIT32(p); p += BIT32SZ; d->mtime = GBIT32(p); p += BIT32SZ; d->length = GBIT64(p); return len; }
static int dirpackage(uint8_t *buf, int ts, Dir **d, uint32_t *nd, int dotu) { char *s; int ss, i, n, nn; uint m; *d = nil; *nd = 0; if(ts <= 0) return 0; /* * first find number of all stats, check they look like stats, & size all associated strings */ ss = 0; n = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16(&buf[i]); if(statcheck(&buf[i], m, dotu) < 0) break; ss += m; n++; } if(i != ts) { DEBUG("statcheck"); return EBADRPC; } *d = malloc_9p(n * sizeof(Dir) + ss); if (*d == NULL) return ENOMEM; /* * then convert all buffers */ s = (char*)*d + n * sizeof(Dir); nn = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16(&buf[i]); if(nn >= n || convM2D(&buf[i], m, *d + nn, s, dotu) != m){ free_9p(*d); *d = nil; DEBUG("convM2D"); return EBADRPC; } nn++; s += m; } *nd = nn; return 0; }
static long dirpackage(uchar *buf, long ts, Dir **d) { char *s; long ss, i, n, nn, m; *d = nil; if(ts <= 0) return 0; /* * first find number of all stats, check they look like stats, & size all associated strings */ ss = 0; n = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16(&buf[i]); if(statcheck(&buf[i], m) < 0) break; ss += m; n++; } if(i != ts) return -1; *d = malloc(n * sizeof(Dir) + ss); if(*d == nil) return -1; /* * then convert all buffers */ s = (char*)*d + n * sizeof(Dir); nn = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16((uchar*)&buf[i]); if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){ free(*d); *d = nil; return -1; } nn++; s += m; } return nn; }
static void rstat(Req *r, char *error) { int n; uchar *statbuf; uchar tmp[BIT16SZ]; if(error) return; if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){ r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ"; return; } n = GBIT16(tmp)+BIT16SZ; statbuf = emalloc9p(n); if(statbuf == nil){ r->error = "out of memory"; return; } r->ofcall.nstat = convD2M(&r->d, statbuf, n); r->ofcall.stat = statbuf; /* freed in closereq */ if(r->ofcall.nstat <= BIT16SZ){ r->error = "convD2M fails"; free(statbuf); return; } }
Dir* dirfstat(int fd) { Dir *d; uint8_t *buf; int n, nd, i; nd = DIRSIZE; for(i=0; i<2; i++){ /* should work by the second try */ d = malloc(sizeof(Dir) + BIT16SZ + nd); if(d == nil) return nil; buf = (uint8_t*)&d[1]; n = fstat(fd, buf, BIT16SZ+nd); if(n < BIT16SZ){ free(d); return nil; } nd = GBIT16(buf); /* upper bound on size of Dir + strings */ if(nd <= n){ convM2D(buf, n, d, (char*)&d[1]); return d; } /* else sizeof(Dir)+BIT16SZ+nd is plenty */ free(d); } return nil; }
/* * Mountfix might have caused the fixed results of the directory read * to overflow the buffer. Catch the overflow in c->dirrock. */ static void mountrock(Chan *c, uint8_t *p, uint8_t **pe) { uint8_t *e, *r; int len, n; e = *pe; /* find last directory entry */ for(;;){ len = BIT16SZ+GBIT16(p); if(p+len >= e) break; p += len; } /* save it away */ qlock(&c->rockqlock); if(c->nrock+len > c->mrock){ n = ROUNDUP(c->nrock+len, 1024); r = smalloc(n); memmove(r, c->dirrock, c->nrock); free(c->dirrock); c->dirrock = r; c->mrock = n; } memmove(c->dirrock+c->nrock, p, len); c->nrock += len; qunlock(&c->rockqlock); /* drop it */ *pe = p; }
void validstat(uint8_t *s, usize n) { usize m; char buf[64]; if(statcheck(s, n) < 0) error(Ebadstat); /* verify that name entry is acceptable */ s += STATFIXLEN - 4*BIT16SZ; /* location of first string */ /* * s now points at count for first string. * if it's too long, let the server decide; this is * only for his protection anyway. otherwise * we'd have to allocate and waserror. */ m = GBIT16(s); s += BIT16SZ; if(m+1 > sizeof buf) return; memmove(buf, s, m); buf[m] = '\0'; /* name could be '/' */ if(strcmp(buf, "/") != 0) validname(buf, 0); }
Dir* _dirfstat(int fd) { Dir *d; uint8_t *buf; int n, nd, i; nd = DIRSIZE; for(i=0; i<2; i++){ /* should work by the second try */ d = malloc(sizeof(Dir) + nd); if(d == nil) return nil; buf = (uint8_t*)&d[1]; n = _FSTAT(fd, buf, nd); if(n < BIT16SZ){ free(d); return nil; } nd = GBIT16(buf); /* size needed to store whole stat buffer */ if(nd <= n){ _convM2D(buf, n, d, (char*)&d[1]); return d; } /* else sizeof(Dir)+nd is plenty */ free(d); } return nil; }
__private_extern__ int stat_9p(mount_9p *nmp, fid_9p fid, dir_9p **dpp) { Fcall tx, rx; Dir *dp; void *p; int e, n; TRACE(); p = NULL; dp = NULL; tx.type = Tstat; tx.fid = fid; if ((e=rpc_9p(nmp, &tx, &rx, &p))) return e; n = GBIT16((uint8_t*)p); dp = malloc_9p(sizeof(Dir) + BIT16SZ + n); if (dp == NULL) { e = ENOMEM; goto error; } if(convM2D(rx.stat, rx.nstat, dp, (char*)&dp[1], ISSET(nmp->flags, F_DOTU)) != rx.nstat) { DEBUG("convM2D"); e = EBADRPC; goto error; } error: free_9p(p); *dpp = dp; return e; }
static char* dirname(uchar *p, int *n) { p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ; *n = GBIT16(p); return (char*)p+BIT16SZ; }
static char* dirname(uint8_t *p, usize *n) { p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ; *n = GBIT16(p); return (char*)p+BIT16SZ; }
int preaddir(Fid *f, uchar *data, int n, vlong offset) { int r = 0, m; Dir *d; DEBUG(DFD, "\tpreaddir n=%d wo=%lld fo=%lld\n", n, offset, f->offset); if(offset == 0 && f->offset != 0){ if(seek(f->fid, 0, 0) != 0) return -1; f->offset = f->cdir = f->ndir = 0; free(f->dir); f->dir = nil; }else if(offset != f->offset){ werrstr("can't seek dir %lld to %lld", f->offset, offset); return -1; } while(n > 0){ if(f->dir == nil){ f->ndir = dirread(f->fid, &f->dir); if(f->ndir < 0) return f->ndir; if(f->ndir == 0) return r; } d = &f->dir[f->cdir++]; if(exclude){ char *p = makepath(f->f, d->name); if(excludefile(p)){ free(p); goto skipentry; } free(p); } m = convD2M(d, data, n); DEBUG(DFD, "\t\tconvD2M %d\n", m); if(m <= BIT16SZ){ DEBUG(DFD, "\t\t\tneeded %d\n", GBIT16(data)); /* not enough room for full entry; leave for next time */ f->cdir--; return r; }else{ data += m; n -= m; r += m; f->offset += m; } skipentry: if(f->cdir >= f->ndir){ f->cdir = f->ndir = 0; free(f->dir); f->dir = nil; } } return r; }
static usize dirfixed(uint8_t *p, uint8_t *e, Dir *d) { int len; Dev *dev; len = GBIT16(p)+BIT16SZ; if(p + len > e) return 0; p += BIT16SZ; /* ignore size */ dev = devtabget(GBIT16(p), 1); //XDYNX if(dev != nil){ d->type = dev->dc; //devtabdecr(dev); } else d->type = -1; p += BIT16SZ; d->dev = GBIT32(p); p += BIT32SZ; d->qid.type = GBIT8(p); p += BIT8SZ; d->qid.vers = GBIT32(p); p += BIT32SZ; d->qid.path = GBIT64(p); p += BIT64SZ; d->mode = GBIT32(p); p += BIT32SZ; d->atime = GBIT32(p); p += BIT32SZ; d->mtime = GBIT32(p); p += BIT32SZ; d->length = GBIT64(p); return len; }
unsigned int convM2kstat(uint8_t * buf, unsigned int nbuf, struct kstat *ks) { uint8_t *p, *ebuf; char *sv[4]; int i, ns; uint32_t junk; if (nbuf < STATFIXLEN) return 0; p = buf; ebuf = buf + nbuf; p += BIT16SZ; /* ignore size */ junk /*kd->d_type */ = GBIT16(p); p += BIT16SZ; ks->st_rdev = ks->st_dev = GBIT32(p); p += BIT32SZ; junk /*qid.type */ = GBIT8(p); p += BIT8SZ; junk /*qid.vers */ = GBIT32(p); p += BIT32SZ; ks->st_ino = GBIT64(p); p += BIT64SZ; ks->st_mode = GBIT32(p); if (ks->st_mode & DMDIR) { ks->st_mode &= ~DMDIR; ks->st_mode |= __S_IFDIR; } else if (ks->st_mode & DMSYMLINK) { ks->st_mode &= ~DMSYMLINK; ks->st_mode |= __S_IFLNK; } else { ks->st_mode |= __S_IFREG; } p += BIT32SZ; ks->st_atime.tv_sec = GBIT32(p); p += BIT32SZ; ks->st_mtime.tv_sec = GBIT32(p); p += BIT32SZ; ks->st_size = GBIT64(p); p += BIT64SZ; ks->st_blksize = 512; ks->st_blocks = ROUNDUP(ks->st_size, ks->st_blksize) / ks->st_blksize; ks->st_nlink = 2; // links make no sense any more. ks->st_uid = ks->st_gid = 0; return p - buf; }
int statcheck(uchar *buf, uint nbuf) { uchar *ebuf; int i; ebuf = buf + nbuf; if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)) return -1; buf += STATFIXLEN - 4 * BIT16SZ; for(i = 0; i < 4; i++){ if(buf + BIT16SZ > ebuf) return -1; buf += BIT16SZ + GBIT16(buf); } if(buf != ebuf) return -1; return 0; }
void inputthread(void *arg) { uchar *pkt; int n, nn, tag; Msg *m; Ioproc *io; threadsetname("input"); if(verbose) fprint(2, "%T input thread\n"); io = ioproc(); USED(arg); while((pkt = read9ppkt(io, 0)) != nil){ n = GBIT32(pkt); if(n < 7){ fprint(2, "%T short 9P packet from server\n"); free(pkt); continue; } if(verbose > 2) fprint(2, "%T read %.*H\n", n, pkt); tag = GBIT16(pkt+5); if((m = msgget(tag)) == nil){ fprint(2, "%T unexpected 9P response tag %d\n", tag); free(pkt); continue; } if((nn = convM2S(pkt, n, &m->rx)) != n){ fprint(2, "%T bad packet - convM2S %d but %d\n", nn, n); free(pkt); msgput(m); continue; } if(verbose > 1) fprint(2, "%T * -> %F%s\n", &m->rx, m->internal ? " (internal)" : ""); m->rpkt = pkt; m->rx.tag = m->ctag; if(m->internal) sendp(m->c->internal, m); else if(m->c->outq) sendq(m->c->outq, m); else msgput(m); } closeioproc(io); /*fprint(2, "%T input eof\n"); */ threadexitsall(0); }
static u8* gstring(u8 *p, u8 *ep, char **s) { u16 n; if(p+BIT16SZ > ep) return nil; n = GBIT16(p); p += BIT16SZ - 1; if(p+n+1 > ep) return nil; /* move it down, on top of count, to make room for '\0' */ memmove(p, p + 1, n); p[n] = '\0'; *s = (char*)p; p += n+1; return p; }
static int readmsg(Chan *c, void *abuf, int n, int *ninep) { int fd, len; uint8_t *buf; buf = abuf; fd = c->chan; qlock(&c->rlock); if(readn(fd, buf, 3) != 3){ qunlock(&c->rlock); print("readn(3) fails: %r\n"); return -1; } if((50 <= buf[0] && buf[0] <= 87 && (buf[0]&1)==0 && GBIT16(buf+1) == 0xFFFF) || buf[0] == 86 /* Tattach */){ *ninep = 1; /* assume message boundaries */ n = read(fd, buf+3, n-3); if(n < 0){ qunlock(&c->rlock); return -1; } return n+3; } *ninep = 2; if(read(fd, buf+3, 1) != 1){ qunlock(&c->rlock); print("read(1) fails: %r\n"); return -1; } len = GBIT32(buf); if(len > n){ print("msg too large\n"); qunlock(&c->rlock); return -1; } if(readn(fd, buf+4, len-4) != len-4){ print("readn(%d) fails: %r\n", len-4); qunlock(&c->rlock); return -1; } qunlock(&c->rlock); return len; }
static uint8_t *gstring(uint8_t * p, uint8_t * ep, char **s) { unsigned int n; if (p + BIT16SZ > ep) return NULL; n = GBIT16(p); p += BIT16SZ - 1; if (p + n + 1 > ep) return NULL; /* move it down, on top of count, to make room for '\0' */ memmove(p, p + 1, n); p[n] = '\0'; *s = (char *)p; p += n + 1; return p; }
static uchar* gstring(uchar *p, uchar *ep, char **s) { uint n; if(p == nil) return nil; if(p+BIT16SZ > ep) return nil; n = GBIT16(p); p += BIT16SZ; if(p+n > ep) return nil; *s = malloc(n+1); memmove((*s), p, n); (*s)[n] = '\0'; p += n; return p; }
int logfsgn(uchar **pp, uchar *mep, char **v) { uchar *p = *pp; int l; if(p + BIT16SZ > mep) return 0; l = GBIT16(p); p += BIT16SZ; if(p + l > mep) return 0; *pp = p + l; if(l == 0) { *v = 0; return 1; } *v = (char *)(p - 1); memmove(p - 1, p, l); p[l - 1] = 0; return 1; }
static uchar* gcarray(uchar *p, uchar *ep, uchar **s, int *np) { uint n; if(p == nil) return nil; if(p+BIT16SZ > ep) return nil; n = GBIT16(p); p += BIT16SZ; if(p+n > ep) return nil; *s = malloc(n); if(*s == nil) return nil; memmove((*s), p, n); *np = n; p += n; return p; }
static int statcheck(char *buf, uint32_t nbuf) { char *ebuf; int i; ebuf = buf + nbuf; buf += STATFIXLEN - 4 * BIT16SZ; for(i = 0; i < 4; i++){ if(buf + BIT16SZ > ebuf) return -1; buf += BIT16SZ + GBIT16(buf); } if(buf != ebuf) return -1; return 0; }
/* * Satisfy a directory read with the results saved in c->dirrock. */ static int mountrockread(Chan *c, uint8_t *op, int32_t n, int32_t *nn) { int32_t dirlen; uint8_t *rp, *erp, *ep, *p; /* common case */ if(c->nrock == 0) return 0; /* copy out what we can */ qlock(&c->rockqlock); rp = c->dirrock; erp = rp+c->nrock; p = op; ep = p+n; while(rp+BIT16SZ <= erp){ dirlen = BIT16SZ+GBIT16(rp); if(p+dirlen > ep) break; memmove(p, rp, dirlen); p += dirlen; rp += dirlen; } if(p == op){ qunlock(&c->rockqlock); return 0; } /* shift the rest */ if(rp != erp) memmove(c->dirrock, rp, erp-rp); c->nrock = erp - rp; *nn = p - op; qunlock(&c->rockqlock); return 1; }
static int pcicfgrw(Pcidev *pcidev, int rno, int data, int len, int read) { uchar buf[4]; if(read){ memset(buf, 0, sizeof(buf)); if(pread(pcidev->rawfd, buf, len, rno) != len) return -1; switch(len){ case 1: return GBIT8(buf); case 2: return GBIT16(buf); case 4: return GBIT32(buf); default: abort(); } } else { switch(len){ case 1: PBIT8(buf, data); break; case 2: PBIT16(buf, data); break; case 4: PBIT32(buf, data); break; default: abort(); } if(pwrite(pcidev->rawfd, buf, len, rno) != len) return -1; } return 0; }
static int fswstat(Chan *c, uchar *buf, int n) { char *elem, *path, *npath, *strs, *t; int nn; Dir d; UnixFd *ufd; if(n < 2) error(Ebadstat); nn = GBIT16((uchar*)buf); strs = smalloc(nn); if(convM2D(buf, n, &d, strs) != n){ free(strs); error(Ebadstat); } path = fspath(c, nil); if(waserror()){ free(path); free(strs); nexterror(); } if(d.muid[0]) error("cannot change muid"); if(d.uid[0] || d.gid[0]){ int uid, gid; uid = -1; gid = -1; if(d.uid[0] && (uid = nametouid(d.uid)) < 0) error("unknown uid"); if(d.gid[0] && (gid = nametogid(d.gid)) < 0) error("unknown gid"); if(chown(path, uid, gid) < 0) oserror(); } ufd = c->aux; elem = lastelem(path); if(d.name[0] && strcmp(d.name, elem) != 0){ if(strchr(d.name, '/')) error(Ebadarg); npath = smalloc(strlen(path)+strlen(d.name)+1); strcpy(npath, path); t = strrchr(npath, '/'); strcpy(t+1, d.name); if(rename(path, npath) < 0){ free(npath); oserror(); } free(npath); } if(~d.mode != 0 && chmod(path, d.mode&0777) < 0) oserror(); // TODO: Code to change uid, gid. poperror(); return n; }
/* * no syntactic checks. * three causes for error: * 1. message size field is incorrect * 2. input buffer too short for its own data (counts too long, etc.) * 3. too many names or qids * gqid() and gstring() return nil if they would reach beyond buffer. * main switch statement checks range and also can fall through * to test at end of routine. */ uint convM2S(uchar *ap, uint nap, Fcall *f) { uchar *p, *ep; uint i, size; p = ap; ep = p + nap; if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) return 0; size = GBIT32(p); p += BIT32SZ; if(size < BIT32SZ+BIT8SZ+BIT16SZ) return 0; f->type = GBIT8(p); p += BIT8SZ; f->tag = GBIT16(p); p += BIT16SZ; switch(f->type) { default: return 0; case Tversion: if(p+BIT32SZ > ep) return 0; f->msize = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->version); break; case Tflush: if(p+BIT16SZ > ep) return 0; f->oldtag = GBIT16(p); p += BIT16SZ; break; case Tauth: if(p+BIT32SZ > ep) return 0; f->afid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->uname); if(p == nil) break; p = gstring(p, ep, &f->aname); if(p == nil) break; break; case Tattach: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; if(p+BIT32SZ > ep) return 0; f->afid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->uname); if(p == nil) break; p = gstring(p, ep, &f->aname); if(p == nil) break; break; case Twalk: if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->newfid = GBIT32(p); p += BIT32SZ; f->nwname = GBIT16(p); p += BIT16SZ; if(f->nwname > MAXWELEM) return 0; for(i=0; i<f->nwname; i++){ p = gstring(p, ep, &f->wname[i]); if(p == nil) break; } break; case Topen: if(p+BIT32SZ+BIT8SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->mode = GBIT8(p); p += BIT8SZ; break; case Tcreate: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->name); if(p == nil) break; if(p+BIT32SZ+BIT8SZ > ep) return 0; f->perm = GBIT32(p); p += BIT32SZ; f->mode = GBIT8(p); p += BIT8SZ; break; case Tread: if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->offset = GBIT64(p); p += BIT64SZ; f->count = GBIT32(p); p += BIT32SZ; break; case Twrite: if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->offset = GBIT64(p); p += BIT64SZ; f->count = GBIT32(p); p += BIT32SZ; if(p+f->count > ep) return 0; f->data = (char*)p; p += f->count; break; case Tclunk: case Tremove: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; break; case Tstat: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; break; case Twstat: if(p+BIT32SZ+BIT16SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->nstat = GBIT16(p); p += BIT16SZ; if(p+f->nstat > ep) return 0; f->stat = p; p += f->nstat; break; /* */ case Rversion: if(p+BIT32SZ > ep) return 0; f->msize = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->version); break; case Rerror: p = gstring(p, ep, &f->ename); break; case Rflush: break; case Rauth: p = gqid(p, ep, &f->aqid); if(p == nil) break; break; case Rattach: p = gqid(p, ep, &f->qid); if(p == nil) break; break; case Rwalk: if(p+BIT16SZ > ep) return 0; f->nwqid = GBIT16(p); p += BIT16SZ; if(f->nwqid > MAXWELEM) return 0; for(i=0; i<f->nwqid; i++){ p = gqid(p, ep, &f->wqid[i]); if(p == nil) break; } break; case Ropen: case Rcreate: p = gqid(p, ep, &f->qid); if(p == nil) break; if(p+BIT32SZ > ep) return 0; f->iounit = GBIT32(p); p += BIT32SZ; break; case Rread: if(p+BIT32SZ > ep) return 0; f->count = GBIT32(p); p += BIT32SZ; if(p+f->count > ep) return 0; f->data = (char*)p; p += f->count; break; case Rwrite: if(p+BIT32SZ > ep) return 0; f->count = GBIT32(p); p += BIT32SZ; break; case Rclunk: case Rremove: break; case Rstat: if(p+BIT16SZ > ep) return 0; f->nstat = GBIT16(p); p += BIT16SZ; if(p+f->nstat > ep) return 0; f->stat = p; p += f->nstat; break; case Rwstat: break; } if(p==nil || p>ep) return 0; if(ap+size == p) return size; return 0; }
uint _convM2D(uint8_t *buf, uint nbuf, Dir *d, char *strs) { uint8_t *p, *ebuf; char *sv[4]; int i, ns, nsv[4]; p = buf; ebuf = buf + nbuf; p += BIT16SZ; /* ignore size */ d->type = GBIT16(p); p += BIT16SZ; d->dev = GBIT32(p); p += BIT32SZ; d->qid.type = GBIT8(p); p += BIT8SZ; d->qid.vers = GBIT32(p); p += BIT32SZ; d->qid.path = GBIT64(p); p += BIT64SZ; d->mode = GBIT32(p); p += BIT32SZ; d->atime = GBIT32(p); p += BIT32SZ; d->mtime = GBIT32(p); p += BIT32SZ; d->length = GBIT64(p); p += BIT64SZ; d->name = nil; d->uid = nil; d->gid = nil; d->muid = nil; for(i = 0; i < 4; i++){ if(p + BIT16SZ > ebuf) return 0; ns = GBIT16(p); p += BIT16SZ; if(p + ns > ebuf) return 0; if(strs){ nsv[i] = ns; sv[i] = strs; memmove(strs, p, ns); strs += ns; *strs++ = '\0'; } p += ns; } if(strs){ d->name = sv[0]; d->uid = sv[1]; d->gid = sv[2]; d->muid = sv[3]; }else{ d->name = nullstring; d->uid = nullstring; d->gid = nullstring; d->muid = nullstring; } return p - buf; }
u16 convM2S(u8 *ap, u16 nap, estyx_fcall_t *f) { u8 *p, *ep; u16 i, size; p = ap; ep = p + nap; if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) return 0; size = GBIT32(p); p += BIT32SZ; if (size<BIT32SZ+BIT8SZ+BIT16SZ) return 0; f->type = GBIT8(p); p += BIT8SZ; f->tag = GBIT16(p); p += BIT16SZ; switch(f->type) { default: return 0; case Tversion: if(p+BIT32SZ > ep) return 0; f->u.version.msize = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->u.version.version); break; case Tflush: if(p+BIT16SZ > ep) return 0; f->u.oldtag = GBIT16(p); p += BIT16SZ; break; case Tauth: if(p+BIT32SZ > ep) return 0; f->u.attach.afid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->u.attach.uname); if(p == nil) break; p = gstring(p, ep, &f->u.attach.aname); if(p == nil) break; break; case Tattach: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; if(p+BIT32SZ > ep) return 0; f->u.attach.afid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->u.attach.uname); if(p == nil) break; p = gstring(p, ep, &f->u.attach.aname); if(p == nil) break; break; case Twalk: if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->u.twalk.newfid = GBIT32(p); p += BIT32SZ; f->u.twalk.nwname = GBIT16(p); p += BIT16SZ; if(f->u.twalk.nwname > MAXWELEM) return 0; for(i=0; i<f->u.twalk.nwname; i++){ p = gstring(p, ep, &f->u.twalk.wname[i]); if(p == nil) break; } break; case Topen: if(p+BIT32SZ+BIT8SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->u.create.mode = GBIT8(p); p += BIT8SZ; break; case Tcreate: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->u.create.name); if(p == nil) break; if(p+BIT32SZ+BIT8SZ > ep) return 0; f->u.create.perm = GBIT32(p); p += BIT32SZ; f->u.create.mode = GBIT8(p); p += BIT8SZ; break; case Tread: if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->u.rw.offset = GBIT32(p); p += BIT64SZ; f->u.rw.count = GBIT32(p); p += BIT32SZ; break; case Twrite: if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->u.rw.offset = GBIT32(p); p += BIT64SZ; f->u.rw.count = GBIT32(p); p += BIT32SZ; if(p+f->u.rw.count > ep) return 0; f->u.rw.data = p; p += f->u.rw.count; break; case Tclunk: case Tremove: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; break; case Tstat: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; break; case Twstat: if(p+BIT32SZ+BIT16SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->u.stat.nstat = GBIT16(p); p += BIT16SZ; if(p+f->u.stat.nstat > ep) return 0; f->u.stat.stat = p; p += f->u.stat.nstat; break; #if 0 // we never receive R packets so no need for this /* */ case Rversion: if(p+BIT32SZ > ep) return 0; f->u.version.msize = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->u.version.version); break; case Rerror: p = gstring(p, ep, &f->u.ename); break; case Rflush: break; case Rauth: p = gqid(p, ep, &f->u.aqid); if(p == nil) break; break; case Rattach: p = gqid(p, ep, &f->u.open.qid); if(p == nil) break; break; case Rwalk: if(p+BIT16SZ > ep) return 0; f->u.rwalk.nwqid = GBIT16(p); p += BIT16SZ; if(f->u.rwalk.nwqid > MAXWELEM) return 0; for(i=0; i<f->u.rwalk.nwqid; i++){ p = gqid(p, ep, &f->u.rwalk.wqid[i]); if(p == nil) break; } break; case Ropen: case Rcreate: p = gqid(p, ep, &f->u.open.qid); if(p == nil) break; if(p+BIT32SZ > ep) return 0; f->u.open.iounit = GBIT32(p); p += BIT32SZ; break; case Rread: if(p+BIT32SZ > ep) return 0; f->u.rw.count = GBIT32(p); p += BIT32SZ; if(p+f->u.rw.count > ep) return 0; f->u.rw.data = data; p += f->u.rw.count; break; case Rwrite: if(p+BIT32SZ > ep) return 0; f->u.rw.count = GBIT32(p); p += BIT32SZ; break; case Rclunk: case Rremove: break; case Rstat: if(p+BIT16SZ > ep) return 0; f->u.stat.nstat = GBIT16(p); p += BIT16SZ; if(p+f->u.stat.nstat > ep) return 0; f->u.stat.stat = p; p += f->u.stat.nstat; break; case Rwstat: break; #endif } if(p==nil || p>ep) return 0; if(ap+size == p) return size; return 0; }
unsigned int convM2kdirent(uint8_t * buf, unsigned int nbuf, struct kdirent *kd, char *strs) { uint8_t *p, *ebuf; char *sv[4]; int i, ns; uint32_t junk; printd("%s >>>>>>>>>nbuf %d STATFIXLEN %d\n", __func__, nbuf, STATFIXLEN); if (nbuf < STATFIXLEN) return 0; p = buf; ebuf = buf + nbuf; p += BIT16SZ; /* ignore size */ kd->d_type = GBIT16(p); p += BIT16SZ; junk = GBIT32(p); p += BIT32SZ; junk = GBIT8(p); p += BIT8SZ; junk = GBIT32(p); p += BIT32SZ; kd->d_ino = GBIT64(p); p += BIT64SZ; junk /* mode */ = GBIT32(p); p += BIT32SZ; junk /*d->atime */ = GBIT32(p); p += BIT32SZ; junk /*d->mtime */ = GBIT32(p); p += BIT32SZ; junk /*d->length */ = GBIT64(p); p += BIT64SZ; /* for now, uids in akaros are ints. Does not * matter; kdirents are limited in what they tell you. * get the name, ignore the rest. Maybe we can * fix this later. */ for (i = 0; i < 4; i++) { if (p + BIT16SZ > ebuf) return 0; ns = GBIT16(p); p += BIT16SZ; if (p + ns > ebuf) return 0; if (strs) { sv[i] = strs; memmove(strs, p, ns); strs += ns; *strs++ = '\0'; } if (i == 0) { kd->d_reclen = ns; printd("memmove %p %p %d\n", kd->d_name, p, ns); memmove(kd->d_name, p, ns); kd->d_name[ns] = 0; } p += ns; } printd("%s returns %d %s\n", __func__, p - buf, kd->d_name); return p - buf; }