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