28 static char *nametab[] = {
43 static Revlog changelog;
44 static Revlog manifest;
45 static Revlog *revlogs;
46 static int nfreerevlogs = 0;
48 static char workdir[MAXPATH];
49 static int mangle = 0;
52 getrevlog(Revnode *nd)
60 nodepath(seprint(buf, buf+sizeof(buf), "%s/.hg/store/data", workdir),
61 buf+sizeof(buf), nd, mang);
64 if(strcmp(buf, rl->path) == 0){
65 if(rl->ref == 0) nfreerevlogs--;
68 if(nfreerevlogs > 8 && rl->ref == 0){
78 rl = emalloc9p(sizeof(*rl));
79 memset(rl, 0, sizeof(*rl));
80 if(revlogopen(rl, buf, OREAD) < 0){
97 closerevlog(Revlog *rl)
99 if(rl != nil && decref(rl) == 0)
108 if(rev < 0 || rev >= changelog.nmap)
110 if(ri = changelog.map[rev].aux)
112 if(ri = loadrevinfo(&changelog, rev))
113 changelog.map[rev].aux = ri;
118 getrevtree(Revtree *(*fn)(Revlog *, Revlog *, Revinfo *), Revinfo *ri)
130 for(i=j=0; i<nelem(cache); i++){
131 if(cache[i].t == nil){
135 if(cache[i].f == fn && cache[i].i == ri){
140 if(cache[j].t && cache[i].g < cache[j].g)
143 if((rt = (*fn)(&changelog, &manifest, ri)) == nil)
146 closerevtree(cache[j].t);
164 while(x = strchr(s, '<'))
167 if(x = strchr(s, '>'))
169 if(x = strchr(s, '@'))
171 if(x = strchr(s, '\n'))
174 if(s == nil || *s == 0){
176 s = estrdup9p("hgfs");
182 fsmkqid(Qid *q, int level, void *aux)
207 q->path = hash2qid(ri->chash) + (level - Qrev);
213 if(level == Qtree && nd->down){
218 q->path = nd->path + (level - Qtree);
225 fsmkrevname(char *buf, int nbuf, int rev)
227 if(rev < 0 || rev >= changelog.nmap)
229 snprint(buf, nbuf, "%d.%H", rev, changelog.map[rev].hash);
234 fsmkdir(Dir *d, int level, void *aux)
241 memset(d, 0, sizeof(*d));
243 fsmkqid(&d->qid, level, aux);
246 if(d->qid.type & QTDIR)
247 d->mode |= DMDIR | 0111;
259 rev = hashrev(&changelog, ri->chash);
261 rev = changelog.map[rev].p1rev;
262 else if(level == Qrev2)
263 rev = changelog.map[rev].p2rev;
264 s = fsmkrevname(buf, sizeof(buf), rev);
266 d->name = estrdup9p(s);
272 d->length = ri->loglen;
282 d->length = s ? strlen(s)+1 : 0;
283 if(level == Qtreerev)
290 d->name = estrdup9p(nametab[level]);
295 if(level == Qtree && nd->mode == 'x')
297 d->name = estrdup9p(nd->name);
301 if((rl = getrevlog(nd)) == nil)
303 if((rev = hashrev(rl, nd->hash)) >= 0){
306 * BUG: this is not correct. mercurial might
307 * prefix the data log with random \1\n escaped
308 * metadata strings (see fmetaheader()) and the flen
309 * *includes* the metadata part. we try to compensate
310 * for this once the revision got extracted and
311 * subtract the metadata header in fsstat().
313 d->length = rl->map[rev].flen;
315 ri = getrevinfo(rl->map[rev].linkrev);
318 if(level == Qtreerev && ri)
325 d->atime = d->mtime = ri->when;
326 d->muid = fsmkuid(ri->who);
327 d->uid = fsmkuid(ri->who);
329 d->atime = d->mtime = time(0);
332 d->uid = fsmkuid(nil);
334 d->gid = fsmkuid(nil);
336 d->muid = fsmkuid(nil);
344 if(r->ifcall.aname && r->ifcall.aname[0]){
345 respond(r, "invalid attach specifier");
348 r->fid->qid.path = Qroot;
349 r->fid->qid.type = QTDIR;
350 r->fid->qid.vers = 0;
351 r->ofcall.qid = r->fid->qid;
353 rf = emalloc9p(sizeof(*rf));
375 if(rf->level < Qtree)
376 fsmkdir(&r->d, rf->level, rf->info);
378 fsmkdir(&r->d, rf->level, rf->node);
379 if(rf->level == Qtree)
380 r->d.length -= rf->doff;
386 findrev(Revlog *rl, char *name)
392 if(strcmp(name, "tip") == 0)
394 rev = strtol(name, &s, 10);
395 if(s > name && (*s == 0 || ispunct(*s)))
398 if(s = strchr(name, '.'))
400 if((n = hex2hash(name, hash)) > 0){
401 for(i=0; i<rl->nmap; i++){
402 if(memcmp(rl->map[i].hash, hash, n) == 0){
416 fswalk1(Fid *fid, char *name, Qid *qid)
418 Revtree* (*loadfn)(Revlog *, Revlog *, Revinfo *);
419 char buf[MAXPATH], *sname;
424 if((fid->qid.type & QTDIR) == 0)
425 return "walk in non-directory";
428 if(strcmp(name, "..") == 0){
438 closerevtree(rf->tree);
443 closerevlog(rf->rlog);
445 if((rf->node = rf->node->up) == rf->tree->root)
446 rf->level = rf->tree->level;
452 revlogupdate(&changelog);
453 revlogupdate(&manifest);
455 i = findrev(&changelog, name);
456 if(rf->info = getrevinfo(i)){
461 return "directory entry not found";
464 for(i = Qrev+1; i < Qtree; i++){
465 if(nametab[i] == nil)
467 if(strcmp(name, nametab[i]) == 0)
475 loadfn = loadfilestree;
478 loadfn = loadchangestree;
482 if((rf->tree = getrevtree(loadfn, rf->info)) == nil)
484 rf->node = rf->tree->root;
496 for(nd = rf->node->down; nd; nd = nd->next)
497 if(strcmp(nd->name, sname) == 0)
501 sname = strrchr(name, '.');
502 if((i = sname - name) > 0){
504 if(strncmp(sname, "rev", 3) == 0){
508 snprint(buf, sizeof(buf), "%.*s", i, name);
512 i = strtol(sname, &sname, 10);
513 if(i < 0 || *sname != '\0')
526 if((rf->rlog = getrevlog(nd)) == nil)
528 j = hashrev(rf->rlog, nd->hash) - i;
529 if(i < 0 || j < 0 || j >= rf->rlog->nmap){
530 closerevlog(rf->rlog);
534 for(nb = nd; nb; nb = nb->before)
535 if(hashrev(rf->rlog, nb->hash) == j)
538 nb = mknode(nd->name, revhash(rf->rlog, j), nd->mode);
540 nb->before = nd->before;
544 } else if(name != sname)
552 if(rf->level < Qtree)
553 fsmkqid(qid, rf->level, rf->info);
555 fsmkqid(qid, rf->level, rf->node);
562 fsclone(Fid *oldfid, Fid *newfid)
567 if(orf = oldfid->aux){
568 rf = emalloc9p(sizeof(*rf));
575 rf->fd = dup(rf->fd, -1);
577 rf->buf = estrdup9p(rf->buf);
584 fsdestroyfid(Fid *fid)
589 closerevlog(rf->rlog);
590 closerevtree(rf->tree);
604 switch(r->ifcall.mode & 3){
606 if(rf->node == nil || rf->node->mode != 'x')
609 if(rf->level == Qlog){
610 if((rf->fd = revlogopentemp(&changelog, hashrev(&changelog, rf->info->chash))) < 0){
614 rf->doff = rf->info->logoff;
615 } else if(rf->level == Qtree && rf->node->down == nil){
616 if((rf->fd = revlogopentemp(rf->rlog, hashrev(rf->rlog, rf->node->hash))) < 0){
620 rf->doff = fmetaheader(rf->fd);
625 respond(r, "permission denied");
629 rootgen(int i, Dir *d, void *)
633 if((ri = getrevinfo(i)) == nil)
635 fsmkdir(d, Qrev, ri);
640 revgen(int i, Dir *d, void *aux)
650 treegen(int i, Dir *d, void *aux)
660 fsmkdir(d, Qtree, nd);
667 char buf[MAXPATH], *s;
673 off = r->ifcall.offset;
674 len = r->ifcall.count;
680 revlogupdate(&changelog);
681 revlogupdate(&manifest);
683 dirread9p(r, rootgen, nil);
687 dirread9p(r, revgen, rf->info);
696 i = hashrev(&changelog, rf->info->chash);
697 if(rf->level == Qrev1)
698 i = changelog.map[i].p1rev;
699 else if(rf->level == Qrev2)
700 i = changelog.map[i].p2rev;
702 s = fsmkrevname(buf, sizeof(buf), i);
705 if((i = hashrev(rf->rlog, rf->node->hash)) >= 0)
706 i = rf->rlog->map[i].linkrev;
709 if(off >= rf->info->loglen)
711 else if((off + len) >= rf->info->loglen)
712 len = rf->info->loglen - off;
721 rf->buf = s ? smprint("%s\n", s) : estrdup9p("");
729 dirread9p(r, treegen, rf->node->down);
736 if((n = pread(rf->fd, r->ofcall.data, len, off + rf->doff)) < 0){
744 respond(r, "bug in fsread");
753 .destroyfid=fsdestroyfid,
761 fprint(2, "usage: %s [-D] [-m mtpt] [-s srv] [root]\n", argv0);
766 main(int argc, char *argv[])
772 fmtinstall('H', Hfmt);
782 mtpt = EARGF(usage());
785 srv = EARGF(usage());
791 if(getworkdir(workdir, *argv) < 0)
792 sysfatal("can't find workdir: %r");
794 snprint(buf, sizeof(buf), "%s/.hg/store/00changelog", workdir);
795 if(revlogopen(&changelog, buf, OREAD) < 0)
796 sysfatal("can't open changelog: %r\n");
797 snprint(buf, sizeof(buf), "%s/.hg/store/00manifest", workdir);
798 if(revlogopen(&manifest, buf, OREAD) < 0)
799 sysfatal("can't open menifest: %r\n");
801 postmountsrv(&fs, srv, mtpt, MREPL);