hgfs: get previous file revisions with appending .n or .revn
This commit is contained in:
parent
d0485d345d
commit
6d91601a77
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue