27 static char *nametab[] = {
41 static Revlog changelog;
42 static Revlog manifest;
45 getrevlog(Revnode *nd)
50 nodepath(seprint(path, path+MAXPATH, ".hg/store/data"), path+MAXPATH, nd);
51 rl = emalloc9p(sizeof(*rl));
52 memset(rl, 0, sizeof(*rl));
53 if(revlogopen(rl, path, OREAD) < 0){
54 fprint(2, "getrevlod %s: %r\n", path);
63 closerevlog(Revlog *rl)
78 if(rev < 0 || rev >= changelog.nmap)
80 if(ri = changelog.map[rev].aux)
82 if(ri = loadrevinfo(&changelog, rev))
83 changelog.map[rev].aux = ri;
88 getrevtree(Revtree *(*fn)(Revlog *, Revlog *, Revinfo *), Revinfo *ri)
100 for(i=j=0; i<nelem(cache); i++){
101 if(cache[i].t == nil){
105 if(cache[i].f == fn && cache[i].i == ri){
110 if(cache[j].t && cache[i].g < cache[j].g)
113 if((rt = (*fn)(&changelog, &manifest, ri)) == nil)
116 closerevtree(cache[j].t);
134 while(x = strchr(s, '<'))
137 if(x = strchr(s, '>'))
139 if(x = strchr(s, '@'))
141 if(x = strchr(s, '\n'))
144 if(s == nil || *s == 0){
146 s = estrdup9p("hgfs");
152 fsmkqid(Qid *q, int level, void *aux)
176 q->path = *((uvlong*)ri->chash) + (level - Qrev);
182 if(level == Qtree && nd->down){
187 q->path = nd->path + (level - Qtree);
194 fsmkdir(Dir *d, int level, void *aux)
201 memset(d, 0, sizeof(*d));
203 fsmkqid(&d->qid, level, aux);
206 if(d->qid.type == QTDIR)
207 d->mode |= DMDIR | 0111;
219 rev = hashrev(&changelog, ri->chash);
221 rev = changelog.map[rev].p1rev;
222 else if(level == Qrev2)
223 rev = changelog.map[rev].p2rev;
225 snprint(s = buf, sizeof(buf), "%d.%H", rev, changelog.map[rev].hash);
227 d->name = estrdup9p(buf);
233 d->length = ri->loglen;
243 d->length = s ? strlen(s)+1 : 0;
244 if(level == Qtreerev)
251 d->name = estrdup9p(nametab[level]);
256 d->name = estrdup9p(nd->name);
262 if((rl = getrevlog(nd)) == nil)
264 if((rev = hashrev(rl, nd->hash)) >= 0){
266 d->length = rl->map[rev].flen;
267 ri = getrevinfo(rl->map[rev].linkrev);
270 if(level == Qtreerev && ri)
277 d->atime = d->mtime = ri->when;
278 d->muid = fsmkuid(ri->who);
279 d->uid = fsmkuid(ri->who);
281 d->atime = d->mtime = time(0);
284 d->uid = fsmkuid(nil);
286 d->gid = fsmkuid(nil);
288 d->muid = fsmkuid(nil);
296 if(r->ifcall.aname && r->ifcall.aname[0]){
297 respond(r, "invalid attach specifier");
300 r->fid->qid.path = Qroot;
301 r->fid->qid.type = QTDIR;
302 r->fid->qid.vers = 0;
303 r->ofcall.qid = r->fid->qid;
305 rf = emalloc9p(sizeof(*rf));
326 if(rf->level < Qtree)
327 fsmkdir(&r->d, rf->level, rf->info);
329 fsmkdir(&r->d, rf->level, rf->node);
334 findrev(Revlog *rl, char *name)
340 if(strcmp(name, "tip") == 0)
342 rev = strtol(name, &s, 10);
343 if(s > name && (*s == 0 || ispunct(*s)))
346 if(s = strchr(name, '.'))
348 if((n = strhash(name, hash)) > 0){
349 for(i=0; i<rl->nmap; i++){
350 if(memcmp(rl->map[i].hash, hash, n) == 0){
364 fswalk1(Fid *fid, char *name, Qid *qid)
366 Revtree* (*loadfn)(Revlog *, Revlog *, Revinfo *);
373 if(!(fid->qid.type&QTDIR))
374 return "walk in non-directory";
377 if(strcmp(name, "..") == 0){
387 closerevtree(rf->tree);
392 closerevlog(rf->rlog);
394 if((rf->node = rf->node->up) == rf->tree->root)
395 rf->level = rf->tree->level;
401 revlogupdate(&changelog);
402 revlogupdate(&manifest);
404 i = findrev(&changelog, name);
405 if(rf->info = getrevinfo(i)){
410 return "directory entry not found";
413 for(i = Qrev+1; i < Qtree; i++){
414 if(nametab[i] == nil)
416 if(strcmp(name, nametab[i]) == 0)
424 loadfn = loadfilestree;
427 loadfn = loadchangestree;
431 if((rf->tree = getrevtree(loadfn, rf->info)) == nil)
433 rf->node = rf->tree->root;
445 for(nd = rf->node->down; nd; nd = nd->next)
446 if(strcmp(nd->name, sname) == 0)
450 sname = strrchr(name, '.');
451 if((i = sname - name) > 0){
453 if(strncmp(sname, "rev", 3) == 0){
457 snprint(path, sizeof(path), "%.*s", i, name);
469 if((rf->rlog = getrevlog(nd)) == nil)
471 j = hashrev(rf->rlog, nd->hash) - i;
472 if(i < 0 || j < 0 || j >= rf->rlog->nmap){
473 closerevlog(rf->rlog);
477 for(nb = nd; nb; nb = nb->before)
478 if(hashrev(rf->rlog, nb->hash) == j)
481 nb = mknode(nd->name, revhash(rf->rlog, j), nd->mode);
483 nb->before = nd->before;
487 } else if(i || level != Qtree)
495 if(rf->level < Qtree)
496 fsmkqid(qid, rf->level, rf->info);
498 fsmkqid(qid, rf->level, rf->node);
505 fsclone(Fid *oldfid, Fid *newfid)
510 if(orf = oldfid->aux){
511 rf = emalloc9p(sizeof(*rf));
518 rf->fd = dup(rf->fd, -1);
520 rf->buf = estrdup9p(rf->buf);
527 fsdestroyfid(Fid *fid)
532 closerevlog(rf->rlog);
533 closerevtree(rf->tree);
547 switch(r->ifcall.mode & 3){
549 if(rf->node == nil || rf->node->mode != 'x')
555 respond(r, "permission denied");
559 rootgen(int i, Dir *d, void *)
563 if((ri = getrevinfo(i)) == nil)
565 fsmkdir(d, Qrev, ri);
570 revgen(int i, Dir *d, void *aux)
580 treegen(int i, Dir *d, void *aux)
590 fsmkdir(d, Qtree, nd);
604 off = r->ifcall.offset;
605 len = r->ifcall.count;
610 revlogupdate(&changelog);
611 revlogupdate(&manifest);
612 dirread9p(r, rootgen, nil);
616 dirread9p(r, revgen, rf->info);
624 if((i = hashrev(&changelog, rf->info->chash)) >= 0){
625 if(rf->level == Qrev1)
626 i = changelog.map[i].p1rev;
628 i = changelog.map[i].p2rev;
631 snprint(s = buf, sizeof(buf), "%d.%H", i, changelog.map[i].hash);
636 if((i = hashrev(rf->rlog, rf->node->hash)) >= 0)
637 i = rf->rlog->map[i].linkrev;
640 if(off >= rf->info->loglen)
642 else if((off + len) >= rf->info->loglen)
643 len = rf->info->loglen - off;
644 off += rf->info->logoff;
647 if((rf->fd = revlogopentemp(&changelog, hashrev(&changelog, rf->info->chash))) < 0){
659 rf->buf = s ? smprint("%s\n", s) : estrdup9p("");
667 dirread9p(r, treegen, rf->node->down);
673 if((rf->fd = revlogopentemp(rf->rlog, hashrev(rf->rlog, rf->node->hash))) < 0){
678 if((n = pread(rf->fd, r->ofcall.data, len, off)) < 0){
686 respond(r, "bug in fsread");
695 .destroyfid=fsdestroyfid,
703 fprint(2, "usage: %s [-D] [-m mtpt] [-s srv]\n", argv0);
708 main(int argc, char *argv[])
713 fmtinstall('H', Hfmt);
723 mtpt = EARGF(usage());
726 srv = EARGF(usage());
732 if(revlogopen(&changelog, ".hg/store/00changelog", OREAD) < 0)
733 sysfatal("can't open changelog: %r\n");
734 if(revlogopen(&manifest, ".hg/store/00manifest", OREAD) < 0)
735 sysfatal("can't open menifest: %r\n");
737 postmountsrv(&fs, srv, mtpt, MREPL);