blob: 5e9a7c1fe8e25eaf7f9b6bb384afc7e9221c8c82 [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <venti.h>
#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;
}