|
|
1.1 root 1: #include "sam.h"
2:
3: /*
4: * Guarantee: No compaction from Dread, Dinsert, Ddelete, Dreplace
5: */
6: static Discdesc desc[NBUFFILES];
7: static bkalloc();
8: static bkfree();
9: static int bkread();
10: static int bkwrite();
11: static char tempnam[20];
12:
13: Discdesc *
14: Dstart()
15: {
16: register i;
17: register Discdesc *dd;
18: register fd;
19: for(i=0, dd=desc; dd->fd; i++, dd++)
20: if(i==NBUFFILES-1)
21: panic("too many buffer files");
22: if(tempnam[0]==0)
23: sprint(tempnam, "/tmp/sam%d", getpid());
24: fd=creat(tempnam, 0600);
25: if(fd<0){
26: unlink(tempnam);
27: fd=creat(tempnam, 0600);
28: }
29: if(fd<0 || (close(fd), fd=open(tempnam, 2))<0)
30: panic("can't create buffer file");
31: closeonexec(fd);
32: unlink(tempnam);
33: dd->fd=fd;
34: return dd;
35: }
36: Dclosefd()
37: {
38: register i;
39: for(i=0; i<NBUFFILES; i++)
40: if(desc[i].fd)
41: close(desc[i].fd);
42: }
43: Disc *
44: Dopen(dd)
45: Discdesc *dd;
46: {
47: register Disc *d;
48: d=new(Disc, 1);
49: d->desc=dd;
50: return d;
51: }
52: Dclose(d)
53: register Disc *d;
54: {
55: register i;
56: for(i=d->block.nused; --i>=0; ) /* backwards because bkfree() stacks */
57: bkfree(d, i);
58: gcfree((uchar *)d->block.ptr);
59: free((uchar *)d);
60: }
61: int
62: Dread(d, addr, n, p1)
63: register Disc *d;
64: uchar *addr;
65: int n;
66: Posn p1;
67: {
68: register i, nb, nr;
69: register Posn p=0, p2=p1+n;
70: for(i=0; i<d->block.nused; i++){
71: if((p+=d->block.ptr[i].nbytes)>p1){
72: p-=d->block.ptr[i].nbytes;
73: goto out;
74: }
75: }
76: if(p==p1)
77: return 0; /* eof */
78: return -1; /* past eof */
79: out:
80: n=0;
81: if(p!=p1){ /* trailing partial block */
82: nb=d->block.ptr[i].nbytes;
83: if(p2>p+nb)
84: nr=nb-(p1-p);
85: else
86: nr=p2-p1;
87: bkread(d, addr, nr, i, (int)(p1-p));
88: /* advance to next block */
89: p+=nb;
90: addr+=nr;
91: n+=nr;
92: i++;
93: }
94: /* whole blocks */
95: while(p<p2 && (nb=d->block.ptr[i].nbytes)<=p2-p){
96: if(i>=d->block.nused)
97: return n; /* eof */
98: bkread(d, addr, nb, i, 0);
99: p+=nb;
100: addr+=nb;
101: n+=nb;
102: i++;
103: }
104: if(p<p2){ /* any initial partial block left? */
105: nr=p2-p;
106: nb=d->block.ptr[i].nbytes;
107: if(nr>nb)
108: nr=nb; /* eof */
109: /* just read in the part that survives */
110: bkread(d, addr, nr, i, 0);
111: n+=nr;
112: }
113: return n;
114: }
115: Dinsert(d, addr, n, p0)
116: register Disc *d;
117: uchar *addr; /* if null, just make space */
118: int n;
119: Posn p0;
120: {
121: register i, nb, ni;
122: register Posn p=0;
123: uchar hold[BLOCKSIZE];
124: int nhold;
125: for(i=0; i<d->block.nused; i++){
126: if((p+=d->block.ptr[i].nbytes)>=p0){
127: p-=d->block.ptr[i].nbytes;
128: goto out;
129: }
130: }
131: if(p!=p0)
132: panic("Dinsert"); /* beyond eof */
133: out:
134: d->nbytes+=n;
135: nhold=0;
136: if(i<d->block.nused && (nb=d->block.ptr[i].nbytes)>p0-p){
137: nhold=nb-(p0-p);
138: bkread(d, hold, nhold, i, (int)(p0-p));
139: d->block.ptr[i].nbytes-=nhold; /* no write necessary */
140: }
141: /* insertion point is now at end of block i (which may not exist) */
142: while(n>0){
143: if(i<d->block.nused && (nb=d->block.ptr[i].nbytes)<BLOCKSIZE/2){
144: /* fill this block */
145: if(nb+n>BLOCKSIZE)
146: ni=BLOCKSIZE/2-nb;
147: else
148: ni=n;
149: if(addr)
150: bkwrite(d, addr, ni, i, nb);
151: nb+=ni;
152: }else{ /* make new block */
153: if(i<d->block.nused)
154: i++; /* put after this block, if it exists */
155: bkalloc(d, i);
156: if(n>BLOCKSIZE)
157: ni=BLOCKSIZE/2;
158: else
159: ni=n;
160: if(addr)
161: bkwrite(d, addr, ni, i, 0);
162: nb=ni;
163: }
164: d->block.ptr[i].nbytes=nb;
165: if(addr)
166: addr+=ni;
167: n-=ni;
168: }
169: if(nhold){
170: if(i<d->block.nused && (nb=d->block.ptr[i].nbytes)+nhold<BLOCKSIZE){
171: /* fill this block */
172: bkwrite(d, hold, nhold, i, nb);
173: nb+=nhold;
174: }else{ /* make new block */
175: if(i<d->block.nused)
176: i++; /* put after this block, if it exists */
177: bkalloc(d, i);
178: bkwrite(d, hold, nhold, i, 0);
179: nb=nhold;
180: }
181: d->block.ptr[i].nbytes=nb;
182: }
183: }
184: Ddelete(d, p1, p2)
185: register Disc *d;
186: Posn p1, p2;
187: {
188: register i, nb, nd;
189: register Posn p=0;
190: uchar buf[BLOCKSIZE];
191: for(i=0; i<d->block.nused; i++){
192: if((p+=d->block.ptr[i].nbytes)>p1){
193: p-=d->block.ptr[i].nbytes;
194: goto out;
195: }
196: }
197: if(p1!=d->nbytes || p2!=p1)
198: panic("Ddelete");
199: return; /* beyond eof */
200: out:
201: d->nbytes-=p2-p1;
202: if(p!=p1){ /* throw away partial block */
203: nb=d->block.ptr[i].nbytes;
204: bkread(d, buf, nb, i, 0);
205: if(p2>=p+nb)
206: nd=nb-(p1-p);
207: else{
208: nd=p2-p1;
209: bcopy(buf+(p1-p)+nd, buf+nb, buf+(p1-p), 1);
210: }
211: nb-=nd;
212: bkwrite(d, buf, nb, i, 0);
213: d->block.ptr[i].nbytes=nb;
214: p2-=nd;
215: /* advance to next block */
216: p+=nb;
217: i++;
218: }
219: /* throw away whole blocks */
220: while(p<p2 && (nb=d->block.ptr[i].nbytes)<=p2-p){
221: if(i>=d->block.nused)
222: panic("Ddelete 2");
223: bkfree(d, i);
224: p2-=nb;
225: }
226: if(p>=p2) /* any initial partial block left to delete? */
227: return; /* no */
228: nd=p2-p;
229: nb=d->block.ptr[i].nbytes;
230: /* just read in the part that survives */
231: bkread(d, buf, nb-=nd, i, nd);
232: /* a little block merging */
233: if(nb<BLOCKSIZE/2 && i>0 && (nd=d->block.ptr[i-1].nbytes)<BLOCKSIZE/2){
234: bcopy(buf, buf+nb, buf+nd, -1);
235: bkread(d, buf, nd, --i, 0);
236: bkfree(d, i);
237: nb+=nd;
238: }
239: bkwrite(d, buf, nb, i, 0);
240: d->block.ptr[i].nbytes=nb;
241: }
242: Dreplace(d, p1, p2, addr, n)
243: register Disc *d;
244: Posn p1, p2;
245: uchar *addr;
246: int n;
247: {
248: register i, nb, nr;
249: register Posn p=0;
250: uchar buf[BLOCKSIZE];
251: if(p2-p1>n)
252: Ddelete(d, p1+n, p2);
253: else if(p2-p1<n)
254: Dinsert(d, (uchar *)0, (int)(n-(p2-p1)), p2);
255: p2=p1+n;
256: /* they're now conformal; replace in place */
257: for(i=0; i<d->block.nused; i++){
258: if((p+=d->block.ptr[i].nbytes)>p1){
259: p-=d->block.ptr[i].nbytes;
260: goto out;
261: }
262: }
263: panic("Dreplace");
264: out:
265: if(p!=p1){ /* trailing partial block */
266: nb=d->block.ptr[i].nbytes;
267: bkread(d, buf, nb, i, 0);
268: if(p2>p+nb)
269: nr=nb-(p1-p);
270: else
271: nr=p2-p1;
272: bcopy(addr, addr+nr, buf+p1-p, 1);
273: bkwrite(d, buf, nb, i, 0);
274: /* advance to next block */
275: p+=nb;
276: addr+=nr;
277: i++;
278: }
279: /* whole blocks */
280: while(p<p2 && (nb=d->block.ptr[i].nbytes)<=p2-p){
281: if(i>=d->block.nused)
282: panic("Dreplace 2");
283: bkwrite(d, addr, nb, i, 0);
284: p+=nb;
285: addr+=nb;
286: i++;
287: }
288: if(p<p2){ /* any initial partial block left? */
289: nr=p2-p;
290: nb=d->block.ptr[i].nbytes;
291: /* just read in the part that survives */
292: bkread(d, buf+nr, nb-nr, i, nr);
293: bcopy(addr, addr+nr, buf, 1);
294: bkwrite(d, buf, nb, i, 0);
295: }
296: }
297: static int
298: bkread(d, loc, n, bk, off)
299: Disc *d;
300: uchar *loc;
301: int n;
302: int bk;
303: int off;
304: {
305: Lseek(d->desc->fd, BLOCKSIZE*(long)d->block.ptr[bk].bnum+off, 0);
306: return Read(d->desc->fd, loc, n);
307: }
308: static int
309: bkwrite(d, loc, n, bk, off)
310: Disc *d;
311: uchar *loc;
312: int n;
313: int bk;
314: int off;
315: {
316: Lseek(d->desc->fd, BLOCKSIZE*(long)d->block.ptr[bk].bnum+off, 0);
317: return Write(d->desc->fd, loc, n);
318: }
319: static
320: bkalloc(d, n)
321: register Disc *d;
322: int n;
323: {
324: register Discdesc *dd=d->desc;
325: register bnum;
326: if(dd->free.nused)
327: bnum=dd->free.ptr[--dd->free.nused];
328: else
329: bnum=dd->nbk++;
330: nocompact();
331: inslist((List *)&d->block, n, 0L);
332: compactok();
333: d->block.ptr[n].bnum=bnum;
334: }
335: static
336: bkfree(d, n)
337: Disc *d;
338: int n;
339: {
340: Discdesc *dd=d->desc;
341: nocompact();
342: inslist(&dd->free, dd->free.nused, (long)d->block.ptr[n].bnum);
343: compactok();
344: dellist((List *)&d->block, n);
345: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.