From f377eee1983a7c9f33a9920b3bf16180dca909da Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sun, 22 Jan 2012 13:12:15 +0000 Subject: [PATCH] cc-hash.c, hashsum.c: Move hash-file parsing stuff to `cc-hash.c'. This is a bit trickier than just slinging existing functions about and tarting them up a bit: it introduces a proper interface to parsing hash files, which previously was interleaved with actually verifying the hashes. Also moved a couple of auxiliary functions which are needed by the moved code. --- cc-hash.c | 99 +++++++++++++++++++++++++++++++++++++++++ cc.h | 42 ++++++++++++++++++ hashsum.c | 150 +++++++++++++++++--------------------------------------------- 3 files changed, 182 insertions(+), 109 deletions(-) diff --git a/cc-hash.c b/cc-hash.c index 81a06a2..b0d8bb2 100644 --- a/cc-hash.c +++ b/cc-hash.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -165,6 +166,33 @@ const encodeops *getencoding(const char *ename) /*----- File hashing ------------------------------------------------------*/ +/* --- @gethash@ --- * + * + * Arguments: @const char *name@ = pointer to name string + * + * Returns: Pointer to appropriate hash class. + * + * Use: Chooses a hash function by name. + */ + +const gchash *gethash(const char *name) +{ + const gchash *const *g, *gg = 0; + size_t sz = strlen(name); + for (g = ghashtab; *g; g++) { + if (strncmp(name, (*g)->name, sz) == 0) { + if ((*g)->name[sz] == 0) { + gg = *g; + break; + } else if (gg) + return (0); + else + gg = *g; + } + } + return (gg); +} + /* --- @fhash@ --- * * * Arguments: @const gchash *gch@ = pointer to hash function to use @@ -208,6 +236,77 @@ int fhash(const gchash *gch, unsigned f, const char *file, void *buf) return (rc); } +/* --- @hfparse@ --- * + * + * Arguments: @hfpctx *hfp@ = pointer to the context structure + * + * Returns: A code indicating what happened. + * + * Use: Parses a line from the input file. + */ + +int hfparse(hfpctx *hfp) +{ + char *p, *q; + const gchash *gch; + const encodeops *ee; + dstr *d = hfp->dline; + size_t hsz; + + /* --- Fetch the input line and get ready to parse --- */ + + DRESET(d); + if (dstr_putline(d, hfp->fp) == EOF) return (HF_EOF); + p = d->buf; + + /* --- Parse magic comments --- */ + + if (*p == '#') { + p++; + if ((q = str_getword(&p)) == 0) return (HF_BAD); + if (strcmp(q, "hash") == 0) { + if ((q = str_getword(&p)) == 0) return (HF_BAD); + if ((gch = gethash(q)) == 0) return (HF_BAD); + hfp->gch = gch; + return (HF_HASH); + } else if (strcmp(q, "encoding") == 0) { + if ((q = str_getword(&p)) == 0) return (HF_BAD); + if ((ee = getencoding(q)) == 0) return (HF_BAD); + hfp->ee = ee; + return (HF_ENC); + } else if (strcmp(q, "escape") == 0) { + hfp->f |= HFF_ESCAPE; + return (HF_ESC); + } + return (HF_BAD); + } + + /* --- Otherwise it's a file line --- */ + + q = p; + while (*p && *p != ' ') p++; + if (!*p) return (HF_BAD); + *p++ = 0; + hsz = hfp->gch->hashsz; + if (hfp->ee->get(q, hfp->hbuf, hsz, 0) < hsz) return (HF_BAD); + switch (*p) { + case '*': hfp->f |= FHF_BINARY; break; + case ' ': hfp->f &= ~FHF_BINARY; break; + default: return (HF_BAD); + } + p++; + + DRESET(hfp->dfile); + if (hfp->f & HFF_ESCAPE) + getstring(&p, hfp->dfile, GSF_STRING); + else { + dstr_putm(hfp->dfile, p, d->len - (p - d->buf)); + dstr_putz(hfp->dfile); + } + + return (HF_FILE); +} + /*----- String I/O --------------------------------------------------------*/ /* --- @getstring@ --- * diff --git a/cc.h b/cc.h index 04ff17f..2e0503a 100644 --- a/cc.h +++ b/cc.h @@ -326,6 +326,17 @@ extern const encodeops *getencoding(const char */*ename*/); /*----- File hashing ------------------------------------------------------*/ +/* --- @gethash@ --- * + * + * Arguments: @const char *name@ = pointer to name string + * + * Returns: Pointer to appropriate hash class. + * + * Use: Chooses a hash function by name. + */ + +extern const gchash *gethash(const char */*name*/); + /* --- @fhash@ --- * * * Arguments: @const gchash *gch@ = pointer to hash function to use @@ -346,6 +357,37 @@ extern const encodeops *getencoding(const char */*ename*/); extern int fhash(const gchash */*gch*/, unsigned /*f*/, const char */*file*/, void */*buf*/); +/* --- @hfparse@ --- * + * + * Arguments: @hfpctx *hfp@ = pointer to the context structure + * + * Returns: A code indicating what happened. + * + * Use: Parses a line from the input file. + */ + +enum { /* Meaning and members set */ + HF_FILE, /* File hash: @dline@ and @hbuf@ */ + HF_ENC, /* Encoding: @ee@ */ + HF_HASH, /* Hash function: @gch@ */ + HF_ESC, /* Name escape: @f@ */ + HF_EOF, /* End of file */ + HF_BAD /* Unrecognized line */ +}; + +typedef struct hfpctx { + unsigned f; /* Flags to read */ +#define HFF_ESCAPE 1u /* File names are escaped */ + FILE *fp; /* Input file to read */ + dstr *dline; /* Line contents, corrupted */ + const gchash *gch; /* Hash function to use */ + const encodeops *ee; /* Encoding to apply to hashes */ + dstr *dfile; /* File name for @HF_FILE@ lines */ + octet *hbuf; /* Output buffer for hash data */ +} hfpctx; + +extern int hfparse(hfpctx */*hfp*/); + /*----- String I/O --------------------------------------------------------*/ #define GSF_RAW 4096u diff --git a/hashsum.c b/hashsum.c index 5eeb41b..23b5d56 100644 --- a/hashsum.c +++ b/hashsum.c @@ -45,7 +45,6 @@ #include #include #include -#include #include "ghash.h" #include "cc.h" @@ -60,132 +59,65 @@ #define f_escape 32u #define f_oddenc 64u -/*----- Support functions -------------------------------------------------*/ - -/* --- @gethash@ --- * - * - * Arguments: @const char *name@ = pointer to name string - * - * Returns: Pointer to appropriate hash class. - * - * Use: Chooses a hash function by name. - */ - -static const gchash *gethash(const char *name) -{ - const gchash *const *g, *gg = 0; - size_t sz = strlen(name); - for (g = ghashtab; *g; g++) { - if (strncmp(name, (*g)->name, sz) == 0) { - if ((*g)->name[sz] == 0) { - gg = *g; - break; - } else if (gg) - return (0); - else - gg = *g; - } - } - return (gg); -} - /*----- Guts --------------------------------------------------------------*/ static int checkhash(const gchash *gch, unsigned f, const char *file, const encodeops *e) { int rc; - FILE *fp; - dstr d = DSTR_INIT; - dstr dd = DSTR_INIT; + hfpctx hfp; + dstr dl = DSTR_INIT; + dstr df = DSTR_INIT; unsigned long n = 0, nfail = 0; - octet *buf = xmalloc(2 * gch->hashsz); + int hf; if (!file || strcmp(file, "-") == 0) - fp = stdin; - else if ((fp = fopen(file, f & GSF_RAW ? "r" : "rb")) == 0) { + hfp.fp = stdin; + else if ((hfp.fp = fopen(file, f & GSF_RAW ? "r" : "rb")) == 0) { moan("couldn't open `%s': %s", file, strerror(errno)); return (EXIT_FAILURE); } - while (DRESET(&d), dstr_putline(&d, fp) != EOF) { - char *p = d.buf; - char *q; - unsigned ff = f; - - /* --- Handle a directive --- */ - - if (*p == '#') { - p++; - if ((q = str_getword(&p)) == 0) - continue; - if (strcmp(q, "hash") == 0) { - const gchash *g; - if ((q = str_getword(&p)) == 0) - continue; - if ((g = gethash(q)) == 0) - continue; - gch = g; - xfree(buf); - buf = xmalloc(2 * gch->hashsz); - } else if (strcmp(q, "encoding") == 0) { - const encodeops *ee; - if ((q = str_getword(&p)) == 0) - continue; - if ((ee = getencoding(q)) == 0) + hfp.dline = &dl; + hfp.dfile = &df; + hfp.hbuf = xmalloc(2 * gch->hashsz); + hfp.gch = gch; + hfp.ee = e; + hfp.f = f; + + while ((hf = hfparse(&hfp)) != HF_EOF) { + switch (hf) { + case HF_HASH: + xfree(hfp.hbuf); + hfp.hbuf = xmalloc(2 * hfp.gch->hashsz); + break; + case HF_FILE: + if (fhash(hfp.gch, hfp.f, df.buf, hfp.hbuf + hfp.gch->hashsz)) { + moan("couldn't read `%s': %s", df.buf, strerror(errno)); + rc = EXIT_FAILURE; continue; - e = ee; - } else if (strcmp(q, "escape") == 0) - f |= f_escape; - continue; - } - - /* --- Otherwise it's a hex thing --- */ - - q = p; - while (*p && *p != ' ') - p++; - if (!*p) - continue; - *p++ = 0; - if (e->get(q, buf, gch->hashsz, 0) < gch->hashsz) - continue; - if (*p == '*') - ff |= FHF_BINARY; - else if (*p != ' ') - continue; - p++; - - if (f & f_escape) { - DRESET(&dd); - getstring(&p, &dd, GSF_STRING); - p = dd.buf; - } - - if (fhash(gch, ff, p, buf + gch->hashsz)) { - moan("couldn't read `%s': %s", p, strerror(errno)); - rc = EXIT_FAILURE; - continue; - } - if (memcmp(buf, buf + gch->hashsz, gch->hashsz) != 0) { - if (ff & f_verbose) - fprintf(stderr, "FAIL %s\n", p); - else - moan("%s check failed for `%s'", gch->name, p); - nfail++; - rc = EXIT_FAILURE; - } else { - if (ff & f_verbose) - fprintf(stderr, "OK %s\n", p); + } + if (memcmp(hfp.hbuf, hfp.hbuf + hfp.gch->hashsz, + hfp.gch->hashsz) != 0) { + if (hfp.f & f_verbose) + fprintf(stderr, "FAIL %s\n", df.buf); + else + moan("%s check failed for `%s'", hfp.gch->name, df.buf); + nfail++; + rc = EXIT_FAILURE; + } else { + if (hfp.f & f_verbose) + fprintf(stderr, "OK %s\n", df.buf); + } + n++; } - n++; } - dstr_destroy(&d); - dstr_destroy(&dd); - xfree(buf); + dstr_destroy(&dl); + dstr_destroy(&df); + xfree(hfp.hbuf); if ((f & f_verbose) && nfail) - moan("%lu of %lu file(s) failed %s check", nfail, n, gch->name); + moan("%lu of %lu file(s) failed %s check", nfail, n, hfp.gch->name); else if (!n) moan("no files checked"); return (0); -- 2.11.0