Dump-like file system backup for Unix, built on Venti.
This commit is contained in:
parent
0c98da8bf8
commit
004aa293f3
27 changed files with 4437 additions and 0 deletions
515
src/cmd/vbackup/config.c
Normal file
515
src/cmd/vbackup/config.c
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <thread.h>
|
||||
#include <sunrpc.h>
|
||||
#include <nfs3.h>
|
||||
#include <diskfs.h>
|
||||
#include <venti.h>
|
||||
#include <libsec.h>
|
||||
|
||||
#undef stime
|
||||
#define stime configstime /* sometimes in <time.h> */
|
||||
typedef struct Entry Entry;
|
||||
struct Entry
|
||||
{
|
||||
Entry *parent;
|
||||
Entry *nextdir;
|
||||
Entry *nexthash;
|
||||
Entry *kids;
|
||||
int isfsys;
|
||||
Fsys *fsys;
|
||||
uchar score[VtScoreSize]; /* of fsys */
|
||||
char *name;
|
||||
uchar sha1[VtScoreSize]; /* of path to this entry */
|
||||
ulong time;
|
||||
};
|
||||
|
||||
typedef struct Config Config;
|
||||
struct Config
|
||||
{
|
||||
VtCache *vcache;
|
||||
Entry *root;
|
||||
Entry *hash[1024];
|
||||
Qid qid;
|
||||
};
|
||||
|
||||
Config *config;
|
||||
static ulong mtime; /* mod time */
|
||||
static ulong stime; /* sync time */
|
||||
static char* configfile;
|
||||
|
||||
static int addpath(Config*, char*, uchar[VtScoreSize], ulong);
|
||||
Fsys fsysconfig;
|
||||
|
||||
static void
|
||||
freeconfig(Config *c)
|
||||
{
|
||||
Entry *next, *e;
|
||||
int i;
|
||||
|
||||
for(i=0; i<nelem(c->hash); i++){
|
||||
for(e=c->hash[i]; e; e=next){
|
||||
next = e->nexthash;
|
||||
free(e);
|
||||
}
|
||||
}
|
||||
free(c);
|
||||
}
|
||||
|
||||
static int
|
||||
namehash(uchar *s)
|
||||
{
|
||||
return (s[0]<<2)|(s[1]>>6);
|
||||
}
|
||||
|
||||
static Entry*
|
||||
entrybyhandle(Nfs3Handle *h)
|
||||
{
|
||||
int hh;
|
||||
Entry *e;
|
||||
|
||||
hh = namehash(h->h);
|
||||
for(e=config->hash[hh]; e; e=e->nexthash)
|
||||
if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
|
||||
return e;
|
||||
return nil;
|
||||
}
|
||||
|
||||
static Config*
|
||||
readconfigfile(char *name, VtCache *vcache)
|
||||
{
|
||||
char *p, *pref, *f[10];
|
||||
int ok;
|
||||
Config *c;
|
||||
uchar score[VtScoreSize];
|
||||
int h, nf, line;
|
||||
Biobuf *b;
|
||||
Dir *dir;
|
||||
|
||||
configfile = vtstrdup(name);
|
||||
|
||||
if((dir = dirstat(name)) == nil)
|
||||
return nil;
|
||||
|
||||
if((b = Bopen(name, OREAD)) == nil){
|
||||
free(dir);
|
||||
return nil;
|
||||
}
|
||||
|
||||
line = 0;
|
||||
ok = 1;
|
||||
c = emalloc(sizeof(Config));
|
||||
c->vcache = vcache;
|
||||
c->qid = dir->qid;
|
||||
free(dir);
|
||||
c->root = emalloc(sizeof(Entry));
|
||||
c->root->name = "/";
|
||||
c->root->parent = c->root;
|
||||
sha1((uchar*)"/", 1, c->root->sha1, nil);
|
||||
h = namehash(c->root->sha1);
|
||||
c->hash[h] = c->root;
|
||||
|
||||
for(; (p = Brdstr(b, '\n', 1)) != nil; free(p)){
|
||||
line++;
|
||||
if(p[0] == '#')
|
||||
continue;
|
||||
nf = tokenize(p, f, nelem(f));
|
||||
if(nf != 3){
|
||||
fprint(2, "%s:%d: syntax error\n", name, line);
|
||||
// ok = 0;
|
||||
continue;
|
||||
}
|
||||
if(vtparsescore(f[1], &pref, score) < 0){
|
||||
fprint(2, "%s:%d: bad score '%s'\n", name, line, f[1]);
|
||||
// ok = 0;
|
||||
continue;
|
||||
}
|
||||
if(f[0][0] != '/'){
|
||||
fprint(2, "%s:%d: unrooted path '%s'\n", name, line, f[0]);
|
||||
// ok = 0;
|
||||
continue;
|
||||
}
|
||||
if(addpath(c, f[0], score, strtoul(f[2], 0, 0)) < 0){
|
||||
fprint(2, "%s:%d: %s: %r\n", name, line, f[0]);
|
||||
// ok = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Bterm(b);
|
||||
|
||||
if(!ok){
|
||||
freeconfig(c);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
refreshconfig(void)
|
||||
{
|
||||
ulong now;
|
||||
Config *c, *old;
|
||||
Dir *d;
|
||||
|
||||
now = time(0);
|
||||
if(now - stime < 60)
|
||||
return;
|
||||
if((d = dirstat(configfile)) == nil)
|
||||
return;
|
||||
if(d->mtime == mtime){
|
||||
free(d);
|
||||
stime = now;
|
||||
return;
|
||||
}
|
||||
|
||||
c = readconfigfile(configfile, config->vcache);
|
||||
if(c == nil){
|
||||
free(d);
|
||||
return;
|
||||
}
|
||||
|
||||
old = config;
|
||||
config = c;
|
||||
stime = now;
|
||||
mtime = d->mtime;
|
||||
free(d);
|
||||
freeconfig(old);
|
||||
}
|
||||
|
||||
static Entry*
|
||||
entrylookup(Entry *e, char *p, int np)
|
||||
{
|
||||
for(e=e->kids; e; e=e->nextdir)
|
||||
if(strlen(e->name) == np && memcmp(e->name, p, np) == 0)
|
||||
return e;
|
||||
return nil;
|
||||
}
|
||||
|
||||
static Entry*
|
||||
walkpath(Config *c, char *name)
|
||||
{
|
||||
Entry *e, *ee;
|
||||
char *p, *nextp;
|
||||
int h;
|
||||
|
||||
e = c->root;
|
||||
p = name;
|
||||
for(; *p; p=nextp){
|
||||
assert(*p == '/');
|
||||
p++;
|
||||
nextp = strchr(p, '/');
|
||||
if(nextp == nil)
|
||||
nextp = p+strlen(p);
|
||||
if(e->fsys){
|
||||
werrstr("%.*s is already a mount point", utfnlen(name, nextp-name), name);
|
||||
return nil;
|
||||
}
|
||||
if((ee = entrylookup(e, p, nextp-p)) == nil){
|
||||
ee = emalloc(sizeof(Entry)+(nextp-p)+1);
|
||||
ee->parent = e;
|
||||
ee->nextdir = e->kids;
|
||||
e->kids = ee;
|
||||
ee->name = (char*)&ee[1];
|
||||
memmove(ee->name, p, nextp-p);
|
||||
ee->name[nextp-p] = 0;
|
||||
sha1((uchar*)name, nextp-name, ee->sha1, nil);
|
||||
h = namehash(ee->sha1);
|
||||
ee->nexthash = c->hash[h];
|
||||
c->hash[h] = ee;
|
||||
}
|
||||
e = ee;
|
||||
}
|
||||
if(e->kids){
|
||||
werrstr("%s already has children; cannot be mount point", name);
|
||||
return nil;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static int
|
||||
addpath(Config *c, char *name, uchar score[VtScoreSize], ulong time)
|
||||
{
|
||||
Entry *e;
|
||||
|
||||
e = walkpath(c, name);
|
||||
if(e == nil)
|
||||
return -1;
|
||||
e->isfsys = 1;
|
||||
e->time = time;
|
||||
memmove(e->score, score, VtScoreSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mkhandle(Nfs3Handle *h, Entry *e)
|
||||
{
|
||||
memmove(h->h, e->sha1, VtScoreSize);
|
||||
h->len = VtScoreSize;
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
handleparse(Nfs3Handle *h, Fsys **pfsys, Nfs3Handle *nh, int isgetattr)
|
||||
{
|
||||
int hh;
|
||||
Entry *e;
|
||||
Disk *disk;
|
||||
Fsys *fsys;
|
||||
|
||||
refreshconfig();
|
||||
|
||||
if(h->len < VtScoreSize)
|
||||
return Nfs3ErrBadHandle;
|
||||
|
||||
hh = namehash(h->h);
|
||||
for(e=config->hash[hh]; e; e=e->nexthash)
|
||||
if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
|
||||
break;
|
||||
if(e == nil)
|
||||
return Nfs3ErrBadHandle;
|
||||
|
||||
if(e->isfsys == 1 && e->fsys == nil && (h->len != VtScoreSize || !isgetattr)){
|
||||
if((disk = diskopenventi(config->vcache, e->score)) == nil){
|
||||
fprint(2, "cannot open disk %V: %r\n", e->score);
|
||||
return Nfs3ErrIo;
|
||||
}
|
||||
if((fsys = fsysopen(disk)) == nil){
|
||||
fprint(2, "cannot open fsys on %V: %r\n", e->score);
|
||||
diskclose(disk);
|
||||
return Nfs3ErrIo;
|
||||
}
|
||||
e->fsys = fsys;
|
||||
}
|
||||
|
||||
if(e->fsys == nil || (isgetattr && h->len == VtScoreSize)){
|
||||
if(h->len != VtScoreSize)
|
||||
return Nfs3ErrBadHandle;
|
||||
*pfsys = &fsysconfig;
|
||||
*nh = *h;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
*pfsys = e->fsys;
|
||||
if(h->len == VtScoreSize)
|
||||
return fsysroot(*pfsys, nh);
|
||||
nh->len = h->len - VtScoreSize;
|
||||
memmove(nh->h, h->h+VtScoreSize, nh->len);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
void
|
||||
handleunparse(Fsys *fsys, Nfs3Handle *h, Nfs3Handle *nh, int dotdot)
|
||||
{
|
||||
Entry *e;
|
||||
int hh;
|
||||
|
||||
refreshconfig();
|
||||
|
||||
if(fsys == &fsysconfig)
|
||||
return;
|
||||
|
||||
if(dotdot && nh->len == h->len - VtScoreSize
|
||||
&& memcmp(h->h+VtScoreSize, nh->h, nh->len) == 0){
|
||||
/* walked .. but didn't go anywhere: must be at root */
|
||||
hh = namehash(h->h);
|
||||
for(e=config->hash[hh]; e; e=e->nexthash)
|
||||
if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
|
||||
break;
|
||||
if(e == nil)
|
||||
return; /* cannot happen */
|
||||
|
||||
/* walk .. */
|
||||
e = e->parent;
|
||||
nh->len = VtScoreSize;
|
||||
memmove(nh->h, e->sha1, VtScoreSize);
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise just insert the same prefix */
|
||||
memmove(nh->h+VtScoreSize, nh->h, VtScoreSize);
|
||||
nh->len += VtScoreSize;
|
||||
memmove(nh->h, h->h, VtScoreSize);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysconfigroot(Fsys *fsys, Nfs3Handle *h)
|
||||
{
|
||||
USED(fsys);
|
||||
|
||||
mkhandle(h, config->root);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysconfiggetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
|
||||
{
|
||||
Entry *e;
|
||||
|
||||
USED(fsys);
|
||||
USED(au);
|
||||
|
||||
if(h->len != VtScoreSize)
|
||||
return Nfs3ErrBadHandle;
|
||||
|
||||
e = entrybyhandle(h);
|
||||
if(e == nil)
|
||||
return Nfs3ErrNoEnt;
|
||||
|
||||
memset(attr, 0, sizeof *attr);
|
||||
attr->type = Nfs3FileDir;
|
||||
attr->mode = 0555;
|
||||
attr->nlink = 2;
|
||||
attr->size = 1024;
|
||||
attr->fileid = *(u64int*)h->h;
|
||||
attr->atime.sec = e->time;
|
||||
attr->mtime.sec = e->time;
|
||||
attr->ctime.sec = e->time;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysconfigaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
|
||||
{
|
||||
want &= Nfs3AccessRead|Nfs3AccessLookup|Nfs3AccessExecute;
|
||||
*got = want;
|
||||
return fsysconfiggetattr(fsys, au, h, attr);
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysconfiglookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
|
||||
{
|
||||
Entry *e;
|
||||
|
||||
USED(fsys);
|
||||
USED(au);
|
||||
|
||||
if(h->len != VtScoreSize)
|
||||
return Nfs3ErrBadHandle;
|
||||
|
||||
e = entrybyhandle(h);
|
||||
if(e == nil)
|
||||
return Nfs3ErrNoEnt;
|
||||
|
||||
if(strcmp(name, "..") == 0)
|
||||
e = e->parent;
|
||||
else if(strcmp(name, ".") == 0){
|
||||
/* nothing */
|
||||
}else{
|
||||
if((e = entrylookup(e, name, strlen(name))) == nil)
|
||||
return Nfs3ErrNoEnt;
|
||||
}
|
||||
|
||||
mkhandle(nh, e);
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysconfigreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
|
||||
{
|
||||
USED(h);
|
||||
USED(fsys);
|
||||
USED(au);
|
||||
|
||||
*link = 0;
|
||||
return Nfs3ErrNotSupp;
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysconfigreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
|
||||
{
|
||||
USED(fsys);
|
||||
USED(h);
|
||||
USED(count);
|
||||
USED(offset);
|
||||
USED(pdata);
|
||||
USED(pcount);
|
||||
USED(peof);
|
||||
USED(au);
|
||||
|
||||
return Nfs3ErrNotSupp;
|
||||
}
|
||||
|
||||
Nfs3Status
|
||||
fsysconfigreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
|
||||
{
|
||||
uchar *data, *p, *ep, *np;
|
||||
u64int c;
|
||||
Entry *e;
|
||||
Nfs3Entry ne;
|
||||
|
||||
USED(fsys);
|
||||
USED(au);
|
||||
|
||||
if(h->len != VtScoreSize)
|
||||
return Nfs3ErrBadHandle;
|
||||
|
||||
e = entrybyhandle(h);
|
||||
if(e == nil)
|
||||
return Nfs3ErrNoEnt;
|
||||
|
||||
e = e->kids;
|
||||
c = cookie;
|
||||
for(; c && e; c--)
|
||||
e = e->nextdir;
|
||||
if(e == nil){
|
||||
*pdata = 0;
|
||||
*pcount = 0;
|
||||
*peof = 1;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
data = emalloc(count);
|
||||
p = data;
|
||||
ep = data+count;
|
||||
while(e && p < ep){
|
||||
ne.name = e->name;
|
||||
ne.cookie = ++cookie;
|
||||
ne.fileid = *(u64int*)e->sha1;
|
||||
if(nfs3entrypack(p, ep, &np, &ne) < 0)
|
||||
break;
|
||||
p = np;
|
||||
e = e->nextdir;
|
||||
}
|
||||
*pdata = data;
|
||||
*pcount = p - data;
|
||||
*peof = 0;
|
||||
return Nfs3Ok;
|
||||
}
|
||||
|
||||
void
|
||||
fsysconfigclose(Fsys *fsys)
|
||||
{
|
||||
USED(fsys);
|
||||
}
|
||||
|
||||
int
|
||||
readconfig(char *name, VtCache *vcache, Nfs3Handle *h)
|
||||
{
|
||||
Config *c;
|
||||
Dir *d;
|
||||
|
||||
if((d = dirstat(name)) == nil)
|
||||
return -1;
|
||||
|
||||
c = readconfigfile(name, vcache);
|
||||
if(c == nil){
|
||||
free(d);
|
||||
return -1;
|
||||
}
|
||||
|
||||
config = c;
|
||||
mtime = d->mtime;
|
||||
stime = time(0);
|
||||
free(d);
|
||||
|
||||
mkhandle(h, c->root);
|
||||
fsysconfig._lookup = fsysconfiglookup;
|
||||
fsysconfig._access = fsysconfigaccess;
|
||||
fsysconfig._getattr = fsysconfiggetattr;
|
||||
fsysconfig._readdir = fsysconfigreaddir;
|
||||
fsysconfig._readfile = fsysconfigreadfile;
|
||||
fsysconfig._readlink = fsysconfigreadlink;
|
||||
fsysconfig._root = fsysconfigroot;
|
||||
fsysconfig._close = fsysconfigclose;
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue