iInitial commit - dedup - deduplicating backup program Err bitreich.org 70 hgit clone git://bitreich.org/dedup/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/dedup/ URL:git://bitreich.org/dedup/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/dedup/ bitreich.org 70 1Log /scm/dedup/log.gph bitreich.org 70 1Files /scm/dedup/files.gph bitreich.org 70 1Refs /scm/dedup/refs.gph bitreich.org 70 1Tags /scm/dedup/tag bitreich.org 70 1README /scm/dedup/file/README.gph bitreich.org 70 1LICENSE /scm/dedup/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 1commit 72a5c2c2269c959061bfb34a05f29875653f3e92 /scm/dedup/commit/72a5c2c2269c959061bfb34a05f29875653f3e92.gph bitreich.org 70 hAuthor: sin URL:mailto:sin@2f30.org bitreich.org 70 iDate: Tue, 20 Mar 2018 16:02:29 +0000 Err bitreich.org 70 i Err bitreich.org 70 iInitial commit Err bitreich.org 70 i Err bitreich.org 70 iDiffstat: Err bitreich.org 70 i A LICENSE | 13 +++++++++++++ Err bitreich.org 70 i A arg.h | 65 +++++++++++++++++++++++++++++++ Err bitreich.org 70 i A dedup.c | 320 +++++++++++++++++++++++++++++++ Err bitreich.org 70 i Err bitreich.org 70 i3 files changed, 398 insertions(+), 0 deletions(-) Err bitreich.org 70 i--- Err bitreich.org 70 1diff --git a/LICENSE b/LICENSE /scm/dedup/file/LICENSE.gph bitreich.org 70 i@@ -0,0 +1,13 @@ Err bitreich.org 70 i+© 2018 Dimitris Papastamos Err bitreich.org 70 i+ Err bitreich.org 70 i+Permission to use, copy, modify, and distribute this software for any Err bitreich.org 70 i+purpose with or without fee is hereby granted, provided that the above Err bitreich.org 70 i+copyright notice and this permission notice appear in all copies. Err bitreich.org 70 i+ Err bitreich.org 70 i+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES Err bitreich.org 70 i+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF Err bitreich.org 70 i+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR Err bitreich.org 70 i+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES Err bitreich.org 70 i+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN Err bitreich.org 70 i+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF Err bitreich.org 70 i+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Err bitreich.org 70 1diff --git a/arg.h b/arg.h /scm/dedup/file/arg.h.gph bitreich.org 70 i@@ -0,0 +1,65 @@ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Copy me if you can. Err bitreich.org 70 i+ * by 20h Err bitreich.org 70 i+ */ Err bitreich.org 70 i+ Err bitreich.org 70 i+#ifndef ARG_H__ Err bitreich.org 70 i+#define ARG_H__ Err bitreich.org 70 i+ Err bitreich.org 70 i+extern char *argv0; Err bitreich.org 70 i+ Err bitreich.org 70 i+/* use main(int argc, char *argv[]) */ Err bitreich.org 70 i+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ Err bitreich.org 70 i+ argv[0] && argv[0][0] == '-'\ Err bitreich.org 70 i+ && argv[0][1];\ Err bitreich.org 70 i+ argc--, argv++) {\ Err bitreich.org 70 i+ char argc_;\ Err bitreich.org 70 i+ char **argv_;\ Err bitreich.org 70 i+ int brk_;\ Err bitreich.org 70 i+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\ Err bitreich.org 70 i+ argv++;\ Err bitreich.org 70 i+ argc--;\ Err bitreich.org 70 i+ break;\ Err bitreich.org 70 i+ }\ Err bitreich.org 70 i+ for (brk_ = 0, argv[0]++, argv_ = argv;\ Err bitreich.org 70 i+ argv[0][0] && !brk_;\ Err bitreich.org 70 i+ argv[0]++) {\ Err bitreich.org 70 i+ if (argv_ != argv)\ Err bitreich.org 70 i+ break;\ Err bitreich.org 70 i+ argc_ = argv[0][0];\ Err bitreich.org 70 i+ switch (argc_) Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Handles obsolete -NUM syntax */ Err bitreich.org 70 i+#define ARGNUM case '0':\ Err bitreich.org 70 i+ case '1':\ Err bitreich.org 70 i+ case '2':\ Err bitreich.org 70 i+ case '3':\ Err bitreich.org 70 i+ case '4':\ Err bitreich.org 70 i+ case '5':\ Err bitreich.org 70 i+ case '6':\ Err bitreich.org 70 i+ case '7':\ Err bitreich.org 70 i+ case '8':\ Err bitreich.org 70 i+ case '9' Err bitreich.org 70 i+ Err bitreich.org 70 i+#define ARGEND }\ Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+#define ARGC() argc_ Err bitreich.org 70 i+ Err bitreich.org 70 i+#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) Err bitreich.org 70 i+ Err bitreich.org 70 i+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ Err bitreich.org 70 i+ ((x), abort(), (char *)0) :\ Err bitreich.org 70 i+ (brk_ = 1, (argv[0][1] != '\0')?\ Err bitreich.org 70 i+ (&argv[0][1]) :\ Err bitreich.org 70 i+ (argc--, argv++, argv[0]))) Err bitreich.org 70 i+ Err bitreich.org 70 i+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ Err bitreich.org 70 i+ (char *)0 :\ Err bitreich.org 70 i+ (brk_ = 1, (argv[0][1] != '\0')?\ Err bitreich.org 70 i+ (&argv[0][1]) :\ Err bitreich.org 70 i+ (argc--, argv++, argv[0]))) Err bitreich.org 70 i+ Err bitreich.org 70 i+#define LNGARG() &argv[0][0] Err bitreich.org 70 i+ Err bitreich.org 70 i+#endif Err bitreich.org 70 1diff --git a/dedup.c b/dedup.c /scm/dedup/file/dedup.c.gph bitreich.org 70 i@@ -0,0 +1,320 @@ Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include "arg.h" Err bitreich.org 70 i+ Err bitreich.org 70 i+#define BLKSIZ 32768 Err bitreich.org 70 i+ Err bitreich.org 70 i+struct enthdr { Err bitreich.org 70 i+ uint64_t flags; Err bitreich.org 70 i+ uint64_t nents; Err bitreich.org 70 i+} __attribute__((packed)); Err bitreich.org 70 i+ Err bitreich.org 70 i+struct ent { Err bitreich.org 70 i+ uint64_t sz; Err bitreich.org 70 i+ unsigned char md[SHA256_DIGEST_LENGTH]; Err bitreich.org 70 i+ uint64_t nblks; Err bitreich.org 70 i+ uint64_t blks[]; Err bitreich.org 70 i+} __attribute__((packed)); Err bitreich.org 70 i+ Err bitreich.org 70 i+struct blk { Err bitreich.org 70 i+ unsigned char md[SHA256_DIGEST_LENGTH]; Err bitreich.org 70 i+ uint64_t sz; Err bitreich.org 70 i+ unsigned char data[BLKSIZ]; Err bitreich.org 70 i+} __attribute__((packed)); Err bitreich.org 70 i+ Err bitreich.org 70 i+struct enthdr enthdr; Err bitreich.org 70 i+int ifd; Err bitreich.org 70 i+int sfd; Err bitreich.org 70 i+int verbose; Err bitreich.org 70 i+char *argv0; Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+dump_md(const unsigned char *md, size_t len) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ size_t i; Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (i = 0; i < len; i++) Err bitreich.org 70 i+ fprintf(stderr, "%02x", md[i]); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+dump_enthdr(struct enthdr *hdr) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ uint64_t i; Err bitreich.org 70 i+ Err bitreich.org 70 i+ fprintf(stderr, "hdr->flags = %llx\n", Err bitreich.org 70 i+ (unsigned long long)hdr->flags); Err bitreich.org 70 i+ fprintf(stderr, "hdr->nents = %llx\n", Err bitreich.org 70 i+ (unsigned long long)hdr->nents); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+dump_ent(struct ent *ent) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ uint64_t i; Err bitreich.org 70 i+ Err bitreich.org 70 i+ fprintf(stderr, "ent->sz: %lld\n", (unsigned long long)ent->sz); Err bitreich.org 70 i+ fprintf(stderr, "ent->md: "); Err bitreich.org 70 i+ dump_md(ent->md, sizeof(ent->md)); Err bitreich.org 70 i+ fputc('\n', stderr); Err bitreich.org 70 i+ if (verbose) { Err bitreich.org 70 i+ fprintf(stderr, "ent->nblks: %lld\n", Err bitreich.org 70 i+ (unsigned long long)ent->nblks); Err bitreich.org 70 i+ for (i = 0; i < ent->nblks; i++) Err bitreich.org 70 i+ fprintf(stderr, "ent->blks[%lld]: %lld\n", Err bitreich.org 70 i+ (unsigned long long)i, Err bitreich.org 70 i+ (unsigned long long)ent->blks[i]); Err bitreich.org 70 i+ } Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+dump_blk(struct blk *blk) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ uint64_t i; Err bitreich.org 70 i+ Err bitreich.org 70 i+ fprintf(stderr, "blk->md: "); Err bitreich.org 70 i+ dump_md(blk->md, sizeof(blk->md)); Err bitreich.org 70 i+ putchar('\n'); Err bitreich.org 70 i+ fprintf(stderr, "blk->sz: %lld\n", (unsigned long long)blk->sz); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+append_ent(struct ent *ent) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ enthdr.nents++; Err bitreich.org 70 i+ lseek(ifd, 0, SEEK_SET); Err bitreich.org 70 i+ write(ifd, &enthdr, sizeof(enthdr)); Err bitreich.org 70 i+ Err bitreich.org 70 i+ lseek(ifd, 0, SEEK_END); Err bitreich.org 70 i+ ent->sz = sizeof(*ent); Err bitreich.org 70 i+ ent->sz += ent->nblks * sizeof(ent->blks[0]); Err bitreich.org 70 i+ write(ifd, ent, ent->sz); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+struct ent * Err bitreich.org 70 i+alloc_ent(void) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ struct ent *ent; Err bitreich.org 70 i+ Err bitreich.org 70 i+ ent = malloc(sizeof(*ent)); Err bitreich.org 70 i+ if (ent == NULL) Err bitreich.org 70 i+ err(1, "malloc"); Err bitreich.org 70 i+ return ent; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+struct ent * Err bitreich.org 70 i+grow_ent(struct ent *ent, uint64_t nblks) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ size_t sz; Err bitreich.org 70 i+ Err bitreich.org 70 i+ sz = sizeof(*ent); Err bitreich.org 70 i+ sz += nblks * sizeof(ent->blks[0]); Err bitreich.org 70 i+ ent = realloc(ent, sz); Err bitreich.org 70 i+ if (ent == NULL) Err bitreich.org 70 i+ err(1, "realloc"); Err bitreich.org 70 i+ return ent; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+hash_blk(struct blk *blk) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ SHA256_CTX ctx; Err bitreich.org 70 i+ Err bitreich.org 70 i+ SHA256_Init(&ctx); Err bitreich.org 70 i+ SHA256_Update(&ctx, blk->data, blk->sz); Err bitreich.org 70 i+ SHA256_Final(blk->md, &ctx); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+read_blk(struct blk *blk, off_t blkidx) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ lseek(sfd, blkidx * sizeof(*blk), SEEK_SET); Err bitreich.org 70 i+ read(sfd, blk, sizeof(*blk)); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+append_blk(struct blk *blk) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ lseek(sfd, 0, SEEK_END); Err bitreich.org 70 i+ write(sfd, blk, sizeof(*blk)); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+int Err bitreich.org 70 i+lookup_blk(struct blk *b1, uint64_t *blkidx) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ uint64_t nblks; Err bitreich.org 70 i+ uint64_t i; Err bitreich.org 70 i+ Err bitreich.org 70 i+ nblks = lseek(sfd, 0, SEEK_END); Err bitreich.org 70 i+ nblks /= sizeof(struct blk); Err bitreich.org 70 i+ for (i = 0; i < nblks; i++) { Err bitreich.org 70 i+ struct blk b2; Err bitreich.org 70 i+ Err bitreich.org 70 i+ read_blk(&b2, i); Err bitreich.org 70 i+ if (memcmp(b1->md, b2.md, sizeof(b1->md)) == 0) { Err bitreich.org 70 i+ *blkidx = i; Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ } Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+dedup(int fd) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ struct blk blk; Err bitreich.org 70 i+ struct ent *ent; Err bitreich.org 70 i+ SHA256_CTX ctx; Err bitreich.org 70 i+ ssize_t n; Err bitreich.org 70 i+ Err bitreich.org 70 i+ ent = alloc_ent(); Err bitreich.org 70 i+ SHA256_Init(&ctx); Err bitreich.org 70 i+ while ((n = read(fd, blk.data, BLKSIZ)) > 0) { Err bitreich.org 70 i+ uint64_t blkidx; Err bitreich.org 70 i+ Err bitreich.org 70 i+ blk.sz = n; Err bitreich.org 70 i+ hash_blk(&blk); Err bitreich.org 70 i+ SHA256_Update(&ctx, blk.data, blk.sz); Err bitreich.org 70 i+ ent = grow_ent(ent, ent->nblks + 1); Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (lookup_blk(&blk, &blkidx) == -1) { Err bitreich.org 70 i+ off_t offs; Err bitreich.org 70 i+ Err bitreich.org 70 i+ offs = lseek(sfd, 0, SEEK_END); Err bitreich.org 70 i+ offs /= sizeof(blk); Err bitreich.org 70 i+ ent->blks[ent->nblks++] = offs; Err bitreich.org 70 i+ Err bitreich.org 70 i+ append_blk(&blk); Err bitreich.org 70 i+ } else { Err bitreich.org 70 i+ ent->blks[ent->nblks++] = blkidx; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ } Err bitreich.org 70 i+ if (n < 0) Err bitreich.org 70 i+ err(1, "read"); Err bitreich.org 70 i+ Err bitreich.org 70 i+ SHA256_Final(ent->md, &ctx); Err bitreich.org 70 i+ append_ent(ent); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+str2id(unsigned char *idstr, uint8_t *id) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ size_t i, len = strlen(idstr) / 2; Err bitreich.org 70 i+ char *p = idstr; Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (i = 0; i < len; i++, p += 2) Err bitreich.org 70 i+ sscanf(p, "%2hhx", &id[i]); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+extract(unsigned char *id, int fd) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ unsigned char md[SHA256_DIGEST_LENGTH]; Err bitreich.org 70 i+ struct ent *ent; Err bitreich.org 70 i+ uint64_t i; Err bitreich.org 70 i+ Err bitreich.org 70 i+ str2id(id, md); Err bitreich.org 70 i+ lseek(ifd, sizeof(enthdr), SEEK_SET); Err bitreich.org 70 i+ for (i = 0; i < enthdr.nents; i++) { Err bitreich.org 70 i+ ent = alloc_ent(); Err bitreich.org 70 i+ read(ifd, ent, sizeof(*ent)); Err bitreich.org 70 i+ ent = grow_ent(ent, ent->nblks); Err bitreich.org 70 i+ read(ifd, ent->blks, ent->nblks * sizeof(ent->blks[0])); Err bitreich.org 70 i+ if (memcmp(ent->md, md, sizeof(ent->md)) == 0) { Err bitreich.org 70 i+ uint64_t j; Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (j = 0; j < ent->nblks; j++) { Err bitreich.org 70 i+ struct blk blk; Err bitreich.org 70 i+ Err bitreich.org 70 i+ read_blk(&blk, ent->blks[j]); Err bitreich.org 70 i+ write(1, blk.data, blk.sz); Err bitreich.org 70 i+ } Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ free(ent); Err bitreich.org 70 i+ } Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+init(void) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ struct stat sb; Err bitreich.org 70 i+ Err bitreich.org 70 i+ ifd = open("index", O_RDWR | O_CREAT, 0600); Err bitreich.org 70 i+ if (ifd == -1) Err bitreich.org 70 i+ err(1, "open index"); Err bitreich.org 70 i+ Err bitreich.org 70 i+ sfd = open("store", O_RDWR | O_CREAT, 0600); Err bitreich.org 70 i+ if (sfd == -1) Err bitreich.org 70 i+ err(1, "open store"); Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (fstat(ifd, &sb) == -1) Err bitreich.org 70 i+ err(1, "stat index"); Err bitreich.org 70 i+ if (sb.st_size != 0) Err bitreich.org 70 i+ read(ifd, &enthdr, sizeof(enthdr)); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+dump_index(void) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ struct ent *ent; Err bitreich.org 70 i+ uint64_t i; Err bitreich.org 70 i+ Err bitreich.org 70 i+ dump_enthdr(&enthdr); Err bitreich.org 70 i+ lseek(ifd, sizeof(enthdr), SEEK_SET); Err bitreich.org 70 i+ for (i = 0; i < enthdr.nents; i++) { Err bitreich.org 70 i+ ent = alloc_ent(); Err bitreich.org 70 i+ read(ifd, ent, sizeof(*ent)); Err bitreich.org 70 i+ ent = grow_ent(ent, ent->nblks); Err bitreich.org 70 i+ read(ifd, ent->blks, ent->nblks * sizeof(ent->blks[0])); Err bitreich.org 70 i+ dump_ent(ent); Err bitreich.org 70 i+ free(ent); Err bitreich.org 70 i+ } Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+usage(void) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ fprintf(stderr, "usage: %s [-lv] [-e id]\n", argv0); Err bitreich.org 70 i+ exit(1); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+int Err bitreich.org 70 i+main(int argc, char *argv[]) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ unsigned char *id = NULL; Err bitreich.org 70 i+ int lflag = 0; Err bitreich.org 70 i+ Err bitreich.org 70 i+ ARGBEGIN { Err bitreich.org 70 i+ case 'e': Err bitreich.org 70 i+ id = EARGF(usage()); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ case 'l': Err bitreich.org 70 i+ lflag = 1; Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ case 'v': Err bitreich.org 70 i+ verbose = 1; Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ default: Err bitreich.org 70 i+ usage(); Err bitreich.org 70 i+ } ARGEND Err bitreich.org 70 i+ Err bitreich.org 70 i+ init(); Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (lflag) { Err bitreich.org 70 i+ dump_index(); Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (id) Err bitreich.org 70 i+ extract(id, 0); Err bitreich.org 70 i+ else Err bitreich.org 70 i+ dedup(0); Err bitreich.org 70 i+} Err bitreich.org 70 .