/* is `a' a direct block? */
if(a < NDBLOCK) {
addr = d->dblock[a];
if(!addr && tag) {
addr = bufalloc(dev, tag, qpath, uid);
d->dblock[a] = addr;
p->flags |= Bmod|Bimm;
}
if(putb)
putbuf(p);
return addr;
}
a -= NDBLOCK;
/*
* loop through indirect block depths.
*/
for (i = 0; i < NIBLOCK; i++) {
indaddrs *= INDPERBUF;
/* is a's disk addr in this indir block or one of its kids? */
if (a < indaddrs) {
addr = d->iblocks[i];
if(!addr && tag) {
addr = bufalloc(dev, Tind1+i, qpath, uid);
d->iblocks[i] = addr;
p->flags |= Bmod|Bimm;
}
if(putb)
putbuf(p);
div = indaddrs;
for (; i >= 0; i--) {
div /= INDPERBUF;
if (div <= 0)
panic("rel2abs: non-positive divisor");
addr = indfetch(dev, qpath, addr,
(a/div)%INDPERBUF, Tind1+i,
(i == 0? tag: Tind1+i-1), uid);
}
return addr;
}
a -= indaddrs;
}
if(putb)
putbuf(p);
/* quintuple-indirect blocks not implemented. */
fprint(2, "rel2abs: no %d-deep indirect\n", NIBLOCK+1);
return 0;
}
/*
* read-ahead strategy
* on second block, read RAGAP blocks,
* thereafter, read RAGAP ahead of current pos
*/
Off
dbufread(Iobuf *p, Dentry *d, Off a, Off ra, int uid)
{
Off addr;
/*
* same as dnodebuf but it calls putbuf(p)
* to reduce interference.
*/
Iobuf*
dnodebuf1(Iobuf *p, Dentry *d, Off a, int tag, int uid)
{
Off addr;
Device *dev;
dev = p->dev;
addr = rel2abs(p, d, a, tag, 1, uid);
if(addr)
return getbuf(dev, addr, Brd);
return 0;
}
Off
indfetch(Device* d, Off qpath, Off addr, Off a, int itag, int tag, int uid)
{
Iobuf *bp;
/*
* truncate d (in p) to length `newsize'.
* if larger, just increase size.
* if smaller, deallocate blocks after last one
* still in file at new size. last byte to keep
* is newsize-1, due to zero origin.
* we free in forward order because it's simpler to get right.
* if the final block at the new size is partially-filled,
* zero the remainder.
*/
int
dtrunclen(Iobuf *p, Dentry *d, Off newsize, int uid)
{
int i, pastlast;
Truncstate trunc;
if (newsize <= 0) {
dtrunc(p, d, uid);
return 0;
}
memset(&trunc, 0, sizeof trunc);
trunc.d = d;
trunc.p = p;
trunc.uid = uid;
trunc.newsize = newsize;
trunc.lastblk = newsize/BUFSIZE;
if (newsize % BUFSIZE == 0)
trunc.lastblk--;
else
trunczero(&trunc);
for (i = 0; i < NDBLOCK; i++)
if (trunc.pastlast) {
trunc.relblk = i;
buffree(p->dev, d->dblock[i], 0, &trunc);
d->dblock[i] = 0;
} else if (i == trunc.lastblk)
trunc.pastlast = 1;
trunc.relblk = NDBLOCK;
for (i = 0; i < NIBLOCK; i++) {
pastlast = trunc.pastlast;
buffree(p->dev, d->iblocks[i], i+1, &trunc);
if (pastlast)
d->iblocks[i] = 0;
}
/*
* truncate d (in p) to zero length.
* freeing blocks in reverse order is traditional, from Unix,
* in an attempt to keep the free list contiguous.
*/
void
dtrunc(Iobuf *p, Dentry *d, int uid)
{
int i;
for (i = NIBLOCK-1; i >= 0; i--) {
buffree(p->dev, d->iblocks[i], i+1, nil);
d->iblocks[i] = 0;
}
for (i = NDBLOCK-1; i >= 0; i--) {
buffree(p->dev, d->dblock[i], 0, nil);
d->dblock[i] = 0;
}
d->size = 0;
p->flags |= Bmod|Bimm;
accessdir(p, d, FWRITE, uid);
}