243 lines
3.8 KiB
C
243 lines
3.8 KiB
C
/*
|
|
* archfs - mount mkfs style archives
|
|
*/
|
|
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <auth.h>
|
|
#include <fcall.h>
|
|
#include <thread.h>
|
|
#include <9p.h>
|
|
|
|
Tree *archtree;
|
|
Biobuf *b;
|
|
int verbose;
|
|
|
|
typedef struct Ahdr Ahdr;
|
|
struct Ahdr {
|
|
char *name;
|
|
Dir;
|
|
};
|
|
|
|
typedef struct Arch Arch;
|
|
struct Arch {
|
|
vlong off;
|
|
vlong length;
|
|
};
|
|
|
|
static void*
|
|
emalloc(long sz)
|
|
{
|
|
void *v;
|
|
|
|
v = malloc(sz);
|
|
if(v == nil)
|
|
sysfatal("malloc %lud fails", sz);
|
|
memset(v, 0, sz);
|
|
return v;
|
|
}
|
|
|
|
static char*
|
|
estrdup(char *s)
|
|
{
|
|
s = strdup(s);
|
|
if(s == nil)
|
|
sysfatal("strdup (%.10s) fails", s);
|
|
return s;
|
|
}
|
|
|
|
static char*
|
|
Bgetline(Biobuf *b)
|
|
{
|
|
char *p;
|
|
|
|
if(p = Brdline(b, '\n'))
|
|
p[Blinelen(b)-1] = '\0';
|
|
return p;
|
|
}
|
|
|
|
Ahdr*
|
|
gethdr(Biobuf *b)
|
|
{
|
|
Ahdr *a;
|
|
char *p, *f[10];
|
|
|
|
if((p = Bgetline(b)) == nil)
|
|
return nil;
|
|
|
|
if(strcmp(p, "end of archive") == 0) {
|
|
werrstr("");
|
|
return nil;
|
|
}
|
|
|
|
if(tokenize(p, f, nelem(f)) != 6) {
|
|
werrstr("bad format");
|
|
return nil;
|
|
}
|
|
|
|
a = emalloc(sizeof(*a));
|
|
a->name = estrdup(f[0]);
|
|
a->mode = strtoul(f[1], 0, 8);
|
|
a->uid = estrdup(f[2]);
|
|
a->gid = estrdup(f[3]);
|
|
a->mtime = strtoll(f[4], 0, 10);
|
|
a->length = strtoll(f[5], 0, 10);
|
|
return a;
|
|
}
|
|
|
|
static Arch*
|
|
newarch(vlong off, vlong length)
|
|
{
|
|
static Arch *abuf;
|
|
static int nabuf;
|
|
|
|
if(nabuf == 0) {
|
|
nabuf = 256;
|
|
abuf = emalloc(sizeof(Arch)*nabuf);
|
|
}
|
|
|
|
nabuf--;
|
|
abuf->off = off;
|
|
abuf->length = length;
|
|
return abuf++;
|
|
}
|
|
|
|
static File*
|
|
createpath(File *f, char *name, char *u, ulong m)
|
|
{
|
|
char *p;
|
|
File *nf;
|
|
|
|
if(verbose)
|
|
fprint(2, "createpath %s\n", name);
|
|
incref(f);
|
|
while(f && (p = strchr(name, '/'))) {
|
|
*p = '\0';
|
|
if(strcmp(name, "") != 0 && strcmp(name, ".") != 0){
|
|
/* this would be a race if we were multithreaded */
|
|
incref(f); /* so walk doesn't kill it immediately on failure */
|
|
if((nf = walkfile(f, name)) == nil)
|
|
nf = createfile(f, name, u, DMDIR|0777, nil);
|
|
decref(f);
|
|
f = nf;
|
|
}
|
|
*p = '/';
|
|
name = p+1;
|
|
}
|
|
if(f == nil)
|
|
return nil;
|
|
|
|
incref(f);
|
|
if((nf = walkfile(f, name)) == nil)
|
|
nf = createfile(f, name, u, m, nil);
|
|
decref(f);
|
|
return nf;
|
|
}
|
|
|
|
static void
|
|
archcreatefile(char *name, Arch *arch, Dir *d)
|
|
{
|
|
File *f;
|
|
f = createpath(archtree->root, name, d->uid, d->mode);
|
|
if(f == nil)
|
|
sysfatal("creating %s: %r", name);
|
|
free(f->gid);
|
|
f->gid = estrdup9p(d->gid);
|
|
f->aux = arch;
|
|
f->mtime = d->mtime;
|
|
f->length = d->length;
|
|
decref(f);
|
|
}
|
|
|
|
static void
|
|
fsread(Req *r)
|
|
{
|
|
Arch *a;
|
|
char err[ERRMAX];
|
|
int n;
|
|
|
|
a = r->fid->file->aux;
|
|
if(a->length <= r->ifcall.offset)
|
|
r->ifcall.count = 0;
|
|
else if(a->length <= r->ifcall.offset+r->ifcall.count)
|
|
r->ifcall.count = a->length - r->ifcall.offset;
|
|
|
|
werrstr("unknown error");
|
|
if(Bseek(b, a->off+r->ifcall.offset, 0) < 0
|
|
|| (n = Bread(b, r->ofcall.data, r->ifcall.count)) < 0) {
|
|
err[0] = '\0';
|
|
errstr(err, sizeof err);
|
|
respond(r, err);
|
|
} else {
|
|
r->ofcall.count = n;
|
|
respond(r, nil);
|
|
}
|
|
}
|
|
|
|
Srv fs = {
|
|
.read= fsread,
|
|
};
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
fprint(2, "usage: archfs [-abcC] [-m mtpt] archfile\n");
|
|
exits("usage");
|
|
}
|
|
|
|
void
|
|
main(int argc, char **argv)
|
|
{
|
|
Ahdr *a;
|
|
ulong flag;
|
|
char *mtpt;
|
|
char err[ERRMAX];
|
|
|
|
flag = 0;
|
|
mtpt = "/mnt/arch";
|
|
ARGBEGIN{
|
|
case 'D':
|
|
chatty9p++;
|
|
break;
|
|
case 'a':
|
|
flag |= MAFTER;
|
|
break;
|
|
case 'b':
|
|
flag |= MBEFORE;
|
|
break;
|
|
case 'c':
|
|
flag |= MCREATE;
|
|
break;
|
|
case 'C':
|
|
flag |= MCACHE;
|
|
break;
|
|
case 'm':
|
|
mtpt = EARGF(usage());
|
|
break;
|
|
default:
|
|
usage();
|
|
break;
|
|
}ARGEND;
|
|
|
|
if(argc != 1)
|
|
usage();
|
|
|
|
if((b = Bopen(argv[0], OREAD)) == nil)
|
|
sysfatal("open '%s': %r", argv[0]);
|
|
|
|
archtree = fs.tree = alloctree("sys", "sys", DMDIR|0775, nil);
|
|
while(a = gethdr(b)) {
|
|
archcreatefile(a->name, newarch(Boffset(b), a->length), a);
|
|
Bseek(b, a->length, 1);
|
|
}
|
|
|
|
err[0] = '\0';
|
|
errstr(err, sizeof err);
|
|
if(err[0])
|
|
sysfatal("reading archive: %s", err);
|
|
|
|
postmountsrv(&fs, nil, mtpt, flag);
|
|
exits(0);
|
|
}
|