Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <diskfs.h>
4 #include <venti.h>
6 extern void vtlibthread(void);
8 typedef struct DiskVenti DiskVenti;
9 struct DiskVenti
10 {
11 Disk disk;
12 VtEntry e;
13 VtCache *c;
14 };
16 int nfilereads;
18 /*
19 * This part is like file.c but doesn't require storing the root block
20 * in the cache permanently and doesn't care about locking since
21 * all the blocks are read-only. Perhaps at some point this functionality
22 * should go into libvac in some form.
23 */
24 static int
25 vtfileindices(VtEntry *e, u32int bn, int *index)
26 {
27 int i, np;
29 memset(index, 0, VtPointerDepth*sizeof(int));
31 np = e->psize/VtScoreSize;
32 memset(index, 0, sizeof(index));
33 for(i=0; bn > 0; i++){
34 if(i >= VtPointerDepth){
35 werrstr("bad block number %lud", (ulong)bn);
36 return -1;
37 }
38 index[i] = bn % np;
39 bn /= np;
40 }
41 return i;
42 }
44 static VtBlock*
45 _vtfileblock(VtCache *c, VtEntry *e, u32int bn)
46 {
47 VtBlock *b, *bb;
48 int i, d, index[VtPointerDepth+1], t;
50 i = vtfileindices(e, bn, index);
51 if(i < 0)
52 return nil;
53 d = (e->type&VtTypeDepthMask);
54 if(i > d){
55 werrstr("bad address %d > %d (%x %x)", i, d, e->type, e->flags);
56 return nil;
57 }
59 //fprint(2, "vtread %V\n", e->score);
60 b = vtcacheglobal(c, e->score, e->type);
61 if(b == nil)
62 return nil;
64 for(i=d-1; i>=0; i--){
65 t = VtDataType+i;
66 //fprint(2, "vtread %V\n", b->data+index[i]*VtScoreSize);
67 bb = vtcacheglobal(c, b->data+index[i]*VtScoreSize, t);
68 vtblockput(b);
69 if(bb == nil)
70 return nil;
71 b = bb;
72 }
73 return b;
74 }
76 static void
77 diskventiblockput(Block *b)
78 {
79 vtblockput(b->priv);
80 free(b);
81 }
83 static Block*
84 diskventiread(Disk *dd, u32int len, u64int offset)
85 {
86 DiskVenti *d = (DiskVenti*)dd;
87 VtBlock *vb;
88 Block *b;
89 int frag;
91 nfilereads++;
92 vb = _vtfileblock(d->c, &d->e, offset/d->e.dsize);
93 if(vb == nil)
94 return nil;
96 b = mallocz(sizeof(Block), 1);
97 if(b == nil){
98 vtblockput(vb);
99 return nil;
102 b->priv = vb;
103 b->_close = diskventiblockput;
104 frag = offset%d->e.dsize;
105 b->data = (uchar*)vb->data + frag;
106 b->len = d->e.dsize - frag;
107 if(b->len > len)
108 b->len = len;
109 return b;
112 static void
113 diskventiclose(Disk *dd)
115 DiskVenti *d = (DiskVenti*)dd;
116 free(d);
119 Disk*
120 diskopenventi(VtCache *c, uchar score[VtScoreSize])
122 DiskVenti *d;
123 VtEntry e;
124 VtRoot root;
125 VtBlock *b;
127 if((b = vtcacheglobal(c, score, VtRootType)) == nil)
128 goto Err;
129 if(vtrootunpack(&root, b->data) < 0)
130 goto Err;
131 if(root.blocksize < 512 || (root.blocksize&(root.blocksize-1))){
132 werrstr("bad blocksize %d", root.blocksize);
133 goto Err;
135 vtblockput(b);
137 if((b = vtcacheglobal(c, root.score, VtDirType)) == nil)
138 goto Err;
139 if(vtentryunpack(&e, b->data, 0) < 0)
140 goto Err;
141 vtblockput(b);
142 b = nil;
143 if((e.type&VtTypeBaseMask) != VtDataType){
144 werrstr("not a single file");
145 goto Err;
148 d = mallocz(sizeof(DiskVenti), 1);
149 if(d == nil)
150 goto Err;
152 d->disk._read = diskventiread;
153 d->disk._close = diskventiclose;
154 d->e = e;
155 d->c = c;
156 return &d->disk;
158 Err:
159 if(b)
160 vtblockput(b);
161 return nil;