hgfs: get previous file revisions with appending .n or .revn

This commit is contained in:
cinap_lenrek 2011-06-28 03:51:05 +02:00
parent d0485d345d
commit 6d91601a77
5 changed files with 153 additions and 52 deletions

View file

@ -33,6 +33,10 @@ struct Revmap
struct Revlog
{
Ref;
char *path;
int ifd;
int dfd;
@ -51,6 +55,7 @@ struct Revnode
Revnode *up;
Revnode *next;
Revnode *down;
Revnode *before;
char mode;
};
@ -82,6 +87,7 @@ struct Revfile
Revinfo *info;
Revtree *tree;
Revnode *node;
Revlog *rlog;
char *buf;
int fd;

View file

@ -25,6 +25,7 @@ Revinfo *loadrevinfo(Revlog *changelog, int rev);
/* tree */
char *nodepath(char *s, char *e, Revnode *nd);
Revnode *mknode(char *name, uchar *hash, char mode);
Revtree *loadfilestree(Revlog *changelog, Revlog *manifest, Revinfo *ri);
Revtree *loadchangestree(Revlog *changelog, Revlog *manifest, Revinfo *ri);
void closerevtree(Revtree *t);

View file

@ -21,9 +21,10 @@ enum {
Qfiles,
Qchanges,
Qtree,
Qtreerev,
};
static char *nametab[Qtree+1] = {
static char *nametab[] = {
"/",
nil,
"rev1",
@ -34,11 +35,41 @@ static char *nametab[Qtree+1] = {
"files",
"changes",
nil,
nil,
};
static Revlog changelog;
static Revlog manifest;
static Revlog*
getrevlog(Revnode *nd)
{
char path[MAXPATH];
Revlog *rl;
nodepath(seprint(path, path+MAXPATH, ".hg/store/data"), path+MAXPATH, nd);
rl = emalloc9p(sizeof(*rl));
memset(rl, 0, sizeof(*rl));
if(revlogopen(rl, path, OREAD) < 0){
fprint(2, "getrevlod %s: %r\n", path);
free(rl);
return nil;
}
incref(rl);
return rl;
}
static void
closerevlog(Revlog *rl)
{
if(rl == nil)
return;
if(decref(rl))
return;
revlogclose(rl);
free(rl);
}
static Revinfo*
getrevinfo(int rev)
{
@ -146,13 +177,14 @@ fsmkqid(Qid *q, int level, void *aux)
q->vers = 0;
break;
case Qtree:
case Qtreerev:
nd = aux;
if(nd->down){
if(level == Qtree && nd->down){
q->type = QTDIR;
} else {
q->type = 0;
}
q->path = nd->path;
q->path = nd->path + (level - Qtree);
q->vers = 0;
break;
}
@ -183,6 +215,7 @@ fsmkdir(Dir *d, int level, void *aux)
case Qrev1:
case Qrev2:
ri = aux;
Revgen:
rev = hashrev(&changelog, ri->chash);
if(level == Qrev1)
rev = changelog.map[rev].p1rev;
@ -208,6 +241,8 @@ fsmkdir(Dir *d, int level, void *aux)
s = ri->why;
Strgen:
d->length = s ? strlen(s)+1 : 0;
if(level == Qtreerev)
break;
case Qfiles:
case Qchanges:
ri = aux;
@ -216,22 +251,24 @@ fsmkdir(Dir *d, int level, void *aux)
d->name = estrdup9p(nametab[level]);
break;
case Qtree:
case Qtreerev:
nd = aux;
d->name = estrdup9p(nd->name);
if(nd->mode == 'x')
d->mode |= 0111;
if(nd->hash){
char path[MAXPATH];
Revlog rl;
Revlog *rl;
nodepath(seprint(path, path+MAXPATH, ".hg/store/data"), path+MAXPATH, nd);
if(revlogopen(&rl, path, OREAD) < 0)
if((rl = getrevlog(nd)) == nil)
break;
if((rev = hashrev(&rl, nd->hash)) >= 0){
d->length = rl.map[rev].flen;
ri = getrevinfo(rl.map[rev].linkrev);
if((rev = hashrev(rl, nd->hash)) >= 0){
if(level == Qtree)
d->length = rl->map[rev].flen;
ri = getrevinfo(rl->map[rev].linkrev);
}
revlogclose(&rl);
closerevlog(rl);
if(level == Qtreerev && ri)
goto Revgen;
}
break;
}
@ -270,6 +307,7 @@ fsattach(Req *r)
rf->info = nil;
rf->tree = nil;
rf->node = nil;
rf->rlog = nil;
rf->fd = -1;
rf->buf = nil;
@ -326,9 +364,11 @@ static char*
fswalk1(Fid *fid, char *name, Qid *qid)
{
Revtree* (*loadfn)(Revlog *, Revlog *, Revinfo *);
Revfile *rf;
char path[MAXPATH];
Revnode *nd;
int i;
Revfile *rf;
char *sname;
int i, level;
if(!(fid->qid.type&QTDIR))
return "walk in non-directory";
@ -349,6 +389,8 @@ fswalk1(Fid *fid, char *name, Qid *qid)
rf->level = Qrev;
break;
case Qtree:
closerevlog(rf->rlog);
rf->rlog = nil;
if((rf->node = rf->node->up) == rf->tree->root)
rf->level = rf->tree->level;
break;
@ -396,13 +438,56 @@ fswalk1(Fid *fid, char *name, Qid *qid)
case Qtree:
case Qfiles:
case Qchanges:
i = 0;
level = Qtree;
sname = name;
Searchtree:
for(nd = rf->node->down; nd; nd = nd->next)
if(strcmp(nd->name, name) == 0)
if(strcmp(nd->name, sname) == 0)
break;
if(nd == nil)
if(nd == nil){
if(sname == name){
sname = strrchr(name, '.');
if((i = sname - name) > 0){
sname++;
if(strncmp(sname, "rev", 3) == 0){
level = Qtreerev;
sname += 3;
}
snprint(path, sizeof(path), "%.*s", i, name);
i = atoi(sname);
sname = path;
goto Searchtree;
}
}
goto Notfound;
}
if(nd->hash){
Revnode *nb;
int j;
if((rf->rlog = getrevlog(nd)) == nil)
goto Notfound;
j = hashrev(rf->rlog, nd->hash) - i;
if(i < 0 || j < 0 || j >= rf->rlog->nmap){
closerevlog(rf->rlog);
rf->rlog = nil;
goto Notfound;
}
for(nb = nd; nb; nb = nb->before)
if(hashrev(rf->rlog, nb->hash) == j)
break;
if(nb == nil){
nb = mknode(nd->name, revhash(rf->rlog, j), nd->mode);
nb->up = nd->up;
nb->before = nd->before;
nd->before = nb;
}
nd = nb;
} else if(i || level != Qtree)
goto Notfound;
rf->node = nd;
rf->level = Qtree;
rf->level = level;
break;
}
}
@ -425,6 +510,8 @@ fsclone(Fid *oldfid, Fid *newfid)
if(orf = oldfid->aux){
rf = emalloc9p(sizeof(*rf));
*rf = *orf;
if(rf->rlog)
incref(rf->rlog);
if(rf->tree)
incref(rf->tree);
if(rf->fd >= 0)
@ -442,6 +529,7 @@ fsdestroyfid(Fid *fid)
Revfile *rf;
if(rf = fid->aux){
closerevlog(rf->rlog);
closerevtree(rf->tree);
if(rf->fd >= 0)
close(rf->fd);
@ -508,7 +596,6 @@ fsread(Req *r)
{
Revfile *rf;
char buf[MAXPATH];
Revlog rl;
char *s;
int i, n;
vlong off;
@ -539,10 +626,16 @@ fsread(Req *r)
i = changelog.map[i].p1rev;
else
i = changelog.map[i].p2rev;
Revgen:
if(i >= 0)
snprint(s = buf, sizeof(buf), "%d.%H", i, changelog.map[i].hash);
}
goto Strgen;
case Qtreerev:
s = nil;
if((i = hashrev(rf->rlog, rf->node->hash)) >= 0)
i = rf->rlog->map[i].linkrev;
goto Revgen;
case Qlog:
if(off >= rf->info->loglen)
len = 0;
@ -577,17 +670,10 @@ fsread(Req *r)
}
if(rf->fd >= 0)
goto Fdgen;
nodepath(seprint(buf, buf+sizeof(buf), ".hg/store/data"), buf+sizeof(buf), rf->node);
if(revlogopen(&rl, buf, OREAD) < 0){
if((rf->fd = revlogopentemp(rf->rlog, hashrev(rf->rlog, rf->node->hash))) < 0){
responderror(r);
return;
}
if((rf->fd = revlogopentemp(&rl, hashrev(&rl, rf->node->hash))) < 0){
responderror(r);
revlogclose(&rl);
return;
}
revlogclose(&rl);
Fdgen:
if((n = pread(rf->fd, r->ofcall.data, len, off)) < 0){
responderror(r);

View file

@ -68,7 +68,10 @@ revlogopen(Revlog *r, char *path, int mode)
}
path[strlen(path)-1] = 'd';
r->dfd = open(path, mode);
free(path);
path[strlen(path)-2] = 0;
r->path = path;
r->ioff = 0;
r->nmap = 0;
r->map = nil;
@ -90,6 +93,7 @@ revlogclose(Revlog *r)
free(r->map);
r->map = nil;
r->nmap = 0;
free(r->path);
}
uchar*

View file

@ -22,7 +22,7 @@ nodepath(char *s, char *e, Revnode *nd)
p = nd->name;
for(i=0; i<nelem(frogs); i++)
if(strcmp(frogs[i], p) == 0)
if(strncmp(frogs[i], p, strlen(frogs[i])) == 0)
return seprint(s, e, "%.2s~%.2x%s", p, p[2], p+3);
for(; s+4 < e && *p; p++){
@ -43,10 +43,35 @@ nodepath(char *s, char *e, Revnode *nd)
return s;
}
Revnode*
mknode(char *name, uchar *hash, char mode)
{
Revnode *d;
char *s;
d = malloc(sizeof(*d) + (hash ? HASHSZ : 0) + (name ? strlen(name)+1 : 0));
d->up = d->down = d->next = d->before = nil;
s = (char*)&d[1];
if(hash){
d->path = *((uvlong*)hash);
memmove(d->hash = (uchar*)s, hash, HASHSZ);
s += HASHSZ;
} else {
d->path = 1;
d->hash = nil;
}
if(name)
strcpy(d->name = s, name);
else
d->name = nil;
d->mode = mode;
return d;
}
static void
addnode(Revnode *d, char *path, uchar *hash, char mode)
{
char *slash, *x;
char *slash;
Revnode *c, *p;
while(path && *path){
@ -57,20 +82,8 @@ addnode(Revnode *d, char *path, uchar *hash, char mode)
if(strcmp(c->name, path) == 0)
break;
if(c == nil){
c = malloc(sizeof(*c) + (!slash ? HASHSZ : 0) + strlen(path)+1);
c->path = 1;
x = (char*)&c[1];
if(!slash){
c->mode = mode;
memmove(c->hash = (uchar*)x, hash, HASHSZ);
x += HASHSZ;
}else{
c->mode = 0;
c->hash = nil;
}
strcpy(c->name = x, path);
c = mknode(path, slash ? nil : hash, slash ? 0 : mode);
c->up = d;
c->down = nil;
if(p){
c->next = p->next;
p->next = c;
@ -78,7 +91,6 @@ addnode(Revnode *d, char *path, uchar *hash, char mode)
c->next = d->down;
d->down = c;
}
if(c->hash){
p = c;
p->path = *((uvlong*)c->hash);
@ -170,21 +182,12 @@ loadtree(Revlog *manifest, Revinfo *ri, Hashstr **ht, int nh)
t = malloc(sizeof(*t));
memset(t, 0, sizeof(*t));
incref(t);
t->root = malloc(sizeof(Revnode));
t->root->path = 0;
t->root->name = 0;
t->root->up = nil;
t->root->down = nil;
t->root->next = nil;
t->root->hash = nil;
t->root = mknode(nil, nil, 0);
if(loadmanifest(t->root, fd, ht, nh) < 0){
close(fd);
closerevtree(t);
return nil;
}
close(fd);
return t;
@ -259,6 +262,7 @@ freenode(Revnode *nd)
return;
freenode(nd->down);
freenode(nd->next);
freenode(nd->before);
free(nd);
}