]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hgfs/revlog.c
hgfs: make qid generation machine independent
[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 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         path = smprint("%s.i", path);
69         if((r->ifd = open(path, mode)) < 0){
70                 free(path);
71                 return -1;
72         }
73         path[strlen(path)-1] = 'd';
74         r->dfd = open(path, mode);
75
76         path[strlen(path)-2] = 0;
77         r->path = path;
78
79         r->ioff = 0;
80         r->nmap = 0;
81         r->map = nil;
82         revlogupdate(r);
83         return 0;
84 }
85
86 void
87 revlogclose(Revlog *r)
88 {
89         if(r->ifd >= 0){
90                 close(r->ifd);
91                 r->ifd = -1;
92         }
93         if(r->dfd >= 0){
94                 close(r->dfd);
95                 r->dfd = -1;
96         }
97         free(r->map);
98         r->map = nil;
99         r->nmap = 0;
100         free(r->path);
101         r->path = nil;
102 }
103
104 uchar*
105 revhash(Revlog *r, int rev)
106 {
107         static uchar nullid[HASHSZ];
108         if(rev < 0 || rev >= r->nmap)
109                 return nullid;
110         return r->map[rev].hash;
111 }
112
113 int
114 hashrev(Revlog *r, uchar hash[])
115 {
116         int rev;
117
118         for(rev=0; rev<r->nmap; rev++)
119                 if(memcmp(r->map[rev].hash, hash, HASHSZ) == 0)
120                         return rev;
121         return -1;
122 }
123
124 static int
125 prevlogrev(Revlog *r, int rev)
126 {
127         if(r->map[rev].baserev == rev)
128                 return -1;
129         return rev-1;
130 }
131
132 static int
133 prevbundlerev(Revlog *r, int rev)
134 {
135         if(r->map[rev].baserev == rev)
136                 return -1;
137         return r->map[rev].p1rev;
138 }
139
140 static Revmap**
141 getchain1(Revlog *r, int rev, int *count, int (*next)(Revlog *, int))
142 {
143         Revmap **chain;
144
145         if(rev < 0 || rev >= r->nmap){
146                 if(*count <= 0)
147                         return nil;
148                 chain = malloc(sizeof(chain[0]) * ((*count)+1));
149                 chain[*count] = nil;
150                 *count = 0;
151         }else{
152                 (*count)++;
153                 if(chain = getchain1(r, (*next)(r, rev), count, next))
154                         chain[(*count)++] = &r->map[rev];
155         }
156         return chain;
157 }
158
159 static Revmap**
160 getchain(Revlog *r, int rev, int (*next)(Revlog *, int))
161 {
162         int count = 0;
163         return getchain1(r, rev, &count, next);
164 }
165
166 int
167 revlogextract(Revlog *r, int rev, int ofd)
168 {
169         int err, hfd, pfd, bfd;
170         uchar hash[HASHSZ];
171         Revmap **chain, *m;
172         char buf[32];
173         vlong off;
174         int i;
175
176         err = -1;
177         bfd = -1;
178         pfd = -1;
179
180         if((chain = getchain(r, rev, prevlogrev)) == nil){
181                 werrstr("bad patch chain");
182                 goto errout;
183         }
184
185         off = seek(ofd, 0, 1);
186         if(off < 0){
187                 werrstr("seek outfile: %r");
188                 goto errout;
189         }
190         hfd = r->dfd < 0 ? r->ifd : r->dfd;
191         for(i=0; m = chain[i]; i++){
192                 if(seek(hfd, m->hoff, 0) < 0){
193                         werrstr("seek index: %r");
194                         goto errout;
195                 }
196                 if(m == chain[0] && m->baserev == m->rev){
197                         if(chain[1]){
198                                 if(bfd >= 0 && bfd != ofd)
199                                         close(bfd);
200                                 if((bfd = fmktemp()) < 0){
201                                         werrstr("create basefile: %r");
202                                         goto errout;
203                                 }
204                         } else
205                                 bfd = ofd;
206                         if(funzip(bfd, hfd, m->hlen) < 0){
207                                 werrstr("unzip basefile: %r");
208                                 goto errout;
209                         }
210                 } else {
211                         if(pfd < 0){
212                                 if((pfd = fmktemp()) < 0){
213                                         werrstr("create patchfile: %r");
214                                         goto errout;
215                                 }
216                         }
217
218                         /* put a mark before the patch data */
219                         snprint(buf, sizeof(buf), "%H", m->hash);
220                         if(fpatchmark(pfd, buf) < 0){
221                                 werrstr("patchmark: %r");
222                                 goto errout;
223                         }
224
225                         if(funzip(pfd, hfd, m->hlen) < 0){
226                                 werrstr("unzip patchfile: %r");
227                                 goto errout;
228                         }
229                 }
230         }
231         m = chain[i-1];
232
233         if(pfd >= 0 && bfd >= 0 && bfd != ofd){
234                 if(seek(pfd, 0, 0) < 0){
235                         werrstr("seek patchfile: %r");
236                         goto errout;
237                 }
238                 if(fpatch(ofd, bfd, pfd) < 0){
239                         werrstr("patch: %r");
240                         goto errout;
241                 }
242         }
243
244         if(seek(ofd, off, 0) < 0){
245                 werrstr("seek outfile: %r");
246                 goto errout;
247         }
248         if(fhash(ofd, revhash(r, m->p1rev), revhash(r, m->p2rev), hash) < 0){
249                 werrstr("hash outfile: %r");
250                 goto errout;
251         }
252         if(memcmp(m->hash, hash, HASHSZ)){
253                 werrstr("got bad hash");
254                 goto errout;
255         }
256         err = 0;
257
258 errout:
259         if(pfd >= 0)
260                 close(pfd);
261         if(bfd >= 0 && bfd != ofd)
262                 close(bfd);
263         free(chain);
264
265         return err;
266 }
267
268 int
269 revlogopentemp(Revlog *r, int rev)
270 {
271         int fd;
272
273         if((fd = fmktemp()) < 0)
274                 return -1;
275         if(revlogextract(r, rev, fd) < 0){
276                 close(fd);
277                 return -1;
278         }
279         if(seek(fd, 0, 0) < 0){
280                 close(fd);
281                 return -1;
282         }
283         return fd;
284 }