add hgfs, a mercurial filesystem
This commit is contained in:
parent
8fa679d041
commit
bc1ff6985c
10 changed files with 1639 additions and 0 deletions
84
sys/src/cmd/hgfs/dat.h
Normal file
84
sys/src/cmd/hgfs/dat.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
enum {
|
||||
MAXPATH = 1024,
|
||||
BUFSZ = 1024,
|
||||
HASHSZ = 20,
|
||||
};
|
||||
|
||||
typedef struct Revlog Revlog;
|
||||
typedef struct Revmap Revmap;
|
||||
typedef struct Revinfo Revinfo;
|
||||
typedef struct Revtree Revtree;
|
||||
typedef struct Revnode Revnode;
|
||||
typedef struct Revfile Revfile;
|
||||
|
||||
struct Revmap
|
||||
{
|
||||
int rev;
|
||||
int p1rev;
|
||||
int p2rev;
|
||||
int baserev;
|
||||
int linkrev;
|
||||
|
||||
uchar hash[HASHSZ];
|
||||
|
||||
int flags;
|
||||
|
||||
vlong hoff;
|
||||
vlong hlen;
|
||||
|
||||
vlong flen;
|
||||
|
||||
void *aux;
|
||||
};
|
||||
|
||||
struct Revlog
|
||||
{
|
||||
int ifd;
|
||||
int dfd;
|
||||
|
||||
int nmap;
|
||||
Revmap *map;
|
||||
};
|
||||
|
||||
struct Revnode
|
||||
{
|
||||
char *name;
|
||||
uchar *hash;
|
||||
uvlong path;
|
||||
|
||||
Revnode *up;
|
||||
Revnode *next;
|
||||
Revnode *down;
|
||||
};
|
||||
|
||||
struct Revinfo
|
||||
{
|
||||
uchar chash[HASHSZ];
|
||||
uchar mhash[HASHSZ];
|
||||
|
||||
char *who;
|
||||
char *why;
|
||||
long when;
|
||||
};
|
||||
|
||||
struct Revtree
|
||||
{
|
||||
Ref;
|
||||
|
||||
int level;
|
||||
|
||||
Revinfo *info;
|
||||
Revnode *root;
|
||||
};
|
||||
|
||||
struct Revfile
|
||||
{
|
||||
int level;
|
||||
|
||||
Revinfo *info;
|
||||
Revtree *tree;
|
||||
Revnode *node;
|
||||
|
||||
char *buf;
|
||||
int fd;
|
||||
};
|
30
sys/src/cmd/hgfs/fns.h
Normal file
30
sys/src/cmd/hgfs/fns.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* hash */
|
||||
int Hfmt(Fmt *f);
|
||||
int strhash(char *s, uchar *h);
|
||||
int fhash(int fd, uchar p1[], uchar p2[], uchar h[]);
|
||||
|
||||
/* patch */
|
||||
int fpatchmark(int pfd, char *mark);
|
||||
int fpatch(int ofd, int bfd, int pfd);
|
||||
|
||||
/* zip */
|
||||
int funzip(int ofd, int zfd, int len);
|
||||
|
||||
/* revlog */
|
||||
int fmktemp(void);
|
||||
int revlogopen(Revlog *r, char *path, int mode);
|
||||
void revlogclose(Revlog *r);
|
||||
int revlogextract(Revlog *r, int rev, int ofd);
|
||||
uchar *revhash(Revlog *r, int rev);
|
||||
int hashrev(Revlog *r, uchar hash[]);
|
||||
int revlogopentemp(Revlog *r, int rev);
|
||||
|
||||
/* info */
|
||||
Revinfo *loadrevinfo(Revlog *changelog, int rev);
|
||||
|
||||
/* tree */
|
||||
char *nodepath(char *s, char *e, Revnode *nd);
|
||||
Revtree *loadfilestree(Revlog *changelog, Revlog *manifest, Revinfo *ri);
|
||||
Revtree *loadchangestree(Revlog *changelog, Revlog *manifest, Revinfo *ri);
|
||||
void closerevtree(Revtree *t);
|
||||
|
587
sys/src/cmd/hgfs/fs.c
Normal file
587
sys/src/cmd/hgfs/fs.c
Normal file
|
@ -0,0 +1,587 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <flate.h>
|
||||
#include <auth.h>
|
||||
#include <fcall.h>
|
||||
#include <9p.h>
|
||||
|
||||
enum {
|
||||
Qroot,
|
||||
Qrev,
|
||||
Qrev1,
|
||||
Qrev2,
|
||||
Qlog,
|
||||
Qwho,
|
||||
Qwhy,
|
||||
Qfiles,
|
||||
Qchanges,
|
||||
Qtree,
|
||||
};
|
||||
|
||||
static char *nametab[Qtree+1] = {
|
||||
"/",
|
||||
nil,
|
||||
"rev1",
|
||||
"rev2",
|
||||
"log",
|
||||
"who",
|
||||
"why",
|
||||
"files",
|
||||
"changes",
|
||||
nil,
|
||||
};
|
||||
|
||||
static Revlog changelog;
|
||||
static Revlog manifest;
|
||||
|
||||
static Revinfo*
|
||||
getrevinfo(int rev)
|
||||
{
|
||||
Revinfo *ri;
|
||||
|
||||
if(rev < 0 || rev >= changelog.nmap)
|
||||
return nil;
|
||||
if(ri = changelog.map[rev].aux)
|
||||
return ri;
|
||||
if(ri = loadrevinfo(&changelog, rev))
|
||||
changelog.map[rev].aux = ri;
|
||||
return ri;
|
||||
}
|
||||
|
||||
static char*
|
||||
fsmkuid(char *s)
|
||||
{
|
||||
if(s){
|
||||
char *x;
|
||||
|
||||
while(x = strchr(s, '<'))
|
||||
s = x+1;
|
||||
s = estrdup9p(s);
|
||||
if(x = strchr(s, '>'))
|
||||
*x = 0;
|
||||
if(x = strchr(s, '@'))
|
||||
*x = 0;
|
||||
if(x = strchr(s, '\n'))
|
||||
*x = 0;
|
||||
}
|
||||
if(s == nil || *s == 0){
|
||||
free(s);
|
||||
s = estrdup9p("hgfs");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
fsmkqid(Qid *q, int level, void *aux)
|
||||
{
|
||||
Revnode *nd;
|
||||
Revinfo *ri;
|
||||
|
||||
switch(level){
|
||||
case Qroot:
|
||||
q->type = QTDIR;
|
||||
q->path = Qroot;
|
||||
q->vers = 0;
|
||||
break;
|
||||
case Qrev:
|
||||
case Qfiles:
|
||||
case Qchanges:
|
||||
q->type = QTDIR;
|
||||
if(0){
|
||||
case Qrev1:
|
||||
case Qrev2:
|
||||
case Qlog:
|
||||
case Qwho:
|
||||
case Qwhy:
|
||||
q->type = 0;
|
||||
}
|
||||
ri = aux;
|
||||
q->path = *((uvlong*)ri->chash) + (level - Qrev);
|
||||
q->vers = 0;
|
||||
break;
|
||||
case Qtree:
|
||||
nd = aux;
|
||||
if(nd->hash){
|
||||
q->type = 0;
|
||||
} else {
|
||||
q->type = QTDIR;
|
||||
}
|
||||
q->path = nd->path;
|
||||
q->vers = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fsmkdir(Dir *d, int level, void *aux)
|
||||
{
|
||||
char buf[64], *s;
|
||||
Revnode *nd;
|
||||
Revinfo *ri;
|
||||
int rev;
|
||||
|
||||
memset(d, 0, sizeof(*d));
|
||||
|
||||
fsmkqid(&d->qid, level, aux);
|
||||
|
||||
d->mode = 0444;
|
||||
if(d->qid.type == QTDIR)
|
||||
d->mode |= DMDIR | 0111;
|
||||
|
||||
s = nil;
|
||||
ri = nil;
|
||||
switch(level){
|
||||
case Qroot:
|
||||
goto Namegen;
|
||||
case Qrev:
|
||||
case Qrev1:
|
||||
case Qrev2:
|
||||
ri = aux;
|
||||
rev = hashrev(&changelog, ri->chash);
|
||||
if(level == Qrev1)
|
||||
rev = changelog.map[rev].p1rev;
|
||||
else if(level == Qrev2)
|
||||
rev = changelog.map[rev].p2rev;
|
||||
if(rev >= 0)
|
||||
snprint(s = buf, sizeof(buf), "%d.%H", rev, changelog.map[rev].hash);
|
||||
if(level == Qrev){
|
||||
d->name = estrdup9p(buf);
|
||||
break;
|
||||
}
|
||||
goto Strgen;
|
||||
case Qlog:
|
||||
ri = aux;
|
||||
if((rev = hashrev(&changelog, ri->chash)) >= 0)
|
||||
d->length = changelog.map[rev].flen;
|
||||
goto Namegen;
|
||||
case Qwho:
|
||||
ri = aux;
|
||||
s = ri->who;
|
||||
goto Strgen;
|
||||
case Qwhy:
|
||||
ri = aux;
|
||||
s = ri->why;
|
||||
Strgen:
|
||||
d->length = s ? strlen(s)+1 : 0;
|
||||
case Qfiles:
|
||||
case Qchanges:
|
||||
ri = aux;
|
||||
/* no break */
|
||||
Namegen:
|
||||
d->name = estrdup9p(nametab[level]);
|
||||
break;
|
||||
case Qtree:
|
||||
nd = aux;
|
||||
d->name = estrdup9p(nd->name);
|
||||
if(nd->hash){
|
||||
char path[MAXPATH];
|
||||
Revlog rl;
|
||||
|
||||
nodepath(seprint(path, path+MAXPATH, ".hg/store/data"), path+MAXPATH, nd);
|
||||
if(revlogopen(&rl, path, OREAD) < 0)
|
||||
break;
|
||||
if((rev = hashrev(&rl, nd->hash)) >= 0){
|
||||
d->length = rl.map[rev].flen;
|
||||
ri = getrevinfo(rl.map[rev].linkrev);
|
||||
}
|
||||
revlogclose(&rl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(ri){
|
||||
d->atime = d->mtime = ri->when;
|
||||
d->muid = fsmkuid(ri->who);
|
||||
d->uid = fsmkuid(ri->who);
|
||||
} else
|
||||
d->atime = d->mtime = time(0);
|
||||
|
||||
if(d->uid == nil)
|
||||
d->uid = fsmkuid(nil);
|
||||
if(d->gid == nil)
|
||||
d->gid = fsmkuid(nil);
|
||||
if(d->muid == nil)
|
||||
d->muid = fsmkuid(nil);
|
||||
}
|
||||
|
||||
static void
|
||||
fsattach(Req *r)
|
||||
{
|
||||
Revfile *rf;
|
||||
|
||||
if(r->ifcall.aname && r->ifcall.aname[0]){
|
||||
respond(r, "invalid attach specifier");
|
||||
return;
|
||||
}
|
||||
r->fid->qid.path = Qroot;
|
||||
r->fid->qid.type = QTDIR;
|
||||
r->fid->qid.vers = 0;
|
||||
r->ofcall.qid = r->fid->qid;
|
||||
|
||||
rf = emalloc9p(sizeof(*rf));
|
||||
rf->level = Qroot;
|
||||
rf->info = nil;
|
||||
rf->tree = nil;
|
||||
rf->node = nil;
|
||||
|
||||
rf->fd = -1;
|
||||
rf->buf = nil;
|
||||
|
||||
r->fid->aux = rf;
|
||||
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
fsstat(Req *r)
|
||||
{
|
||||
Revfile *rf;
|
||||
|
||||
rf = r->fid->aux;
|
||||
if(rf->level < Qtree)
|
||||
fsmkdir(&r->d, rf->level, rf->info);
|
||||
else
|
||||
fsmkdir(&r->d, rf->level, rf->node);
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static int
|
||||
findrev(Revlog *rl, char *name)
|
||||
{
|
||||
uchar hash[HASHSZ];
|
||||
int n, i, rev;
|
||||
char *s;
|
||||
|
||||
rev = strtol(name, &s, 10);
|
||||
if(s > name && (*s == 0 || ispunct(*s)))
|
||||
return rev;
|
||||
rev = -1;
|
||||
if(s = strchr(name, '.'))
|
||||
name = s+1;
|
||||
if((n = strhash(name, hash)) > 0){
|
||||
for(i=0; i<rl->nmap; i++){
|
||||
if(memcmp(rl->map[i].hash, hash, n) == 0){
|
||||
if(rev < 0)
|
||||
rev = i;
|
||||
else {
|
||||
rev = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rev;
|
||||
}
|
||||
|
||||
static char*
|
||||
fswalk1(Fid *fid, char *name, Qid *qid)
|
||||
{
|
||||
Revfile *rf;
|
||||
Revnode *nd;
|
||||
int i;
|
||||
|
||||
if(!(fid->qid.type&QTDIR))
|
||||
return "walk in non-directory";
|
||||
|
||||
rf = fid->aux;
|
||||
if(strcmp(name, "..") == 0){
|
||||
switch(rf->level){
|
||||
case Qroot:
|
||||
break;
|
||||
case Qrev:
|
||||
rf->info = nil;
|
||||
rf->level = Qroot;
|
||||
break;
|
||||
case Qfiles:
|
||||
case Qchanges:
|
||||
closerevtree(rf->tree);
|
||||
rf->tree = nil;
|
||||
rf->level = Qrev;
|
||||
break;
|
||||
case Qtree:
|
||||
if((rf->node = rf->node->up) == rf->tree->root)
|
||||
rf->level = rf->tree->level;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch(rf->level){
|
||||
case Qroot:
|
||||
i = findrev(&changelog, name);
|
||||
if(rf->info = getrevinfo(i)){
|
||||
rf->level = Qrev;
|
||||
break;
|
||||
}
|
||||
Notfound:
|
||||
return "directory entry not found";
|
||||
break;
|
||||
case Qrev:
|
||||
for(i = Qrev+1; i < Qtree; i++){
|
||||
if(nametab[i] == nil)
|
||||
continue;
|
||||
if(strcmp(name, nametab[i]) == 0)
|
||||
break;
|
||||
}
|
||||
switch(i){
|
||||
case Qtree:
|
||||
goto Notfound;
|
||||
case Qfiles:
|
||||
if((rf->tree = loadfilestree(&changelog, &manifest, rf->info)) == nil)
|
||||
goto Notfound;
|
||||
break;
|
||||
case Qchanges:
|
||||
if((rf->tree = loadchangestree(&changelog, &manifest, rf->info)) == nil)
|
||||
goto Notfound;
|
||||
break;
|
||||
}
|
||||
if(rf->tree){
|
||||
rf->node = rf->tree->root;
|
||||
rf->tree->level = i;
|
||||
}
|
||||
rf->level = i;
|
||||
break;
|
||||
case Qtree:
|
||||
case Qfiles:
|
||||
case Qchanges:
|
||||
for(nd = rf->node->down; nd; nd = nd->next)
|
||||
if(strcmp(nd->name, name) == 0)
|
||||
break;
|
||||
if(nd == nil)
|
||||
goto Notfound;
|
||||
rf->node = nd;
|
||||
rf->level = Qtree;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(rf->level < Qtree)
|
||||
fsmkqid(qid, rf->level, rf->info);
|
||||
else
|
||||
fsmkqid(qid, rf->level, rf->node);
|
||||
fid->qid = *qid;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
static char*
|
||||
fsclone(Fid *oldfid, Fid *newfid)
|
||||
{
|
||||
Revfile *orf, *rf;
|
||||
|
||||
rf = nil;
|
||||
if(orf = oldfid->aux){
|
||||
rf = emalloc9p(sizeof(*rf));
|
||||
*rf = *orf;
|
||||
if(rf->tree)
|
||||
incref(rf->tree);
|
||||
if(rf->fd >= 0)
|
||||
rf->fd = dup(rf->fd, -1);
|
||||
if(rf->buf)
|
||||
rf->buf = estrdup9p(rf->buf);
|
||||
}
|
||||
newfid->aux = rf;
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void
|
||||
fsdestroyfid(Fid *fid)
|
||||
{
|
||||
Revfile *rf;
|
||||
|
||||
if(rf = fid->aux){
|
||||
closerevtree(rf->tree);
|
||||
if(rf->fd >= 0)
|
||||
close(rf->fd);
|
||||
free(rf->buf);
|
||||
free(rf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fsopen(Req *r)
|
||||
{
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static int
|
||||
rootgen(int i, Dir *d, void *)
|
||||
{
|
||||
Revinfo *ri;
|
||||
|
||||
if((ri = getrevinfo(i)) == nil)
|
||||
return -1;
|
||||
fsmkdir(d, Qrev, ri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
revgen(int i, Dir *d, void *aux)
|
||||
{
|
||||
i += Qrev+1;
|
||||
if(i >= Qtree)
|
||||
return -1;
|
||||
fsmkdir(d, i, aux);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
treegen(int i, Dir *d, void *aux)
|
||||
{
|
||||
Revnode *nd = aux;
|
||||
|
||||
while(i > 0 && nd){
|
||||
nd = nd->next;
|
||||
i--;
|
||||
}
|
||||
if(i || nd == nil)
|
||||
return -1;
|
||||
fsmkdir(d, Qtree, nd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
fsread(Req *r)
|
||||
{
|
||||
Revfile *rf;
|
||||
|
||||
rf = r->fid->aux;
|
||||
if(r->fid->qid.type == QTDIR){
|
||||
switch(rf->level){
|
||||
default:
|
||||
respond(r, "bug in fsread");
|
||||
return;
|
||||
case Qroot:
|
||||
dirread9p(r, rootgen, nil);
|
||||
respond(r, nil);
|
||||
return;
|
||||
case Qrev:
|
||||
dirread9p(r, revgen, rf->info);
|
||||
respond(r, nil);
|
||||
return;
|
||||
case Qtree:
|
||||
case Qfiles:
|
||||
case Qchanges:
|
||||
dirread9p(r, treegen, rf->node->down);
|
||||
respond(r, nil);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
char buf[MAXPATH];
|
||||
Revlog rl;
|
||||
char *s;
|
||||
int i, n;
|
||||
|
||||
switch(rf->level){
|
||||
default:
|
||||
respond(r, "bug in fsread");
|
||||
return;
|
||||
case Qlog:
|
||||
if(rf->fd >= 0)
|
||||
break;
|
||||
if((rf->fd = revlogopentemp(&changelog, hashrev(&changelog, rf->info->chash))) < 0){
|
||||
responderror(r);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case Qrev1:
|
||||
case Qrev2:
|
||||
s = nil;
|
||||
if((i = hashrev(&changelog, rf->info->chash)) >= 0){
|
||||
if(rf->level == Qrev1)
|
||||
i = changelog.map[i].p1rev;
|
||||
else
|
||||
i = changelog.map[i].p2rev;
|
||||
if(i >= 0)
|
||||
snprint(s = buf, sizeof(buf), "%d.%H", i, changelog.map[i].hash);
|
||||
}
|
||||
goto Strgen;
|
||||
case Qwho:
|
||||
s = rf->info->who;
|
||||
goto Strgen;
|
||||
case Qwhy:
|
||||
s = rf->info->why;
|
||||
Strgen:
|
||||
if(rf->buf == nil)
|
||||
rf->buf = s ? smprint("%s\n", s) : estrdup9p("");
|
||||
readstr(r, rf->buf);
|
||||
respond(r, nil);
|
||||
return;
|
||||
case Qtree:
|
||||
if(rf->fd >= 0)
|
||||
break;
|
||||
nodepath(seprint(buf, buf+sizeof(buf), ".hg/store/data"), buf+sizeof(buf), rf->node);
|
||||
if(revlogopen(&rl, buf, OREAD) < 0){
|
||||
responderror(r);
|
||||
return;
|
||||
}
|
||||
if((rf->fd = revlogopentemp(&rl, hashrev(&rl, rf->node->hash))) < 0){
|
||||
responderror(r);
|
||||
revlogclose(&rl);
|
||||
return;
|
||||
}
|
||||
revlogclose(&rl);
|
||||
break;
|
||||
}
|
||||
if((n = pread(rf->fd, r->ofcall.data, r->ifcall.count, r->ifcall.offset)) < 0){
|
||||
responderror(r);
|
||||
return;
|
||||
}
|
||||
r->ofcall.count = n;
|
||||
respond(r, nil);
|
||||
}
|
||||
}
|
||||
|
||||
Srv fs =
|
||||
{
|
||||
.attach=fsattach,
|
||||
.stat=fsstat,
|
||||
.walk1=fswalk1,
|
||||
.clone=fsclone,
|
||||
.destroyfid=fsdestroyfid,
|
||||
.open=fsopen,
|
||||
.read=fsread,
|
||||
};
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-D] [-m mtpt] [-s srv]\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *srv, *mtpt;
|
||||
|
||||
inflateinit();
|
||||
fmtinstall('H', Hfmt);
|
||||
|
||||
srv = nil;
|
||||
mtpt = "/n/hg";
|
||||
|
||||
ARGBEGIN {
|
||||
case 'D':
|
||||
chatty9p++;
|
||||
break;
|
||||
case 'm':
|
||||
mtpt = EARGF(usage());
|
||||
break;
|
||||
case 's':
|
||||
srv = EARGF(usage());
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND;
|
||||
|
||||
if(revlogopen(&changelog, ".hg/store/00changelog", OREAD) < 0)
|
||||
sysfatal("can't open changelog: %r\n");
|
||||
if(revlogopen(&manifest, ".hg/store/00manifest", OREAD) < 0)
|
||||
sysfatal("can't open menifest: %r\n");
|
||||
|
||||
postmountsrv(&fs, srv, mtpt, MREPL);
|
||||
}
|
69
sys/src/cmd/hgfs/hash.c
Normal file
69
sys/src/cmd/hgfs/hash.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
#include <mp.h>
|
||||
#include <libsec.h>
|
||||
|
||||
int
|
||||
Hfmt(Fmt *f)
|
||||
{
|
||||
uchar *p;
|
||||
|
||||
p = va_arg(f->args, uchar*);
|
||||
return fmtprint(f,
|
||||
"%.2x%.2x%.2x%.2x%.2x%.2x",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5]);
|
||||
}
|
||||
|
||||
int
|
||||
fhash(int fd, uchar p1[], uchar p2[], uchar h[])
|
||||
{
|
||||
DigestState *ds;
|
||||
uchar buf[BUFSZ];
|
||||
int n;
|
||||
|
||||
ds = nil;
|
||||
memset(h, 0, HASHSZ);
|
||||
if(memcmp(p1, p2, HASHSZ) > 0){
|
||||
ds = sha1(p2, HASHSZ, nil, ds);
|
||||
sha1(p1, HASHSZ, nil, ds);
|
||||
} else {
|
||||
ds = sha1(p1, HASHSZ, nil, ds);
|
||||
sha1(p2, HASHSZ, nil, ds);
|
||||
}
|
||||
while((n = read(fd, buf, BUFSZ)) > 0)
|
||||
sha1(buf, n, nil, ds);
|
||||
sha1(buf, 0, h, ds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
strhash(char *s, uchar *h)
|
||||
{
|
||||
uchar *b;
|
||||
int n;
|
||||
|
||||
b = h;
|
||||
memset(h, 0, HASHSZ);
|
||||
n = HASHSZ*2;
|
||||
while(*s && n > 0){
|
||||
if(*s >= '0' && *s <= '9')
|
||||
*h |= *s - '0';
|
||||
else if(*s >= 'a' && *s <= 'f')
|
||||
*h |= 10 + *s - 'a';
|
||||
else if(*s >= 'A' && *s <= 'F')
|
||||
*h |= 10 + *s - 'A';
|
||||
else
|
||||
break;
|
||||
if(n-- & 1)
|
||||
h++;
|
||||
else
|
||||
*h <<= 4;
|
||||
s++;
|
||||
}
|
||||
return h - b;
|
||||
}
|
64
sys/src/cmd/hgfs/info.c
Normal file
64
sys/src/cmd/hgfs/info.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
Revinfo*
|
||||
loadrevinfo(Revlog *changelog, int rev)
|
||||
{
|
||||
char buf[BUFSZ], *p, *e;
|
||||
int fd, line, inmsg, n;
|
||||
Revinfo *ri;
|
||||
|
||||
if((fd = revlogopentemp(changelog, rev)) < 0)
|
||||
return nil;
|
||||
|
||||
seek(fd, 0, 2);
|
||||
write(fd, "\n", 1);
|
||||
seek(fd, 0, 0);
|
||||
|
||||
ri = malloc(sizeof(*ri));
|
||||
memset(ri, 0, sizeof(*ri));
|
||||
|
||||
memmove(ri->chash, changelog->map[rev].hash, HASHSZ);
|
||||
|
||||
line = 0;
|
||||
inmsg = 0;
|
||||
p = buf;
|
||||
e = buf + BUFSZ;
|
||||
while((n = read(fd, p, e - p)) > 0){
|
||||
p += n;
|
||||
while((p > buf) && (e = memchr(buf, '\n', p - buf))){
|
||||
*e++ = 0;
|
||||
|
||||
switch(line++){
|
||||
case 0:
|
||||
strhash(buf, ri->mhash);
|
||||
break;
|
||||
case 1:
|
||||
ri->who = strdup(buf);
|
||||
break;
|
||||
case 2:
|
||||
ri->when = strtol(buf, nil, 10);
|
||||
break;
|
||||
default:
|
||||
if(!inmsg){
|
||||
if(*buf == 0)
|
||||
inmsg = 1;
|
||||
} else {
|
||||
n = ri->why ? strlen(ri->why) : 0;
|
||||
ri->why = realloc(ri->why, n + strlen(buf)+1);
|
||||
strcpy(ri->why + n, buf);
|
||||
}
|
||||
}
|
||||
p -= e - buf;
|
||||
if(p > buf)
|
||||
memmove(buf, e, p - buf);
|
||||
}
|
||||
e = buf + BUFSZ;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return ri;
|
||||
}
|
10
sys/src/cmd/hgfs/mkfile
Normal file
10
sys/src/cmd/hgfs/mkfile
Normal file
|
@ -0,0 +1,10 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
TARG=hgfs
|
||||
CFLAGS=-FTVw
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
OFILES=zip.$O patch.$O hash.$O revlog.$O tree.$O info.$O fs.$O
|
||||
|
||||
</sys/src/cmd/mkone
|
159
sys/src/cmd/hgfs/patch.c
Normal file
159
sys/src/cmd/hgfs/patch.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
int
|
||||
fcopy(int dfd, int sfd, vlong len)
|
||||
{
|
||||
uchar buf[BUFSZ];
|
||||
int n;
|
||||
|
||||
while(len > 0){
|
||||
if((n = BUFSZ) > len)
|
||||
n = len;
|
||||
if((n = read(sfd, buf, n)) < 0)
|
||||
return -1;
|
||||
if(write(dfd, buf, n) != n)
|
||||
return -1;
|
||||
len -= n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uchar patchmark[12] = {
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
|
||||
int
|
||||
fpatchmark(int pfd, char *)
|
||||
{
|
||||
if(write(pfd, patchmark, 12) != 12)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct Frag Frag;
|
||||
struct Frag
|
||||
{
|
||||
Frag *next;
|
||||
int fd;
|
||||
vlong len;
|
||||
vlong off;
|
||||
};
|
||||
|
||||
int
|
||||
fpatch(int ofd, int bfd, int pfd)
|
||||
{
|
||||
vlong off, fstart, fend, start, end, len;
|
||||
int err, front, back;
|
||||
Frag *h, *f, *p;
|
||||
uchar buf[12];
|
||||
|
||||
h = nil;
|
||||
err = -1;
|
||||
|
||||
if(bfd >= 0){
|
||||
h = malloc(sizeof(Frag));
|
||||
h->next = nil;
|
||||
h->off = 0;
|
||||
h->fd = bfd;
|
||||
h->len = seek(h->fd, 0, 2);
|
||||
if(h->len < 0)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
off = 0;
|
||||
while(pfd >= 0){
|
||||
if(readn(pfd, buf, 12) != 12)
|
||||
break;
|
||||
|
||||
if(memcmp(buf, patchmark, 12) == 0){
|
||||
off = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
start = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
|
||||
end = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
|
||||
len = buf[8]<<24 | buf[9]<<16 | buf[10]<<8 | buf[11];
|
||||
|
||||
if(start > end){
|
||||
werrstr("bad patch: start > end");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
start += off;
|
||||
end += off;
|
||||
off += start + len - end;
|
||||
|
||||
fstart = 0;
|
||||
for(f = h; f; f = f->next, fstart = fend){
|
||||
fend = fstart + f->len;
|
||||
if(fend <= start)
|
||||
continue;
|
||||
if(fstart >= end)
|
||||
break;
|
||||
|
||||
front = start > fstart;
|
||||
back = end < fend;
|
||||
if(front && back){
|
||||
p = malloc(sizeof(Frag));
|
||||
*p = *f;
|
||||
f->next = p;
|
||||
f->len = start - fstart;
|
||||
p->off += end - fstart;
|
||||
p->len -= end - fstart;
|
||||
break;
|
||||
} else if(back){
|
||||
f->off += end - fstart;
|
||||
f->len -= end - fstart;
|
||||
break;
|
||||
} else if(front){
|
||||
f->len = start - fstart;
|
||||
} else {
|
||||
f->len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fstart = 0;
|
||||
for(p = nil, f = h; f && fstart < start; p = f, f = f->next)
|
||||
fstart += f->len;
|
||||
|
||||
f = malloc(sizeof(Frag));
|
||||
f->fd = pfd;
|
||||
f->len = len;
|
||||
f->off = seek(f->fd, 0, 1);
|
||||
|
||||
if(p){
|
||||
f->next = p->next;
|
||||
p->next = f;
|
||||
} else {
|
||||
f->next = h;
|
||||
h = f;
|
||||
}
|
||||
|
||||
if(f->off < 0)
|
||||
goto errout;
|
||||
if(seek(pfd, f->len, 1) < 0)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
for(f = h; f; f = f->next){
|
||||
if(seek(f->fd, f->off, 0) < 0)
|
||||
goto errout;
|
||||
if(fcopy(ofd, f->fd, f->len) < 0)
|
||||
goto errout;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
errout:
|
||||
while(f = h){
|
||||
h = f->next;
|
||||
free(f);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
272
sys/src/cmd/hgfs/revlog.c
Normal file
272
sys/src/cmd/hgfs/revlog.c
Normal file
|
@ -0,0 +1,272 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
int
|
||||
fmktemp(void)
|
||||
{
|
||||
char temp[MAXPATH];
|
||||
|
||||
snprint(temp, sizeof(temp), "/tmp/hgXXXXXXXXXXX");
|
||||
return create(mktemp(temp), OTRUNC|ORCLOSE|ORDWR, 0666);
|
||||
}
|
||||
|
||||
static void
|
||||
readindex(Revlog *r)
|
||||
{
|
||||
uchar buf[64];
|
||||
Revmap *m;
|
||||
int rev;
|
||||
|
||||
seek(r->ifd, 0, 0);
|
||||
for(rev=0;;rev++){
|
||||
if(readn(r->ifd, buf, sizeof(buf)) != sizeof(buf))
|
||||
break;
|
||||
if((rev % 16) == 0)
|
||||
r->map = realloc(r->map, sizeof(r->map[0])*(rev+16));
|
||||
m = &r->map[rev];
|
||||
memset(m, 0, sizeof(*m));
|
||||
m->hoff = (vlong)buf[0]<<40 |
|
||||
(vlong)buf[1]<<32 |
|
||||
(vlong)buf[2]<<24 |
|
||||
(vlong)buf[3]<<16 |
|
||||
(vlong)buf[4]<<8 |
|
||||
(vlong)buf[5];
|
||||
if(rev == 0)
|
||||
m->hoff &= 0xFFFF;
|
||||
m->rev = rev;
|
||||
m->flags = buf[6]<<8 | buf[7];
|
||||
m->hlen = buf[8]<<24 | buf[9]<<16 | buf[10]<<8 | buf[11];
|
||||
m->flen = buf[12]<<24 | buf[13]<<16 | buf[14]<<8 | buf[15];
|
||||
m->baserev = buf[16]<<24 | buf[17]<<16 | buf[18]<<8 | buf[19];
|
||||
m->linkrev = buf[20]<<24 | buf[21]<<16 | buf[22]<<8 | buf[23];
|
||||
m->p1rev = buf[24]<<24 | buf[25]<<16 | buf[26]<<8 | buf[27];
|
||||
m->p2rev = buf[28]<<24 | buf[29]<<16 | buf[30]<<8 | buf[31];
|
||||
memmove(m->hash, buf+32, HASHSZ);
|
||||
|
||||
if(r->dfd < 0){
|
||||
m->hoff = seek(r->ifd, 0, 1);
|
||||
seek(r->ifd, m->hlen, 1);
|
||||
}
|
||||
}
|
||||
r->nmap = rev;
|
||||
}
|
||||
|
||||
int
|
||||
revlogopen(Revlog *r, char *path, int mode)
|
||||
{
|
||||
r->ifd = -1;
|
||||
r->dfd = -1;
|
||||
path = smprint("%s.i", path);
|
||||
if((r->ifd = open(path, mode)) < 0){
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
path[strlen(path)-1] = 'd';
|
||||
r->dfd = open(path, mode);
|
||||
free(path);
|
||||
r->nmap = 0;
|
||||
r->map = nil;
|
||||
readindex(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
revlogclose(Revlog *r)
|
||||
{
|
||||
if(r->ifd >= 0){
|
||||
close(r->ifd);
|
||||
r->ifd = -1;
|
||||
}
|
||||
if(r->dfd >= 0){
|
||||
close(r->dfd);
|
||||
r->dfd = -1;
|
||||
}
|
||||
free(r->map);
|
||||
r->map = nil;
|
||||
r->nmap = 0;
|
||||
}
|
||||
|
||||
uchar*
|
||||
revhash(Revlog *r, int rev)
|
||||
{
|
||||
static uchar nullid[HASHSZ];
|
||||
if(rev < 0 || rev >= r->nmap)
|
||||
return nullid;
|
||||
return r->map[rev].hash;
|
||||
}
|
||||
|
||||
int
|
||||
hashrev(Revlog *r, uchar hash[])
|
||||
{
|
||||
int rev;
|
||||
|
||||
for(rev=0; rev<r->nmap; rev++)
|
||||
if(memcmp(r->map[rev].hash, hash, HASHSZ) == 0)
|
||||
return rev;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
prevlogrev(Revlog *r, int rev)
|
||||
{
|
||||
if(r->map[rev].baserev == rev)
|
||||
return -1;
|
||||
return rev-1;
|
||||
}
|
||||
|
||||
static int
|
||||
prevbundlerev(Revlog *r, int rev)
|
||||
{
|
||||
if(r->map[rev].baserev == rev)
|
||||
return -1;
|
||||
return r->map[rev].p1rev;
|
||||
}
|
||||
|
||||
static Revmap**
|
||||
getchain1(Revlog *r, int rev, int *count, int (*next)(Revlog *, int))
|
||||
{
|
||||
Revmap **chain;
|
||||
|
||||
if(rev < 0 || rev >= r->nmap){
|
||||
if(*count <= 0)
|
||||
return nil;
|
||||
chain = malloc(sizeof(chain[0]) * ((*count)+1));
|
||||
chain[*count] = nil;
|
||||
*count = 0;
|
||||
}else{
|
||||
(*count)++;
|
||||
if(chain = getchain1(r, (*next)(r, rev), count, next))
|
||||
chain[(*count)++] = &r->map[rev];
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
|
||||
static Revmap**
|
||||
getchain(Revlog *r, int rev, int (*next)(Revlog *, int))
|
||||
{
|
||||
int count = 0;
|
||||
return getchain1(r, rev, &count, next);
|
||||
}
|
||||
|
||||
int
|
||||
revlogextract(Revlog *r, int rev, int ofd)
|
||||
{
|
||||
int err, hfd, pfd, bfd;
|
||||
uchar hash[HASHSZ];
|
||||
Revmap **chain, *m;
|
||||
char buf[32];
|
||||
vlong off;
|
||||
int i;
|
||||
|
||||
err = -1;
|
||||
bfd = -1;
|
||||
pfd = -1;
|
||||
|
||||
if((chain = getchain(r, rev, prevlogrev)) == nil){
|
||||
werrstr("bad patch chain");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
off = seek(ofd, 0, 1);
|
||||
if(off < 0){
|
||||
werrstr("seek outfile: %r");
|
||||
goto errout;
|
||||
}
|
||||
hfd = r->dfd < 0 ? r->ifd : r->dfd;
|
||||
for(i=0; m = chain[i]; i++){
|
||||
if(seek(hfd, m->hoff, 0) < 0){
|
||||
werrstr("seek index: %r");
|
||||
goto errout;
|
||||
}
|
||||
if(m == chain[0] && m->baserev == m->rev){
|
||||
if(chain[1]){
|
||||
if(bfd >= 0 && bfd != ofd)
|
||||
close(bfd);
|
||||
if((bfd = fmktemp()) < 0){
|
||||
werrstr("create basefile: %r");
|
||||
goto errout;
|
||||
}
|
||||
} else
|
||||
bfd = ofd;
|
||||
if(funzip(bfd, hfd, m->hlen) < 0){
|
||||
werrstr("unzip basefile: %r");
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
if(pfd < 0){
|
||||
if((pfd = fmktemp()) < 0){
|
||||
werrstr("create patchfile: %r");
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
/* put a mark before the patch data */
|
||||
snprint(buf, sizeof(buf), "%H", m->hash);
|
||||
if(fpatchmark(pfd, buf) < 0){
|
||||
werrstr("patchmark: %r");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(funzip(pfd, hfd, m->hlen) < 0){
|
||||
werrstr("unzip patchfile: %r");
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
}
|
||||
m = chain[i-1];
|
||||
|
||||
if(pfd >= 0 && bfd >= 0 && bfd != ofd){
|
||||
if(seek(pfd, 0, 0) < 0){
|
||||
werrstr("seek patchfile: %r");
|
||||
goto errout;
|
||||
}
|
||||
if(fpatch(ofd, bfd, pfd) < 0){
|
||||
werrstr("patch: %r");
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if(seek(ofd, off, 0) < 0){
|
||||
werrstr("seek outfile: %r");
|
||||
goto errout;
|
||||
}
|
||||
if(fhash(ofd, revhash(r, m->p1rev), revhash(r, m->p2rev), hash) < 0){
|
||||
werrstr("hash outfile: %r");
|
||||
goto errout;
|
||||
}
|
||||
if(memcmp(m->hash, hash, HASHSZ)){
|
||||
werrstr("got bad hash");
|
||||
goto errout;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
errout:
|
||||
if(pfd >= 0)
|
||||
close(pfd);
|
||||
if(bfd >= 0 && bfd != ofd)
|
||||
close(bfd);
|
||||
free(chain);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
revlogopentemp(Revlog *r, int rev)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if((fd = fmktemp()) < 0)
|
||||
return -1;
|
||||
if(revlogextract(r, rev, fd) < 0){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if(seek(fd, 0, 0) < 0){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
267
sys/src/cmd/hgfs/tree.c
Normal file
267
sys/src/cmd/hgfs/tree.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
char*
|
||||
nodepath(char *s, char *e, Revnode *nd)
|
||||
{
|
||||
static char *frogs[] = {
|
||||
"con", "prn", "aux", "nul",
|
||||
"com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
|
||||
"lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
|
||||
};
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
if(nd == nil || nd->name == nil)
|
||||
return s;
|
||||
|
||||
s = seprint(nodepath(s, e, nd->up), e, "/");
|
||||
|
||||
p = nd->name;
|
||||
for(i=0; i<nelem(frogs); i++)
|
||||
if(strcmp(frogs[i], p) == 0)
|
||||
return seprint(s, e, "%.2s~%.2x%s", p, p[2], p+3);
|
||||
|
||||
for(; s+4 < e && *p; p++){
|
||||
if(*p == '_'){
|
||||
*s++ = '_';
|
||||
*s++ = '_';
|
||||
} else if(*p >= 'A' && *p <= 'Z'){
|
||||
*s++ = '_';
|
||||
*s++ = 'a' + (*p - 'A');
|
||||
} else if(*p >= 126 || strchr("\\:*?\"<>|", *p)){
|
||||
*s++ = '~';
|
||||
s = seprint(s, e, "%.2x", *p);
|
||||
} else
|
||||
*s++ = *p;
|
||||
}
|
||||
*s = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
addnode(Revnode *d, char *path, uchar *hash)
|
||||
{
|
||||
char *slash, *x;
|
||||
Revnode *c, *p;
|
||||
|
||||
while(path && *path){
|
||||
if(slash = strchr(path, '/'))
|
||||
*slash++ = 0;
|
||||
p = nil;
|
||||
for(c = d->down; c; p = c, c = c->next)
|
||||
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){
|
||||
memmove(c->hash = (uchar*)x, hash, HASHSZ);
|
||||
x += HASHSZ;
|
||||
} else
|
||||
c->hash = nil;
|
||||
strcpy(c->name = x, path);
|
||||
c->up = d;
|
||||
c->down = nil;
|
||||
if(p){
|
||||
c->next = p->next;
|
||||
p->next = c;
|
||||
} else {
|
||||
c->next = d->down;
|
||||
d->down = c;
|
||||
}
|
||||
|
||||
if(c->hash){
|
||||
p = c;
|
||||
p->path = *((uvlong*)c->hash);
|
||||
while(d->up){
|
||||
d->path += p->path;
|
||||
p = d;
|
||||
d = d->up;
|
||||
}
|
||||
}
|
||||
}
|
||||
d = c;
|
||||
path = slash;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct Hashstr Hashstr;
|
||||
struct Hashstr
|
||||
{
|
||||
Hashstr *next;
|
||||
char str[];
|
||||
};
|
||||
|
||||
static ulong
|
||||
hashstr(char *s)
|
||||
{
|
||||
ulong h, t;
|
||||
char c;
|
||||
|
||||
h = 0;
|
||||
while(c = *s++){
|
||||
t = h & 0xf8000000;
|
||||
h <<= 5;
|
||||
h ^= t>>27;
|
||||
h ^= (ulong)c;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static int
|
||||
loadmanifest(Revnode *root, int fd, Hashstr **ht, int nh)
|
||||
{
|
||||
char buf[BUFSZ], *p, *e;
|
||||
uchar hash[HASHSZ];
|
||||
int n;
|
||||
|
||||
p = buf;
|
||||
e = buf + BUFSZ;
|
||||
while((n = read(fd, p, e - p)) > 0){
|
||||
p += n;
|
||||
while((p > buf) && (e = memchr(buf, '\n', p - buf))){
|
||||
*e++ = 0;
|
||||
|
||||
strhash(buf + strlen(buf) + 1, hash);
|
||||
if(ht == nil)
|
||||
addnode(root, buf, hash);
|
||||
else {
|
||||
Hashstr *he;
|
||||
|
||||
for(he = ht[hashstr(buf) % nh]; he; he = he->next){
|
||||
if(strcmp(he->str, buf) == 0){
|
||||
addnode(root, buf, hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p -= e - buf;
|
||||
if(p > buf)
|
||||
memmove(buf, e, p - buf);
|
||||
}
|
||||
e = buf + BUFSZ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Revtree*
|
||||
loadtree(Revlog *manifest, Revinfo *ri, Hashstr **ht, int nh)
|
||||
{
|
||||
Revtree *t;
|
||||
int fd;
|
||||
|
||||
if((fd = revlogopentemp(manifest, hashrev(manifest, ri->mhash))) < 0)
|
||||
return nil;
|
||||
|
||||
t = malloc(sizeof(*t));
|
||||
memset(t, 0, sizeof(*t));
|
||||
incref(t);
|
||||
|
||||
t->info = ri;
|
||||
|
||||
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;
|
||||
|
||||
if(loadmanifest(t->root, fd, ht, nh) < 0){
|
||||
close(fd);
|
||||
closerevtree(t);
|
||||
return nil;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Revtree*
|
||||
loadfilestree(Revlog *, Revlog *manifest, Revinfo *ri)
|
||||
{
|
||||
return loadtree(manifest, ri, nil, 0);
|
||||
}
|
||||
|
||||
Revtree*
|
||||
loadchangestree(Revlog *changelog, Revlog *manifest, Revinfo *ri)
|
||||
{
|
||||
char buf[BUFSZ], *p, *e;
|
||||
Hashstr *ht[256], *he, **hp;
|
||||
int fd, done, line, n;
|
||||
Revtree *t;
|
||||
|
||||
if((fd = revlogopentemp(changelog, hashrev(changelog, ri->chash))) < 0)
|
||||
return nil;
|
||||
|
||||
done = 0;
|
||||
line = 0;
|
||||
memset(ht, 0, sizeof(ht));
|
||||
|
||||
p = buf;
|
||||
e = buf + BUFSZ;
|
||||
while((n = read(fd, p, e - p)) > 0){
|
||||
p += n;
|
||||
while((p > buf) && (e = memchr(buf, '\n', p - buf))){
|
||||
*e++ = 0;
|
||||
|
||||
if(++line >= 4){
|
||||
if(*buf == 0){
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
he = malloc(sizeof(*he) + strlen(buf)+1);
|
||||
hp = &ht[hashstr(strcpy(he->str, buf)) % nelem(ht)];
|
||||
he->next = *hp;
|
||||
*hp = he;
|
||||
}
|
||||
|
||||
p -= e - buf;
|
||||
if(p > buf)
|
||||
memmove(buf, e, p - buf);
|
||||
}
|
||||
if(done)
|
||||
break;
|
||||
e = buf + BUFSZ;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
t = loadtree(manifest, ri, ht, nelem(ht));
|
||||
|
||||
for(hp = ht; hp != &ht[nelem(ht)]; hp++){
|
||||
while(he = *hp){
|
||||
*hp = he->next;
|
||||
free(he);
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void
|
||||
freenode(Revnode *nd)
|
||||
{
|
||||
if(nd == nil)
|
||||
return;
|
||||
freenode(nd->down);
|
||||
freenode(nd->next);
|
||||
free(nd);
|
||||
}
|
||||
|
||||
void
|
||||
closerevtree(Revtree *t)
|
||||
{
|
||||
if(t == nil || decref(t))
|
||||
return;
|
||||
freenode(t->root);
|
||||
free(t);
|
||||
}
|
97
sys/src/cmd/hgfs/zip.c
Normal file
97
sys/src/cmd/hgfs/zip.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
#include <flate.h>
|
||||
|
||||
struct zbuf {
|
||||
int fd;
|
||||
int len;
|
||||
|
||||
uchar *b, *p, *e;
|
||||
};
|
||||
|
||||
static int
|
||||
zwrite(void *a, void *p, int n)
|
||||
{
|
||||
int *ofd = a;
|
||||
|
||||
if(write(*ofd, p, n) != n)
|
||||
return -1;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
zgetc(void *a)
|
||||
{
|
||||
struct zbuf *z = a;
|
||||
int n;
|
||||
|
||||
for(;;){
|
||||
if(z->p < z->e)
|
||||
return *z->p++;
|
||||
if(z->len <= 0)
|
||||
return -1;
|
||||
if((n = BUFSZ) > z->len)
|
||||
n = z->len;
|
||||
if((n = read(z->fd, z->p = z->b, n)) <= 0)
|
||||
return -1;
|
||||
z->len -= n;
|
||||
z->e = z->p + n;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
funzip(int ofd, int zfd, int len)
|
||||
{
|
||||
uchar buf[BUFSZ];
|
||||
struct zbuf z;
|
||||
int wlen, n;
|
||||
uchar *p;
|
||||
|
||||
if(len == 0)
|
||||
return 0;
|
||||
|
||||
wlen = 0;
|
||||
if((n = BUFSZ) > len)
|
||||
n = len;
|
||||
if((n = read(zfd, p = buf, n)) <= 0)
|
||||
return -1;
|
||||
len -= n;
|
||||
switch(*p){
|
||||
default:
|
||||
return -1;
|
||||
case 'u':
|
||||
p++;
|
||||
n--;
|
||||
/* no break */
|
||||
case '\0':
|
||||
while((n > 0) && (write(ofd, p, n) == n)){
|
||||
wlen += n;
|
||||
if(len <= 0)
|
||||
break;
|
||||
if((n = BUFSZ) > len)
|
||||
n = len;
|
||||
if((n = read(zfd, p = buf, n)) <= 0)
|
||||
break;
|
||||
len -= n;
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
if(n < 2)
|
||||
return -1;
|
||||
z.fd = zfd;
|
||||
z.len = len;
|
||||
z.b = buf;
|
||||
z.p = p + 2;
|
||||
z.e = p + n;
|
||||
if((wlen = inflate(&ofd, zwrite, &z, zgetc)) < 0){
|
||||
werrstr("%s", flateerr(wlen));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return wlen;
|
||||
}
|
Loading…
Reference in a new issue