]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hgfs/revlog.c
upas/fs: fix more locking bugs, remove debugging clutter, remove planb mbox code
[plan9front.git] / sys / src / cmd / hgfs / revlog.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 int
8 fmktemp(void)
9 {
10         static ulong id = 1;
11         char path[MAXPATH];
12         snprint(path, sizeof(path), "/tmp/hg%.12d%.8lux", getpid(), id++);
13         return create(path, OEXCL|ORDWR|ORCLOSE, 0600);
14 }
15
16 void
17 revlogupdate(Revlog *r)
18 {
19         uchar buf[64];
20         Revmap *m;
21         vlong noff;
22         int rev;
23
24         if(seek(r->ifd, r->ioff, 0) < 0)
25                 return;
26         for(rev=r->nmap;;rev++){
27                 if(readn(r->ifd, buf, sizeof(buf)) != sizeof(buf))
28                         break;
29                 if((rev % 16) == 0)
30                         r->map = realloc(r->map, sizeof(r->map[0])*(rev+16));
31                 m = &r->map[rev];
32                 memset(m, 0, sizeof(*m));
33                 m->hoff = (vlong)buf[0]<<40 | 
34                         (vlong)buf[1]<<32 |
35                         (vlong)buf[2]<<24 | 
36                         (vlong)buf[3]<<16 | 
37                         (vlong)buf[4]<<8 | 
38                         (vlong)buf[5];
39                 if(rev == 0)
40                         m->hoff &= 0xFFFF;
41                 m->rev = rev;
42                 m->flags = buf[6]<<8 | buf[7];
43                 m->hlen = buf[8]<<24 | buf[9]<<16 | buf[10]<<8 | buf[11];
44                 m->flen = buf[12]<<24 | buf[13]<<16 | buf[14]<<8 | buf[15];
45                 m->baserev = buf[16]<<24 | buf[17]<<16 | buf[18]<<8 | buf[19];
46                 m->linkrev = buf[20]<<24 | buf[21]<<16 | buf[22]<<8 | buf[23];
47                 m->p1rev = buf[24]<<24 | buf[25]<<16 | buf[26]<<8 | buf[27];
48                 m->p2rev = buf[28]<<24 | buf[29]<<16 | buf[30]<<8 | buf[31];
49                 memmove(m->hash, buf+32, HASHSZ);
50
51                 noff = r->ioff + sizeof(buf);
52                 if(r->dfd < 0){
53                         m->hoff = noff;
54                         noff = seek(r->ifd, m->hoff + m->hlen, 0);
55                         if(noff < 0)
56                                 break;
57                 }
58                 r->ioff = noff;
59         }
60         r->nmap = rev;
61 }
62
63 int
64 revlogopen(Revlog *r, char *path, int mode)
65 {
66         r->ifd = -1;
67         r->dfd = -1;
68         r->tfd = -1;
69         r->tid = -1;
70         path = smprint("%s.i", path);
71         if((r->ifd = open(path, mode)) < 0){
72                 free(path);
73                 return -1;
74         }
75         path[strlen(path)-1] = 'd';
76         r->dfd = open(path, mode);
77
78         path[strlen(path)-2] = 0;
79         r->path = path;
80
81         r->ioff = 0;
82         r->nmap = 0;
83         r->map = nil;
84         revlogupdate(r);
85         return 0;
86 }
87
88 void
89 revlogclose(Revlog *r)
90 {
91         if(r->ifd >= 0){
92                 close(r->ifd);
93                 r->ifd = -1;
94         }
95         if(r->dfd >= 0){
96                 close(r->dfd);
97                 r->dfd = -1;
98         }
99         if(r->tfd >= 0){
100                 close(r->tfd);
101                 r->tfd = -1;
102         }
103         r->tid = -1;
104         free(r->map);
105         r->map = nil;
106         r->nmap = 0;
107         free(r->path);
108         r->path = nil;
109 }
110
111 uchar*
112 revhash(Revlog *r, int rev)
113 {
114         if(rev < 0 || rev >= r->nmap)
115                 return nullid;
116         return r->map[rev].hash;
117 }
118
119 int
120 hashrev(Revlog *r, uchar hash[])
121 {
122         int rev;
123
124         for(rev=0; rev<r->nmap; rev++)
125                 if(memcmp(r->map[rev].hash, hash, HASHSZ) == 0)
126                         return rev;
127         return -1;
128 }
129
130 static int
131 prevlogrev(Revlog *r, int rev)
132 {
133         if(r->map[rev].baserev == rev)
134                 return -1;
135         return rev-1;
136 }
137
138 static int
139 prevbundlerev(Revlog *r, int rev)
140 {
141         if(r->map[rev].baserev == rev)
142                 return -1;
143         return r->map[rev].p1rev;
144 }
145
146 static Revmap**
147 getchain1(Revlog *r, int rev, int *count, int (*next)(Revlog *, int))
148 {
149         Revmap **chain;
150
151         if(rev < 0 || rev >= r->nmap){
152                 if(*count <= 0)
153                         return nil;
154                 chain = malloc(sizeof(chain[0]) * ((*count)+1));
155                 chain[*count] = nil;
156                 *count = 0;
157         }else{
158                 (*count)++;
159                 if(chain = getchain1(r, (*next)(r, rev), count, next))
160                         chain[(*count)++] = &r->map[rev];
161         }
162         return chain;
163 }
164
165 static Revmap**
166 getchain(Revlog *r, int rev, int (*next)(Revlog *, int))
167 {
168         int count = 0;
169         return getchain1(r, rev, &count, next);
170 }
171
172 int
173 revlogextract(Revlog *r, int rev, int ofd)
174 {
175         int err, hfd, pfd, bfd;
176         uchar hash[HASHSZ];
177         Revmap **chain, *m;
178         char buf[32];
179         vlong off;
180         int i;
181
182         err = -1;
183         bfd = -1;
184         pfd = -1;
185
186         if((chain = getchain(r, rev, prevlogrev)) == nil){
187                 werrstr("bad patch chain");
188                 goto errout;
189         }
190
191         off = seek(ofd, 0, 1);
192         if(off < 0){
193                 werrstr("seek outfile: %r");
194                 goto errout;
195         }
196         hfd = r->dfd < 0 ? r->ifd : r->dfd;
197         for(i=0; m = chain[i]; i++){
198                 if(seek(hfd, m->hoff, 0) < 0){
199                         werrstr("seek index: %r");
200                         goto errout;
201                 }
202                 if(m == chain[0] && m->baserev == m->rev){
203                         if(chain[1]){
204                                 if(bfd >= 0 && bfd != ofd)
205                                         close(bfd);
206                                 if((bfd = fmktemp()) < 0){
207                                         werrstr("create basefile: %r");
208                                         goto errout;
209                                 }
210                         } else
211                                 bfd = ofd;
212                         if(funzip(bfd, hfd, m->hlen) < 0){
213                                 werrstr("unzip basefile: %r");
214                                 goto errout;
215                         }
216                 } else {
217                         if(pfd < 0){
218                                 if((pfd = fmktemp()) < 0){
219                                         werrstr("create patchfile: %r");
220                                         goto errout;
221                                 }
222                         }
223
224                         /* put a mark before the patch data */
225                         snprint(buf, sizeof(buf), "%H", m->hash);
226                         if(fpatchmark(pfd, buf) < 0){
227                                 werrstr("patchmark: %r");
228                                 goto errout;
229                         }
230
231                         if(funzip(pfd, hfd, m->hlen) < 0){
232                                 werrstr("unzip patchfile: %r");
233                                 goto errout;
234                         }
235                 }
236         }
237         m = chain[i-1];
238
239         if(pfd >= 0 && bfd >= 0 && bfd != ofd){
240                 if(seek(pfd, 0, 0) < 0){
241                         werrstr("seek patchfile: %r");
242                         goto errout;
243                 }
244                 if(fpatch(ofd, bfd, pfd) < 0){
245                         werrstr("patch: %r");
246                         goto errout;
247                 }
248         }
249
250         if(seek(ofd, off, 0) < 0){
251                 werrstr("seek outfile: %r");
252                 goto errout;
253         }
254         if(fhash(ofd, revhash(r, m->p1rev), revhash(r, m->p2rev), hash) < 0){
255                 werrstr("hash outfile: %r");
256                 goto errout;
257         }
258         if(memcmp(m->hash, hash, HASHSZ)){
259                 werrstr("got bad hash");
260                 goto errout;
261         }
262         err = 0;
263
264 errout:
265         if(pfd >= 0)
266                 close(pfd);
267         if(bfd >= 0 && bfd != ofd)
268                 close(bfd);
269         free(chain);
270
271         return err;
272 }
273
274 int
275 revlogopentemp(Revlog *r, int rev)
276 {
277         int fd;
278
279         if(r->tfd < 0 || rev != r->tid){
280                 if((fd = fmktemp()) < 0)
281                         return -1;
282                 if(revlogextract(r, rev, fd) < 0){
283                         close(fd);
284                         return -1;
285                 }
286                 if(r->tfd >= 0)
287                         close(r->tfd);
288                 r->tfd = fd;
289                 r->tid = rev;
290         }
291         fd = dup(r->tfd, -1);
292         if(seek(fd, 0, 0) < 0){
293                 close(fd);
294                 return -1;
295         }
296         return fd;
297 }
298
299 int
300 fmetaheader(int fd)
301 {
302         static char magic[2] = { 0x01, 0x0A, };
303         char buf[4096], *s, *p;
304         int o, n;
305
306         o = 0;
307         while(o < sizeof(buf)){
308                 if((n = pread(fd, buf+o, sizeof(buf)-o, o)) <= 0)
309                         break;
310                 o += n;
311                 if(o < sizeof(magic))
312                         continue;
313                 if(memcmp(buf, magic, sizeof(magic)) != 0)
314                         break;
315                 s = buf + sizeof(magic);
316                 while((s - buf) <= (o - sizeof(magic))){
317                         if((p = memchr(s, magic[0], o - (s - buf))) == nil)
318                                 break;
319                         if(memcmp(p, magic, sizeof(magic)) == 0)
320                                 return (p - buf) + sizeof(magic);
321                         s = p+1;
322                 }
323         }
324         return 0;
325 }