xref: /plan9/sys/src/cmd/sam/disk.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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