1 #include "sam.h"
2 
3 static	Block	*blist;
4 
5 #if 0
6 static int
7 tempdisk(void)
8 {
9 	char buf[128];
10 	int i, fd;
11 
12 	snprint(buf, sizeof buf, "/tmp/X%d.%.4ssam", getpid(), getuser());
13 	for(i='A'; i<='Z'; i++){
14 		buf[5] = i;
15 		if(access(buf, AEXIST) == 0)
16 			continue;
17 		fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600);
18 		if(fd >= 0)
19 			return fd;
20 	}
21 	return -1;
22 }
23 #else
24 extern int tempdisk(void);
25 #endif
26 
27 Disk*
diskinit(void)28 diskinit(void)
29 {
30 	Disk *d;
31 
32 	d = emalloc(sizeof(Disk));
33 	d->fd = tempdisk();
34 	if(d->fd < 0){
35 		fprint(2, "sam: can't create temp file: %r\n");
36 		exits("diskinit");
37 	}
38 	return d;
39 }
40 
41 static
42 uint
ntosize(uint n,uint * ip)43 ntosize(uint n, uint *ip)
44 {
45 	uint size;
46 
47 	if(n > Maxblock)
48 		panic("internal error: ntosize");
49 	size = n;
50 	if(size & (Blockincr-1))
51 		size += Blockincr - (size & (Blockincr-1));
52 	/* last bucket holds blocks of exactly Maxblock */
53 	if(ip)
54 		*ip = size/Blockincr;
55 	return size * sizeof(Rune);
56 }
57 
58 Block*
disknewblock(Disk * d,uint n)59 disknewblock(Disk *d, uint n)
60 {
61 	uint i, j, size;
62 	Block *b;
63 
64 	size = ntosize(n, &i);
65 	b = d->free[i];
66 	if(b)
67 		d->free[i] = b->u.next;
68 	else{
69 		/* allocate in chunks to reduce malloc overhead */
70 		if(blist == nil){
71 			blist = emalloc(100*sizeof(Block));
72 			for(j=0; j<100-1; j++)
73 				blist[j].u.next = &blist[j+1];
74 		}
75 		b = blist;
76 		blist = b->u.next;
77 		b->addr = d->addr;
78 		d->addr += size;
79 	}
80 	b->u.n = n;
81 	return b;
82 }
83 
84 void
diskrelease(Disk * d,Block * b)85 diskrelease(Disk *d, Block *b)
86 {
87 	uint i;
88 
89 	ntosize(b->u.n, &i);
90 	b->u.next = d->free[i];
91 	d->free[i] = b;
92 }
93 
94 void
diskwrite(Disk * d,Block ** bp,Rune * r,uint n)95 diskwrite(Disk *d, Block **bp, Rune *r, uint n)
96 {
97 	int size, nsize;
98 	Block *b;
99 
100 	b = *bp;
101 	size = ntosize(b->u.n, nil);
102 	nsize = ntosize(n, nil);
103 	if(size != nsize){
104 		diskrelease(d, b);
105 		b = disknewblock(d, n);
106 		*bp = b;
107 	}
108 	if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
109 		panic("write error to temp file");
110 	b->u.n = n;
111 }
112 
113 void
diskread(Disk * d,Block * b,Rune * r,uint n)114 diskread(Disk *d, Block *b, Rune *r, uint n)
115 {
116 	if(n > b->u.n)
117 		panic("internal error: diskread");
118 
119 	ntosize(b->u.n, nil);	/* called only for sanity check on Maxblock */
120 	if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
121 		panic("read error from temp file");
122 }
123