summaryrefslogtreecommitdiff
path: root/sys/src/cmd/cwfs/dentry.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cwfs/dentry.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cwfs/dentry.c')
-rwxr-xr-xsys/src/cmd/cwfs/dentry.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/sys/src/cmd/cwfs/dentry.c b/sys/src/cmd/cwfs/dentry.c
new file mode 100755
index 000000000..35f6a38aa
--- /dev/null
+++ b/sys/src/cmd/cwfs/dentry.c
@@ -0,0 +1,337 @@
+#include "all.h"
+
+Dentry*
+getdir(Iobuf *p, int slot)
+{
+ if(!p)
+ return 0;
+ return (Dentry*)p->iobuf + slot%DIRPERBUF;
+}
+
+void
+accessdir(Iobuf *p, Dentry *d, int f, int uid)
+{
+ Timet t;
+
+ if(p && p->dev->type != Devro) {
+ p->flags |= Bmod;
+ t = time(nil);
+ if(f & (FREAD|FWRITE))
+ d->atime = t;
+ if(f & FWRITE) {
+ d->mtime = t;
+ d->muid = uid;
+ d->qid.version++;
+ }
+ }
+}
+
+void
+preread(Device *d, Off addr)
+{
+ Rabuf *rb;
+
+ if(addr == 0)
+ return;
+ if(raheadq->count+10 >= raheadq->size) /* ugly knowing layout */
+ return;
+ lock(&rabuflock);
+ rb = rabuffree;
+ if(rb == 0) {
+ unlock(&rabuflock);
+ return;
+ }
+ rabuffree = rb->link;
+ unlock(&rabuflock);
+ rb->dev = d;
+ rb->addr = addr;
+ fs_send(raheadq, rb);
+}
+
+Off
+rel2abs(Iobuf *p, Dentry *d, Off a, int tag, int putb, int uid)
+{
+ int i;
+ Off addr, qpath, indaddrs = 1, div;
+ Device *dev;
+
+ if(a < 0) {
+ print("rel2abs: neg offset\n");
+ if(putb)
+ putbuf(p);
+ return 0;
+ }
+ dev = p->dev;
+ qpath = d->qid.path;
+
+ /* 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. */
+ print("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;
+
+ if(a == 0)
+ return 1;
+ if(a == 1 && ra == 1) {
+ while(ra < a+RAGAP) {
+ ra++;
+ addr = rel2abs(p, d, ra, 0, 0, uid);
+ if(!addr)
+ return 0;
+ preread(p->dev, addr);
+ }
+ return ra+1;
+ }
+ if(ra == a+RAGAP) {
+ addr = rel2abs(p, d, ra, 0, 0, uid);
+ if(!addr)
+ return 0;
+ preread(p->dev, addr);
+ return ra+1;
+ }
+ return ra;
+}
+
+Iobuf*
+dnodebuf(Iobuf *p, Dentry *d, Off a, int tag, int uid)
+{
+ Off addr;
+
+ addr = rel2abs(p, d, a, tag, 0, uid);
+ if(addr)
+ return getbuf(p->dev, addr, Brd);
+ return 0;
+}
+
+/*
+ * 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;
+
+ if(!addr)
+ return 0;
+ bp = getbuf(d, addr, Brd);
+ if(!bp || checktag(bp, itag, qpath)) {
+ if(!bp) {
+ print("ind fetch bp = 0\n");
+ return 0;
+ }
+ print("ind fetch tag\n");
+ putbuf(bp);
+ return 0;
+ }
+ addr = ((Off *)bp->iobuf)[a];
+ if(!addr && tag) {
+ addr = bufalloc(d, tag, qpath, uid);
+ if(addr) {
+ ((Off *)bp->iobuf)[a] = addr;
+ bp->flags |= Bmod;
+ if(tag == Tdir)
+ bp->flags |= Bimm;
+ settag(bp, itag, qpath);
+ }
+ }
+ putbuf(bp);
+ return addr;
+}
+
+/* return INDPERBUF^exp */
+Off
+ibbpow(int exp)
+{
+ static Off pows[] = {
+ 1,
+ INDPERBUF,
+ (Off)INDPERBUF*INDPERBUF,
+ (Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
+ (Off)INDPERBUF*(Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
+ };
+
+ if (exp < 0)
+ return 0;
+ else if (exp >= nelem(pows)) { /* not in table? do it long-hand */
+ Off indpow = 1;
+
+ while (exp-- > 0 && indpow > 0)
+ indpow *= INDPERBUF;
+ return indpow;
+ } else
+ return pows[exp];
+}
+
+/* return sum of INDPERBUF^n for 1 ≤ n ≤ exp */
+Off
+ibbpowsum(int exp)
+{
+ Off indsum = 0;
+
+ for (; exp > 0; exp--)
+ indsum += ibbpow(exp);
+ return indsum;
+}
+
+/* zero bytes past new file length; return an error code */
+int
+trunczero(Truncstate *ts)
+{
+ int blkoff = ts->newsize % BUFSIZE;
+ Iobuf *pd;
+
+ pd = dnodebuf(ts->p, ts->d, ts->lastblk, Tfile, ts->uid);
+ if (pd == nil || checktag(pd, Tfile, QPNONE)) {
+ if (pd != nil)
+ putbuf(pd);
+ ts->err = Ephase;
+ return Ephase;
+ }
+ memset(pd->iobuf+blkoff, 0, BUFSIZE - blkoff);
+ putbuf(pd);
+ return 0;
+}
+
+/*
+ * 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;
+ }
+
+ d->size = newsize;
+ p->flags |= Bmod|Bimm;
+ accessdir(p, d, FWRITE, uid);
+ return trunc.err;
+}
+
+/*
+ * 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);
+}