/* * 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 "stdinc.h"#include "dat.h"#include "fns.h" /* * disk structure conversion routines */#define U8GET(p) ((p)[0])#define U16GET(p) (((p)[0]<<8)|(p)[1])#define U32GET(p) ((u32int)(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3]))#define U64GET(p) (((u64int)U32GET(p)<<32)|(u64int)U32GET((p)+4)) #define U8PUT(p,v) (p)[0]=(v)&0xFF#define U16PUT(p,v) (p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF#define U32PUT(p,v) (p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF#define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32) int debugarena = -1; /* hack to improve error reporting */ static struct { u32int m; char *s;} magics[] = { ArenaPartMagic, "ArenaPartMagic", ArenaHeadMagic, "ArenaHeadMagic", ArenaMagic, "ArenaMagic", ISectMagic, "ISectMagic", BloomMagic, "BloomMagic",}; static char*fmtmagic(char *s, u32int m){ int i; for(i=0; i<nelem(magics); i++) if(magics[i].m == m) return magics[i].s; sprint(s, "%#08ux", m); return s;} u32intunpackmagic(u8int *buf){ return U32GET(buf);} voidpackmagic(u32int magic, u8int *buf){ U32PUT(buf, magic);} intunpackarenapart(ArenaPart *ap, u8int *buf){ u8int *p; u32int m; char fbuf[20]; p = buf; m = U32GET(p); if(m != ArenaPartMagic){ seterr(ECorrupt, "arena set has wrong magic number: %s expected ArenaPartMagic (%#lux)", fmtmagic(fbuf, m), ArenaPartMagic); return -1; } p += U32Size; ap->version = U32GET(p); p += U32Size; ap->blocksize = U32GET(p); p += U32Size; ap->arenabase = U32GET(p); p += U32Size; if(buf + ArenaPartSize != p) sysfatal("unpackarenapart unpacked wrong amount"); return 0;} intpackarenapart(ArenaPart *ap, u8int *buf){ u8int *p; p = buf; U32PUT(p, ArenaPartMagic); p += U32Size; U32PUT(p, ap->version); p += U32Size; U32PUT(p, ap->blocksize); p += U32Size; U32PUT(p, ap->arenabase); p += U32Size; if(buf + ArenaPartSize != p) sysfatal("packarenapart packed wrong amount"); return 0;} intunpackarena(Arena *arena, u8int *buf){ int sz; u8int *p; u32int m; char fbuf[20]; p = buf; m = U32GET(p); if(m != ArenaMagic){ seterr(ECorrupt, "arena %d has wrong magic number: %s " "expected ArenaMagic (%#lux)", debugarena, fmtmagic(fbuf, m), ArenaMagic); return -1; } p += U32Size; arena->version = U32GET(p); p += U32Size; namecp(arena->name, (char*)p); p += ANameSize; arena->diskstats.clumps = U32GET(p); p += U32Size; arena->diskstats.cclumps = U32GET(p); p += U32Size; arena->ctime = U32GET(p); p += U32Size; arena->wtime = U32GET(p); p += U32Size; if(arena->version == ArenaVersion5){ arena->clumpmagic = U32GET(p); p += U32Size; } arena->diskstats.used = U64GET(p); p += U64Size; arena->diskstats.uncsize = U64GET(p); p += U64Size; arena->diskstats.sealed = U8GET(p); p += U8Size; switch(arena->version){ case ArenaVersion4: sz = ArenaSize4; arena->clumpmagic = _ClumpMagic; break; case ArenaVersion5: sz = ArenaSize5; break; default: seterr(ECorrupt, "arena has bad version number %d", arena->version); return -1; } /* * Additional fields for the memstats version of the stats. * Diskstats reflects what is committed to the index. * Memstats reflects what is in the arena. Originally intended * this to be a version 5 extension, but might as well use for * all the existing version 4 arenas too. * * To maintain backwards compatibility with existing venti * installations using the older format, we define that if * memstats == diskstats, then the extension fields are not * included (see packarena below). That is, only partially * indexed arenas have these fields. Fully indexed arenas * (in particular, sealed arenas) do not. */ if(U8GET(p) == 1){ sz += ArenaSize5a-ArenaSize5; p += U8Size; arena->memstats.clumps = U32GET(p); p += U32Size; arena->memstats.cclumps = U32GET(p); p += U32Size; arena->memstats.used = U64GET(p); p += U64Size; arena->memstats.uncsize = U64GET(p); p += U64Size; arena->memstats.sealed = U8GET(p); p += U8Size; /* * 2008/4/2 * Packarena (below) used to have a bug in which it would * not zero out any existing extension fields when writing * the arena metadata. This would manifest itself as arenas * with arena->diskstats.sealed == 1 but arena->memstats.sealed == 0 * after a server restart. Because arena->memstats.sealed wouldn't * be set, the server might try to fit another block into the arena * (and succeed), violating the append-only structure of the log * and invalidating any already-computed seal on the arena. * * It might end up that other fields in arena->memstats end up * behind arena->diskstats too, but that would be considerably * more rare, and the bug is fixed now. The case we need to * handle is just the sealed mismatch. * * If we encounter such a bogus arena, fix the sealed field. */ if(arena->diskstats.sealed) arena->memstats.sealed = 1; }else arena->memstats = arena->diskstats; if(buf + sz != p) sysfatal("unpackarena unpacked wrong amount"); return 0;} intpackarena(Arena *arena, u8int *buf){ return _packarena(arena, buf, 0);} int_packarena(Arena *arena, u8int *buf, int forceext){ int sz; u8int *p; u32int t32; switch(arena->version){ case ArenaVersion4: sz = ArenaSize4; if(arena->clumpmagic != _ClumpMagic) fprint(2, "warning: writing old arena tail loses clump magic 0x%lux != 0x%lux\n", (ulong)arena->clumpmagic, (ulong)_ClumpMagic); break; case ArenaVersion5: sz = ArenaSize5; break; default: sysfatal("packarena unknown version %d", arena->version); return -1; } p = buf; U32PUT(p, ArenaMagic); p += U32Size; U32PUT(p, arena->version); p += U32Size; namecp((char*)p, arena->name); p += ANameSize; U32PUT(p, arena->diskstats.clumps); p += U32Size; U32PUT(p, arena->diskstats.cclumps); p += U32Size; U32PUT(p, arena->ctime); p += U32Size; U32PUT(p, arena->wtime); p += U32Size; if(arena->version == ArenaVersion5){ U32PUT(p, arena->clumpmagic); p += U32Size; } U64PUT(p, arena->diskstats.used, t32); p += U64Size; U64PUT(p, arena->diskstats.uncsize, t32); p += U64Size; U8PUT(p, arena->diskstats.sealed); p += U8Size; /* * Extension fields; see above. */ if(forceext || arena->memstats.clumps != arena->diskstats.clumps || arena->memstats.cclumps != arena->diskstats.cclumps || arena->memstats.used != arena->diskstats.used || arena->memstats.uncsize != arena->diskstats.uncsize || arena->memstats.sealed != arena->diskstats.sealed){ sz += ArenaSize5a - ArenaSize5; U8PUT(p, 1); p += U8Size; U32PUT(p, arena->memstats.clumps); p += U32Size; U32PUT(p, arena->memstats.cclumps); p += U32Size; U64PUT(p, arena->memstats.used, t32); p += U64Size; U64PUT(p, arena->memstats.uncsize, t32); p += U64Size; U8PUT(p, arena->memstats.sealed); p += U8Size; }else{ /* Clear any extension fields already on disk. */ memset(p, 0, ArenaSize5a - ArenaSize5); p += ArenaSize5a - ArenaSize5; sz += ArenaSize5a - ArenaSize5; } if(buf + sz != p) sysfatal("packarena packed wrong amount"); return 0;} intunpackarenahead(ArenaHead *head, u8int *buf){ u8int *p; u32int m; int sz; char fbuf[20]; p = buf; m = U32GET(p); if(m != ArenaHeadMagic){ seterr(ECorrupt, "arena %d head has wrong magic number: %s " "expected ArenaHeadMagic (%#lux)", debugarena, fmtmagic(fbuf, m), ArenaHeadMagic); return -1; } p += U32Size; head->version = U32GET(p); p += U32Size; namecp(head->name, (char*)p); p += ANameSize; head->blocksize = U32GET(p); p += U32Size; head->size = U64GET(p); p += U64Size; if(head->version == ArenaVersion5){ head->clumpmagic = U32GET(p); p += U32Size; } switch(head->version){ case ArenaVersion4: sz = ArenaHeadSize4; head->clumpmagic = _ClumpMagic; break; case ArenaVersion5: sz = ArenaHeadSize5; break; default: seterr(ECorrupt, "arena head has unexpected version %d", head->version); return -1; } if(buf + sz != p) sysfatal("unpackarenahead unpacked wrong amount"); return 0;} intpackarenahead(ArenaHead *head, u8int *buf){ u8int *p; int sz; u32int t32; switch(head->version){ case ArenaVersion4: sz = ArenaHeadSize4; if(head->clumpmagic != _ClumpMagic) fprint(2, "warning: writing old arena header loses clump magic 0x%lux != 0x%lux\n", (ulong)head->clumpmagic, (ulong)_ClumpMagic); break; case ArenaVersion5: sz = ArenaHeadSize5; break; default: sysfatal("packarenahead unknown version %d", head->version); return -1; } p = buf; U32PUT(p, ArenaHeadMagic); p += U32Size; U32PUT(p, head->version); p += U32Size; namecp((char*)p, head->name); p += ANameSize; U32PUT(p, head->blocksize); p += U32Size; U64PUT(p, head->size, t32); p += U64Size; if(head->version == ArenaVersion5){ U32PUT(p, head->clumpmagic); p += U32Size; } if(buf + sz != p) sysfatal("packarenahead packed wrong amount"); return 0;} static intcheckclump(Clump *w){ if(w->encoding == ClumpENone){ if(w->info.size != w->info.uncsize){ seterr(ECorrupt, "uncompressed wad size mismatch"); return -1; } }else if(w->encoding == ClumpECompress){ if(w->info.size >= w->info.uncsize){ seterr(ECorrupt, "compressed lump has inconsistent block sizes %d %d", w->info.size, w->info.uncsize); return -1; } }else{ seterr(ECorrupt, "clump has illegal encoding"); return -1; } return 0;} intunpackclump(Clump *c, u8int *buf, u32int cmagic){ u8int *p; u32int magic; p = buf; magic = U32GET(p); if(magic != cmagic){ seterr(ECorrupt, "clump has bad magic number=%#8.8ux != %#8.8ux", magic, cmagic); return -1; } p += U32Size; c->info.type = vtfromdisktype(U8GET(p)); p += U8Size; c->info.size = U16GET(p); p += U16Size; c->info.uncsize = U16GET(p); p += U16Size; scorecp(c->info.score, p); p += VtScoreSize; c->encoding = U8GET(p); p += U8Size; c->creator = U32GET(p); p += U32Size; c->time = U32GET(p); p += U32Size; if(buf + ClumpSize != p) sysfatal("unpackclump unpacked wrong amount"); return checkclump(c);} intpackclump(Clump *c, u8int *buf, u32int magic){ u8int *p; p = buf; U32PUT(p, magic); p += U32Size; U8PUT(p, vttodisktype(c->info.type)); p += U8Size; U16PUT(p, c->info.size); p += U16Size; U16PUT(p, c->info.uncsize); p += U16Size; scorecp(p, c->info.score); p += VtScoreSize; U8PUT(p, c->encoding); p += U8Size; U32PUT(p, c->creator); p += U32Size; U32PUT(p, c->time); p += U32Size; if(buf + ClumpSize != p) sysfatal("packclump packed wrong amount"); return checkclump(c);} voidunpackclumpinfo(ClumpInfo *ci, u8int *buf){ u8int *p; p = buf;Lines 1–500 of 739. Load more
/* * 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 "stdinc.h" #include "dat.h" #include "fns.h" /* * disk structure conversion routines */ #define U8GET(p) ((p)[0]) #define U16GET(p) (((p)[0]<<8)|(p)[1]) #define U32GET(p) ((u32int)(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])) #define U64GET(p) (((u64int)U32GET(p)<<32)|(u64int)U32GET((p)+4)) #define U8PUT(p,v) (p)[0]=(v)&0xFF #define U16PUT(p,v) (p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF #define U32PUT(p,v) (p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32) int debugarena = -1; /* hack to improve error reporting */ static struct { u32int m; char *s; } magics[] = { ArenaPartMagic, "ArenaPartMagic", ArenaHeadMagic, "ArenaHeadMagic", ArenaMagic, "ArenaMagic", ISectMagic, "ISectMagic", BloomMagic, "BloomMagic", }; static char* fmtmagic(char *s, u32int m) { int i; for(i=0; i<nelem(magics); i++) if(magics[i].m == m) return magics[i].s; sprint(s, "%#08ux", m); return s; } u32int unpackmagic(u8int *buf) { return U32GET(buf); } void packmagic(u32int magic, u8int *buf) { U32PUT(buf, magic); } int unpackarenapart(ArenaPart *ap, u8int *buf) { u8int *p; u32int m; char fbuf[20]; p = buf; m = U32GET(p); if(m != ArenaPartMagic){ seterr(ECorrupt, "arena set has wrong magic number: %s expected ArenaPartMagic (%#lux)", fmtmagic(fbuf, m), ArenaPartMagic); return -1; } p += U32Size; ap->version = U32GET(p); p += U32Size; ap->blocksize = U32GET(p); p += U32Size; ap->arenabase = U32GET(p); p += U32Size; if(buf + ArenaPartSize != p) sysfatal("unpackarenapart unpacked wrong amount"); return 0; } int packarenapart(ArenaPart *ap, u8int *buf) { u8int *p; p = buf; U32PUT(p, ArenaPartMagic); p += U32Size; U32PUT(p, ap->version); p += U32Size; U32PUT(p, ap->blocksize); p += U32Size; U32PUT(p, ap->arenabase); p += U32Size; if(buf + ArenaPartSize != p) sysfatal("packarenapart packed wrong amount"); return 0; } int unpackarena(Arena *arena, u8int *buf) { int sz; u8int *p; u32int m; char fbuf[20]; p = buf; m = U32GET(p); if(m != ArenaMagic){ seterr(ECorrupt, "arena %d has wrong magic number: %s " "expected ArenaMagic (%#lux)", debugarena, fmtmagic(fbuf, m), ArenaMagic); return -1; } p += U32Size; arena->version = U32GET(p); p += U32Size; namecp(arena->name, (char*)p); p += ANameSize; arena->diskstats.clumps = U32GET(p); p += U32Size; arena->diskstats.cclumps = U32GET(p); p += U32Size; arena->ctime = U32GET(p); p += U32Size; arena->wtime = U32GET(p); p += U32Size; if(arena->version == ArenaVersion5){ arena->clumpmagic = U32GET(p); p += U32Size; } arena->diskstats.used = U64GET(p); p += U64Size; arena->diskstats.uncsize = U64GET(p); p += U64Size; arena->diskstats.sealed = U8GET(p); p += U8Size; switch(arena->version){ case ArenaVersion4: sz = ArenaSize4; arena->clumpmagic = _ClumpMagic; break; case ArenaVersion5: sz = ArenaSize5; break; default: seterr(ECorrupt, "arena has bad version number %d", arena->version); return -1; } /* * Additional fields for the memstats version of the stats. * Diskstats reflects what is committed to the index. * Memstats reflects what is in the arena. Originally intended * this to be a version 5 extension, but might as well use for * all the existing version 4 arenas too. * * To maintain backwards compatibility with existing venti * installations using the older format, we define that if * memstats == diskstats, then the extension fields are not * included (see packarena below). That is, only partially * indexed arenas have these fields. Fully indexed arenas * (in particular, sealed arenas) do not. */ if(U8GET(p) == 1){ sz += ArenaSize5a-ArenaSize5; p += U8Size; arena->memstats.clumps = U32GET(p); p += U32Size; arena->memstats.cclumps = U32GET(p); p += U32Size; arena->memstats.used = U64GET(p); p += U64Size; arena->memstats.uncsize = U64GET(p); p += U64Size; arena->memstats.sealed = U8GET(p); p += U8Size; /* * 2008/4/2 * Packarena (below) used to have a bug in which it would * not zero out any existing extension fields when writing * the arena metadata. This would manifest itself as arenas * with arena->diskstats.sealed == 1 but arena->memstats.sealed == 0 * after a server restart. Because arena->memstats.sealed wouldn't * be set, the server might try to fit another block into the arena * (and succeed), violating the append-only structure of the log * and invalidating any already-computed seal on the arena. * * It might end up that other fields in arena->memstats end up * behind arena->diskstats too, but that would be considerably * more rare, and the bug is fixed now. The case we need to * handle is just the sealed mismatch. * * If we encounter such a bogus arena, fix the sealed field. */ if(arena->diskstats.sealed) arena->memstats.sealed = 1; }else arena->memstats = arena->diskstats; if(buf + sz != p) sysfatal("unpackarena unpacked wrong amount"); return 0; } int packarena(Arena *arena, u8int *buf) { return _packarena(arena, buf, 0); } int _packarena(Arena *arena, u8int *buf, int forceext) { int sz; u8int *p; u32int t32; switch(arena->version){ case ArenaVersion4: sz = ArenaSize4; if(arena->clumpmagic != _ClumpMagic) fprint(2, "warning: writing old arena tail loses clump magic 0x%lux != 0x%lux\n", (ulong)arena->clumpmagic, (ulong)_ClumpMagic); break; case ArenaVersion5: sz = ArenaSize5; break; default: sysfatal("packarena unknown version %d", arena->version); return -1; } p = buf; U32PUT(p, ArenaMagic); p += U32Size; U32PUT(p, arena->version); p += U32Size; namecp((char*)p, arena->name); p += ANameSize; U32PUT(p, arena->diskstats.clumps); p += U32Size; U32PUT(p, arena->diskstats.cclumps); p += U32Size; U32PUT(p, arena->ctime); p += U32Size; U32PUT(p, arena->wtime); p += U32Size; if(arena->version == ArenaVersion5){ U32PUT(p, arena->clumpmagic); p += U32Size; } U64PUT(p, arena->diskstats.used, t32); p += U64Size; U64PUT(p, arena->diskstats.uncsize, t32); p += U64Size; U8PUT(p, arena->diskstats.sealed); p += U8Size; /* * Extension fields; see above. */ if(forceext || arena->memstats.clumps != arena->diskstats.clumps || arena->memstats.cclumps != arena->diskstats.cclumps || arena->memstats.used != arena->diskstats.used || arena->memstats.uncsize != arena->diskstats.uncsize || arena->memstats.sealed != arena->diskstats.sealed){ sz += ArenaSize5a - ArenaSize5; U8PUT(p, 1); p += U8Size; U32PUT(p, arena->memstats.clumps); p += U32Size; U32PUT(p, arena->memstats.cclumps); p += U32Size; U64PUT(p, arena->memstats.used, t32); p += U64Size; U64PUT(p, arena->memstats.uncsize, t32); p += U64Size; U8PUT(p, arena->memstats.sealed); p += U8Size; }else{ /* Clear any extension fields already on disk. */ memset(p, 0, ArenaSize5a - ArenaSize5); p += ArenaSize5a - ArenaSize5; sz += ArenaSize5a - ArenaSize5; } if(buf + sz != p) sysfatal("packarena packed wrong amount"); return 0; } int unpackarenahead(ArenaHead *head, u8int *buf) { u8int *p; u32int m; int sz; char fbuf[20]; p = buf; m = U32GET(p); if(m != ArenaHeadMagic){ seterr(ECorrupt, "arena %d head has wrong magic number: %s " "expected ArenaHeadMagic (%#lux)", debugarena, fmtmagic(fbuf, m), ArenaHeadMagic); return -1; } p += U32Size; head->version = U32GET(p); p += U32Size; namecp(head->name, (char*)p); p += ANameSize; head->blocksize = U32GET(p); p += U32Size; head->size = U64GET(p); p += U64Size; if(head->version == ArenaVersion5){ head->clumpmagic = U32GET(p); p += U32Size; } switch(head->version){ case ArenaVersion4: sz = ArenaHeadSize4; head->clumpmagic = _ClumpMagic; break; case ArenaVersion5: sz = ArenaHeadSize5; break; default: seterr(ECorrupt, "arena head has unexpected version %d", head->version); return -1; } if(buf + sz != p) sysfatal("unpackarenahead unpacked wrong amount"); return 0; } int packarenahead(ArenaHead *head, u8int *buf) { u8int *p; int sz; u32int t32; switch(head->version){ case ArenaVersion4: sz = ArenaHeadSize4; if(head->clumpmagic != _ClumpMagic) fprint(2, "warning: writing old arena header loses clump magic 0x%lux != 0x%lux\n", (ulong)head->clumpmagic, (ulong)_ClumpMagic); break; case ArenaVersion5: sz = ArenaHeadSize5; break; default: sysfatal("packarenahead unknown version %d", head->version); return -1; } p = buf; U32PUT(p, ArenaHeadMagic); p += U32Size; U32PUT(p, head->version); p += U32Size; namecp((char*)p, head->name); p += ANameSize; U32PUT(p, head->blocksize); p += U32Size; U64PUT(p, head->size, t32); p += U64Size; if(head->version == ArenaVersion5){ U32PUT(p, head->clumpmagic); p += U32Size; } if(buf + sz != p) sysfatal("packarenahead packed wrong amount"); return 0; } static int checkclump(Clump *w) { if(w->encoding == ClumpENone){ if(w->info.size != w->info.uncsize){ seterr(ECorrupt, "uncompressed wad size mismatch"); return -1; } }else if(w->encoding == ClumpECompress){ if(w->info.size >= w->info.uncsize){ seterr(ECorrupt, "compressed lump has inconsistent block sizes %d %d", w->info.size, w->info.uncsize); return -1; } }else{ seterr(ECorrupt, "clump has illegal encoding"); return -1; } return 0; } int unpackclump(Clump *c, u8int *buf, u32int cmagic) { u8int *p; u32int magic; p = buf; magic = U32GET(p); if(magic != cmagic){ seterr(ECorrupt, "clump has bad magic number=%#8.8ux != %#8.8ux", magic, cmagic); return -1; } p += U32Size; c->info.type = vtfromdisktype(U8GET(p)); p += U8Size; c->info.size = U16GET(p); p += U16Size; c->info.uncsize = U16GET(p); p += U16Size; scorecp(c->info.score, p); p += VtScoreSize; c->encoding = U8GET(p); p += U8Size; c->creator = U32GET(p); p += U32Size; c->time = U32GET(p); p += U32Size; if(buf + ClumpSize != p) sysfatal("unpackclump unpacked wrong amount"); return checkclump(c); } int packclump(Clump *c, u8int *buf, u32int magic) { u8int *p; p = buf; U32PUT(p, magic); p += U32Size; U8PUT(p, vttodisktype(c->info.type)); p += U8Size; U16PUT(p, c->info.size); p += U16Size; U16PUT(p, c->info.uncsize); p += U16Size; scorecp(p, c->info.score); p += VtScoreSize; U8PUT(p, c->encoding); p += U8Size; U32PUT(p, c->creator); p += U32Size; U32PUT(p, c->time); p += U32Size; if(buf + ClumpSize != p) sysfatal("packclump packed wrong amount"); return checkclump(c); } void unpackclumpinfo(ClumpInfo *ci, u8int *buf) { u8int *p; p = buf;