]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hgfs/revlog.c
e4d9fcfa1831bc33b6c4f0ae0e432d6bc082ddd9
[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         char temp[MAXPATH];
11
12         snprint(temp, sizeof(temp), "/tmp/hgXXXXXXXXXXX");
13         return create(mktemp(temp), OTRUNC|ORCLOSE|ORDWR, 0666);
14 }
15
16 static void
17 readindex(Revlog *r)
18 {
19         uchar buf[64];
20         Revmap *m;
21         int rev;
22
23         seek(r->ifd, 0, 0);
24         for(rev=0;;rev++){
25                 if(readn(r->ifd, buf, sizeof(buf)) != sizeof(buf))
26                         break;
27                 if((rev % 16) == 0)
28                         r->map = realloc(r->map, sizeof(r->map[0])*(rev+16));
29                 m = &r->map[rev];
30                 memset(m, 0, sizeof(*m));
31                 m->hoff = (vlong)buf[0]<<40 | 
32                         (vlong)buf[1]<<32 |
33                         (vlong)buf[2]<<24 | 
34                         (vlong)buf[3]<<16 | 
35                         (vlong)buf[4]<<8 | 
36                         (vlong)buf[5];
37                 if(rev == 0)
38                         m->hoff &= 0xFFFF;
39                 m->rev = rev;
40                 m->flags = buf[6]<<8 | buf[7];
41                 m->hlen = buf[8]<<24 | buf[9]<<16 | buf[10]<<8 | buf[11];
42                 m->flen = buf[12]<<24 | buf[13]<<16 | buf[14]<<8 | buf[15];
43                 m->baserev = buf[16]<<24 | buf[17]<<16 | buf[18]<<8 | buf[19];
44                 m->linkrev = buf[20]<<24 | buf[21]<<16 | buf[22]<<8 | buf[23];
45                 m->p1rev = buf[24]<<24 | buf[25]<<16 | buf[26]<<8 | buf[27];
46                 m->p2rev = buf[28]<<24 | buf[29]<<16 | buf[30]<<8 | buf[31];
47                 memmove(m->hash, buf+32, HASHSZ);
48
49                 if(r->dfd < 0){
50                         m->hoff = seek(r->ifd, 0, 1);
51                         seek(r->ifd, m->hlen, 1);
52                 }
53         }
54         r->nmap = rev;
55 }
56
57 int
58 revlogopen(Revlog *r, char *path, int mode)
59 {
60         r->ifd = -1;
61         r->dfd = -1;
62         path = smprint("%s.i", path);
63         if((r->ifd = open(path, mode)) < 0){
64                 free(path);
65                 return -1;
66         }
67         path[strlen(path)-1] = 'd';
68         r->dfd = open(path, mode);
69         free(path);
70         r->nmap = 0;
71         r->map = nil;
72         readindex(r);
73         return 0;
74 }
75
76 void
77 revlogclose(Revlog *r)
78 {
79         if(r->ifd >= 0){
80                 close(r->ifd);
81                 r->ifd = -1;
82         }
83         if(r->dfd >= 0){
84                 close(r->dfd);
85                 r->dfd = -1;
86         }
87         free(r->map);
88         r->map = nil;
89         r->nmap = 0;
90 }
91
92 uchar*
93 revhash(Revlog *r, int rev)
94 {
95         static uchar nullid[HASHSZ];
96         if(rev < 0 || rev >= r->nmap)
97                 return nullid;
98         return r->map[rev].hash;
99 }
100
101 int
102 hashrev(Revlog *r, uchar hash[])
103 {
104         int rev;
105
106         for(rev=0; rev<r->nmap; rev++)
107                 if(memcmp(r->map[rev].hash, hash, HASHSZ) == 0)
108                         return rev;
109         return -1;
110 }
111
112 static int
113 prevlogrev(Revlog *r, int rev)
114 {
115         if(r->map[rev].baserev == rev)
116                 return -1;
117         return rev-1;
118 }
119
120 static int
121 prevbundlerev(Revlog *r, int rev)
122 {
123         if(r->map[rev].baserev == rev)
124                 return -1;
125         return r->map[rev].p1rev;
126 }
127
128 static Revmap**
129 getchain1(Revlog *r, int rev, int *count, int (*next)(Revlog *, int))
130 {
131         Revmap **chain;
132
133         if(rev < 0 || rev >= r->nmap){
134                 if(*count <= 0)
135                         return nil;
136                 chain = malloc(sizeof(chain[0]) * ((*count)+1));
137                 chain[*count] = nil;
138                 *count = 0;
139         }else{
140                 (*count)++;
141                 if(chain = getchain1(r, (*next)(r, rev), count, next))
142                         chain[(*count)++] = &r->map[rev];
143         }
144         return chain;
145 }
146
147 static Revmap**
148 getchain(Revlog *r, int rev, int (*next)(Revlog *, int))
149 {
150         int count = 0;
151         return getchain1(r, rev, &count, next);
152 }
153
154 int
155 revlogextract(Revlog *r, int rev, int ofd)
156 {
157         int err, hfd, pfd, bfd;
158         uchar hash[HASHSZ];
159         Revmap **chain, *m;
160         char buf[32];
161         vlong off;
162         int i;
163
164         err = -1;
165         bfd = -1;
166         pfd = -1;
167
168         if((chain = getchain(r, rev, prevlogrev)) == nil){
169                 werrstr("bad patch chain");
170                 goto errout;
171         }
172
173         off = seek(ofd, 0, 1);
174         if(off < 0){
175                 werrstr("seek outfile: %r");
176                 goto errout;
177         }
178         hfd = r->dfd < 0 ? r->ifd : r->dfd;
179         for(i=0; m = chain[i]; i++){
180                 if(seek(hfd, m->hoff, 0) < 0){
181                         werrstr("seek index: %r");
182                         goto errout;
183                 }
184                 if(m == chain[0] && m->baserev == m->rev){
185                         if(chain[1]){
186                                 if(bfd >= 0 && bfd != ofd)
187                                         close(bfd);
188                                 if((bfd = fmktemp()) < 0){
189                                         werrstr("create basefile: %r");
190                                         goto errout;
191                                 }
192                         } else
193                                 bfd = ofd;
194                         if(funzip(bfd, hfd, m->hlen) < 0){
195                                 werrstr("unzip basefile: %r");
196                                 goto errout;
197                         }
198                 } else {
199                         if(pfd < 0){
200                                 if((pfd = fmktemp()) < 0){
201                                         werrstr("create patchfile: %r");
202                                         goto errout;
203                                 }
204                         }
205
206                         /* put a mark before the patch data */
207                         snprint(buf, sizeof(buf), "%H", m->hash);
208                         if(fpatchmark(pfd, buf) < 0){
209                                 werrstr("patchmark: %r");
210                                 goto errout;
211                         }
212
213                         if(funzip(pfd, hfd, m->hlen) < 0){
214                                 werrstr("unzip patchfile: %r");
215                                 goto errout;
216                         }
217                 }
218         }
219         m = chain[i-1];
220
221         if(pfd >= 0 && bfd >= 0 && bfd != ofd){
222                 if(seek(pfd, 0, 0) < 0){
223                         werrstr("seek patchfile: %r");
224                         goto errout;
225                 }
226                 if(fpatch(ofd, bfd, pfd) < 0){
227                         werrstr("patch: %r");
228                         goto errout;
229                 }
230         }
231
232         if(seek(ofd, off, 0) < 0){
233                 werrstr("seek outfile: %r");
234                 goto errout;
235         }
236         if(fhash(ofd, revhash(r, m->p1rev), revhash(r, m->p2rev), hash) < 0){
237                 werrstr("hash outfile: %r");
238                 goto errout;
239         }
240         if(memcmp(m->hash, hash, HASHSZ)){
241                 werrstr("got bad hash");
242                 goto errout;
243         }
244         err = 0;
245
246 errout:
247         if(pfd >= 0)
248                 close(pfd);
249         if(bfd >= 0 && bfd != ofd)
250                 close(bfd);
251         free(chain);
252
253         return err;
254 }
255
256 int
257 revlogopentemp(Revlog *r, int rev)
258 {
259         int fd;
260
261         if((fd = fmktemp()) < 0)
262                 return -1;
263         if(revlogextract(r, rev, fd) < 0){
264                 close(fd);
265                 return -1;
266         }
267         if(seek(fd, 0, 0) < 0){
268                 close(fd);
269                 return -1;
270         }
271         return fd;
272 }