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