27 static char *nametab[] = {
41 static Revlog changelog;
42 static Revlog manifest;
43 static Revlog *revlogs;
45 static char dothg[MAXPATH];
48 getrevlog(Revnode *nd)
53 nodepath(seprint(buf, buf+sizeof(buf), "%s/store/data", dothg),
54 buf+sizeof(buf), nd, 1);
55 for(rl = revlogs; rl; rl = rl->next)
56 if(strcmp(buf, rl->path) == 0)
59 rl = emalloc9p(sizeof(*rl));
60 memset(rl, 0, sizeof(*rl));
61 if(revlogopen(rl, buf, OREAD) < 0){
74 closerevlog(Revlog *rl)
78 if(rl == nil || decref(rl))
80 for(pp = &revlogs; *pp; pp = &((*pp)->next)){
95 if(rev < 0 || rev >= changelog.nmap)
97 if(ri = changelog.map[rev].aux)
99 if(ri = loadrevinfo(&changelog, rev))
100 changelog.map[rev].aux = ri;
105 getrevtree(Revtree *(*fn)(Revlog *, Revlog *, Revinfo *), Revinfo *ri)
117 for(i=j=0; i<nelem(cache); i++){
118 if(cache[i].t == nil){
122 if(cache[i].f == fn && cache[i].i == ri){
127 if(cache[j].t && cache[i].g < cache[j].g)
130 if((rt = (*fn)(&changelog, &manifest, ri)) == nil)
133 closerevtree(cache[j].t);
151 while(x = strchr(s, '<'))
154 if(x = strchr(s, '>'))
156 if(x = strchr(s, '@'))
158 if(x = strchr(s, '\n'))
161 if(s == nil || *s == 0){
163 s = estrdup9p("hgfs");
169 fsmkqid(Qid *q, int level, void *aux)
193 q->path = hash2qid(ri->chash) + (level - Qrev);
199 if(level == Qtree && nd->down){
204 q->path = nd->path + (level - Qtree);
211 fsmkrevname(char *buf, int nbuf, int rev)
213 if(rev < 0 || rev >= changelog.nmap)
215 snprint(buf, nbuf, "%d.%H", rev, changelog.map[rev].hash);
220 fsmkdir(Dir *d, int level, void *aux)
227 memset(d, 0, sizeof(*d));
229 fsmkqid(&d->qid, level, aux);
232 if(d->qid.type == QTDIR)
233 d->mode |= DMDIR | 0111;
244 rev = hashrev(&changelog, ri->chash);
246 rev = changelog.map[rev].p1rev;
247 else if(level == Qrev2)
248 rev = changelog.map[rev].p2rev;
249 s = fsmkrevname(buf, sizeof(buf), rev);
251 d->name = estrdup9p(s);
257 d->length = ri->loglen;
267 d->length = s ? strlen(s)+1 : 0;
268 if(level == Qtreerev)
275 d->name = estrdup9p(nametab[level]);
280 if(level == Qtree && nd->mode == 'x')
282 d->name = estrdup9p(nd->name);
286 if((rl = getrevlog(nd)) == nil)
288 if((rev = hashrev(rl, nd->hash)) >= 0){
290 d->length = rl->map[rev].flen;
291 ri = getrevinfo(rl->map[rev].linkrev);
294 if(level == Qtreerev && ri)
301 d->atime = d->mtime = ri->when;
302 d->muid = fsmkuid(ri->who);
303 d->uid = fsmkuid(ri->who);
305 d->atime = d->mtime = time(0);
308 d->uid = fsmkuid(nil);
310 d->gid = fsmkuid(nil);
312 d->muid = fsmkuid(nil);
320 if(r->ifcall.aname && r->ifcall.aname[0]){
321 respond(r, "invalid attach specifier");
324 r->fid->qid.path = Qroot;
325 r->fid->qid.type = QTDIR;
326 r->fid->qid.vers = 0;
327 r->ofcall.qid = r->fid->qid;
329 rf = emalloc9p(sizeof(*rf));
350 if(rf->level < Qtree)
351 fsmkdir(&r->d, rf->level, rf->info);
353 fsmkdir(&r->d, rf->level, rf->node);
358 findrev(Revlog *rl, char *name)
364 if(strcmp(name, "tip") == 0)
366 rev = strtol(name, &s, 10);
367 if(s > name && (*s == 0 || ispunct(*s)))
370 if(s = strchr(name, '.'))
372 if((n = hex2hash(name, hash)) > 0){
373 for(i=0; i<rl->nmap; i++){
374 if(memcmp(rl->map[i].hash, hash, n) == 0){
388 fswalk1(Fid *fid, char *name, Qid *qid)
390 Revtree* (*loadfn)(Revlog *, Revlog *, Revinfo *);
391 char buf[MAXPATH], *sname;
396 if(!(fid->qid.type&QTDIR))
397 return "walk in non-directory";
400 if(strcmp(name, "..") == 0){
410 closerevtree(rf->tree);
415 closerevlog(rf->rlog);
417 if((rf->node = rf->node->up) == rf->tree->root)
418 rf->level = rf->tree->level;
424 revlogupdate(&changelog);
425 revlogupdate(&manifest);
427 i = findrev(&changelog, name);
428 if(rf->info = getrevinfo(i)){
433 return "directory entry not found";
436 for(i = Qrev+1; i < Qtree; i++){
437 if(nametab[i] == nil)
439 if(strcmp(name, nametab[i]) == 0)
447 loadfn = loadfilestree;
450 loadfn = loadchangestree;
454 if((rf->tree = getrevtree(loadfn, rf->info)) == nil)
456 rf->node = rf->tree->root;
468 for(nd = rf->node->down; nd; nd = nd->next)
469 if(strcmp(nd->name, sname) == 0)
473 sname = strrchr(name, '.');
474 if((i = sname - name) > 0){
476 if(strncmp(sname, "rev", 3) == 0){
480 snprint(buf, sizeof(buf), "%.*s", i, name);
492 if((rf->rlog = getrevlog(nd)) == nil)
494 j = hashrev(rf->rlog, nd->hash) - i;
495 if(i < 0 || j < 0 || j >= rf->rlog->nmap){
496 closerevlog(rf->rlog);
500 for(nb = nd; nb; nb = nb->before)
501 if(hashrev(rf->rlog, nb->hash) == j)
504 nb = mknode(nd->name, revhash(rf->rlog, j), nd->mode);
506 nb->before = nd->before;
510 } else if(name != sname)
518 if(rf->level < Qtree)
519 fsmkqid(qid, rf->level, rf->info);
521 fsmkqid(qid, rf->level, rf->node);
528 fsclone(Fid *oldfid, Fid *newfid)
533 if(orf = oldfid->aux){
534 rf = emalloc9p(sizeof(*rf));
541 rf->fd = dup(rf->fd, -1);
543 rf->buf = estrdup9p(rf->buf);
550 fsdestroyfid(Fid *fid)
555 closerevlog(rf->rlog);
556 closerevtree(rf->tree);
570 switch(r->ifcall.mode & 3){
572 if(rf->node == nil || rf->node->mode != 'x')
578 respond(r, "permission denied");
582 rootgen(int i, Dir *d, void *)
586 if((ri = getrevinfo(i)) == nil)
588 fsmkdir(d, Qrev, ri);
593 revgen(int i, Dir *d, void *aux)
603 treegen(int i, Dir *d, void *aux)
613 fsmkdir(d, Qtree, nd);
620 char buf[MAXPATH], *s;
626 off = r->ifcall.offset;
627 len = r->ifcall.count;
632 revlogupdate(&changelog);
633 revlogupdate(&manifest);
634 dirread9p(r, rootgen, nil);
638 dirread9p(r, revgen, rf->info);
646 i = hashrev(&changelog, rf->info->chash);
647 if(rf->level == Qrev1)
648 i = changelog.map[i].p1rev;
650 i = changelog.map[i].p2rev;
652 s = fsmkrevname(buf, sizeof(buf), i);
655 if((i = hashrev(rf->rlog, rf->node->hash)) >= 0)
656 i = rf->rlog->map[i].linkrev;
659 if(off >= rf->info->loglen)
661 else if((off + len) >= rf->info->loglen)
662 len = rf->info->loglen - off;
663 off += rf->info->logoff;
666 if((rf->fd = revlogopentemp(&changelog, hashrev(&changelog, rf->info->chash))) < 0){
678 rf->buf = s ? smprint("%s\n", s) : estrdup9p("");
686 dirread9p(r, treegen, rf->node->down);
692 if((rf->fd = revlogopentemp(rf->rlog, hashrev(rf->rlog, rf->node->hash))) < 0){
697 if((n = pread(rf->fd, r->ofcall.data, len, off)) < 0){
705 respond(r, "bug in fsread");
714 .destroyfid=fsdestroyfid,
722 fprint(2, "usage: %s [-D] [-m mtpt] [-s srv] [root]\n", argv0);
727 main(int argc, char *argv[])
733 fmtinstall('H', Hfmt);
743 mtpt = EARGF(usage());
746 srv = EARGF(usage());
753 snprint(dothg, sizeof(dothg), "%s/.hg", *argv);
755 if(getwd(buf, sizeof(buf)) == nil)
756 sysfatal("can't get working dir: %r");
760 snprint(dothg, sizeof(dothg), "%s/.hg", buf);
761 if(access(dothg, AEXIST) == 0)
763 if((s = strrchr(buf, '/')) == nil)
770 snprint(buf, sizeof(buf), "%s/store/00changelog", dothg);
771 if(revlogopen(&changelog, buf, OREAD) < 0)
772 sysfatal("can't open changelog: %r\n");
773 snprint(buf, sizeof(buf), "%s/store/00manifest", dothg);
774 if(revlogopen(&manifest, buf, OREAD) < 0)
775 sysfatal("can't open menifest: %r\n");
777 postmountsrv(&fs, srv, mtpt, MREPL);