diff options
| author | Quentin Carbonneaux | 2022-04-05 15:35:02 +0200 |
|---|---|---|
| committer | Quentin Carbonneaux | 2022-04-05 15:35:02 +0200 |
| commit | 737202fcafa7812d5d758c8e360a142b4b11dd43 (patch) | |
| tree | ba3e4866aaf4e16c588e1c2ab4954e184bc340b4 | |
| parent | 8fe4eaa0fbfd2b92071ab1d4de7ef84adfa3db00 (diff) | |
sdar overhaul
- new Slice API for managing buffers;
it wraps the error-prone APIs from
nacl
- kill use of global static buffers;
the new slice API offers allocation
and freeing functions that should
be efficient
| -rw-r--r-- | sdar/all.h | 78 | ||||
| -rw-r--r-- | sdar/arch.c | 276 | ||||
| -rw-r--r-- | sdar/cache.c | 8 | ||||
| -rw-r--r-- | sdar/crypt.c | 77 | ||||
| -rw-r--r-- | sdar/hmac.c | 13 | ||||
| -rw-r--r-- | sdar/key.c | 48 | ||||
| -rw-r--r-- | sdar/lib/crypto/scrypt.c | 10 | ||||
| -rw-r--r-- | sdar/lib/crypto/smix.c | 4 | ||||
| -rw-r--r-- | sdar/main.c | 104 | ||||
| -rw-r--r-- | sdar/sdar.1 | 20 | ||||
| -rw-r--r-- | sdar/slice.c | 158 | ||||
| -rw-r--r-- | sdar/stash.c | 314 | ||||
| -rw-r--r-- | sdar/util.c | 8 | ||||
| -rw-r--r-- | sdar/write.c (renamed from sdar/writer.c) | 77 |
14 files changed, 644 insertions, 551 deletions
@@ -6,6 +6,8 @@ enum { Plnpad = 32, Cippad = 16, + Cipovh = Plnpad - Cippad, + Bufpad = 32, Prepsz = 32, Noncesz = 24, Hmacsz = 32, @@ -19,10 +21,7 @@ enum { Indexsz = Maxblk / Entrysz, Magicsz = 8, Segmetasz = 8 + 8 + 8 + 128, - Seghdsz = - Magicsz + Keysz + - (Plnpad - Cippad) + - Segmetasz, + Seghdsz = Magicsz + Keysz + Cipovh + Segmetasz, Segitemsz = Hmacsz + 4, Permf = 0666, @@ -47,17 +46,24 @@ typedef struct Loghd Loghd; typedef struct Reader Reader; typedef struct Segfile Segfile; typedef struct Segmeta Segmeta; +typedef struct Slice Slice; typedef struct Writer Writer; typedef uchar hmac_t[Hmacsz]; -typedef int flushcb(void *, hmac_t, uchar *, int); -typedef int blockcb(Block *, hmac_t, uchar *, void *); +typedef int flushcb(void *, hmac_t, Slice); +typedef int blockcb(Block *, hmac_t, uchar[Prepsz], void *); + + +struct Slice { + uchar *buf; + long len; +}; struct Key { uchar *hmac; - uchar *masterpub; - uchar *mastersec; + uchar *pub; + uchar *sec; }; struct Block { @@ -98,7 +104,7 @@ struct Reader { /* open segment */ FILE *segf; int segno; - uchar segpre[Prepsz]; + uchar segp[Prepsz]; }; struct Writer { @@ -109,7 +115,7 @@ struct Writer { vlong vlen; vlong vlen0; Ilevel level[2]; - uchar buf[Plnpad + 2*Maxblk]; + uchar buf[Bufpad + 2*Maxblk]; }; struct Segmeta { @@ -125,8 +131,8 @@ struct Segfile { }; struct Loghd { - uchar kpub[Keysz]; - uchar kpre[Prepsz]; + uchar segk[Keysz]; + uchar segp[Prepsz]; vlong nitem; vlong dlen; }; @@ -151,10 +157,6 @@ struct Addr { #define MAKESURE(what, x) _Static_assert(x, #what) #define min(a, b) ((a) > (b) ? (b) : (a)) -#define sizeof (vlong)sizeof - -extern uchar iobuf[Maxblk]; -extern uchar inflate[Maxblk]; /* util.c */ extern FILE *flog; @@ -165,6 +167,7 @@ char *segs(uchar[Segidsz]); char *hmacs(hmac_t); void hmaccpy(hmac_t, hmac_t); FILE *fopenat(int, int, char *, ...); +int flushsync(FILE *); void enc32be(uchar *, uvlong); void enc32le(uchar *, uvlong); void enc64be(uchar *, uvlong); @@ -172,12 +175,18 @@ uvlong dec32be(uchar *); uvlong dec32le(uchar *); uvlong dec64be(uchar *); -/* crypt.c */ -extern uchar plain[Plnpad + Maxblk]; -extern uchar cipher[Plnpad + Maxblk]; -char *cread(FILE *, uchar *, vlong, long); -char *creadp(FILE *, uchar *, vlong, long); -char *cwritep(FILE *, uchar *, vlong, uchar *, long); +/* slice.c */ +Slice mksl(uchar *, long); +Slice newsl(); +void freesl(Slice); +void sldeflate(Slice *, Slice); +int slinflate(Slice *, Slice); +void slencryptp(Slice *, Slice, uchar[Prepsz], vlong); +int sldecryptp(Slice *, Slice, uchar[Prepsz], vlong); +int decrypt(Slice *, FILE *, long, uchar[Prepsz], vlong); +void slhmac(Slice, hmac_t); +int slwrite(Slice, FILE *); +int slread(Slice *, long, FILE *); /* key.c */ extern Key key; @@ -207,33 +216,26 @@ void readerinit(Reader *, Arch *); int readerstart(Reader *, Addr *, vlong); void readerdone(Reader *); int readerseek(Reader *, vlong); -int reader(Reader *, uchar **, long *); -void encmeta(uchar *, Segmeta *); +int reader(Reader *, Slice *); +void encmeta(Slice *, Segmeta *); void decitem(uchar *, Block *); -int walkblocks(FILE *, blockcb *, void *); +int walkblocks(FILE *, blockcb, void *); /* stash.c */ int stashinit(Arch *); int stashadd(Arch *, uchar *, vlong); -int stashblk(Arch *, hmac_t, int, uchar *, int); +int stashblk(Arch *, hmac_t, int, Slice); int stashdone(Arch *, Addr *); int stashsync(Arch *); int stashcommit(Arch *, char *, uchar[Segidsz]); -/* writer.c */ +/* write.c */ void writerinit(Writer *, flushcb *, void *); int writer(Writer *, uchar *, vlong); int writerdone(Writer *, Addr *); -int getlevel(Ilevel *, uchar *, long); - -/* hmac.c */ -void hmac_blake3(uchar *, long, uchar *, long, hmac_t); +int declevel(Ilevel *, Slice); /* lib/crypto */ -void crypto_scrypt_smix(uint8_t *, size_t, uint64_t, void *, void *); -int crypto_scrypt( - uint8_t *passwd, size_t passwdlen, uint8_t *salt, size_t saltlen, - uint64_t N, uint32_t _r, uint32_t _p, uint8_t *buf, size_t buflen); -int crypto_scrypt_test(); -void pbkdf2_sha256(uchar *p, size_t np, uint8_t *s, size_t ns, - uint64_t c, uint8_t *buf, size_t dkLen); +void scrypt_smix(uint8_t *, size_t, uint64_t, void *, void *); +int scrypt(uint8_t *, size_t, uint8_t *, size_t, uint64_t, uint32_t, uint32_t, uint8_t *, size_t); +void pbkdf2_sha256(uchar *, size_t, uint8_t *, size_t, uint64_t, uint8_t *, size_t); diff --git a/sdar/arch.c b/sdar/arch.c index 14160ef..104783c 100644 --- a/sdar/arch.c +++ b/sdar/arch.c @@ -12,6 +12,8 @@ typedef struct Cacheblk Cacheblk; +typedef int walkcb(Arch *, uchar[Segidsz], void *); + struct Cacheblk { Cache *cache; int segno; @@ -24,7 +26,7 @@ uchar segmagic[Magicsz] = { uchar inflate[Maxblk]; static int -walkseg(Arch *a, int fn(Arch *, uchar[Segidsz], void *), void *arg) +walkseg(Arch *a, walkcb fn, void *arg) { uchar segid[Segidsz]; struct dirent *de; @@ -51,8 +53,7 @@ walkseg(Arch *a, int fn(Arch *, uchar[Segidsz], void *), void *arg) logs("W ignoring seg/%s", de->d_name); continue; } - err = fn(a, segid, arg); - if (err) + if ((err = fn(a, segid, arg)) != 0) break; } @@ -64,12 +65,13 @@ walkseg(Arch *a, int fn(Arch *, uchar[Segidsz], void *), void *arg) } void -encmeta(uchar *buf, Segmeta *meta) +encmeta(Slice *s, Segmeta *meta) { - enc64be(buf, meta->nitem); - enc64be(buf + 8, meta->dlen); - enc64be(buf + 16, meta->date); - memcpy(buf + 24, meta->msg, sizeof meta->msg); + enc64be(s->buf, meta->nitem); + enc64be(s->buf + 8, meta->dlen); + enc64be(s->buf + 16, meta->date); + memcpy(s->buf + 24, meta->msg, sizeof meta->msg); + s->len = Segmetasz; } static void @@ -82,70 +84,87 @@ decmeta(uchar *buf, Segmeta *meta) } void -decitem(uchar *buf, Block *b) +decitem(uchar *p, Block *b) { - b->len = dec32be(buf + Hmacsz); + b->len = dec32be(p + Hmacsz); b->lz4 = b->len & 1; b->len >>= 1; } -int -walkblocks(FILE *f, blockcb *fn, void *arg) +static int +prepseg(FILE *f, uchar prep[Prepsz]) { - static uchar scratch[sizeof plain]; - uchar buf[Magicsz + Keysz]; - uchar *it, *end, *segkey; - vlong idx, blk, sz, rd; - Segmeta meta; - char *e; - Block b = {.off = 0}; - - if (fread(buf, sizeof buf, 1, f) != 1 - || memcmp(segmagic, buf, Magicsz) != 0) { - logs("E invalid header"); + uchar seghd[Magicsz + Keysz]; + + if (fread(seghd, sizeof seghd, 1, f) != 1 + || memcmp(segmagic, seghd, Magicsz) != 0) { + logs("E invalid semment header"); return 1; } + crypto_box_beforenm(prep, seghd + Magicsz, key.sec); + return 0; +} - segkey = buf + Magicsz; - e = cread(f, segkey, -1, Segmetasz); - if (e) { - logs("E cannot read metadata (%s)", e); +int +walkblocks(FILE *f, blockcb fn, void *arg) +{ + uchar segp[Prepsz]; + Slice s; + uchar *p, *pp; + vlong n, len, idx; + Segmeta m; + Block b; + int err; + + if (prepseg(f, segp)) return 1; + + err = 1; + s = newsl(); + + if (decrypt(&s, f, Segmetasz, segp, -1)) { + logs("E cannot read metadata"); + goto out; } - decmeta(plain + Plnpad, &meta); + decmeta(s.buf, &m); - if (fseek(f, meta.dlen, SEEK_CUR)) - return 1; + if (fseek(f, m.dlen, SEEK_CUR) == -1) + goto out; + b.off = 0; idx = -1; - sz = meta.nitem * Segitemsz; - blk = (Maxblk / Segitemsz) * Segitemsz; - for (; sz > 0; sz -= rd) { - rd = min(sz, blk); - e = cread(f, segkey, --idx, rd); - if (e) { - logs("E cannot read items (%s)", e); - return 1; + len = m.nitem * Segitemsz; + while (len > 0) { + n = (Maxblk/Segitemsz) * Segitemsz; + n = min(len, n); + len -= n; + if (decrypt(&s, f, n, segp, --idx)) { + logs("E cannot read items"); + goto out; } - memcpy(scratch, plain, Plnpad+rd); - it = scratch + Plnpad; - end = it + rd; - for (; it != end; it += Segitemsz) { - decitem(it, &b); - if (fn(&b, it, segkey, arg)) - return 1; - b.off += b.len + (Plnpad - Cippad); + p = s.buf; + pp = p + n; + while (p < pp) { + decitem(p, &b); + if (fn(&b, p, segp, arg)) + goto out; + b.off += b.len + Cipovh; + p += Segitemsz; } } - return 0; + err = 0; + +out: + freesl(s); + return err; } static int -cacheblk(Block *b, hmac_t hmac, uchar *key, void *arg) +cacheblk(Block *b, hmac_t hmac, uchar segp[Prepsz], void *arg) { Cacheblk *cb; - (void)key; + (void)segp; cb = arg; b->seg = cb->segno; if (cput(cb->cache, hmac, b)) { @@ -176,8 +195,8 @@ indexseg(Arch *a, uchar segid[Segidsz]) } /* returns 2 when a new segment cannot be - * indexed because the master key is not - * available */ + * indexed because the archive secret key + * is not available */ static int addseg(Arch *a, uchar segid[Segidsz], void *arg) { @@ -185,14 +204,14 @@ addseg(Arch *a, uchar segid[Segidsz], void *arg) int n; if (cgetseg(&a->cache, segid, &n)) { - if (!key.mastersec) + if (!key.sec) return 2; /* index the unknown segment */ if (indexseg(a, segid)) return 1; n = a->nseg; p = realloc(a->seg, n*sizeof *p); - if (!p) { + if (p == 0) { a->nseg--; return 1; } @@ -215,7 +234,7 @@ readcache(Arch *a) { int nold, nin; - /* TODO, grab a lock if writing */ + /* TODO: grab a lock if writing */ if (cinit(&a->cache, a->fd, "cache", 0)) { if (errno != ENOENT) @@ -226,6 +245,8 @@ readcache(Arch *a) a->nseg = a->cache.meta->nseg; a->seg = calloc(a->nseg, sizeof a->seg[0]); + if (a->seg == 0) + goto error; nold = a->nseg; nin = 0; switch (walkseg(a, addseg, &nin)) { @@ -233,7 +254,7 @@ readcache(Arch *a) creset(&a->cache); goto error; case 2: - logs("W could not update cache in write operation"); + logs("W archive open in write-only mode"); goto error; } a->cache.meta->nseg = a->nseg; @@ -257,19 +278,21 @@ archinit(Arch *a, char *path) logs("E %s/seg does not exist", path); goto error; } + a->fd = fd; a->log = 0; a->data = 0; a->logh = 0; if (readcache(a)) { - logs("E could not initialize archive cache"); + logs("E cache init failed"); goto error; } + return 0; error: - close(fd); memset(a, 0, sizeof *a); + close(fd); return 1; } @@ -304,60 +327,67 @@ archhas(Arch *a, hmac_t hmac) } static int -readblock(Reader *r, hmac_t hmac, Block *b, uchar **data, long *blen) +openseg(Reader *r, uchar *segid, int segno) { - uchar buf[Magicsz + Keysz]; - hmac_t check; - char *src, *dst, *seg; - int decomp; FILE *f; - if (cget(&r->arch->cache, hmac, b)) { - logs("E missing block %s", hmacs(hmac)); + f = fopenat(r->arch->fd, O_RDONLY, segs(segid)); + if (f == 0) + return 1; + if (prepseg(f, r->segp)) { + fclose(f); return 1; } - if (!getsegid(r->arch, b->seg)) { - logs("W block %s in deleted segment", hmacs(hmac)); + if (r->segf != 0) + fclose(r->segf); + r->segf = f; + r->segno = segno; + return 0; +} + +static int +readblock(Reader *r, hmac_t hmac, Block *b, Slice *ps) +{ + hmac_t bhmac; + Slice s; + uchar *segid, *segp; + FILE *segf; + vlong off; + int len, err; + + if (cget(&r->arch->cache, hmac, b) + || (segid = getsegid(r->arch, b->seg)) == 0) { + logs("E block %s not found", hmacs(hmac)); return 1; } + off = b->off; + len = b->len; - if (!r->segf || r->segno != b->seg) { - if (r->segf) - fclose(r->segf); - seg = segs(getsegid(r->arch, b->seg)); - f = fopenat(r->arch->fd, O_RDONLY, seg); - r->segf = f; - r->segno = b->seg; - if (!f) - goto error; - if (fread(buf, sizeof buf, 1, f) != 1) + if (r->segf == 0 || r->segno != b->seg) + if (openseg(r, segid, b->seg)) { + logs("E cannot open segment"); goto error; - assert(key.mastersec); - crypto_box_beforenm(r->segpre, buf + Magicsz, key.mastersec); - } + } + segf = r->segf; + segp = r->segp; - if (fseek(r->segf, Seghdsz + b->off, SEEK_SET)) - goto error; - if (creadp(r->segf, r->segpre, b->off, b->len)) + if (fseek(segf, Seghdsz + off, SEEK_SET) == -1) goto error; if (b->lz4) { - src = (char*)plain + Plnpad; - dst = (char*)inflate; - decomp = LZ4_decompress_safe(src, dst, b->len, Maxblk); - if (decomp < 0) { - logs("E lz4 decompression failure"); - goto error; - } - *data = inflate; - *blen = decomp; - } else { - *data = plain + Plnpad; - *blen = b->len; + s = newsl(); + err = decrypt(&s, segf, len, segp, off); + err = err || slinflate(ps, s); + freesl(s); + } else + err = decrypt(ps, segf, len, segp, off); + if (err) { + logs("E decrypt/inflate failed"); + goto error; } - assert(key.hmac); - hmac_blake3(key.hmac, Keysz, *data, *blen, check); - if (memcmp(hmac, check, Hmacsz) != 0) { + slhmac(*ps, bhmac); + if (ps->len != len + || memcmp(hmac, bhmac, Hmacsz) != 0) { logs("E corrupt block"); goto error; } @@ -365,13 +395,8 @@ readblock(Reader *r, hmac_t hmac, Block *b, uchar **data, long *blen) return 0; error: - seg = segs(getsegid(r->arch, b->seg)); logs("E read failed for %s", hmacs(hmac)); - logs("E at %s off:%lld len:%d", seg, b->off, b->len); - if (r->segf) { - fclose(r->segf); - r->segf = 0; - } + logs("E at %s off:%lld len:%d", segs(segid), off, len); return 1; } @@ -379,16 +404,15 @@ static int readlevel(Reader *rd, hmac_t hmac, Ilevel *l) { Block b; - uchar *data; - long blen; + Slice s; + int err; - if (readblock(rd, hmac, &b, &data, &blen)) - return 1; - if (getlevel(l, data, blen)) { + s = newsl(); + err = readblock(rd, hmac, &b, &s); + if (!err && (err = declevel(l, s))) logs("E invalid level %s", hmacs(hmac)); - return 1; - } - return 0; + freesl(s); + return err; } void @@ -405,9 +429,11 @@ readerstart(Reader *r, Addr *addr, vlong off) Ientry *ent; hmac_t hmac; + assert(key.sec); + r->pos1 = 0; r->pos = 0; - hmaccpy(r->hmac0, (hmac_t){0}); + memset(r->hmac0, 0, Hmacsz); l = r->level; l[0].nent = 0; l[1].nent = 0; @@ -490,30 +516,28 @@ readerseek(Reader *r, vlong pos) } int -reader(Reader *r, uchar **data, long *len) +reader(Reader *r, Slice *s) { - Ientry *e; - vlong pos; Block b; - long n, blen; + vlong pos; + long n; + Ientry *e; if (readerseek(r, r->pos)) return 1; pos = r->pos1; e = findentry(&r->level[0], &pos, r->pos); - - if (readblock(r, e->hmac, &b, data, &blen)) + if (readblock(r, e->hmac, &b, s)) return 1; - if (r->pos >= pos + blen) { - *len = 0; - *data = 0; + if (r->pos >= pos + b.len) { + s->len = 0; return 0; } - n = r->pos - pos; - *data += n; - *len = blen - n; - - r->pos += *len; + if (n != 0) { + s->len -= n; + memmove(s->buf, s->buf + n, s->len); + } + r->pos += s->len; return 0; } diff --git a/sdar/cache.c b/sdar/cache.c index a44cc5e..b3bb4fd 100644 --- a/sdar/cache.c +++ b/sdar/cache.c @@ -14,23 +14,23 @@ static uchar cachemagic[4] = { }; int -cinit(Cache *c, int afd, char *path, int new) +cinit(Cache *c, int afd, char *path, int create) { int flags, fd; c->meta = 0; flags = O_RDWR; - if (new) + if (create) flags |= O_CREAT|O_TRUNC; fd = openat(afd, path, flags, Permf); if (fd == -1) return 1; - if (mmhmap(&c->hash, fd, new) == -1) { + if (mmhmap(&c->hash, fd, create) == -1) { close(fd); return 1; } c->meta = mmhhdr(&c->hash); - if (new) + if (create) creset(c); if (memcmp(c->meta->magic, cachemagic, 4) != 0) { logs("E invalid cache file %s", path); diff --git a/sdar/crypt.c b/sdar/crypt.c deleted file mode 100644 index a7f8465..0000000 --- a/sdar/crypt.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "all.h" -#include <stdio.h> -#include <string.h> -#include <crypto_box.h> - -MAKESURE(nacl_nonce_len_is_Noncesz, crypto_box_NONCEBYTES == Noncesz); -MAKESURE(nacl_pubkey_len_is_Keysz, crypto_box_PUBLICKEYBYTES == Keysz); -MAKESURE(nacl_seckey_len_is_Keysz, crypto_box_SECRETKEYBYTES == Keysz); -MAKESURE(nacl_plain_pad_is_Plnpad, crypto_box_ZEROBYTES == Plnpad); -MAKESURE(nacl_cipher_pad_is_Cippad, crypto_box_BOXZEROBYTES == Cippad); -MAKESURE(nacl_prep_len_is_Prepsz, crypto_box_BEFORENMBYTES == Prepsz); -MAKESURE(cipher_pad_leq_plain_pad, Cippad <= Plnpad); - -uchar plain[Plnpad + Maxblk]; -uchar cipher[Plnpad + Maxblk]; - -static void -noncegen(uchar *dst, vlong i) -{ - memset(dst, 0, Noncesz); - enc64be(dst, dec64be(dst) + (uvlong)i); -} - -char * -cread(FILE *f, uchar *sendkey, vlong nonceidx, long sz) -{ - uchar prep[Prepsz]; - - assert(key.mastersec); - - crypto_box_beforenm(prep, sendkey, key.mastersec); - return creadp(f, prep, nonceidx, sz); -} - -char * -creadp(FILE *f, uchar *prep, vlong nonceidx, long sz) -{ - uchar nonce[Noncesz]; - long cryptsz; - - if (Plnpad + sz > sizeof cipher) - return "too big"; - - cryptsz = (Plnpad - Cippad) + sz; - if ((long)fread(cipher + Cippad, 1, cryptsz, f) != cryptsz) - return "could not read file"; - sz += Plnpad; - - memset(cipher, 0, Cippad); - noncegen(nonce, nonceidx); - if (crypto_box_open_afternm(plain, cipher, sz, nonce, prep) != 0) - return "decryption failure"; - - return 0; -} - -char * -cwritep(FILE *f, uchar *prep, vlong nonceidx, uchar *buf, long sz) -{ - uchar nonce[Noncesz]; - - assert(key.masterpub); - assert(sz >= Plnpad); - - if (sz > sizeof cipher) - return "too big"; - - memset(buf, 0, Plnpad); - noncegen(nonce, nonceidx); - crypto_box_afternm(cipher, buf, sz, nonce, prep); - - sz -= Cippad; - if ((long)fwrite(&cipher[Cippad], 1, sz, f) != sz) - return "could not write file"; - - return 0; -} diff --git a/sdar/hmac.c b/sdar/hmac.c deleted file mode 100644 index d68723e..0000000 --- a/sdar/hmac.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "all.h" -#include <blake3.h> - -void -hmac_blake3(uchar *key, long nk, uchar *buf, long sz, hmac_t hmac) -{ - blake3_hasher bh; - - assert(nk == BLAKE3_KEY_LEN); - blake3_hasher_init_keyed(&bh, key); - blake3_hasher_update(&bh, buf, sz); - blake3_hasher_finalize(&bh, hmac, 32); -} @@ -27,18 +27,18 @@ static uchar keymagic[Magicsz] = { Key key; static uchar hmac[Keysz]; -static uchar masterpub[Keysz]; -static uchar mastersec[Plnpad + Keysz]; +static uchar pub[Keysz]; +static uchar sec[Plnpad + Keysz]; void keygen() { randombytes(hmac, Keysz); - crypto_box_keypair(masterpub, mastersec + Plnpad); + crypto_box_keypair(pub, sec + Plnpad); key.hmac = hmac; - key.masterpub = masterpub; - key.mastersec = mastersec + Plnpad; + key.pub = pub; + key.sec = sec + Plnpad; } void @@ -49,8 +49,8 @@ keydump() vlong off; } *p, parts[] = { { "hmac: ", offsetof(Key, hmac) }, - { "masterpub: ", offsetof(Key, masterpub) }, - { "mastersec: ", offsetof(Key, mastersec) }, + { "pub: ", offsetof(Key, pub) }, + { "sec: ", offsetof(Key, sec) }, {0} }; uchar *k; @@ -69,9 +69,9 @@ keydump() enum { Osalt = Magicsz, Ohmackey = Osalt + Saltsz, - Omasterpub = Ohmackey + Keysz, - Omastersec = Omasterpub + Keysz, - Oend = Omastersec + (Plnpad - Cippad) + Keysz, + Opub = Ohmackey + Keysz, + Osec = Opub + Keysz, + Oend = Osec + (Plnpad - Cippad) + Keysz, }; int @@ -82,21 +82,21 @@ keywrite(char *p, long np, FILE *f) uchar buf[Oend]; int ret; - assert(key.mastersec); + assert(key.sec); memcpy(buf, keymagic, Magicsz); randombytes(buf + Osalt, Saltsz); memcpy(buf + Ohmackey, key.hmac, Keysz); - memcpy(buf + Omasterpub, key.masterpub, Keysz); + memcpy(buf + Opub, key.pub, Keysz); - ret = crypto_scrypt((uint8_t*)p, np, buf + Osalt, Saltsz, + ret = scrypt((uint8_t*)p, np, buf + Osalt, Saltsz, ScryptN, Scryptr, Scryptp, nk, sizeof nk); if (ret != 0) return 1; - memset(mastersec, 0, Plnpad); - crypto_secretbox(cip, mastersec, Plnpad + Keysz, nk, nk + Noncesz); - memcpy(buf + Omastersec, cip + Cippad, Oend - Omastersec); + memset(sec, 0, Plnpad); + crypto_secretbox(cip, sec, Plnpad + Keysz, nk, nk + Noncesz); + memcpy(buf + Osec, cip + Cippad, Oend - Osec); return (fwrite(buf, Oend, 1, f) != 1); } @@ -113,10 +113,10 @@ keyreadpub(FILE *f) return "invalid key file"; memcpy(hmac, buf + Ohmackey, Keysz); - memcpy(masterpub, buf + Omasterpub, Keysz); + memcpy(pub, buf + Opub, Keysz); key.hmac = hmac; - key.masterpub = masterpub; + key.pub = pub; return 0; } @@ -136,23 +136,23 @@ keyreadsec(char *p, long np, FILE *f) return "invalid key file"; memcpy(hmac, buf + Ohmackey, Keysz); - memcpy(masterpub, buf + Omasterpub, Keysz); + memcpy(pub, buf + Opub, Keysz); - ret = crypto_scrypt((uint8_t*)p, np, buf + Osalt, Saltsz, + ret = scrypt((uint8_t*)p, np, buf + Osalt, Saltsz, ScryptN, Scryptr, Scryptp, nk, sizeof nk); if (ret != 0) return "out of memory"; - memcpy(cip + Cippad, buf + Omastersec, Oend - Omastersec); + memcpy(cip + Cippad, buf + Osec, Oend - Osec); memset(cip, 0, Cippad); - ret = crypto_secretbox_open(mastersec, cip, Plnpad + Keysz, + ret = crypto_secretbox_open(sec, cip, Plnpad + Keysz, nk, nk + Noncesz); if (ret != 0) return "decryption failed"; key.hmac = hmac; - key.masterpub = masterpub; - key.mastersec = mastersec + Plnpad; + key.pub = pub; + key.sec = sec + Plnpad; return 0; } diff --git a/sdar/lib/crypto/scrypt.c b/sdar/lib/crypto/scrypt.c index 3f53e0a..730321c 100644 --- a/sdar/lib/crypto/scrypt.c +++ b/sdar/lib/crypto/scrypt.c @@ -35,7 +35,7 @@ #include <sys/mman.h> /** - * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, * p, buflen) and write the result into buf. The parameters r, p, and buflen * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N @@ -44,7 +44,7 @@ * Return 0 on success; or -1 on error. */ int -crypto_scrypt(uint8_t * passwd, size_t passwdlen, +scrypt(uint8_t * passwd, size_t passwdlen, uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, uint8_t * buf, size_t buflen) { @@ -123,7 +123,7 @@ crypto_scrypt(uint8_t * passwd, size_t passwdlen, /* 2: for i = 0 to p - 1 do */ for (i = 0; i < p; i++) { /* 3: B_i <-- MF(B_i, N) */ - crypto_scrypt_smix(&B[i * 128 * r], r, N, V, XY); + scrypt_smix(&B[i * 128 * r], r, N, V, XY); } /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ @@ -178,12 +178,12 @@ static struct scrypt_test { }; int -crypto_scrypt_test() +scrypt_test() { uint8_t hbuf[TESTLEN]; /* Perform the computation. */ - if (crypto_scrypt( + if (scrypt( (uint8_t *)testcase.passwd, strlen(testcase.passwd), (uint8_t *)testcase.salt, strlen(testcase.salt), testcase.N, testcase.r, testcase.p, hbuf, TESTLEN)) diff --git a/sdar/lib/crypto/smix.c b/sdar/lib/crypto/smix.c index 9166d2e..f2a955b 100644 --- a/sdar/lib/crypto/smix.c +++ b/sdar/lib/crypto/smix.c @@ -143,7 +143,7 @@ integerify(const void * B, size_t r) } /** - * crypto_scrypt_smix(B, r, N, V, XY): + * scrypt_smix(B, r, N, V, XY): * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; * the temporary storage V must be 128rN bytes in length; the temporary * storage XY must be 256r + 64 bytes in length. The value N must be a @@ -151,7 +151,7 @@ integerify(const void * B, size_t r) * multiple of 64 bytes. */ void -crypto_scrypt_smix(uint8_t * B, size_t r, uint64_t N, void * _V, void * XY) +scrypt_smix(uint8_t * B, size_t r, uint64_t N, void * _V, void * XY) { uint32_t * X = XY; uint32_t * Y = (void *)((uint8_t *)(XY) + 128 * r); diff --git a/sdar/main.c b/sdar/main.c index 83da93e..b23f933 100644 --- a/sdar/main.c +++ b/sdar/main.c @@ -13,8 +13,7 @@ #include <unistd.h> enum { - /* length of an address as a string */ - Addrsz = 1 + 2*Hmacsz, + Addrsz = 1 + 2 * Hmacsz, /* length of an address as a string */ }; uchar iobuf[Maxblk]; @@ -103,7 +102,7 @@ readpass(char *prefix, int *interact) memcpy(&new, &old, sizeof new); new.c_lflag &= ~ECHO; tcsetattr(fd, TCSANOW, &new); - for (i = 0; i < sizeof buf - 1; i++) { + for (i = 0; i < (int)sizeof buf - 1; i++) { n = read(fd, buf+i, 1); if (n <= 0 || buf[i] == '\n') break; @@ -261,7 +260,7 @@ pkt(char *msg, ...) va_start(vl, msg); n = vsnprintf(buf, sizeof buf, msg, vl); va_end(vl); - assert(n < sizeof buf); + assert(n < (int)sizeof buf); printf("%02x%s\n", n+1, buf); } @@ -269,23 +268,25 @@ static int addbatch(Arch *a) { char buf[65] = {0}; + Slice s; int rc, werr, lz4; - vlong sz, rd; - uchar *blk; + vlong n, len; hmac_t hmac; Addr addr; + s = newsl(); pkt("ready"); rc = 0; - blk = plain + Plnpad; for (;;) { fflush(stdout); - sz = fread(buf, 6, 1, stdin); - if (sz == 0) + n = fread(buf, 6, 1, stdin); + if (n == 0) { + freesl(s); return rc; - if (sz != 1) + } + if (n != 1) goto error; if (memcmp(buf+2, "blk ", 4) == 0) { @@ -299,12 +300,12 @@ addbatch(Arch *a) goto error; getchar(); - if (readnum(&sz, stdin) - || sz > Maxblk - || (sz > 0 && fread(blk, sz, 1, stdin) != 1)) + if (readnum(&len, stdin) + || len > Maxblk + || (len > 0 && slread(&s, len, stdin))) goto error; - if (stashblk(a, hmac, lz4, blk, sz)) { + if (stashblk(a, hmac, lz4, s)) { pkt("err"); rc = 1; } else @@ -316,17 +317,17 @@ addbatch(Arch *a) if (memcmp(buf+2, "raw ", 4) != 0) goto error; - if (readnum(&sz, stdin)) + if (readnum(&len, stdin)) goto error; werr = 0; - while (sz > 0) { - rd = min(sz, sizeof iobuf); - rd = fread(iobuf, 1, rd, stdin); - sz -= rd; - if (rd == 0) + while (len > 0) { + n = min(len, (long)sizeof iobuf); + n = fread(iobuf, 1, n, stdin); + len -= n; + if (n == 0) goto error; - if (!werr && stashadd(a, iobuf, rd)) + if (!werr && stashadd(a, iobuf, n)) werr = 1; } @@ -340,6 +341,7 @@ addbatch(Arch *a) error: err("batch protocol error"); + freesl(s); return 1; } @@ -443,7 +445,7 @@ idbatch(Writer *w) { Addr a; char cmd[6]; - vlong sz, rd; + vlong n, len; int werr, rc; pkt("ready"); @@ -451,10 +453,10 @@ idbatch(Writer *w) werr = 0; for (;;) { fflush(stdout); - sz = fread(cmd, 6, 1, stdin); - if (sz == 0) + n = fread(cmd, 6, 1, stdin); + if (n == 0) return rc; - if (sz != 1) + if (n != 1) goto error; if (memcmp(cmd+2, "end\n", 4) == 0) { @@ -473,15 +475,15 @@ idbatch(Writer *w) goto error; /* write more data in w */ - if (readnum(&sz, stdin)) + if (readnum(&len, stdin)) goto error; - while (sz > 0) { - rd = min(sz, sizeof iobuf); - rd = fread(iobuf, 1, rd, stdin); - sz -= rd; - if (rd == 0) + while (len > 0) { + n = min(len, (long)sizeof iobuf); + n = fread(iobuf, 1, n, stdin); + len -= n; + if (n == 0) goto error; - if (!werr && writer(w, iobuf, rd)) + if (!werr && writer(w, iobuf, n)) werr = 1; } } @@ -539,24 +541,23 @@ parseaddr(char *s, Addr *a) static int readdata(Reader *rd, Addr *addr, vlong off, vlong len, int batch) { - uchar *buf; - long sz; + Slice s; if (readerstart(rd, addr, off)) return 1; do { - if (reader(rd, &buf, &sz)) + if (reader(rd, &s)) return 1; - if (!sz) + if (!s.len) break; if (len > 0) { - if (sz > len) - sz = len; - len -= sz; + if (s.len > len) + s.len = len; + len -= s.len; } if (batch) - pkt("raw %ld", sz); - fwrite(buf, 1, sz, stdout); + pkt("raw %ld", s.len); + fwrite(s.buf, 1, s.len, stdout); } while (len != 0); return 0; } @@ -564,11 +565,12 @@ readdata(Reader *rd, Addr *addr, vlong off, vlong len, int batch) static int readbatch(Reader *rd) { - char buf[Addrsz+1+20+1+20+1+1] = {0}, *cur; + char buf[Addrsz+1+20+1+20+1+1], *cur; vlong off, len; Addr addr; uchar n; + memset(buf, 0, sizeof buf); pkt("ready"); for (;;) { fflush(stdout); @@ -694,20 +696,24 @@ cmd_update(int argc, char *argv[]) } static int -emitblock(Block *b, hmac_t hmac, uchar *key, void *arg) +emitblock(Block *b, hmac_t hmac, uchar segp[Prepsz], void *arg) { - FILE *data; + Slice s; + FILE *f; - data = arg; - if (fseek(data, Seghdsz + b->off, SEEK_SET)) + f = arg; + if (fseek(f, Seghdsz + b->off, SEEK_SET) == 1) return 1; - if (cread(data, key, b->off, b->len)) { + s = newsl(); + if (decrypt(&s, f, b->len, segp, b->off)) { logs("E could not read block"); err("could not read block"); + freesl(s); return 1; } pkt("blk %d %s %d", b->lz4, hmacs(hmac), b->len); - fwrite(plain + Plnpad, 1, b->len, stdout); + fwrite(s.buf, 1, b->len, stdout); + freesl(s); return 0; } @@ -789,7 +795,7 @@ openlog() exit(1); } n = snprintf(buf, sizeof buf, "%s/.sdar.log", p); - if (n >= sizeof buf) { + if (n >= (int)sizeof buf) { err("log path too long"); exit(1); } diff --git a/sdar/sdar.1 b/sdar/sdar.1 deleted file mode 100644 index 069d350..0000000 --- a/sdar/sdar.1 +++ /dev/null @@ -1,20 +0,0 @@ -.TH sdar 1 -.SH NAME -sdar \- implements secure deduplicated archives -.SH SYNOPSIS -.B sdar -.RB [ \-p -.IR passphrase ] -.SH DESCRIPTION -.B sdar -creates and updates encrypted archives. -.SH OPTIONS -.TP -.B \-p " passphrase" -the archive key's -.I passphrase -.SH AUTHORS -Quentin Carbonneaux <quentin@c9x.me> -.SH SEE ALSO -.BR ar (1) -.BR tarsnap (1) diff --git a/sdar/slice.c b/sdar/slice.c new file mode 100644 index 0000000..c2ecc18 --- /dev/null +++ b/sdar/slice.c @@ -0,0 +1,158 @@ +#include "all.h" +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <blake3.h> +#include <crypto_box.h> +#include <lz4.h> + +/* module wrapping buffer allocation, crypto, + * and compression functions in a uniform api */ + +enum { + Nstk = 4, + Bufdat = LZ4_COMPRESSBOUND(Maxblk), +}; + +MAKESURE(Noncesz, crypto_box_NONCEBYTES == Noncesz); +MAKESURE(Keysz0, crypto_box_PUBLICKEYBYTES == Keysz); +MAKESURE(Keysz1, crypto_box_SECRETKEYBYTES == Keysz); +MAKESURE(Keysz2, BLAKE3_KEY_LEN == Keysz); +MAKESURE(Plnpad, crypto_box_ZEROBYTES == Plnpad); +MAKESURE(Cippad, crypto_box_BOXZEROBYTES == Cippad); +MAKESURE(Prepsz, crypto_box_BEFORENMBYTES == Prepsz); +MAKESURE(Plncip, Plnpad >= Cippad); +MAKESURE(Bufpad0, (int)Bufpad >= (int)Plnpad); +MAKESURE(Bufpad1, (int)Bufpad >= (int)Cippad); +MAKESURE(Bufpad2, (Bufpad & 7) == 0); + +static uchar bstk[Nstk][Bufpad + Bufdat]; +static int bid; + +Slice +mksl(uchar *buf, long len) +{ + /* + * it is required that Bufpad bytes + * are available right before the + * buf pointer + */ + return (Slice){buf, len}; +} + +/* buffers life cycle must adhere to a + * stack discipline */ +Slice +newsl() +{ + uchar *buf; + + if (bid == Nstk) { + logs("E out of buffers!"); + abort(); + } + buf = &bstk[bid++][Bufpad]; + return (Slice){buf, 0}; +} + +void +freesl(Slice s) +{ + bid--; + assert(s.buf == &bstk[bid][Bufpad]); +} + +void +slencryptp(Slice *sc, Slice sp, uchar prep[Prepsz], vlong nonce) +{ + uchar nbuf[Noncesz] = {0}; + + memset(sp.buf - Plnpad, 0, Plnpad); + enc64be(nbuf, nonce); + crypto_box_afternm( + sc->buf - Cippad, sp.buf - Plnpad, + sp.len + Plnpad, nbuf, prep); + sc->len = sp.len + Cipovh; +} + +int +sldecryptp(Slice *sp, Slice sc, uchar prep[Prepsz], vlong nonce) +{ + uchar nbuf[Noncesz] = {0}; + + memset(sc.buf - Cippad, 0, Cippad); + enc64be(nbuf, nonce); + if (crypto_box_open_afternm( + sp->buf - Plnpad, sc.buf - Cippad, + sc.len + Cippad, nbuf, prep) != 0) + return 1; + sp->len = sc.len - Cipovh; + return 0; +} + +int +decrypt(Slice *s, FILE *f, long sz, uchar prep[Prepsz], vlong nonce) +{ + Slice sr; + int err; + + sr = newsl(); + if ((err = slread(&sr, Cipovh + sz, f)) == 0) + err = sldecryptp(s, sr, prep, nonce); + freesl(sr); + return err; +} + +void +slhmac(Slice s, hmac_t hmac) +{ + blake3_hasher bh; + + assert(key.hmac); + blake3_hasher_init_keyed(&bh, key.hmac); + blake3_hasher_update(&bh, s.buf, s.len); + blake3_hasher_finalize(&bh, hmac, 32); +} + +void +sldeflate(Slice *sd, Slice si) +{ + sd->len = LZ4_compress_default( + (char*)si.buf, (char*)sd->buf, + si.len, Bufdat); + assert(sd->len != 0); +} + +int +slinflate(Slice *si, Slice sd) +{ + int sz; + + sz = LZ4_decompress_safe( + (char*)sd.buf, (char*)si->buf, + sd.len, Bufdat); + if (sz < 0) + return 1; + si->len = sz; + return 0; +} + +int +slwrite(Slice s, FILE *f) +{ + long n; + + n = fwrite(s.buf, 1, s.len, f); + return n != s.len; +} + +int +slread(Slice *s, long sz, FILE *f) +{ + long n; + + n = fread(s->buf, 1, sz, f); + s->len = n; + return n != sz; +} diff --git a/sdar/stash.c b/sdar/stash.c index bdd6354..12abf67 100644 --- a/sdar/stash.c +++ b/sdar/stash.c @@ -1,5 +1,4 @@ #include "all.h" -#include <errno.h> #include <stdio.h> #include <string.h> #include <fcntl.h> @@ -8,73 +7,62 @@ #include <sys/time.h> #include <unistd.h> #include <crypto_box.h> -#include <lz4.h> MAKESURE(Segidsz_is_ok, Segidsz <= Keysz); -static flushcb flushblock; +static flushcb flushblk; int stashinit(Arch *a) { - uchar seckey[Keysz]; + uchar sec[Keysz]; struct stat sb; - vlong sz, pg; - int log, flags; Loghd *h; + int fd; - assert(!a->log); - writerinit(&a->writer, flushblock, a); - - flags = O_CREAT|O_RDWR; - log = openat(a->fd, "stash/log", flags, Permf); - if (log == -1) + if (a->log != 0) return 1; - flags = PROT_READ|PROT_WRITE; - pg = sysconf(_SC_PAGESIZE); - h = mmap(0, pg, flags, MAP_SHARED, log, 0); + writerinit(&a->writer, flushblk, a); + a->log = fopenat(a->fd, O_CREAT|O_RDWR, "stash/log"); + a->data = fopenat(a->fd, O_CREAT|O_RDWR, "stash/data"); + if (a->log == 0 || a->data == 0) + goto error; + + fd = fileno(a->log); + h = mmap(0, sizeof(Loghd), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (h == MAP_FAILED) goto error; - if (fstat(log, &sb) == -1) + if (fstat(fd, &sb) == -1) goto error1; - sz = sb.st_size; - - if (sz < sizeof *h) { - if (ftruncate(log, sizeof *h) == -1) + if (sb.st_size < (int)sizeof(Loghd)) { + if (ftruncate(fd, sizeof(Loghd)) == -1) goto error1; - crypto_box_keypair(h->kpub, seckey); - crypto_box_beforenm(h->kpre, key.masterpub, seckey); + crypto_box_keypair(h->segk, sec); + crypto_box_beforenm(h->segp, key.pub, sec); h->nitem = 0; h->dlen = 0; - msync(h, sizeof *h, MS_SYNC); + msync(h, sizeof(Loghd), MS_SYNC); } - a->log = fdopen(log, "w+"); - if (!a->log) + if (fseek(a->log, 0, SEEK_END) == -1) + goto error1; + if (fseek(a->data, 0, SEEK_END) == -1) goto error1; - log = -1; - - if (fseek(a->log, 0, SEEK_END)) - goto error2; - - flags = O_CREAT|O_RDWR|O_APPEND; - a->data = fopenat(a->fd, flags, "stash/data"); - if (!a->data) - goto error2; a->logh = h; return 0; -error2: - fclose(a->log); - a->log = 0; error1: munmap(h, sizeof(Loghd)); error: - if (log != -1) - close(log); + if (a->data) + fclose(a->data); + if (a->log) + fclose(a->log); + a->data = 0; + a->log = 0; return 1; } @@ -87,17 +75,15 @@ stashadd(Arch *a, uchar *buf, vlong sz) int stashsync(Arch *a) { - int rc; - - rc = 0; - rc |= (msync(a->logh, sizeof(Loghd), MS_SYNC) == -1); - rc |= (fflush(a->log) == EOF); - rc |= (fsync(fileno(a->log)) == -1); - rc |= (fflush(a->data) == EOF); - rc |= (fsync(fileno(a->data)) == -1); - if (rc) + int err; + + err = 0; + err |= msync(a->logh, sizeof(Loghd), MS_SYNC) == -1; + err |= flushsync(a->log); + err |= flushsync(a->data); + if (err) logs("E error while syncing stash"); - return rc; + return err; } int @@ -107,58 +93,64 @@ stashdone(Arch *a, Addr *addr) } static int -flushraw(Arch *a, hmac_t hmac, int lz4, uchar *buf, int sz) +flushraw(Arch *a, hmac_t hmac, int lz4, Slice s) { - uchar item[Hmacsz + 4]; + uchar item[Segitemsz]; + Slice sc; Loghd *h; h = a->logh; - if (cwritep(a->data, h->kpre, h->dlen, buf - Plnpad, sz + Plnpad)) + sc = newsl(); + + slencryptp(&sc, s, h->segp, h->dlen); + if (slwrite(sc, a->data)) goto ioerror; hmaccpy(item, hmac); - enc32be(item + Hmacsz, lz4 | sz << 1); - if (fwrite(item, Hmacsz + 4, 1, a->log) != 1) + enc32be(item + Hmacsz, lz4 | s.len << 1); + if (fwrite(item, Segitemsz, 1, a->log) != 1) goto ioerror; h->nitem++; - h->dlen += sz + (Plnpad - Cippad); + h->dlen += sc.len; + + freesl(sc); return 0; ioerror: logs("E io error while writing to stash"); + freesl(sc); return 1; } /* adds a block directly to the stash; - * we will check if the provided hmac - * is correct and if the block size is - * fine */ + * we will check that the provided hmac + * is correct and that the block size + * is fine */ int -stashblk(Arch *a, hmac_t hmac, int lz4, uchar *buf, int sz) +stashblk(Arch *a, hmac_t hmac, int lz4, Slice sb) { - char *src, *dst; - hmac_t check; - uchar *dbuf; - int dsz; + hmac_t bhmac; + Slice s; + int bsz; if (lz4) { - src = (char*)buf; - dst = (char*)inflate; - dsz = LZ4_decompress_safe(src, dst, sz, Maxblk); - if (dsz < 0) + s = newsl(); + if (slinflate(&s, sb)) { + freesl(s); return 1; - dbuf = inflate; + } + bsz = s.len; + slhmac(s, bhmac); + freesl(s); } else { - dbuf = buf; - dsz = sz; + slhmac(sb, bhmac); + bsz = sb.len; } - if (dsz > Maxblk) - return 1; - assert(key.hmac); - hmac_blake3(key.hmac, Keysz, dbuf, dsz, check); - if (memcmp(hmac, check, Hmacsz) != 0) { + if (bsz > Maxblk) + return 1; + if (memcmp(hmac, bhmac, Hmacsz) != 0) { logs("E invalid block hmac %s", hmacs(hmac)); return 1; } @@ -166,115 +158,127 @@ stashblk(Arch *a, hmac_t hmac, int lz4, uchar *buf, int sz) if (archhas(a, hmac)) return 0; - return flushraw(a, hmac, lz4, buf, sz); + return flushraw(a, hmac, lz4, sb); } static int -flushblock(void *arg, hmac_t hmac, uchar *buf, int sz) +flushblk(void *arg, hmac_t hmac, Slice sb) { - static uchar deflate[Plnpad + LZ4_COMPRESSBOUND(Maxblk)]; - char *dst; - int compsz, dstsz; + Slice sd; + int err; Arch *a; a = arg; if (archhas(a, hmac)) return 0; - /* we may also want to dedup within the stash */ - - dst = (char*)deflate + Plnpad; - dstsz = sizeof deflate - Plnpad; - compsz = LZ4_compress_default((char*)buf, dst, sz, dstsz); - if (compsz && compsz < sz) { - buf = deflate + Plnpad; - sz = compsz; - } else - compsz = 0; - - return flushraw(a, hmac, (compsz != 0), buf, sz); + /* TODO: we may also want to dedup within the stash */ + + sd = newsl(); + sldeflate(&sd, sb); + if (sd.len < sb.len) + err = flushraw(a, hmac, 1, sd); + else + err = flushraw(a, hmac, 0, sb); + freesl(sd); + return err; } static int -writeseg(Arch *a, char *msg, FILE *segf) +writeseg(Arch *a, char *msg, FILE *f) { - vlong ni, sz, idx, nleft, total; struct timeval tv; - Segmeta meta; + Slice sb, sc; + Segmeta m; + vlong len, idx; + int err, n; Loghd *h; + err = 1; h = a->logh; - if (fwrite(segmagic, Magicsz, 1, segf) != 1) - return 1; - if (fwrite(h->kpub, Keysz, 1, segf) != 1) - return 1; + sb = newsl(); + sc = newsl(); - meta.nitem = h->nitem; - meta.dlen = h->dlen; - meta.date = 0; - if (gettimeofday(&tv, 0) == 0) - meta.date = tv.tv_sec; - strncpy(meta.msg, msg, sizeof meta.msg - 1); - encmeta(plain + Plnpad, &meta); - idx = -1; - if (cwritep(segf, h->kpre, idx, plain, Plnpad + Segmetasz)) - return 1; + if (fwrite(segmagic, Magicsz, 1, f) != 1) + goto out; + if (fwrite(h->segk, Keysz, 1, f) != 1) + goto out; - if (fseek(a->data, 0, SEEK_SET)) - return 1; - total = 0; - while ((sz = fread(iobuf, 1, sizeof iobuf, a->data))) { - if ((vlong)fwrite(iobuf, 1, sz, segf) != sz) - return 1; - total += sz; + memset(&m, 0, sizeof(Segmeta)); + m.nitem = h->nitem; + m.dlen = h->dlen; + if (gettimeofday(&tv, 0) == 0) + m.date = tv.tv_sec; + strncpy(m.msg, msg, sizeof m.msg - 1); + encmeta(&sb, &m); + + slencryptp(&sc, sb, h->segp, -1); + if (slwrite(sc, f)) + goto out; + + if (fseek(a->data, 0, SEEK_SET) == -1) + goto out; + for (len = 0;; len += n) { + n = fread(sb.buf, 1, Maxblk, a->data); + if (n == 0) + break; + if (fwrite(sb.buf, 1, n, f) != (size_t)n) + goto out; } - if (total != h->dlen) { - logs("E inconsistent stash, aborting commit"); - return 1; + if (len != h->dlen) { + logs("E inconsistent stash"); + goto out; } - if (fseek(a->log, sizeof(Loghd), SEEK_SET)) - return 1; - nleft = h->nitem; - while (nleft > 0) { - ni = min(nleft, Maxblk / Segitemsz); - nleft -= ni; - sz = ni * Segitemsz; - if ((vlong)fread(plain + Plnpad, 1, sz, a->log) != sz) - return 1; - idx--; - if (cwritep(segf, h->kpre, idx, plain, Plnpad + sz)) - return 1; + if (fseek(a->log, sizeof(Loghd), SEEK_SET) == -1) + goto out; + idx = -1; + len = h->nitem * Segitemsz; + while (len > 0) { + n = (Maxblk/Segitemsz) * Segitemsz; + n = min(len, n); + len -= n; + if (slread(&sb, n, a->log)) + goto out; + slencryptp(&sc, sb, h->segp, --idx); + if (slwrite(sc, f)) + goto out; } - return 0; + if (flushsync(f)) + goto out; + err = 0; +out: + freesl(sc); + freesl(sb); + return err; } static int cacheupdate(Arch *a, uchar segid[Segidsz]) { - uchar it[Segitemsz]; - vlong n; - Cachemeta *m; + uchar itm[Segitemsz]; Block b = {0}; + Cachemeta *m; + vlong n; m = a->cache.meta; b.seg = ++m->nseg; if (cputseg(&a->cache, segid, b.seg)) return 1; - if (fseek(a->log, sizeof(Loghd), SEEK_SET)) + if (fseek(a->log, sizeof(Loghd), SEEK_SET) == -1) return 1; for (n = a->logh->nitem; n > 0; n--) { - if (fread(it, Segitemsz, 1, a->log) != 1) + if (fread(itm, Segitemsz, 1, a->log) != 1) return 1; - decitem(it, &b); - if (cput(&a->cache, it, &b)) { + decitem(itm, &b); + if (cput(&a->cache, itm, &b)) { logs("E cannot write to cache"); return 1; } - b.off += b.len + (Plnpad - Cippad); + b.off += b.len + Cipovh; } return 0; } @@ -282,44 +286,36 @@ cacheupdate(Arch *a, uchar segid[Segidsz]) int stashcommit(Arch *a, char *msg, uchar segid[Segidsz]) { - FILE *segf; - int flags; + FILE *f; assert(a->log); - memcpy(segid, a->logh->kpub, Segidsz); + memcpy(segid, a->logh->segk, Segidsz); - flags = O_CREAT|O_EXCL|O_WRONLY; - segf = fopenat(a->fd, flags, segs(segid)); - if (!segf) { - logs("W %s already exists", segs(segid)); + f = fopenat(a->fd, O_CREAT|O_EXCL|O_WRONLY, segs(segid)); + if (f == 0) { + logs("W cannot create %s", segs(segid)); return 1; } - - if (writeseg(a, msg, segf) - || fflush(segf) == EOF - || fsync(fileno(segf)) == -1) + if (writeseg(a, msg, f)) goto error; - - /* update the cache */ if (cacheupdate(a, segid)) goto error; - /* clear the stash */ fclose(a->log); fclose(a->data); a->log = 0; a->logh = 0; a->data = 0; - if (unlinkat(a->fd, "stash/log", 0) - || unlinkat(a->fd, "stash/data", 0)) - logs("W could not unlink stash files"); + if (unlinkat(a->fd, "stash/log", 0) == -1 + || unlinkat(a->fd, "stash/data", 0) == -1) + logs("W cannot unlink stash files"); - fclose(segf); logs("I committed %s", segs(segid)); + fclose(f); return 0; error: - fclose(segf); + fclose(f); return 1; } diff --git a/sdar/util.c b/sdar/util.c index 84fa830..81b956c 100644 --- a/sdar/util.c +++ b/sdar/util.c @@ -95,7 +95,7 @@ fopenat(int afd, int flags, char *path, ...) va_start(ap, path); n = vsnprintf(buf, sizeof buf, path, ap); va_end(ap); - if (n >= sizeof buf) + if (n >= (int)sizeof buf) return 0; fd = openat(afd, buf, flags, Permf); if (fd == -1) @@ -114,6 +114,12 @@ fopenat(int afd, int flags, char *path, ...) return f; } +int +flushsync(FILE *f) +{ + return fflush(f) == EOF || fsync(fileno(f)); +} + void enc32be(uchar *p, uvlong x) { diff --git a/sdar/writer.c b/sdar/write.c index 44cd81d..501194d 100644 --- a/sdar/writer.c +++ b/sdar/write.c @@ -19,29 +19,31 @@ writerinit(Writer *w, flushcb *flush, void *arg) w->level[1].nent = 0; } -/* callers must arrange for Plnpad bytes to be available - * before the buf pointer */ static int -flush(Writer *w, uchar *buf, long sz, hmac_t hmac) +flush(Writer *w, Slice s, hmac_t hmac) { assert(key.hmac); - hmac_blake3(key.hmac, Keysz, buf, sz, hmac); + slhmac(s, hmac); if (!w->flush) return 0; - return w->flush(w->arg, hmac, buf, sz); + return w->flush(w->arg, hmac, s); } static void -putlevel(uint8_t *ptr, Ilevel *l) +enclevel(Slice *s, Ilevel *l) { Ientry *e; + uchar *p; int i; - for (i = 0, e = l->ent; i < l->nent; e++, i++) { - hmaccpy(ptr, e->hmac); - enc64be(ptr + Hmacsz, e->len); - ptr += Entrysz; + p = s->buf; + for (i = 0; i < l->nent; i++) { + e = &l->ent[i]; + hmaccpy(p, e->hmac); + enc64be(p + Hmacsz, e->len); + p += Entrysz; } + s->len = p - s->buf; } static void @@ -55,14 +57,20 @@ addentry(Ilevel *l, hmac_t hmac, vlong len) } int -getlevel(Ilevel *l, uchar *ptr, long sz) +declevel(Ilevel *l, Slice s) { - if (sz % Entrysz != 0 || sz / Entrysz > Indexsz) + uchar *p; + vlong n, len; + + p = s.buf; + n = s.len; + if (n % Entrysz != 0 || n / Entrysz > Indexsz) return 1; l->nent = 0; - for (; sz > 0; sz -= Entrysz) { - addentry(l, ptr, dec64be(ptr + Hmacsz)); - ptr += Entrysz; + for (; n > 0; n -= Entrysz) { + len = dec64be(p + Hmacsz); + addentry(l, p, len); + p += Entrysz; } return 0; } @@ -70,12 +78,15 @@ getlevel(Ilevel *l, uchar *ptr, long sz) static int flushlevel(Writer *w, Ilevel *l, hmac_t hmac) { - long sz; + Slice s; + int err; assert(l->nent > 0 && l->nent <= Indexsz); - sz = l->nent * Entrysz; - putlevel(plain + Plnpad, l); - return flush(w, plain + Plnpad, sz, hmac); + s = newsl(); + enclevel(&s, l); + err = flush(w, s, hmac); + freesl(s); + return err; } static int @@ -109,9 +120,10 @@ chunkdone(Writer *w, uchar *buf, int sz) assert(sz <= Maxblk); - /* we arranged so that there is Plnpad - * bytes available before buf */ - if (flush(w, buf, sz, hmac)) + /* we arranged so that there is Bufpad + * bytes available before buf, as + * required by mksl() */ + if (flush(w, mksl(buf, sz), hmac)) return 1; l0 = &w->level[0]; @@ -134,7 +146,7 @@ chunker(Writer *w, int sz) uint h, msk; int i, n, l, m, end; - wbuf = w->buf + Plnpad; + wbuf = w->buf + Bufpad; m = 1ull << (Avglog-1); /* min chunk size */ msk = ((uint)m - 1) << (33 - Avglog); h = w->rhash; @@ -183,18 +195,17 @@ chunker(Writer *w, int sz) } int -writer(Writer *w, uchar *buf, vlong sz) +writer(Writer *w, uchar *b, vlong nb) { int n; - while (sz > 0) { - n = sizeof w->buf - (Plnpad + w->bpos); - if (n > sz) - n = sz; - memcpy(w->buf + Plnpad + w->bpos, buf, n); - buf += n; - sz -= n; - if (chunker(w, n + w->bpos)) + while (nb > 0) { + n = sizeof w->buf - (Bufpad + w->bpos); + n = min(nb, n); + memcpy(w->buf + Bufpad + w->bpos, b, n); + b += n; + nb -= n; + if (chunker(w, w->bpos + n)) return 1; } return 0; @@ -205,7 +216,7 @@ writerdone(Writer *w, Addr *a) { Ilevel *l; - if (chunkdone(w, w->buf + Plnpad, w->bpos)) + if (chunkdone(w, w->buf + Bufpad, w->bpos)) return 1; l = w->level; |
