2003-11-23 17:55:34 +00:00
|
|
|
#include "stdinc.h"
|
|
|
|
#include "vac.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "error.h"
|
|
|
|
|
|
|
|
typedef struct MetaChunk MetaChunk;
|
|
|
|
|
|
|
|
struct MetaChunk {
|
|
|
|
ushort offset;
|
|
|
|
ushort size;
|
|
|
|
ushort index;
|
|
|
|
};
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
static int stringunpack(char **s, uchar **p, int *n);
|
2003-11-23 17:55:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* integer conversion routines
|
|
|
|
*/
|
|
|
|
#define U8GET(p) ((p)[0])
|
|
|
|
#define U16GET(p) (((p)[0]<<8)|(p)[1])
|
|
|
|
#define U32GET(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
|
|
|
|
#define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
|
|
|
|
#define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
#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
|
2003-11-23 17:55:34 +00:00
|
|
|
#define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
|
|
|
|
#define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
|
|
|
|
|
|
|
|
static int
|
2004-03-15 01:56:49 +00:00
|
|
|
stringunpack(char **s, uchar **p, int *n)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
int nn;
|
|
|
|
|
|
|
|
if(*n < 2)
|
2004-03-15 01:56:49 +00:00
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
|
|
|
|
nn = U16GET(*p);
|
|
|
|
*p += 2;
|
|
|
|
*n -= 2;
|
|
|
|
if(nn > *n)
|
2004-03-15 01:56:49 +00:00
|
|
|
return -1;
|
|
|
|
*s = vtmalloc(nn+1);
|
2003-11-23 17:55:34 +00:00
|
|
|
memmove(*s, *p, nn);
|
|
|
|
(*s)[nn] = 0;
|
|
|
|
*p += nn;
|
|
|
|
*n -= nn;
|
2004-03-15 01:56:49 +00:00
|
|
|
return 0;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2004-03-15 01:56:49 +00:00
|
|
|
stringpack(char *s, uchar *p)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = strlen(s);
|
|
|
|
U16PUT(p, n);
|
|
|
|
memmove(p+2, s, n);
|
|
|
|
return n+2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-03-15 01:56:49 +00:00
|
|
|
mbunpack(MetaBlock *mb, uchar *p, int n)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
u32int magic;
|
|
|
|
|
|
|
|
mb->maxsize = n;
|
|
|
|
mb->buf = p;
|
|
|
|
|
|
|
|
if(n == 0) {
|
|
|
|
memset(mb, 0, sizeof(MetaBlock));
|
2004-03-15 01:56:49 +00:00
|
|
|
return 0;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
magic = U32GET(p);
|
|
|
|
if(magic != MetaMagic && magic != MetaMagic+1) {
|
2004-03-15 01:56:49 +00:00
|
|
|
werrstr("bad meta block magic");
|
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
mb->size = U16GET(p+4);
|
|
|
|
mb->free = U16GET(p+6);
|
|
|
|
mb->maxindex = U16GET(p+8);
|
|
|
|
mb->nindex = U16GET(p+10);
|
|
|
|
mb->unbotch = (magic == MetaMagic+1);
|
|
|
|
|
|
|
|
if(mb->size > n) {
|
2004-03-15 01:56:49 +00:00
|
|
|
werrstr("bad meta block size");
|
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
p += MetaHeaderSize;
|
|
|
|
n -= MetaHeaderSize;
|
|
|
|
|
|
|
|
USED(p);
|
|
|
|
if(n < mb->maxindex*MetaIndexSize) {
|
2004-03-15 01:56:49 +00:00
|
|
|
werrstr("truncated meta block 2");
|
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
2004-03-15 01:56:49 +00:00
|
|
|
return 0;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-03-15 01:56:49 +00:00
|
|
|
mbpack(MetaBlock *mb)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
uchar *p;
|
|
|
|
|
|
|
|
p = mb->buf;
|
|
|
|
|
|
|
|
U32PUT(p, MetaMagic);
|
|
|
|
U16PUT(p+4, mb->size);
|
|
|
|
U16PUT(p+6, mb->free);
|
|
|
|
U16PUT(p+8, mb->maxindex);
|
|
|
|
U16PUT(p+10, mb->nindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2004-03-15 01:56:49 +00:00
|
|
|
mbdelete(MetaBlock *mb, int i, MetaEntry *me)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
uchar *p;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
assert(i < mb->nindex);
|
|
|
|
|
|
|
|
if(me->p - mb->buf + me->size == mb->size)
|
|
|
|
mb->size -= me->size;
|
|
|
|
else
|
|
|
|
mb->free += me->size;
|
|
|
|
|
|
|
|
p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
|
|
|
|
n = (mb->nindex-i-1)*MetaIndexSize;
|
|
|
|
memmove(p, p+MetaIndexSize, n);
|
|
|
|
memset(p+n, 0, MetaIndexSize);
|
|
|
|
mb->nindex--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-03-15 01:56:49 +00:00
|
|
|
mbinsert(MetaBlock *mb, int i, MetaEntry *me)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
uchar *p;
|
|
|
|
int o, n;
|
|
|
|
|
|
|
|
assert(mb->nindex < mb->maxindex);
|
|
|
|
|
|
|
|
o = me->p - mb->buf;
|
|
|
|
n = me->size;
|
|
|
|
if(o+n > mb->size) {
|
|
|
|
mb->free -= mb->size - o;
|
|
|
|
mb->size = o + n;
|
|
|
|
} else
|
|
|
|
mb->free -= n;
|
|
|
|
|
|
|
|
p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
|
|
|
|
n = (mb->nindex-i)*MetaIndexSize;
|
|
|
|
memmove(p+MetaIndexSize, p, n);
|
|
|
|
U16PUT(p, me->p - mb->buf);
|
|
|
|
U16PUT(p+2, me->size);
|
|
|
|
mb->nindex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-15 01:56:49 +00:00
|
|
|
meunpack(MetaEntry *me, MetaBlock *mb, int i)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
uchar *p;
|
|
|
|
int eo, en;
|
|
|
|
|
|
|
|
if(i < 0 || i >= mb->nindex) {
|
2004-03-15 01:56:49 +00:00
|
|
|
werrstr("bad meta entry index");
|
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
|
|
|
|
eo = U16GET(p);
|
|
|
|
en = U16GET(p+2);
|
|
|
|
|
|
|
|
if(0)print("eo = %d en = %d\n", eo, en);
|
|
|
|
if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) {
|
2004-03-15 01:56:49 +00:00
|
|
|
werrstr("corrupted entry in meta block");
|
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(eo+en > mb->size) {
|
2004-03-15 01:56:49 +00:00
|
|
|
werrstr("truncated meta block");
|
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p = mb->buf + eo;
|
|
|
|
|
|
|
|
/* make sure entry looks ok and includes an elem name */
|
|
|
|
if(en < 8 || U32GET(p) != DirMagic || en < 8 + U16GET(p+6)) {
|
2004-03-15 01:56:49 +00:00
|
|
|
werrstr("corrupted meta block entry");
|
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
me->p = p;
|
|
|
|
me->size = en;
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
return 0;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* assumes a small amount of checking has been done in mbEntry */
|
|
|
|
int
|
2004-03-15 01:56:49 +00:00
|
|
|
mecmp(MetaEntry *me, char *s)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
uchar *p;
|
|
|
|
|
|
|
|
p = me->p;
|
|
|
|
|
|
|
|
p += 6;
|
|
|
|
n = U16GET(p);
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
assert(n + 8 < me->size);
|
|
|
|
|
|
|
|
while(n > 0) {
|
|
|
|
if(*s == 0)
|
|
|
|
return -1;
|
|
|
|
if(*p < (uchar)*s)
|
|
|
|
return -1;
|
|
|
|
if(*p > (uchar)*s)
|
|
|
|
return 1;
|
|
|
|
p++;
|
|
|
|
s++;
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
return *s != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-15 01:56:49 +00:00
|
|
|
mecmpnew(MetaEntry *me, char *s)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
uchar *p;
|
|
|
|
|
|
|
|
p = me->p;
|
|
|
|
|
|
|
|
p += 6;
|
|
|
|
n = U16GET(p);
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
assert(n + 8 < me->size);
|
|
|
|
|
|
|
|
while(n > 0) {
|
|
|
|
if(*s == 0)
|
|
|
|
return 1;
|
|
|
|
if(*p < (uchar)*s)
|
|
|
|
return -1;
|
|
|
|
if(*p > (uchar)*s)
|
|
|
|
return 1;
|
|
|
|
p++;
|
|
|
|
s++;
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
return -(*s != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2004-03-15 01:56:49 +00:00
|
|
|
offsetcmp(const void *s0, const void *s1)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
2004-03-15 01:56:49 +00:00
|
|
|
const MetaChunk *mc0, *mc1;
|
2003-11-23 17:55:34 +00:00
|
|
|
|
|
|
|
mc0 = s0;
|
|
|
|
mc1 = s1;
|
|
|
|
if(mc0->offset < mc1->offset)
|
|
|
|
return -1;
|
|
|
|
if(mc0->offset > mc1->offset)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaChunk *
|
2004-03-15 01:56:49 +00:00
|
|
|
metachunks(MetaBlock *mb)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
MetaChunk *mc;
|
|
|
|
int oo, o, n, i;
|
|
|
|
uchar *p;
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
mc = vtmalloc(mb->nindex*sizeof(MetaChunk));
|
2003-11-23 17:55:34 +00:00
|
|
|
p = mb->buf + MetaHeaderSize;
|
|
|
|
for(i = 0; i<mb->nindex; i++) {
|
|
|
|
mc[i].offset = U16GET(p);
|
|
|
|
mc[i].size = U16GET(p+2);
|
|
|
|
mc[i].index = i;
|
|
|
|
p += MetaIndexSize;
|
|
|
|
}
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
qsort(mc, mb->nindex, sizeof(MetaChunk), offsetcmp);
|
2003-11-23 17:55:34 +00:00
|
|
|
|
|
|
|
/* check block looks ok */
|
|
|
|
oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
|
|
|
|
o = oo;
|
|
|
|
n = 0;
|
|
|
|
for(i=0; i<mb->nindex; i++) {
|
|
|
|
o = mc[i].offset;
|
|
|
|
n = mc[i].size;
|
|
|
|
if(o < oo)
|
|
|
|
goto Err;
|
|
|
|
oo += n;
|
|
|
|
}
|
|
|
|
if(o+n <= mb->size)
|
|
|
|
goto Err;
|
|
|
|
if(mb->size - oo != mb->free)
|
|
|
|
goto Err;
|
|
|
|
|
|
|
|
return mc;
|
|
|
|
Err:
|
2004-03-15 01:56:49 +00:00
|
|
|
vtfree(mc);
|
2003-11-23 17:55:34 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-15 01:56:49 +00:00
|
|
|
mbcompact(MetaBlock *mb, MetaChunk *mc)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
int oo, o, n, i;
|
|
|
|
|
|
|
|
oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
|
|
|
|
|
|
|
|
for(i=0; i<mb->nindex; i++) {
|
|
|
|
o = mc[i].offset;
|
|
|
|
n = mc[i].size;
|
|
|
|
if(o != oo) {
|
|
|
|
memmove(mb->buf + oo, mb->buf + o, n);
|
|
|
|
U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
|
|
|
|
}
|
|
|
|
oo += n;
|
|
|
|
}
|
|
|
|
|
|
|
|
mb->size = oo;
|
|
|
|
mb->free = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uchar *
|
2004-03-15 01:56:49 +00:00
|
|
|
mballoc(MetaBlock *mb, int n)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
int i, o;
|
|
|
|
MetaChunk *mc;
|
|
|
|
|
|
|
|
/* off the end */
|
|
|
|
if(mb->maxsize - mb->size >= n)
|
|
|
|
return mb->buf + mb->size;
|
|
|
|
|
|
|
|
/* check if possible */
|
|
|
|
if(mb->maxsize - mb->size + mb->free < n)
|
|
|
|
return nil;
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
mc = metachunks(mb);
|
2003-11-23 17:55:34 +00:00
|
|
|
|
|
|
|
/* look for hole */
|
|
|
|
o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
|
|
|
|
for(i=0; i<mb->nindex; i++) {
|
|
|
|
if(mc[i].offset - o >= n) {
|
2004-03-15 01:56:49 +00:00
|
|
|
vtfree(mc);
|
2003-11-23 17:55:34 +00:00
|
|
|
return mb->buf + o;
|
|
|
|
}
|
|
|
|
o = mc[i].offset + mc[i].size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mb->maxsize - o >= n) {
|
2004-03-15 01:56:49 +00:00
|
|
|
vtfree(mc);
|
2003-11-23 17:55:34 +00:00
|
|
|
return mb->buf + o;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compact and return off the end */
|
2004-03-15 01:56:49 +00:00
|
|
|
mbcompact(mb, mc);
|
|
|
|
vtfree(mc);
|
2003-11-23 17:55:34 +00:00
|
|
|
|
|
|
|
assert(mb->maxsize - mb->size >= n);
|
|
|
|
return mb->buf + mb->size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-15 01:56:49 +00:00
|
|
|
vdsize(VacDir *dir)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/* constant part */
|
|
|
|
|
|
|
|
n = 4 + /* magic */
|
|
|
|
2 + /* version */
|
|
|
|
4 + /* entry */
|
|
|
|
4 + /* guid */
|
|
|
|
4 + /* mentry */
|
|
|
|
4 + /* mgen */
|
|
|
|
8 + /* qid */
|
|
|
|
4 + /* mtime */
|
|
|
|
4 + /* mcount */
|
|
|
|
4 + /* ctime */
|
|
|
|
4 + /* atime */
|
|
|
|
4 + /* mode */
|
|
|
|
0;
|
|
|
|
|
|
|
|
/* strings */
|
|
|
|
n += 2 + strlen(dir->elem);
|
|
|
|
n += 2 + strlen(dir->uid);
|
|
|
|
n += 2 + strlen(dir->gid);
|
|
|
|
n += 2 + strlen(dir->mid);
|
|
|
|
|
|
|
|
/* optional sections */
|
2004-03-15 01:56:49 +00:00
|
|
|
if(dir->qidspace) {
|
2003-11-23 17:55:34 +00:00
|
|
|
n += 3 + /* option header */
|
2004-03-15 01:56:49 +00:00
|
|
|
8 + /* qid offset */
|
|
|
|
8; /* qid max */
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-03-15 01:56:49 +00:00
|
|
|
vdpack(VacDir *dir, MetaEntry *me)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
uchar *p;
|
|
|
|
ulong t32;
|
|
|
|
|
|
|
|
p = me->p;
|
|
|
|
|
|
|
|
U32PUT(p, DirMagic);
|
|
|
|
U16PUT(p+4, 9); /* version */
|
|
|
|
p += 6;
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
p += stringpack(dir->elem, p);
|
2003-11-23 17:55:34 +00:00
|
|
|
|
|
|
|
U32PUT(p, dir->entry);
|
|
|
|
U32PUT(p+4, dir->gen);
|
|
|
|
U32PUT(p+8, dir->mentry);
|
|
|
|
U32PUT(p+12, dir->mgen);
|
|
|
|
U64PUT(p+16, dir->qid, t32);
|
|
|
|
p += 24;
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
p += stringpack(dir->uid, p);
|
|
|
|
p += stringpack(dir->gid, p);
|
|
|
|
p += stringpack(dir->mid, p);
|
2003-11-23 17:55:34 +00:00
|
|
|
|
|
|
|
U32PUT(p, dir->mtime);
|
|
|
|
U32PUT(p+4, dir->mcount);
|
|
|
|
U32PUT(p+8, dir->ctime);
|
|
|
|
U32PUT(p+12, dir->atime);
|
|
|
|
U32PUT(p+16, dir->mode);
|
|
|
|
p += 5*4;
|
|
|
|
|
2004-03-15 01:56:49 +00:00
|
|
|
if(dir->qidspace) {
|
2003-11-23 17:55:34 +00:00
|
|
|
U8PUT(p, DirQidSpaceEntry);
|
|
|
|
U16PUT(p+1, 2*8);
|
|
|
|
p += 3;
|
2004-03-15 01:56:49 +00:00
|
|
|
U64PUT(p, dir->qidoffset, t32);
|
|
|
|
U64PUT(p+8, dir->qidmax, t32);
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(p == me->p + me->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-03-15 01:56:49 +00:00
|
|
|
vdunpack(VacDir *dir, MetaEntry *me)
|
2003-11-23 17:55:34 +00:00
|
|
|
{
|
|
|
|
int t, nn, n, version;
|
|
|
|
uchar *p;
|
|
|
|
|
|
|
|
p = me->p;
|
|
|
|
n = me->size;
|
|
|
|
|
|
|
|
memset(dir, 0, sizeof(VacDir));
|
|
|
|
|
|
|
|
if(0)print("vdUnpack\n");
|
|
|
|
/* magic */
|
|
|
|
if(n < 4 || U32GET(p) != DirMagic)
|
|
|
|
goto Err;
|
|
|
|
p += 4;
|
|
|
|
n -= 4;
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: got magic\n");
|
|
|
|
/* version */
|
|
|
|
if(n < 2)
|
|
|
|
goto Err;
|
|
|
|
version = U16GET(p);
|
|
|
|
if(version < 7 || version > 9)
|
|
|
|
goto Err;
|
|
|
|
p += 2;
|
|
|
|
n -= 2;
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: got version\n");
|
|
|
|
|
|
|
|
/* elem */
|
2004-03-15 01:56:49 +00:00
|
|
|
if(stringunpack(&dir->elem, &p, &n) < 0)
|
2003-11-23 17:55:34 +00:00
|
|
|
goto Err;
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: got elem\n");
|
|
|
|
|
|
|
|
/* entry */
|
|
|
|
if(n < 4)
|
|
|
|
goto Err;
|
|
|
|
dir->entry = U32GET(p);
|
|
|
|
p += 4;
|
|
|
|
n -= 4;
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: got entry\n");
|
|
|
|
|
|
|
|
if(version < 9) {
|
|
|
|
dir->gen = 0;
|
|
|
|
dir->mentry = dir->entry+1;
|
|
|
|
dir->mgen = 0;
|
|
|
|
} else {
|
|
|
|
if(n < 3*4)
|
|
|
|
goto Err;
|
|
|
|
dir->gen = U32GET(p);
|
|
|
|
dir->mentry = U32GET(p+4);
|
|
|
|
dir->mgen = U32GET(p+8);
|
|
|
|
p += 3*4;
|
|
|
|
n -= 3*4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: got gen etc\n");
|
|
|
|
|
|
|
|
/* size is gotten from DirEntry */
|
|
|
|
|
|
|
|
/* qid */
|
|
|
|
if(n < 8)
|
|
|
|
goto Err;
|
|
|
|
dir->qid = U64GET(p);
|
|
|
|
p += 8;
|
|
|
|
n -= 8;
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: got qid\n");
|
|
|
|
/* skip replacement */
|
|
|
|
if(version == 7) {
|
|
|
|
if(n < VtScoreSize)
|
|
|
|
goto Err;
|
|
|
|
p += VtScoreSize;
|
|
|
|
n -= VtScoreSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* uid */
|
2004-03-15 01:56:49 +00:00
|
|
|
if(stringunpack(&dir->uid, &p, &n) < 0)
|
2003-11-23 17:55:34 +00:00
|
|
|
goto Err;
|
|
|
|
|
|
|
|
/* gid */
|
2004-03-15 01:56:49 +00:00
|
|
|
if(stringunpack(&dir->gid, &p, &n) < 0)
|
2003-11-23 17:55:34 +00:00
|
|
|
goto Err;
|
|
|
|
|
|
|
|
/* mid */
|
2004-03-15 01:56:49 +00:00
|
|
|
if(stringunpack(&dir->mid, &p, &n) < 0)
|
2003-11-23 17:55:34 +00:00
|
|
|
goto Err;
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: got ids\n");
|
|
|
|
if(n < 5*4)
|
|
|
|
goto Err;
|
|
|
|
dir->mtime = U32GET(p);
|
|
|
|
dir->mcount = U32GET(p+4);
|
|
|
|
dir->ctime = U32GET(p+8);
|
|
|
|
dir->atime = U32GET(p+12);
|
|
|
|
dir->mode = U32GET(p+16);
|
|
|
|
p += 5*4;
|
|
|
|
n -= 5*4;
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: got times\n");
|
|
|
|
/* optional meta data */
|
|
|
|
while(n > 0) {
|
|
|
|
if(n < 3)
|
|
|
|
goto Err;
|
|
|
|
t = p[0];
|
|
|
|
nn = U16GET(p+1);
|
|
|
|
p += 3;
|
|
|
|
n -= 3;
|
|
|
|
if(n < nn)
|
|
|
|
goto Err;
|
|
|
|
switch(t) {
|
|
|
|
case DirPlan9Entry:
|
|
|
|
/* not valid in version >= 9 */
|
|
|
|
if(version >= 9)
|
|
|
|
break;
|
|
|
|
if(dir->plan9 || nn != 12)
|
|
|
|
goto Err;
|
|
|
|
dir->plan9 = 1;
|
|
|
|
dir->p9path = U64GET(p);
|
|
|
|
dir->p9version = U32GET(p+8);
|
|
|
|
if(dir->mcount == 0)
|
|
|
|
dir->mcount = dir->p9version;
|
|
|
|
break;
|
|
|
|
case DirGenEntry:
|
|
|
|
/* not valid in version >= 9 */
|
|
|
|
if(version >= 9)
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case DirQidSpaceEntry:
|
2004-03-15 01:56:49 +00:00
|
|
|
if(dir->qidspace || nn != 16)
|
2003-11-23 17:55:34 +00:00
|
|
|
goto Err;
|
2004-03-15 01:56:49 +00:00
|
|
|
dir->qidspace = 1;
|
|
|
|
dir->qidoffset = U64GET(p);
|
|
|
|
dir->qidmax = U64GET(p+8);
|
2003-11-23 17:55:34 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
p += nn;
|
|
|
|
n -= nn;
|
|
|
|
}
|
|
|
|
if(0)print("vdUnpack: got options\n");
|
|
|
|
|
|
|
|
if(p != me->p + me->size)
|
|
|
|
goto Err;
|
|
|
|
|
|
|
|
if(0)print("vdUnpack: correct size\n");
|
2004-03-15 01:56:49 +00:00
|
|
|
return 0;
|
2003-11-23 17:55:34 +00:00
|
|
|
Err:
|
|
|
|
if(0)print("vdUnpack: XXXXXXXXXXXX EbadMeta\n");
|
2004-03-15 01:56:49 +00:00
|
|
|
werrstr(EBadMeta);
|
|
|
|
vdcleanup(dir);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vdcleanup(VacDir *dir)
|
|
|
|
{
|
|
|
|
vtfree(dir->elem);
|
|
|
|
dir->elem = nil;
|
|
|
|
vtfree(dir->uid);
|
|
|
|
dir->uid = nil;
|
|
|
|
vtfree(dir->gid);
|
|
|
|
dir->gid = nil;
|
|
|
|
vtfree(dir->mid);
|
|
|
|
dir->mid = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vdcopy(VacDir *dst, VacDir *src)
|
|
|
|
{
|
|
|
|
*dst = *src;
|
|
|
|
dst->elem = vtstrdup(dst->elem);
|
|
|
|
dst->uid = vtstrdup(dst->uid);
|
|
|
|
dst->gid = vtstrdup(dst->gid);
|
|
|
|
dst->mid = vtstrdup(dst->mid);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
mbsearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int b, t, x;
|
|
|
|
|
|
|
|
/* binary search within block */
|
|
|
|
b = 0;
|
|
|
|
t = mb->nindex;
|
|
|
|
while(b < t) {
|
|
|
|
i = (b+t)>>1;
|
|
|
|
if(meunpack(me, mb, i) < 0)
|
|
|
|
return 0;
|
|
|
|
if(mb->unbotch)
|
|
|
|
x = mecmpnew(me, elem);
|
|
|
|
else
|
|
|
|
x = mecmp(me, elem);
|
|
|
|
|
|
|
|
if(x == 0) {
|
|
|
|
*ri = i;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(x < 0)
|
|
|
|
b = i+1;
|
|
|
|
else /* x > 0 */
|
|
|
|
t = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(b == t);
|
|
|
|
|
|
|
|
*ri = b; /* b is the index to insert this entry */
|
|
|
|
memset(me, 0, sizeof(*me));
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mbinit(MetaBlock *mb, uchar *p, int n)
|
|
|
|
{
|
|
|
|
memset(mb, 0, sizeof(MetaBlock));
|
|
|
|
mb->maxsize = n;
|
|
|
|
mb->buf = p;
|
|
|
|
mb->maxindex = n/100;
|
|
|
|
mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
mbresize(MetaBlock *mb, MetaEntry *me, int n)
|
|
|
|
{
|
|
|
|
uchar *p, *ep;
|
|
|
|
|
|
|
|
/* easy case */
|
|
|
|
if(n <= me->size){
|
|
|
|
me->size = n;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try and expand entry */
|
|
|
|
|
|
|
|
p = me->p + me->size;
|
|
|
|
ep = mb->buf + mb->maxsize;
|
|
|
|
while(p < ep && *p == 0)
|
|
|
|
p++;
|
|
|
|
if(n <= p - me->p){
|
|
|
|
me->size = n;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = mballoc(mb, n);
|
|
|
|
if(p != nil){
|
|
|
|
me->p = p;
|
|
|
|
me->size = n;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2003-11-23 17:55:34 +00:00
|
|
|
}
|