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