rework -C (perfect candidate for using hash tables, really):
authorespie <espie@openbsd.org>
Fri, 16 May 2014 16:18:33 +0000 (16:18 +0000)
committerespie <espie@openbsd.org>
Fri, 16 May 2014 16:18:33 +0000 (16:18 +0000)
insert files we want to check into a hash,
parse SHA256 message on the fly, delete entries whose checksum match,
then display entries that failed.

This completely avoids allocating temporary storage for file names and checksums
and removes the quadratic match (argv[i] vs line[n]).

okay tedu@

usr.bin/signify/signify.c

index e5cdfb4..f91dc57 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: signify.c,v 1.84 2014/05/15 13:14:15 espie Exp $ */
+/* $OpenBSD: signify.c,v 1.85 2014/05/16 16:18:33 espie Exp $ */
 /*
  * Copyright (c) 2013 Ted Unangst <tedu@openbsd.org>
  *
 #include <sha2.h>
 
 #include "crypto_api.h"
+#ifndef VERIFY_ONLY
+#include <stdint.h>
+#include <stddef.h>
+#include <ohash.h>
+#endif
 
 #define SIGBYTES crypto_sign_ed25519_BYTES
 #define SECRETBYTES crypto_sign_ed25519_SECRETKEYBYTES
@@ -538,14 +543,28 @@ struct checksum {
        char algo[32];
 };
 
+static void * 
+ecalloc(size_t s1, size_t s2, void *data)
+{
+       void *p = calloc(s1, s2);
+       if (!p)
+               err(1, "calloc");
+       return p;
+}
+
+static void
+efree(void *p, void *data)
+{
+       free(p);
+}
+
 static void
-recodehash(char *hash)
+recodehash(char *hash, size_t len)
 {
        uint8_t data[HASHBUFSIZE / 2];
        int i, rv;
 
-       if (strlen(hash)+1 == SHA256_DIGEST_STRING_LENGTH ||
-           strlen(hash)+1 == SHA512_DIGEST_STRING_LENGTH)
+       if (strlen(hash) == len)
                return;
        if ((rv = b64_pton(hash, data, sizeof(data))) == -1)
                errx(1, "invalid base64 encoding");
@@ -553,93 +572,92 @@ recodehash(char *hash)
                snprintf(hash + i * 2, HASHBUFSIZE - i * 2, "%2.2x", data[i]);
 }
 
+static int
+verifychecksum(struct checksum *c, int quiet)
+{
+       char buf[HASHBUFSIZE];
+       if (strcmp(c->algo, "SHA256") == 0) {
+               recodehash(c->hash, SHA256_DIGEST_STRING_LENGTH-1);
+               if (!SHA256File(c->file, buf))
+                       return 0;
+       } else if (strcmp(c->algo, "SHA512") == 0) {
+               recodehash(c->hash, SHA512_DIGEST_STRING_LENGTH-1);
+               if (!SHA512File(c->file, buf))
+                       return 0;
+       } else {
+               errx(1, "can't handle algorithm %s", c->algo);
+       }
+       if (strcmp(c->hash, buf) != 0) {
+               return 0;
+       }
+       if (!quiet)
+               printf("%s: OK\n", c->file);
+       return 1;
+}
+
 static void
 verifychecksums(char *msg, int argc, char **argv, int quiet)
 {
-       char buf[1024];
+
+       struct ohash_info info = {  0, NULL, ecalloc, efree, NULL };
+       struct ohash myh;
+       unsigned int i;
+       struct checksum c;
        char *line, *endline;
-       struct checksum *checksums = NULL, *c = NULL;
-       int nchecksums = 0, checksumspace = 0;
-       int i, j, rv, uselist, count, hasfailed;
-       int *failures;
+       int hasfailed = 0;
+       int rv;
+       const char *e;
+       unsigned int slot;
+
+
+       if (argc) {
+               ohash_init(&myh, 6, &info);
+               for (i = 0; i < argc; i++) {
+                       slot = ohash_qlookup(&myh, argv[i]);
+                       e = ohash_find(&myh, slot);
+                       if (e == NULL)
+                               ohash_insert(&myh, slot, argv[i]);
+               }
+       }
 
        line = msg;
        while (line && *line) {
-               if (nchecksums == checksumspace) {
-                       checksumspace = 2 * (nchecksums + 1);
-                       if (!(checksums = reallocarray(checksums,
-                           checksumspace, sizeof(*checksums))))
-                               err(1, "realloc");
-               }
-               c = &checksums[nchecksums++];
                if ((endline = strchr(line, '\n')))
                        *endline++ = '\0';
-               rv = sscanf(line, "%31s %1023s = %223s",
-                   c->algo, buf, c->hash);
-               if (rv != 3 || buf[0] != '(' || buf[strlen(buf) - 1] != ')')
+               rv = sscanf(line, "%31s (%1023s = %223s",
+                   c.algo, c.file, c.hash);
+               if (rv != 3 || c.file[0] == 0 || c.file[strlen(c.file)-1] != ')')
                        errx(1, "unable to parse checksum line %s", line);
-               recodehash(c->hash);
-               buf[strlen(buf) - 1] = 0;
-               strlcpy(c->file, buf + 1, sizeof(c->file));
+               c.file[strlen(c.file) - 1] = 0;
                line = endline;
-       }
-
-       if (argc) {
-               uselist = 0;
-               count = argc;
-       } else {
-               uselist = 1;
-               count = nchecksums;
-       }
-       if (!(failures = calloc(count, sizeof(*failures))))
-               err(1, "calloc");
-       for (i = 0; i < count; i++) {
-               if (uselist) {
-                       c = &checksums[i];
-               } else {
-                       for (j = 0; j < nchecksums; j++) {
-                               c = &checksums[j];
-                               if (strcmp(c->file, argv[i]) == 0)
-                                       break;
+               if (argc) {
+                       slot = ohash_qlookup(&myh, c.file);
+                       e = ohash_find(&myh, slot);
+                       if (e != NULL) {
+                               if (verifychecksum(&c, quiet))
+                                       ohash_remove(&myh, slot);
                        }
-                       if (j == nchecksums) {
-                               failures[i] = 1;
-                               continue;
+               } else {
+                       if (!verifychecksum(&c, quiet)) {
+                               fprintf(stderr, "%s: FAIL\n", c.file);
+                               hasfailed = 1;
                        }
                }
+       }
 
-               if (strcmp(c->algo, "SHA256") == 0) {
-                       if (!SHA256File(c->file, buf)) {
-                               failures[i] = 1;
-                               continue;
-                       }
-               } else if (strcmp(c->algo, "SHA512") == 0) {
-                       if (!SHA512File(c->file, buf)) {
-                               failures[i] = 1;
-                               continue;
+       if (argc) {
+               for (i = 0; i < argc; i++) {
+                       slot = ohash_qlookup(&myh, argv[i]);
+                       e = ohash_find(&myh, slot);
+                       if (e != NULL) {
+                               fprintf(stderr, "%s: FAIL\n", argv[i]);
+                               hasfailed = 1;
                        }
-               } else {
-                       errx(1, "can't handle algorithm %s", c->algo);
-               }
-               if (strcmp(c->hash, buf) != 0) {
-                       failures[i] = 1;
-                       continue;
-               }
-               if (!quiet)
-                       printf("%s: OK\n", c->file);
-       }
-       hasfailed = 0;
-       for (i = 0; i < count; i++) {
-               if (failures[i]) {
-                       fprintf(stderr, "%s: FAIL\n",
-                           uselist ? checksums[i].file : argv[i]);
-                       hasfailed = 1;
-               }
+               }
+               ohash_delete(&myh);
        }
        if (hasfailed)
                exit(1);
-       free(checksums);
-       free(failures);
 }
 
 static void