Use a state file to store repository settings - dedup - deduplicating backup program
 (HTM) git clone git://bitreich.org/dedup/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/dedup/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 6b21cc335d619eb1bdf2ea285087e98e4c78d7e4
 (DIR) parent 8ef5e9d6666a818d610e1e1b1ffefa552f2c76f6
 (HTM) Author: sin <sin@2f30.org>
       Date:   Sun, 12 May 2019 10:03:14 +0100
       
       Use a state file to store repository settings
       
       Diffstat:
         M bcompress.c                         |      32 +++++++++++++++++--------------
         M bencrypt.c                          |      37 ++++++++++++++++---------------
         M block.c                             |      25 +++++--------------------
         M block.h                             |      15 ++++-----------
         M bstorage.c                          |      80 ++-----------------------------
         M dup-check.c                         |      61 ++++++++++++++++++++++---------
         M dup-gc.c                            |      61 ++++++++++++++++++++++---------
         M dup-init.c                          |      66 +++++++++++++++++++++-----------
         M dup-keygen.c                        |       2 ++
         M dup-pack.c                          |      60 ++++++++++++++++++++++---------
         M dup-rm.c                            |      60 ++++++++++++++++++++++---------
         M dup-unpack.c                        |      60 ++++++++++++++++++++++---------
         M state.c                             |       1 +
         M state.h                             |       5 +++++
       
       14 files changed, 317 insertions(+), 248 deletions(-)
       ---
 (DIR) diff --git a/bcompress.c b/bcompress.c
       @@ -16,17 +16,21 @@
        #include <snappy-c.h>
        
        #include "block.h"
       +#include "config.h"
       +#include "state.h"
        
        #define CDNONETYPE        0x200
        #define CDSNAPPYTYPE        0x201
        #define CDLZ4TYPE        0x202
        #define CDSIZE                (8 + 8)
        
       +extern struct param param;
       +
        extern int pack(unsigned char *, char *, ...);
        extern int unpack(unsigned char *, char *, ...);
        
       -static int bccreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar);
       -static int bcopen(struct bctx *bctx, char *path, int flags, int mode, struct bparam *bpar);
       +static int bccreat(struct bctx *bctx, char *path, int mode);
       +static int bcopen(struct bctx *bctx, char *path, int flags, int mode);
        static int bcput(struct bctx *bctx, void *buf, size_t n, unsigned char *md);
        static int bcget(struct bctx *bctx, unsigned char *md, void *buf, size_t *n);
        static int bcrm(struct bctx *bctx, unsigned char *md);
       @@ -90,19 +94,19 @@ packcd(void *buf, struct cd *cd)
        }
        
        static int
       -bccreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
       +bccreat(struct bctx *bctx, char *path, int mode)
        {
                struct cctx *cctx;
                int type;
        
       -        if (strcasecmp(bpar->calgo, "none") == 0) {
       +        if (strcasecmp(param.calgo, "none") == 0) {
                        type = CDNONETYPE;
       -        } else if (strcasecmp(bpar->calgo, "snappy") == 0) {
       +        } else if (strcasecmp(param.calgo, "snappy") == 0) {
                        type = CDSNAPPYTYPE;
       -        } else if (strcasecmp(bpar->calgo, "lz4") == 0) {
       +        } else if (strcasecmp(param.calgo, "lz4") == 0) {
                        type = CDLZ4TYPE;
                } else {
       -                bseterr("invalid compression type: %s", bpar->calgo);
       +                bseterr("invalid compression type: %s", param.calgo);
                        return -1;
                }
        
       @@ -114,7 +118,7 @@ bccreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
                cctx = bctx->cctx;
                cctx->type = type;
        
       -        if (bencryptops()->creat(bctx, path, mode, bpar) < 0) {
       +        if (bencryptops()->creat(bctx, path, mode) < 0) {
                        free(cctx);
                        return -1;
                }
       @@ -122,7 +126,7 @@ bccreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
        }
        
        static int
       -bcopen(struct bctx *bctx, char *path, int flags, int mode, struct bparam *bpar)
       +bcopen(struct bctx *bctx, char *path, int flags, int mode)
        {
                struct cctx *cctx;
        
       @@ -133,21 +137,21 @@ bcopen(struct bctx *bctx, char *path, int flags, int mode, struct bparam *bpar)
                }
                cctx = bctx->cctx;
        
       -        if (bencryptops()->open(bctx, path, flags, mode, bpar) < 0) {
       +        if (bencryptops()->open(bctx, path, flags, mode) < 0) {
                        free(cctx);
                        return -1;
                }
        
       -        if (strcasecmp(bpar->calgo, "none") == 0) {
       +        if (strcasecmp(param.calgo, "none") == 0) {
                        cctx->type = CDNONETYPE;
       -        } else if (strcasecmp(bpar->calgo, "snappy") == 0) {
       +        } else if (strcasecmp(param.calgo, "snappy") == 0) {
                        cctx->type = CDSNAPPYTYPE;
       -        } else if (strcasecmp(bpar->calgo, "lz4") == 0) {
       +        } else if (strcasecmp(param.calgo, "lz4") == 0) {
                        cctx->type = CDLZ4TYPE;
                } else {
                        bencryptops()->close(bctx);
                        free(cctx);
       -                bseterr("invalid compression type: %s", bpar->calgo);
       +                bseterr("invalid compression type: %s", param.calgo);
                        return -1;
                }
                return 0;
 (DIR) diff --git a/bencrypt.c b/bencrypt.c
       @@ -16,6 +16,9 @@
        
        #include "block.h"
        #include "config.h"
       +#include "state.h"
       +
       +extern struct param param;
        
        #define EDNONETYPE        0x300
        #define EDCHACHATYPE        0x301
       @@ -24,8 +27,8 @@
        extern int pack(unsigned char *, char *, ...);
        extern int unpack(unsigned char *, char *, ...);
        
       -static int becreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar);
       -static int beopen(struct bctx *bctx, char *path, int flags, int mode, struct bparam *bpar);
       +static int becreat(struct bctx *bctx, char *path, int mode);
       +static int beopen(struct bctx *bctx, char *path, int flags, int mode);
        static int beput(struct bctx *bctx, void *buf, size_t n, unsigned char *md);
        static int beget(struct bctx *bctx, unsigned char *md, void *buf, size_t *n);
        static int berm(struct bctx *bctx, unsigned char *md);
       @@ -93,23 +96,23 @@ packed(void *buf, struct ed *ed)
        }
        
        static int
       -becreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
       +becreat(struct bctx *bctx, char *path, int mode)
        {
                struct ectx *ectx;
                int type;
        
                /* Determine algorithm type */
       -        if (strcasecmp(bpar->ealgo, "none") == 0) {
       +        if (strcasecmp(param.ealgo, "none") == 0) {
                        type = EDNONETYPE;
       -        } else if (strcasecmp(bpar->ealgo, "XChaCha20-Poly1305") == 0) {
       +        } else if (strcasecmp(param.ealgo, "XChaCha20-Poly1305") == 0) {
                        type = EDCHACHATYPE;
                } else {
       -                bseterr("invalid encryption type: %s", bpar->ealgo);
       +                bseterr("invalid encryption type: %s", param.ealgo);
                        return -1;
                }
        
                /* Ensure that if caller requested encryption, a key was provided */
       -        if (type != EDNONETYPE && bpar->key == NULL) {
       +        if (type != EDNONETYPE && !param.keyloaded) {
                        bseterr("expected encryption key");
                        return -1;
                }
       @@ -126,10 +129,9 @@ becreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
                }
                ectx = bctx->ectx;
                ectx->type = type;
       -        if (bpar->key != NULL)
       -                memcpy(ectx->key, bpar->key, KEYSIZE);
       +        memcpy(ectx->key, param.key, KEYSIZE);
        
       -        if (bstorageops()->creat(bctx, path, mode, bpar) < 0) {
       +        if (bstorageops()->creat(bctx, path, mode) < 0) {
                        free(ectx);
                        return -1;
                }
       @@ -137,7 +139,7 @@ becreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
        }
        
        static int
       -beopen(struct bctx *bctx, char *path, int flags, int mode, struct bparam *bpar)
       +beopen(struct bctx *bctx, char *path, int flags, int mode)
        {
                struct ectx *ectx;
        
       @@ -147,28 +149,27 @@ beopen(struct bctx *bctx, char *path, int flags, int mode, struct bparam *bpar)
                        return -1;
                }
                ectx = bctx->ectx;
       -        if (bpar->key != NULL)
       -                memcpy(ectx->key, bpar->key, KEYSIZE);
       +        memcpy(ectx->key, param.key, KEYSIZE);
        
       -        if (bstorageops()->open(bctx, path, flags, mode, bpar) < 0) {
       +        if (bstorageops()->open(bctx, path, flags, mode) < 0) {
                        free(ectx);
                        return -1;
                }
        
                /* Determine algorithm type */
       -        if (strcasecmp(bpar->ealgo, "none") == 0)
       +        if (strcasecmp(param.ealgo, "none") == 0)
                        ectx->type = EDNONETYPE;
       -        else if (strcasecmp(bpar->ealgo, "XChaCha20-Poly1305") == 0)
       +        else if (strcasecmp(param.ealgo, "XChaCha20-Poly1305") == 0)
                        ectx->type = EDCHACHATYPE;
                else {
                        bstorageops()->close(bctx);
                        free(ectx);
       -                bseterr("invalid encryption type: %s", bpar->ealgo);
       +                bseterr("invalid encryption type: %s", param.ealgo);
                        return -1;
                }
        
                /* Ensure that if repo is encrypted, a key was provided */
       -        if (ectx->type != EDNONETYPE && bpar->key == NULL) {
       +        if (ectx->type != EDNONETYPE && !param.keyloaded) {
                        bstorageops()->close(bctx);
                        free(ectx);
                        bseterr("expected encryption key");
 (DIR) diff --git a/block.c b/block.c
       @@ -16,7 +16,7 @@
        static char errbuf[NERRBUF];
        
        int
       -bcreat(char *path, int mode, struct bparam *bpar, struct bctx **bctx)
       +bcreat(char *path, int mode, struct bctx **bctx)
        {
                struct bops *bops;
        
       @@ -25,9 +25,6 @@ bcreat(char *path, int mode, struct bparam *bpar, struct bctx **bctx)
                        return -1;
                }
        
       -        if (bpar == NULL)
       -                bpar = bparamdef();
       -
                *bctx = calloc(1, sizeof(**bctx));
                if (*bctx == NULL) {
                        bseterr("calloc: %s", strerror(errno));
       @@ -35,7 +32,7 @@ bcreat(char *path, int mode, struct bparam *bpar, struct bctx **bctx)
                }
        
                bops = bcompressops();
       -        if (bops->creat(*bctx, path, mode, bpar) < 0) {
       +        if (bops->creat(*bctx, path, mode) < 0) {
                        free(*bctx);
                        return -1;
                }
       @@ -43,11 +40,11 @@ bcreat(char *path, int mode, struct bparam *bpar, struct bctx **bctx)
        }
        
        int
       -bopen(char *path, int flags, int mode, struct bparam *bpar, struct bctx **bctx)
       +bopen(char *path, int flags, int mode, struct bctx **bctx)
        {
                struct bops *bops;
        
       -        if (path == NULL || bpar == NULL || bctx == NULL) {
       +        if (path == NULL || bctx == NULL) {
                        bseterr("invalid params");
                        return -1;
                }
       @@ -59,7 +56,7 @@ bopen(char *path, int flags, int mode, struct bparam *bpar, struct bctx **bctx)
                }
        
                bops = bcompressops();
       -        if (bops->open(*bctx, path, flags, mode, bpar) < 0) {
       +        if (bops->open(*bctx, path, flags, mode) < 0) {
                        free(*bctx);
                        return -1;
                }
       @@ -169,18 +166,6 @@ bclose(struct bctx *bctx)
                return r;
        }
        
       -struct bparam *
       -bparamdef(void)
       -{
       -        static struct bparam bpar = {
       -                .calgo = "snappy",
       -                .ealgo = "none",
       -                .key = NULL
       -        };
       -
       -        return &bpar;
       -}
       -
        void
        bseterr(char *fmt, ...)
        {
 (DIR) diff --git a/block.h b/block.h
       @@ -10,19 +10,13 @@ struct bctx {
                void *sctx;        /* storage layer context */
        };
        
       -struct bparam {
       -        char *calgo;
       -        char *ealgo;
       -        unsigned char *key;
       -};
       -
        /*
         * Block operations structure.
         * This is implemented by each of the block layers.
         */
        struct bops {
       -        int (*creat)(struct bctx *, char *, int, struct bparam *);
       -        int (*open)(struct bctx *, char *, int, int, struct bparam *);
       +        int (*creat)(struct bctx *, char *, int);
       +        int (*open)(struct bctx *, char *, int, int);
                int (*put)(struct bctx *, void *, size_t, unsigned char *);
                int (*get)(struct bctx *, unsigned char *, void *, size_t *);
                int (*rm)(struct bctx *, unsigned char *);
       @@ -33,8 +27,8 @@ struct bops {
        };
        
        /* block.c */
       -extern int bcreat(char *, int, struct bparam *, struct bctx **);
       -extern int bopen(char *, int, int, struct bparam *, struct bctx **);
       +extern int bcreat(char *, int, struct bctx **);
       +extern int bopen(char *, int, int, struct bctx **);
        extern int bput(struct bctx *, void *, size_t, unsigned char *);
        extern int bget(struct bctx *, unsigned char *, void *, size_t *);
        extern int brm(struct bctx *, unsigned char *);
       @@ -42,7 +36,6 @@ extern int bgc(struct bctx *);
        extern int bcheck(struct bctx *, unsigned char *);
        extern int bsync(struct bctx *);
        extern int bclose(struct bctx *);
       -extern struct bparam *bparamdef(void);
        extern void bseterr(char *, ...);
        extern void berr(char *, ...);
        
 (DIR) diff --git a/bstorage.c b/bstorage.c
       @@ -40,17 +40,6 @@
        #define VMAJSHIFT        8
        #define VMAJMASK        0xff
        
       -#define CALGOSHIFT        16
       -#define CALGOMASK        0x7
       -#define CNONETYPE        0
       -#define CSNAPPYTYPE        1
       -#define CLZ4TYPE        2
       -
       -#define EALGOSHIFT        19
       -#define EALGOMASK        0x7
       -#define ENONETYPE        0
       -#define ECHACHATYPE        1
       -
        #define BHDRSIZE        (NBHDRMAGIC + 8 + 8)
        
        /* block descriptor constants */
       @@ -61,8 +50,8 @@
        extern int pack(unsigned char *, char *, ...);
        extern int unpack(unsigned char *, char *, ...);
        
       -static int bscreat(struct bctx *, char *, int, struct bparam *);
       -static int bsopen(struct bctx *, char *, int, int, struct bparam *);
       +static int bscreat(struct bctx *, char *, int);
       +static int bsopen(struct bctx *, char *, int, int);
        static int bsput(struct bctx *, void *, size_t, unsigned char *);
        static int bsget(struct bctx *, unsigned char *, void *, size_t *);
        static int bsrm(struct bctx *, unsigned char *);
       @@ -307,7 +296,7 @@ initbdcache(struct sctx *sctx)
        
        /* Create storage file */
        static int
       -bscreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
       +bscreat(struct bctx *bctx, char *path, int mode)
        {
                struct sctx *sctx;
                struct bhdr *bhdr;
       @@ -339,32 +328,6 @@ bscreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
                bhdr = &sctx->bhdr;
                memcpy(bhdr->magic, BHDRMAGIC, NBHDRMAGIC);
                bhdr->flags = (VMAJ << VMAJSHIFT) | VMIN;
       -
       -        /* Set compression type */
       -        if (strcasecmp(bpar->calgo, "none") == 0) {
       -                bhdr->flags |= CNONETYPE << CALGOSHIFT;
       -        } else if (strcasecmp(bpar->calgo, "snappy") == 0) {
       -                bhdr->flags |= CSNAPPYTYPE << CALGOSHIFT;
       -        } else if (strcasecmp(bpar->calgo, "lz4") == 0) {
       -                bhdr->flags |= CLZ4TYPE << CALGOSHIFT;
       -        } else {
       -                free(sctx);
       -                close(fd);
       -                bseterr("invalid compression type: %s", bpar->calgo);
       -                return -1;
       -        }
       -
       -        /* Set encryption type */
       -        if (strcasecmp(bpar->ealgo, "none") == 0) {
       -                bhdr->flags |= ENONETYPE << EALGOSHIFT;
       -        } else if (strcasecmp(bpar->ealgo, "XChaCha20-Poly1305") == 0) {
       -                bhdr->flags |= ECHACHATYPE << EALGOSHIFT;
       -        } else {
       -                free(sctx);
       -                close(fd);
       -                bseterr("invalid encryption type: %s", bpar->ealgo);
       -                return -1;
       -        }
                bhdr->nbd = 0;
        
                if (packbhdr(fd, bhdr) < 0) {
       @@ -377,7 +340,7 @@ bscreat(struct bctx *bctx, char *path, int mode, struct bparam *bpar)
        
        /* Open storage file */
        static int
       -bsopen(struct bctx *bctx, char *path, int flags, int mode, struct bparam *bpar)
       +bsopen(struct bctx *bctx, char *path, int flags, int mode)
        {
                struct sctx *sctx;
                struct bhdr *bhdr;
       @@ -439,41 +402,6 @@ bsopen(struct bctx *bctx, char *path, int flags, int mode, struct bparam *bpar)
                        return -1;
                }
        
       -        /* Populate bparam compression algo */
       -        algo = (bhdr->flags >> CALGOSHIFT) & CALGOMASK;
       -        switch (algo) {
       -        case CNONETYPE:
       -                bpar->calgo = "none";
       -                break;
       -        case CSNAPPYTYPE:
       -                bpar->calgo = "snappy";
       -                break;
       -        case CLZ4TYPE:
       -                bpar->calgo = "lz4";
       -                break;
       -        default:
       -                free(sctx);
       -                close(fd);
       -                bseterr("invalid compression type: %d", algo);
       -                return -1;
       -        }
       -
       -        /* Populate bparam encryption algo */
       -        algo = (bhdr->flags >> EALGOSHIFT) & EALGOMASK;
       -        switch (algo) {
       -        case ENONETYPE:
       -                bpar->ealgo = "none";
       -                break;
       -        case ECHACHATYPE:
       -                bpar->ealgo = "XChaCha20-Poly1305";
       -                break;
       -        default:
       -                free(sctx);
       -                close(fd);
       -                bseterr("invalid encryption type: %d", algo);
       -                return -1;
       -        }
       -
                sctx->fd = fd;
                sctx->rdonly = flags == O_RDONLY;
        
 (DIR) diff --git a/dup-check.c b/dup-check.c
       @@ -16,11 +16,48 @@
        #include "key.h"
        #include "lock.h"
        #include "snap.h"
       +#include "state.h"
        
       +struct param param;
        int verbose;
        char *argv0;
        
        static void
       +initparam(char *repo)
       +{
       +        char path[PATH_MAX];
       +        int fd;
       +
       +        if (snprintf(path, sizeof(path), "%s/state", repo) >= sizeof(path))
       +                errx(1, "snprintf: %s: path too long", path);
       +        fd = open(path, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", path);
       +        if (loadstate(fd, &param) < 0)
       +                errx(1, "loadstate: failed");
       +        if (close(fd) < 0)
       +                err(1, "close: %s", path);
       +}
       +
       +static void
       +initkey(char *keyfile)
       +{
       +        int fd;
       +
       +        if (keyfile == NULL)
       +                return;
       +
       +        fd = open(keyfile, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", keyfile);
       +        if (loadkey(fd, param.key, sizeof(param.key)) < 0)
       +                errx(1, "loadkey: failed");
       +        param.keyloaded = 1;
       +        if (close(fd) < 0)
       +                err(1, "close: %s", keyfile);
       +}
       +
       +static void
        check(struct sctx *sctx, struct bctx *bctx)
        {
                unsigned char md[MDSIZE];
       @@ -56,10 +93,8 @@ main(int argc, char *argv[])
        {
                char spath[PATH_MAX];
                char bpath[PATH_MAX];
       -        unsigned char key[KEYSIZE];
                struct sctx *sctx;
                struct bctx *bctx;
       -        struct bparam bpar;
                char *keyfile = NULL;
                char *repo = ".";
                int lfd;
       @@ -81,21 +116,6 @@ main(int argc, char *argv[])
                if (argc != 1)
                        usage();
        
       -        if (keyfile != NULL) {
       -                int fd;
       -
       -                fd = open(keyfile, O_RDONLY);
       -                if (fd < 0)
       -                        err(1, "open: %s", keyfile);
       -                if (loadkey(fd, key, sizeof(key)) < 0)
       -                        errx(1, "loadkey: failed");
       -                bpar.key = key;
       -                if (close(fd) < 0)
       -                        err(1, "close: %s", keyfile);
       -        } else {
       -                bpar.key = NULL;
       -        }
       -
                if (snprintf(spath, sizeof(spath), "%s/archive/%s",
                             repo, argv[0]) >= sizeof(spath))
                        errx(1, "snprintf: %s: path too long", spath);
       @@ -105,9 +125,13 @@ main(int argc, char *argv[])
        
                if ((lfd = lockrepo(repo)) < 0)
                        errx(1, "failed to lock repository");
       +
       +        initparam(repo);
       +        initkey(keyfile);
       +
                if (sopen(spath, S_READ, 0600, &sctx) < 0)
                        serr("sopen: %s", spath);
       -        if (bopen(bpath, B_READ, 0600, &bpar, &bctx) <0)
       +        if (bopen(bpath, B_READ, 0600, &bctx) <0)
                        berr("bopen: %s", bpath);
        
                check(sctx, bctx);
       @@ -116,6 +140,7 @@ main(int argc, char *argv[])
                        berr("bclose: %s", bpath);
                if (sclose(sctx) < 0)
                        serr("sclose: %s", spath);
       +
                if (unlockrepo(lfd) < 0)
                        errx(1, "failed to unlock repository");
                
 (DIR) diff --git a/dup-gc.c b/dup-gc.c
       @@ -14,11 +14,48 @@
        #include "key.h"
        #include "lock.h"
        #include "snap.h"
       +#include "state.h"
        
       +struct param param;
        int verbose;
        char *argv0;
        
        static void
       +initparam(char *repo)
       +{
       +        char path[PATH_MAX];
       +        int fd;
       +
       +        if (snprintf(path, sizeof(path), "%s/state", repo) >= sizeof(path))
       +                errx(1, "snprintf: %s: path too long", path);
       +        fd = open(path, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", path);
       +        if (loadstate(fd, &param) < 0)
       +                errx(1, "loadstate: failed");
       +        if (close(fd) < 0)
       +                err(1, "close: %s", path);
       +}
       +
       +static void
       +initkey(char *keyfile)
       +{
       +        int fd;
       +
       +        if (keyfile == NULL)
       +                return;
       +
       +        fd = open(keyfile, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", keyfile);
       +        if (loadkey(fd, param.key, sizeof(param.key)) < 0)
       +                errx(1, "loadkey: failed");
       +        param.keyloaded = 1;
       +        if (close(fd) < 0)
       +                err(1, "close: %s", keyfile);
       +}
       +
       +static void
        usage(void)
        {
                fprintf(stderr, "usage: %s [-v] [-k keyfile] [repo]\n", argv0);
       @@ -29,9 +66,7 @@ int
        main(int argc, char *argv[])
        {
                char path[PATH_MAX];
       -        unsigned char key[KEYSIZE];
                struct bctx *bctx;
       -        struct bparam bpar;
                char *keyfile = NULL;
                char *repo;
                int lfd;
       @@ -58,33 +93,23 @@ main(int argc, char *argv[])
                        usage();
                };
        
       -        if (keyfile != NULL) {
       -                int fd;
       -
       -                fd = open(keyfile, O_RDONLY);
       -                if (fd < 0)
       -                        err(1, "open: %s", keyfile);
       -                if (loadkey(fd, key, sizeof(key)) < 0)
       -                        errx(1, "loadkey: failed");
       -                bpar.key = key;
       -                if (close(fd) < 0)
       -                        err(1, "close: %s", keyfile);
       -        } else {
       -                bpar.key = NULL;
       -        }
       -
                if (snprintf(path, sizeof(path), "%s/%s",
                             repo, STORAGEPATH) >= sizeof(path))
                        errx(1, "snprintf: %s: path too long", path);
        
                if ((lfd = lockrepo(repo)) < 0)
                        errx(1, "failed to lock repository");
       -        if (bopen(path, B_RDWR, 0600, &bpar, &bctx) < 0)
       +
       +        initparam(repo);
       +        initkey(keyfile);
       +
       +        if (bopen(path, B_RDWR, 0600, &bctx) < 0)
                        berr("bopen: %s", path);
                if (bgc(bctx) < 0)
                        berr("bgc: %s", path);
                if (bclose(bctx) < 0)
                        berr("bclose: %s", path);
       +
                if (unlockrepo(lfd) < 0)
                        errx(1, "failed to unlock repository");
                return 0;
 (DIR) diff --git a/dup-init.c b/dup-init.c
       @@ -15,11 +15,48 @@
        #include "lock.h"
        #include "misc.h"
        #include "snap.h"
       +#include "state.h"
        
       +struct param param;
        int verbose;
        char *argv0;
        
        static void
       +initparam(char *repo)
       +{
       +        char path[PATH_MAX];
       +        int fd;
       +
       +        if (snprintf(path, sizeof(path), "%s/state", repo) >= sizeof(path))
       +                errx(1, "snprintf: %s: path too long", path);
       +        fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
       +        if (fd < 0)
       +                err(1, "open: %s", path);
       +        if (savestate(fd, &param) < 0)
       +                errx(1, "loadstate: failed");
       +        if (close(fd) < 0)
       +                err(1, "close: %s", path);
       +}
       +
       +static void
       +initkey(char *keyfile)
       +{
       +        int fd;
       +
       +        if (keyfile == NULL)
       +                return;
       +
       +        fd = open(keyfile, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", keyfile);
       +        if (loadkey(fd, param.key, sizeof(param.key)) < 0)
       +                errx(1, "loadkey: failed");
       +        param.keyloaded = 1;
       +        if (close(fd) < 0)
       +                err(1, "close: %s", keyfile);
       +}
       +
       +static void
        usage(void)
        {
                fprintf(stderr, "usage: %s [-v] [-E algo] [-Z algo] [-k keyfile] [repo]\n", argv0);
       @@ -31,25 +68,23 @@ main(int argc, char *argv[])
        {
                char spath[PATH_MAX];
                char bpath[PATH_MAX];
       -        unsigned char key[KEYSIZE];
                struct bctx *bctx;
       -        struct bparam bpar;
                char *keyfile = NULL;
                char *repo;
                int lfd;
        
       -        bpar.calgo = bparamdef()->calgo;
       -        bpar.ealgo = bparamdef()->ealgo;
       +        param.calgo = "snappy";
       +        param.ealgo = "none";
        
                ARGBEGIN {
                case 'k':
                        keyfile = EARGF(usage());
                        break;
                case 'E':
       -                bpar.ealgo = EARGF(usage());
       +                param.ealgo = EARGF(usage());
                        break;
                case 'Z':
       -                bpar.calgo = EARGF(usage());
       +                param.calgo = EARGF(usage());
                        break;
                case 'v':
                        verbose++;
       @@ -69,21 +104,6 @@ main(int argc, char *argv[])
                        usage();
                };
        
       -        if (keyfile != NULL) {
       -                int fd;
       -
       -                fd = open(keyfile, O_RDONLY);
       -                if (fd < 0)
       -                        err(1, "open: %s", keyfile);
       -                if (loadkey(fd, key, sizeof(key)) < 0)
       -                        errx(1, "loadkey: failed");
       -                bpar.key = key;
       -                if (close(fd) < 0)
       -                        err(1, "close: %s", keyfile);
       -        } else {
       -                bpar.key = NULL;
       -        }
       -
                if (snprintf(spath, sizeof(spath), "%s/%s",
                             repo, ARCHIVEPATH) >= sizeof(spath))
                        errx(1, "snprintf: %s: path too long", spath);
       @@ -91,13 +111,15 @@ main(int argc, char *argv[])
                             repo, STORAGEPATH) >= sizeof(bpath))
                        errx(1, "snprintf: %s: path too long", bpath);
        
       +        initkey(keyfile);
                if (mkdir(repo, 0700) < 0)
                        err(1, "mkdir: %s", repo);
                if ((lfd = lockrepo(repo)) < 0)
                        errx(1, "failed to lock repository");
                if (mkdir(spath, 0700) < 0)
                        err(1, "mkdir: %s", spath);
       -        if (bcreat(bpath, 0600, &bpar, &bctx) < 0)
       +        initparam(repo);
       +        if (bcreat(bpath, 0600, &bctx) < 0)
                        berr("bcreat: %s", bpath);
                if (bclose(bctx) < 0)
                        berr("bclose: %s", bpath);
 (DIR) diff --git a/dup-keygen.c b/dup-keygen.c
       @@ -10,7 +10,9 @@
        #include "arg.h"
        #include "config.h"
        #include "key.h"
       +#include "state.h"
        
       +struct param param;        /* unused */
        int verbose;
        char *argv0;
        
 (DIR) diff --git a/dup-pack.c b/dup-pack.c
       @@ -15,11 +15,48 @@
        #include "key.h"
        #include "lock.h"
        #include "snap.h"
       +#include "state.h"
        
       +struct param param;
        int verbose;
        char *argv0;
        
        static void
       +initparam(char *repo)
       +{
       +        char path[PATH_MAX];
       +        int fd;
       +
       +        if (snprintf(path, sizeof(path), "%s/state", repo) >= sizeof(path))
       +                errx(1, "snprintf: %s: path too long", path);
       +        fd = open(path, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", path);
       +        if (loadstate(fd, &param) < 0)
       +                errx(1, "loadstate: failed");
       +        if (close(fd) < 0)
       +                err(1, "close: %s", path);
       +}
       +
       +static void
       +initkey(char *keyfile)
       +{
       +        int fd;
       +
       +        if (keyfile == NULL)
       +                return;
       +
       +        fd = open(keyfile, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", keyfile);
       +        if (loadkey(fd, param.key, sizeof(param.key)) < 0)
       +                errx(1, "loadkey: failed");
       +        param.keyloaded = 1;
       +        if (close(fd) < 0)
       +                err(1, "close: %s", keyfile);
       +}
       +
       +static void
        pack(struct sctx *sctx, struct bctx *bctx)
        {
                struct chunker *c;
       @@ -61,7 +98,6 @@ main(int argc, char *argv[])
                unsigned char key[KEYSIZE];
                struct sctx *sctx;
                struct bctx *bctx;
       -        struct bparam bpar;
                char *keyfile = NULL;
                char *repo = ".";
                int lfd;
       @@ -83,21 +119,6 @@ main(int argc, char *argv[])
                if (argc != 1)
                        usage();
        
       -        if (keyfile != NULL) {
       -                int fd;
       -
       -                fd = open(keyfile, O_RDONLY);
       -                if (fd < 0)
       -                        err(1, "open: %s", keyfile);
       -                if (loadkey(fd, key, sizeof(key)) < 0)
       -                        errx(1, "loadkey: failed");
       -                bpar.key = key;
       -                if (close(fd) < 0)
       -                        err(1, "close: %s", keyfile);
       -        } else {
       -                bpar.key = NULL;
       -        }
       -
                if (snprintf(spath, sizeof(spath), "%s/archive/%s",
                             repo, argv[0]) >= sizeof(spath))
                        errx(1, "snprintf: %s: path too long", spath);
       @@ -107,9 +128,13 @@ main(int argc, char *argv[])
        
                if ((lfd = lockrepo(repo)) < 0)
                        errx(1, "failed to lock repository");
       +
       +        initparam(repo);
       +        initkey(keyfile);
       +
                if (screat(spath, 0600, &sctx) < 0)
                        serr("screat: %s", spath);
       -        if (bopen(bpath, B_RDWR, 0600, &bpar, &bctx) <0)
       +        if (bopen(bpath, B_RDWR, 0600, &bctx) <0)
                        berr("bopen: %s", bpath);
        
                pack(sctx, bctx);
       @@ -118,6 +143,7 @@ main(int argc, char *argv[])
                        berr("bclose: %s", bpath);
                if (sclose(sctx) < 0)
                        serr("sclose: %s", spath);
       +
                if (unlockrepo(lfd) < 0)
                        errx(1, "failed to unlock repository");
                return 0;
 (DIR) diff --git a/dup-rm.c b/dup-rm.c
       @@ -14,11 +14,48 @@
        #include "key.h"
        #include "lock.h"
        #include "snap.h"
       +#include "state.h"
        
       +struct param param;
        int verbose;
        char *argv0;
        
        static void
       +initparam(char *repo)
       +{
       +        char path[PATH_MAX];
       +        int fd;
       +
       +        if (snprintf(path, sizeof(path), "%s/state", repo) >= sizeof(path))
       +                errx(1, "snprintf: %s: path too long", path);
       +        fd = open(path, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", path);
       +        if (loadstate(fd, &param) < 0)
       +                errx(1, "loadstate: failed");
       +        if (close(fd) < 0)
       +                err(1, "close: %s", path);
       +}
       +
       +static void
       +initkey(char *keyfile)
       +{
       +        int fd;
       +
       +        if (keyfile == NULL)
       +                return;
       +
       +        fd = open(keyfile, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", keyfile);
       +        if (loadkey(fd, param.key, sizeof(param.key)) < 0)
       +                errx(1, "loadkey: failed");
       +        param.keyloaded = 1;
       +        if (close(fd) < 0)
       +                err(1, "close: %s", keyfile);
       +}
       +
       +static void
        rm(struct sctx *sctx, struct bctx *bctx)
        {
                unsigned char md[MDSIZE];
       @@ -47,7 +84,6 @@ main(int argc, char *argv[])
                unsigned char key[KEYSIZE];
                struct sctx *sctx;
                struct bctx *bctx;
       -        struct bparam bpar;
                char *keyfile = NULL;
                char *repo = ".";
                int lfd;
       @@ -69,21 +105,6 @@ main(int argc, char *argv[])
                if (argc != 1)
                        usage();
        
       -        if (keyfile != NULL) {
       -                int fd;
       -
       -                fd = open(keyfile, O_RDONLY);
       -                if (fd < 0)
       -                        err(1, "open: %s", keyfile);
       -                if (loadkey(fd, key, sizeof(key)) < 0)
       -                        errx(1, "loadkey: failed");
       -                bpar.key = key;
       -                if (close(fd) < 0)
       -                        err(1, "close: %s", keyfile);
       -        } else {
       -                bpar.key = NULL;
       -        }
       -
                if (snprintf(spath, sizeof(spath), "%s/archive/%s",
                             repo, argv[0]) >= sizeof(spath))
                        errx(1, "snprintf: %s: path too long", spath);
       @@ -93,9 +114,13 @@ main(int argc, char *argv[])
        
                if ((lfd = lockrepo(repo)) < 0)
                        errx(1, "failed to lock repository");
       +
       +        initparam(repo);
       +        initkey(keyfile);
       +
                if (sopen(spath, S_READ, 0600, &sctx) < 0)
                        serr("sopen: %s", spath);
       -        if (bopen(bpath, B_RDWR, 0600, &bpar, &bctx) <0)
       +        if (bopen(bpath, B_RDWR, 0600, &bctx) <0)
                        berr("bopen: %s", bpath);
        
                rm(sctx, bctx);
       @@ -106,6 +131,7 @@ main(int argc, char *argv[])
                        serr("sclose: %s", spath);
                if (unlink(spath) < 0)
                        err(1, "unlink: %s", spath);
       +
                if (unlockrepo(lfd) < 0)
                        errx(1, "failed to unlock repository");
                
 (DIR) diff --git a/dup-unpack.c b/dup-unpack.c
       @@ -15,11 +15,48 @@
        #include "lock.h"
        #include "misc.h"
        #include "snap.h"
       +#include "state.h"
        
       +struct param param;
        int verbose;
        char *argv0;
        
        static void
       +initparam(char *repo)
       +{
       +        char path[PATH_MAX];
       +        int fd;
       +
       +        if (snprintf(path, sizeof(path), "%s/state", repo) >= sizeof(path))
       +                errx(1, "snprintf: %s: path too long", path);
       +        fd = open(path, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", path);
       +        if (loadstate(fd, &param) < 0)
       +                errx(1, "loadstate: failed");
       +        if (close(fd) < 0)
       +                err(1, "close: %s", path);
       +}
       +
       +static void
       +initkey(char *keyfile)
       +{
       +        int fd;
       +
       +        if (keyfile == NULL)
       +                return;
       +
       +        fd = open(keyfile, O_RDONLY);
       +        if (fd < 0)
       +                err(1, "open: %s", keyfile);
       +        if (loadkey(fd, param.key, sizeof(param.key)) < 0)
       +                errx(1, "loadkey: failed");
       +        param.keyloaded = 1;
       +        if (close(fd) < 0)
       +                err(1, "close: %s", keyfile);
       +}
       +
       +static void
        unpack(struct sctx *sctx, struct bctx *bctx)
        {
                unsigned char md[MDSIZE];
       @@ -57,7 +94,6 @@ main(int argc, char *argv[])
                unsigned char key[KEYSIZE];
                struct sctx *sctx;
                struct bctx *bctx;
       -        struct bparam bpar;
                char *keyfile = NULL;
                char *repo = ".";
                int lfd;
       @@ -79,21 +115,6 @@ main(int argc, char *argv[])
                if (argc != 1)
                        usage();
        
       -        if (keyfile != NULL) {
       -                int fd;
       -
       -                fd = open(keyfile, O_RDONLY);
       -                if (fd < 0)
       -                        err(1, "open: %s", keyfile);
       -                if (loadkey(fd, key, sizeof(key)) < 0)
       -                        errx(1, "loadkey: failed");
       -                bpar.key = key;
       -                if (close(fd) < 0)
       -                        err(1, "close: %s", keyfile);
       -        } else {
       -                bpar.key = NULL;
       -        }
       -
                if (snprintf(spath, sizeof(spath), "%s/archive/%s",
                             repo, argv[0]) >= sizeof(spath))
                        errx(1, "snprintf: %s: path too long", spath);
       @@ -103,9 +124,13 @@ main(int argc, char *argv[])
        
                if ((lfd = lockrepo(repo)) < 0)
                        errx(1, "failed to lock repository");
       +
       +        initparam(repo);
       +        initkey(keyfile);
       +
                if (sopen(spath, S_READ, 0600, &sctx) < 0)
                        serr("sopen: %s", spath);
       -        if (bopen(bpath, B_READ, 0600, &bpar, &bctx) <0)
       +        if (bopen(bpath, B_READ, 0600, &bctx) <0)
                        berr("bopen: %s", bpath);
        
                unpack(sctx, bctx);
       @@ -114,6 +139,7 @@ main(int argc, char *argv[])
                        berr("bclose: %s", bpath);
                if (sclose(sctx) < 0)
                        serr("sclose: %s", spath);
       +
                if (unlockrepo(lfd) < 0)
                        errx(1, "failed to unlock repository");
                
 (DIR) diff --git a/state.c b/state.c
       @@ -4,6 +4,7 @@
        #include <string.h>
        #include <strings.h>
        
       +#include "config.h"
        #include "misc.h"
        #include "state.h"
        
 (DIR) diff --git a/state.h b/state.h
       @@ -1,4 +1,9 @@
        struct param {
                char *calgo;
                char *ealgo;
       +        unsigned char key[KEYSIZE];
       +        int keyloaded;
        };
       +
       +int savestate(int, struct param *);
       +int loadstate(int fd, struct param *);