blob: bcb9b57e22665e1ab95eccfd12cc5a22244d72a6 [file] [log] [blame]
rsccb98c6f2005-01-14 18:46:35 +00001#include <u.h>
rsc2277c5d2004-03-21 04:33:13 +00002#include <sys/stat.h>
rsc3d77c872004-03-15 01:56:49 +00003#include "stdinc.h"
4#include "vac.h"
5#include "dat.h"
6#include "fns.h"
rsc7763a612003-11-23 17:55:34 +00007
rsc2277c5d2004-03-21 04:33:13 +00008int mainstacksize = 128*1024;
9
rsc3d77c872004-03-15 01:56:49 +000010typedef struct Sink Sink;
11typedef struct MetaSink MetaSink;
12typedef struct DirSink DirSink;
rsc7763a612003-11-23 17:55:34 +000013
rsc3d77c872004-03-15 01:56:49 +000014struct Sink {
15 VtConn *z;
16 VtEntry dir;
17 uchar *buf;
18 uchar *pbuf[VtPointerDepth+1];
19};
20
21struct DirSink {
22 Sink *sink;
23 MetaSink *msink;
24 ulong nentry;
25 uchar *buf;
26 uchar *p; /* current pointer */
27 uchar *ep; /* end pointer */
28};
29
30struct MetaSink {
31 Sink *sink;
32 uchar *buf;
33 int maxindex;
34 int nindex;
35 uchar *rp; /* start of current record */
36 uchar *p; /* current pointer */
37 uchar *ep; /* end pointer */
38};
39
40static void usage(void);
41static int strpcmp(const void*, const void*);
42static void warn(char *fmt, ...);
43static void cleanup(void);
44static u64int unittoull(char *s);
45static void vac(VtConn *z, char *argv[]);
46static void vacfile(DirSink *dsink, char *lname, char *sname, VacFile*);
47static void vacstdin(DirSink *dsink, char *name, VacFile *vf);
48static void vacdata(DirSink *dsink, int fd, char *lname, VacFile*, Dir*);
49static void vacdir(DirSink *dsink, int fd, char *lname, char *sname, VacFile*);
50static int vacmerge(DirSink *dsink, char *lname, char *sname);
51
52Sink *sinkalloc(VtConn *z, int psize, int dsize);
53void sinkwrite(Sink *k, uchar *data, int n);
54void sinkwritescore(Sink *k, uchar *score, int n);
55void sinkclose(Sink *k);
56void sinkfree(Sink *k);
57
58DirSink *dirsinkalloc(VtConn *z, int psize, int dsize);
59void dirsinkwrite(DirSink *k, VtEntry*);
60void dirsinkwritesink(DirSink *k, Sink*);
61int dirsinkwritefile(DirSink *k, VacFile *vf);
62void dirsinkclose(DirSink *k);
63void dirsinkfree(DirSink *k);
64
65MetaSink *metasinkalloc(VtConn *z, int psize, int dsize);
66void metasinkputc(MetaSink *k, int c);
67void metasinkputstring(MetaSink *k, char *s);
68void metasinkputuint32(MetaSink *k, ulong x);
69void metasinkputuint64(MetaSink *k, uvlong x);
70void metasinkwrite(MetaSink *k, uchar *data, int n);
71void metasinkwritedir(MetaSink *ms, VacDir *vd);
72void metasinkeor(MetaSink *k);
73void metasinkclose(MetaSink *k);
74void metasinkfree(MetaSink *k);
75void plan9tovacdir(VacDir*, Dir*, ulong entry, uvlong qid);
76
77enum {
78 Version = 8,
79 BlockSize = 8*1024,
80 MaxExclude = 1000,
81};
82
83struct {
84 ulong file;
85 ulong sfile;
86 ulong data;
87 ulong sdata;
88 ulong skip;
89 ulong meta;
90} stats;
91
92int bsize = BlockSize;
93int maxbsize;
94char *oname, *dfile;
95int verbose;
96uvlong fileid = 1;
97int qdiff;
98char *exclude[MaxExclude];
99int nexclude;
100int nowrite;
101int merge;
102char *isi;
103
104static void
rsc7763a612003-11-23 17:55:34 +0000105usage(void)
106{
rsc3d77c872004-03-15 01:56:49 +0000107 fprint(2, "usage: %s [-amqsv] [-h host] [-d vacfile] [-b blocksize] [-i name] [-e exclude] [-f vacfile] file ... \n", argv0);
rsc38c10d12005-01-17 21:29:00 +0000108 threadexitsall("usage");
rsc7763a612003-11-23 17:55:34 +0000109}
110
111void
rsc3d77c872004-03-15 01:56:49 +0000112threadmain(int argc, char *argv[])
rsc7763a612003-11-23 17:55:34 +0000113{
rsc3d77c872004-03-15 01:56:49 +0000114 VtConn *z;
115 char *p;
116 char *host = nil;
117 int statsflag = 0;
118
119 atexit(cleanup);
120
rsc7763a612003-11-23 17:55:34 +0000121 ARGBEGIN{
122 default:
123 usage();
124 case 'b':
rsc3d77c872004-03-15 01:56:49 +0000125 p = ARGF();
126 if(p == 0)
127 usage();
128 bsize = unittoull(p);
129 if(bsize == ~0)
130 usage();
131 break;
132 case 'd':
133 dfile = ARGF();
134 if(dfile == nil)
135 usage();
136 break;
137 case 'e':
138 if(nexclude >= MaxExclude)
139 sysfatal("too many exclusions\n");
140 exclude[nexclude] = ARGF();
141 if(exclude[nexclude] == nil)
142 usage();
143 nexclude++;
144 break;
145 case 'f':
146 oname = ARGF();
147 if(oname == 0)
148 usage();
rsc7763a612003-11-23 17:55:34 +0000149 break;
150 case 'h':
rsc3d77c872004-03-15 01:56:49 +0000151 host = ARGF();
152 if(host == nil)
153 usage();
rsc7763a612003-11-23 17:55:34 +0000154 break;
rsc3d77c872004-03-15 01:56:49 +0000155 case 'i':
156 isi = ARGF();
157 if(isi == nil)
158 usage();
159 break;
160 case 'n':
161 nowrite++;
162 break;
163 case 'm':
164 merge++;
165 break;
166 case 'q':
167 qdiff++;
168 break;
169 case 's':
170 statsflag++;
171 break;
172 case 'v':
173 verbose++;
174 break;
175 }ARGEND;
rsc7763a612003-11-23 17:55:34 +0000176
rsc2277c5d2004-03-21 04:33:13 +0000177 if(argc == 0)
178 usage();
179
rsc7763a612003-11-23 17:55:34 +0000180 if(bsize < 512)
181 bsize = 512;
182 if(bsize > VtMaxLumpSize)
183 bsize = VtMaxLumpSize;
184 maxbsize = bsize;
185
rsc3d77c872004-03-15 01:56:49 +0000186 fmtinstall('V', vtscorefmt);
rsc7763a612003-11-23 17:55:34 +0000187
rsc3d77c872004-03-15 01:56:49 +0000188 z = vtdial(host);
rsc7763a612003-11-23 17:55:34 +0000189 if(z == nil)
rsc3d77c872004-03-15 01:56:49 +0000190 sysfatal("could not connect to server: %r");
rsc7763a612003-11-23 17:55:34 +0000191
rsc3d77c872004-03-15 01:56:49 +0000192 if(vtconnect(z) < 0)
193 sysfatal("vtconnect: %r");
rsc7763a612003-11-23 17:55:34 +0000194
rsc3d77c872004-03-15 01:56:49 +0000195 qsort(exclude, nexclude, sizeof(char*), strpcmp);
rsc7763a612003-11-23 17:55:34 +0000196
197 vac(z, argv);
rsc3d77c872004-03-15 01:56:49 +0000198
199 if(vtsync(z) < 0)
rsc929fcfe2004-12-27 21:05:39 +0000200 fprint(2, "warning: could not ask server to flush pending writes: %r\n");
rsc7763a612003-11-23 17:55:34 +0000201
rsc3d77c872004-03-15 01:56:49 +0000202 if(statsflag)
rsc7763a612003-11-23 17:55:34 +0000203 fprint(2, "files %ld:%ld data %ld:%ld:%ld meta %ld\n", stats.file, stats.sfile,
204 stats.data, stats.skip, stats.sdata, stats.meta);
205//packetStats();
rsc3d77c872004-03-15 01:56:49 +0000206 vthangup(z);
rsc7763a612003-11-23 17:55:34 +0000207
rsc3d77c872004-03-15 01:56:49 +0000208 threadexitsall(0);
rsc7763a612003-11-23 17:55:34 +0000209}
210
211static int
rsc3d77c872004-03-15 01:56:49 +0000212strpcmp(const void *p0, const void *p1)
213{
214 return strcmp(*(char**)p0, *(char**)p1);
215}
216
217int
218vacwrite(VtConn *z, uchar score[VtScoreSize], int type, uchar *buf, int n)
219{
220 assert(n > 0);
221 if(nowrite){
222 sha1(buf, n, score, nil);
223 return 0;
224 }
rsc3d77c872004-03-15 01:56:49 +0000225 return vtwrite(z, score, type, buf, n);
226}
227
228static char*
229lastelem(char *oname)
230{
231 char *p;
232
233 if(oname == nil)
234 abort();
235 if((p = strrchr(oname, '/')) == nil)
236 return oname;
237 return p+1;
238}
239
240static void
241vac(VtConn *z, char *argv[])
rsc7763a612003-11-23 17:55:34 +0000242{
243 DirSink *dsink, *ds;
244 MetaSink *ms;
245 VtRoot root;
246 uchar score[VtScoreSize], buf[VtRootSize];
247 char cwd[2048];
rsc3d77c872004-03-15 01:56:49 +0000248 int cd;
rsc7763a612003-11-23 17:55:34 +0000249 char *cp2, *cp;
rsc3d77c872004-03-15 01:56:49 +0000250 VacFs *fs;
rsc7763a612003-11-23 17:55:34 +0000251 VacFile *vff;
252 int fd;
253 Dir *dir;
254 VacDir vd;
255
256 if(getwd(cwd, sizeof(cwd)) == 0)
257 sysfatal("can't find current directory: %r\n");
258
rsc3d77c872004-03-15 01:56:49 +0000259 dsink = dirsinkalloc(z, bsize, bsize);
rsc7763a612003-11-23 17:55:34 +0000260
261 fs = nil;
262 if(dfile != nil) {
rsc3d77c872004-03-15 01:56:49 +0000263 fs = vacfsopen(z, dfile, VtOREAD, 1000);
rsc7763a612003-11-23 17:55:34 +0000264 if(fs == nil)
rsc3d77c872004-03-15 01:56:49 +0000265 fprint(2, "could not open diff: %s: %r\n", dfile);
rsc7763a612003-11-23 17:55:34 +0000266 }
267
268
269 if(oname != nil) {
270 fd = create(oname, OWRITE, 0666);
271 if(fd < 0)
272 sysfatal("could not create file: %s: %r", oname);
273 } else
274 fd = 1;
275
276 dir = dirfstat(fd);
277 if(dir == nil)
278 sysfatal("dirfstat failed: %r");
rsc3d77c872004-03-15 01:56:49 +0000279 if(oname)
280 dir->name = lastelem(oname);
281 else
282 dir->name = "stdin";
rsc7763a612003-11-23 17:55:34 +0000283
284 for(; *argv; argv++) {
285 cp2 = *argv;
286 cd = 0;
287 for (cp = *argv; *cp; cp++)
288 if (*cp == '/')
289 cp2 = cp;
290 if (cp2 != *argv) {
291 *cp2 = '\0';
292 chdir(*argv);
293 *cp2 = '/';
294 cp2++;
295 cd = 1;
296 }
297 vff = nil;
298 if(fs)
rsc3d77c872004-03-15 01:56:49 +0000299 vff = vacfileopen(fs, cp2);
300 vacfile(dsink, argv[0], cp2, vff);
rsc7763a612003-11-23 17:55:34 +0000301 if(vff)
rsc3d77c872004-03-15 01:56:49 +0000302 vacfiledecref(vff);
rsc7763a612003-11-23 17:55:34 +0000303 if(cd && chdir(cwd) < 0)
304 sysfatal("can't cd back to %s: %r\n", cwd);
305 }
306
307 if(isi) {
308 vff = nil;
309 if(fs)
rsc3d77c872004-03-15 01:56:49 +0000310 vff = vacfileopen(fs, isi);
311 vacstdin(dsink, isi, vff);
rsc7763a612003-11-23 17:55:34 +0000312 if(vff)
rsc3d77c872004-03-15 01:56:49 +0000313 vacfiledecref(vff);
rsc7763a612003-11-23 17:55:34 +0000314 }
315
rsc3d77c872004-03-15 01:56:49 +0000316 dirsinkclose(dsink);
rsc7763a612003-11-23 17:55:34 +0000317
318 /* build meta information for the root */
rsc3d77c872004-03-15 01:56:49 +0000319 ms = metasinkalloc(z, bsize, bsize);
rsc7763a612003-11-23 17:55:34 +0000320 /* fake into a directory */
rsc23fb2ed2005-07-24 20:15:44 +0000321 dir->mode = DMDIR|0555;
rsc7763a612003-11-23 17:55:34 +0000322 dir->qid.type |= QTDIR;
rsc3d77c872004-03-15 01:56:49 +0000323 plan9tovacdir(&vd, dir, 0, fileid++);
rsc7763a612003-11-23 17:55:34 +0000324 if(strcmp(vd.elem, "/") == 0){
rsc3d77c872004-03-15 01:56:49 +0000325 vtfree(vd.elem);
326 vd.elem = vtstrdup("root");
rsc7763a612003-11-23 17:55:34 +0000327 }
rsc3d77c872004-03-15 01:56:49 +0000328 metasinkwritedir(ms, &vd);
329 vdcleanup(&vd);
330 metasinkclose(ms);
rsc7763a612003-11-23 17:55:34 +0000331
rsc3d77c872004-03-15 01:56:49 +0000332 ds = dirsinkalloc(z, bsize, bsize);
333 dirsinkwritesink(ds, dsink->sink);
334 dirsinkwritesink(ds, dsink->msink->sink);
335 dirsinkwritesink(ds, ms->sink);
336 dirsinkclose(ds);
rsc7763a612003-11-23 17:55:34 +0000337
338 memset(&root, 0, sizeof(root));
rsc7763a612003-11-23 17:55:34 +0000339 strncpy(root.name, dir->name, sizeof(root.name));
340 root.name[sizeof(root.name)-1] = 0;
341 free(dir);
342 sprint(root.type, "vac");
343 memmove(root.score, ds->sink->dir.score, VtScoreSize);
rsc3d77c872004-03-15 01:56:49 +0000344 root.blocksize = maxbsize;
rsc7763a612003-11-23 17:55:34 +0000345 if(fs != nil)
rsc3d77c872004-03-15 01:56:49 +0000346 vacfsgetscore(fs, root.prev);
rsc7763a612003-11-23 17:55:34 +0000347
rsc3d77c872004-03-15 01:56:49 +0000348 metasinkfree(ms);
349 dirsinkfree(ds);
350 dirsinkfree(dsink);
rsc7763a612003-11-23 17:55:34 +0000351 if(fs != nil)
rsc3d77c872004-03-15 01:56:49 +0000352 vacfsclose(fs);
rsc7763a612003-11-23 17:55:34 +0000353
rsc3d77c872004-03-15 01:56:49 +0000354 vtrootpack(&root, buf);
355 if(vacwrite(z, score, VtRootType, buf, VtRootSize) < 0)
356 sysfatal("vacWrite failed: %r");
rsc7763a612003-11-23 17:55:34 +0000357
rsc3d77c872004-03-15 01:56:49 +0000358 fprint(fd, "vac:%V\n", score);
359
rsc7763a612003-11-23 17:55:34 +0000360 /* avoid remove at cleanup */
361 oname = nil;
rsc7763a612003-11-23 17:55:34 +0000362}
363
364static int
rsc3d77c872004-03-15 01:56:49 +0000365isexcluded(char *name)
rsc7763a612003-11-23 17:55:34 +0000366{
367 int bot, top, i, x;
368
369 bot = 0;
370 top = nexclude;
371 while(bot < top) {
372 i = (bot+top)>>1;
373 x = strcmp(exclude[i], name);
374 if(x == 0)
375 return 1;
376 if(x < 0)
377 bot = i + 1;
378 else /* x > 0 */
379 top = i;
380 }
381 return 0;
382}
383
384static void
rsc3d77c872004-03-15 01:56:49 +0000385vacfile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
rsc7763a612003-11-23 17:55:34 +0000386{
387 int fd;
388 Dir *dir;
389 VacDir vd;
390 ulong entry;
391
rsc3d77c872004-03-15 01:56:49 +0000392 if(isexcluded(lname)) {
rsc7763a612003-11-23 17:55:34 +0000393 warn("excluding: %s", lname);
394 return;
395 }
396
rsc3d77c872004-03-15 01:56:49 +0000397 if(merge && vacmerge(dsink, lname, sname) >= 0)
rsc7763a612003-11-23 17:55:34 +0000398 return;
399
rsc5fc55a92005-02-08 20:27:10 +0000400 if((dir = dirstat(sname)) == nil){
401 warn("could not stat file %s: %r", lname);
rsc6c0209f2005-02-11 20:32:41 +0000402 return;
403 }
rsc5fc55a92005-02-08 20:27:10 +0000404 if(dir->mode&(DMSYMLINK|DMDEVICE|DMNAMEDPIPE|DMSOCKET)){
405 free(dir);
rsc2277c5d2004-03-21 04:33:13 +0000406 return;
rsc5fc55a92005-02-08 20:27:10 +0000407 }
408 free(dir);
409
rsc7763a612003-11-23 17:55:34 +0000410 fd = open(sname, OREAD);
411 if(fd < 0) {
rsc3d77c872004-03-15 01:56:49 +0000412 warn("could not open file: %s: %r", lname);
rsc7763a612003-11-23 17:55:34 +0000413 return;
414 }
415
416 if(verbose)
417 fprint(2, "%s\n", lname);
418
419 dir = dirfstat(fd);
420 if(dir == nil) {
421 warn("can't stat %s: %r", lname);
422 close(fd);
423 return;
424 }
rsc3d77c872004-03-15 01:56:49 +0000425 dir->name = lastelem(sname);
rsc7763a612003-11-23 17:55:34 +0000426
427 entry = dsink->nentry;
428
429 if(dir->mode & DMDIR)
rsc3d77c872004-03-15 01:56:49 +0000430 vacdir(dsink, fd, lname, sname, vf);
rsc7763a612003-11-23 17:55:34 +0000431 else
rsc3d77c872004-03-15 01:56:49 +0000432 vacdata(dsink, fd, lname, vf, dir);
rsc7763a612003-11-23 17:55:34 +0000433
rsc3d77c872004-03-15 01:56:49 +0000434 plan9tovacdir(&vd, dir, entry, fileid++);
435 metasinkwritedir(dsink->msink, &vd);
436 vdcleanup(&vd);
rsc7763a612003-11-23 17:55:34 +0000437
438 free(dir);
439 close(fd);
440}
441
442static void
rsc3d77c872004-03-15 01:56:49 +0000443vacstdin(DirSink *dsink, char *name, VacFile *vf)
rsc7763a612003-11-23 17:55:34 +0000444{
445 Dir *dir;
446 VacDir vd;
447 ulong entry;
448
449 if(verbose)
450 fprint(2, "%s\n", "<stdio>");
451
452 dir = dirfstat(0);
453 if(dir == nil) {
454 warn("can't stat <stdio>: %r");
455 return;
456 }
rsc3d77c872004-03-15 01:56:49 +0000457 dir->name = "stdin";
rsc7763a612003-11-23 17:55:34 +0000458
459 entry = dsink->nentry;
460
rsc3d77c872004-03-15 01:56:49 +0000461 vacdata(dsink, 0, "<stdin>", vf, dir);
rsc7763a612003-11-23 17:55:34 +0000462
rsc3d77c872004-03-15 01:56:49 +0000463 plan9tovacdir(&vd, dir, entry, fileid++);
464 vd.elem = vtstrdup(name);
465 metasinkwritedir(dsink->msink, &vd);
466 vdcleanup(&vd);
rsc7763a612003-11-23 17:55:34 +0000467
468 free(dir);
469}
470
rsc3d77c872004-03-15 01:56:49 +0000471static int
472sha1check(u8int *score, uchar *buf, int n)
473{
rscedefa242005-03-15 20:27:59 +0000474 uchar score2[VtScoreSize];
rsc3d77c872004-03-15 01:56:49 +0000475
rsc3e1960c2005-02-18 18:28:00 +0000476 sha1(buf, n, score2, nil);
rsc3d77c872004-03-15 01:56:49 +0000477 if(memcmp(score, score2, VtScoreSize) == 0)
478 return 0;
479 return -1;
480}
481
rsc7763a612003-11-23 17:55:34 +0000482static ulong
rsc3d77c872004-03-15 01:56:49 +0000483vacdataskip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lname)
rsc7763a612003-11-23 17:55:34 +0000484{
485 int n;
486 ulong i;
487 uchar score[VtScoreSize];
488
489 /* skip blocks for append only files */
490 if(seek(fd, (blocks-1)*bsize, 0) != (blocks-1)*bsize) {
491 warn("error seeking: %s", lname);
492 goto Err;
493 }
rsc3d77c872004-03-15 01:56:49 +0000494 n = readn(fd, buf, bsize);
rsc7763a612003-11-23 17:55:34 +0000495 if(n < bsize) {
496 warn("error checking append only file: %s", lname);
497 goto Err;
498 }
rsc3d77c872004-03-15 01:56:49 +0000499 if(vacfileblockscore(vf, blocks-1, score)<0 || sha1check(score, buf, n)<0) {
rsc7763a612003-11-23 17:55:34 +0000500 warn("last block of append file did not match: %s", lname);
501 goto Err;
502 }
503
504 for(i=0; i<blocks; i++) {
rsc3d77c872004-03-15 01:56:49 +0000505 if(vacfileblockscore(vf, i, score) < 0) {
rsc7763a612003-11-23 17:55:34 +0000506 warn("could not get score: %s: %lud", lname, i);
507 seek(fd, i*bsize, 0);
508 return i;
509 }
510 stats.skip++;
rsc3d77c872004-03-15 01:56:49 +0000511 sinkwritescore(sink, score, bsize);
rsc7763a612003-11-23 17:55:34 +0000512 }
513
514 return i;
515Err:
516 seek(fd, 0, 0);
517 return 0;
518}
519
520static void
rsc3d77c872004-03-15 01:56:49 +0000521vacdata(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir)
rsc7763a612003-11-23 17:55:34 +0000522{
523 uchar *buf;
524 Sink *sink;
525 int n;
526 uchar score[VtScoreSize];
527 ulong block, same;
528 VacDir vd;
529 ulong vfblocks;
530
531 vfblocks = 0;
532 if(vf != nil && qdiff) {
rsc3d77c872004-03-15 01:56:49 +0000533 vacfilegetdir(vf, &vd);
rsc7763a612003-11-23 17:55:34 +0000534 if(vd.mtime == dir->mtime)
535 if(vd.size == dir->length)
536 if(!vd.plan9 || /* vd.p9path == dir->qid.path && */ vd.p9version == dir->qid.vers)
rsc3d77c872004-03-15 01:56:49 +0000537 if(dirsinkwritefile(dsink, vf)) {
rsc7763a612003-11-23 17:55:34 +0000538 stats.sfile++;
rsc3d77c872004-03-15 01:56:49 +0000539 vdcleanup(&vd);
rsc7763a612003-11-23 17:55:34 +0000540 return;
541 }
542
543 /* look for an append only file */
544 if((dir->mode&DMAPPEND) != 0)
545 if(vd.size < dir->length)
546 if(vd.plan9)
547 if(vd.p9path == dir->qid.path)
548 vfblocks = vd.size/bsize;
549
rsc3d77c872004-03-15 01:56:49 +0000550 vdcleanup(&vd);
rsc7763a612003-11-23 17:55:34 +0000551 }
552 stats.file++;
553
rsc3d77c872004-03-15 01:56:49 +0000554 buf = vtmalloc(bsize);
555 sink = sinkalloc(dsink->sink->z, bsize, bsize);
rsc7763a612003-11-23 17:55:34 +0000556 block = 0;
557 same = stats.sdata+stats.skip;
558
559 if(vfblocks > 1)
rsc3d77c872004-03-15 01:56:49 +0000560 block += vacdataskip(sink, vf, fd, vfblocks, buf, lname);
rsc7763a612003-11-23 17:55:34 +0000561
562if(0) fprint(2, "vacData: %s: %ld\n", lname, block);
563 for(;;) {
rsc3d77c872004-03-15 01:56:49 +0000564 n = readn(fd, buf, bsize);
rsc7763a612003-11-23 17:55:34 +0000565 if(0 && n < 0)
rsc3d77c872004-03-15 01:56:49 +0000566 warn("file truncated due to read error: %s: %r", lname);
rsc7763a612003-11-23 17:55:34 +0000567 if(n <= 0)
568 break;
rsc3e1960c2005-02-18 18:28:00 +0000569 if(vf != nil && vacfileblockscore(vf, block, score)>=0 && sha1check(score, buf, n)>=0) {
rsc7763a612003-11-23 17:55:34 +0000570 stats.sdata++;
rsc3d77c872004-03-15 01:56:49 +0000571 sinkwritescore(sink, score, n);
rsc7763a612003-11-23 17:55:34 +0000572 } else
rsc3d77c872004-03-15 01:56:49 +0000573 sinkwrite(sink, buf, n);
rsc7763a612003-11-23 17:55:34 +0000574 block++;
575 }
576 same = stats.sdata+stats.skip - same;
577
578 if(same && (dir->mode&DMAPPEND) != 0)
579 if(0)fprint(2, "%s: total %lud same %lud:%lud diff %lud\n",
580 lname, block, same, vfblocks, block-same);
581
rsc3d77c872004-03-15 01:56:49 +0000582 sinkclose(sink);
583 dirsinkwritesink(dsink, sink);
584 sinkfree(sink);
rsc7763a612003-11-23 17:55:34 +0000585 free(buf);
586}
587
588
589static void
rsc3d77c872004-03-15 01:56:49 +0000590vacdir(DirSink *dsink, int fd, char *lname, char *sname, VacFile *vf)
rsc7763a612003-11-23 17:55:34 +0000591{
592 Dir *dirs;
593 char *ln, *sn;
594 int i, nd;
595 DirSink *ds;
596 VacFile *vvf;
597 char *name;
598
rsc3d77c872004-03-15 01:56:49 +0000599 ds = dirsinkalloc(dsink->sink->z, bsize, bsize);
rsc7763a612003-11-23 17:55:34 +0000600 while((nd = dirread(fd, &dirs)) > 0){
601 for(i = 0; i < nd; i++){
602 name = dirs[i].name;
603 /* check for bad file names */
604 if(name[0] == 0 || strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
605 continue;
rsc3d77c872004-03-15 01:56:49 +0000606 ln = vtmalloc(strlen(lname) + strlen(name) + 2);
607 sn = vtmalloc(strlen(sname) + strlen(name) + 2);
rsc7763a612003-11-23 17:55:34 +0000608 sprint(ln, "%s/%s", lname, name);
609 sprint(sn, "%s/%s", sname, name);
610 if(vf != nil)
rsc3d77c872004-03-15 01:56:49 +0000611 vvf = vacfilewalk(vf, name);
rsc7763a612003-11-23 17:55:34 +0000612 else
613 vvf = nil;
rsc3d77c872004-03-15 01:56:49 +0000614 vacfile(ds, ln, sn, vvf);
rsc7763a612003-11-23 17:55:34 +0000615 if(vvf != nil)
rsc3d77c872004-03-15 01:56:49 +0000616 vacfiledecref(vvf);
617 vtfree(ln);
618 vtfree(sn);
rsc7763a612003-11-23 17:55:34 +0000619 }
620 free(dirs);
621 }
rsc3d77c872004-03-15 01:56:49 +0000622 dirsinkclose(ds);
623 dirsinkwritesink(dsink, ds->sink);
624 dirsinkwritesink(dsink, ds->msink->sink);
625 dirsinkfree(ds);
rsc7763a612003-11-23 17:55:34 +0000626}
627
628static int
rsc3d77c872004-03-15 01:56:49 +0000629vacmergefile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max)
rsc7763a612003-11-23 17:55:34 +0000630{
631 uchar buf[VtEntrySize];
632 VtEntry dd, md;
633 int e;
634
rsc3d77c872004-03-15 01:56:49 +0000635 if(vacfileread(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) {
rsc7763a612003-11-23 17:55:34 +0000636 warn("could not read venti dir entry: %s\n", dir->elem);
rsc3d77c872004-03-15 01:56:49 +0000637 return -1;
rsc7763a612003-11-23 17:55:34 +0000638 }
rsc3d77c872004-03-15 01:56:49 +0000639 vtentryunpack(&dd, buf, 0);
rsc7763a612003-11-23 17:55:34 +0000640
641 if(dir->mode & ModeDir) {
642 e = dir->mentry;
643 if(e == 0)
644 e = dir->entry + 1;
645
rsc3d77c872004-03-15 01:56:49 +0000646 if(vacfileread(vf, buf, VtEntrySize, e*VtEntrySize) != VtEntrySize) {
rsc7763a612003-11-23 17:55:34 +0000647 warn("could not read venti dir entry: %s\n", dir->elem);
648 return 0;
649 }
rsc3d77c872004-03-15 01:56:49 +0000650 vtentryunpack(&md, buf, 0);
rsc7763a612003-11-23 17:55:34 +0000651 }
652
653 /* max might incorrect in some old dumps */
654 if(dir->qid >= *max) {
655 warn("qid out of range: %s", dir->elem);
656 *max = dir->qid;
657 }
658
659 dir->qid += offset;
660 dir->entry = dsink->nentry;
661
rsc3d77c872004-03-15 01:56:49 +0000662 if(dir->qidspace) {
663 dir->qidoffset += offset;
rsc7763a612003-11-23 17:55:34 +0000664 } else {
rsc3d77c872004-03-15 01:56:49 +0000665 dir->qidspace = 1;
666 dir->qidoffset = offset;
667 dir->qidmax = *max;
rsc7763a612003-11-23 17:55:34 +0000668 }
669
rsc3d77c872004-03-15 01:56:49 +0000670 dirsinkwrite(dsink, &dd);
rsc7763a612003-11-23 17:55:34 +0000671 if(dir->mode & ModeDir)
rsc3d77c872004-03-15 01:56:49 +0000672 dirsinkwrite(dsink, &md);
673 metasinkwritedir(dsink->msink, dir);
rsc7763a612003-11-23 17:55:34 +0000674
rsc3d77c872004-03-15 01:56:49 +0000675 return 0;
rsc7763a612003-11-23 17:55:34 +0000676}
677
678static int
rsc3d77c872004-03-15 01:56:49 +0000679vacmerge(DirSink *dsink, char *lname, char *sname)
rsc7763a612003-11-23 17:55:34 +0000680{
681 char *p;
rsc3d77c872004-03-15 01:56:49 +0000682 VacFs *fs;
rsc7763a612003-11-23 17:55:34 +0000683 VacFile *vf;
684 VacDirEnum *d;
685 VacDir dir;
686 uvlong max;
687
rsc5db61d62005-02-21 04:28:34 +0000688 if((p=strrchr(sname, '.')) == nil || strcmp(p, ".vac") != 0)
rscd24aad82005-02-20 22:51:24 +0000689 return -1;
rsc7763a612003-11-23 17:55:34 +0000690
691 d = nil;
rsc3d77c872004-03-15 01:56:49 +0000692 fs = vacfsopen(dsink->sink->z, sname, VtOREAD, 100);
rsc7763a612003-11-23 17:55:34 +0000693 if(fs == nil)
rsc3d77c872004-03-15 01:56:49 +0000694 return -1;
rsc7763a612003-11-23 17:55:34 +0000695
rsc3d77c872004-03-15 01:56:49 +0000696 vf = vacfileopen(fs, "/");
rsc7763a612003-11-23 17:55:34 +0000697 if(vf == nil)
698 goto Done;
rsc3d77c872004-03-15 01:56:49 +0000699 max = vacfilegetid(vf);
700 d = vdeopen(vf);
rsc7763a612003-11-23 17:55:34 +0000701 if(d == nil)
702 goto Done;
703
704 if(verbose)
705 fprint(2, "merging: %s\n", lname);
706
rsc3d77c872004-03-15 01:56:49 +0000707 if(maxbsize < fs->bsize)
708 maxbsize = fs->bsize;
rsc7763a612003-11-23 17:55:34 +0000709
710 for(;;) {
rsc3d77c872004-03-15 01:56:49 +0000711 if(vderead(d, &dir) < 1)
rsc7763a612003-11-23 17:55:34 +0000712 break;
rsc3d77c872004-03-15 01:56:49 +0000713 vacmergefile(dsink, vf, &dir, fileid, &max);
714 vdcleanup(&dir);
rsc7763a612003-11-23 17:55:34 +0000715 }
716 fileid += max;
717
718Done:
719 if(d != nil)
rsc3d77c872004-03-15 01:56:49 +0000720 vdeclose(d);
rsc7763a612003-11-23 17:55:34 +0000721 if(vf != nil)
rsc3d77c872004-03-15 01:56:49 +0000722 vacfiledecref(vf);
723 vacfsclose(fs);
724 return 0;
rsc7763a612003-11-23 17:55:34 +0000725}
726
727Sink *
rsc3d77c872004-03-15 01:56:49 +0000728sinkalloc(VtConn *z, int psize, int dsize)
rsc7763a612003-11-23 17:55:34 +0000729{
730 Sink *k;
731 int i;
732
733 if(psize < 512 || psize > VtMaxLumpSize)
rsc3d77c872004-03-15 01:56:49 +0000734 sysfatal("sinkalloc: bad psize");
rsc7763a612003-11-23 17:55:34 +0000735 if(dsize < 512 || dsize > VtMaxLumpSize)
rsc3d77c872004-03-15 01:56:49 +0000736 sysfatal("sinkalloc: bad psize");
rsc7763a612003-11-23 17:55:34 +0000737
738 psize = VtScoreSize*(psize/VtScoreSize);
739
rsc3d77c872004-03-15 01:56:49 +0000740 k = vtmallocz(sizeof(Sink));
rsc7763a612003-11-23 17:55:34 +0000741 k->z = z;
742 k->dir.flags = VtEntryActive;
743 k->dir.psize = psize;
744 k->dir.dsize = dsize;
rsc3d77c872004-03-15 01:56:49 +0000745 k->buf = vtmallocz(VtPointerDepth*k->dir.psize + VtScoreSize);
rsc7763a612003-11-23 17:55:34 +0000746 for(i=0; i<=VtPointerDepth; i++)
747 k->pbuf[i] = k->buf + i*k->dir.psize;
748 return k;
749}
750
751void
rsc3d77c872004-03-15 01:56:49 +0000752sinkwritescore(Sink *k, uchar score[VtScoreSize], int n)
rsc7763a612003-11-23 17:55:34 +0000753{
754 int i;
755 uchar *p;
756 VtEntry *d;
757
758 memmove(k->pbuf[0], score, VtScoreSize);
759
760 d = &k->dir;
761
762 for(i=0; i<VtPointerDepth; i++) {
763 k->pbuf[i] += VtScoreSize;
764 if(k->pbuf[i] < k->buf + d->psize*(i+1))
765 break;
766 if(i == VtPointerDepth-1)
rsc3d77c872004-03-15 01:56:49 +0000767 sysfatal("file too big");
rsc7763a612003-11-23 17:55:34 +0000768 p = k->buf+i*d->psize;
769 stats.meta++;
rsc3d77c872004-03-15 01:56:49 +0000770 if(vacwrite(k->z, k->pbuf[i+1], VtDataType+1+i, p, d->psize) < 0)
771 sysfatal("vacwrite failed: %r");
rsc7763a612003-11-23 17:55:34 +0000772 k->pbuf[i] = p;
773 }
774
775 /* round size up to multiple of dsize */
776 d->size = d->dsize * ((d->size + d->dsize-1)/d->dsize);
777
778 d->size += n;
779}
780
781void
rsc3d77c872004-03-15 01:56:49 +0000782sinkwrite(Sink *k, uchar *p, int n)
rsc7763a612003-11-23 17:55:34 +0000783{
784 int type;
785 uchar score[VtScoreSize];
786
787 if(n > k->dir.dsize)
rsc3d77c872004-03-15 01:56:49 +0000788 sysfatal("sinkWrite: size too big");
rsc7763a612003-11-23 17:55:34 +0000789
rsc3d77c872004-03-15 01:56:49 +0000790 if((k->dir.type&~VtTypeDepthMask) == VtDirType){
rsc7763a612003-11-23 17:55:34 +0000791 type = VtDirType;
792 stats.meta++;
793 } else {
794 type = VtDataType;
795 stats.data++;
796 }
rsc3d77c872004-03-15 01:56:49 +0000797 if(vacwrite(k->z, score, type, p, n) < 0)
798 sysfatal("vacWrite failed: %r");
rsc7763a612003-11-23 17:55:34 +0000799
rsc3d77c872004-03-15 01:56:49 +0000800 sinkwritescore(k, score, n);
rsc7763a612003-11-23 17:55:34 +0000801}
802
803static int
rsc3d77c872004-03-15 01:56:49 +0000804sizetodepth(uvlong s, int psize, int dsize)
rsc7763a612003-11-23 17:55:34 +0000805{
806 int np;
807 int d;
808
809 /* determine pointer depth */
810 np = psize/VtScoreSize;
811 s = (s + dsize - 1)/dsize;
812 for(d = 0; s > 1; d++)
813 s = (s + np - 1)/np;
814 return d;
815}
816
817void
rsc3d77c872004-03-15 01:56:49 +0000818sinkclose(Sink *k)
rsc7763a612003-11-23 17:55:34 +0000819{
rsc3d77c872004-03-15 01:56:49 +0000820 int i, n, base;
rsc7763a612003-11-23 17:55:34 +0000821 uchar *p;
822 VtEntry *kd;
823
824 kd = &k->dir;
825
826 /* empty */
827 if(kd->size == 0) {
rsc3d77c872004-03-15 01:56:49 +0000828 memmove(kd->score, vtzeroscore, VtScoreSize);
rsc7763a612003-11-23 17:55:34 +0000829 return;
830 }
831
832 for(n=VtPointerDepth-1; n>0; n--)
833 if(k->pbuf[n] > k->buf + kd->psize*n)
834 break;
835
rsc3d77c872004-03-15 01:56:49 +0000836 base = kd->type&~VtTypeDepthMask;
837 kd->type = base + sizetodepth(kd->size, kd->psize, kd->dsize);
rsc7763a612003-11-23 17:55:34 +0000838
839 /* skip full part of tree */
840 for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++)
841 ;
842
843 /* is the tree completely full */
844 if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) {
845 memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize);
846 return;
847 }
848 n++;
849
850 /* clean up the edge */
851 for(; i<n; i++) {
852 p = k->buf+i*kd->psize;
853 stats.meta++;
rsc3d77c872004-03-15 01:56:49 +0000854 if(vacwrite(k->z, k->pbuf[i+1], base+1+i, p, k->pbuf[i]-p) < 0)
855 sysfatal("vacWrite failed: %r");
rsc7763a612003-11-23 17:55:34 +0000856 k->pbuf[i+1] += VtScoreSize;
857 }
858 memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
859}
860
861void
rsc3d77c872004-03-15 01:56:49 +0000862sinkfree(Sink *k)
rsc7763a612003-11-23 17:55:34 +0000863{
rsc3d77c872004-03-15 01:56:49 +0000864 vtfree(k->buf);
865 vtfree(k);
rsc7763a612003-11-23 17:55:34 +0000866}
867
868DirSink *
rsc3d77c872004-03-15 01:56:49 +0000869dirsinkalloc(VtConn *z, int psize, int dsize)
rsc7763a612003-11-23 17:55:34 +0000870{
871 DirSink *k;
872 int ds;
873
874 ds = VtEntrySize*(dsize/VtEntrySize);
875
rsc3d77c872004-03-15 01:56:49 +0000876 k = vtmallocz(sizeof(DirSink));
877 k->sink = sinkalloc(z, psize, ds);
878 k->sink->dir.type = VtDirType;
879 k->msink = metasinkalloc(z, psize, dsize);
880 k->buf = vtmalloc(ds);
rsc7763a612003-11-23 17:55:34 +0000881 k->p = k->buf;
882 k->ep = k->buf + ds;
883 return k;
884}
885
886void
rsc3d77c872004-03-15 01:56:49 +0000887dirsinkwrite(DirSink *k, VtEntry *dir)
rsc7763a612003-11-23 17:55:34 +0000888{
889 if(k->p + VtEntrySize > k->ep) {
rsc3d77c872004-03-15 01:56:49 +0000890 sinkwrite(k->sink, k->buf, k->p - k->buf);
rsc7763a612003-11-23 17:55:34 +0000891 k->p = k->buf;
892 }
rsc3d77c872004-03-15 01:56:49 +0000893 vtentrypack(dir, k->p, 0);
rsc7763a612003-11-23 17:55:34 +0000894 k->nentry++;
895 k->p += VtEntrySize;
896}
897
898void
rsc3d77c872004-03-15 01:56:49 +0000899dirsinkwritesink(DirSink *k, Sink *sink)
rsc7763a612003-11-23 17:55:34 +0000900{
rsc3d77c872004-03-15 01:56:49 +0000901 dirsinkwrite(k, &sink->dir);
rsc7763a612003-11-23 17:55:34 +0000902}
903
904int
rsc3d77c872004-03-15 01:56:49 +0000905dirsinkwritefile(DirSink *k, VacFile *vf)
rsc7763a612003-11-23 17:55:34 +0000906{
907 VtEntry dir;
908
rsc3d77c872004-03-15 01:56:49 +0000909 if(vacfilegetvtentry(vf, &dir) < 0)
910 return -1;
911 dirsinkwrite(k, &dir);
912 return 0;
rsc7763a612003-11-23 17:55:34 +0000913}
914
915void
rsc3d77c872004-03-15 01:56:49 +0000916dirsinkclose(DirSink *k)
rsc7763a612003-11-23 17:55:34 +0000917{
rsc3d77c872004-03-15 01:56:49 +0000918 metasinkclose(k->msink);
rsc7763a612003-11-23 17:55:34 +0000919 if(k->p != k->buf)
rsc3d77c872004-03-15 01:56:49 +0000920 sinkwrite(k->sink, k->buf, k->p - k->buf);
921 sinkclose(k->sink);
rsc7763a612003-11-23 17:55:34 +0000922}
923
924void
rsc3d77c872004-03-15 01:56:49 +0000925dirsinkfree(DirSink *k)
rsc7763a612003-11-23 17:55:34 +0000926{
rsc3d77c872004-03-15 01:56:49 +0000927 sinkfree(k->sink);
928 metasinkfree(k->msink);
929 vtfree(k->buf);
930 vtfree(k);
rsc7763a612003-11-23 17:55:34 +0000931}
932
rsc3d77c872004-03-15 01:56:49 +0000933MetaSink*
934metasinkalloc(VtConn *z, int psize, int dsize)
rsc7763a612003-11-23 17:55:34 +0000935{
936 MetaSink *k;
937
rsc3d77c872004-03-15 01:56:49 +0000938 k = vtmallocz(sizeof(MetaSink));
939 k->sink = sinkalloc(z, psize, dsize);
940 k->buf = vtmalloc(dsize);
rsc7763a612003-11-23 17:55:34 +0000941 k->maxindex = dsize/100; /* 100 byte entries seems reasonable */
942 if(k->maxindex < 1)
943 k->maxindex = 1;
944 k->rp = k->p = k->buf + MetaHeaderSize + k->maxindex*MetaIndexSize;
945 k->ep = k->buf + dsize;
946 return k;
947}
948
949/* hack to get base to compare routine - not reentrant */
rsc3d77c872004-03-15 01:56:49 +0000950uchar *blockbase;
rsc7763a612003-11-23 17:55:34 +0000951
952int
rsc3d77c872004-03-15 01:56:49 +0000953dircmp(const void *p0, const void *p1)
rsc7763a612003-11-23 17:55:34 +0000954{
955 uchar *q0, *q1;
956 int n0, n1, r;
957
958 /* name is first element of entry */
rsc3d77c872004-03-15 01:56:49 +0000959 q0 = (uchar*)p0;
960 q0 = blockbase + (q0[0]<<8) + q0[1];
rsc7763a612003-11-23 17:55:34 +0000961 n0 = (q0[6]<<8) + q0[7];
962 q0 += 8;
963
rsc3d77c872004-03-15 01:56:49 +0000964 q1 = (uchar*)p1;
965 q1 = blockbase + (q1[0]<<8) + q1[1];
rsc7763a612003-11-23 17:55:34 +0000966 n1 = (q1[6]<<8) + q1[7];
967 q1 += 8;
968
969 if(n0 == n1)
970 return memcmp(q0, q1, n0);
971 else if (n0 < n1) {
972 r = memcmp(q0, q1, n0);
973 return (r==0)?1:r;
974 } else {
975 r = memcmp(q0, q1, n1);
976 return (r==0)?-1:r;
977 }
978}
979
980void
rsc3d77c872004-03-15 01:56:49 +0000981metasinkflush(MetaSink *k)
rsc7763a612003-11-23 17:55:34 +0000982{
983 uchar *p;
984 int n;
985 MetaBlock mb;
986
987 if(k->nindex == 0)
988 return;
989 assert(k->nindex <= k->maxindex);
990
991 p = k->buf;
992 n = k->rp - p;
993
994 mb.size = n;
995 mb.free = 0;
996 mb.nindex = k->nindex;
997 mb.maxindex = k->maxindex;
998 mb.buf = p;
rsc3d77c872004-03-15 01:56:49 +0000999 mbpack(&mb);
rsc7763a612003-11-23 17:55:34 +00001000
1001 p += MetaHeaderSize;
1002
1003 /* XXX this is not reentrant! */
rsc3d77c872004-03-15 01:56:49 +00001004 blockbase = k->buf;
1005 qsort(p, k->nindex, MetaIndexSize, dircmp);
rsc7763a612003-11-23 17:55:34 +00001006 p += k->nindex*MetaIndexSize;
1007
1008 memset(p, 0, (k->maxindex-k->nindex)*MetaIndexSize);
1009 p += (k->maxindex-k->nindex)*MetaIndexSize;
1010
rsc3d77c872004-03-15 01:56:49 +00001011 sinkwrite(k->sink, k->buf, n);
rsc7763a612003-11-23 17:55:34 +00001012
1013 /* move down partial entry */
1014 n = k->p - k->rp;
1015 memmove(p, k->rp, n);
1016 k->rp = p;
1017 k->p = p + n;
1018 k->nindex = 0;
1019}
1020
1021void
rsc3d77c872004-03-15 01:56:49 +00001022metasinkputc(MetaSink *k, int c)
rsc7763a612003-11-23 17:55:34 +00001023{
1024 if(k->p+1 > k->ep)
rsc3d77c872004-03-15 01:56:49 +00001025 metasinkflush(k);
rsc7763a612003-11-23 17:55:34 +00001026 if(k->p+1 > k->ep)
rsc3d77c872004-03-15 01:56:49 +00001027 sysfatal("directory entry too large");
rsc7763a612003-11-23 17:55:34 +00001028 k->p[0] = c;
1029 k->p++;
1030}
1031
1032void
rsc3d77c872004-03-15 01:56:49 +00001033metasinkputstring(MetaSink *k, char *s)
rsc7763a612003-11-23 17:55:34 +00001034{
1035 int n = strlen(s);
rsc3d77c872004-03-15 01:56:49 +00001036 metasinkputc(k, n>>8);
1037 metasinkputc(k, n);
1038 metasinkwrite(k, (uchar*)s, n);
rsc7763a612003-11-23 17:55:34 +00001039}
1040
1041void
rsc3d77c872004-03-15 01:56:49 +00001042metasinkputuint32(MetaSink *k, ulong x)
rsc7763a612003-11-23 17:55:34 +00001043{
rsc3d77c872004-03-15 01:56:49 +00001044 metasinkputc(k, x>>24);
1045 metasinkputc(k, x>>16);
1046 metasinkputc(k, x>>8);
1047 metasinkputc(k, x);
rsc7763a612003-11-23 17:55:34 +00001048}
1049
1050void
rsc3d77c872004-03-15 01:56:49 +00001051metasinkputuint64(MetaSink *k, uvlong x)
rsc7763a612003-11-23 17:55:34 +00001052{
rsc3d77c872004-03-15 01:56:49 +00001053 metasinkputuint32(k, x>>32);
1054 metasinkputuint32(k, x);
rsc7763a612003-11-23 17:55:34 +00001055}
1056
1057void
rsc3d77c872004-03-15 01:56:49 +00001058metasinkwrite(MetaSink *k, uchar *data, int n)
rsc7763a612003-11-23 17:55:34 +00001059{
1060 if(k->p + n > k->ep)
rsc3d77c872004-03-15 01:56:49 +00001061 metasinkflush(k);
rsc7763a612003-11-23 17:55:34 +00001062 if(k->p + n > k->ep)
rsc3d77c872004-03-15 01:56:49 +00001063 sysfatal("directory entry too large");
rsc7763a612003-11-23 17:55:34 +00001064
1065 memmove(k->p, data, n);
1066 k->p += n;
1067}
1068
1069void
rsc3d77c872004-03-15 01:56:49 +00001070metasinkwritedir(MetaSink *ms, VacDir *dir)
rsc7763a612003-11-23 17:55:34 +00001071{
rsc3d77c872004-03-15 01:56:49 +00001072 metasinkputuint32(ms, DirMagic);
1073 metasinkputc(ms, Version>>8);
1074 metasinkputc(ms, Version);
1075 metasinkputstring(ms, dir->elem);
1076 metasinkputuint32(ms, dir->entry);
1077 metasinkputuint64(ms, dir->qid);
1078 metasinkputstring(ms, dir->uid);
1079 metasinkputstring(ms, dir->gid);
1080 metasinkputstring(ms, dir->mid);
1081 metasinkputuint32(ms, dir->mtime);
1082 metasinkputuint32(ms, dir->mcount);
1083 metasinkputuint32(ms, dir->ctime);
1084 metasinkputuint32(ms, dir->atime);
1085 metasinkputuint32(ms, dir->mode);
rsc7763a612003-11-23 17:55:34 +00001086
1087 if(dir->plan9) {
rsc3d77c872004-03-15 01:56:49 +00001088 metasinkputc(ms, DirPlan9Entry); /* plan9 extra info */
1089 metasinkputc(ms, 0); /* plan9 extra size */
1090 metasinkputc(ms, 12); /* plan9 extra size */
1091 metasinkputuint64(ms, dir->p9path);
1092 metasinkputuint32(ms, dir->p9version);
rsc7763a612003-11-23 17:55:34 +00001093 }
1094
rsc3d77c872004-03-15 01:56:49 +00001095 if(dir->qidspace != 0) {
1096 metasinkputc(ms, DirQidSpaceEntry);
1097 metasinkputc(ms, 0);
1098 metasinkputc(ms, 16);
1099 metasinkputuint64(ms, dir->qidoffset);
1100 metasinkputuint64(ms, dir->qidmax);
rsc7763a612003-11-23 17:55:34 +00001101 }
1102
1103 if(dir->gen != 0) {
rsc3d77c872004-03-15 01:56:49 +00001104 metasinkputc(ms, DirGenEntry);
1105 metasinkputc(ms, 0);
1106 metasinkputc(ms, 4);
1107 metasinkputuint32(ms, dir->gen);
rsc7763a612003-11-23 17:55:34 +00001108 }
1109
rsc3d77c872004-03-15 01:56:49 +00001110 metasinkeor(ms);
rsc7763a612003-11-23 17:55:34 +00001111}
1112
1113
1114void
rsc3d77c872004-03-15 01:56:49 +00001115plan9tovacdir(VacDir *vd, Dir *dir, ulong entry, uvlong qid)
rsc7763a612003-11-23 17:55:34 +00001116{
1117 memset(vd, 0, sizeof(VacDir));
1118
rsc3d77c872004-03-15 01:56:49 +00001119 vd->elem = vtstrdup(dir->name);
rsc7763a612003-11-23 17:55:34 +00001120 vd->entry = entry;
1121 vd->qid = qid;
rsc3d77c872004-03-15 01:56:49 +00001122 vd->uid = vtstrdup(dir->uid);
1123 vd->gid = vtstrdup(dir->gid);
1124 vd->mid = vtstrdup(dir->muid);
rsc7763a612003-11-23 17:55:34 +00001125 vd->mtime = dir->mtime;
1126 vd->mcount = 0;
1127 vd->ctime = dir->mtime; /* ctime: not available on plan 9 */
1128 vd->atime = dir->atime;
1129
1130 vd->mode = dir->mode & 0777;
1131 if(dir->mode & DMDIR)
1132 vd->mode |= ModeDir;
1133 if(dir->mode & DMAPPEND)
1134 vd->mode |= ModeAppend;
1135 if(dir->mode & DMEXCL)
1136 vd->mode |= ModeExclusive;
1137
1138 vd->plan9 = 1;
1139 vd->p9path = dir->qid.path;
1140 vd->p9version = dir->qid.vers;
1141}
1142
1143
1144void
rsc3d77c872004-03-15 01:56:49 +00001145metasinkeor(MetaSink *k)
rsc7763a612003-11-23 17:55:34 +00001146{
1147 uchar *p;
1148 int o, n;
1149
1150 p = k->buf + MetaHeaderSize;
1151 p += k->nindex * MetaIndexSize;
1152 o = k->rp-k->buf; /* offset from start of block */
1153 n = k->p-k->rp; /* size of entry */
1154 p[0] = o >> 8;
1155 p[1] = o;
1156 p[2] = n >> 8;
1157 p[3] = n;
1158 k->rp = k->p;
1159 k->nindex++;
1160 if(k->nindex == k->maxindex)
rsc3d77c872004-03-15 01:56:49 +00001161 metasinkflush(k);
rsc7763a612003-11-23 17:55:34 +00001162}
1163
1164void
rsc3d77c872004-03-15 01:56:49 +00001165metasinkclose(MetaSink *k)
rsc7763a612003-11-23 17:55:34 +00001166{
rsc3d77c872004-03-15 01:56:49 +00001167 metasinkflush(k);
1168 sinkclose(k->sink);
rsc7763a612003-11-23 17:55:34 +00001169}
1170
1171void
rsc3d77c872004-03-15 01:56:49 +00001172metasinkfree(MetaSink *k)
rsc7763a612003-11-23 17:55:34 +00001173{
rsc3d77c872004-03-15 01:56:49 +00001174 sinkfree(k->sink);
1175 vtfree(k->buf);
1176 vtfree(k);
rsc7763a612003-11-23 17:55:34 +00001177}
1178
1179static void
1180warn(char *fmt, ...)
1181{
1182 va_list arg;
1183
1184 va_start(arg, fmt);
1185 fprint(2, "%s: ", argv0);
1186 vfprint(2, fmt, arg);
1187 fprint(2, "\n");
1188 va_end(arg);
1189}
1190
1191static void
1192cleanup(void)
1193{
1194 if(oname != nil)
1195 remove(oname);
1196}
1197
1198#define TWID64 ((u64int)~(u64int)0)
1199
1200static u64int
1201unittoull(char *s)
1202{
1203 char *es;
1204 u64int n;
1205
1206 if(s == nil)
1207 return TWID64;
1208 n = strtoul(s, &es, 0);
1209 if(*es == 'k' || *es == 'K'){
1210 n *= 1024;
1211 es++;
1212 }else if(*es == 'm' || *es == 'M'){
1213 n *= 1024*1024;
1214 es++;
1215 }else if(*es == 'g' || *es == 'G'){
1216 n *= 1024*1024*1024;
1217 es++;
1218 }
1219 if(*es != '\0')
1220 return TWID64;
1221 return n;
1222}