#include #include #include #include "cvt.h" static int checksize(int n) { if(n < 256) { werrstr("bad block size %#ux", n); return -1; } return 0; } // _VtEntryBig integer format is floating-point: // (n>>5) << (n&31). // Convert this number; must be exact or return -1. int vttobig(ulong n) { int shift; ulong n0; n0 = n; shift = 0; while(n >= (1<<(16 - 5))) { if(n & 1) return -1; shift++; n >>= 1; } n = (n<<5) | shift; if(((n>>5)<<(n&31)) != n0) sysfatal("vttobig %#lux => %#lux failed", n0, n); return n; } void vtentrypack(VtEntry *e, uchar *p, int index) { ulong t32; int flags; uchar *op; int depth; int psize, dsize; p += index * VtEntrySize; op = p; depth = e->type&VtTypeDepthMask; flags = (e->flags&~(_VtEntryDir|_VtEntryDepthMask)); flags |= depth << _VtEntryDepthShift; if(e->type - depth == VtDirType) flags |= _VtEntryDir; U32PUT(p, e->gen); p += 4; psize = e->psize; dsize = e->dsize; if(psize >= (1<<16) || dsize >= (1<<16)) { flags |= _VtEntryBig; psize = vttobig(psize); dsize = vttobig(dsize); if(psize < 0 || dsize < 0) sysfatal("invalid entry psize/dsize: %ld/%ld", e->psize, e->dsize); } U16PUT(p, psize); p += 2; U16PUT(p, dsize); p += 2; U8PUT(p, flags); p++; memset(p, 0, 5); p += 5; U48PUT(p, e->size, t32); p += 6; memmove(p, e->score, VtScoreSize); p += VtScoreSize; assert(p-op == VtEntrySize); } int vtentryunpack(VtEntry *e, uchar *p, int index) { uchar *op; p += index * VtEntrySize; op = p; e->gen = U32GET(p); p += 4; e->psize = U16GET(p); p += 2; e->dsize = U16GET(p); p += 2; e->flags = U8GET(p); p++; if(e->flags & _VtEntryBig) { e->psize = (e->psize>>5)<<(e->psize & 31); e->dsize = (e->dsize>>5)<<(e->dsize & 31); } e->type = (e->flags&_VtEntryDir) ? VtDirType : VtDataType; e->type += (e->flags & _VtEntryDepthMask) >> _VtEntryDepthShift; e->flags &= ~(_VtEntryDir|_VtEntryDepthMask|_VtEntryBig); p += 5; e->size = U48GET(p); p += 6; memmove(e->score, p, VtScoreSize); p += VtScoreSize; assert(p-op == VtEntrySize); if(!(e->flags & VtEntryActive)) return 0; /* * Some old vac files use psize==0 and dsize==0 when the * file itself has size 0 or is zeros. Just to make programs not * have to figure out what block sizes of 0 means, rewrite them. */ if(e->psize == 0 && e->dsize == 0 && memcmp(e->score, vtzeroscore, VtScoreSize) == 0){ e->psize = 4096; e->dsize = 4096; } if(checksize(e->psize) < 0 || checksize(e->dsize) < 0) return -1; return 0; }