From 004aa293f360ea0f63ec50f5042f8c0fb2831e4f Mon Sep 17 00:00:00 2001 From: rsc Date: Wed, 13 Jul 2005 03:49:41 +0000 Subject: Dump-like file system backup for Unix, built on Venti. --- src/cmd/vbackup/config.c | 515 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 515 insertions(+) create mode 100644 src/cmd/vbackup/config.c (limited to 'src/cmd/vbackup/config.c') diff --git a/src/cmd/vbackup/config.c b/src/cmd/vbackup/config.c new file mode 100644 index 00000000..0efeeee9 --- /dev/null +++ b/src/cmd/vbackup/config.c @@ -0,0 +1,515 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef stime +#define stime configstime /* sometimes in */ +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; ihash); 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; +} -- cgit v1.2.3