aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vbackup/config.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-07-13 03:49:41 +0000
committerrsc <devnull@localhost>2005-07-13 03:49:41 +0000
commit004aa293f360ea0f63ec50f5042f8c0fb2831e4f (patch)
treed44b801b47c82861d68d4045acf0bf7129ce6009 /src/cmd/vbackup/config.c
parent0c98da8bf8ea51d0288222f6c6ba3c125cf20f46 (diff)
downloadplan9port-004aa293f360ea0f63ec50f5042f8c0fb2831e4f.tar.gz
plan9port-004aa293f360ea0f63ec50f5042f8c0fb2831e4f.tar.bz2
plan9port-004aa293f360ea0f63ec50f5042f8c0fb2831e4f.zip
Dump-like file system backup for Unix, built on Venti.
Diffstat (limited to 'src/cmd/vbackup/config.c')
-rw-r--r--src/cmd/vbackup/config.c515
1 files changed, 515 insertions, 0 deletions
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 <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;
+}