mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-01-30 14:52:17 +00:00
825 lines
18 KiB
C
825 lines
18 KiB
C
|
/* $Id: hsum.c 243 2010-06-21 17:13:32Z tp $ */
|
||
|
/*
|
||
|
* Command-line utility to compute hash functions over files. This is
|
||
|
* intended to work similarly to the usual "md5sum" utility, but for
|
||
|
* all hash functions implemented by sphlib.
|
||
|
*
|
||
|
* Usage is the following:
|
||
|
* <pre>
|
||
|
* sphsum function [ options ] [ file... ]
|
||
|
* </pre>
|
||
|
* where <code>function</code> is the hash function name (short internal
|
||
|
* name, such as <code>md5</code> or <code>whirlpool0</code>). Options
|
||
|
* specify whether the file must be read as text or binary (it makes no
|
||
|
* difference on Unix systems); moreover, with the <code>"-c"</code> option,
|
||
|
* a list of checksums can be verified. If no file name is specified, then
|
||
|
* standard input is used; the special file name <code>"-"</code> (a single
|
||
|
* minus sign) is also an alias for standard input.
|
||
|
*
|
||
|
* Alternatively, the executable binary may be named after the hash
|
||
|
* function itself. In that situation, the <code>function</code> parameter
|
||
|
* must be omitted. For function name recognition, suffixes <code>".exe"</code>
|
||
|
* and <code>"sum"</code> are suppressed; thus, the executable may be named
|
||
|
* <code>"md5sum"</code> or <code>"md5sum.exe"</code>, and will then behave
|
||
|
* as the standard Linux utility <code>"md5sum"</code>.
|
||
|
*
|
||
|
* ==========================(LICENSE BEGIN)============================
|
||
|
*
|
||
|
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||
|
* a copy of this software and associated documentation files (the
|
||
|
* "Software"), to deal in the Software without restriction, including
|
||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||
|
* the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be
|
||
|
* included in all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*
|
||
|
* ===========================(LICENSE END)=============================
|
||
|
*
|
||
|
* @author Thomas Pornin <thomas.pornin@cryptolog.com>
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "sph_blake.h"
|
||
|
#include "sph_bmw.h"
|
||
|
#include "sph_cubehash.h"
|
||
|
#include "sph_echo.h"
|
||
|
#include "sph_fugue.h"
|
||
|
#include "sph_groestl.h"
|
||
|
#include "sph_hamsi.h"
|
||
|
#include "sph_haval.h"
|
||
|
#include "sph_jh.h"
|
||
|
#include "sph_keccak.h"
|
||
|
#include "sph_luffa.h"
|
||
|
#include "sph_md2.h"
|
||
|
#include "sph_md4.h"
|
||
|
#include "sph_md5.h"
|
||
|
#include "sph_panama.h"
|
||
|
#include "sph_radiogatun.h"
|
||
|
#include "sph_ripemd.h"
|
||
|
#include "sph_sha0.h"
|
||
|
#include "sph_sha1.h"
|
||
|
#include "sph_sha2.h"
|
||
|
#include "sph_shabal.h"
|
||
|
#include "sph_shavite.h"
|
||
|
#include "sph_simd.h"
|
||
|
#include "sph_skein.h"
|
||
|
#include "sph_tiger.h"
|
||
|
#include "sph_whirlpool.h"
|
||
|
|
||
|
/**
|
||
|
* The program name, as extracted from the invocation name.
|
||
|
*/
|
||
|
static char *program_name;
|
||
|
|
||
|
/**
|
||
|
* Extract the program name from the invocation name.
|
||
|
*
|
||
|
* @param fullname the invocation name
|
||
|
*/
|
||
|
static void
|
||
|
make_program_name(char *fullname)
|
||
|
{
|
||
|
char *c, *d;
|
||
|
|
||
|
if (fullname == NULL) {
|
||
|
program_name = "hsum";
|
||
|
return;
|
||
|
}
|
||
|
for (c = d = fullname; *d != 0; d ++)
|
||
|
if (*d == '/' || *d == '\\')
|
||
|
c = d + 1;
|
||
|
program_name = c;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Print out usage and exit.
|
||
|
*
|
||
|
* @param genf non-zero if generic executable
|
||
|
* @param fail non-zero to exit with a failure status
|
||
|
*/
|
||
|
static void
|
||
|
usage(int genf, int fail)
|
||
|
{
|
||
|
fprintf(stderr,
|
||
|
"usage: %s%s [options] [file...]\n"
|
||
|
"options:\n"
|
||
|
" -b, --binary\n"
|
||
|
" read in binary mode\n"
|
||
|
" -c, --check\n"
|
||
|
" read sums from the files and check them\n"
|
||
|
" -t, --text\n"
|
||
|
" read in text mode (default)\n"
|
||
|
" --status\n"
|
||
|
" output is discarded; success or failure is shown by the exit code\n"
|
||
|
" -w, --warn\n"
|
||
|
" warn about improperly formatted checksum lines (which are ignored)\n"
|
||
|
" -h, --help\n"
|
||
|
" display this help and exit\n"
|
||
|
" -v, --version\n"
|
||
|
" display version information and exit\n",
|
||
|
program_name, genf ? " function" : "");
|
||
|
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Print out version information and exit with a success status.
|
||
|
*/
|
||
|
static void
|
||
|
version(void)
|
||
|
{
|
||
|
fprintf(stderr,
|
||
|
"sphlib: version 2.1\n"
|
||
|
"Copyright (c) 2007-2010 Projet RNRT SAPHIR\n"
|
||
|
"This software is provided WITHOUT ANY WARRANTY, to the extent\n"
|
||
|
"permitted by law.\n");
|
||
|
exit(EXIT_SUCCESS);
|
||
|
}
|
||
|
|
||
|
#define MAKECC(name) sph_ ## name ## _context cc_ ## name
|
||
|
|
||
|
/**
|
||
|
* The hash function context is static; this union ensures that we have
|
||
|
* a properly sized and aligned context for all functions (but not
|
||
|
* simultaneously, of course).
|
||
|
*/
|
||
|
static union {
|
||
|
MAKECC(blake224);
|
||
|
MAKECC(blake256);
|
||
|
#if SPH_64
|
||
|
MAKECC(blake384);
|
||
|
MAKECC(blake512);
|
||
|
#endif
|
||
|
MAKECC(bmw224);
|
||
|
MAKECC(bmw256);
|
||
|
#if SPH_64
|
||
|
MAKECC(bmw384);
|
||
|
MAKECC(bmw512);
|
||
|
#endif
|
||
|
MAKECC(cubehash224);
|
||
|
MAKECC(cubehash256);
|
||
|
MAKECC(cubehash384);
|
||
|
MAKECC(cubehash512);
|
||
|
MAKECC(echo224);
|
||
|
MAKECC(echo256);
|
||
|
MAKECC(echo384);
|
||
|
MAKECC(echo512);
|
||
|
MAKECC(fugue224);
|
||
|
MAKECC(fugue256);
|
||
|
MAKECC(fugue384);
|
||
|
MAKECC(fugue512);
|
||
|
MAKECC(groestl224);
|
||
|
MAKECC(groestl256);
|
||
|
MAKECC(groestl384);
|
||
|
MAKECC(groestl512);
|
||
|
MAKECC(hamsi224);
|
||
|
MAKECC(hamsi256);
|
||
|
MAKECC(hamsi384);
|
||
|
MAKECC(hamsi512);
|
||
|
MAKECC(haval128_3);
|
||
|
MAKECC(haval128_4);
|
||
|
MAKECC(haval128_5);
|
||
|
MAKECC(haval160_3);
|
||
|
MAKECC(haval160_4);
|
||
|
MAKECC(haval160_5);
|
||
|
MAKECC(haval192_3);
|
||
|
MAKECC(haval192_4);
|
||
|
MAKECC(haval192_5);
|
||
|
MAKECC(haval224_3);
|
||
|
MAKECC(haval224_4);
|
||
|
MAKECC(haval224_5);
|
||
|
MAKECC(haval256_3);
|
||
|
MAKECC(haval256_4);
|
||
|
MAKECC(haval256_5);
|
||
|
MAKECC(jh224);
|
||
|
MAKECC(jh256);
|
||
|
MAKECC(jh384);
|
||
|
MAKECC(jh512);
|
||
|
MAKECC(keccak224);
|
||
|
MAKECC(keccak256);
|
||
|
MAKECC(keccak384);
|
||
|
MAKECC(keccak512);
|
||
|
MAKECC(luffa224);
|
||
|
MAKECC(luffa256);
|
||
|
MAKECC(luffa384);
|
||
|
MAKECC(luffa512);
|
||
|
MAKECC(md2);
|
||
|
MAKECC(md4);
|
||
|
MAKECC(md5);
|
||
|
MAKECC(panama);
|
||
|
MAKECC(radiogatun32);
|
||
|
#if SPH_64
|
||
|
MAKECC(radiogatun64);
|
||
|
#endif
|
||
|
MAKECC(ripemd128);
|
||
|
MAKECC(ripemd160);
|
||
|
MAKECC(ripemd);
|
||
|
MAKECC(sha0);
|
||
|
MAKECC(sha1);
|
||
|
MAKECC(sha224);
|
||
|
MAKECC(sha256);
|
||
|
#if SPH_64
|
||
|
MAKECC(sha384);
|
||
|
MAKECC(sha512);
|
||
|
#endif
|
||
|
MAKECC(shabal224);
|
||
|
MAKECC(shabal256);
|
||
|
MAKECC(shabal384);
|
||
|
MAKECC(shabal512);
|
||
|
MAKECC(shavite224);
|
||
|
MAKECC(shavite256);
|
||
|
MAKECC(shavite384);
|
||
|
MAKECC(shavite512);
|
||
|
MAKECC(simd224);
|
||
|
MAKECC(simd256);
|
||
|
MAKECC(simd384);
|
||
|
MAKECC(simd512);
|
||
|
#if SPH_64
|
||
|
MAKECC(skein224);
|
||
|
MAKECC(skein256);
|
||
|
MAKECC(skein384);
|
||
|
MAKECC(skein512);
|
||
|
#endif
|
||
|
MAKECC(tiger2);
|
||
|
MAKECC(tiger);
|
||
|
MAKECC(whirlpool0);
|
||
|
MAKECC(whirlpool1);
|
||
|
MAKECC(whirlpool);
|
||
|
} hcontext;
|
||
|
|
||
|
/**
|
||
|
* File data will come through this buffer. Using the union ensures
|
||
|
* proper alignment. Eight kilobytes are used for the buffer: this
|
||
|
* should be enough to get near-optimal speed.
|
||
|
*/
|
||
|
static union {
|
||
|
unsigned char buf[8192];
|
||
|
long l;
|
||
|
void *p;
|
||
|
sph_u32 w32;
|
||
|
#if SPH_64
|
||
|
sph_u64 w64;
|
||
|
#endif
|
||
|
} ubuf;
|
||
|
|
||
|
#define MAKEFFGEN(id, name, len) { \
|
||
|
&sph_ ## id ## _init, &sph_ ## id, \
|
||
|
&sph_ ## id ## _close, #name, len \
|
||
|
}
|
||
|
|
||
|
#define MAKEFF(id) MAKEFFGEN(id, id, SPH_SIZE_ ## id / 8)
|
||
|
|
||
|
/**
|
||
|
* This array contains the callbacks to the hash function implementation.
|
||
|
*/
|
||
|
static struct known_function {
|
||
|
void (*ff_init)(void *cc);
|
||
|
void (*ff_update)(void *cc, const void *data, size_t len);
|
||
|
void (*ff_close)(void *cc, void *dst);
|
||
|
char *name;
|
||
|
size_t out_len;
|
||
|
} known_functions[] = {
|
||
|
MAKEFF(blake224),
|
||
|
MAKEFF(blake256),
|
||
|
#if SPH_64
|
||
|
MAKEFF(blake384),
|
||
|
MAKEFF(blake512),
|
||
|
#endif
|
||
|
MAKEFF(bmw224),
|
||
|
MAKEFF(bmw256),
|
||
|
#if SPH_64
|
||
|
MAKEFF(bmw384),
|
||
|
MAKEFF(bmw512),
|
||
|
#endif
|
||
|
MAKEFF(cubehash224),
|
||
|
MAKEFF(cubehash256),
|
||
|
MAKEFF(cubehash384),
|
||
|
MAKEFF(cubehash512),
|
||
|
MAKEFF(echo224),
|
||
|
MAKEFF(echo256),
|
||
|
MAKEFF(echo384),
|
||
|
MAKEFF(echo512),
|
||
|
MAKEFF(fugue224),
|
||
|
MAKEFF(fugue256),
|
||
|
MAKEFF(fugue384),
|
||
|
MAKEFF(fugue512),
|
||
|
MAKEFF(groestl224),
|
||
|
MAKEFF(groestl256),
|
||
|
MAKEFF(groestl384),
|
||
|
MAKEFF(groestl512),
|
||
|
MAKEFF(hamsi224),
|
||
|
MAKEFF(hamsi256),
|
||
|
MAKEFF(hamsi384),
|
||
|
MAKEFF(hamsi512),
|
||
|
MAKEFF(haval128_3),
|
||
|
MAKEFF(haval128_4),
|
||
|
MAKEFF(haval128_5),
|
||
|
MAKEFF(haval160_3),
|
||
|
MAKEFF(haval160_4),
|
||
|
MAKEFF(haval160_5),
|
||
|
MAKEFF(haval192_3),
|
||
|
MAKEFF(haval192_4),
|
||
|
MAKEFF(haval192_5),
|
||
|
MAKEFF(haval224_3),
|
||
|
MAKEFF(haval224_4),
|
||
|
MAKEFF(haval224_5),
|
||
|
MAKEFF(haval256_3),
|
||
|
MAKEFF(haval256_4),
|
||
|
MAKEFF(haval256_5),
|
||
|
MAKEFF(jh224),
|
||
|
MAKEFF(jh256),
|
||
|
MAKEFF(jh384),
|
||
|
MAKEFF(jh512),
|
||
|
MAKEFF(keccak224),
|
||
|
MAKEFF(keccak256),
|
||
|
MAKEFF(keccak384),
|
||
|
MAKEFF(keccak512),
|
||
|
MAKEFF(luffa224),
|
||
|
MAKEFF(luffa256),
|
||
|
MAKEFF(luffa384),
|
||
|
MAKEFF(luffa512),
|
||
|
MAKEFF(md2),
|
||
|
MAKEFF(md4),
|
||
|
MAKEFF(md5),
|
||
|
MAKEFF(panama),
|
||
|
MAKEFF(radiogatun32),
|
||
|
#if SPH_64
|
||
|
MAKEFF(radiogatun64),
|
||
|
#endif
|
||
|
MAKEFF(ripemd128),
|
||
|
MAKEFF(ripemd160),
|
||
|
MAKEFF(ripemd),
|
||
|
MAKEFFGEN(ripemd128, rmd128, 16),
|
||
|
MAKEFFGEN(ripemd160, rmd160, 20),
|
||
|
MAKEFFGEN(ripemd, rmd, 16),
|
||
|
MAKEFF(sha0),
|
||
|
MAKEFF(sha1),
|
||
|
MAKEFF(sha224),
|
||
|
MAKEFF(sha256),
|
||
|
#if SPH_64
|
||
|
MAKEFF(sha384),
|
||
|
MAKEFF(sha512),
|
||
|
#endif
|
||
|
MAKEFF(shabal224),
|
||
|
MAKEFF(shabal256),
|
||
|
MAKEFF(shabal384),
|
||
|
MAKEFF(shabal512),
|
||
|
MAKEFF(shavite224),
|
||
|
MAKEFF(shavite256),
|
||
|
MAKEFF(shavite384),
|
||
|
MAKEFF(shavite512),
|
||
|
MAKEFF(simd224),
|
||
|
MAKEFF(simd256),
|
||
|
MAKEFF(simd384),
|
||
|
MAKEFF(simd512),
|
||
|
#if SPH_64
|
||
|
MAKEFF(skein224),
|
||
|
MAKEFF(skein256),
|
||
|
MAKEFF(skein384),
|
||
|
MAKEFF(skein512),
|
||
|
#endif
|
||
|
MAKEFF(tiger2),
|
||
|
MAKEFF(tiger),
|
||
|
MAKEFF(whirlpool0),
|
||
|
MAKEFF(whirlpool1),
|
||
|
MAKEFF(whirlpool),
|
||
|
|
||
|
{ 0, 0, 0, 0, 0 }
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Compare two strings, case insensitive. Note: this function assumes
|
||
|
* an architecture which operates with an ASCII-compatible charset.
|
||
|
*
|
||
|
* @param s1 the first string
|
||
|
* @param s2 the second string
|
||
|
* @return non-zero on string equality
|
||
|
*/
|
||
|
static int
|
||
|
equals_string_nocase(char *s1, char *s2)
|
||
|
{
|
||
|
while (*s1 || *s2) {
|
||
|
int c1, c2;
|
||
|
|
||
|
c1 = *s1 ++;
|
||
|
c2 = *s2 ++;
|
||
|
if (c1 >= 'A' && c1 <= 'Z')
|
||
|
c1 += 'a' - 'A';
|
||
|
if (c2 >= 'A' && c2 <= 'Z')
|
||
|
c2 += 'a' - 'A';
|
||
|
if (c1 != c2)
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Recognize the function name.
|
||
|
*
|
||
|
* @param name the name to match
|
||
|
* @return the function index, of -1
|
||
|
*/
|
||
|
static int
|
||
|
get_function_name(char *name)
|
||
|
{
|
||
|
int i;
|
||
|
size_t u, v, w, len;
|
||
|
char name_ext[30];
|
||
|
|
||
|
len = strlen(name);
|
||
|
v = 0;
|
||
|
for (u = 0; u < len; u ++)
|
||
|
if (name[u] == '/' || name[u] == '\\')
|
||
|
v = u + 1;
|
||
|
w = len;
|
||
|
if (w > (v + 4) && equals_string_nocase(name + (w - 4), ".exe"))
|
||
|
w -= 3;
|
||
|
if (w > (v + 3) && equals_string_nocase(name + (w - 3), "sum"))
|
||
|
w -= 3;
|
||
|
if ((w - v) >= sizeof name_ext)
|
||
|
return -1;
|
||
|
memcpy(name_ext, name + v, w - v);
|
||
|
name_ext[w - v] = 0;
|
||
|
for (i = 0; known_functions[i].name != NULL; i ++)
|
||
|
if (equals_string_nocase(name_ext, known_functions[i].name))
|
||
|
return i;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Static state: options, counts for computations and failures, and
|
||
|
* the function to use.
|
||
|
*/
|
||
|
|
||
|
static int function_id, binary, check, nostatus, nowarn;
|
||
|
static int has_failed;
|
||
|
static long mismatch_count, computed_count;
|
||
|
static struct known_function kf;
|
||
|
|
||
|
/**
|
||
|
* Print out a file hash.
|
||
|
*
|
||
|
* @param buf the hash output
|
||
|
* @param len the hash output length
|
||
|
* @param fname the hashed file name
|
||
|
*/
|
||
|
static void
|
||
|
print_hash(unsigned char *buf, size_t len, char *fname)
|
||
|
{
|
||
|
while (len -- > 0)
|
||
|
printf("%02x", (unsigned)*buf ++);
|
||
|
printf(" %s%s\n", binary ? "*" : " ", fname);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Print out the file status (when checking). A <code>NULL</code> file name
|
||
|
* means "standard input".
|
||
|
*
|
||
|
* @param fname the file name (may be <code>NULL</code>)
|
||
|
* @param ok zero for a failure
|
||
|
*/
|
||
|
static void
|
||
|
print_status(char *fname, int ok)
|
||
|
{
|
||
|
if (nostatus)
|
||
|
return;
|
||
|
if (fname == NULL)
|
||
|
fname = "-";
|
||
|
printf("%s: %s\n", fname, ok ? "OK" : "FAILED");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Hash some data
|
||
|
*
|
||
|
* @param in the data input stream
|
||
|
* @param fname the file name (for error reporting), or <code>NULL</code>
|
||
|
* @param dst the output buffer for the hash result
|
||
|
* @return 0 on success, -1 on error (I/O error)
|
||
|
*/
|
||
|
static int
|
||
|
hash_file(FILE *in, char *fname, void *dst)
|
||
|
{
|
||
|
for (;;) {
|
||
|
size_t len;
|
||
|
|
||
|
len = fread(ubuf.buf, 1, sizeof ubuf.buf, in);
|
||
|
kf.ff_update(&hcontext, ubuf.buf, len);
|
||
|
if (len < sizeof ubuf.buf)
|
||
|
break;
|
||
|
}
|
||
|
if (ferror(in)) {
|
||
|
fprintf(stderr, "%s: %s: ", program_name,
|
||
|
fname == NULL ? "<stdin>" : fname);
|
||
|
perror("fread");
|
||
|
return -1;
|
||
|
}
|
||
|
kf.ff_close(&hcontext, dst);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the numerical value of an hexadecimal digit.
|
||
|
*
|
||
|
* @param c the character value
|
||
|
* @return the numerical value, or -1 on error
|
||
|
*/
|
||
|
static int
|
||
|
hexnum(int c)
|
||
|
{
|
||
|
if (c >= '0' && c <= '9')
|
||
|
return c - '0';
|
||
|
switch (c) {
|
||
|
case 'a': case 'A': return 10;
|
||
|
case 'b': case 'B': return 11;
|
||
|
case 'c': case 'C': return 12;
|
||
|
case 'd': case 'D': return 13;
|
||
|
case 'e': case 'E': return 14;
|
||
|
case 'f': case 'F': return 15;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Parse a line from a checksum file. The terminating newline must have
|
||
|
* been removed from the line.
|
||
|
*
|
||
|
* @param line the read line
|
||
|
* @param line_num the file line number (for error reporting)
|
||
|
* @param out the output buffer for the expected hash result
|
||
|
* @param rbin set to 1 if the "binary" flag is set in the line
|
||
|
* @return pointer to the file name (within the line), or <code>NULL</code>
|
||
|
*/
|
||
|
static char *
|
||
|
parse_line(char *line, long line_num, unsigned char *out, int *rbin)
|
||
|
{
|
||
|
char *c;
|
||
|
size_t u;
|
||
|
|
||
|
for (c = line; *c == ' ' || *c == '\t'; c ++);
|
||
|
for (u = 0; u < kf.out_len; u ++) {
|
||
|
int z1, z2;
|
||
|
|
||
|
z1 = hexnum(*c ++);
|
||
|
if (z1 < 0)
|
||
|
goto error;
|
||
|
z2 = hexnum(*c ++);
|
||
|
if (z2 < 0)
|
||
|
goto error;
|
||
|
out[u] = (z1 << 4) | z2;
|
||
|
}
|
||
|
if (*c ++ != ' ')
|
||
|
goto error;
|
||
|
switch (*c ++) {
|
||
|
case ' ':
|
||
|
*rbin = 0;
|
||
|
break;
|
||
|
case '*':
|
||
|
*rbin = 1;
|
||
|
break;
|
||
|
default:
|
||
|
goto error;
|
||
|
}
|
||
|
return c;
|
||
|
|
||
|
error:
|
||
|
if (!nowarn)
|
||
|
fprintf(stderr, "%s: warning: improperly formatted"
|
||
|
" checksum file line %ld, skipping.\n",
|
||
|
program_name, line_num);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Process the provided file name.
|
||
|
*
|
||
|
* @param fname the file name (<code>NULL</code> for standard input)
|
||
|
*/
|
||
|
static void
|
||
|
process_file(char *fname)
|
||
|
{
|
||
|
FILE *in;
|
||
|
|
||
|
if (fname == NULL) {
|
||
|
in = stdin;
|
||
|
} else {
|
||
|
in = fopen(fname, (binary && !check) ? "rb" : "r");
|
||
|
if (in == NULL) {
|
||
|
fprintf(stderr, "%s: %s: ", program_name, fname);
|
||
|
perror("fopen");
|
||
|
has_failed = 1;
|
||
|
if (check)
|
||
|
mismatch_count ++;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
if (check) {
|
||
|
char line[4096];
|
||
|
long line_num;
|
||
|
|
||
|
line_num = 0;
|
||
|
while (fgets(line, sizeof line, in) != NULL) {
|
||
|
size_t n;
|
||
|
char *fname2;
|
||
|
int rbin;
|
||
|
FILE *in2;
|
||
|
unsigned char buf[128];
|
||
|
unsigned char exp_res[128];
|
||
|
int good;
|
||
|
|
||
|
line_num ++;
|
||
|
n = strlen(line);
|
||
|
if (n > 0 && line[n - 1] == '\n')
|
||
|
line[-- n] = 0;
|
||
|
if (n == 1 + sizeof line) {
|
||
|
int quit;
|
||
|
|
||
|
if (!nowarn)
|
||
|
fprintf(stderr, "%s: warning: checksum"
|
||
|
" file line %ld too long,"
|
||
|
" skipping.\n",
|
||
|
program_name, line_num);
|
||
|
quit = 0;
|
||
|
for (;;) {
|
||
|
if (fgets(line,
|
||
|
sizeof line, in) == NULL) {
|
||
|
quit = 1;
|
||
|
break;
|
||
|
}
|
||
|
n = strlen(line);
|
||
|
if (n > 0 && line[n - 1] == '\n')
|
||
|
break;
|
||
|
}
|
||
|
if (quit)
|
||
|
break;
|
||
|
}
|
||
|
fname2 = parse_line(line, line_num, exp_res, &rbin);
|
||
|
if (fname2 == NULL)
|
||
|
continue;
|
||
|
if (strcmp(fname2, "-") == 0) {
|
||
|
if (fname == NULL) {
|
||
|
fprintf(stderr, "%s: error: stdin"
|
||
|
" double use (checksum file"
|
||
|
" line %ld), skipping.\n",
|
||
|
program_name, line_num);
|
||
|
has_failed = 1;
|
||
|
mismatch_count ++;
|
||
|
continue;
|
||
|
}
|
||
|
fname2 = NULL;
|
||
|
in2 = stdin;
|
||
|
} else {
|
||
|
in2 = fopen(fname2, rbin ? "rb" : "r");
|
||
|
if (in2 == NULL) {
|
||
|
fprintf(stderr, "%s: %s: ",
|
||
|
program_name, fname2);
|
||
|
perror("fopen");
|
||
|
has_failed = 1;
|
||
|
mismatch_count ++;
|
||
|
}
|
||
|
}
|
||
|
computed_count ++;
|
||
|
if (hash_file(in2, fname2, buf) < 0) {
|
||
|
has_failed = 1;
|
||
|
mismatch_count ++;
|
||
|
} else {
|
||
|
good = (memcmp(buf, exp_res, kf.out_len) == 0);
|
||
|
print_status(fname2, good);
|
||
|
if (!good) {
|
||
|
has_failed = 1;
|
||
|
mismatch_count ++;
|
||
|
}
|
||
|
}
|
||
|
if (fname2 != NULL)
|
||
|
fclose(in2);
|
||
|
}
|
||
|
if (ferror(in)) {
|
||
|
fprintf(stderr, "%s: error: read error on checksum"
|
||
|
" file\n", program_name);
|
||
|
has_failed = 1;
|
||
|
}
|
||
|
} else {
|
||
|
unsigned char buf[128];
|
||
|
|
||
|
if (hash_file(in, fname, buf) < 0) {
|
||
|
has_failed = 1;
|
||
|
if (check)
|
||
|
mismatch_count ++;
|
||
|
} else {
|
||
|
print_hash(buf, kf.out_len,
|
||
|
fname == NULL ? "-" : fname);
|
||
|
}
|
||
|
}
|
||
|
if (fname != NULL)
|
||
|
fclose(in);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Main function. See <code>usage()</code> for options.
|
||
|
*
|
||
|
* @param argc the argument count
|
||
|
* @param argv the program arguments
|
||
|
* @return the exit status
|
||
|
*/
|
||
|
int
|
||
|
main(int argc, char *argv[])
|
||
|
{
|
||
|
int i;
|
||
|
int fid, skip, ff;
|
||
|
|
||
|
binary = 0;
|
||
|
check = 0;
|
||
|
nostatus = 0;
|
||
|
nowarn = 0;
|
||
|
make_program_name(argv[0]);
|
||
|
if (argc <= 0)
|
||
|
usage(1, 1);
|
||
|
fid = get_function_name(program_name);
|
||
|
if (fid < 0) {
|
||
|
if (argc <= 1)
|
||
|
usage(1, 1);
|
||
|
fid = get_function_name(argv[1]);
|
||
|
if (fid < 0) {
|
||
|
if (!strcmp(argv[1], "-v")
|
||
|
|| !strcmp(argv[1], "--version"))
|
||
|
version();
|
||
|
usage(1, 1);
|
||
|
}
|
||
|
skip = 1;
|
||
|
} else {
|
||
|
skip = 0;
|
||
|
}
|
||
|
for (ff = 0, i = 1 + skip; i < argc; i ++) {
|
||
|
char *opt;
|
||
|
|
||
|
opt = argv[i];
|
||
|
if (!strcmp(opt, "-b") || !strcmp(opt, "--binary")) {
|
||
|
binary = 1;
|
||
|
} else if (!strcmp(opt, "-c") || !strcmp(opt, "--check")) {
|
||
|
check = 1;
|
||
|
} else if (!strcmp(opt, "-t") || !strcmp(opt, "--text")) {
|
||
|
binary = 0;
|
||
|
} else if (!strcmp(opt, "--status")) {
|
||
|
nostatus = 1;
|
||
|
} else if (!strcmp(opt, "-w") || !strcmp(opt, "--warn")) {
|
||
|
nowarn = 1;
|
||
|
} else if (!strcmp(opt, "-h") || !strcmp(opt, "--help")) {
|
||
|
usage(skip, 0);
|
||
|
} else if (!strcmp(opt, "-v") || !strcmp(opt, "--version")) {
|
||
|
version();
|
||
|
} else if (!strcmp(opt, "--")) {
|
||
|
if ((i + 1) < argc)
|
||
|
ff = 1;
|
||
|
argv[i] = NULL;
|
||
|
break;
|
||
|
} else {
|
||
|
ff = 1;
|
||
|
continue;
|
||
|
}
|
||
|
argv[i] = NULL;
|
||
|
}
|
||
|
if ((nostatus || nowarn) && !check)
|
||
|
usage(skip, 1);
|
||
|
has_failed = 0;
|
||
|
mismatch_count = 0;
|
||
|
computed_count = 0;
|
||
|
function_id = fid;
|
||
|
kf = known_functions[fid];
|
||
|
kf.ff_init(&hcontext);
|
||
|
if (ff) {
|
||
|
for (i = 1 + skip; i < argc; i ++) {
|
||
|
char *fname;
|
||
|
|
||
|
fname = argv[i];
|
||
|
if (fname == NULL)
|
||
|
continue;
|
||
|
if (!strcmp(fname, "-"))
|
||
|
fname = NULL;
|
||
|
process_file(fname);
|
||
|
}
|
||
|
} else {
|
||
|
process_file(NULL);
|
||
|
}
|
||
|
if (check && mismatch_count > 0 && !nostatus) {
|
||
|
fprintf(stderr, "%s: WARNING: %ld of %ld computed checksum%s"
|
||
|
" did NOT match\n",
|
||
|
program_name, mismatch_count, computed_count,
|
||
|
computed_count > 1 ? "s" : "");
|
||
|
}
|
||
|
return has_failed ? EXIT_FAILURE : EXIT_SUCCESS;
|
||
|
}
|